summaryrefslogtreecommitdiff
path: root/chromium/cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-06-18 14:10:49 +0200
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2015-06-18 13:53:24 +0000
commit813fbf95af77a531c57a8c497345ad2c61d475b3 (patch)
tree821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/cc
parentaf6588f8d723931a298c995fa97259bb7f7deb55 (diff)
downloadqtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn362
-rw-r--r--chromium/cc/OWNERS9
-rw-r--r--chromium/cc/PRESUBMIT.py20
-rw-r--r--chromium/cc/animation/animation.cc141
-rw-r--r--chromium/cc/animation/animation.h80
-rw-r--r--chromium/cc/animation/animation_curve.cc22
-rw-r--r--chromium/cc/animation/animation_curve.h20
-rw-r--r--chromium/cc/animation/animation_events.h2
-rw-r--r--chromium/cc/animation/animation_id_provider.cc12
-rw-r--r--chromium/cc/animation/animation_registrar.cc72
-rw-r--r--chromium/cc/animation/animation_registrar.h21
-rw-r--r--chromium/cc/animation/animation_unittest.cc1005
-rw-r--r--chromium/cc/animation/keyframed_animation_curve.cc111
-rw-r--r--chromium/cc/animation/keyframed_animation_curve.h52
-rw-r--r--chromium/cc/animation/keyframed_animation_curve_unittest.cc756
-rw-r--r--chromium/cc/animation/layer_animation_controller.cc305
-rw-r--r--chromium/cc/animation/layer_animation_controller.h36
-rw-r--r--chromium/cc/animation/layer_animation_controller_unittest.cc1090
-rw-r--r--chromium/cc/animation/layer_animation_event_observer.h2
-rw-r--r--chromium/cc/animation/layer_animation_value_observer.h7
-rw-r--r--chromium/cc/animation/layer_animation_value_provider.h6
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve.cc25
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve.h4
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve_unittest.cc103
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller.cc24
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller.h26
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc22
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_linear_fade.h2
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc88
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_thinning.cc39
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_thinning.h2
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc39
-rw-r--r--chromium/cc/animation/timing_function.cc38
-rw-r--r--chromium/cc/animation/timing_function.h22
-rw-r--r--chromium/cc/animation/transform_operation.cc32
-rw-r--r--chromium/cc/animation/transform_operation.h18
-rw-r--r--chromium/cc/animation/transform_operations.cc65
-rw-r--r--chromium/cc/animation/transform_operations.h3
-rw-r--r--chromium/cc/base/BUILD.gn50
-rw-r--r--chromium/cc/base/DEPS12
-rw-r--r--chromium/cc/base/completion_event.h10
-rw-r--r--chromium/cc/base/delayed_unique_notifier_unittest.cc2
-rw-r--r--chromium/cc/base/math_util.cc99
-rw-r--r--chromium/cc/base/math_util.h71
-rw-r--r--chromium/cc/base/ref_counted_managed.h65
-rw-r--r--chromium/cc/base/region.cc4
-rw-r--r--chromium/cc/base/region.h4
-rw-r--r--chromium/cc/base/rolling_time_delta_history.cc4
-rw-r--r--chromium/cc/base/rolling_time_delta_history.h2
-rw-r--r--chromium/cc/base/scoped_ptr_vector.h24
-rw-r--r--chromium/cc/base/scoped_ptr_vector_unittest.cc79
-rw-r--r--chromium/cc/base/swap_promise.h53
-rw-r--r--chromium/cc/base/switches.cc24
-rw-r--r--chromium/cc/base/switches.h8
-rw-r--r--chromium/cc/base/synced_property.h187
-rw-r--r--chromium/cc/base/tiling_data.cc241
-rw-r--r--chromium/cc/base/tiling_data.h76
-rw-r--r--chromium/cc/base/tiling_data_unittest.cc98
-rw-r--r--chromium/cc/base/time_util.h35
-rw-r--r--chromium/cc/base/unique_notifier_unittest.cc6
-rw-r--r--chromium/cc/base/util.h6
-rw-r--r--chromium/cc/blink/BUILD.gn73
-rw-r--r--chromium/cc/blink/cc_blink.gyp3
-rw-r--r--chromium/cc/blink/cc_blink_tests.gyp3
-rw-r--r--chromium/cc/blink/context_provider_web_context.h24
-rw-r--r--chromium/cc/blink/web_animation_impl.cc32
-rw-r--r--chromium/cc/blink/web_compositor_support_impl.cc2
-rw-r--r--chromium/cc/blink/web_compositor_support_impl.h1
-rw-r--r--chromium/cc/blink/web_content_layer_impl.cc49
-rw-r--r--chromium/cc/blink/web_content_layer_impl.h11
-rw-r--r--chromium/cc/blink/web_display_item_list_impl.cc136
-rw-r--r--chromium/cc/blink/web_display_item_list_impl.h71
-rw-r--r--chromium/cc/blink/web_external_bitmap_impl.cc15
-rw-r--r--chromium/cc/blink/web_external_bitmap_impl.h21
-rw-r--r--chromium/cc/blink/web_external_texture_layer_impl.cc8
-rw-r--r--chromium/cc/blink/web_external_texture_layer_impl.h2
-rw-r--r--chromium/cc/blink/web_filter_animation_curve_impl.cc39
-rw-r--r--chromium/cc/blink/web_filter_animation_curve_impl.h13
-rw-r--r--chromium/cc/blink/web_float_animation_curve_impl.cc40
-rw-r--r--chromium/cc/blink/web_float_animation_curve_impl.h13
-rw-r--r--chromium/cc/blink/web_image_layer_impl.cc7
-rw-r--r--chromium/cc/blink/web_image_layer_impl.h1
-rw-r--r--chromium/cc/blink/web_layer_impl.cc64
-rw-r--r--chromium/cc/blink/web_layer_impl.h13
-rw-r--r--chromium/cc/blink/web_layer_impl_fixed_bounds.h12
-rw-r--r--chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc5
-rw-r--r--chromium/cc/blink/web_scroll_offset_animation_curve_impl.cc15
-rw-r--r--chromium/cc/blink/web_scroll_offset_animation_curve_impl.h2
-rw-r--r--chromium/cc/blink/web_scrollbar_layer_impl.cc6
-rw-r--r--chromium/cc/blink/web_transform_animation_curve_impl.cc38
-rw-r--r--chromium/cc/blink/web_transform_animation_curve_impl.h13
-rw-r--r--chromium/cc/cc.gyp256
-rw-r--r--chromium/cc/cc_tests.gyp104
-rw-r--r--chromium/cc/cc_unittests.isolate89
-rw-r--r--chromium/cc/debug/benchmark_instrumentation.cc19
-rw-r--r--chromium/cc/debug/benchmark_instrumentation.h5
-rw-r--r--chromium/cc/debug/debug_colors.cc30
-rw-r--r--chromium/cc/debug/debug_colors.h12
-rw-r--r--chromium/cc/debug/debug_rect_history.cc68
-rw-r--r--chromium/cc/debug/debug_rect_history.h15
-rw-r--r--chromium/cc/debug/devtools_instrumentation.h40
-rw-r--r--chromium/cc/debug/frame_rate_counter.cc2
-rw-r--r--chromium/cc/debug/frame_timing_request.cc17
-rw-r--r--chromium/cc/debug/frame_timing_request.h35
-rw-r--r--chromium/cc/debug/frame_timing_tracker.cc98
-rw-r--r--chromium/cc/debug/frame_timing_tracker.h87
-rw-r--r--chromium/cc/debug/frame_timing_tracker_unittest.cc228
-rw-r--r--chromium/cc/debug/frame_viewer_instrumentation.cc78
-rw-r--r--chromium/cc/debug/frame_viewer_instrumentation.h60
-rw-r--r--chromium/cc/debug/invalidation_benchmark.cc8
-rw-r--r--chromium/cc/debug/invalidation_benchmark.h1
-rw-r--r--chromium/cc/debug/lap_timer.cc16
-rw-r--r--chromium/cc/debug/lap_timer.h2
-rw-r--r--chromium/cc/debug/layer_tree_debug_state.cc9
-rw-r--r--chromium/cc/debug/layer_tree_debug_state.h2
-rw-r--r--chromium/cc/debug/micro_benchmark.cc8
-rw-r--r--chromium/cc/debug/micro_benchmark.h6
-rw-r--r--chromium/cc/debug/micro_benchmark_controller.cc9
-rw-r--r--chromium/cc/debug/micro_benchmark_controller.h4
-rw-r--r--chromium/cc/debug/micro_benchmark_controller_unittest.cc6
-rw-r--r--chromium/cc/debug/micro_benchmark_impl.cc15
-rw-r--r--chromium/cc/debug/micro_benchmark_impl.h6
-rw-r--r--chromium/cc/debug/picture_debug_util.cc73
-rw-r--r--chromium/cc/debug/picture_debug_util.h21
-rw-r--r--chromium/cc/debug/picture_record_benchmark.cc23
-rw-r--r--chromium/cc/debug/picture_record_benchmark.h2
-rw-r--r--chromium/cc/debug/rasterize_and_record_benchmark.cc163
-rw-r--r--chromium/cc/debug/rasterize_and_record_benchmark.h13
-rw-r--r--chromium/cc/debug/rasterize_and_record_benchmark_impl.cc212
-rw-r--r--chromium/cc/debug/rasterize_and_record_benchmark_impl.h9
-rw-r--r--chromium/cc/debug/rendering_stats.cc91
-rw-r--r--chromium/cc/debug/rendering_stats.h63
-rw-r--r--chromium/cc/debug/rendering_stats_instrumentation.cc52
-rw-r--r--chromium/cc/debug/rendering_stats_instrumentation.h18
-rw-r--r--chromium/cc/debug/rendering_stats_unittest.cc8
-rw-r--r--chromium/cc/debug/ring_buffer.h4
-rw-r--r--chromium/cc/debug/traced_picture.cc8
-rw-r--r--chromium/cc/debug/traced_picture.h10
-rw-r--r--chromium/cc/debug/traced_value.cc18
-rw-r--r--chromium/cc/debug/traced_value.h13
-rw-r--r--chromium/cc/debug/unittest_only_benchmark.cc7
-rw-r--r--chromium/cc/debug/unittest_only_benchmark.h6
-rw-r--r--chromium/cc/debug/unittest_only_benchmark_impl.cc7
-rw-r--r--chromium/cc/debug/unittest_only_benchmark_impl.h9
-rw-r--r--chromium/cc/input/input_handler.h38
-rw-r--r--chromium/cc/input/layer_selection_bound.h3
-rw-r--r--chromium/cc/input/page_scale_animation.h19
-rw-r--r--chromium/cc/input/scroll_elasticity_helper.cc91
-rw-r--r--chromium/cc/input/scroll_elasticity_helper.h73
-rw-r--r--chromium/cc/input/selection.h38
-rw-r--r--chromium/cc/input/top_controls_manager.cc172
-rw-r--r--chromium/cc/input/top_controls_manager.h34
-rw-r--r--chromium/cc/input/top_controls_manager_client.h5
-rw-r--r--chromium/cc/input/top_controls_manager_unittest.cc286
-rw-r--r--chromium/cc/layers/append_quads_data.h13
-rw-r--r--chromium/cc/layers/content_layer.cc39
-rw-r--r--chromium/cc/layers/content_layer.h5
-rw-r--r--chromium/cc/layers/content_layer_client.h18
-rw-r--r--chromium/cc/layers/contents_scaling_layer.cc13
-rw-r--r--chromium/cc/layers/delegated_frame_provider.cc2
-rw-r--r--chromium/cc/layers/delegated_frame_provider_unittest.cc5
-rw-r--r--chromium/cc/layers/delegated_frame_resource_collection_unittest.cc25
-rw-r--r--chromium/cc/layers/delegated_renderer_layer_impl.cc142
-rw-r--r--chromium/cc/layers/delegated_renderer_layer_impl.h12
-rw-r--r--chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc511
-rw-r--r--chromium/cc/layers/draw_properties.h26
-rw-r--r--chromium/cc/layers/heads_up_display_layer.cc2
-rw-r--r--chromium/cc/layers/heads_up_display_layer.h4
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc206
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.h15
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl_unittest.cc7
-rw-r--r--chromium/cc/layers/io_surface_layer_impl.cc10
-rw-r--r--chromium/cc/layers/io_surface_layer_impl.h1
-rw-r--r--chromium/cc/layers/io_surface_layer_impl_unittest.cc4
-rw-r--r--chromium/cc/layers/layer.cc420
-rw-r--r--chromium/cc/layers/layer.h156
-rw-r--r--chromium/cc/layers/layer_client.h4
-rw-r--r--chromium/cc/layers/layer_impl.cc636
-rw-r--r--chromium/cc/layers/layer_impl.h205
-rw-r--r--chromium/cc/layers/layer_impl_unittest.cc413
-rw-r--r--chromium/cc/layers/layer_perftest.cc12
-rw-r--r--chromium/cc/layers/layer_position_constraint_unittest.cc14
-rw-r--r--chromium/cc/layers/layer_unittest.cc140
-rw-r--r--chromium/cc/layers/layer_utils.h22
-rw-r--r--chromium/cc/layers/layer_utils_unittest.cc16
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl.cc78
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl.h1
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl_unittest.cc76
-rw-r--r--chromium/cc/layers/nine_patch_layer_unittest.cc4
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.cc82
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.h22
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.cc73
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.h17
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc23
-rw-r--r--chromium/cc/layers/picture_image_layer.cc21
-rw-r--r--chromium/cc/layers/picture_image_layer.h7
-rw-r--r--chromium/cc/layers/picture_image_layer_impl.cc11
-rw-r--r--chromium/cc/layers/picture_image_layer_impl.h7
-rw-r--r--chromium/cc/layers/picture_image_layer_impl_unittest.cc30
-rw-r--r--chromium/cc/layers/picture_image_layer_unittest.cc83
-rw-r--r--chromium/cc/layers/picture_layer.cc170
-rw-r--r--chromium/cc/layers/picture_layer.h21
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc1327
-rw-r--r--chromium/cc/layers/picture_layer_impl.h180
-rw-r--r--chromium/cc/layers/picture_layer_impl_perftest.cc161
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc3783
-rw-r--r--chromium/cc/layers/picture_layer_unittest.cc98
-rw-r--r--chromium/cc/layers/render_surface_impl.cc83
-rw-r--r--chromium/cc/layers/render_surface_impl.h25
-rw-r--r--chromium/cc/layers/render_surface_impl_unittest.cc2
-rw-r--r--chromium/cc/layers/render_surface_unittest.cc31
-rw-r--r--chromium/cc/layers/scroll_blocks_on.h26
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.cc8
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.h1
-rw-r--r--chromium/cc/layers/scrollbar_layer_unittest.cc351
-rw-r--r--chromium/cc/layers/solid_color_layer_impl.cc10
-rw-r--r--chromium/cc/layers/solid_color_layer_impl.h1
-rw-r--r--chromium/cc/layers/solid_color_layer_impl_unittest.cc47
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer_impl.cc4
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer_impl.h1
-rw-r--r--chromium/cc/layers/surface_layer.cc17
-rw-r--r--chromium/cc/layers/surface_layer.h5
-rw-r--r--chromium/cc/layers/surface_layer_impl.cc8
-rw-r--r--chromium/cc/layers/surface_layer_impl.h3
-rw-r--r--chromium/cc/layers/surface_layer_unittest.cc52
-rw-r--r--chromium/cc/layers/texture_layer.cc9
-rw-r--r--chromium/cc/layers/texture_layer.h6
-rw-r--r--chromium/cc/layers/texture_layer_impl.cc24
-rw-r--r--chromium/cc/layers/texture_layer_impl.h7
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc219
-rw-r--r--chromium/cc/layers/tiled_layer.cc1
-rw-r--r--chromium/cc/layers/tiled_layer.h2
-rw-r--r--chromium/cc/layers/tiled_layer_impl.cc36
-rw-r--r--chromium/cc/layers/tiled_layer_impl.h17
-rw-r--r--chromium/cc/layers/tiled_layer_impl_unittest.cc44
-rw-r--r--chromium/cc/layers/tiled_layer_unittest.cc102
-rw-r--r--chromium/cc/layers/ui_resource_layer.cc22
-rw-r--r--chromium/cc/layers/ui_resource_layer.h6
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl.cc9
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl.h1
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl_unittest.cc11
-rw-r--r--chromium/cc/layers/ui_resource_layer_unittest.cc57
-rw-r--r--chromium/cc/layers/video_frame_provider.h82
-rw-r--r--chromium/cc/layers/video_frame_provider_client_impl.cc129
-rw-r--r--chromium/cc/layers/video_frame_provider_client_impl.h60
-rw-r--r--chromium/cc/layers/video_layer_impl.cc162
-rw-r--r--chromium/cc/layers/video_layer_impl.h17
-rw-r--r--chromium/cc/layers/video_layer_impl_unittest.cc151
-rw-r--r--chromium/cc/layers/viewport.cc133
-rw-r--r--chromium/cc/layers/viewport.h59
-rw-r--r--chromium/cc/output/begin_frame_args.cc82
-rw-r--r--chromium/cc/output/begin_frame_args.h54
-rw-r--r--chromium/cc/output/begin_frame_args_unittest.cc66
-rw-r--r--chromium/cc/output/bsp_tree.cc4
-rw-r--r--chromium/cc/output/bsp_tree.h1
-rw-r--r--chromium/cc/output/bsp_walk_action.cc26
-rw-r--r--chromium/cc/output/bsp_walk_action.h16
-rw-r--r--chromium/cc/output/compositor_frame_metadata.cc4
-rw-r--r--chromium/cc/output/compositor_frame_metadata.h5
-rw-r--r--chromium/cc/output/context_provider.h16
-rw-r--r--chromium/cc/output/copy_output_request.cc5
-rw-r--r--chromium/cc/output/copy_output_request.h7
-rw-r--r--chromium/cc/output/delegating_renderer.cc10
-rw-r--r--chromium/cc/output/delegating_renderer.h4
-rw-r--r--chromium/cc/output/delegating_renderer_unittest.cc4
-rw-r--r--chromium/cc/output/direct_renderer.cc261
-rw-r--r--chromium/cc/output/direct_renderer.h64
-rw-r--r--chromium/cc/output/dynamic_geometry_binding.cc66
-rw-r--r--chromium/cc/output/dynamic_geometry_binding.h30
-rw-r--r--chromium/cc/output/filter_operation.cc8
-rw-r--r--chromium/cc/output/filter_operation.h4
-rw-r--r--chromium/cc/output/filter_operations.cc5
-rw-r--r--chromium/cc/output/filter_operations.h4
-rw-r--r--chromium/cc/output/geometry_binding.cc143
-rw-r--r--chromium/cc/output/geometry_binding.h61
-rw-r--r--chromium/cc/output/gl_renderer.cc2180
-rw-r--r--chromium/cc/output/gl_renderer.h246
-rw-r--r--chromium/cc/output/gl_renderer_draw_cache.cc1
-rw-r--r--chromium/cc/output/gl_renderer_draw_cache.h1
-rw-r--r--chromium/cc/output/gl_renderer_unittest.cc675
-rw-r--r--chromium/cc/output/latency_info_swap_promise.cc (renamed from chromium/cc/base/latency_info_swap_promise.cc)32
-rw-r--r--chromium/cc/output/latency_info_swap_promise.h (renamed from chromium/cc/base/latency_info_swap_promise.h)9
-rw-r--r--chromium/cc/output/layer_quad.cc124
-rw-r--r--chromium/cc/output/layer_quad.h (renamed from chromium/cc/resources/layer_quad.h)19
-rw-r--r--chromium/cc/output/layer_quad_unittest.cc (renamed from chromium/cc/resources/layer_quad_unittest.cc)29
-rw-r--r--chromium/cc/output/managed_memory_policy.h2
-rw-r--r--chromium/cc/output/output_surface.cc131
-rw-r--r--chromium/cc/output/output_surface.h55
-rw-r--r--chromium/cc/output/output_surface_client.h10
-rw-r--r--chromium/cc/output/output_surface_unittest.cc94
-rw-r--r--chromium/cc/output/overlay_candidate.cc159
-rw-r--r--chromium/cc/output/overlay_candidate.h15
-rw-r--r--chromium/cc/output/overlay_candidate_validator.h4
-rw-r--r--chromium/cc/output/overlay_processor.cc5
-rw-r--r--chromium/cc/output/overlay_strategy_common.cc136
-rw-r--r--chromium/cc/output/overlay_strategy_common.h49
-rw-r--r--chromium/cc/output/overlay_strategy_single_on_top.cc40
-rw-r--r--chromium/cc/output/overlay_strategy_single_on_top.h8
-rw-r--r--chromium/cc/output/overlay_strategy_underlay.cc69
-rw-r--r--chromium/cc/output/overlay_strategy_underlay.h32
-rw-r--r--chromium/cc/output/overlay_unittest.cc479
-rw-r--r--chromium/cc/output/program_binding.cc2
-rw-r--r--chromium/cc/output/program_binding.h19
-rw-r--r--chromium/cc/output/render_surface_filters.cc1
-rw-r--r--chromium/cc/output/renderer.cc3
-rw-r--r--chromium/cc/output/renderer.h9
-rw-r--r--chromium/cc/output/renderer_capabilities.cc29
-rw-r--r--chromium/cc/output/renderer_capabilities.h32
-rw-r--r--chromium/cc/output/renderer_pixeltest.cc1416
-rw-r--r--chromium/cc/output/renderer_settings.cc29
-rw-r--r--chromium/cc/output/renderer_settings.h32
-rw-r--r--chromium/cc/output/renderer_unittest.cc8
-rw-r--r--chromium/cc/output/shader.cc2133
-rw-r--r--chromium/cc/output/shader.h194
-rw-r--r--chromium/cc/output/shader_unittest.cc40
-rw-r--r--chromium/cc/output/software_output_device.cc17
-rw-r--r--chromium/cc/output/software_output_device.h11
-rw-r--r--chromium/cc/output/software_renderer.cc113
-rw-r--r--chromium/cc/output/software_renderer.h19
-rw-r--r--chromium/cc/output/software_renderer_unittest.cc56
-rw-r--r--chromium/cc/output/static_geometry_binding.cc70
-rw-r--r--chromium/cc/output/static_geometry_binding.h33
-rw-r--r--chromium/cc/output/swap_promise.h66
-rw-r--r--chromium/cc/output/texture_mailbox_deleter.cc (renamed from chromium/cc/resources/texture_mailbox_deleter.cc)2
-rw-r--r--chromium/cc/output/texture_mailbox_deleter.h (renamed from chromium/cc/resources/texture_mailbox_deleter.h)6
-rw-r--r--chromium/cc/output/texture_mailbox_deleter_unittest.cc (renamed from chromium/cc/resources/texture_mailbox_deleter_unittest.cc)7
-rw-r--r--chromium/cc/output/viewport_selection_bound.h4
-rw-r--r--chromium/cc/playback/clip_display_item.cc95
-rw-r--r--chromium/cc/playback/clip_display_item.h48
-rw-r--r--chromium/cc/playback/clip_path_display_item.cc61
-rw-r--r--chromium/cc/playback/clip_path_display_item.h50
-rw-r--r--chromium/cc/playback/compositing_display_item.cc78
-rw-r--r--chromium/cc/playback/compositing_display_item.h58
-rw-r--r--chromium/cc/playback/display_item.cc12
-rw-r--r--chromium/cc/playback/display_item.h51
-rw-r--r--chromium/cc/playback/display_item_list.cc229
-rw-r--r--chromium/cc/playback/display_item_list.h100
-rw-r--r--chromium/cc/playback/display_item_list_unittest.cc340
-rw-r--r--chromium/cc/playback/display_list_raster_source.cc235
-rw-r--r--chromium/cc/playback/display_list_raster_source.h98
-rw-r--r--chromium/cc/playback/display_list_recording_source.cc192
-rw-r--r--chromium/cc/playback/display_list_recording_source.h70
-rw-r--r--chromium/cc/playback/display_list_recording_source_unittest.cc165
-rw-r--r--chromium/cc/playback/drawing_display_item.cc62
-rw-r--r--chromium/cc/playback/drawing_display_item.h38
-rw-r--r--chromium/cc/playback/filter_display_item.cc81
-rw-r--r--chromium/cc/playback/filter_display_item.h49
-rw-r--r--chromium/cc/playback/float_clip_display_item.cc58
-rw-r--r--chromium/cc/playback/float_clip_display_item.h49
-rw-r--r--chromium/cc/playback/largest_display_item.cc71
-rw-r--r--chromium/cc/playback/largest_display_item.h17
-rw-r--r--chromium/cc/playback/picture.cc340
-rw-r--r--chromium/cc/playback/picture.h (renamed from chromium/cc/resources/picture.h)92
-rw-r--r--chromium/cc/playback/picture_pile.cc (renamed from chromium/cc/resources/picture_pile.cc)366
-rw-r--r--chromium/cc/playback/picture_pile.h107
-rw-r--r--chromium/cc/playback/picture_pile_impl.cc (renamed from chromium/cc/resources/picture_pile_impl.cc)225
-rw-r--r--chromium/cc/playback/picture_pile_impl.h (renamed from chromium/cc/resources/picture_pile_impl.h)119
-rw-r--r--chromium/cc/playback/picture_pile_impl_perftest.cc (renamed from chromium/cc/resources/picture_pile_impl_perftest.cc)2
-rw-r--r--chromium/cc/playback/picture_pile_impl_unittest.cc (renamed from chromium/cc/resources/picture_pile_impl_unittest.cc)522
-rw-r--r--chromium/cc/playback/picture_pile_unittest.cc (renamed from chromium/cc/resources/picture_pile_unittest.cc)516
-rw-r--r--chromium/cc/playback/picture_unittest.cc181
-rw-r--r--chromium/cc/playback/pixel_ref_map.cc172
-rw-r--r--chromium/cc/playback/pixel_ref_map.h94
-rw-r--r--chromium/cc/playback/pixel_ref_map_unittest.cc292
-rw-r--r--chromium/cc/playback/raster_source.h (renamed from chromium/cc/resources/raster_source.h)53
-rw-r--r--chromium/cc/playback/raster_source_helper.cc81
-rw-r--r--chromium/cc/playback/raster_source_helper.h29
-rw-r--r--chromium/cc/playback/recording_source.h63
-rw-r--r--chromium/cc/playback/recording_source_unittest.cc470
-rw-r--r--chromium/cc/playback/transform_display_item.cc59
-rw-r--r--chromium/cc/playback/transform_display_item.h47
-rw-r--r--chromium/cc/quads/checkerboard_draw_quad.cc17
-rw-r--r--chromium/cc/quads/checkerboard_draw_quad.h9
-rw-r--r--chromium/cc/quads/content_draw_quad_base.cc23
-rw-r--r--chromium/cc/quads/content_draw_quad_base.h10
-rw-r--r--chromium/cc/quads/debug_border_draw_quad.cc5
-rw-r--r--chromium/cc/quads/debug_border_draw_quad.h2
-rw-r--r--chromium/cc/quads/draw_polygon.cc35
-rw-r--r--chromium/cc/quads/draw_polygon.h11
-rw-r--r--chromium/cc/quads/draw_quad.cc35
-rw-r--r--chromium/cc/quads/draw_quad.h6
-rw-r--r--chromium/cc/quads/draw_quad_unittest.cc289
-rw-r--r--chromium/cc/quads/io_surface_draw_quad.cc9
-rw-r--r--chromium/cc/quads/io_surface_draw_quad.h2
-rw-r--r--chromium/cc/quads/largest_draw_quad.cc53
-rw-r--r--chromium/cc/quads/list_container.cc86
-rw-r--r--chromium/cc/quads/list_container.h12
-rw-r--r--chromium/cc/quads/list_container_unittest.cc138
-rw-r--r--chromium/cc/quads/picture_draw_quad.cc26
-rw-r--r--chromium/cc/quads/picture_draw_quad.h12
-rw-r--r--chromium/cc/quads/render_pass.cc13
-rw-r--r--chromium/cc/quads/render_pass.h6
-rw-r--r--chromium/cc/quads/render_pass_draw_quad.cc20
-rw-r--r--chromium/cc/quads/render_pass_draw_quad.h2
-rw-r--r--chromium/cc/quads/render_pass_id.cc4
-rw-r--r--chromium/cc/quads/render_pass_unittest.cc47
-rw-r--r--chromium/cc/quads/shared_quad_state.cc23
-rw-r--r--chromium/cc/quads/shared_quad_state.h4
-rw-r--r--chromium/cc/quads/solid_color_draw_quad.cc5
-rw-r--r--chromium/cc/quads/solid_color_draw_quad.h2
-rw-r--r--chromium/cc/quads/stream_video_draw_quad.cc9
-rw-r--r--chromium/cc/quads/stream_video_draw_quad.h2
-rw-r--r--chromium/cc/quads/surface_draw_quad.cc4
-rw-r--r--chromium/cc/quads/surface_draw_quad.h2
-rw-r--r--chromium/cc/quads/texture_draw_quad.cc36
-rw-r--r--chromium/cc/quads/texture_draw_quad.h11
-rw-r--r--chromium/cc/quads/tile_draw_quad.cc17
-rw-r--r--chromium/cc/quads/tile_draw_quad.h14
-rw-r--r--chromium/cc/quads/yuv_video_draw_quad.cc32
-rw-r--r--chromium/cc/quads/yuv_video_draw_quad.h31
-rw-r--r--chromium/cc/raster/bitmap_tile_task_worker_pool.cc206
-rw-r--r--chromium/cc/raster/bitmap_tile_task_worker_pool.h81
-rw-r--r--chromium/cc/raster/gpu_rasterizer.cc85
-rw-r--r--chromium/cc/raster/gpu_rasterizer.h49
-rw-r--r--chromium/cc/raster/gpu_tile_task_worker_pool.cc229
-rw-r--r--chromium/cc/raster/gpu_tile_task_worker_pool.h82
-rw-r--r--chromium/cc/raster/one_copy_tile_task_worker_pool.cc (renamed from chromium/cc/resources/one_copy_raster_worker_pool.cc)201
-rw-r--r--chromium/cc/raster/one_copy_tile_task_worker_pool.h (renamed from chromium/cc/resources/one_copy_raster_worker_pool.h)67
-rw-r--r--chromium/cc/raster/pixel_buffer_tile_task_worker_pool.cc (renamed from chromium/cc/resources/pixel_buffer_raster_worker_pool.cc)247
-rw-r--r--chromium/cc/raster/pixel_buffer_tile_task_worker_pool.h (renamed from chromium/cc/resources/pixel_buffer_raster_worker_pool.h)69
-rw-r--r--chromium/cc/raster/raster_buffer.cc (renamed from chromium/cc/resources/raster_buffer.cc)2
-rw-r--r--chromium/cc/raster/raster_buffer.h (renamed from chromium/cc/resources/raster_buffer.h)6
-rw-r--r--chromium/cc/raster/scoped_gpu_raster.cc (renamed from chromium/cc/resources/scoped_gpu_raster.cc)15
-rw-r--r--chromium/cc/raster/scoped_gpu_raster.h (renamed from chromium/cc/resources/scoped_gpu_raster.h)8
-rw-r--r--chromium/cc/raster/scoped_gpu_raster_unittest.cc39
-rw-r--r--chromium/cc/raster/task_graph_runner.cc (renamed from chromium/cc/resources/task_graph_runner.cc)5
-rw-r--r--chromium/cc/raster/task_graph_runner.h (renamed from chromium/cc/resources/task_graph_runner.h)6
-rw-r--r--chromium/cc/raster/task_graph_runner_perftest.cc (renamed from chromium/cc/resources/task_graph_runner_perftest.cc)12
-rw-r--r--chromium/cc/raster/task_graph_runner_unittest.cc (renamed from chromium/cc/resources/task_graph_runner_unittest.cc)10
-rw-r--r--chromium/cc/raster/texture_compressor.cc34
-rw-r--r--chromium/cc/raster/texture_compressor.h46
-rw-r--r--chromium/cc/raster/texture_compressor_etc1.cc332
-rw-r--r--chromium/cc/raster/texture_compressor_etc1.h206
-rw-r--r--chromium/cc/raster/texture_compressor_etc1_sse.cc821
-rw-r--r--chromium/cc/raster/texture_compressor_etc1_sse.h31
-rw-r--r--chromium/cc/raster/texture_compressor_etc1_unittest.cc56
-rw-r--r--chromium/cc/raster/texture_compressor_perftest.cc121
-rw-r--r--chromium/cc/raster/tile_task_runner.cc100
-rw-r--r--chromium/cc/raster/tile_task_runner.h (renamed from chromium/cc/resources/rasterizer.h)72
-rw-r--r--chromium/cc/raster/tile_task_worker_pool.cc207
-rw-r--r--chromium/cc/raster/tile_task_worker_pool.h (renamed from chromium/cc/resources/raster_worker_pool.h)41
-rw-r--r--chromium/cc/raster/tile_task_worker_pool_perftest.cc (renamed from chromium/cc/resources/raster_worker_pool_perftest.cc)324
-rw-r--r--chromium/cc/raster/tile_task_worker_pool_unittest.cc (renamed from chromium/cc/resources/raster_worker_pool_unittest.cc)262
-rw-r--r--chromium/cc/raster/zero_copy_tile_task_worker_pool.cc216
-rw-r--r--chromium/cc/raster/zero_copy_tile_task_worker_pool.h81
-rw-r--r--chromium/cc/resources/bitmap_content_layer_updater.cc12
-rw-r--r--chromium/cc/resources/bitmap_content_layer_updater.h2
-rw-r--r--chromium/cc/resources/bitmap_raster_worker_pool.cc203
-rw-r--r--chromium/cc/resources/bitmap_raster_worker_pool.h79
-rw-r--r--chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc5
-rw-r--r--chromium/cc/resources/content_layer_updater.cc17
-rw-r--r--chromium/cc/resources/content_layer_updater.h6
-rw-r--r--chromium/cc/resources/eviction_tile_priority_queue.cc221
-rw-r--r--chromium/cc/resources/eviction_tile_priority_queue.h61
-rw-r--r--chromium/cc/resources/gpu_raster_worker_pool.cc252
-rw-r--r--chromium/cc/resources/gpu_raster_worker_pool.h83
-rw-r--r--chromium/cc/resources/layer_quad.cc67
-rw-r--r--chromium/cc/resources/managed_tile_state.cc94
-rw-r--r--chromium/cc/resources/managed_tile_state.h124
-rw-r--r--chromium/cc/resources/picture.cc520
-rw-r--r--chromium/cc/resources/picture_layer_tiling.cc1243
-rw-r--r--chromium/cc/resources/picture_layer_tiling_perftest.cc360
-rw-r--r--chromium/cc/resources/picture_layer_tiling_set.cc374
-rw-r--r--chromium/cc/resources/picture_layer_tiling_set.h135
-rw-r--r--chromium/cc/resources/picture_layer_tiling_set_unittest.cc562
-rw-r--r--chromium/cc/resources/picture_pile.h76
-rw-r--r--chromium/cc/resources/picture_pile_base.cc205
-rw-r--r--chromium/cc/resources/picture_pile_base.h137
-rw-r--r--chromium/cc/resources/picture_unittest.cc475
-rw-r--r--chromium/cc/resources/platform_color.h2
-rw-r--r--chromium/cc/resources/platform_color_unittest.cc42
-rw-r--r--chromium/cc/resources/prioritized_resource.cc4
-rw-r--r--chromium/cc/resources/prioritized_resource.h2
-rw-r--r--chromium/cc/resources/prioritized_resource_manager.cc13
-rw-r--r--chromium/cc/resources/prioritized_resource_unittest.cc2
-rw-r--r--chromium/cc/resources/raster_tile_priority_queue.cc310
-rw-r--r--chromium/cc/resources/raster_tile_priority_queue.h66
-rw-r--r--chromium/cc/resources/raster_worker_pool.cc267
-rw-r--r--chromium/cc/resources/rasterizer.cc80
-rw-r--r--chromium/cc/resources/resource.h1
-rw-r--r--chromium/cc/resources/resource_format.cc1
-rw-r--r--chromium/cc/resources/resource_format.h3
-rw-r--r--chromium/cc/resources/resource_pool.cc11
-rw-r--r--chromium/cc/resources/resource_pool.h15
-rw-r--r--chromium/cc/resources/resource_provider.cc866
-rw-r--r--chromium/cc/resources/resource_provider.h137
-rw-r--r--chromium/cc/resources/resource_provider_unittest.cc948
-rw-r--r--chromium/cc/resources/resource_update_controller.h1
-rw-r--r--chromium/cc/resources/resource_update_controller_unittest.cc4
-rw-r--r--chromium/cc/resources/scoped_resource.cc11
-rw-r--r--chromium/cc/resources/scoped_resource.h4
-rw-r--r--chromium/cc/resources/scoped_resource_unittest.cc12
-rw-r--r--chromium/cc/resources/shared_bitmap.cc18
-rw-r--r--chromium/cc/resources/shared_bitmap.h28
-rw-r--r--chromium/cc/resources/shared_bitmap_manager.h3
-rw-r--r--chromium/cc/resources/single_release_callback.cc11
-rw-r--r--chromium/cc/resources/single_release_callback.h1
-rw-r--r--chromium/cc/resources/single_release_callback_impl.cc12
-rw-r--r--chromium/cc/resources/single_release_callback_impl.h1
-rw-r--r--chromium/cc/resources/skpicture_content_layer_updater.cc14
-rw-r--r--chromium/cc/resources/skpicture_content_layer_updater.h1
-rw-r--r--chromium/cc/resources/texture_mailbox.cc25
-rw-r--r--chromium/cc/resources/texture_mailbox.h14
-rw-r--r--chromium/cc/resources/texture_uploader.cc33
-rw-r--r--chromium/cc/resources/texture_uploader.h6
-rw-r--r--chromium/cc/resources/texture_uploader_unittest.cc17
-rw-r--r--chromium/cc/resources/tile.cc90
-rw-r--r--chromium/cc/resources/tile.h186
-rw-r--r--chromium/cc/resources/tile_manager_unittest.cc769
-rw-r--r--chromium/cc/resources/ui_resource_request.h6
-rw-r--r--chromium/cc/resources/video_resource_updater.cc425
-rw-r--r--chromium/cc/resources/video_resource_updater.h55
-rw-r--r--chromium/cc/resources/video_resource_updater_unittest.cc255
-rw-r--r--chromium/cc/resources/zero_copy_raster_worker_pool.cc211
-rw-r--r--chromium/cc/resources/zero_copy_raster_worker_pool.h79
-rw-r--r--chromium/cc/scheduler/begin_frame_source.cc72
-rw-r--r--chromium/cc/scheduler/begin_frame_source.h40
-rw-r--r--chromium/cc/scheduler/begin_frame_source_unittest.cc144
-rw-r--r--chromium/cc/scheduler/commit_earlyout_reason.h40
-rw-r--r--chromium/cc/scheduler/delay_based_time_source.cc39
-rw-r--r--chromium/cc/scheduler/delay_based_time_source.h8
-rw-r--r--chromium/cc/scheduler/delay_based_time_source_unittest.cc17
-rw-r--r--chromium/cc/scheduler/scheduler.cc599
-rw-r--r--chromium/cc/scheduler/scheduler.h93
-rw-r--r--chromium/cc/scheduler/scheduler_settings.cc40
-rw-r--r--chromium/cc/scheduler/scheduler_settings.h18
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.cc655
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.h152
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine_unittest.cc1100
-rw-r--r--chromium/cc/scheduler/scheduler_unittest.cc3649
-rw-r--r--chromium/cc/scheduler/video_frame_controller.h40
-rw-r--r--chromium/cc/surfaces/BUILD.gn17
-rw-r--r--chromium/cc/surfaces/display.cc186
-rw-r--r--chromium/cc/surfaces/display.h35
-rw-r--r--chromium/cc/surfaces/display_client.h3
-rw-r--r--chromium/cc/surfaces/display_unittest.cc239
-rw-r--r--chromium/cc/surfaces/onscreen_display_client.cc96
-rw-r--r--chromium/cc/surfaces/onscreen_display_client.h76
-rw-r--r--chromium/cc/surfaces/surface.cc46
-rw-r--r--chromium/cc/surfaces/surface.h13
-rw-r--r--chromium/cc/surfaces/surface_aggregator.cc277
-rw-r--r--chromium/cc/surfaces/surface_aggregator.h39
-rw-r--r--chromium/cc/surfaces/surface_aggregator_perftest.cc132
-rw-r--r--chromium/cc/surfaces/surface_aggregator_test_helpers.cc4
-rw-r--r--chromium/cc/surfaces/surface_aggregator_test_helpers.h5
-rw-r--r--chromium/cc/surfaces/surface_aggregator_unittest.cc469
-rw-r--r--chromium/cc/surfaces/surface_damage_observer.h4
-rw-r--r--chromium/cc/surfaces/surface_display_output_surface.cc99
-rw-r--r--chromium/cc/surfaces/surface_display_output_surface.h62
-rw-r--r--chromium/cc/surfaces/surface_display_output_surface_unittest.cc147
-rw-r--r--chromium/cc/surfaces/surface_factory.cc14
-rw-r--r--chromium/cc/surfaces/surface_factory.h24
-rw-r--r--chromium/cc/surfaces/surface_factory_unittest.cc47
-rw-r--r--chromium/cc/surfaces/surface_manager.cc8
-rw-r--r--chromium/cc/surfaces/surface_manager.h2
-rw-r--r--chromium/cc/surfaces/surface_unittest.cc4
-rw-r--r--chromium/cc/surfaces/surfaces_pixeltest.cc30
-rw-r--r--chromium/cc/tiles/eviction_tile_priority_queue.cc161
-rw-r--r--chromium/cc/tiles/eviction_tile_priority_queue.h46
-rw-r--r--chromium/cc/tiles/layer_tiling_data.cc (renamed from chromium/cc/resources/layer_tiling_data.cc)2
-rw-r--r--chromium/cc/tiles/layer_tiling_data.h (renamed from chromium/cc/resources/layer_tiling_data.h)8
-rw-r--r--chromium/cc/tiles/picture_layer_tiling.cc1087
-rw-r--r--chromium/cc/tiles/picture_layer_tiling.h (renamed from chromium/cc/resources/picture_layer_tiling.h)343
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_perftest.cc174
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set.cc605
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set.h206
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set_unittest.cc454
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_unittest.cc (renamed from chromium/cc/resources/picture_layer_tiling_unittest.cc)1085
-rw-r--r--chromium/cc/tiles/prioritized_tile.cc41
-rw-r--r--chromium/cc/tiles/prioritized_tile.h46
-rw-r--r--chromium/cc/tiles/raster_tile_priority_queue.cc37
-rw-r--r--chromium/cc/tiles/raster_tile_priority_queue.h42
-rw-r--r--chromium/cc/tiles/raster_tile_priority_queue_all.cc170
-rw-r--r--chromium/cc/tiles/raster_tile_priority_queue_all.h48
-rw-r--r--chromium/cc/tiles/raster_tile_priority_queue_required.cc85
-rw-r--r--chromium/cc/tiles/raster_tile_priority_queue_required.h45
-rw-r--r--chromium/cc/tiles/tile.cc78
-rw-r--r--chromium/cc/tiles/tile.h117
-rw-r--r--chromium/cc/tiles/tile_draw_info.cc25
-rw-r--r--chromium/cc/tiles/tile_draw_info.h106
-rw-r--r--chromium/cc/tiles/tile_manager.cc (renamed from chromium/cc/resources/tile_manager.cc)668
-rw-r--r--chromium/cc/tiles/tile_manager.h (renamed from chromium/cc/resources/tile_manager.h)186
-rw-r--r--chromium/cc/tiles/tile_manager_perftest.cc (renamed from chromium/cc/resources/tile_manager_perftest.cc)200
-rw-r--r--chromium/cc/tiles/tile_manager_unittest.cc1428
-rw-r--r--chromium/cc/tiles/tile_priority.cc (renamed from chromium/cc/resources/tile_priority.cc)8
-rw-r--r--chromium/cc/tiles/tile_priority.h (renamed from chromium/cc/resources/tile_priority.h)49
-rw-r--r--chromium/cc/tiles/tile_priority_unittest.cc (renamed from chromium/cc/resources/tile_priority_unittest.cc)2
-rw-r--r--chromium/cc/tiles/tiling_set_eviction_queue.cc523
-rw-r--r--chromium/cc/tiles/tiling_set_eviction_queue.h203
-rw-r--r--chromium/cc/tiles/tiling_set_raster_queue_all.cc460
-rw-r--r--chromium/cc/tiles/tiling_set_raster_queue_all.h199
-rw-r--r--chromium/cc/tiles/tiling_set_raster_queue_required.cc152
-rw-r--r--chromium/cc/tiles/tiling_set_raster_queue_required.h60
-rw-r--r--chromium/cc/trees/blocking_task_runner_unittest.cc7
-rw-r--r--chromium/cc/trees/damage_tracker.cc3
-rw-r--r--chromium/cc/trees/damage_tracker_unittest.cc35
-rw-r--r--chromium/cc/trees/draw_property_utils.cc595
-rw-r--r--chromium/cc/trees/draw_property_utils.h92
-rw-r--r--chromium/cc/trees/latency_info_swap_promise_monitor.cc (renamed from chromium/cc/base/latency_info_swap_promise_monitor.cc)49
-rw-r--r--chromium/cc/trees/latency_info_swap_promise_monitor.h (renamed from chromium/cc/base/latency_info_swap_promise_monitor.h)8
-rw-r--r--chromium/cc/trees/layer_sorter.cc470
-rw-r--r--chromium/cc/trees/layer_sorter.h101
-rw-r--r--chromium/cc/trees/layer_sorter_unittest.cc329
-rw-r--r--chromium/cc/trees/layer_tree_host.cc637
-rw-r--r--chromium/cc/trees/layer_tree_host.h183
-rw-r--r--chromium/cc/trees/layer_tree_host_client.h33
-rw-r--r--chromium/cc/trees/layer_tree_host_common.cc771
-rw-r--r--chromium/cc/trees/layer_tree_host_common.h99
-rw-r--r--chromium/cc/trees/layer_tree_host_common_perftest.cc112
-rw-r--r--chromium/cc/trees/layer_tree_host_common_unittest.cc2244
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc2181
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h302
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc4010
-rw-r--r--chromium/cc/trees/layer_tree_host_perftest.cc10
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_blending.cc287
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_filters.cc182
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_masks.cc279
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc125
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_readback.cc826
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc30
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc2979
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_animation.cc538
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_context.cc219
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc129
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_damage.cc96
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_delegated.cc143
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_no_message_loop.cc30
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_occlusion.cc743
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_picture.cc481
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_proxy.cc8
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_scroll.cc193
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc933
-rw-r--r--chromium/cc/trees/layer_tree_impl.h233
-rw-r--r--chromium/cc/trees/layer_tree_impl_unittest.cc916
-rw-r--r--chromium/cc/trees/layer_tree_settings.cc57
-rw-r--r--chromium/cc/trees/layer_tree_settings.h42
-rw-r--r--chromium/cc/trees/occlusion.cc12
-rw-r--r--chromium/cc/trees/occlusion.h5
-rw-r--r--chromium/cc/trees/occlusion_tracker.cc125
-rw-r--r--chromium/cc/trees/occlusion_tracker.h23
-rw-r--r--chromium/cc/trees/occlusion_tracker_perftest.cc17
-rw-r--r--chromium/cc/trees/occlusion_tracker_unittest.cc220
-rw-r--r--chromium/cc/trees/property_tree.cc388
-rw-r--r--chromium/cc/trees/property_tree.h261
-rw-r--r--chromium/cc/trees/property_tree_builder.cc459
-rw-r--r--chromium/cc/trees/property_tree_builder.h39
-rw-r--r--chromium/cc/trees/property_tree_unittest.cc467
-rw-r--r--chromium/cc/trees/proxy.cc12
-rw-r--r--chromium/cc/trees/proxy.h23
-rw-r--r--chromium/cc/trees/proxy_timing_history.cc11
-rw-r--r--chromium/cc/trees/scoped_abort_remaining_swap_promises.h2
-rw-r--r--chromium/cc/trees/single_thread_proxy.cc503
-rw-r--r--chromium/cc/trees/single_thread_proxy.h65
-rw-r--r--chromium/cc/trees/swap_promise_monitor.cc (renamed from chromium/cc/base/swap_promise_monitor.cc)2
-rw-r--r--chromium/cc/trees/swap_promise_monitor.h (renamed from chromium/cc/base/swap_promise_monitor.h)6
-rw-r--r--chromium/cc/trees/thread_proxy.cc367
-rw-r--r--chromium/cc/trees/thread_proxy.h60
-rw-r--r--chromium/cc/trees/tree_synchronizer.cc7
-rw-r--r--chromium/cc/trees/tree_synchronizer_unittest.cc27
659 files changed, 58557 insertions, 36980 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
index e9ef9e27285..7001440e61a 100644
--- a/chromium/cc/BUILD.gn
+++ b/chromium/cc/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//testing/test.gni")
+
component("cc") {
sources = [
"animation/animation.cc",
@@ -24,8 +26,8 @@ component("cc") {
"animation/layer_animation_value_provider.h",
"animation/scroll_offset_animation_curve.cc",
"animation/scroll_offset_animation_curve.h",
- "animation/scrollbar_animation_controller.h",
"animation/scrollbar_animation_controller.cc",
+ "animation/scrollbar_animation_controller.h",
"animation/scrollbar_animation_controller_linear_fade.cc",
"animation/scrollbar_animation_controller_linear_fade.h",
"animation/scrollbar_animation_controller_thinning.cc",
@@ -36,37 +38,6 @@ component("cc") {
"animation/transform_operation.h",
"animation/transform_operations.cc",
"animation/transform_operations.h",
- "base/completion_event.h",
- "base/delayed_unique_notifier.cc",
- "base/delayed_unique_notifier.h",
- "base/invalidation_region.cc",
- "base/invalidation_region.h",
- "base/latency_info_swap_promise.cc",
- "base/latency_info_swap_promise.h",
- "base/latency_info_swap_promise_monitor.cc",
- "base/latency_info_swap_promise_monitor.h",
- "base/math_util.cc",
- "base/math_util.h",
- "base/ref_counted_managed.h",
- "base/region.cc",
- "base/region.h",
- "base/rolling_time_delta_history.cc",
- "base/rolling_time_delta_history.h",
- "base/scoped_ptr_algorithm.h",
- "base/scoped_ptr_deque.h",
- "base/scoped_ptr_vector.h",
- "base/simple_enclosed_region.cc",
- "base/simple_enclosed_region.h",
- "base/swap_promise.h",
- "base/swap_promise_monitor.cc",
- "base/swap_promise_monitor.h",
- "base/switches.cc",
- "base/switches.h",
- "base/tiling_data.cc",
- "base/tiling_data.h",
- "base/unique_notifier.cc",
- "base/unique_notifier.h",
- "base/util.h",
"debug/benchmark_instrumentation.cc",
"debug/benchmark_instrumentation.h",
"debug/debug_colors.cc",
@@ -76,6 +47,11 @@ component("cc") {
"debug/devtools_instrumentation.h",
"debug/frame_rate_counter.cc",
"debug/frame_rate_counter.h",
+ "debug/frame_timing_request.cc",
+ "debug/frame_timing_request.h",
+ "debug/frame_timing_tracker.cc",
+ "debug/frame_timing_tracker.h",
+ "debug/frame_viewer_instrumentation.cc",
"debug/frame_viewer_instrumentation.h",
"debug/invalidation_benchmark.cc",
"debug/invalidation_benchmark.h",
@@ -85,14 +61,16 @@ component("cc") {
"debug/layer_tree_debug_state.h",
"debug/micro_benchmark.cc",
"debug/micro_benchmark.h",
- "debug/micro_benchmark_impl.cc",
- "debug/micro_benchmark_impl.h",
"debug/micro_benchmark_controller.cc",
"debug/micro_benchmark_controller.h",
"debug/micro_benchmark_controller_impl.cc",
"debug/micro_benchmark_controller_impl.h",
+ "debug/micro_benchmark_impl.cc",
+ "debug/micro_benchmark_impl.h",
"debug/paint_time_counter.cc",
"debug/paint_time_counter.h",
+ "debug/picture_debug_util.cc",
+ "debug/picture_debug_util.h",
"debug/picture_record_benchmark.cc",
"debug/picture_record_benchmark.h",
"debug/rasterize_and_record_benchmark.cc",
@@ -114,10 +92,13 @@ component("cc") {
"debug/unittest_only_benchmark_impl.h",
"input/input_handler.cc",
"input/input_handler.h",
- "input/page_scale_animation.cc",
- "input/page_scale_animation.h",
"input/layer_selection_bound.cc",
"input/layer_selection_bound.h",
+ "input/page_scale_animation.cc",
+ "input/page_scale_animation.h",
+ "input/scroll_elasticity_helper.cc",
+ "input/scroll_elasticity_helper.h",
+ "input/selection.h",
"input/selection_bound_type.h",
"input/top_controls_manager.cc",
"input/top_controls_manager.h",
@@ -216,6 +197,8 @@ component("cc") {
"layers/video_layer.h",
"layers/video_layer_impl.cc",
"layers/video_layer_impl.h",
+ "layers/viewport.cc",
+ "layers/viewport.h",
"output/begin_frame_args.cc",
"output/begin_frame_args.h",
"output/bsp_tree.cc",
@@ -240,6 +223,8 @@ component("cc") {
"output/delegating_renderer.h",
"output/direct_renderer.cc",
"output/direct_renderer.h",
+ "output/dynamic_geometry_binding.cc",
+ "output/dynamic_geometry_binding.h",
"output/filter_operation.cc",
"output/filter_operation.h",
"output/filter_operations.cc",
@@ -252,6 +237,10 @@ component("cc") {
"output/gl_renderer.h",
"output/gl_renderer_draw_cache.cc",
"output/gl_renderer_draw_cache.h",
+ "output/latency_info_swap_promise.cc",
+ "output/latency_info_swap_promise.h",
+ "output/layer_quad.cc",
+ "output/layer_quad.h",
"output/managed_memory_policy.cc",
"output/managed_memory_policy.h",
"output/output_surface.cc",
@@ -262,14 +251,22 @@ component("cc") {
"output/overlay_candidate_validator.h",
"output/overlay_processor.cc",
"output/overlay_processor.h",
+ "output/overlay_strategy_common.cc",
+ "output/overlay_strategy_common.h",
"output/overlay_strategy_single_on_top.cc",
"output/overlay_strategy_single_on_top.h",
+ "output/overlay_strategy_underlay.cc",
+ "output/overlay_strategy_underlay.h",
"output/program_binding.cc",
"output/program_binding.h",
"output/render_surface_filters.cc",
"output/render_surface_filters.h",
"output/renderer.cc",
"output/renderer.h",
+ "output/renderer_capabilities.cc",
+ "output/renderer_capabilities.h",
+ "output/renderer_settings.cc",
+ "output/renderer_settings.h",
"output/shader.cc",
"output/shader.h",
"output/software_frame_data.cc",
@@ -278,9 +275,49 @@ component("cc") {
"output/software_output_device.h",
"output/software_renderer.cc",
"output/software_renderer.h",
+ "output/static_geometry_binding.cc",
+ "output/static_geometry_binding.h",
+ "output/swap_promise.h",
+ "output/texture_mailbox_deleter.cc",
+ "output/texture_mailbox_deleter.h",
"output/viewport_selection_bound.cc",
"output/viewport_selection_bound.h",
"output/vsync_parameter_observer.h",
+ "playback/clip_display_item.cc",
+ "playback/clip_display_item.h",
+ "playback/clip_path_display_item.cc",
+ "playback/clip_path_display_item.h",
+ "playback/compositing_display_item.cc",
+ "playback/compositing_display_item.h",
+ "playback/display_item.cc",
+ "playback/display_item.h",
+ "playback/display_item_list.cc",
+ "playback/display_item_list.h",
+ "playback/display_list_raster_source.cc",
+ "playback/display_list_raster_source.h",
+ "playback/display_list_recording_source.cc",
+ "playback/display_list_recording_source.h",
+ "playback/drawing_display_item.cc",
+ "playback/drawing_display_item.h",
+ "playback/filter_display_item.cc",
+ "playback/filter_display_item.h",
+ "playback/float_clip_display_item.cc",
+ "playback/float_clip_display_item.h",
+ "playback/largest_display_item.cc",
+ "playback/largest_display_item.h",
+ "playback/picture.cc",
+ "playback/picture.h",
+ "playback/picture_pile.cc",
+ "playback/picture_pile.h",
+ "playback/picture_pile_impl.cc",
+ "playback/picture_pile_impl.h",
+ "playback/pixel_ref_map.cc",
+ "playback/pixel_ref_map.h",
+ "playback/raster_source.h",
+ "playback/raster_source_helper.cc",
+ "playback/raster_source_helper.h",
+ "playback/transform_display_item.cc",
+ "playback/transform_display_item.h",
"quads/checkerboard_draw_quad.cc",
"quads/checkerboard_draw_quad.h",
"quads/content_draw_quad_base.cc",
@@ -293,8 +330,8 @@ component("cc") {
"quads/draw_quad.h",
"quads/io_surface_draw_quad.cc",
"quads/io_surface_draw_quad.h",
- "quads/largest_draw_quad.h",
"quads/largest_draw_quad.cc",
+ "quads/largest_draw_quad.h",
"quads/list_container.cc",
"quads/list_container.h",
"quads/picture_draw_quad.cc",
@@ -319,47 +356,45 @@ component("cc") {
"quads/tile_draw_quad.h",
"quads/yuv_video_draw_quad.cc",
"quads/yuv_video_draw_quad.h",
+ "raster/bitmap_tile_task_worker_pool.cc",
+ "raster/bitmap_tile_task_worker_pool.h",
+ "raster/gpu_rasterizer.cc",
+ "raster/gpu_rasterizer.h",
+ "raster/gpu_tile_task_worker_pool.cc",
+ "raster/gpu_tile_task_worker_pool.h",
+ "raster/one_copy_tile_task_worker_pool.cc",
+ "raster/one_copy_tile_task_worker_pool.h",
+ "raster/pixel_buffer_tile_task_worker_pool.cc",
+ "raster/pixel_buffer_tile_task_worker_pool.h",
+ "raster/raster_buffer.cc",
+ "raster/raster_buffer.h",
+ "raster/scoped_gpu_raster.cc",
+ "raster/scoped_gpu_raster.h",
+ "raster/task_graph_runner.cc",
+ "raster/task_graph_runner.h",
+ "raster/texture_compressor.cc",
+ "raster/texture_compressor.h",
+ "raster/texture_compressor_etc1.cc",
+ "raster/texture_compressor_etc1.h",
+ "raster/tile_task_runner.cc",
+ "raster/tile_task_runner.h",
+ "raster/tile_task_worker_pool.cc",
+ "raster/tile_task_worker_pool.h",
+ "raster/zero_copy_tile_task_worker_pool.cc",
+ "raster/zero_copy_tile_task_worker_pool.h",
"resources/bitmap_content_layer_updater.cc",
"resources/bitmap_content_layer_updater.h",
- "resources/bitmap_raster_worker_pool.cc",
- "resources/bitmap_raster_worker_pool.h",
"resources/bitmap_skpicture_content_layer_updater.cc",
"resources/bitmap_skpicture_content_layer_updater.h",
"resources/content_layer_updater.cc",
"resources/content_layer_updater.h",
- "resources/eviction_tile_priority_queue.cc",
- "resources/eviction_tile_priority_queue.h",
- "resources/gpu_raster_worker_pool.cc",
- "resources/gpu_raster_worker_pool.h",
"resources/image_layer_updater.cc",
"resources/image_layer_updater.h",
"resources/layer_painter.h",
- "resources/layer_quad.cc",
- "resources/layer_quad.h",
- "resources/layer_tiling_data.cc",
- "resources/layer_tiling_data.h",
"resources/layer_updater.cc",
"resources/layer_updater.h",
- "resources/managed_tile_state.cc",
- "resources/managed_tile_state.h",
"resources/memory_history.cc",
"resources/memory_history.h",
- "resources/one_copy_raster_worker_pool.cc",
- "resources/one_copy_raster_worker_pool.h",
- "resources/picture.cc",
- "resources/picture.h",
- "resources/picture_layer_tiling.cc",
- "resources/picture_layer_tiling.h",
- "resources/picture_layer_tiling_set.cc",
- "resources/picture_layer_tiling_set.h",
- "resources/picture_pile.cc",
- "resources/picture_pile.h",
- "resources/picture_pile_base.cc",
- "resources/picture_pile_base.h",
- "resources/picture_pile_impl.cc",
- "resources/picture_pile_impl.h",
- "resources/pixel_buffer_raster_worker_pool.cc",
- "resources/pixel_buffer_raster_worker_pool.h",
"resources/platform_color.h",
"resources/prioritized_resource.cc",
"resources/prioritized_resource.h",
@@ -367,15 +402,6 @@ component("cc") {
"resources/prioritized_resource_manager.h",
"resources/priority_calculator.cc",
"resources/priority_calculator.h",
- "resources/raster_buffer.cc",
- "resources/raster_buffer.h",
- "resources/raster_source.h",
- "resources/raster_tile_priority_queue.cc",
- "resources/raster_tile_priority_queue.h",
- "resources/raster_worker_pool.cc",
- "resources/raster_worker_pool.h",
- "resources/rasterizer.cc",
- "resources/rasterizer.h",
"resources/release_callback.h",
"resources/resource.cc",
"resources/resource.h",
@@ -392,8 +418,6 @@ component("cc") {
"resources/resource_update_queue.cc",
"resources/resource_update_queue.h",
"resources/returned_resource.h",
- "resources/scoped_gpu_raster.cc",
- "resources/scoped_gpu_raster.h",
"resources/scoped_resource.cc",
"resources/scoped_resource.h",
"resources/scoped_ui_resource.cc",
@@ -407,20 +431,10 @@ component("cc") {
"resources/single_release_callback_impl.h",
"resources/skpicture_content_layer_updater.cc",
"resources/skpicture_content_layer_updater.h",
- "resources/task_graph_runner.cc",
- "resources/task_graph_runner.h",
"resources/texture_mailbox.cc",
"resources/texture_mailbox.h",
- "resources/texture_mailbox_deleter.cc",
- "resources/texture_mailbox_deleter.h",
"resources/texture_uploader.cc",
"resources/texture_uploader.h",
- "resources/tile.cc",
- "resources/tile.h",
- "resources/tile_manager.cc",
- "resources/tile_manager.h",
- "resources/tile_priority.cc",
- "resources/tile_priority.h",
"resources/transferable_resource.cc",
"resources/transferable_resource.h",
"resources/ui_resource_bitmap.cc",
@@ -430,10 +444,9 @@ component("cc") {
"resources/ui_resource_request.h",
"resources/video_resource_updater.cc",
"resources/video_resource_updater.h",
- "resources/zero_copy_raster_worker_pool.cc",
- "resources/zero_copy_raster_worker_pool.h",
"scheduler/begin_frame_source.cc",
"scheduler/begin_frame_source.h",
+ "scheduler/commit_earlyout_reason.h",
"scheduler/delay_based_time_source.cc",
"scheduler/delay_based_time_source.h",
"scheduler/draw_result.h",
@@ -443,12 +456,45 @@ component("cc") {
"scheduler/scheduler_settings.h",
"scheduler/scheduler_state_machine.cc",
"scheduler/scheduler_state_machine.h",
+ "scheduler/video_frame_controller.h",
+ "tiles/eviction_tile_priority_queue.cc",
+ "tiles/eviction_tile_priority_queue.h",
+ "tiles/layer_tiling_data.cc",
+ "tiles/layer_tiling_data.h",
+ "tiles/picture_layer_tiling.cc",
+ "tiles/picture_layer_tiling.h",
+ "tiles/picture_layer_tiling_set.cc",
+ "tiles/picture_layer_tiling_set.h",
+ "tiles/prioritized_tile.cc",
+ "tiles/prioritized_tile.h",
+ "tiles/raster_tile_priority_queue.cc",
+ "tiles/raster_tile_priority_queue.h",
+ "tiles/raster_tile_priority_queue_all.cc",
+ "tiles/raster_tile_priority_queue_all.h",
+ "tiles/raster_tile_priority_queue_required.cc",
+ "tiles/raster_tile_priority_queue_required.h",
+ "tiles/tile.cc",
+ "tiles/tile.h",
+ "tiles/tile_draw_info.cc",
+ "tiles/tile_draw_info.h",
+ "tiles/tile_manager.cc",
+ "tiles/tile_manager.h",
+ "tiles/tile_priority.cc",
+ "tiles/tile_priority.h",
+ "tiles/tiling_set_eviction_queue.cc",
+ "tiles/tiling_set_eviction_queue.h",
+ "tiles/tiling_set_raster_queue_all.cc",
+ "tiles/tiling_set_raster_queue_all.h",
+ "tiles/tiling_set_raster_queue_required.cc",
+ "tiles/tiling_set_raster_queue_required.h",
"trees/blocking_task_runner.cc",
"trees/blocking_task_runner.h",
"trees/damage_tracker.cc",
"trees/damage_tracker.h",
- "trees/layer_sorter.cc",
- "trees/layer_sorter.h",
+ "trees/draw_property_utils.cc",
+ "trees/draw_property_utils.h",
+ "trees/latency_info_swap_promise_monitor.cc",
+ "trees/latency_info_swap_promise_monitor.h",
"trees/layer_tree_host.cc",
"trees/layer_tree_host.h",
"trees/layer_tree_host_client.h",
@@ -456,6 +502,7 @@ component("cc") {
"trees/layer_tree_host_common.h",
"trees/layer_tree_host_impl.cc",
"trees/layer_tree_host_impl.h",
+ "trees/layer_tree_host_single_thread_client.h",
"trees/layer_tree_impl.cc",
"trees/layer_tree_impl.h",
"trees/layer_tree_settings.cc",
@@ -464,6 +511,10 @@ component("cc") {
"trees/occlusion.h",
"trees/occlusion_tracker.cc",
"trees/occlusion_tracker.h",
+ "trees/property_tree.cc",
+ "trees/property_tree.h",
+ "trees/property_tree_builder.cc",
+ "trees/property_tree_builder.h",
"trees/proxy.cc",
"trees/proxy.h",
"trees/proxy_timing_history.cc",
@@ -471,26 +522,28 @@ component("cc") {
"trees/scoped_abort_remaining_swap_promises.h",
"trees/single_thread_proxy.cc",
"trees/single_thread_proxy.h",
+ "trees/swap_promise_monitor.cc",
+ "trees/swap_promise_monitor.h",
"trees/thread_proxy.cc",
"trees/thread_proxy.h",
"trees/tree_synchronizer.cc",
"trees/tree_synchronizer.h",
]
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ] # size_t -> int
- }
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
public_deps = [
+ "//cc/base",
"//skia",
]
deps = [
"//base",
"//base/third_party/dynamic_annotations",
+ "//cc:cc_opts",
+ "//cc/surfaces:surface_id",
"//gpu",
"//gpu/command_buffer/client:gles2_interface",
- "//gpu/command_buffer/client:gpu_memory_buffer_manager",
"//media",
"//ui/events:events_base",
"//ui/gfx",
@@ -505,6 +558,36 @@ component("cc") {
}
}
+source_set("cc_opts") {
+ public_deps = [
+ "//cc:cc_opts_sse",
+ ]
+}
+
+source_set("cc_opts_sse") {
+ if (target_cpu == "x86" || target_cpu == "x64") {
+ deps = [
+ "//base",
+ ]
+
+ defines = [ "CC_IMPLEMENTATION=1" ]
+
+ if (!is_debug && (is_win || is_android)) {
+ configs -= [ "//build/config/compiler:optimize" ]
+ configs += [ "//build/config/compiler:optimize_max" ]
+ }
+
+ sources = [
+ "raster/texture_compressor.h",
+ "raster/texture_compressor_etc1.h",
+ "raster/texture_compressor_etc1_sse.cc",
+ "raster/texture_compressor_etc1_sse.h",
+ ]
+
+ cflags = [ "-msse2" ]
+ }
+}
+
source_set("test_support") {
testonly = true
sources = [
@@ -512,6 +595,8 @@ source_set("test_support") {
"test/animation_test_common.h",
"test/begin_frame_args_test.cc",
"test/begin_frame_args_test.h",
+ "test/failure_output_surface.cc",
+ "test/failure_output_surface.h",
"test/fake_content_layer.cc",
"test/fake_content_layer.h",
"test/fake_content_layer_client.cc",
@@ -522,6 +607,9 @@ source_set("test_support") {
"test/fake_delegated_renderer_layer.h",
"test/fake_delegated_renderer_layer_impl.cc",
"test/fake_delegated_renderer_layer_impl.h",
+ "test/fake_display_list_recording_source.h",
+ "test/fake_external_begin_frame_source.cc",
+ "test/fake_external_begin_frame_source.h",
"test/fake_impl_proxy.h",
"test/fake_layer_tree_host.cc",
"test/fake_layer_tree_host.h",
@@ -543,6 +631,8 @@ source_set("test_support") {
"test/fake_picture_layer_impl.h",
"test/fake_picture_layer_tiling_client.cc",
"test/fake_picture_layer_tiling_client.h",
+ "test/fake_picture_pile.cc",
+ "test/fake_picture_pile.h",
"test/fake_picture_pile_impl.cc",
"test/fake_picture_pile_impl.h",
"test/fake_proxy.cc",
@@ -564,8 +654,6 @@ source_set("test_support") {
"test/fake_video_frame_provider.h",
"test/geometry_test_utils.cc",
"test/geometry_test_utils.h",
- "test/test_in_process_context_provider.cc",
- "test/test_in_process_context_provider.h",
"test/impl_side_painting_settings.h",
"test/layer_test_common.cc",
"test/layer_test_common.h",
@@ -616,11 +704,15 @@ source_set("test_support") {
"test/test_gpu_memory_buffer_manager.h",
"test/test_image_factory.cc",
"test/test_image_factory.h",
+ "test/test_in_process_context_provider.cc",
+ "test/test_in_process_context_provider.h",
"test/test_now_source.cc",
"test/test_now_source.h",
"test/test_occlusion_tracker.h",
"test/test_shared_bitmap_manager.cc",
"test/test_shared_bitmap_manager.h",
+ "test/test_task_graph_runner.cc",
+ "test/test_task_graph_runner.h",
"test/test_texture.cc",
"test/test_texture.h",
"test/test_tile_priorities.cc",
@@ -631,6 +723,8 @@ source_set("test_support") {
"test/tiled_layer_test_common.h",
]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
include_dirs = [
".",
"test",
@@ -642,13 +736,14 @@ source_set("test_support") {
]
deps = [
"//base",
+ "//base/test:test_support",
"//base/third_party/dynamic_annotations",
"//gpu/command_buffer/client:gles2_c_lib",
"//gpu/command_buffer/client:gles2_implementation",
- "//gpu/command_buffer/client:gpu_memory_buffer_manager",
"//gpu/command_buffer/client:gl_in_process_context",
"//gpu/command_buffer/common:gles2_utils",
"//gpu/skia_bindings",
+ "//media",
"//skia",
"//testing/gmock",
"//testing/gtest",
@@ -680,6 +775,7 @@ test("cc_unittests") {
"base/simple_enclosed_region_unittest.cc",
"base/tiling_data_unittest.cc",
"base/util_unittest.cc",
+ "debug/frame_timing_tracker_unittest.cc",
"debug/micro_benchmark_controller_unittest.cc",
"input/top_controls_manager_unittest.cc",
"layers/contents_scaling_layer_unittest.cc",
@@ -687,8 +783,8 @@ test("cc_unittests") {
"layers/delegated_frame_resource_collection_unittest.cc",
"layers/delegated_renderer_layer_impl_unittest.cc",
"layers/delegated_renderer_layer_unittest.cc",
- "layers/heads_up_display_unittest.cc",
"layers/heads_up_display_layer_impl_unittest.cc",
+ "layers/heads_up_display_unittest.cc",
"layers/io_surface_layer_impl_unittest.cc",
"layers/layer_impl_unittest.cc",
"layers/layer_iterator_unittest.cc",
@@ -699,17 +795,18 @@ test("cc_unittests") {
"layers/nine_patch_layer_unittest.cc",
"layers/painted_scrollbar_layer_impl_unittest.cc",
"layers/picture_image_layer_impl_unittest.cc",
+ "layers/picture_image_layer_unittest.cc",
"layers/picture_layer_impl_unittest.cc",
"layers/picture_layer_unittest.cc",
- "layers/render_surface_unittest.cc",
"layers/render_surface_impl_unittest.cc",
+ "layers/render_surface_unittest.cc",
"layers/scrollbar_layer_unittest.cc",
"layers/solid_color_layer_impl_unittest.cc",
"layers/solid_color_scrollbar_layer_impl_unittest.cc",
- "layers/surface_layer_unittest.cc",
"layers/surface_layer_impl_unittest.cc",
- "layers/texture_layer_unittest.cc",
+ "layers/surface_layer_unittest.cc",
"layers/texture_layer_impl_unittest.cc",
+ "layers/texture_layer_unittest.cc",
"layers/tiled_layer_impl_unittest.cc",
"layers/tiled_layer_unittest.cc",
"layers/ui_resource_layer_impl_unittest.cc",
@@ -719,31 +816,34 @@ test("cc_unittests") {
"output/delegating_renderer_unittest.cc",
"output/filter_operations_unittest.cc",
"output/gl_renderer_unittest.cc",
+ "output/layer_quad_unittest.cc",
"output/output_surface_unittest.cc",
"output/overlay_unittest.cc",
"output/renderer_pixeltest.cc",
"output/renderer_unittest.cc",
"output/shader_unittest.cc",
"output/software_renderer_unittest.cc",
+ "output/texture_mailbox_deleter_unittest.cc",
+ "playback/display_item_list_unittest.cc",
+ "playback/display_list_recording_source_unittest.cc",
+ "playback/picture_pile_impl_unittest.cc",
+ "playback/picture_pile_unittest.cc",
+ "playback/picture_unittest.cc",
+ "playback/pixel_ref_map_unittest.cc",
+ "playback/recording_source_unittest.cc",
"quads/draw_quad_unittest.cc",
"quads/list_container_unittest.cc",
"quads/render_pass_unittest.cc",
- "resources/layer_quad_unittest.cc",
- "resources/picture_layer_tiling_set_unittest.cc",
- "resources/picture_layer_tiling_unittest.cc",
- "resources/picture_pile_impl_unittest.cc",
- "resources/picture_pile_unittest.cc",
- "resources/picture_unittest.cc",
+ "raster/scoped_gpu_raster_unittest.cc",
+ "raster/task_graph_runner_unittest.cc",
+ "raster/texture_compressor_etc1_unittest.cc",
+ "raster/tile_task_worker_pool_unittest.cc",
+ "resources/platform_color_unittest.cc",
"resources/prioritized_resource_unittest.cc",
- "resources/raster_worker_pool_unittest.cc",
"resources/resource_provider_unittest.cc",
"resources/resource_update_controller_unittest.cc",
"resources/scoped_resource_unittest.cc",
- "resources/task_graph_runner_unittest.cc",
- "resources/texture_mailbox_deleter_unittest.cc",
"resources/texture_uploader_unittest.cc",
- "resources/tile_manager_unittest.cc",
- "resources/tile_priority_unittest.cc",
"resources/video_resource_updater_unittest.cc",
"scheduler/begin_frame_source_unittest.cc",
"scheduler/delay_based_time_source_unittest.cc",
@@ -751,15 +851,17 @@ test("cc_unittests") {
"scheduler/scheduler_unittest.cc",
"test/layer_tree_json_parser_unittest.cc",
"test/test_web_graphics_context_3d_unittest.cc",
+ "tiles/picture_layer_tiling_set_unittest.cc",
+ "tiles/picture_layer_tiling_unittest.cc",
+ "tiles/tile_manager_unittest.cc",
+ "tiles/tile_priority_unittest.cc",
"trees/blocking_task_runner_unittest.cc",
"trees/damage_tracker_unittest.cc",
- "trees/layer_sorter_unittest.cc",
"trees/layer_tree_host_common_unittest.cc",
"trees/layer_tree_host_impl_unittest.cc",
"trees/layer_tree_host_pixeltest_blending.cc",
"trees/layer_tree_host_pixeltest_filters.cc",
"trees/layer_tree_host_pixeltest_masks.cc",
- "trees/layer_tree_host_pixeltest_on_demand_raster.cc",
"trees/layer_tree_host_pixeltest_readback.cc",
"trees/layer_tree_host_pixeltest_synchronous.cc",
"trees/layer_tree_host_unittest.cc",
@@ -768,8 +870,8 @@ test("cc_unittests") {
"trees/layer_tree_host_unittest_copyrequest.cc",
"trees/layer_tree_host_unittest_damage.cc",
"trees/layer_tree_host_unittest_delegated.cc",
- "trees/layer_tree_host_unittest_occlusion.cc",
"trees/layer_tree_host_unittest_no_message_loop.cc",
+ "trees/layer_tree_host_unittest_occlusion.cc",
"trees/layer_tree_host_unittest_picture.cc",
"trees/layer_tree_host_unittest_proxy.cc",
"trees/layer_tree_host_unittest_scroll.cc",
@@ -777,6 +879,7 @@ test("cc_unittests") {
"trees/layer_tree_impl_unittest.cc",
"trees/occlusion_tracker_unittest.cc",
"trees/occlusion_unittest.cc",
+ "trees/property_tree_unittest.cc",
"trees/tree_synchronizer_unittest.cc",
# Surfaces test files.
@@ -787,15 +890,18 @@ test("cc_unittests") {
"surfaces/surfaces_pixeltest.cc",
# Setup.
- "test/run_all_unittests.cc",
"test/cc_test_suite.cc",
+ "test/run_all_unittests.cc",
]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
deps = [
":cc",
":test_support",
"//base/test:test_support",
"//cc/surfaces",
+ "//cc/surfaces:surface_id",
"//gpu",
"//gpu:test_support",
"//gpu/command_buffer/client:gles2_interface",
@@ -806,6 +912,8 @@ test("cc_unittests") {
"//ui/events:events_base",
"//ui/gfx",
"//ui/gfx/geometry",
+ "//ui/gfx:test_support",
+ "//ui/gl",
]
}
@@ -813,22 +921,29 @@ test("cc_perftests") {
sources = [
"layers/layer_perftest.cc",
"layers/picture_layer_impl_perftest.cc",
- "resources/picture_layer_tiling_perftest.cc",
- "resources/picture_pile_impl_perftest.cc",
- "resources/raster_worker_pool_perftest.cc",
- "resources/task_graph_runner_perftest.cc",
- "resources/tile_manager_perftest.cc",
+ "playback/picture_pile_impl_perftest.cc",
+ "raster/task_graph_runner_perftest.cc",
+ "raster/texture_compressor_perftest.cc",
+ "raster/tile_task_worker_pool_perftest.cc",
+ "surfaces/surface_aggregator_perftest.cc",
"test/cc_test_suite.cc",
"test/run_all_perftests.cc",
+ "tiles/picture_layer_tiling_perftest.cc",
+ "tiles/tile_manager_perftest.cc",
"trees/layer_tree_host_common_perftest.cc",
"trees/layer_tree_host_perftest.cc",
"trees/occlusion_tracker_perftest.cc",
]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
deps = [
":cc",
":test_support",
"//base",
+ "//base/test:test_support",
+ "//cc/surfaces",
+ "//cc/surfaces:surface_id",
"//gpu",
"//gpu:test_support",
"//gpu/command_buffer/common:gles2_utils",
@@ -839,5 +954,8 @@ test("cc_perftests") {
"//testing/perf",
"//ui/gfx",
"//ui/gfx/geometry",
+ "//ui/gl",
]
}
+# When adding support for isolates, please have a look at run-time dependencies
+# in the cc_unittests_run target in cc_tests.gyp.
diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS
index f213e28b561..b0bce1de929 100644
--- a/chromium/cc/OWNERS
+++ b/chromium/cc/OWNERS
@@ -23,9 +23,14 @@ ccameron@chromium.org
# input, gestures, scrolling
aelias@chromium.org
-jamesr@chromium.org
-# scheduling and texture uploading
+# scheduling / begin frames
+brianderson@chromium.org
+skyostil@chromium.org
+mithro@mithis.com
+sunnyps@chromium.org
+
+# texture uploading
brianderson@chromium.org
reveman@chromium.org
skyostil@chromium.org
diff --git a/chromium/cc/PRESUBMIT.py b/chromium/cc/PRESUBMIT.py
index 46c3a54349e..fa15632fd45 100644
--- a/chromium/cc/PRESUBMIT.py
+++ b/chromium/cc/PRESUBMIT.py
@@ -11,28 +11,14 @@ for more details about the presubmit API built into depot_tools.
import re
import string
-CC_SOURCE_FILES=(r'^cc/.*\.(cc|h)$',)
+CC_SOURCE_FILES=(r'^cc[\\/].*\.(cc|h)$',)
def CheckChangeLintsClean(input_api, output_api):
- input_api.cpplint._cpplint_state.ResetErrorCounts() # reset global state
source_filter = lambda x: input_api.FilterSourceFile(
x, white_list=CC_SOURCE_FILES, black_list=None)
- files = [f.AbsoluteLocalPath() for f in
- input_api.AffectedSourceFiles(source_filter)]
- level = 1 # strict, but just warn
- # TODO(danakj): Temporary, while the OVERRIDE and FINAL fixup is in progress.
- # crbug.com/422353
- input_api.cpplint._SetFilters('-readability/inheritance')
-
- for file_name in files:
- input_api.cpplint.ProcessFile(file_name, level)
-
- if not input_api.cpplint._cpplint_state.error_count:
- return []
-
- return [output_api.PresubmitPromptWarning(
- 'Changelist failed cpplint.py check.')]
+ return input_api.canned_checks.CheckChangeLintsClean(
+ input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
def CheckAsserts(input_api, output_api, white_list=CC_SOURCE_FILES, black_list=None):
black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
diff --git a/chromium/cc/animation/animation.cc b/chromium/cc/animation/animation.cc
index e49cf1e56ff..96cb40ae712 100644
--- a/chromium/cc/animation/animation.cc
+++ b/chromium/cc/animation/animation.cc
@@ -6,39 +6,38 @@
#include <cmath>
-#include "base/debug/trace_event.h"
#include "base/strings/string_util.h"
+#include "base/trace_event/trace_event.h"
#include "cc/animation/animation_curve.h"
+#include "cc/base/time_util.h"
namespace {
// This should match the RunState enum.
-static const char* const s_runStateNames[] = {
- "WaitingForTargetAvailability",
- "WaitingForDeletion",
- "Starting",
- "Running",
- "Paused",
- "Finished",
- "Aborted"
-};
-
-COMPILE_ASSERT(static_cast<int>(cc::Animation::RunStateEnumSize) ==
- arraysize(s_runStateNames),
- RunState_names_match_enum);
+static const char* const s_runStateNames[] = {"WAITING_FOR_TARGET_AVAILABILITY",
+ "WAITING_FOR_DELETION",
+ "STARTING",
+ "RUNNING",
+ "PAUSED",
+ "FINISHED",
+ "ABORTED"};
+
+static_assert(static_cast<int>(cc::Animation::LAST_RUN_STATE) + 1 ==
+ arraysize(s_runStateNames),
+ "RunStateEnumSize should equal the number of elements in "
+ "s_runStateNames");
// This should match the TargetProperty enum.
-static const char* const s_targetPropertyNames[] = {
- "Transform",
- "Opacity",
- "Filter",
- "ScrollOffset",
- "BackgroundColor"
-};
-
-COMPILE_ASSERT(static_cast<int>(cc::Animation::TargetPropertyEnumSize) ==
- arraysize(s_targetPropertyNames),
- TargetProperty_names_match_enum);
+static const char* const s_targetPropertyNames[] = {"TRANSFORM",
+ "OPACITY",
+ "FILTER",
+ "SCROLL_OFFSET",
+ "BACKGROUND_COLOR"};
+
+static_assert(static_cast<int>(cc::Animation::LAST_TARGET_PROPERTY) + 1 ==
+ arraysize(s_targetPropertyNames),
+ "TargetPropertyEnumSize should equal the number of elements in "
+ "s_targetPropertyNames");
} // namespace
@@ -62,12 +61,12 @@ Animation::Animation(scoped_ptr<AnimationCurve> curve,
id_(animation_id),
group_(group_id),
target_property_(target_property),
- run_state_(WaitingForTargetAvailability),
+ run_state_(WAITING_FOR_TARGET_AVAILABILITY),
iterations_(1),
iteration_start_(0),
- direction_(Normal),
+ direction_(DIRECTION_NORMAL),
playback_rate_(1),
- fill_mode_(FillModeBoth),
+ fill_mode_(FILL_MODE_BOTH),
needs_synchronized_start_time_(false),
received_finished_event_(false),
suspended_(false),
@@ -78,8 +77,8 @@ Animation::Animation(scoped_ptr<AnimationCurve> curve,
}
Animation::~Animation() {
- if (run_state_ == Running || run_state_ == Paused)
- SetRunState(Aborted, base::TimeTicks());
+ if (run_state_ == RUNNING || run_state_ == PAUSED)
+ SetRunState(ABORTED, base::TimeTicks());
}
void Animation::SetRunState(RunState run_state,
@@ -94,10 +93,10 @@ void Animation::SetRunState(RunState run_state,
s_targetPropertyNames[target_property_],
group_);
- bool is_waiting_to_start = run_state_ == WaitingForTargetAvailability ||
- run_state_ == Starting;
+ bool is_waiting_to_start =
+ run_state_ == WAITING_FOR_TARGET_AVAILABILITY || run_state_ == STARTING;
- if (is_controlling_instance_ && is_waiting_to_start && run_state == Running) {
+ if (is_controlling_instance_ && is_waiting_to_start && run_state == RUNNING) {
TRACE_EVENT_ASYNC_BEGIN1(
"cc", "Animation", this, "Name", TRACE_STR_COPY(name_buffer));
}
@@ -106,9 +105,9 @@ void Animation::SetRunState(RunState run_state,
const char* old_run_state_name = s_runStateNames[run_state_];
- if (run_state == Running && run_state_ == Paused)
+ if (run_state == RUNNING && run_state_ == PAUSED)
total_paused_time_ += (monotonic_time - pause_time_);
- else if (run_state == Paused)
+ else if (run_state == PAUSED)
pause_time_ = monotonic_time;
run_state_ = run_state;
@@ -134,13 +133,13 @@ void Animation::SetRunState(RunState run_state,
}
void Animation::Suspend(base::TimeTicks monotonic_time) {
- SetRunState(Paused, monotonic_time);
+ SetRunState(PAUSED, monotonic_time);
suspended_ = true;
}
void Animation::Resume(base::TimeTicks monotonic_time) {
suspended_ = false;
- SetRunState(Running, monotonic_time);
+ SetRunState(RUNNING, monotonic_time);
}
bool Animation::IsFinishedAt(base::TimeTicks monotonic_time) const {
@@ -153,22 +152,23 @@ bool Animation::IsFinishedAt(base::TimeTicks monotonic_time) const {
if (playback_rate_ == 0)
return false;
- return run_state_ == Running && iterations_ >= 0 &&
- iterations_ * curve_->Duration() / std::abs(playback_rate_) <=
- (monotonic_time + time_offset_ - start_time_ - total_paused_time_)
- .InSecondsF();
+ return run_state_ == RUNNING && iterations_ >= 0 &&
+ TimeUtil::Scale(curve_->Duration(),
+ iterations_ / std::abs(playback_rate_)) <=
+ (monotonic_time + time_offset_ - start_time_ - total_paused_time_);
}
bool Animation::InEffect(base::TimeTicks monotonic_time) const {
- return ConvertToActiveTime(monotonic_time) >= 0 ||
- (fill_mode_ == FillModeBoth || fill_mode_ == FillModeBackwards);
+ return ConvertToActiveTime(monotonic_time) >= base::TimeDelta() ||
+ (fill_mode_ == FILL_MODE_BOTH || fill_mode_ == FILL_MODE_BACKWARDS);
}
-double Animation::ConvertToActiveTime(base::TimeTicks monotonic_time) const {
+base::TimeDelta Animation::ConvertToActiveTime(
+ base::TimeTicks monotonic_time) const {
base::TimeTicks trimmed = monotonic_time + time_offset_;
// If we're paused, time is 'stuck' at the pause time.
- if (run_state_ == Paused)
+ if (run_state_ == PAUSED)
trimmed = pause_time_;
// Returned time should always be relative to the start time and should
@@ -177,60 +177,64 @@ double Animation::ConvertToActiveTime(base::TimeTicks monotonic_time) const {
// If we're just starting or we're waiting on receiving a start time,
// time is 'stuck' at the initial state.
- if ((run_state_ == Starting && !has_set_start_time()) ||
+ if ((run_state_ == STARTING && !has_set_start_time()) ||
needs_synchronized_start_time())
trimmed = base::TimeTicks() + time_offset_;
- return (trimmed - base::TimeTicks()).InSecondsF();
+ return (trimmed - base::TimeTicks());
}
-double Animation::TrimTimeToCurrentIteration(
+base::TimeDelta Animation::TrimTimeToCurrentIteration(
base::TimeTicks monotonic_time) const {
// Check for valid parameters
DCHECK(playback_rate_);
DCHECK_GE(iteration_start_, 0);
- double active_time = ConvertToActiveTime(monotonic_time);
- double start_offset = iteration_start_ * curve_->Duration();
+ base::TimeDelta active_time = ConvertToActiveTime(monotonic_time);
+ base::TimeDelta start_offset =
+ TimeUtil::Scale(curve_->Duration(), iteration_start_);
// Return start offset if we are before the start of the animation
- if (active_time < 0)
+ if (active_time < base::TimeDelta())
return start_offset;
-
// Always return zero if we have no iterations.
if (!iterations_)
- return 0;
+ return base::TimeDelta();
// Don't attempt to trim if we have no duration.
- if (curve_->Duration() <= 0)
- return 0;
+ if (curve_->Duration() <= base::TimeDelta())
+ return base::TimeDelta();
- double repeated_duration = iterations_ * curve_->Duration();
- double active_duration = repeated_duration / std::abs(playback_rate_);
+ base::TimeDelta repeated_duration =
+ TimeUtil::Scale(curve_->Duration(), iterations_);
+ base::TimeDelta active_duration =
+ TimeUtil::Scale(repeated_duration, 1.0 / std::abs(playback_rate_));
// Check if we are past active duration
if (iterations_ > 0 && active_time >= active_duration)
active_time = active_duration;
// Calculate the scaled active time
- double scaled_active_time;
+ base::TimeDelta scaled_active_time;
if (playback_rate_ < 0)
scaled_active_time =
- (active_time - active_duration) * playback_rate_ + start_offset;
+ TimeUtil::Scale((active_time - active_duration), playback_rate_) +
+ start_offset;
else
- scaled_active_time = active_time * playback_rate_ + start_offset;
+ scaled_active_time =
+ TimeUtil::Scale(active_time, playback_rate_) + start_offset;
// Calculate the iteration time
- double iteration_time;
+ base::TimeDelta iteration_time;
if (scaled_active_time - start_offset == repeated_duration &&
fmod(iterations_ + iteration_start_, 1) == 0)
iteration_time = curve_->Duration();
else
- iteration_time = fmod(scaled_active_time, curve_->Duration());
+ iteration_time = TimeUtil::Mod(scaled_active_time, curve_->Duration());
// Calculate the current iteration
int iteration;
- if (scaled_active_time <= 0)
+ if (scaled_active_time <= base::TimeDelta())
iteration = 0;
else if (iteration_time == curve_->Duration())
iteration = ceil(iteration_start_ + iterations_ - 1);
@@ -239,9 +243,10 @@ double Animation::TrimTimeToCurrentIteration(
// Check if we are running the animation in reverse direction for the current
// iteration
- bool reverse = (direction_ == Reverse) ||
- (direction_ == Alternate && iteration % 2 == 1) ||
- (direction_ == AlternateReverse && iteration % 2 == 0);
+ bool reverse =
+ (direction_ == DIRECTION_REVERSE) ||
+ (direction_ == DIRECTION_ALTERNATE && iteration % 2 == 1) ||
+ (direction_ == DIRECTION_ALTERNATE_REVERSE && iteration % 2 == 0);
// If we are running the animation in reverse direction, reverse the result
if (reverse)
@@ -272,8 +277,8 @@ scoped_ptr<Animation> Animation::CloneAndInitialize(
void Animation::PushPropertiesTo(Animation* other) const {
// Currently, we only push changes due to pausing and resuming animations on
// the main thread.
- if (run_state_ == Animation::Paused ||
- other->run_state_ == Animation::Paused) {
+ if (run_state_ == Animation::PAUSED ||
+ other->run_state_ == Animation::PAUSED) {
other->run_state_ = run_state_;
other->pause_time_ = pause_time_;
other->total_paused_time_ = total_paused_time_;
diff --git a/chromium/cc/animation/animation.h b/chromium/cc/animation/animation.h
index 78564971e0a..2677fdeff58 100644
--- a/chromium/cc/animation/animation.h
+++ b/chromium/cc/animation/animation.h
@@ -19,43 +19,48 @@ class AnimationCurve;
// loop count, last pause time, and the total time spent paused.
class CC_EXPORT Animation {
public:
- // Animations begin in the 'WaitingForTargetAvailability' state. An Animation
- // waiting for target availibility will run as soon as its target property
- // is free (and all the animations animating with it are also able to run).
- // When this time arrives, the controller will move the animation into the
- // Starting state, and then into the Running state. Running animations may
- // toggle between Running and Paused, and may be stopped by moving into either
- // the Aborted or Finished states. A Finished animation was allowed to run to
- // completion, but an Aborted animation was not.
+ // Animations begin in the 'WAITING_FOR_TARGET_AVAILABILITY' state. An
+ // Animation waiting for target availibility will run as soon as its target
+ // property is free (and all the animations animating with it are also able to
+ // run). When this time arrives, the controller will move the animation into
+ // the STARTING state, and then into the RUNNING state. RUNNING animations may
+ // toggle between RUNNING and PAUSED, and may be stopped by moving into either
+ // the ABORTED or FINISHED states. A FINISHED animation was allowed to run to
+ // completion, but an ABORTED animation was not.
enum RunState {
- WaitingForTargetAvailability = 0,
- WaitingForDeletion,
- Starting,
- Running,
- Paused,
- Finished,
- Aborted,
+ WAITING_FOR_TARGET_AVAILABILITY = 0,
+ WAITING_FOR_DELETION,
+ STARTING,
+ RUNNING,
+ PAUSED,
+ FINISHED,
+ ABORTED,
// This sentinel must be last.
- RunStateEnumSize
+ LAST_RUN_STATE = ABORTED
};
enum TargetProperty {
- Transform = 0,
- Opacity,
- Filter,
- ScrollOffset,
- BackgroundColor,
+ TRANSFORM = 0,
+ OPACITY,
+ FILTER,
+ SCROLL_OFFSET,
+ BACKGROUND_COLOR,
// This sentinel must be last.
- TargetPropertyEnumSize
+ LAST_TARGET_PROPERTY = BACKGROUND_COLOR
};
- enum Direction { Normal, Reverse, Alternate, AlternateReverse };
+ enum Direction {
+ DIRECTION_NORMAL,
+ DIRECTION_REVERSE,
+ DIRECTION_ALTERNATE,
+ DIRECTION_ALTERNATE_REVERSE
+ };
enum FillMode {
- FillModeNone,
- FillModeForwards,
- FillModeBackwards,
- FillModeBoth
+ FILL_MODE_NONE,
+ FILL_MODE_FORWARDS,
+ FILL_MODE_BACKWARDS,
+ FILL_MODE_BOTH
};
static scoped_ptr<Animation> Create(scoped_ptr<AnimationCurve> curve,
@@ -111,9 +116,8 @@ class CC_EXPORT Animation {
bool IsFinishedAt(base::TimeTicks monotonic_time) const;
bool is_finished() const {
- return run_state_ == Finished ||
- run_state_ == Aborted ||
- run_state_ == WaitingForDeletion;
+ return run_state_ == FINISHED || run_state_ == ABORTED ||
+ run_state_ == WAITING_FOR_DELETION;
}
bool InEffect(base::TimeTicks monotonic_time) const;
@@ -131,7 +135,7 @@ class CC_EXPORT Animation {
needs_synchronized_start_time_ = needs_synchronized_start_time;
}
- // This is true for animations running on the main thread when the Finished
+ // This is true for animations running on the main thread when the FINISHED
// event sent by the corresponding impl animation has been received.
bool received_finished_event() const {
return received_finished_event_;
@@ -142,7 +146,8 @@ class CC_EXPORT Animation {
// Takes the given absolute time, and using the start time and the number
// of iterations, returns the relative time in the current iteration.
- double TrimTimeToCurrentIteration(base::TimeTicks monotonic_time) const;
+ base::TimeDelta TrimTimeToCurrentIteration(
+ base::TimeTicks monotonic_time) const;
scoped_ptr<Animation> CloneAndInitialize(RunState initial_run_state) const;
@@ -169,18 +174,17 @@ class CC_EXPORT Animation {
int group_id,
TargetProperty target_property);
- double ConvertToActiveTime(base::TimeTicks monotonic_time) const;
+ base::TimeDelta ConvertToActiveTime(base::TimeTicks monotonic_time) const;
scoped_ptr<AnimationCurve> curve_;
- // IDs are not necessarily unique.
+ // IDs must be unique.
int id_;
// Animations that must be run together are called 'grouped' and have the same
// group id. Grouped animations are guaranteed to start at the same time and
// no other animations may animate any of the group's target properties until
- // all animations in the group have finished animating. Note: an active
- // animation's group id and target property uniquely identify that animation.
+ // all animations in the group have finished animating.
int group_;
TargetProperty target_property_;
@@ -227,10 +231,10 @@ class CC_EXPORT Animation {
// When pushed from a main-thread controller to a compositor-thread
// controller, an animation will initially only affect pending observers
// (corresponding to layers in the pending tree). Animations that only
- // affect pending observers are able to reach the Starting state and tick
+ // affect pending observers are able to reach the STARTING state and tick
// pending observers, but cannot proceed any further and do not tick active
// observers. After activation, such animations affect both kinds of observers
- // and are able to proceed past the Starting state. When the removal of
+ // and are able to proceed past the STARTING state. When the removal of
// an animation is pushed from a main-thread controller to a
// compositor-thread controller, this initially only makes the animation
// stop affecting pending observers. After activation, such animations no
diff --git a/chromium/cc/animation/animation_curve.cc b/chromium/cc/animation/animation_curve.cc
index 3acff5d1f62..9e8cae93538 100644
--- a/chromium/cc/animation/animation_curve.cc
+++ b/chromium/cc/animation/animation_curve.cc
@@ -10,48 +10,50 @@
namespace cc {
const ColorAnimationCurve* AnimationCurve::ToColorAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::Color);
+ DCHECK(Type() == AnimationCurve::COLOR);
return static_cast<const ColorAnimationCurve*>(this);
}
-AnimationCurve::CurveType ColorAnimationCurve::Type() const { return Color; }
+AnimationCurve::CurveType ColorAnimationCurve::Type() const {
+ return COLOR;
+}
const FloatAnimationCurve* AnimationCurve::ToFloatAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::Float);
+ DCHECK(Type() == AnimationCurve::FLOAT);
return static_cast<const FloatAnimationCurve*>(this);
}
AnimationCurve::CurveType FloatAnimationCurve::Type() const {
- return Float;
+ return FLOAT;
}
const TransformAnimationCurve* AnimationCurve::ToTransformAnimationCurve()
const {
- DCHECK(Type() == AnimationCurve::Transform);
+ DCHECK(Type() == AnimationCurve::TRANSFORM);
return static_cast<const TransformAnimationCurve*>(this);
}
AnimationCurve::CurveType TransformAnimationCurve::Type() const {
- return Transform;
+ return TRANSFORM;
}
const FilterAnimationCurve* AnimationCurve::ToFilterAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::Filter);
+ DCHECK(Type() == AnimationCurve::FILTER);
return static_cast<const FilterAnimationCurve*>(this);
}
AnimationCurve::CurveType FilterAnimationCurve::Type() const {
- return Filter;
+ return FILTER;
}
const ScrollOffsetAnimationCurve* AnimationCurve::ToScrollOffsetAnimationCurve()
const {
- DCHECK(Type() == AnimationCurve::ScrollOffset);
+ DCHECK(Type() == AnimationCurve::SCROLL_OFFSET);
return static_cast<const ScrollOffsetAnimationCurve*>(this);
}
ScrollOffsetAnimationCurve* AnimationCurve::ToScrollOffsetAnimationCurve() {
- DCHECK(Type() == AnimationCurve::ScrollOffset);
+ DCHECK(Type() == AnimationCurve::SCROLL_OFFSET);
return static_cast<ScrollOffsetAnimationCurve*>(this);
}
diff --git a/chromium/cc/animation/animation_curve.h b/chromium/cc/animation/animation_curve.h
index 57c42c7c9f5..68bad3ba3b5 100644
--- a/chromium/cc/animation/animation_curve.h
+++ b/chromium/cc/animation/animation_curve.h
@@ -6,6 +6,7 @@
#define CC_ANIMATION_ANIMATION_CURVE_H_
#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/output/filter_operations.h"
#include "ui/gfx/transform.h"
@@ -26,11 +27,11 @@ class TransformOperations;
// An animation curve is a function that returns a value given a time.
class CC_EXPORT AnimationCurve {
public:
- enum CurveType { Color, Float, Transform, Filter, ScrollOffset };
+ enum CurveType { COLOR, FLOAT, TRANSFORM, FILTER, SCROLL_OFFSET };
virtual ~AnimationCurve() {}
- virtual double Duration() const = 0;
+ virtual base::TimeDelta Duration() const = 0;
virtual CurveType Type() const = 0;
virtual scoped_ptr<AnimationCurve> Clone() const = 0;
@@ -47,7 +48,7 @@ class CC_EXPORT ColorAnimationCurve : public AnimationCurve {
public:
~ColorAnimationCurve() override {}
- virtual SkColor GetValue(double t) const = 0;
+ virtual SkColor GetValue(base::TimeDelta t) const = 0;
// Partial Animation implementation.
CurveType Type() const override;
@@ -57,7 +58,7 @@ class CC_EXPORT FloatAnimationCurve : public AnimationCurve {
public:
~FloatAnimationCurve() override {}
- virtual float GetValue(double t) const = 0;
+ virtual float GetValue(base::TimeDelta t) const = 0;
// Partial Animation implementation.
CurveType Type() const override;
@@ -67,7 +68,7 @@ class CC_EXPORT TransformAnimationCurve : public AnimationCurve {
public:
~TransformAnimationCurve() override {}
- virtual gfx::Transform GetValue(double t) const = 0;
+ virtual gfx::Transform GetValue(base::TimeDelta t) const = 0;
// Sets |bounds| to be the bounding box for the region within which |box|
// will move during this animation. If this region cannot be computed,
@@ -81,6 +82,13 @@ class CC_EXPORT TransformAnimationCurve : public AnimationCurve {
// Returns true if this animation is a translation.
virtual bool IsTranslation() const = 0;
+ // Returns true if this animation preserves axis alignment.
+ virtual bool PreservesAxisAlignment() const = 0;
+
+ // Animation start scale
+ virtual bool AnimationStartScale(bool forward_direction,
+ float* start_scale) const = 0;
+
// Set |max_scale| to the maximum scale along any dimension at the end of
// intermediate animation target points (eg keyframe end points). When
// |forward_direction| is true, the animation curve assumes it plays from
@@ -97,7 +105,7 @@ class CC_EXPORT FilterAnimationCurve : public AnimationCurve {
public:
~FilterAnimationCurve() override {}
- virtual FilterOperations GetValue(double t) const = 0;
+ virtual FilterOperations GetValue(base::TimeDelta t) const = 0;
virtual bool HasFilterThatMovesPixels() const = 0;
// Partial Animation implementation.
diff --git a/chromium/cc/animation/animation_events.h b/chromium/cc/animation/animation_events.h
index e40ca3f633f..d2681628f81 100644
--- a/chromium/cc/animation/animation_events.h
+++ b/chromium/cc/animation/animation_events.h
@@ -15,7 +15,7 @@
namespace cc {
struct CC_EXPORT AnimationEvent {
- enum Type { Started, Finished, Aborted, PropertyUpdate };
+ enum Type { STARTED, FINISHED, ABORTED, PROPERTY_UPDATE };
AnimationEvent(Type type,
int layer_id,
diff --git a/chromium/cc/animation/animation_id_provider.cc b/chromium/cc/animation/animation_id_provider.cc
index 5c7afb6d98c..caefdb8fee5 100644
--- a/chromium/cc/animation/animation_id_provider.cc
+++ b/chromium/cc/animation/animation_id_provider.cc
@@ -2,18 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/atomic_sequence_num.h"
#include "cc/animation/animation_id_provider.h"
namespace cc {
+base::StaticAtomicSequenceNumber g_next_animation_id;
+base::StaticAtomicSequenceNumber g_next_group_id;
+
int AnimationIdProvider::NextAnimationId() {
- static int next_animation_id = 1;
- return next_animation_id++;
+ // Animation IDs start from 1.
+ return g_next_animation_id.GetNext() + 1;
}
int AnimationIdProvider::NextGroupId() {
- static int next_group_id = 1;
- return next_group_id++;
+ // Animation group IDs start from 1.
+ return g_next_group_id.GetNext() + 1;
}
} // namespace cc
diff --git a/chromium/cc/animation/animation_registrar.cc b/chromium/cc/animation/animation_registrar.cc
index 5327926b1cc..3fb8055e191 100644
--- a/chromium/cc/animation/animation_registrar.cc
+++ b/chromium/cc/animation/animation_registrar.cc
@@ -4,6 +4,7 @@
#include "cc/animation/animation_registrar.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/animation/layer_animation_controller.h"
namespace cc {
@@ -55,4 +56,75 @@ void AnimationRegistrar::UnregisterAnimationController(
DidDeactivateAnimationController(controller);
}
+bool AnimationRegistrar::ActivateAnimations() {
+ if (!needs_animate_layers())
+ return false;
+
+ TRACE_EVENT0("cc", "AnimationRegistrar::ActivateAnimations");
+ AnimationControllerMap active_controllers_copy =
+ active_animation_controllers_;
+ for (auto& it : active_controllers_copy)
+ it.second->ActivateAnimations();
+
+ return true;
+}
+
+bool AnimationRegistrar::AnimateLayers(base::TimeTicks monotonic_time) {
+ if (!needs_animate_layers())
+ return false;
+
+ TRACE_EVENT0("cc", "AnimationRegistrar::AnimateLayers");
+ AnimationControllerMap controllers_copy = active_animation_controllers_;
+ for (auto& it : controllers_copy)
+ it.second->Animate(monotonic_time);
+
+ return true;
+}
+
+bool AnimationRegistrar::UpdateAnimationState(bool start_ready_animations,
+ AnimationEventsVector* events) {
+ if (!needs_animate_layers())
+ return false;
+
+ TRACE_EVENT0("cc", "AnimationRegistrar::UpdateAnimationState");
+ AnimationControllerMap active_controllers_copy =
+ active_animation_controllers_;
+ for (auto& it : active_controllers_copy)
+ it.second->UpdateState(start_ready_animations, events);
+
+ return true;
+}
+
+void AnimationRegistrar::SetAnimationEvents(
+ scoped_ptr<AnimationEventsVector> events) {
+ for (size_t event_index = 0; event_index < events->size(); ++event_index) {
+ int event_layer_id = (*events)[event_index].layer_id;
+
+ // Use the map of all controllers, not just active ones, since non-active
+ // controllers may still receive events for impl-only animations.
+ const AnimationRegistrar::AnimationControllerMap& animation_controllers =
+ all_animation_controllers_;
+ auto iter = animation_controllers.find(event_layer_id);
+ if (iter != animation_controllers.end()) {
+ switch ((*events)[event_index].type) {
+ case AnimationEvent::STARTED:
+ (*iter).second->NotifyAnimationStarted((*events)[event_index]);
+ break;
+
+ case AnimationEvent::FINISHED:
+ (*iter).second->NotifyAnimationFinished((*events)[event_index]);
+ break;
+
+ case AnimationEvent::ABORTED:
+ (*iter).second->NotifyAnimationAborted((*events)[event_index]);
+ break;
+
+ case AnimationEvent::PROPERTY_UPDATE:
+ (*iter).second->NotifyAnimationPropertyUpdate((*events)[event_index]);
+ break;
+ }
+ }
+ }
+}
+
} // namespace cc
diff --git a/chromium/cc/animation/animation_registrar.h b/chromium/cc/animation/animation_registrar.h
index 36c45c78904..53023909670 100644
--- a/chromium/cc/animation/animation_registrar.h
+++ b/chromium/cc/animation/animation_registrar.h
@@ -8,6 +8,7 @@
#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "cc/animation/animation_events.h"
#include "cc/base/cc_export.h"
namespace cc {
@@ -43,11 +44,12 @@ class CC_EXPORT AnimationRegistrar {
// Unregisters the given controller as alive.
void UnregisterAnimationController(LayerAnimationController* controller);
- const AnimationControllerMap& active_animation_controllers() const {
+ const AnimationControllerMap& active_animation_controllers_for_testing()
+ const {
return active_animation_controllers_;
}
- const AnimationControllerMap& all_animation_controllers() const {
+ const AnimationControllerMap& all_animation_controllers_for_testing() const {
return all_animation_controllers_;
}
@@ -57,6 +59,21 @@ class CC_EXPORT AnimationRegistrar {
bool supports_scroll_animations() { return supports_scroll_animations_; }
+ bool needs_animate_layers() const {
+ return !active_animation_controllers_.empty();
+ }
+
+ bool ActivateAnimations();
+ bool AnimateLayers(base::TimeTicks monotonic_time);
+ bool UpdateAnimationState(bool start_ready_animations,
+ AnimationEventsVector* events);
+
+ scoped_ptr<AnimationEventsVector> CreateEvents() {
+ return make_scoped_ptr(new AnimationEventsVector());
+ }
+
+ void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events);
+
private:
AnimationRegistrar();
diff --git a/chromium/cc/animation/animation_unittest.cc b/chromium/cc/animation/animation_unittest.cc
index b1592d690f4..9345c6b1fc5 100644
--- a/chromium/cc/animation/animation_unittest.cc
+++ b/chromium/cc/animation/animation_unittest.cc
@@ -23,9 +23,7 @@ scoped_ptr<Animation> CreateAnimation(double iterations,
double playback_rate) {
scoped_ptr<Animation> to_return(
Animation::Create(make_scoped_ptr(new FakeFloatAnimationCurve(duration)),
- 0,
- 1,
- Animation::Opacity));
+ 0, 1, Animation::OPACITY));
to_return->set_iterations(iterations);
to_return->set_playback_rate(playback_rate);
return to_return.Pass();
@@ -41,296 +39,441 @@ scoped_ptr<Animation> CreateAnimation(double iterations) {
TEST(AnimationTest, TrimTimeZeroIterations) {
scoped_ptr<Animation> anim(CreateAnimation(0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeOneHalfIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1.5));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.9, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.9)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.9, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.9))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->set_direction(Animation::Reverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ anim->set_direction(Animation::DIRECTION_REVERSE);
+ EXPECT_EQ(
+ 1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoIterations) {
scoped_ptr<Animation> anim(CreateAnimation(2));
- anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoHalfIterations) {
scoped_ptr<Animation> anim(CreateAnimation(2.5));
- anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.50)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.50))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateReverseInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateReverseOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateReverseTwoIterations) {
scoped_ptr<Animation> anim(CreateAnimation(2));
- anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_start_time(TicksFromSecondsF(4));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeStartTimeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_start_time(TicksFromSecondsF(4));
- anim->set_direction(Animation::Reverse);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)));
+ anim->set_direction(Animation::DIRECTION_REVERSE);
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(4000));
anim->set_start_time(TicksFromSecondsF(4));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeTimeOffsetReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(4000));
anim->set_start_time(TicksFromSecondsF(4));
- anim->set_direction(Animation::Reverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ anim->set_direction(Animation::DIRECTION_REVERSE);
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeNegativeTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(-4000));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeNegativeTimeOffsetReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(-4000));
- anim->set_direction(Animation::Reverse);
+ anim->set_direction(Animation::DIRECTION_REVERSE);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimePauseResume) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.5));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5)));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(0.5));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(1024.0));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimePauseResumeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_direction(Animation::Reverse);
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.25));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.75)));
+ anim->set_direction(Animation::DIRECTION_REVERSE);
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(0.25));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(1024.0));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.75))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeSuspendResume) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
anim->Suspend(TicksFromSecondsF(0.5));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
anim->Resume(TicksFromSecondsF(1024));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeSuspendResumeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_direction(Animation::Reverse);
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ anim->set_direction(Animation::DIRECTION_REVERSE);
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
anim->Suspend(TicksFromSecondsF(0.75));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
anim->Resume(TicksFromSecondsF(1024));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.25)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeZeroDuration) {
scoped_ptr<Animation> anim(CreateAnimation(0, 0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeStarting) {
scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
- anim->SetRunState(Animation::Starting, TicksFromSecondsF(0.0));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ anim->SetRunState(Animation::STARTING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
anim->set_time_offset(TimeDelta::FromMilliseconds(2000));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
anim->set_start_time(TicksFromSecondsF(1.0));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeNeedsSynchronizedStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
anim->set_needs_synchronized_start_time(true);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
anim->set_time_offset(TimeDelta::FromMilliseconds(2000));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
anim->set_start_time(TicksFromSecondsF(1.0));
anim->set_needs_synchronized_start_time(false);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
}
TEST(AnimationTest, IsFinishedAtZeroIterations) {
scoped_ptr<Animation> anim(CreateAnimation(0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
@@ -338,7 +481,7 @@ TEST(AnimationTest, IsFinishedAtZeroIterations) {
TEST(AnimationTest, IsFinishedAtOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
@@ -347,7 +490,7 @@ TEST(AnimationTest, IsFinishedAtOneIteration) {
TEST(AnimationTest, IsFinishedAtInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.5)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
@@ -357,7 +500,7 @@ TEST(AnimationTest, IsFinishedAtInfiniteIterations) {
TEST(AnimationTest, IsFinishedNegativeTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(-500));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
@@ -371,7 +514,7 @@ TEST(AnimationTest, IsFinishedNegativeTimeOffset) {
TEST(AnimationTest, IsFinishedPositiveTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(500));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
@@ -381,311 +524,455 @@ TEST(AnimationTest, IsFinishedPositiveTimeOffset) {
TEST(AnimationTest, IsFinishedAtNotRunning) {
scoped_ptr<Animation> anim(CreateAnimation(0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
- anim->SetRunState(Animation::WaitingForTargetAvailability,
+ anim->SetRunState(Animation::WAITING_FOR_TARGET_AVAILABILITY,
TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
- anim->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
- anim->SetRunState(Animation::Aborted, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::ABORTED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
}
TEST(AnimationTest, IsFinished) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::WaitingForTargetAvailability,
+ anim->SetRunState(Animation::WAITING_FOR_TARGET_AVAILABILITY,
TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
- anim->SetRunState(Animation::Aborted, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::ABORTED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
}
TEST(AnimationTest, IsFinishedNeedsSynchronizedStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(2.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(2.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(2.0));
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(2.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::WaitingForTargetAvailability,
+ anim->SetRunState(Animation::WAITING_FOR_TARGET_AVAILABILITY,
TicksFromSecondsF(2.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
- anim->SetRunState(Animation::Aborted, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::ABORTED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
}
TEST(AnimationTest, RunStateChangesIgnoredWhileSuspended) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->Suspend(TicksFromSecondsF(0));
- EXPECT_EQ(Animation::Paused, anim->run_state());
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(Animation::Paused, anim->run_state());
+ EXPECT_EQ(Animation::PAUSED, anim->run_state());
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(Animation::PAUSED, anim->run_state());
anim->Resume(TicksFromSecondsF(0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(Animation::Running, anim->run_state());
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(Animation::RUNNING, anim->run_state());
}
TEST(AnimationTest, TrimTimePlaybackNormal) {
scoped_ptr<Animation> anim(CreateAnimation(1, 1, 1));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackSlow) {
scoped_ptr<Animation> anim(CreateAnimation(1, 1, 0.5));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackFast) {
scoped_ptr<Animation> anim(CreateAnimation(1, 4, 2));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
+ EXPECT_EQ(
+ 4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(
+ 4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackNormalReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 2, -1));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackSlowReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 2, -0.5));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
- EXPECT_EQ(1.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+ EXPECT_EQ(1.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3)).InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackFastReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 2, -2));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackFastInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1, 4, 4));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.5)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.0))
+ .InSecondsF());
+ EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackNormalDoubleReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 1, -1));
- anim->set_direction(Animation::Reverse);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ anim->set_direction(Animation::DIRECTION_REVERSE);
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackFastDoubleReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 4, -2));
- anim->set_direction(Animation::Reverse);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+ anim->set_direction(Animation::DIRECTION_REVERSE);
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
+ EXPECT_EQ(
+ 4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(
+ 4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFast) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, 2));
- anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFastReverse) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, 2));
- anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFastDoubleReverse) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, -2));
- anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest,
TrimTimeAlternateReverseThreeIterationsPlaybackFastAlternateReverse) {
scoped_ptr<Animation> anim(CreateAnimation(3, 2, -2));
- anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.25)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.25))
+ .InSecondsF());
}
TEST(AnimationTest,
TrimTimeAlternateReverseTwoIterationsPlaybackNormalAlternate) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, -1));
- anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeIterationStart) {
scoped_ptr<Animation> anim(CreateAnimation(2, 1, 1));
anim->set_iteration_start(0.5);
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeIterationStartAlternate) {
scoped_ptr<Animation> anim(CreateAnimation(2, 1, 1));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
anim->set_iteration_start(0.3);
- EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.8, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.7)));
- EXPECT_EQ(0.7, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.2)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.7)));
+ EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.8, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.7))
+ .InSecondsF());
+ EXPECT_EQ(0.7, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.2))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.7))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeIterationStartAlternateThreeIterations) {
scoped_ptr<Animation> anim(CreateAnimation(3, 1, 1));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
anim->set_iteration_start(1);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+ .InSecondsF());
}
TEST(AnimationTest,
TrimTimeIterationStartAlternateThreeIterationsPlaybackReverse) {
scoped_ptr<Animation> anim(CreateAnimation(3, 1, -1));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
anim->set_iteration_start(1);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+ .InSecondsF());
}
TEST(AnimationTest, InEffectFillMode) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_fill_mode(Animation::FillModeNone);
+ anim->set_fill_mode(Animation::FILL_MODE_NONE);
EXPECT_FALSE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeForwards);
+ anim->set_fill_mode(Animation::FILL_MODE_FORWARDS);
EXPECT_FALSE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeBackwards);
+ anim->set_fill_mode(Animation::FILL_MODE_BACKWARDS);
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeBoth);
+ anim->set_fill_mode(Animation::FILL_MODE_BOTH);
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
@@ -693,22 +980,22 @@ TEST(AnimationTest, InEffectFillMode) {
TEST(AnimationTest, InEffectFillModePlayback) {
scoped_ptr<Animation> anim(CreateAnimation(1, 1, -1));
- anim->set_fill_mode(Animation::FillModeNone);
+ anim->set_fill_mode(Animation::FILL_MODE_NONE);
EXPECT_FALSE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeForwards);
+ anim->set_fill_mode(Animation::FILL_MODE_FORWARDS);
EXPECT_FALSE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeBackwards);
+ anim->set_fill_mode(Animation::FILL_MODE_BACKWARDS);
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeBoth);
+ anim->set_fill_mode(Animation::FILL_MODE_BOTH);
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
diff --git a/chromium/cc/animation/keyframed_animation_curve.cc b/chromium/cc/animation/keyframed_animation_curve.cc
index 333a5c9a2e3..f8f6021b188 100644
--- a/chromium/cc/animation/keyframed_animation_curve.cc
+++ b/chromium/cc/animation/keyframed_animation_curve.cc
@@ -5,6 +5,7 @@
#include <algorithm>
#include "cc/animation/keyframed_animation_curve.h"
+#include "cc/base/time_util.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/geometry/box_f.h"
@@ -30,16 +31,18 @@ void InsertKeyframe(scoped_ptr<KeyframeType> keyframe,
}
template <typename KeyframeType>
-double TransformedAnimationTime(
+base::TimeDelta TransformedAnimationTime(
const ScopedPtrVector<KeyframeType>& keyframes,
const scoped_ptr<TimingFunction>& timing_function,
- double time) {
+ base::TimeDelta time) {
if (timing_function) {
- double start_time = keyframes.front()->Time();
- double duration = keyframes.back()->Time() - start_time;
- double progress = (time - start_time) / duration;
+ base::TimeDelta start_time = keyframes.front()->Time();
+ base::TimeDelta duration =
+ keyframes.back()->Time() - keyframes.front()->Time();
+ double progress = TimeUtil::Divide(time - start_time, duration);
- time = timing_function->GetValue(progress) * duration + start_time;
+ time = TimeUtil::Scale(duration, timing_function->GetValue(progress)) +
+ start_time;
}
return time;
@@ -47,7 +50,7 @@ double TransformedAnimationTime(
template <typename KeyframeType>
size_t GetActiveKeyframe(const ScopedPtrVector<KeyframeType>& keyframes,
- double time) {
+ base::TimeDelta time) {
DCHECK_GE(keyframes.size(), 2ul);
size_t i = 0;
for (; i < keyframes.size() - 2; ++i) { // Last keyframe is never active.
@@ -61,10 +64,11 @@ size_t GetActiveKeyframe(const ScopedPtrVector<KeyframeType>& keyframes,
template <typename KeyframeType>
double TransformedKeyframeProgress(
const ScopedPtrVector<KeyframeType>& keyframes,
- double time,
+ base::TimeDelta time,
size_t i) {
- double progress = (time - keyframes[i]->Time()) /
- (keyframes[i + 1]->Time() - keyframes[i]->Time());
+ double progress =
+ TimeUtil::Divide(time - keyframes[i]->Time(),
+ keyframes[i + 1]->Time() - keyframes[i]->Time());
if (keyframes[i]->timing_function()) {
progress = keyframes[i]->timing_function()->GetValue(progress);
@@ -75,29 +79,30 @@ double TransformedKeyframeProgress(
} // namespace
-Keyframe::Keyframe(double time, scoped_ptr<TimingFunction> timing_function)
- : time_(time),
- timing_function_(timing_function.Pass()) {}
+Keyframe::Keyframe(base::TimeDelta time,
+ scoped_ptr<TimingFunction> timing_function)
+ : time_(time), timing_function_(timing_function.Pass()) {
+}
Keyframe::~Keyframe() {}
-double Keyframe::Time() const {
+base::TimeDelta Keyframe::Time() const {
return time_;
}
scoped_ptr<ColorKeyframe> ColorKeyframe::Create(
- double time,
+ base::TimeDelta time,
SkColor value,
scoped_ptr<TimingFunction> timing_function) {
return make_scoped_ptr(
new ColorKeyframe(time, value, timing_function.Pass()));
}
-ColorKeyframe::ColorKeyframe(double time,
+ColorKeyframe::ColorKeyframe(base::TimeDelta time,
SkColor value,
scoped_ptr<TimingFunction> timing_function)
- : Keyframe(time, timing_function.Pass()),
- value_(value) {}
+ : Keyframe(time, timing_function.Pass()), value_(value) {
+}
ColorKeyframe::~ColorKeyframe() {}
@@ -111,18 +116,18 @@ scoped_ptr<ColorKeyframe> ColorKeyframe::Clone() const {
}
scoped_ptr<FloatKeyframe> FloatKeyframe::Create(
- double time,
+ base::TimeDelta time,
float value,
scoped_ptr<TimingFunction> timing_function) {
return make_scoped_ptr(
new FloatKeyframe(time, value, timing_function.Pass()));
}
-FloatKeyframe::FloatKeyframe(double time,
+FloatKeyframe::FloatKeyframe(base::TimeDelta time,
float value,
scoped_ptr<TimingFunction> timing_function)
- : Keyframe(time, timing_function.Pass()),
- value_(value) {}
+ : Keyframe(time, timing_function.Pass()), value_(value) {
+}
FloatKeyframe::~FloatKeyframe() {}
@@ -138,18 +143,18 @@ scoped_ptr<FloatKeyframe> FloatKeyframe::Clone() const {
}
scoped_ptr<TransformKeyframe> TransformKeyframe::Create(
- double time,
+ base::TimeDelta time,
const TransformOperations& value,
scoped_ptr<TimingFunction> timing_function) {
return make_scoped_ptr(
new TransformKeyframe(time, value, timing_function.Pass()));
}
-TransformKeyframe::TransformKeyframe(double time,
+TransformKeyframe::TransformKeyframe(base::TimeDelta time,
const TransformOperations& value,
scoped_ptr<TimingFunction> timing_function)
- : Keyframe(time, timing_function.Pass()),
- value_(value) {}
+ : Keyframe(time, timing_function.Pass()), value_(value) {
+}
TransformKeyframe::~TransformKeyframe() {}
@@ -165,18 +170,18 @@ scoped_ptr<TransformKeyframe> TransformKeyframe::Clone() const {
}
scoped_ptr<FilterKeyframe> FilterKeyframe::Create(
- double time,
+ base::TimeDelta time,
const FilterOperations& value,
scoped_ptr<TimingFunction> timing_function) {
return make_scoped_ptr(
new FilterKeyframe(time, value, timing_function.Pass()));
}
-FilterKeyframe::FilterKeyframe(double time,
+FilterKeyframe::FilterKeyframe(base::TimeDelta time,
const FilterOperations& value,
scoped_ptr<TimingFunction> timing_function)
- : Keyframe(time, timing_function.Pass()),
- value_(value) {}
+ : Keyframe(time, timing_function.Pass()), value_(value) {
+}
FilterKeyframe::~FilterKeyframe() {}
@@ -205,7 +210,7 @@ void KeyframedColorAnimationCurve::AddKeyframe(
InsertKeyframe(keyframe.Pass(), &keyframes_);
}
-double KeyframedColorAnimationCurve::Duration() const {
+base::TimeDelta KeyframedColorAnimationCurve::Duration() const {
return keyframes_.back()->Time() - keyframes_.front()->Time();
}
@@ -221,7 +226,7 @@ scoped_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const {
return to_return.Pass();
}
-SkColor KeyframedColorAnimationCurve::GetValue(double t) const {
+SkColor KeyframedColorAnimationCurve::GetValue(base::TimeDelta t) const {
if (t <= keyframes_.front()->Time())
return keyframes_.front()->Value();
@@ -252,7 +257,7 @@ void KeyframedFloatAnimationCurve::AddKeyframe(
InsertKeyframe(keyframe.Pass(), &keyframes_);
}
-double KeyframedFloatAnimationCurve::Duration() const {
+base::TimeDelta KeyframedFloatAnimationCurve::Duration() const {
return keyframes_.back()->Time() - keyframes_.front()->Time();
}
@@ -268,7 +273,7 @@ scoped_ptr<AnimationCurve> KeyframedFloatAnimationCurve::Clone() const {
return to_return.Pass();
}
-float KeyframedFloatAnimationCurve::GetValue(double t) const {
+float KeyframedFloatAnimationCurve::GetValue(base::TimeDelta t) const {
if (t <= keyframes_.front()->Time())
return keyframes_.front()->Value();
@@ -297,7 +302,7 @@ void KeyframedTransformAnimationCurve::AddKeyframe(
InsertKeyframe(keyframe.Pass(), &keyframes_);
}
-double KeyframedTransformAnimationCurve::Duration() const {
+base::TimeDelta KeyframedTransformAnimationCurve::Duration() const {
return keyframes_.back()->Time() - keyframes_.front()->Time();
}
@@ -313,7 +318,8 @@ scoped_ptr<AnimationCurve> KeyframedTransformAnimationCurve::Clone() const {
return to_return.Pass();
}
-gfx::Transform KeyframedTransformAnimationCurve::GetValue(double t) const {
+gfx::Transform KeyframedTransformAnimationCurve::GetValue(
+ base::TimeDelta t) const {
if (t <= keyframes_.front()->Time())
return keyframes_.front()->Value().Apply();
@@ -357,6 +363,14 @@ bool KeyframedTransformAnimationCurve::AffectsScale() const {
return false;
}
+bool KeyframedTransformAnimationCurve::PreservesAxisAlignment() const {
+ for (size_t i = 0; i < keyframes_.size(); ++i) {
+ if (!keyframes_[i]->Value().PreservesAxisAlignment())
+ return false;
+ }
+ return true;
+}
+
bool KeyframedTransformAnimationCurve::IsTranslation() const {
for (size_t i = 0; i < keyframes_.size(); ++i) {
if (!keyframes_[i]->Value().IsTranslation() &&
@@ -365,7 +379,27 @@ bool KeyframedTransformAnimationCurve::IsTranslation() const {
}
return true;
}
+bool KeyframedTransformAnimationCurve::AnimationStartScale(
+ bool forward_direction,
+ float* start_scale) const {
+ DCHECK_GE(keyframes_.size(), 2ul);
+ *start_scale = 0.f;
+ size_t start_location = 0;
+ if (!forward_direction) {
+ start_location = keyframes_.size() - 1;
+ }
+ gfx::Vector3dF initial_target_scale;
+ if (!keyframes_[start_location]->Value().ScaleComponent(
+ &initial_target_scale))
+ return false;
+ float start_scale_for_segment =
+ fmax(std::abs(initial_target_scale.x()),
+ fmax(std::abs(initial_target_scale.y()),
+ std::abs(initial_target_scale.z())));
+ *start_scale = start_scale_for_segment;
+ return true;
+}
bool KeyframedTransformAnimationCurve::MaximumTargetScale(
bool forward_direction,
float* max_scale) const {
@@ -408,7 +442,7 @@ void KeyframedFilterAnimationCurve::AddKeyframe(
InsertKeyframe(keyframe.Pass(), &keyframes_);
}
-double KeyframedFilterAnimationCurve::Duration() const {
+base::TimeDelta KeyframedFilterAnimationCurve::Duration() const {
return keyframes_.back()->Time() - keyframes_.front()->Time();
}
@@ -424,7 +458,8 @@ scoped_ptr<AnimationCurve> KeyframedFilterAnimationCurve::Clone() const {
return to_return.Pass();
}
-FilterOperations KeyframedFilterAnimationCurve::GetValue(double t) const {
+FilterOperations KeyframedFilterAnimationCurve::GetValue(
+ base::TimeDelta t) const {
if (t <= keyframes_.front()->Time())
return keyframes_.front()->Value();
diff --git a/chromium/cc/animation/keyframed_animation_curve.h b/chromium/cc/animation/keyframed_animation_curve.h
index a6e6740e560..b5dfb14628f 100644
--- a/chromium/cc/animation/keyframed_animation_curve.h
+++ b/chromium/cc/animation/keyframed_animation_curve.h
@@ -5,6 +5,7 @@
#ifndef CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
#define CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
+#include "base/time/time.h"
#include "cc/animation/animation_curve.h"
#include "cc/animation/timing_function.h"
#include "cc/animation/transform_operations.h"
@@ -15,17 +16,17 @@ namespace cc {
class CC_EXPORT Keyframe {
public:
- double Time() const;
+ base::TimeDelta Time() const;
const TimingFunction* timing_function() const {
return timing_function_.get();
}
protected:
- Keyframe(double time, scoped_ptr<TimingFunction> timing_function);
+ Keyframe(base::TimeDelta time, scoped_ptr<TimingFunction> timing_function);
virtual ~Keyframe();
private:
- double time_;
+ base::TimeDelta time_;
scoped_ptr<TimingFunction> timing_function_;
DISALLOW_COPY_AND_ASSIGN(Keyframe);
@@ -34,7 +35,7 @@ class CC_EXPORT Keyframe {
class CC_EXPORT ColorKeyframe : public Keyframe {
public:
static scoped_ptr<ColorKeyframe> Create(
- double time,
+ base::TimeDelta time,
SkColor value,
scoped_ptr<TimingFunction> timing_function);
~ColorKeyframe() override;
@@ -44,7 +45,7 @@ class CC_EXPORT ColorKeyframe : public Keyframe {
scoped_ptr<ColorKeyframe> Clone() const;
private:
- ColorKeyframe(double time,
+ ColorKeyframe(base::TimeDelta time,
SkColor value,
scoped_ptr<TimingFunction> timing_function);
@@ -54,7 +55,7 @@ class CC_EXPORT ColorKeyframe : public Keyframe {
class CC_EXPORT FloatKeyframe : public Keyframe {
public:
static scoped_ptr<FloatKeyframe> Create(
- double time,
+ base::TimeDelta time,
float value,
scoped_ptr<TimingFunction> timing_function);
~FloatKeyframe() override;
@@ -64,7 +65,7 @@ class CC_EXPORT FloatKeyframe : public Keyframe {
scoped_ptr<FloatKeyframe> Clone() const;
private:
- FloatKeyframe(double time,
+ FloatKeyframe(base::TimeDelta time,
float value,
scoped_ptr<TimingFunction> timing_function);
@@ -74,7 +75,7 @@ class CC_EXPORT FloatKeyframe : public Keyframe {
class CC_EXPORT TransformKeyframe : public Keyframe {
public:
static scoped_ptr<TransformKeyframe> Create(
- double time,
+ base::TimeDelta time,
const TransformOperations& value,
scoped_ptr<TimingFunction> timing_function);
~TransformKeyframe() override;
@@ -84,10 +85,9 @@ class CC_EXPORT TransformKeyframe : public Keyframe {
scoped_ptr<TransformKeyframe> Clone() const;
private:
- TransformKeyframe(
- double time,
- const TransformOperations& value,
- scoped_ptr<TimingFunction> timing_function);
+ TransformKeyframe(base::TimeDelta time,
+ const TransformOperations& value,
+ scoped_ptr<TimingFunction> timing_function);
TransformOperations value_;
};
@@ -95,7 +95,7 @@ class CC_EXPORT TransformKeyframe : public Keyframe {
class CC_EXPORT FilterKeyframe : public Keyframe {
public:
static scoped_ptr<FilterKeyframe> Create(
- double time,
+ base::TimeDelta time,
const FilterOperations& value,
scoped_ptr<TimingFunction> timing_function);
~FilterKeyframe() override;
@@ -105,10 +105,9 @@ class CC_EXPORT FilterKeyframe : public Keyframe {
scoped_ptr<FilterKeyframe> Clone() const;
private:
- FilterKeyframe(
- double time,
- const FilterOperations& value,
- scoped_ptr<TimingFunction> timing_function);
+ FilterKeyframe(base::TimeDelta time,
+ const FilterOperations& value,
+ scoped_ptr<TimingFunction> timing_function);
FilterOperations value_;
};
@@ -126,11 +125,11 @@ class CC_EXPORT KeyframedColorAnimationCurve : public ColorAnimationCurve {
}
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
// BackgrounColorAnimationCurve implementation
- SkColor GetValue(double t) const override;
+ SkColor GetValue(base::TimeDelta t) const override;
private:
KeyframedColorAnimationCurve();
@@ -156,11 +155,11 @@ class CC_EXPORT KeyframedFloatAnimationCurve : public FloatAnimationCurve {
}
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
// FloatAnimationCurve implementation
- float GetValue(double t) const override;
+ float GetValue(base::TimeDelta t) const override;
private:
KeyframedFloatAnimationCurve();
@@ -187,15 +186,18 @@ class CC_EXPORT KeyframedTransformAnimationCurve
}
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
// TransformAnimationCurve implementation
- gfx::Transform GetValue(double t) const override;
+ gfx::Transform GetValue(base::TimeDelta t) const override;
bool AnimatedBoundsForBox(const gfx::BoxF& box,
gfx::BoxF* bounds) const override;
bool AffectsScale() const override;
+ bool PreservesAxisAlignment() const override;
bool IsTranslation() const override;
+ bool AnimationStartScale(bool forward_direction,
+ float* start_scale) const override;
bool MaximumTargetScale(bool forward_direction,
float* max_scale) const override;
@@ -224,11 +226,11 @@ class CC_EXPORT KeyframedFilterAnimationCurve
}
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
// FilterAnimationCurve implementation
- FilterOperations GetValue(double t) const override;
+ FilterOperations GetValue(base::TimeDelta t) const override;
bool HasFilterThatMovesPixels() const override;
private:
diff --git a/chromium/cc/animation/keyframed_animation_curve_unittest.cc b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
index 71fd5219626..dc4e8173f1c 100644
--- a/chromium/cc/animation/keyframed_animation_curve_unittest.cc
+++ b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
@@ -29,13 +29,15 @@ TEST(KeyframedAnimationCurveTest, OneColorKeyFrame) {
SkColor color = SkColorSetARGB(255, 255, 255, 255);
scoped_ptr<KeyframedColorAnimationCurve> curve(
KeyframedColorAnimationCurve::Create());
- curve->AddKeyframe(ColorKeyframe::Create(0.0, color, nullptr));
-
- EXPECT_SKCOLOR_EQ(color, curve->GetValue(-1.f));
- EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.f));
- EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.5f));
- EXPECT_SKCOLOR_EQ(color, curve->GetValue(1.f));
- EXPECT_SKCOLOR_EQ(color, curve->GetValue(2.f));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta(), color, nullptr));
+
+ EXPECT_SKCOLOR_EQ(color,
+ curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SKCOLOR_EQ(color,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a color animation with two keyframes works as expected.
@@ -45,14 +47,21 @@ TEST(KeyframedAnimationCurveTest, TwoColorKeyFrame) {
SkColor color_midpoint = gfx::Tween::ColorValueBetween(0.5, color_a, color_b);
scoped_ptr<KeyframedColorAnimationCurve> curve(
KeyframedColorAnimationCurve::Create());
- curve->AddKeyframe(ColorKeyframe::Create(0.0, color_a, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(1.0, color_b, nullptr));
-
- EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
- EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
- EXPECT_SKCOLOR_EQ(color_midpoint, curve->GetValue(0.5f));
- EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f));
- EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(2.f));
+ curve->AddKeyframe(
+ ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ color_b, nullptr));
+
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SKCOLOR_EQ(color_midpoint,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a color animation with three keyframes works as expected.
@@ -66,17 +75,27 @@ TEST(KeyframedAnimationCurveTest, ThreeColorKeyFrame) {
gfx::Tween::ColorValueBetween(0.5, color_b, color_c);
scoped_ptr<KeyframedColorAnimationCurve> curve(
KeyframedColorAnimationCurve::Create());
- curve->AddKeyframe(ColorKeyframe::Create(0.0, color_a, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(1.0, color_b, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(2.0, color_c, nullptr));
-
- EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
- EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
- EXPECT_SKCOLOR_EQ(color_midpoint1, curve->GetValue(0.5f));
- EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f));
- EXPECT_SKCOLOR_EQ(color_midpoint2, curve->GetValue(1.5f));
- EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(2.f));
- EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(3.f));
+ curve->AddKeyframe(
+ ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ color_b, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
+ color_c, nullptr));
+
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SKCOLOR_EQ(color_midpoint1,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_SKCOLOR_EQ(color_midpoint2,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_SKCOLOR_EQ(color_c,
+ curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_SKCOLOR_EQ(color_c,
+ curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that a colro animation with multiple keys at a given time works sanely.
@@ -86,87 +105,103 @@ TEST(KeyframedAnimationCurveTest, RepeatedColorKeyFrame) {
scoped_ptr<KeyframedColorAnimationCurve> curve(
KeyframedColorAnimationCurve::Create());
- curve->AddKeyframe(ColorKeyframe::Create(0.0, color_a, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(1.0, color_a, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(1.0, color_b, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(2.0, color_b, nullptr));
-
- EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
- EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
- EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.5f));
-
- SkColor value = curve->GetValue(1.0f);
+ curve->AddKeyframe(
+ ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ color_a, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ color_b, nullptr));
+ curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
+ color_b, nullptr));
+
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_SKCOLOR_EQ(color_a,
+ curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+
+ SkColor value = curve->GetValue(base::TimeDelta::FromSecondsD(1.0f));
EXPECT_EQ(255u, SkColorGetA(value));
int red_value = SkColorGetR(value);
EXPECT_LE(64, red_value);
EXPECT_GE(192, red_value);
- EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.5f));
- EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(2.f));
- EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(3.f));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_SKCOLOR_EQ(color_b,
+ curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that a float animation with one keyframe works as expected.
TEST(KeyframedAnimationCurveTest, OneFloatKeyframe) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(0.0, 2.f, nullptr));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.5f));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(1.f));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(2.f));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a float animation with two keyframes works as expected.
TEST(KeyframedAnimationCurveTest, TwoFloatKeyframe) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(0.0, 2.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 4.f, nullptr));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
- EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(2.f));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a float animation with three keyframes works as expected.
TEST(KeyframedAnimationCurveTest, ThreeFloatKeyframe) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(0.0, 2.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 4.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(2.0, 8.f, nullptr));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
- EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f));
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f));
- EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f));
- EXPECT_FLOAT_EQ(8.f, curve->GetValue(3.f));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 8.f, nullptr));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that a float animation with multiple keys at a given time works sanely.
TEST(KeyframedAnimationCurveTest, RepeatedFloatKeyTimes) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(0.0, 4.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 4.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 6.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(2.0, 6.f, nullptr));
-
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(-1.f));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.f));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.5f));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 4.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 6.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 6.f, nullptr));
+
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
// There is a discontinuity at 1. Any value between 4 and 6 is valid.
- float value = curve->GetValue(1.f);
+ float value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
EXPECT_TRUE(value >= 4 && value <= 6);
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f));
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(2.f));
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(3.f));
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that a transform animation with one keyframe works as expected.
@@ -175,13 +210,14 @@ TEST(KeyframedAnimationCurveTest, OneTransformKeyframe) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations;
operations.AppendTranslate(2.f, 0.f, 0.f);
- curve->AddKeyframe(TransformKeyframe::Create(0.f, operations, nullptr));
-
- ExpectTranslateX(2.f, curve->GetValue(-1.f));
- ExpectTranslateX(2.f, curve->GetValue(0.f));
- ExpectTranslateX(2.f, curve->GetValue(0.5f));
- ExpectTranslateX(2.f, curve->GetValue(1.f));
- ExpectTranslateX(2.f, curve->GetValue(2.f));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations, nullptr));
+
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a transform animation with two keyframes works as expected.
@@ -193,13 +229,15 @@ TEST(KeyframedAnimationCurveTest, TwoTransformKeyframe) {
TransformOperations operations2;
operations2.AppendTranslate(4.f, 0.f, 0.f);
- curve->AddKeyframe(TransformKeyframe::Create(0.f, operations1, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(1.f, operations2, nullptr));
- ExpectTranslateX(2.f, curve->GetValue(-1.f));
- ExpectTranslateX(2.f, curve->GetValue(0.f));
- ExpectTranslateX(3.f, curve->GetValue(0.5f));
- ExpectTranslateX(4.f, curve->GetValue(1.f));
- ExpectTranslateX(4.f, curve->GetValue(2.f));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a transform animation with three keyframes works as expected.
@@ -212,16 +250,19 @@ TEST(KeyframedAnimationCurveTest, ThreeTransformKeyframe) {
operations2.AppendTranslate(4.f, 0.f, 0.f);
TransformOperations operations3;
operations3.AppendTranslate(8.f, 0.f, 0.f);
- curve->AddKeyframe(TransformKeyframe::Create(0.f, operations1, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(1.f, operations2, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(2.f, operations3, nullptr));
- ExpectTranslateX(2.f, curve->GetValue(-1.f));
- ExpectTranslateX(2.f, curve->GetValue(0.f));
- ExpectTranslateX(3.f, curve->GetValue(0.5f));
- ExpectTranslateX(4.f, curve->GetValue(1.f));
- ExpectTranslateX(6.f, curve->GetValue(1.5f));
- ExpectTranslateX(8.f, curve->GetValue(2.f));
- ExpectTranslateX(8.f, curve->GetValue(3.f));
+ 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));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that a transform animation with multiple keys at a given time works
@@ -238,23 +279,27 @@ TEST(KeyframedAnimationCurveTest, RepeatedTransformKeyTimes) {
operations3.AppendTranslate(6.f, 0.f, 0.f);
TransformOperations operations4;
operations4.AppendTranslate(6.f, 0.f, 0.f);
- curve->AddKeyframe(TransformKeyframe::Create(0.f, operations1, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(1.f, operations2, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(1.f, operations3, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(2.f, operations4, nullptr));
+ 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(1.0), operations3, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.0), operations4, nullptr));
- ExpectTranslateX(4.f, curve->GetValue(-1.f));
- ExpectTranslateX(4.f, curve->GetValue(0.f));
- ExpectTranslateX(4.f, curve->GetValue(0.5f));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
// There is a discontinuity at 1. Any value between 4 and 6 is valid.
- gfx::Transform value = curve->GetValue(1.f);
+ gfx::Transform value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
EXPECT_GE(value.matrix().get(0, 3), 4.f);
EXPECT_LE(value.matrix().get(0, 3), 6.f);
- ExpectTranslateX(6.f, curve->GetValue(1.5f));
- ExpectTranslateX(6.f, curve->GetValue(2.f));
- ExpectTranslateX(6.f, curve->GetValue(3.f));
+ ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that a filter animation with one keyframe works as expected.
@@ -263,13 +308,14 @@ TEST(KeyframedAnimationCurveTest, OneFilterKeyframe) {
KeyframedFilterAnimationCurve::Create());
FilterOperations operations;
operations.Append(FilterOperation::CreateBrightnessFilter(2.f));
- curve->AddKeyframe(FilterKeyframe::Create(0.f, operations, nullptr));
-
- ExpectBrightness(2.f, curve->GetValue(-1.f));
- ExpectBrightness(2.f, curve->GetValue(0.f));
- ExpectBrightness(2.f, curve->GetValue(0.5f));
- ExpectBrightness(2.f, curve->GetValue(1.f));
- ExpectBrightness(2.f, curve->GetValue(2.f));
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), operations, nullptr));
+
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a filter animation with two keyframes works as expected.
@@ -281,13 +327,15 @@ TEST(KeyframedAnimationCurveTest, TwoFilterKeyframe) {
FilterOperations operations2;
operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
- curve->AddKeyframe(FilterKeyframe::Create(0.f, operations1, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(1.f, operations2, nullptr));
- ExpectBrightness(2.f, curve->GetValue(-1.f));
- ExpectBrightness(2.f, curve->GetValue(0.f));
- ExpectBrightness(3.f, curve->GetValue(0.5f));
- ExpectBrightness(4.f, curve->GetValue(1.f));
- ExpectBrightness(4.f, curve->GetValue(2.f));
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+ operations2, nullptr));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a filter animation with three keyframes works as expected.
@@ -300,16 +348,19 @@ TEST(KeyframedAnimationCurveTest, ThreeFilterKeyframe) {
operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
FilterOperations operations3;
operations3.Append(FilterOperation::CreateBrightnessFilter(8.f));
- curve->AddKeyframe(FilterKeyframe::Create(0.f, operations1, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(1.f, operations2, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(2.f, operations3, nullptr));
- ExpectBrightness(2.f, curve->GetValue(-1.f));
- ExpectBrightness(2.f, curve->GetValue(0.f));
- ExpectBrightness(3.f, curve->GetValue(0.5f));
- ExpectBrightness(4.f, curve->GetValue(1.f));
- ExpectBrightness(6.f, curve->GetValue(1.5f));
- ExpectBrightness(8.f, curve->GetValue(2.f));
- ExpectBrightness(8.f, curve->GetValue(3.f));
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+ operations2, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f),
+ operations3, nullptr));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that a filter animation with multiple keys at a given time works
@@ -326,41 +377,47 @@ TEST(KeyframedAnimationCurveTest, RepeatedFilterKeyTimes) {
operations3.Append(FilterOperation::CreateBrightnessFilter(6.f));
FilterOperations operations4;
operations4.Append(FilterOperation::CreateBrightnessFilter(6.f));
- curve->AddKeyframe(FilterKeyframe::Create(0.f, operations1, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(1.f, operations2, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(1.f, operations3, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(2.f, operations4, nullptr));
-
- ExpectBrightness(4.f, curve->GetValue(-1.f));
- ExpectBrightness(4.f, curve->GetValue(0.f));
- ExpectBrightness(4.f, curve->GetValue(0.5f));
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+ operations2, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+ operations3, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f),
+ operations4, nullptr));
+
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
// There is a discontinuity at 1. Any value between 4 and 6 is valid.
- FilterOperations value = curve->GetValue(1.f);
+ FilterOperations value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
EXPECT_EQ(1u, value.size());
EXPECT_EQ(FilterOperation::BRIGHTNESS, value.at(0).type());
EXPECT_GE(value.at(0).amount(), 4);
EXPECT_LE(value.at(0).amount(), 6);
- ExpectBrightness(6.f, curve->GetValue(1.5f));
- ExpectBrightness(6.f, curve->GetValue(2.f));
- ExpectBrightness(6.f, curve->GetValue(3.f));
+ ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that the keyframes may be added out of order.
TEST(KeyframedAnimationCurveTest, UnsortedKeyframes) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(2.0, 8.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(0.0, 2.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 4.f, nullptr));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
- EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f));
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f));
- EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f));
- EXPECT_FLOAT_EQ(8.f, curve->GetValue(3.f));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 8.f, nullptr));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 4.f, nullptr));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that a cubic bezier timing function works as expected.
@@ -368,16 +425,114 @@ TEST(KeyframedAnimationCurveTest, CubicBezierTimingFunction) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
curve->AddKeyframe(FloatKeyframe::Create(
- 0.0, 0.f, CubicBezierTimingFunction::Create(0.25f, 0.f, 0.75f, 1.f)));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
+ base::TimeDelta(), 0.f,
+ CubicBezierTimingFunction::Create(0.25f, 0.f, 0.75f, 1.f)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
+
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_LT(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+ EXPECT_GT(0.25f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+ EXPECT_NEAR(curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)), 0.5f,
+ 0.00015f);
+ EXPECT_LT(0.75f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+ EXPECT_GT(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+}
+
+// Tests a step timing function if the change of values occur at the start.
+TEST(KeyframedAnimationCurveTest, StepsTimingFunctionStepAtStart) {
+ scoped_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ const int num_steps = 36;
+ const float steps_start_offset = 1.0f;
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ StepsTimingFunction::Create(num_steps, steps_start_offset)));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ num_steps, nullptr));
+
+ const float time_threshold = 0.0001f;
+
+ for (float i = 0.f; i < num_steps; i += 1.f) {
+ const base::TimeDelta time1 =
+ base::TimeDelta::FromSecondsD(i / num_steps - time_threshold);
+ const base::TimeDelta time2 =
+ base::TimeDelta::FromSecondsD(i / num_steps + time_threshold);
+ EXPECT_FLOAT_EQ(std::ceil(i), curve->GetValue(time1));
+ EXPECT_FLOAT_EQ(std::ceil(i) + 1.f, curve->GetValue(time2));
+ }
+ EXPECT_FLOAT_EQ(num_steps,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.0)));
+
+ for (float i = 0.5f; i <= num_steps; i += 1.0f) {
+ const base::TimeDelta time = base::TimeDelta::FromSecondsD(i / num_steps);
+ EXPECT_FLOAT_EQ(std::ceil(i), curve->GetValue(time));
+ }
+}
+
+// Tests a step timing function if the change of values occur at the middle.
+TEST(KeyframedAnimationCurveTest, StepsTimingFunctionStepAtMiddle) {
+ scoped_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ const int num_steps = 36;
+ const float steps_start_offset = 0.5f;
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ StepsTimingFunction::Create(num_steps, steps_start_offset)));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ num_steps, nullptr));
+
+ const float time_threshold = 0.0001f;
+
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta()));
+ for (float i = 0.5f; i < num_steps; i += 1.f) {
+ const base::TimeDelta time1 =
+ base::TimeDelta::FromSecondsD(i / num_steps - time_threshold);
+ const base::TimeDelta time2 =
+ base::TimeDelta::FromSecondsD(i / num_steps + time_threshold);
+ EXPECT_FLOAT_EQ(std::floor(i), curve->GetValue(time1));
+ EXPECT_FLOAT_EQ(std::floor(i) + 1.f, curve->GetValue(time2));
+ }
+ EXPECT_FLOAT_EQ(num_steps,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.0)));
+
+ for (float i = 0.25f; i <= num_steps; i += 1.0f) {
+ const base::TimeDelta time = base::TimeDelta::FromSecondsD(i / num_steps);
+ EXPECT_FLOAT_EQ(std::floor(i), curve->GetValue(time));
+ }
+}
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f));
- EXPECT_LT(0.f, curve->GetValue(0.25f));
- EXPECT_GT(0.25f, curve->GetValue(0.25f));
- EXPECT_NEAR(curve->GetValue(0.5f), 0.5f, 0.00015f);
- EXPECT_LT(0.75f, curve->GetValue(0.75f));
- EXPECT_GT(1.f, curve->GetValue(0.75f));
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(1.f));
+// Tests a step timing function if the change of values occur at the end.
+TEST(KeyframedAnimationCurveTest, StepsTimingFunctionStepAtEnd) {
+ scoped_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ const int num_steps = 36;
+ const float steps_start_offset = 0.0f;
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ StepsTimingFunction::Create(num_steps, steps_start_offset)));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ num_steps, nullptr));
+
+ const float time_threshold = 0.0001f;
+
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta()));
+ for (float i = 1.f; i <= num_steps; i += 1.f) {
+ const base::TimeDelta time1 =
+ base::TimeDelta::FromSecondsD(i / num_steps - time_threshold);
+ const base::TimeDelta time2 =
+ base::TimeDelta::FromSecondsD(i / num_steps + time_threshold);
+ EXPECT_FLOAT_EQ(std::floor(i) - 1.f, curve->GetValue(time1));
+ EXPECT_FLOAT_EQ(std::floor(i), curve->GetValue(time2));
+ }
+ EXPECT_FLOAT_EQ(num_steps,
+ curve->GetValue(base::TimeDelta::FromSecondsD(1.0)));
+
+ for (float i = 0.5f; i <= num_steps; i += 1.0f) {
+ const base::TimeDelta time = base::TimeDelta::FromSecondsD(i / num_steps);
+ EXPECT_FLOAT_EQ(std::floor(i), curve->GetValue(time));
+ }
}
// Tests that animated bounds are computed as expected.
@@ -386,13 +541,16 @@ TEST(KeyframedAnimationCurveTest, AnimatedBounds) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations1;
- curve->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
operations1.AppendTranslate(2.0, 3.0, -1.0);
- curve->AddKeyframe(TransformKeyframe::Create(0.5, operations1, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(0.5f), operations1, nullptr));
TransformOperations operations2;
operations2.AppendTranslate(4.0, 1.0, 2.0);
- curve->AddKeyframe(TransformKeyframe::Create(
- 1.0, operations2, EaseTimingFunction::Create()));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations2,
+ EaseTimingFunction::Create()));
gfx::BoxF box(2.f, 3.f, 4.f, 1.f, 3.f, 2.f);
gfx::BoxF bounds;
@@ -408,23 +566,27 @@ TEST(KeyframedAnimationCurveTest, AffectsScale) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations1;
- curve->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
operations1.AppendTranslate(2.0, 3.0, -1.0);
TransformOperations operations2;
operations2.AppendTranslate(4.0, 1.0, 2.0);
- curve->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.f), operations2, nullptr));
EXPECT_FALSE(curve->AffectsScale());
TransformOperations operations3;
operations3.AppendScale(2.f, 2.f, 2.f);
- curve->AddKeyframe(TransformKeyframe::Create(2.0, operations3, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.f), operations3, nullptr));
EXPECT_TRUE(curve->AffectsScale());
TransformOperations operations4;
operations3.AppendTranslate(2.f, 2.f, 2.f);
- curve->AddKeyframe(TransformKeyframe::Create(3.0, operations4, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(3.f), operations4, nullptr));
EXPECT_TRUE(curve->AffectsScale());
}
@@ -435,23 +597,27 @@ TEST(KeyframedAnimationCurveTest, IsTranslation) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations1;
- curve->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
operations1.AppendTranslate(2.0, 3.0, -1.0);
TransformOperations operations2;
operations2.AppendTranslate(4.0, 1.0, 2.0);
- curve->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.f), operations2, nullptr));
EXPECT_TRUE(curve->IsTranslation());
TransformOperations operations3;
operations3.AppendScale(2.f, 2.f, 2.f);
- curve->AddKeyframe(TransformKeyframe::Create(2.0, operations3, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(2.f), operations3, nullptr));
EXPECT_FALSE(curve->IsTranslation());
TransformOperations operations4;
operations3.AppendTranslate(2.f, 2.f, 2.f);
- curve->AddKeyframe(TransformKeyframe::Create(3.0, operations4, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(3.f), operations4, nullptr));
EXPECT_FALSE(curve->IsTranslation());
}
@@ -462,10 +628,12 @@ TEST(KeyframedAnimationCurveTest, MaximumTargetScale) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations1;
- curve->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
operations1.AppendScale(2.f, -3.f, 1.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- 1.0, operations1, EaseTimingFunction::Create()));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations1,
+ EaseTimingFunction::Create()));
float maximum_scale = 0.f;
EXPECT_TRUE(curve->MaximumTargetScale(true, &maximum_scale));
@@ -473,16 +641,18 @@ TEST(KeyframedAnimationCurveTest, MaximumTargetScale) {
TransformOperations operations2;
operations2.AppendScale(6.f, 3.f, 2.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- 2.0, operations2, EaseTimingFunction::Create()));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), operations2,
+ EaseTimingFunction::Create()));
EXPECT_TRUE(curve->MaximumTargetScale(true, &maximum_scale));
EXPECT_EQ(6.f, maximum_scale);
TransformOperations operations3;
operations3.AppendRotate(1.f, 0.f, 0.f, 90.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- 3.0, operations3, EaseTimingFunction::Create()));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), operations3,
+ EaseTimingFunction::Create()));
EXPECT_FALSE(curve->MaximumTargetScale(true, &maximum_scale));
@@ -492,12 +662,13 @@ TEST(KeyframedAnimationCurveTest, MaximumTargetScale) {
TransformOperations operations4;
operations4.AppendScale(0.4f, 0.2f, 0.6f);
- curve2->AddKeyframe(TransformKeyframe::Create(
- 0.0, operations4, EaseTimingFunction::Create()));
+ curve2->AddKeyframe(TransformKeyframe::Create(base::TimeDelta(), operations4,
+ EaseTimingFunction::Create()));
TransformOperations operations5;
operations5.AppendScale(0.5f, 0.3f, -0.8f);
- curve2->AddKeyframe(TransformKeyframe::Create(
- 1.0, operations5, EaseTimingFunction::Create()));
+ curve2->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations5,
+ EaseTimingFunction::Create()));
EXPECT_TRUE(curve2->MaximumTargetScale(true, &maximum_scale));
EXPECT_EQ(0.8f, maximum_scale);
@@ -506,21 +677,71 @@ TEST(KeyframedAnimationCurveTest, MaximumTargetScale) {
EXPECT_EQ(0.6f, maximum_scale);
}
+// Tests that starting animation scale is computed as expected.
+TEST(KeyframedAnimationCurveTest, AnimationStartScale) {
+ scoped_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations1;
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ operations1.AppendScale(2.f, -3.f, 1.f);
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations1,
+ EaseTimingFunction::Create()));
+
+ float start_scale = 0.f;
+
+ // Forward direction
+ EXPECT_TRUE(curve->AnimationStartScale(true, &start_scale));
+ EXPECT_EQ(1.f, start_scale);
+
+ // Backward direction
+ EXPECT_TRUE(curve->AnimationStartScale(false, &start_scale));
+ EXPECT_EQ(3.f, start_scale);
+
+ TransformOperations operations2;
+ operations2.AppendScale(6.f, 3.f, 2.f);
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), operations2,
+ EaseTimingFunction::Create()));
+
+ // Backward direction
+ EXPECT_TRUE(curve->AnimationStartScale(true, &start_scale));
+ EXPECT_EQ(1.f, start_scale);
+
+ // Backward direction
+ EXPECT_TRUE(curve->AnimationStartScale(false, &start_scale));
+ EXPECT_EQ(6.f, start_scale);
+
+ TransformOperations operations3;
+ operations3.AppendRotate(1.f, 0.f, 0.f, 90.f);
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), operations3,
+ EaseTimingFunction::Create()));
+
+ EXPECT_FALSE(curve->AnimationStartScale(false, &start_scale));
+ EXPECT_EQ(0.f, start_scale);
+}
+
// Tests that an animation with a curve timing function works as expected.
TEST(KeyframedAnimationCurveTest, CurveTiming) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(0.0, 0.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
curve->SetTimingFunction(
CubicBezierTimingFunction::Create(0.75f, 0.f, 0.25f, 1.f).Pass());
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(-1.f));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f));
- EXPECT_NEAR(0.05f, curve->GetValue(0.25f), 0.005f);
- EXPECT_FLOAT_EQ(0.5f, curve->GetValue(0.5f));
- EXPECT_NEAR(0.95f, curve->GetValue(0.75f), 0.005f);
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(1.f));
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(2.f));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_NEAR(0.05f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
+ 0.005f);
+ EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_NEAR(0.95f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
+ 0.005f);
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that an animation with a curve and keyframe timing function works as
@@ -529,22 +750,88 @@ TEST(KeyframedAnimationCurveTest, CurveAndKeyframeTiming) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
curve->AddKeyframe(FloatKeyframe::Create(
- 0.0,
- 0.f,
+ base::TimeDelta(), 0.f,
CubicBezierTimingFunction::Create(0.35f, 0.f, 0.65f, 1.f).Pass()));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
// Curve timing function producing outputs outside of range [0,1].
curve->SetTimingFunction(
CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass());
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(-1.f));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.25f)); // Clamped. c(.25) < 0
- EXPECT_NEAR(0.17f, curve->GetValue(0.42f), 0.005f); // c(.42)=.27, k(.27)=.17
- EXPECT_FLOAT_EQ(0.5f, curve->GetValue(0.5f));
- EXPECT_NEAR(0.83f, curve->GetValue(0.58f), 0.005f); // c(.58)=.73, k(.73)=.83
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(0.75f)); // Clamped. c(.75) > 1
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(1.f));
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(2.f));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(
+ 0.25f))); // Clamped. c(.25) < 0
+ EXPECT_NEAR(0.17f, curve->GetValue(base::TimeDelta::FromSecondsD(0.42f)),
+ 0.005f); // c(.42)=.27, k(.27)=.17
+ EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ EXPECT_NEAR(0.83f, curve->GetValue(base::TimeDelta::FromSecondsD(0.58f)),
+ 0.005f); // c(.58)=.73, k(.73)=.83
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(
+ 0.75f))); // Clamped. c(.75) > 1
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a linear timing function works as expected for inputs outside of
+// range [0,1]
+TEST(KeyframedAnimationCurveTest, LinearTimingInputsOutsideZeroOneRange) {
+ scoped_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
+ // Curve timing function producing timing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass());
+
+ EXPECT_NEAR(-0.076f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
+ 0.001f);
+ EXPECT_NEAR(2.076f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
+ 0.001f);
+}
+
+// If a curve cubic-bezier timing function produces timing outputs outside
+// the range [0, 1] then a keyframe cubic-bezier timing function
+// should consume that input properly (using end-point gradients).
+TEST(KeyframedAnimationCurveTest, CurveTimingInputsOutsideZeroOneRange) {
+ scoped_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ // Keyframe timing function with 0.5 gradients at each end.
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ CubicBezierTimingFunction::Create(0.5f, 0.25f, 0.5f, 0.75f).Pass()));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
+ // Curve timing function producing timing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass());
+
+ EXPECT_NEAR(-0.02f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
+ 0.002f); // c(.25)=-.04, -.04*0.5=-0.02
+ EXPECT_NEAR(0.33f, curve->GetValue(base::TimeDelta::FromSecondsD(0.46f)),
+ 0.002f); // c(.46)=.38, k(.38)=.33
+
+ EXPECT_NEAR(0.67f, curve->GetValue(base::TimeDelta::FromSecondsD(0.54f)),
+ 0.002f); // c(.54)=.62, k(.62)=.67
+ EXPECT_NEAR(1.02f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
+ 0.002f); // c(.75)=1.04 1+.04*0.5=1.02
+}
+
+// Tests that a step timing function works as expected for inputs outside of
+// range [0,1]
+TEST(KeyframedAnimationCurveTest, StepsTimingInputsOutsideZeroOneRange) {
+ scoped_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f, StepsTimingFunction::Create(4, 0.5f)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
+ // Curve timing function producing timing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass());
+
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+ EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
}
// Tests that an animation with a curve timing function and multiple keyframes
@@ -552,21 +839,28 @@ TEST(KeyframedAnimationCurveTest, CurveAndKeyframeTiming) {
TEST(KeyframedAnimationCurveTest, CurveTimingMultipleKeyframes) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(0.0, 0.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(2.0, 3.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(3.0, 6.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(4.0, 9.f, nullptr));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 3.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), 6.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.f), 9.f, nullptr));
curve->SetTimingFunction(
CubicBezierTimingFunction::Create(0.5f, 0.f, 0.5f, 1.f).Pass());
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(-1.f));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f));
- EXPECT_NEAR(0.42f, curve->GetValue(1.f), 0.005f);
- EXPECT_NEAR(1.f, curve->GetValue(1.455f), 0.005f);
- EXPECT_FLOAT_EQ(3.f, curve->GetValue(2.f));
- EXPECT_NEAR(8.72f, curve->GetValue(3.5f), 0.01f);
- EXPECT_FLOAT_EQ(9.f, curve->GetValue(4.f));
- EXPECT_FLOAT_EQ(9.f, curve->GetValue(5.f));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ EXPECT_NEAR(0.42f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)),
+ 0.005f);
+ EXPECT_NEAR(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.455f)),
+ 0.005f);
+ EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ EXPECT_NEAR(8.72f, curve->GetValue(base::TimeDelta::FromSecondsD(3.5f)),
+ 0.01f);
+ EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(4.f)));
+ EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(5.f)));
}
// Tests that an animation with a curve timing function that overshoots works as
@@ -574,16 +868,22 @@ TEST(KeyframedAnimationCurveTest, CurveTimingMultipleKeyframes) {
TEST(KeyframedAnimationCurveTest, CurveTimingOvershootMultipeKeyframes) {
scoped_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(0.0, 0.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(2.0, 3.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(3.0, 6.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(4.0, 9.f, nullptr));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 3.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.0), 6.f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.0), 9.f, nullptr));
// Curve timing function producing outputs outside of range [0,1].
curve->SetTimingFunction(
CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass());
- EXPECT_LE(curve->GetValue(1.f), 0.f); // c(.25) < 0
- EXPECT_GE(curve->GetValue(3.f), 9.f); // c(.75) > 1
+ EXPECT_LE(curve->GetValue(base::TimeDelta::FromSecondsD(1.f)),
+ 0.f); // c(.25) < 0
+ EXPECT_GE(curve->GetValue(base::TimeDelta::FromSecondsD(3.f)),
+ 9.f); // c(.75) > 1
}
} // namespace
diff --git a/chromium/cc/animation/layer_animation_controller.cc b/chromium/cc/animation/layer_animation_controller.cc
index b779a37957a..91bfe54e159 100644
--- a/chromium/cc/animation/layer_animation_controller.cc
+++ b/chromium/cc/animation/layer_animation_controller.cc
@@ -27,7 +27,8 @@ LayerAnimationController::LayerAnimationController(int id)
is_active_(false),
value_provider_(nullptr),
layer_animation_delegate_(nullptr),
- needs_to_start_animations_(false) {
+ needs_to_start_animations_(false),
+ scroll_offset_animation_was_interrupted_(false) {
}
LayerAnimationController::~LayerAnimationController() {
@@ -44,7 +45,7 @@ void LayerAnimationController::PauseAnimation(int animation_id,
base::TimeDelta time_offset) {
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->id() == animation_id) {
- animations_[i]->SetRunState(Animation::Paused,
+ animations_[i]->SetRunState(Animation::PAUSED,
time_offset + animations_[i]->start_time());
}
}
@@ -61,12 +62,16 @@ struct HasAnimationId {
};
void LayerAnimationController::RemoveAnimation(int animation_id) {
- animations_.erase(cc::remove_if(&animations_,
- animations_.begin(),
- animations_.end(),
- HasAnimationId(animation_id)),
- animations_.end());
- UpdateActivation(NormalActivation);
+ auto animations_to_remove =
+ animations_.remove_if(HasAnimationId(animation_id));
+ for (auto it = animations_to_remove; it != animations_.end(); ++it) {
+ if ((*it)->target_property() == Animation::SCROLL_OFFSET) {
+ scroll_offset_animation_was_interrupted_ = true;
+ break;
+ }
+ }
+ animations_.erase(animations_to_remove, animations_.end());
+ UpdateActivation(NORMAL_ACTIVATION);
}
struct HasAnimationIdAndProperty {
@@ -85,13 +90,14 @@ struct HasAnimationIdAndProperty {
void LayerAnimationController::RemoveAnimation(
int animation_id,
Animation::TargetProperty target_property) {
- animations_.erase(
- cc::remove_if(&animations_,
- animations_.begin(),
- animations_.end(),
- HasAnimationIdAndProperty(animation_id, target_property)),
- animations_.end());
- UpdateActivation(NormalActivation);
+ auto animations_to_remove = animations_.remove_if(
+ HasAnimationIdAndProperty(animation_id, target_property));
+ if (target_property == Animation::SCROLL_OFFSET &&
+ animations_to_remove != animations_.end())
+ scroll_offset_animation_was_interrupted_ = true;
+
+ animations_.erase(animations_to_remove, animations_.end());
+ UpdateActivation(NORMAL_ACTIVATION);
}
void LayerAnimationController::AbortAnimations(
@@ -99,7 +105,7 @@ void LayerAnimationController::AbortAnimations(
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->target_property() == target_property &&
!animations_[i]->is_finished())
- animations_[i]->SetRunState(Animation::Aborted, last_tick_time_);
+ animations_[i]->SetRunState(Animation::ABORTED, last_tick_time_);
}
}
@@ -119,8 +125,8 @@ void LayerAnimationController::PushAnimationUpdatesTo(
RemoveAnimationsCompletedOnMainThread(controller_impl);
PushPropertiesToImplThread(controller_impl);
- controller_impl->UpdateActivation(NormalActivation);
- UpdateActivation(NormalActivation);
+ controller_impl->UpdateActivation(NORMAL_ACTIVATION);
+ UpdateActivation(NORMAL_ACTIVATION);
}
void LayerAnimationController::Animate(base::TimeTicks monotonic_time) {
@@ -148,13 +154,12 @@ void LayerAnimationController::AccumulatePropertyUpdates(
if (!animation->InEffect(monotonic_time))
continue;
- double trimmed = animation->TrimTimeToCurrentIteration(monotonic_time);
+ base::TimeDelta trimmed =
+ animation->TrimTimeToCurrentIteration(monotonic_time);
switch (animation->target_property()) {
- case Animation::Opacity: {
- AnimationEvent event(AnimationEvent::PropertyUpdate,
- id_,
- animation->group(),
- Animation::Opacity,
+ case Animation::OPACITY: {
+ AnimationEvent event(AnimationEvent::PROPERTY_UPDATE, id_,
+ animation->group(), Animation::OPACITY,
monotonic_time);
const FloatAnimationCurve* float_animation_curve =
animation->curve()->ToFloatAnimationCurve();
@@ -164,11 +169,9 @@ void LayerAnimationController::AccumulatePropertyUpdates(
break;
}
- case Animation::Transform: {
- AnimationEvent event(AnimationEvent::PropertyUpdate,
- id_,
- animation->group(),
- Animation::Transform,
+ case Animation::TRANSFORM: {
+ AnimationEvent event(AnimationEvent::PROPERTY_UPDATE, id_,
+ animation->group(), Animation::TRANSFORM,
monotonic_time);
const TransformAnimationCurve* transform_animation_curve =
animation->curve()->ToTransformAnimationCurve();
@@ -178,11 +181,9 @@ void LayerAnimationController::AccumulatePropertyUpdates(
break;
}
- case Animation::Filter: {
- AnimationEvent event(AnimationEvent::PropertyUpdate,
- id_,
- animation->group(),
- Animation::Filter,
+ case Animation::FILTER: {
+ AnimationEvent event(AnimationEvent::PROPERTY_UPDATE, id_,
+ animation->group(), Animation::FILTER,
monotonic_time);
const FilterAnimationCurve* filter_animation_curve =
animation->curve()->ToFilterAnimationCurve();
@@ -192,17 +193,16 @@ void LayerAnimationController::AccumulatePropertyUpdates(
break;
}
- case Animation::BackgroundColor: { break; }
+ case Animation::BACKGROUND_COLOR: {
+ break;
+ }
- case Animation::ScrollOffset: {
+ case Animation::SCROLL_OFFSET: {
// Impl-side changes to scroll offset are already sent back to the
- // main thread (e.g. for user-driven scrolling), so a PropertyUpdate
+ // main thread (e.g. for user-driven scrolling), so a PROPERTY_UPDATE
// isn't needed.
break;
}
-
- case Animation::TargetPropertyEnumSize:
- NOTREACHED();
}
}
}
@@ -212,7 +212,11 @@ void LayerAnimationController::UpdateState(bool start_ready_animations,
if (!HasActiveValueObserver())
return;
- DCHECK(last_tick_time_ != base::TimeTicks());
+ // Animate hasn't been called, this happens if an observer has been added
+ // between the Commit and Draw phases.
+ if (last_tick_time_ == base::TimeTicks())
+ return;
+
if (start_ready_animations)
PromoteStartedAnimations(last_tick_time_, events);
@@ -226,7 +230,7 @@ void LayerAnimationController::UpdateState(bool start_ready_animations,
AccumulatePropertyUpdates(last_tick_time_, events);
- UpdateActivation(NormalActivation);
+ UpdateActivation(NORMAL_ACTIVATION);
}
struct AffectsNoObservers {
@@ -246,23 +250,14 @@ void LayerAnimationController::ActivateAnimations() {
animations_.end(),
AffectsNoObservers()),
animations_.end());
- UpdateActivation(NormalActivation);
+ scroll_offset_animation_was_interrupted_ = false;
+ UpdateActivation(NORMAL_ACTIVATION);
}
void LayerAnimationController::AddAnimation(scoped_ptr<Animation> animation) {
animations_.push_back(animation.Pass());
needs_to_start_animations_ = true;
- UpdateActivation(NormalActivation);
-}
-
-Animation* LayerAnimationController::GetAnimation(
- int group_id,
- Animation::TargetProperty target_property) const {
- for (size_t i = 0; i < animations_.size(); ++i)
- if (animations_[i]->group() == group_id &&
- animations_[i]->target_property() == target_property)
- return animations_[i];
- return 0;
+ UpdateActivation(NORMAL_ACTIVATION);
}
Animation* LayerAnimationController::GetAnimation(
@@ -275,6 +270,13 @@ Animation* LayerAnimationController::GetAnimation(
return 0;
}
+Animation* LayerAnimationController::GetAnimationById(int animation_id) const {
+ for (size_t i = 0; i < animations_.size(); ++i)
+ if (animations_[i]->id() == animation_id)
+ return animations_[i];
+ return nullptr;
+}
+
bool LayerAnimationController::HasActiveAnimation() const {
for (size_t i = 0; i < animations_.size(); ++i) {
if (!animations_[i]->is_finished())
@@ -306,7 +308,7 @@ void LayerAnimationController::SetAnimationRegistrar(
if (registrar_)
registrar_->RegisterAnimationController(this);
- UpdateActivation(ForceActivation);
+ UpdateActivation(FORCE_ACTIVATION);
}
void LayerAnimationController::NotifyAnimationStarted(
@@ -366,7 +368,7 @@ void LayerAnimationController::NotifyAnimationAborted(
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->group() == event.group_id &&
animations_[i]->target_property() == event.target_property) {
- animations_[i]->SetRunState(Animation::Aborted, event.monotonic_time);
+ animations_[i]->SetRunState(Animation::ABORTED, event.monotonic_time);
}
}
}
@@ -376,11 +378,11 @@ void LayerAnimationController::NotifyAnimationPropertyUpdate(
bool notify_active_observers = true;
bool notify_pending_observers = true;
switch (event.target_property) {
- case Animation::Opacity:
+ case Animation::OPACITY:
NotifyObserversOpacityAnimated(
event.opacity, notify_active_observers, notify_pending_observers);
break;
- case Animation::Transform:
+ case Animation::TRANSFORM:
NotifyObserversTransformAnimated(
event.transform, notify_active_observers, notify_pending_observers);
break;
@@ -414,7 +416,7 @@ void LayerAnimationController::RemoveEventObserver(
bool LayerAnimationController::HasFilterAnimationThatInflatesBounds() const {
for (size_t i = 0; i < animations_.size(); ++i) {
if (!animations_[i]->is_finished() &&
- animations_[i]->target_property() == Animation::Filter &&
+ animations_[i]->target_property() == Animation::FILTER &&
animations_[i]
->curve()
->ToFilterAnimationCurve()
@@ -426,7 +428,7 @@ bool LayerAnimationController::HasFilterAnimationThatInflatesBounds() const {
}
bool LayerAnimationController::HasTransformAnimationThatInflatesBounds() const {
- return IsAnimatingProperty(Animation::Transform);
+ return IsAnimatingProperty(Animation::TRANSFORM);
}
bool LayerAnimationController::FilterAnimationBoundsForBox(
@@ -450,7 +452,7 @@ bool LayerAnimationController::TransformAnimationBoundsForBox(
*bounds = gfx::BoxF();
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->is_finished() ||
- animations_[i]->target_property() != Animation::Transform)
+ animations_[i]->target_property() != Animation::TRANSFORM)
continue;
const TransformAnimationCurve* transform_animation_curve =
@@ -469,7 +471,7 @@ bool LayerAnimationController::TransformAnimationBoundsForBox(
bool LayerAnimationController::HasAnimationThatAffectsScale() const {
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->is_finished() ||
- animations_[i]->target_property() != Animation::Transform)
+ animations_[i]->target_property() != Animation::TRANSFORM)
continue;
const TransformAnimationCurve* transform_animation_curve =
@@ -484,7 +486,7 @@ bool LayerAnimationController::HasAnimationThatAffectsScale() const {
bool LayerAnimationController::HasOnlyTranslationTransforms() const {
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->is_finished() ||
- animations_[i]->target_property() != Animation::Transform)
+ animations_[i]->target_property() != Animation::TRANSFORM)
continue;
const TransformAnimationCurve* transform_animation_curve =
@@ -496,21 +498,66 @@ bool LayerAnimationController::HasOnlyTranslationTransforms() const {
return true;
}
+bool LayerAnimationController::AnimationsPreserveAxisAlignment() const {
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->is_finished() ||
+ animations_[i]->target_property() != Animation::TRANSFORM)
+ continue;
+
+ const TransformAnimationCurve* transform_animation_curve =
+ animations_[i]->curve()->ToTransformAnimationCurve();
+ if (!transform_animation_curve->PreservesAxisAlignment())
+ return false;
+ }
+
+ return true;
+}
+
+bool LayerAnimationController::AnimationStartScale(float* start_scale) const {
+ *start_scale = 0.f;
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->is_finished() ||
+ animations_[i]->target_property() != Animation::TRANSFORM)
+ continue;
+
+ bool forward_direction = true;
+ switch (animations_[i]->direction()) {
+ case Animation::DIRECTION_NORMAL:
+ case Animation::DIRECTION_ALTERNATE:
+ forward_direction = animations_[i]->playback_rate() >= 0.0;
+ break;
+ case Animation::DIRECTION_REVERSE:
+ case Animation::DIRECTION_ALTERNATE_REVERSE:
+ forward_direction = animations_[i]->playback_rate() < 0.0;
+ break;
+ }
+
+ const TransformAnimationCurve* transform_animation_curve =
+ animations_[i]->curve()->ToTransformAnimationCurve();
+ float animation_start_scale = 0.f;
+ if (!transform_animation_curve->AnimationStartScale(forward_direction,
+ &animation_start_scale))
+ return false;
+ *start_scale = std::max(*start_scale, animation_start_scale);
+ }
+ return true;
+}
+
bool LayerAnimationController::MaximumTargetScale(float* max_scale) const {
*max_scale = 0.f;
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->is_finished() ||
- animations_[i]->target_property() != Animation::Transform)
+ animations_[i]->target_property() != Animation::TRANSFORM)
continue;
bool forward_direction = true;
switch (animations_[i]->direction()) {
- case Animation::Normal:
- case Animation::Alternate:
+ case Animation::DIRECTION_NORMAL:
+ case Animation::DIRECTION_ALTERNATE:
forward_direction = animations_[i]->playback_rate() >= 0.0;
break;
- case Animation::Reverse:
- case Animation::AlternateReverse:
+ case Animation::DIRECTION_REVERSE:
+ case Animation::DIRECTION_ALTERNATE_REVERSE:
forward_direction = animations_[i]->playback_rate() < 0.0;
break;
}
@@ -534,8 +581,7 @@ void LayerAnimationController::PushNewAnimationsToImplThread(
for (size_t i = 0; i < animations_.size(); ++i) {
// If the animation is already running on the impl thread, there is no
// need to copy it over.
- if (controller_impl->GetAnimation(animations_[i]->group(),
- animations_[i]->target_property()))
+ if (controller_impl->GetAnimationById(animations_[i]->id()))
continue;
// If the animation is not running on the impl thread, it does not
@@ -548,7 +594,7 @@ void LayerAnimationController::PushNewAnimationsToImplThread(
continue;
// Scroll animations always start at the current scroll offset.
- if (animations_[i]->target_property() == Animation::ScrollOffset) {
+ if (animations_[i]->target_property() == Animation::SCROLL_OFFSET) {
gfx::ScrollOffset current_scroll_offset;
if (controller_impl->value_provider_) {
current_scroll_offset =
@@ -564,7 +610,7 @@ void LayerAnimationController::PushNewAnimationsToImplThread(
// The new animation should be set to run as soon as possible.
Animation::RunState initial_run_state =
- Animation::WaitingForTargetAvailability;
+ Animation::WAITING_FOR_TARGET_AVAILABILITY;
scoped_ptr<Animation> to_add(
animations_[i]->CloneAndInitialize(initial_run_state));
DCHECK(!to_add->needs_synchronized_start_time());
@@ -577,15 +623,14 @@ static bool IsCompleted(
Animation* animation,
const LayerAnimationController* main_thread_controller) {
if (animation->is_impl_only()) {
- return (animation->run_state() == Animation::WaitingForDeletion);
+ return (animation->run_state() == Animation::WAITING_FOR_DELETION);
} else {
- return !main_thread_controller->GetAnimation(animation->group(),
- animation->target_property());
+ return !main_thread_controller->GetAnimationById(animation->id());
}
}
static bool AffectsActiveOnlyAndIsWaitingForDeletion(Animation* animation) {
- return animation->run_state() == Animation::WaitingForDeletion &&
+ return animation->run_state() == Animation::WAITING_FOR_DELETION &&
!animation->affects_pending_observers();
}
@@ -593,7 +638,7 @@ void LayerAnimationController::RemoveAnimationsCompletedOnMainThread(
LayerAnimationController* controller_impl) const {
// Animations removed on the main thread should no longer affect pending
// observers, and should stop affecting active observers after the next call
- // to ActivateAnimations. If already WaitingForDeletion, they can be removed
+ // to ActivateAnimations. If already WAITING_FOR_DELETION, they can be removed
// immediately.
ScopedPtrVector<Animation>& animations = controller_impl->animations_;
for (size_t i = 0; i < animations.size(); ++i) {
@@ -608,13 +653,16 @@ void LayerAnimationController::RemoveAnimationsCompletedOnMainThread(
}
void LayerAnimationController::PushPropertiesToImplThread(
- LayerAnimationController* controller_impl) const {
+ LayerAnimationController* controller_impl) {
for (size_t i = 0; i < animations_.size(); ++i) {
- Animation* current_impl = controller_impl->GetAnimation(
- animations_[i]->group(), animations_[i]->target_property());
+ Animation* current_impl =
+ controller_impl->GetAnimationById(animations_[i]->id());
if (current_impl)
animations_[i]->PushPropertiesTo(current_impl);
}
+ controller_impl->scroll_offset_animation_was_interrupted_ =
+ scroll_offset_animation_was_interrupted_;
+ scroll_offset_animation_was_interrupted_ = false;
}
void LayerAnimationController::StartAnimations(base::TimeTicks monotonic_time) {
@@ -627,8 +675,8 @@ void LayerAnimationController::StartAnimations(base::TimeTicks monotonic_time) {
animations_waiting_for_target.reserve(animations_.size());
for (size_t i = 0; i < animations_.size(); ++i) {
- if (animations_[i]->run_state() == Animation::Starting ||
- animations_[i]->run_state() == Animation::Running) {
+ if (animations_[i]->run_state() == Animation::STARTING ||
+ animations_[i]->run_state() == Animation::RUNNING) {
if (animations_[i]->affects_active_observers()) {
blocked_properties_for_active_observers.insert(
animations_[i]->target_property());
@@ -638,7 +686,7 @@ void LayerAnimationController::StartAnimations(base::TimeTicks monotonic_time) {
animations_[i]->target_property());
}
} else if (animations_[i]->run_state() ==
- Animation::WaitingForTargetAvailability) {
+ Animation::WAITING_FOR_TARGET_AVAILABILITY) {
animations_waiting_for_target.push_back(i);
}
}
@@ -652,7 +700,7 @@ void LayerAnimationController::StartAnimations(base::TimeTicks monotonic_time) {
// for target because it might have changed the run state while handling
// previous animation in this loop (if they belong to same group).
if (animation_waiting_for_target->run_state() ==
- Animation::WaitingForTargetAvailability) {
+ Animation::WAITING_FOR_TARGET_AVAILABILITY) {
TargetProperties enqueued_properties;
bool affects_active_observers =
animation_waiting_for_target->affects_active_observers();
@@ -690,12 +738,12 @@ void LayerAnimationController::StartAnimations(base::TimeTicks monotonic_time) {
// If the intersection is null, then we are free to start the animations
// in the group.
if (null_intersection) {
- animation_waiting_for_target->SetRunState(Animation::Starting,
+ animation_waiting_for_target->SetRunState(Animation::STARTING,
monotonic_time);
for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
if (animation_waiting_for_target->group() ==
animations_[j]->group()) {
- animations_[j]->SetRunState(Animation::Starting, monotonic_time);
+ animations_[j]->SetRunState(Animation::STARTING, monotonic_time);
}
}
} else {
@@ -709,18 +757,16 @@ void LayerAnimationController::PromoteStartedAnimations(
base::TimeTicks monotonic_time,
AnimationEventsVector* events) {
for (size_t i = 0; i < animations_.size(); ++i) {
- if (animations_[i]->run_state() == Animation::Starting &&
+ if (animations_[i]->run_state() == Animation::STARTING &&
animations_[i]->affects_active_observers()) {
- animations_[i]->SetRunState(Animation::Running, monotonic_time);
+ animations_[i]->SetRunState(Animation::RUNNING, monotonic_time);
if (!animations_[i]->has_set_start_time() &&
!animations_[i]->needs_synchronized_start_time())
animations_[i]->set_start_time(monotonic_time);
if (events) {
- AnimationEvent started_event(AnimationEvent::Started,
- id_,
- animations_[i]->group(),
- animations_[i]->target_property(),
- monotonic_time);
+ AnimationEvent started_event(
+ AnimationEvent::STARTED, id_, animations_[i]->group(),
+ animations_[i]->target_property(), monotonic_time);
started_event.is_impl_only = animations_[i]->is_impl_only();
if (started_event.is_impl_only)
NotifyAnimationStarted(started_event);
@@ -735,9 +781,9 @@ void LayerAnimationController::MarkFinishedAnimations(
base::TimeTicks monotonic_time) {
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->IsFinishedAt(monotonic_time) &&
- animations_[i]->run_state() != Animation::Aborted &&
- animations_[i]->run_state() != Animation::WaitingForDeletion)
- animations_[i]->SetRunState(Animation::Finished, monotonic_time);
+ animations_[i]->run_state() != Animation::ABORTED &&
+ animations_[i]->run_state() != Animation::WAITING_FOR_DELETION)
+ animations_[i]->SetRunState(Animation::FINISHED, monotonic_time);
}
}
@@ -749,21 +795,19 @@ void LayerAnimationController::MarkAnimationsForDeletion(
animations_with_same_group_id.reserve(animations_.size());
// Non-aborted animations are marked for deletion after a corresponding
- // AnimationEvent::Finished event is sent or received. This means that if
+ // AnimationEvent::FINISHED event is sent or received. This means that if
// we don't have an events vector, we must ensure that non-aborted animations
// have received a finished event before marking them for deletion.
for (size_t i = 0; i < animations_.size(); i++) {
int group_id = animations_[i]->group();
- if (animations_[i]->run_state() == Animation::Aborted) {
+ if (animations_[i]->run_state() == Animation::ABORTED) {
if (events && !animations_[i]->is_impl_only()) {
- AnimationEvent aborted_event(AnimationEvent::Aborted,
- id_,
- group_id,
+ AnimationEvent aborted_event(AnimationEvent::ABORTED, id_, group_id,
animations_[i]->target_property(),
monotonic_time);
events->push_back(aborted_event);
}
- animations_[i]->SetRunState(Animation::WaitingForDeletion,
+ animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION,
monotonic_time);
marked_animations_for_deletions = true;
continue;
@@ -772,13 +816,13 @@ void LayerAnimationController::MarkAnimationsForDeletion(
bool all_anims_with_same_id_are_finished = false;
// Since deleting an animation on the main thread leads to its deletion
- // on the impl thread, we only mark a Finished main thread animation for
- // deletion once it has received a Finished event from the impl thread.
+ // on the impl thread, we only mark a FINISHED main thread animation for
+ // deletion once it has received a FINISHED event from the impl thread.
bool animation_i_will_send_or_has_received_finish_event =
events || animations_[i]->received_finished_event();
// If an animation is finished, and not already marked for deletion,
// find out if all other animations in the same group are also finished.
- if (animations_[i]->run_state() == Animation::Finished &&
+ if (animations_[i]->run_state() == Animation::FINISHED &&
animation_i_will_send_or_has_received_finish_event) {
// Clear the animations_with_same_group_id if it was added for
// the previous animation's iteration.
@@ -790,16 +834,16 @@ void LayerAnimationController::MarkAnimationsForDeletion(
events || animations_[j]->received_finished_event();
if (group_id == animations_[j]->group()) {
if (!animations_[j]->is_finished() ||
- (animations_[j]->run_state() == Animation::Finished &&
+ (animations_[j]->run_state() == Animation::FINISHED &&
!animation_j_will_send_or_has_received_finish_event)) {
all_anims_with_same_id_are_finished = false;
break;
} else if (j >= i &&
- animations_[j]->run_state() != Animation::Aborted) {
+ animations_[j]->run_state() != Animation::ABORTED) {
// Mark down the animations which belong to the same group
// and is not yet aborted. If this current iteration finds that all
// animations with same ID are finished, then the marked
- // animations below will be set to WaitingForDeletion in next
+ // animations below will be set to WAITING_FOR_DELETION in next
// iteration.
animations_with_same_group_id.push_back(j);
}
@@ -814,8 +858,7 @@ void LayerAnimationController::MarkAnimationsForDeletion(
size_t animation_index = animations_with_same_group_id[j];
if (events) {
AnimationEvent finished_event(
- AnimationEvent::Finished,
- id_,
+ AnimationEvent::FINISHED, id_,
animations_[animation_index]->group(),
animations_[animation_index]->target_property(),
monotonic_time);
@@ -827,7 +870,7 @@ void LayerAnimationController::MarkAnimationsForDeletion(
events->push_back(finished_event);
}
animations_[animation_index]->SetRunState(
- Animation::WaitingForDeletion, monotonic_time);
+ Animation::WAITING_FOR_DELETION, monotonic_time);
}
marked_animations_for_deletions = true;
}
@@ -837,7 +880,7 @@ void LayerAnimationController::MarkAnimationsForDeletion(
}
static bool IsWaitingForDeletion(Animation* animation) {
- return animation->run_state() == Animation::WaitingForDeletion;
+ return animation->run_state() == Animation::WAITING_FOR_DELETION;
}
void LayerAnimationController::PurgeAnimationsMarkedForDeletion() {
@@ -850,17 +893,17 @@ void LayerAnimationController::PurgeAnimationsMarkedForDeletion() {
void LayerAnimationController::TickAnimations(base::TimeTicks monotonic_time) {
for (size_t i = 0; i < animations_.size(); ++i) {
- if (animations_[i]->run_state() == Animation::Starting ||
- animations_[i]->run_state() == Animation::Running ||
- animations_[i]->run_state() == Animation::Paused) {
+ if (animations_[i]->run_state() == Animation::STARTING ||
+ animations_[i]->run_state() == Animation::RUNNING ||
+ animations_[i]->run_state() == Animation::PAUSED) {
if (!animations_[i]->InEffect(monotonic_time))
continue;
- double trimmed =
+ base::TimeDelta trimmed =
animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
switch (animations_[i]->target_property()) {
- case Animation::Transform: {
+ case Animation::TRANSFORM: {
const TransformAnimationCurve* transform_animation_curve =
animations_[i]->curve()->ToTransformAnimationCurve();
const gfx::Transform transform =
@@ -872,7 +915,7 @@ void LayerAnimationController::TickAnimations(base::TimeTicks monotonic_time) {
break;
}
- case Animation::Opacity: {
+ case Animation::OPACITY: {
const FloatAnimationCurve* float_animation_curve =
animations_[i]->curve()->ToFloatAnimationCurve();
const float opacity = std::max(
@@ -884,7 +927,7 @@ void LayerAnimationController::TickAnimations(base::TimeTicks monotonic_time) {
break;
}
- case Animation::Filter: {
+ case Animation::FILTER: {
const FilterAnimationCurve* filter_animation_curve =
animations_[i]->curve()->ToFilterAnimationCurve();
const FilterOperations filter =
@@ -896,12 +939,12 @@ void LayerAnimationController::TickAnimations(base::TimeTicks monotonic_time) {
break;
}
- case Animation::BackgroundColor: {
+ case Animation::BACKGROUND_COLOR: {
// Not yet implemented.
break;
}
- case Animation::ScrollOffset: {
+ case Animation::SCROLL_OFFSET: {
const ScrollOffsetAnimationCurve* scroll_offset_animation_curve =
animations_[i]->curve()->ToScrollOffsetAnimationCurve();
const gfx::ScrollOffset scroll_offset =
@@ -912,22 +955,18 @@ void LayerAnimationController::TickAnimations(base::TimeTicks monotonic_time) {
animations_[i]->affects_pending_observers());
break;
}
-
- // Do nothing for sentinel value.
- case Animation::TargetPropertyEnumSize:
- NOTREACHED();
}
}
}
}
void LayerAnimationController::UpdateActivation(UpdateActivationType type) {
- bool force = type == ForceActivation;
+ bool force = type == FORCE_ACTIVATION;
if (registrar_) {
bool was_active = is_active_;
is_active_ = false;
for (size_t i = 0; i < animations_.size(); ++i) {
- if (animations_[i]->run_state() != Animation::WaitingForDeletion) {
+ if (animations_[i]->run_state() != Animation::WAITING_FOR_DELETION) {
is_active_ = true;
break;
}
@@ -946,7 +985,7 @@ void LayerAnimationController::NotifyObserversOpacityAnimated(
bool notify_pending_observers) {
if (value_observers_.might_have_observers()) {
ObserverListBase<LayerAnimationValueObserver>::Iterator it(
- value_observers_);
+ &value_observers_);
LayerAnimationValueObserver* obs;
while ((obs = it.GetNext()) != nullptr) {
if ((notify_active_observers && notify_pending_observers) ||
@@ -963,7 +1002,7 @@ void LayerAnimationController::NotifyObserversTransformAnimated(
bool notify_pending_observers) {
if (value_observers_.might_have_observers()) {
ObserverListBase<LayerAnimationValueObserver>::Iterator it(
- value_observers_);
+ &value_observers_);
LayerAnimationValueObserver* obs;
while ((obs = it.GetNext()) != nullptr) {
if ((notify_active_observers && notify_pending_observers) ||
@@ -980,7 +1019,7 @@ void LayerAnimationController::NotifyObserversFilterAnimated(
bool notify_pending_observers) {
if (value_observers_.might_have_observers()) {
ObserverListBase<LayerAnimationValueObserver>::Iterator it(
- value_observers_);
+ &value_observers_);
LayerAnimationValueObserver* obs;
while ((obs = it.GetNext()) != nullptr) {
if ((notify_active_observers && notify_pending_observers) ||
@@ -997,7 +1036,7 @@ void LayerAnimationController::NotifyObserversScrollOffsetAnimated(
bool notify_pending_observers) {
if (value_observers_.might_have_observers()) {
ObserverListBase<LayerAnimationValueObserver>::Iterator it(
- value_observers_);
+ &value_observers_);
LayerAnimationValueObserver* obs;
while ((obs = it.GetNext()) != nullptr) {
if ((notify_active_observers && notify_pending_observers) ||
@@ -1017,7 +1056,7 @@ void LayerAnimationController::NotifyObserversAnimationWaitingForDeletion() {
bool LayerAnimationController::HasValueObserver() {
if (value_observers_.might_have_observers()) {
ObserverListBase<LayerAnimationValueObserver>::Iterator it(
- value_observers_);
+ &value_observers_);
return it.GetNext() != nullptr;
}
return false;
@@ -1026,7 +1065,7 @@ bool LayerAnimationController::HasValueObserver() {
bool LayerAnimationController::HasActiveValueObserver() {
if (value_observers_.might_have_observers()) {
ObserverListBase<LayerAnimationValueObserver>::Iterator it(
- value_observers_);
+ &value_observers_);
LayerAnimationValueObserver* obs;
while ((obs = it.GetNext()) != nullptr)
if (obs->IsActive())
diff --git a/chromium/cc/animation/layer_animation_controller.h b/chromium/cc/animation/layer_animation_controller.h
index 01fce98c466..1ac76fa393e 100644
--- a/chromium/cc/animation/layer_animation_controller.h
+++ b/chromium/cc/animation/layer_animation_controller.h
@@ -65,15 +65,13 @@ class CC_EXPORT LayerAnimationController
// are deleted.
void ActivateAnimations();
- // Returns the active animation in the given group, animating the given
- // property, if such an animation exists.
- Animation* GetAnimation(int group_id,
- Animation::TargetProperty target_property) const;
-
// Returns the active animation animating the given property that is either
// running, or is next to run, if such an animation exists.
Animation* GetAnimation(Animation::TargetProperty target_property) const;
+ // Returns the active animation for the given unique animation id.
+ Animation* GetAnimationById(int animation_id) const;
+
// Returns true if there are any animations that have neither finished nor
// aborted.
bool HasActiveAnimation() const;
@@ -134,11 +132,29 @@ class CC_EXPORT LayerAnimationController
bool HasOnlyTranslationTransforms() const;
+ bool AnimationsPreserveAxisAlignment() const;
+
+ // Sets |start_scale| to the maximum of starting animation scale along any
+ // dimension at any destination in active animations. Returns false if the
+ // starting scale cannot be computed.
+ bool AnimationStartScale(float* start_scale) const;
+
// Sets |max_scale| to the maximum scale along any dimension at any
// destination in active animations. Returns false if the maximum scale cannot
// be computed.
bool MaximumTargetScale(float* max_scale) const;
+ // When a scroll animation is removed on the main thread, its compositor
+ // thread counterpart continues producing scroll deltas until activation.
+ // These scroll deltas need to be cleared at activation, so that the active
+ // layer's scroll offset matches the offset provided by the main thread
+ // rather than a combination of this offset and scroll deltas produced by
+ // the removed animation. This is to provide the illusion of synchronicity to
+ // JS that simultaneously removes an animation and sets the scroll offset.
+ bool scroll_offset_animation_was_interrupted() const {
+ return scroll_offset_animation_was_interrupted_;
+ }
+
bool needs_to_start_animations_for_testing() {
return needs_to_start_animations_;
}
@@ -156,8 +172,7 @@ class CC_EXPORT LayerAnimationController
LayerAnimationController* controller_impl) const;
void RemoveAnimationsCompletedOnMainThread(
LayerAnimationController* controller_impl) const;
- void PushPropertiesToImplThread(
- LayerAnimationController* controller_impl) const;
+ void PushPropertiesToImplThread(LayerAnimationController* controller_impl);
void StartAnimations(base::TimeTicks monotonic_time);
void PromoteStartedAnimations(base::TimeTicks monotonic_time,
@@ -169,10 +184,7 @@ class CC_EXPORT LayerAnimationController
void TickAnimations(base::TimeTicks monotonic_time);
- enum UpdateActivationType {
- NormalActivation,
- ForceActivation
- };
+ enum UpdateActivationType { NORMAL_ACTIVATION, FORCE_ACTIVATION };
void UpdateActivation(UpdateActivationType type);
void NotifyObserversOpacityAnimated(float opacity,
@@ -214,6 +226,8 @@ class CC_EXPORT LayerAnimationController
// previous attempt at starting animations failed to start all animations.
bool needs_to_start_animations_;
+ bool scroll_offset_animation_was_interrupted_;
+
DISALLOW_COPY_AND_ASSIGN(LayerAnimationController);
};
diff --git a/chromium/cc/animation/layer_animation_controller_unittest.cc b/chromium/cc/animation/layer_animation_controller_unittest.cc
index 49ac0a5faef..ad1d4c9eece 100644
--- a/chromium/cc/animation/layer_animation_controller_unittest.cc
+++ b/chromium/cc/animation/layer_animation_controller_unittest.cc
@@ -34,9 +34,9 @@ static base::TimeTicks TicksFromSecondsF(double seconds) {
const TimeTicks kInitialTickTime = TicksFromSecondsF(1.0);
scoped_ptr<Animation> CreateAnimation(scoped_ptr<AnimationCurve> curve,
- int id,
+ int group_id,
Animation::TargetProperty property) {
- return Animation::Create(curve.Pass(), 0, id, property);
+ return Animation::Create(curve.Pass(), 0, group_id, property);
}
TEST(LayerAnimationControllerTest, SyncNewAnimation) {
@@ -49,23 +49,22 @@ TEST(LayerAnimationControllerTest, SyncNewAnimation) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimation(Animation::OPACITY));
EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
- AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
+ int animation_id =
+ AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
controller->PushAnimationUpdatesTo(controller_impl.get());
EXPECT_TRUE(controller_impl->needs_to_start_animations_for_testing());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->run_state());
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller_impl->GetAnimationById(animation_id)->run_state());
}
// If an animation is started on the impl thread before it is ticked on the main
@@ -80,18 +79,17 @@ TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimation(Animation::OPACITY));
- AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
+ int animation_id =
+ AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->run_state());
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller_impl->GetAnimationById(animation_id)->run_state());
AnimationEventsVector events;
controller_impl->Animate(kInitialTickTime);
@@ -100,18 +98,14 @@ TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) {
// Synchronize the start times.
EXPECT_EQ(1u, events.size());
controller->NotifyAnimationStarted(events[0]);
- EXPECT_EQ(controller->GetAnimation(group_id,
- Animation::Opacity)->start_time(),
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->start_time());
+ EXPECT_EQ(controller->GetAnimationById(animation_id)->start_time(),
+ controller_impl->GetAnimationById(animation_id)->start_time());
// Start the animation on the main thread. Should not affect the start time.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, nullptr);
- EXPECT_EQ(controller->GetAnimation(group_id,
- Animation::Opacity)->start_time(),
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->start_time());
+ EXPECT_EQ(controller->GetAnimationById(animation_id)->start_time(),
+ controller_impl->GetAnimationById(animation_id)->start_time());
}
TEST(LayerAnimationControllerTest, UseSpecifiedStartTimes) {
@@ -124,19 +118,18 @@ TEST(LayerAnimationControllerTest, UseSpecifiedStartTimes) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
+ int animation_id =
+ AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
const TimeTicks start_time = TicksFromSecondsF(123);
- controller->GetAnimation(Animation::Opacity)->set_start_time(start_time);
+ controller->GetAnimation(Animation::OPACITY)->set_start_time(start_time);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->run_state());
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller_impl->GetAnimationById(animation_id)->run_state());
AnimationEventsVector events;
controller_impl->Animate(kInitialTickTime);
@@ -147,23 +140,17 @@ TEST(LayerAnimationControllerTest, UseSpecifiedStartTimes) {
controller->NotifyAnimationStarted(events[0]);
EXPECT_EQ(start_time,
- controller->GetAnimation(group_id,
- Animation::Opacity)->start_time());
- EXPECT_EQ(controller->GetAnimation(group_id,
- Animation::Opacity)->start_time(),
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->start_time());
+ controller->GetAnimationById(animation_id)->start_time());
+ EXPECT_EQ(controller->GetAnimationById(animation_id)->start_time(),
+ controller_impl->GetAnimationById(animation_id)->start_time());
// Start the animation on the main thread. Should not affect the start time.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, nullptr);
EXPECT_EQ(start_time,
- controller->GetAnimation(group_id,
- Animation::Opacity)->start_time());
- EXPECT_EQ(controller->GetAnimation(group_id,
- Animation::Opacity)->start_time(),
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->start_time());
+ controller->GetAnimationById(animation_id)->start_time());
+ EXPECT_EQ(controller->GetAnimationById(animation_id)->start_time(),
+ controller_impl->GetAnimationById(animation_id)->start_time());
}
// Tests that controllers activate and deactivate as expected.
@@ -184,67 +171,72 @@ TEST(LayerAnimationControllerTest, Activation) {
controller->SetAnimationRegistrar(registrar.get());
controller_impl->SetAnimationRegistrar(registrar_impl.get());
- EXPECT_EQ(1u, registrar->all_animation_controllers().size());
- EXPECT_EQ(1u, registrar_impl->all_animation_controllers().size());
+ EXPECT_EQ(1u, registrar->all_animation_controllers_for_testing().size());
+ EXPECT_EQ(1u, registrar_impl->all_animation_controllers_for_testing().size());
// Initially, both controllers should be inactive.
- EXPECT_EQ(0u, registrar->active_animation_controllers().size());
- EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size());
+ EXPECT_EQ(0u, registrar->active_animation_controllers_for_testing().size());
+ EXPECT_EQ(0u,
+ registrar_impl->active_animation_controllers_for_testing().size());
AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
// The main thread controller should now be active.
- EXPECT_EQ(1u, registrar->active_animation_controllers().size());
+ EXPECT_EQ(1u, registrar->active_animation_controllers_for_testing().size());
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
// Both controllers should now be active.
- EXPECT_EQ(1u, registrar->active_animation_controllers().size());
- EXPECT_EQ(1u, registrar_impl->active_animation_controllers().size());
+ EXPECT_EQ(1u, registrar->active_animation_controllers_for_testing().size());
+ EXPECT_EQ(1u,
+ registrar_impl->active_animation_controllers_for_testing().size());
controller_impl->Animate(kInitialTickTime);
controller_impl->UpdateState(true, events.get());
EXPECT_EQ(1u, events->size());
controller->NotifyAnimationStarted((*events)[0]);
- EXPECT_EQ(1u, registrar->active_animation_controllers().size());
- EXPECT_EQ(1u, registrar_impl->active_animation_controllers().size());
+ EXPECT_EQ(1u, registrar->active_animation_controllers_for_testing().size());
+ EXPECT_EQ(1u,
+ registrar_impl->active_animation_controllers_for_testing().size());
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, nullptr);
- EXPECT_EQ(1u, registrar->active_animation_controllers().size());
+ EXPECT_EQ(1u, registrar->active_animation_controllers_for_testing().size());
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, nullptr);
- EXPECT_EQ(Animation::Finished,
- controller->GetAnimation(Animation::Opacity)->run_state());
- EXPECT_EQ(1u, registrar->active_animation_controllers().size());
+ EXPECT_EQ(Animation::FINISHED,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
+ EXPECT_EQ(1u, registrar->active_animation_controllers_for_testing().size());
events.reset(new AnimationEventsVector);
controller_impl->Animate(kInitialTickTime +
TimeDelta::FromMilliseconds(1500));
controller_impl->UpdateState(true, events.get());
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller_impl->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller_impl->GetAnimation(Animation::OPACITY)->run_state());
// The impl thread controller should have de-activated.
- EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size());
+ EXPECT_EQ(0u,
+ registrar_impl->active_animation_controllers_for_testing().size());
EXPECT_EQ(1u, events->size());
controller->NotifyAnimationFinished((*events)[0]);
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1500));
controller->UpdateState(true, nullptr);
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
// The main thread controller should have de-activated.
- EXPECT_EQ(0u, registrar->active_animation_controllers().size());
+ EXPECT_EQ(0u, registrar->active_animation_controllers_for_testing().size());
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
EXPECT_FALSE(controller->has_any_animation());
EXPECT_FALSE(controller_impl->has_any_animation());
- EXPECT_EQ(0u, registrar->active_animation_controllers().size());
- EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size());
+ EXPECT_EQ(0u, registrar->active_animation_controllers_for_testing().size());
+ EXPECT_EQ(0u,
+ registrar_impl->active_animation_controllers_for_testing().size());
controller->SetAnimationRegistrar(nullptr);
controller_impl->SetAnimationRegistrar(nullptr);
@@ -260,19 +252,17 @@ TEST(LayerAnimationControllerTest, SyncPause) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimation(Animation::OPACITY));
- AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
- int animation_id = controller->GetAnimation(Animation::Opacity)->id();
+ int animation_id =
+ AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->run_state());
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller_impl->GetAnimationById(animation_id)->run_state());
// Start the animations on each controller.
AnimationEventsVector events;
@@ -280,27 +270,23 @@ TEST(LayerAnimationControllerTest, SyncPause) {
controller_impl->UpdateState(true, &events);
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
- EXPECT_EQ(Animation::Running,
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->run_state());
- EXPECT_EQ(Animation::Running,
- controller->GetAnimation(group_id,
- Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::RUNNING,
+ controller_impl->GetAnimationById(animation_id)->run_state());
+ EXPECT_EQ(Animation::RUNNING,
+ controller->GetAnimationById(animation_id)->run_state());
// Pause the main-thread animation.
controller->PauseAnimation(
animation_id,
TimeDelta::FromMilliseconds(1000) + TimeDelta::FromMilliseconds(1000));
- EXPECT_EQ(Animation::Paused,
- controller->GetAnimation(group_id,
- Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::PAUSED,
+ controller->GetAnimationById(animation_id)->run_state());
// The pause run state change should make it to the impl thread controller.
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_EQ(Animation::Paused,
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::PAUSED,
+ controller_impl->GetAnimationById(animation_id)->run_state());
}
TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) {
@@ -313,39 +299,35 @@ TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimation(Animation::OPACITY));
int animation_id =
AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
+ int group_id = controller->GetAnimationById(animation_id)->group();
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
- controller_impl->GetAnimation(group_id,
- Animation::Opacity)->run_state());
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller_impl->GetAnimationById(animation_id)->run_state());
// Notify main thread controller that the animation has started.
- AnimationEvent animation_started_event(AnimationEvent::Started,
- 0,
- group_id,
- Animation::Opacity,
- kInitialTickTime);
+ AnimationEvent animation_started_event(AnimationEvent::STARTED, 0, group_id,
+ Animation::OPACITY, kInitialTickTime);
controller->NotifyAnimationStarted(animation_started_event);
// Force animation to complete on impl thread.
controller_impl->RemoveAnimation(animation_id);
- EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimationById(animation_id));
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
// Even though the main thread has a 'new' animation, it should not be pushed
// because the animation has already completed on the impl thread.
- EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimationById(animation_id));
}
// Ensure that a finished animation is eventually deleted by both the
@@ -371,9 +353,9 @@ TEST(LayerAnimationControllerTest, AnimationsAreDeleted) {
controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller_impl->UpdateState(true, events.get());
- // There should be a Started event for the animation.
+ // There should be a STARTED event for the animation.
EXPECT_EQ(1u, events->size());
- EXPECT_EQ(AnimationEvent::Started, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[0].type);
controller->NotifyAnimationStarted((*events)[0]);
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
@@ -389,13 +371,13 @@ TEST(LayerAnimationControllerTest, AnimationsAreDeleted) {
EXPECT_TRUE(dummy_impl.animation_waiting_for_deletion());
- // There should be a Finished event for the animation.
+ // There should be a FINISHED event for the animation.
EXPECT_EQ(1u, events->size());
- EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::FINISHED, (*events)[0].type);
// Neither controller should have deleted the animation yet.
- EXPECT_TRUE(controller->GetAnimation(Animation::Opacity));
- EXPECT_TRUE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_TRUE(controller->GetAnimation(Animation::OPACITY));
+ EXPECT_TRUE(controller_impl->GetAnimation(Animation::OPACITY));
controller->NotifyAnimationFinished((*events)[0]);
@@ -419,7 +401,7 @@ static const AnimationEvent* GetMostRecentPropertyUpdateEvent(
const AnimationEventsVector* events) {
const AnimationEvent* event = 0;
for (size_t i = 0; i < events->size(); ++i)
- if ((*events)[i].type == AnimationEvent::PropertyUpdate)
+ if ((*events)[i].type == AnimationEvent::PROPERTY_UPDATE)
event = &(*events)[i];
return event;
@@ -435,8 +417,7 @@ TEST(LayerAnimationControllerTest, TrivialTransition) {
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
controller->AddAnimation(to_add.Pass());
@@ -467,8 +448,7 @@ TEST(LayerAnimationControllerTest, TrivialTransitionOnImpl) {
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_is_impl_only(true);
controller_impl->AddAnimation(to_add.Pass());
@@ -508,14 +488,16 @@ TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) {
scoped_ptr<KeyframedTransformAnimationCurve> curve(
KeyframedTransformAnimationCurve::Create());
- // Create simple Transform animation.
+ // Create simple TRANSFORM animation.
TransformOperations operations;
- curve->AddKeyframe(TransformKeyframe::Create(0, operations, nullptr));
+ curve->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations, nullptr));
operations.AppendTranslate(delta_x, delta_y, 0);
- curve->AddKeyframe(TransformKeyframe::Create(1, operations, nullptr));
+ curve->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::Transform));
+ Animation::Create(curve.Pass(), 1, 0, Animation::TRANSFORM));
animation->set_is_impl_only(true);
controller_impl->AddAnimation(animation.Pass());
@@ -559,13 +541,15 @@ TEST(LayerAnimationControllerTest, FilterTransition) {
FilterOperations start_filters;
start_filters.Append(FilterOperation::CreateBrightnessFilter(1.f));
- curve->AddKeyframe(FilterKeyframe::Create(0, start_filters, nullptr));
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr));
FilterOperations end_filters;
end_filters.Append(FilterOperation::CreateBrightnessFilter(2.f));
- curve->AddKeyframe(FilterKeyframe::Create(1, end_filters, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ end_filters, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::Filter));
+ Animation::Create(curve.Pass(), 1, 0, Animation::FILTER));
controller->AddAnimation(animation.Pass());
controller->Animate(kInitialTickTime);
@@ -603,16 +587,18 @@ TEST(LayerAnimationControllerTest, FilterTransitionOnImplOnly) {
scoped_ptr<KeyframedFilterAnimationCurve> curve(
KeyframedFilterAnimationCurve::Create());
- // Create simple Filter animation.
+ // Create simple FILTER animation.
FilterOperations start_filters;
start_filters.Append(FilterOperation::CreateBrightnessFilter(1.f));
- curve->AddKeyframe(FilterKeyframe::Create(0, start_filters, nullptr));
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr));
FilterOperations end_filters;
end_filters.Append(FilterOperation::CreateBrightnessFilter(2.f));
- curve->AddKeyframe(FilterKeyframe::Create(1, end_filters, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+ end_filters, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::Filter));
+ Animation::Create(curve.Pass(), 1, 0, Animation::FILTER));
animation->set_is_impl_only(true);
controller_impl->AddAnimation(animation.Pass());
@@ -665,23 +651,20 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransition) {
EaseInOutTimingFunction::Create().Pass()));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
animation->set_needs_synchronized_start_time(true);
controller->AddAnimation(animation.Pass());
dummy_provider_impl.set_scroll_offset(initial_value);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
- double duration_in_seconds =
- controller_impl->GetAnimation(Animation::ScrollOffset)
- ->curve()
- ->Duration();
- TimeDelta duration = TimeDelta::FromMicroseconds(
- duration_in_seconds * base::Time::kMicrosecondsPerSecond);
+ EXPECT_TRUE(controller_impl->GetAnimation(Animation::SCROLL_OFFSET));
+ TimeDelta duration = controller_impl->GetAnimation(Animation::SCROLL_OFFSET)
+ ->curve()
+ ->Duration();
EXPECT_EQ(
- duration_in_seconds,
- controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
+ duration,
+ controller->GetAnimation(Animation::SCROLL_OFFSET)->curve()->Duration());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
@@ -747,21 +730,20 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransitionNoImplProvider) {
EaseInOutTimingFunction::Create().Pass()));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
animation->set_needs_synchronized_start_time(true);
controller->AddAnimation(animation.Pass());
dummy_provider.set_scroll_offset(initial_value);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
- double duration_in_seconds =
- controller_impl->GetAnimation(Animation::ScrollOffset)
- ->curve()
- ->Duration();
+ EXPECT_TRUE(controller_impl->GetAnimation(Animation::SCROLL_OFFSET));
+ TimeDelta duration = controller_impl->GetAnimation(Animation::SCROLL_OFFSET)
+ ->curve()
+ ->Duration();
EXPECT_EQ(
- duration_in_seconds,
- controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
+ duration,
+ controller->GetAnimation(Animation::SCROLL_OFFSET)->curve()->Duration());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
@@ -776,8 +758,6 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransitionNoImplProvider) {
const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_FALSE(event);
- TimeDelta duration = TimeDelta::FromMicroseconds(
- duration_in_seconds * base::Time::kMicrosecondsPerSecond);
controller->NotifyAnimationStarted((*events)[0]);
controller->Animate(kInitialTickTime + duration / 2);
@@ -820,10 +800,10 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransitionOnImplOnly) {
target_value,
EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
- double duration_in_seconds = curve->Duration();
+ double duration_in_seconds = curve->Duration().InSecondsF();
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
animation->set_is_impl_only(true);
controller_impl->AddAnimation(animation.Pass());
@@ -853,6 +833,106 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransitionOnImplOnly) {
EXPECT_FALSE(event);
}
+TEST(LayerAnimationControllerTest, ScrollOffsetRemovalClearsScrollDelta) {
+ FakeLayerAnimationValueObserver dummy_impl;
+ FakeLayerAnimationValueProvider dummy_provider_impl;
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+ controller_impl->AddValueObserver(&dummy_impl);
+ controller_impl->set_value_provider(&dummy_provider_impl);
+ scoped_ptr<AnimationEventsVector> events(
+ make_scoped_ptr(new AnimationEventsVector));
+ FakeLayerAnimationValueObserver dummy;
+ FakeLayerAnimationValueProvider dummy_provider;
+ scoped_refptr<LayerAnimationController> controller(
+ LayerAnimationController::Create(0));
+ controller->AddValueObserver(&dummy);
+ controller->set_value_provider(&dummy_provider);
+
+ // First test the 1-argument version of RemoveAnimation.
+ gfx::ScrollOffset target_value(300.f, 200.f);
+ scoped_ptr<ScrollOffsetAnimationCurve> curve(
+ ScrollOffsetAnimationCurve::Create(
+ target_value, EaseInOutTimingFunction::Create().Pass()));
+
+ int animation_id = 1;
+ scoped_ptr<Animation> animation(Animation::Create(
+ curve.Pass(), animation_id, 0, Animation::SCROLL_OFFSET));
+ animation->set_needs_synchronized_start_time(true);
+ controller->AddAnimation(animation.Pass());
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+
+ controller->RemoveAnimation(animation_id);
+ EXPECT_TRUE(controller->scroll_offset_animation_was_interrupted());
+
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ EXPECT_TRUE(controller_impl->scroll_offset_animation_was_interrupted());
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+
+ controller_impl->ActivateAnimations();
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+
+ // Now, test the 2-argument version of RemoveAnimation.
+ curve = ScrollOffsetAnimationCurve::Create(
+ target_value, EaseInOutTimingFunction::Create().Pass());
+ animation = Animation::Create(curve.Pass(), animation_id, 0,
+ Animation::SCROLL_OFFSET);
+ animation->set_needs_synchronized_start_time(true);
+ controller->AddAnimation(animation.Pass());
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+
+ controller->RemoveAnimation(animation_id);
+ EXPECT_TRUE(controller->scroll_offset_animation_was_interrupted());
+
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ EXPECT_TRUE(controller_impl->scroll_offset_animation_was_interrupted());
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+
+ controller_impl->ActivateAnimations();
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+
+ // Check that removing non-scroll-offset animations does not cause
+ // scroll_offset_animation_was_interrupted() to get set.
+ animation_id = AddAnimatedTransformToController(controller.get(), 1.0, 1, 2);
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+
+ controller->RemoveAnimation(animation_id);
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+
+ controller_impl->ActivateAnimations();
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+
+ animation_id =
+ AddAnimatedFilterToController(controller.get(), 1.0, 0.1f, 0.2f);
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+
+ controller->RemoveAnimation(animation_id);
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+ EXPECT_FALSE(controller->scroll_offset_animation_was_interrupted());
+
+ controller_impl->ActivateAnimations();
+ EXPECT_FALSE(controller_impl->scroll_offset_animation_was_interrupted());
+}
+
class FakeAnimationDelegate : public AnimationDelegate {
public:
FakeAnimationDelegate()
@@ -895,8 +975,7 @@ TEST(LayerAnimationControllerTest,
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_is_impl_only(true);
controller_impl->AddAnimation(to_add.Pass());
@@ -931,8 +1010,7 @@ TEST(LayerAnimationControllerTest,
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_needs_synchronized_start_time(true);
// We should pause at the first keyframe indefinitely waiting for that
@@ -953,10 +1031,7 @@ TEST(LayerAnimationControllerTest,
// Send the synchronized start time.
controller->NotifyAnimationStarted(
- AnimationEvent(AnimationEvent::Started,
- 0,
- 1,
- Animation::Opacity,
+ AnimationEvent(AnimationEvent::STARTED, 0, 1, Animation::OPACITY,
kInitialTickTime + TimeDelta::FromMilliseconds(2000)));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(5000));
controller->UpdateState(true, events.get());
@@ -977,13 +1052,11 @@ TEST(LayerAnimationControllerTest, TrivialQueuing) {
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(),
- 2,
- Animation::Opacity));
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f))
+ .Pass(),
+ 2, Animation::OPACITY));
EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
@@ -1019,19 +1092,17 @@ TEST(LayerAnimationControllerTest, Interrupt) {
controller->AddValueObserver(&dummy);
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
scoped_ptr<Animation> to_add(CreateAnimation(
- scoped_ptr<AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(),
- 2,
- Animation::Opacity));
- controller->AbortAnimations(Animation::Opacity);
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f))
+ .Pass(),
+ 2, Animation::OPACITY));
+ controller->AbortAnimations(Animation::OPACITY);
controller->AddAnimation(to_add.Pass());
// Since the previous animation was aborted, the new animation should start
@@ -1057,17 +1128,14 @@ TEST(LayerAnimationControllerTest, ScheduleTogetherWhenAPropertyIsBlocked) {
controller->AddValueObserver(&dummy);
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(),
- 1,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), 1,
+ Animation::TRANSFORM));
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(),
- 2,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), 2,
+ Animation::TRANSFORM));
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 2,
- Animation::Opacity));
+ 2, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
@@ -1097,18 +1165,15 @@ TEST(LayerAnimationControllerTest, ScheduleTogetherWithAnAnimWaiting) {
controller->AddValueObserver(&dummy);
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(2)).Pass(),
- 1,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(2)).Pass(), 1,
+ Animation::TRANSFORM));
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(),
- 2,
- Animation::Opacity));
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f))
+ .Pass(),
+ 2, Animation::OPACITY));
// Animations with id 1 should both start now.
controller->Animate(kInitialTickTime);
@@ -1143,8 +1208,7 @@ TEST(LayerAnimationControllerTest, TrivialLooping) {
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_iterations(3);
controller->AddAnimation(to_add.Pass());
@@ -1188,11 +1252,9 @@ TEST(LayerAnimationControllerTest, InfiniteLooping) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- const int id = 1;
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- id,
- Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_iterations(-1);
controller->AddAnimation(to_add.Pass());
@@ -1220,9 +1282,10 @@ TEST(LayerAnimationControllerTest, InfiniteLooping) {
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
- EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity));
- controller->GetAnimation(id, Animation::Opacity)->SetRunState(
- Animation::Aborted, kInitialTickTime + TimeDelta::FromMilliseconds(750));
+ EXPECT_TRUE(controller->GetAnimation(Animation::OPACITY));
+ controller->GetAnimation(Animation::OPACITY)
+ ->SetRunState(Animation::ABORTED,
+ kInitialTickTime + TimeDelta::FromMilliseconds(750));
EXPECT_FALSE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
}
@@ -1236,11 +1299,9 @@ TEST(LayerAnimationControllerTest, PauseResume) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- const int id = 1;
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- id,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
@@ -1251,18 +1312,19 @@ TEST(LayerAnimationControllerTest, PauseResume) {
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.5f, dummy.opacity());
- EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity));
- controller->GetAnimation(id, Animation::Opacity)->SetRunState(
- Animation::Paused, kInitialTickTime + TimeDelta::FromMilliseconds(500));
+ EXPECT_TRUE(controller->GetAnimation(Animation::OPACITY));
+ controller->GetAnimation(Animation::OPACITY)
+ ->SetRunState(Animation::PAUSED,
+ kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024000));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.5f, dummy.opacity());
- EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity));
- controller->GetAnimation(id, Animation::Opacity)
- ->SetRunState(Animation::Running,
+ EXPECT_TRUE(controller->GetAnimation(Animation::OPACITY));
+ controller->GetAnimation(Animation::OPACITY)
+ ->SetRunState(Animation::RUNNING,
kInitialTickTime + TimeDelta::FromMilliseconds(1024000));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024250));
controller->UpdateState(true, events.get());
@@ -1283,20 +1345,17 @@ TEST(LayerAnimationControllerTest, AbortAGroupedAnimation) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- const int id = 1;
- controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(),
- id,
- Animation::Transform));
- controller->AddAnimation(CreateAnimation(
+ const int animation_id = 2;
+ controller->AddAnimation(Animation::Create(
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), 1, 1,
+ Animation::TRANSFORM));
+ controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(),
- id,
- Animation::Opacity));
- controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.75f)).Pass(),
- 2,
- Animation::Opacity));
+ animation_id, 1, Animation::OPACITY));
+ controller->AddAnimation(Animation::Create(
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.75f))
+ .Pass(),
+ 3, 2, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
@@ -1307,9 +1366,10 @@ TEST(LayerAnimationControllerTest, AbortAGroupedAnimation) {
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.5f, dummy.opacity());
- EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity));
- controller->GetAnimation(id, Animation::Opacity)->SetRunState(
- Animation::Aborted, kInitialTickTime + TimeDelta::FromMilliseconds(1000));
+ EXPECT_TRUE(controller->GetAnimationById(animation_id));
+ controller->GetAnimationById(animation_id)
+ ->SetRunState(Animation::ABORTED,
+ kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
@@ -1334,24 +1394,23 @@ TEST(LayerAnimationControllerTest, PushUpdatesWhenSynchronizedStartTimeNeeded) {
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(),
- 0,
- Animation::Opacity));
+ 0, Animation::OPACITY));
to_add->set_needs_synchronized_start_time(true);
controller->AddAnimation(to_add.Pass());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
- Animation* active_animation = controller->GetAnimation(0, Animation::Opacity);
+ Animation* active_animation = controller->GetAnimation(Animation::OPACITY);
EXPECT_TRUE(active_animation);
EXPECT_TRUE(active_animation->needs_synchronized_start_time());
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- active_animation = controller_impl->GetAnimation(0, Animation::Opacity);
+ active_animation = controller_impl->GetAnimation(Animation::OPACITY);
EXPECT_TRUE(active_animation);
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
active_animation->run_state());
}
@@ -1365,17 +1424,15 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) {
controller->AddValueObserver(&dummy);
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(),
- 1,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), 1,
+ Animation::TRANSFORM));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 2,
- Animation::Opacity));
+ 2, Animation::OPACITY));
// Animate but don't UpdateState.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
@@ -1384,7 +1441,7 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) {
events.reset(new AnimationEventsVector);
controller->UpdateState(true, events.get());
- // Should have one Started event and one Finished event.
+ // Should have one STARTED event and one FINISHED event.
EXPECT_EQ(2u, events->size());
EXPECT_NE((*events)[0].type, (*events)[1].type);
@@ -1401,7 +1458,7 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) {
}
// Tests that an animation controller with only a pending observer gets ticked
-// but doesn't progress animations past the Starting state.
+// but doesn't progress animations past the STARTING state.
TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
scoped_ptr<AnimationEventsVector> events(
make_scoped_ptr(new AnimationEventsVector));
@@ -1411,49 +1468,49 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
LayerAnimationController::Create(0));
const int id = 1;
- controller->AddAnimation(CreateAnimation(scoped_ptr<AnimationCurve>(
- new FakeFloatTransition(1.0, 0.5f, 1.f)).Pass(),
- id,
- Animation::Opacity));
+ controller->AddAnimation(CreateAnimation(
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.5f, 1.f))
+ .Pass(),
+ id, Animation::OPACITY));
- // Without an observer, the animation shouldn't progress to the Starting
+ // Without an observer, the animation shouldn't progress to the STARTING
// state.
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
- controller->GetAnimation(id, Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
controller->AddValueObserver(&pending_dummy);
// With only a pending observer, the animation should progress to the
- // Starting state and get ticked at its starting point, but should not
- // progress to Running.
+ // STARTING state and get ticked at its starting point, but should not
+ // progress to RUNNING.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
- EXPECT_EQ(Animation::Starting,
- controller->GetAnimation(id, Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::STARTING,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_EQ(0.5f, pending_dummy.opacity());
- // Even when already in the Starting state, the animation should stay
+ // Even when already in the STARTING state, the animation should stay
// there, and shouldn't be ticked past its starting point.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
- EXPECT_EQ(Animation::Starting,
- controller->GetAnimation(id, Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::STARTING,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_EQ(0.5f, pending_dummy.opacity());
controller->AddValueObserver(&dummy);
// Now that an active observer has been added, the animation should still
- // initially tick at its starting point, but should now progress to Running.
+ // initially tick at its starting point, but should now progress to RUNNING.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000));
controller->UpdateState(true, events.get());
EXPECT_EQ(1u, events->size());
- EXPECT_EQ(Animation::Running,
- controller->GetAnimation(id, Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::RUNNING,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_EQ(0.5f, pending_dummy.opacity());
EXPECT_EQ(0.5f, dummy.opacity());
@@ -1471,23 +1528,27 @@ TEST(LayerAnimationControllerTest, TransformAnimationBounds) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations1;
- curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+ curve1->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
operations1.AppendTranslate(10.0, 15.0, 0.0);
- curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr));
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve1.Pass(), 1, 1, Animation::Transform));
+ Animation::Create(curve1.Pass(), 1, 1, Animation::TRANSFORM));
controller_impl->AddAnimation(animation.Pass());
scoped_ptr<KeyframedTransformAnimationCurve> curve2(
KeyframedTransformAnimationCurve::Create());
TransformOperations operations2;
- curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr));
+ curve2->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr));
operations2.AppendScale(2.0, 3.0, 4.0);
- curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- animation = Animation::Create(curve2.Pass(), 2, 2, Animation::Transform);
+ animation = Animation::Create(curve2.Pass(), 2, 2, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
gfx::BoxF box(1.f, 2.f, -1.f, 3.f, 4.f, 5.f);
@@ -1497,16 +1558,16 @@ TEST(LayerAnimationControllerTest, TransformAnimationBounds) {
EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 13.f, 19.f, 20.f).ToString(),
bounds.ToString());
- controller_impl->GetAnimation(1, Animation::Transform)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ controller_impl->GetAnimationById(1)
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// Only the unfinished animation should affect the animated bounds.
EXPECT_TRUE(controller_impl->TransformAnimationBoundsForBox(box, &bounds));
EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 7.f, 16.f, 20.f).ToString(),
bounds.ToString());
- controller_impl->GetAnimation(2, Animation::Transform)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ controller_impl->GetAnimationById(2)
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// There are no longer any running animations.
EXPECT_FALSE(controller_impl->HasTransformAnimationThatInflatesBounds());
@@ -1517,10 +1578,12 @@ TEST(LayerAnimationControllerTest, TransformAnimationBounds) {
TransformOperations operations3;
gfx::Transform transform3;
transform3.Scale3d(1.0, 2.0, 3.0);
- curve3->AddKeyframe(TransformKeyframe::Create(0.0, operations3, nullptr));
+ curve3->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations3, nullptr));
operations3.AppendMatrix(transform3);
- curve3->AddKeyframe(TransformKeyframe::Create(1.0, operations3, nullptr));
- animation = Animation::Create(curve3.Pass(), 3, 3, Animation::Transform);
+ curve3->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
+ animation = Animation::Create(curve3.Pass(), 3, 3, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
EXPECT_FALSE(controller_impl->TransformAnimationBoundsForBox(box, &bounds));
}
@@ -1535,56 +1598,42 @@ TEST(LayerAnimationControllerTest, AbortAnimations) {
// Start with several animations, and allow some of them to reach the finished
// state.
- controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(),
- 1,
- Animation::Transform));
- controller->AddAnimation(CreateAnimation(
+ controller->AddAnimation(Animation::Create(
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), 1, 1,
+ Animation::TRANSFORM));
+ controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 2,
- Animation::Opacity));
- controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(),
- 3,
- Animation::Transform));
- controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(),
- 4,
- Animation::Transform));
- controller->AddAnimation(CreateAnimation(
+ 2, 2, Animation::OPACITY));
+ controller->AddAnimation(Animation::Create(
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), 3, 3,
+ Animation::TRANSFORM));
+ controller->AddAnimation(Animation::Create(
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(), 4, 4,
+ Animation::TRANSFORM));
+ controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 5,
- Animation::Opacity));
+ 5, 5, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, nullptr);
- EXPECT_EQ(Animation::Finished,
- controller->GetAnimation(1, Animation::Transform)->run_state());
- EXPECT_EQ(Animation::Finished,
- controller->GetAnimation(2, Animation::Opacity)->run_state());
- EXPECT_EQ(Animation::Running,
- controller->GetAnimation(3, Animation::Transform)->run_state());
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
- controller->GetAnimation(4, Animation::Transform)->run_state());
- EXPECT_EQ(Animation::Running,
- controller->GetAnimation(5, Animation::Opacity)->run_state());
-
- controller->AbortAnimations(Animation::Transform);
-
- // Only un-finished Transform animations should have been aborted.
- EXPECT_EQ(Animation::Finished,
- controller->GetAnimation(1, Animation::Transform)->run_state());
- EXPECT_EQ(Animation::Finished,
- controller->GetAnimation(2, Animation::Opacity)->run_state());
- EXPECT_EQ(Animation::Aborted,
- controller->GetAnimation(3, Animation::Transform)->run_state());
- EXPECT_EQ(Animation::Aborted,
- controller->GetAnimation(4, Animation::Transform)->run_state());
- EXPECT_EQ(Animation::Running,
- controller->GetAnimation(5, Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::FINISHED, controller->GetAnimationById(1)->run_state());
+ EXPECT_EQ(Animation::FINISHED, controller->GetAnimationById(2)->run_state());
+ EXPECT_EQ(Animation::RUNNING, controller->GetAnimationById(3)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller->GetAnimationById(4)->run_state());
+ EXPECT_EQ(Animation::RUNNING, controller->GetAnimationById(5)->run_state());
+
+ controller->AbortAnimations(Animation::TRANSFORM);
+
+ // Only un-finished TRANSFORM animations should have been aborted.
+ EXPECT_EQ(Animation::FINISHED, controller->GetAnimationById(1)->run_state());
+ EXPECT_EQ(Animation::FINISHED, controller->GetAnimationById(2)->run_state());
+ EXPECT_EQ(Animation::ABORTED, controller->GetAnimationById(3)->run_state());
+ EXPECT_EQ(Animation::ABORTED, controller->GetAnimationById(4)->run_state());
+ EXPECT_EQ(Animation::RUNNING, controller->GetAnimationById(5)->run_state());
}
// An animation aborted on the main thread should get deleted on both threads.
@@ -1598,29 +1647,29 @@ TEST(LayerAnimationControllerTest, MainThreadAbortedAnimationGetsDeleted) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- AddOpacityTransitionToController(controller.get(), 1.0, 0.f, 1.f, false);
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
+ int animation_id =
+ AddOpacityTransitionToController(controller.get(), 1.0, 0.f, 1.f, false);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- controller->AbortAnimations(Animation::Opacity);
- EXPECT_EQ(Animation::Aborted,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ controller->AbortAnimations(Animation::OPACITY);
+ EXPECT_EQ(Animation::ABORTED,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_FALSE(dummy.animation_waiting_for_deletion());
EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
EXPECT_TRUE(dummy.animation_waiting_for_deletion());
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_FALSE(controller->GetAnimation(group_id, Animation::Opacity));
- EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+ EXPECT_FALSE(controller->GetAnimationById(animation_id));
+ EXPECT_FALSE(controller_impl->GetAnimationById(animation_id));
}
// An animation aborted on the impl thread should get deleted on both threads.
@@ -1634,16 +1683,16 @@ TEST(LayerAnimationControllerTest, ImplThreadAbortedAnimationGetsDeleted) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- AddOpacityTransitionToController(controller.get(), 1.0, 0.f, 1.f, false);
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
+ int animation_id =
+ AddOpacityTransitionToController(controller.get(), 1.0, 0.f, 1.f, false);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- controller_impl->AbortAnimations(Animation::Opacity);
- EXPECT_EQ(Animation::Aborted,
- controller_impl->GetAnimation(Animation::Opacity)->run_state());
+ controller_impl->AbortAnimations(Animation::OPACITY);
+ EXPECT_EQ(Animation::ABORTED,
+ controller_impl->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_FALSE(dummy.animation_waiting_for_deletion());
EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion());
@@ -1652,27 +1701,27 @@ TEST(LayerAnimationControllerTest, ImplThreadAbortedAnimationGetsDeleted) {
controller_impl->UpdateState(true, &events);
EXPECT_TRUE(dummy_impl.animation_waiting_for_deletion());
EXPECT_EQ(1u, events.size());
- EXPECT_EQ(AnimationEvent::Aborted, events[0].type);
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller_impl->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(AnimationEvent::ABORTED, events[0].type);
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller_impl->GetAnimation(Animation::OPACITY)->run_state());
controller->NotifyAnimationAborted(events[0]);
- EXPECT_EQ(Animation::Aborted,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::ABORTED,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, nullptr);
EXPECT_TRUE(dummy.animation_waiting_for_deletion());
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_FALSE(controller->GetAnimation(group_id, Animation::Opacity));
- EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+ EXPECT_FALSE(controller->GetAnimationById(animation_id));
+ EXPECT_FALSE(controller_impl->GetAnimationById(animation_id));
}
-// Ensure that we only generate Finished events for animations in a group
+// Ensure that we only generate FINISHED events for animations in a group
// once all animations in that group are finished.
TEST(LayerAnimationControllerTest, FinishedEventsForGroup) {
scoped_ptr<AnimationEventsVector> events(
@@ -1682,23 +1731,23 @@ TEST(LayerAnimationControllerTest, FinishedEventsForGroup) {
LayerAnimationController::Create(0));
controller_impl->AddValueObserver(&dummy_impl);
+ const int group_id = 1;
+
// Add two animations with the same group id but different durations.
- controller_impl->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(),
- 1,
- Animation::Transform));
- controller_impl->AddAnimation(CreateAnimation(
+ controller_impl->AddAnimation(Animation::Create(
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(), 1,
+ group_id, Animation::TRANSFORM));
+ controller_impl->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 2, group_id, Animation::OPACITY));
controller_impl->Animate(kInitialTickTime);
controller_impl->UpdateState(true, events.get());
// Both animations should have started.
EXPECT_EQ(2u, events->size());
- EXPECT_EQ(AnimationEvent::Started, (*events)[0].type);
- EXPECT_EQ(AnimationEvent::Started, (*events)[1].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[1].type);
events.reset(new AnimationEventsVector);
controller_impl->Animate(kInitialTickTime +
@@ -1706,26 +1755,25 @@ TEST(LayerAnimationControllerTest, FinishedEventsForGroup) {
controller_impl->UpdateState(true, events.get());
// The opacity animation should be finished, but should not have generated
- // a Finished event yet.
+ // a FINISHED event yet.
EXPECT_EQ(0u, events->size());
- EXPECT_EQ(Animation::Finished,
- controller_impl->GetAnimation(1, Animation::Opacity)->run_state());
- EXPECT_EQ(Animation::Running,
- controller_impl->GetAnimation(1,
- Animation::Transform)->run_state());
+ EXPECT_EQ(Animation::FINISHED,
+ controller_impl->GetAnimationById(2)->run_state());
+ EXPECT_EQ(Animation::RUNNING,
+ controller_impl->GetAnimationById(1)->run_state());
controller_impl->Animate(kInitialTickTime +
TimeDelta::FromMilliseconds(2000));
controller_impl->UpdateState(true, events.get());
- // Both animations should have generated Finished events.
+ // Both animations should have generated FINISHED events.
EXPECT_EQ(2u, events->size());
- EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type);
- EXPECT_EQ(AnimationEvent::Finished, (*events)[1].type);
+ EXPECT_EQ(AnimationEvent::FINISHED, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::FINISHED, (*events)[1].type);
}
// Ensure that when a group has a mix of aborted and finished animations,
-// we generate a Finished event for the finished animation and an Aborted
+// we generate a FINISHED event for the finished animation and an ABORTED
// event for the aborted animation.
TEST(LayerAnimationControllerTest, FinishedAndAbortedEventsForGroup) {
scoped_ptr<AnimationEventsVector> events(
@@ -1737,36 +1785,34 @@ TEST(LayerAnimationControllerTest, FinishedAndAbortedEventsForGroup) {
// Add two animations with the same group id.
controller_impl->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(),
- 1,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), 1,
+ Animation::TRANSFORM));
controller_impl->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller_impl->Animate(kInitialTickTime);
controller_impl->UpdateState(true, events.get());
// Both animations should have started.
EXPECT_EQ(2u, events->size());
- EXPECT_EQ(AnimationEvent::Started, (*events)[0].type);
- EXPECT_EQ(AnimationEvent::Started, (*events)[1].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[1].type);
- controller_impl->AbortAnimations(Animation::Opacity);
+ controller_impl->AbortAnimations(Animation::OPACITY);
events.reset(new AnimationEventsVector);
controller_impl->Animate(kInitialTickTime +
TimeDelta::FromMilliseconds(1000));
controller_impl->UpdateState(true, events.get());
- // We should have exactly 2 events: a Finished event for the tranform
- // animation, and an Aborted event for the opacity animation.
+ // We should have exactly 2 events: a FINISHED event for the tranform
+ // animation, and an ABORTED event for the opacity animation.
EXPECT_EQ(2u, events->size());
- EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type);
- EXPECT_EQ(Animation::Transform, (*events)[0].target_property);
- EXPECT_EQ(AnimationEvent::Aborted, (*events)[1].type);
- EXPECT_EQ(Animation::Opacity, (*events)[1].target_property);
+ EXPECT_EQ(AnimationEvent::FINISHED, (*events)[0].type);
+ EXPECT_EQ(Animation::TRANSFORM, (*events)[0].target_property);
+ EXPECT_EQ(AnimationEvent::ABORTED, (*events)[1].type);
+ EXPECT_EQ(Animation::OPACITY, (*events)[1].target_property);
}
TEST(LayerAnimationControllerTest, HasAnimationThatAffectsScale) {
@@ -1777,8 +1823,7 @@ TEST(LayerAnimationControllerTest, HasAnimationThatAffectsScale) {
controller_impl->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
// Opacity animations don't affect scale.
EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
@@ -1787,12 +1832,14 @@ TEST(LayerAnimationControllerTest, HasAnimationThatAffectsScale) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations1;
- curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+ curve1->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
operations1.AppendTranslate(10.0, 15.0, 0.0);
- curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr));
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve1.Pass(), 2, 2, Animation::Transform));
+ Animation::Create(curve1.Pass(), 2, 2, Animation::TRANSFORM));
controller_impl->AddAnimation(animation.Pass());
// Translations don't affect scale.
@@ -1802,17 +1849,19 @@ TEST(LayerAnimationControllerTest, HasAnimationThatAffectsScale) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations2;
- curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr));
+ curve2->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr));
operations2.AppendScale(2.0, 3.0, 4.0);
- curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- animation = Animation::Create(curve2.Pass(), 3, 3, Animation::Transform);
+ animation = Animation::Create(curve2.Pass(), 3, 3, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
EXPECT_TRUE(controller_impl->HasAnimationThatAffectsScale());
- controller_impl->GetAnimation(3, Animation::Transform)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ controller_impl->GetAnimationById(3)
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// Only unfinished animations should be considered by
// HasAnimationThatAffectsScale.
@@ -1827,8 +1876,7 @@ TEST(LayerAnimationControllerTest, HasOnlyTranslationTransforms) {
controller_impl->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
// Opacity animations aren't non-translation transforms.
EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
@@ -1837,12 +1885,14 @@ TEST(LayerAnimationControllerTest, HasOnlyTranslationTransforms) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations1;
- curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+ curve1->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
operations1.AppendTranslate(10.0, 15.0, 0.0);
- curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr));
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve1.Pass(), 2, 2, Animation::Transform));
+ Animation::Create(curve1.Pass(), 2, 2, Animation::TRANSFORM));
controller_impl->AddAnimation(animation.Pass());
// The only transform animation we've added is a translation.
@@ -1852,24 +1902,90 @@ TEST(LayerAnimationControllerTest, HasOnlyTranslationTransforms) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations2;
- curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr));
+ curve2->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr));
operations2.AppendScale(2.0, 3.0, 4.0);
- curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- animation = Animation::Create(curve2.Pass(), 3, 3, Animation::Transform);
+ animation = Animation::Create(curve2.Pass(), 3, 3, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
// A scale animation is not a translation.
EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms());
- controller_impl->GetAnimation(3, Animation::Transform)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ controller_impl->GetAnimationById(3)
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// Only unfinished animations should be considered by
// HasOnlyTranslationTransforms.
EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
}
+TEST(LayerAnimationControllerTest, AnimationStartScale) {
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+ scoped_ptr<KeyframedTransformAnimationCurve> curve1(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations1;
+ operations1.AppendScale(2.0, 3.0, 4.0);
+ curve1->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ TransformOperations operations2;
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+ scoped_ptr<Animation> animation(
+ Animation::Create(curve1.Pass(), 1, 1, Animation::TRANSFORM));
+ controller_impl->AddAnimation(animation.Pass());
+
+ float start_scale = 0.f;
+ EXPECT_TRUE(controller_impl->AnimationStartScale(&start_scale));
+ EXPECT_EQ(4.f, start_scale);
+
+ scoped_ptr<KeyframedTransformAnimationCurve> curve2(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations3;
+ curve2->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations3, nullptr));
+ operations3.AppendScale(6.0, 5.0, 4.0);
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
+
+ controller_impl->RemoveAnimation(1);
+ animation = Animation::Create(curve2.Pass(), 2, 2, Animation::TRANSFORM);
+
+ // Reverse Direction
+ animation->set_direction(Animation::DIRECTION_REVERSE);
+ controller_impl->AddAnimation(animation.Pass());
+
+ scoped_ptr<KeyframedTransformAnimationCurve> curve3(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations4;
+ operations4.AppendScale(5.0, 3.0, 1.0);
+ curve3->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations4, nullptr));
+ TransformOperations operations5;
+ curve3->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations5, nullptr));
+
+ animation = Animation::Create(curve3.Pass(), 3, 3, Animation::TRANSFORM);
+ controller_impl->AddAnimation(animation.Pass());
+
+ EXPECT_TRUE(controller_impl->AnimationStartScale(&start_scale));
+ EXPECT_EQ(6.f, start_scale);
+
+ controller_impl->GetAnimationById(2)
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
+
+ // Only unfinished animations should be considered by
+ // AnimationStartScale.
+ EXPECT_TRUE(controller_impl->AnimationStartScale(&start_scale));
+ EXPECT_EQ(5.f, start_scale);
+}
+
TEST(LayerAnimationControllerTest, MaximumTargetScale) {
scoped_refptr<LayerAnimationController> controller_impl(
LayerAnimationController::Create(0));
@@ -1882,12 +1998,14 @@ TEST(LayerAnimationControllerTest, MaximumTargetScale) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations1;
- curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+ curve1->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
operations1.AppendScale(2.0, 3.0, 4.0);
- curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr));
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve1.Pass(), 1, 1, Animation::Transform));
+ Animation::Create(curve1.Pass(), 1, 1, Animation::TRANSFORM));
controller_impl->AddAnimation(animation.Pass());
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
@@ -1897,11 +2015,13 @@ TEST(LayerAnimationControllerTest, MaximumTargetScale) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations2;
- curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr));
+ curve2->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr));
operations2.AppendScale(6.0, 5.0, 4.0);
- curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- animation = Animation::Create(curve2.Pass(), 2, 2, Animation::Transform);
+ animation = Animation::Create(curve2.Pass(), 2, 2, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
@@ -1911,19 +2031,21 @@ TEST(LayerAnimationControllerTest, MaximumTargetScale) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations3;
- curve3->AddKeyframe(TransformKeyframe::Create(0.0, operations3, nullptr));
+ curve3->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations3, nullptr));
operations3.AppendPerspective(6.0);
- curve3->AddKeyframe(TransformKeyframe::Create(1.0, operations3, nullptr));
+ curve3->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
- animation = Animation::Create(curve3.Pass(), 3, 3, Animation::Transform);
+ animation = Animation::Create(curve3.Pass(), 3, 3, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
EXPECT_FALSE(controller_impl->MaximumTargetScale(&max_scale));
- controller_impl->GetAnimation(3, Animation::Transform)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
- controller_impl->GetAnimation(2, Animation::Transform)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ controller_impl->GetAnimationById(3)
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
+ controller_impl->GetAnimationById(2)
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// Only unfinished animations should be considered by
// MaximumTargetScale.
@@ -1939,13 +2061,15 @@ TEST(LayerAnimationControllerTest, MaximumTargetScaleWithDirection) {
KeyframedTransformAnimationCurve::Create());
TransformOperations operations1;
operations1.AppendScale(1.0, 2.0, 3.0);
- curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+ curve1->AddKeyframe(
+ TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
TransformOperations operations2;
operations2.AppendScale(4.0, 5.0, 6.0);
- curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
scoped_ptr<Animation> animation_owned(
- Animation::Create(curve1.Pass(), 1, 1, Animation::Transform));
+ Animation::Create(curve1.Pass(), 1, 1, Animation::TRANSFORM));
Animation* animation = animation_owned.get();
controller_impl->AddAnimation(animation_owned.Pass());
@@ -1953,45 +2077,45 @@ TEST(LayerAnimationControllerTest, MaximumTargetScaleWithDirection) {
EXPECT_GT(animation->playback_rate(), 0.0);
- // Normal direction with positive playback rate.
- animation->set_direction(Animation::Normal);
+ // NORMAL direction with positive playback rate.
+ animation->set_direction(Animation::DIRECTION_NORMAL);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(6.f, max_scale);
- // Alternate direction with positive playback rate.
- animation->set_direction(Animation::Alternate);
+ // ALTERNATE direction with positive playback rate.
+ animation->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(6.f, max_scale);
- // Reverse direction with positive playback rate.
- animation->set_direction(Animation::Reverse);
+ // REVERSE direction with positive playback rate.
+ animation->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(3.f, max_scale);
- // Alternate reverse direction.
- animation->set_direction(Animation::Reverse);
+ // ALTERNATE reverse direction.
+ animation->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(3.f, max_scale);
animation->set_playback_rate(-1.0);
- // Normal direction with negative playback rate.
- animation->set_direction(Animation::Normal);
+ // NORMAL direction with negative playback rate.
+ animation->set_direction(Animation::DIRECTION_NORMAL);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(3.f, max_scale);
- // Alternate direction with negative playback rate.
- animation->set_direction(Animation::Alternate);
+ // ALTERNATE direction with negative playback rate.
+ animation->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(3.f, max_scale);
- // Reverse direction with negative playback rate.
- animation->set_direction(Animation::Reverse);
+ // REVERSE direction with negative playback rate.
+ animation->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(6.f, max_scale);
- // Alternate reverse direction with negative playback rate.
- animation->set_direction(Animation::Reverse);
+ // ALTERNATE reverse direction with negative playback rate.
+ animation->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(6.f, max_scale);
}
@@ -2011,32 +2135,30 @@ TEST(LayerAnimationControllerTest, NewlyPushedAnimationWaitsForActivation) {
controller->AddValueObserver(&dummy);
EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
- AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, false);
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
+ int animation_id =
+ AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, false);
EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
controller->PushAnimationUpdatesTo(controller_impl.get());
EXPECT_TRUE(controller_impl->needs_to_start_animations_for_testing());
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
- EXPECT_EQ(
- Animation::WaitingForTargetAvailability,
- controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller_impl->GetAnimationById(animation_id)->run_state());
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_pending_observers());
- EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_FALSE(controller_impl->GetAnimationById(animation_id)
->affects_active_observers());
controller_impl->Animate(kInitialTickTime);
EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
controller_impl->UpdateState(true, events.get());
- // Since the animation hasn't been activated, it should still be Starting
- // rather than Running.
- EXPECT_EQ(
- Animation::Starting,
- controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+ // Since the animation hasn't been activated, it should still be STARTING
+ // rather than RUNNING.
+ EXPECT_EQ(Animation::STARTING,
+ controller_impl->GetAnimationById(animation_id)->run_state());
// Since the animation hasn't been activated, only the pending observer
// should have been ticked.
@@ -2044,9 +2166,9 @@ TEST(LayerAnimationControllerTest, NewlyPushedAnimationWaitsForActivation) {
EXPECT_EQ(0.f, dummy_impl.opacity());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_pending_observers());
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_active_observers());
controller_impl->Animate(kInitialTickTime +
@@ -2054,10 +2176,9 @@ TEST(LayerAnimationControllerTest, NewlyPushedAnimationWaitsForActivation) {
controller_impl->UpdateState(true, events.get());
// Since the animation has been activated, it should have reached the
- // Running state and the active observer should start to get ticked.
- EXPECT_EQ(
- Animation::Running,
- controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+ // RUNNING state and the active observer should start to get ticked.
+ EXPECT_EQ(Animation::RUNNING,
+ controller_impl->GetAnimationById(animation_id)->run_state());
EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
EXPECT_EQ(0.5f, dummy_impl.opacity());
}
@@ -2076,18 +2197,17 @@ TEST(LayerAnimationControllerTest, ActivationBetweenAnimateAndUpdateState) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, true);
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
+ int animation_id =
+ AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, true);
controller->PushAnimationUpdatesTo(controller_impl.get());
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
- EXPECT_EQ(
- Animation::WaitingForTargetAvailability,
- controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller_impl->GetAnimationById(animation_id)->run_state());
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_pending_observers());
- EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_FALSE(controller_impl->GetAnimationById(animation_id)
->affects_active_observers());
controller_impl->Animate(kInitialTickTime);
@@ -2098,18 +2218,17 @@ TEST(LayerAnimationControllerTest, ActivationBetweenAnimateAndUpdateState) {
EXPECT_EQ(0.f, dummy_impl.opacity());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_pending_observers());
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_active_observers());
controller_impl->UpdateState(true, events.get());
// Since the animation has been activated, it should have reached the
- // Running state.
- EXPECT_EQ(
- Animation::Running,
- controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+ // RUNNING state.
+ EXPECT_EQ(Animation::RUNNING,
+ controller_impl->GetAnimationById(animation_id)->run_state());
controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
@@ -2164,33 +2283,32 @@ TEST(LayerAnimationControllerTest, PushedDeletedAnimationWaitsForActivation) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, true);
- int group_id = controller->GetAnimation(Animation::Opacity)->group();
+ int animation_id =
+ AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, true);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
controller_impl->Animate(kInitialTickTime);
controller_impl->UpdateState(true, events.get());
- EXPECT_EQ(
- Animation::Running,
- controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::RUNNING,
+ controller_impl->GetAnimationById(animation_id)->run_state());
EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
EXPECT_EQ(0.5f, dummy_impl.opacity());
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_pending_observers());
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_active_observers());
// Delete the animation on the main-thread controller.
controller->RemoveAnimation(
- controller->GetAnimation(Animation::Opacity)->id());
+ controller->GetAnimation(Animation::OPACITY)->id());
controller->PushAnimationUpdatesTo(controller_impl.get());
// The animation should no longer affect pending observers.
- EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_FALSE(controller_impl->GetAnimationById(animation_id)
->affects_pending_observers());
- EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_active_observers());
controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
@@ -2222,9 +2340,8 @@ TEST(LayerAnimationControllerTest, StartAnimationsAffectingDifferentObservers) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- AddOpacityTransitionToController(controller.get(), 1, 0.f, 1.f, true);
- int first_animation_group_id =
- controller->GetAnimation(Animation::Opacity)->group();
+ int first_animation_id =
+ AddOpacityTransitionToController(controller.get(), 1, 0.f, 1.f, true);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
@@ -2234,25 +2351,20 @@ TEST(LayerAnimationControllerTest, StartAnimationsAffectingDifferentObservers) {
// Remove the first animation from the main-thread controller, and add a
// new animation affecting the same property.
controller->RemoveAnimation(
- controller->GetAnimation(Animation::Opacity)->id());
- AddOpacityTransitionToController(controller.get(), 1, 1.f, 0.5f, true);
- int second_animation_group_id =
- controller->GetAnimation(Animation::Opacity)->group();
+ controller->GetAnimation(Animation::OPACITY)->id());
+ int second_animation_id =
+ AddOpacityTransitionToController(controller.get(), 1, 1.f, 0.5f, true);
controller->PushAnimationUpdatesTo(controller_impl.get());
// The original animation should only affect active observers, and the new
// animation should only affect pending observers.
- EXPECT_FALSE(controller_impl->GetAnimation(first_animation_group_id,
- Animation::Opacity)
+ EXPECT_FALSE(controller_impl->GetAnimationById(first_animation_id)
->affects_pending_observers());
- EXPECT_TRUE(controller_impl->GetAnimation(first_animation_group_id,
- Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(first_animation_id)
->affects_active_observers());
- EXPECT_TRUE(controller_impl->GetAnimation(second_animation_group_id,
- Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(second_animation_id)
->affects_pending_observers());
- EXPECT_FALSE(controller_impl->GetAnimation(second_animation_group_id,
- Animation::Opacity)
+ EXPECT_FALSE(controller_impl->GetAnimationById(second_animation_id)
->affects_active_observers());
controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
@@ -2260,12 +2372,11 @@ TEST(LayerAnimationControllerTest, StartAnimationsAffectingDifferentObservers) {
// The original animation should still be running, and the new animation
// should be starting.
- EXPECT_EQ(Animation::Running,
- controller_impl->GetAnimation(first_animation_group_id,
- Animation::Opacity)->run_state());
- EXPECT_EQ(Animation::Starting,
- controller_impl->GetAnimation(second_animation_group_id,
- Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::RUNNING,
+ controller_impl->GetAnimationById(first_animation_id)->run_state());
+ EXPECT_EQ(
+ Animation::STARTING,
+ controller_impl->GetAnimationById(second_animation_id)->run_state());
// The active observer should have been ticked by the original animation,
// and the pending observer should have been ticked by the new animation.
@@ -2276,13 +2387,10 @@ TEST(LayerAnimationControllerTest, StartAnimationsAffectingDifferentObservers) {
// The original animation should have been deleted, and the new animation
// should now affect both observers.
- EXPECT_FALSE(controller_impl->GetAnimation(first_animation_group_id,
- Animation::Opacity));
- EXPECT_TRUE(controller_impl->GetAnimation(second_animation_group_id,
- Animation::Opacity)
+ EXPECT_FALSE(controller_impl->GetAnimationById(first_animation_id));
+ EXPECT_TRUE(controller_impl->GetAnimationById(second_animation_id)
->affects_pending_observers());
- EXPECT_TRUE(controller_impl->GetAnimation(second_animation_group_id,
- Animation::Opacity)
+ EXPECT_TRUE(controller_impl->GetAnimationById(second_animation_id)
->affects_active_observers());
controller_impl->Animate(kInitialTickTime +
@@ -2291,9 +2399,9 @@ TEST(LayerAnimationControllerTest, StartAnimationsAffectingDifferentObservers) {
// The new animation should be running, and the active observer should have
// been ticked at the new animation's starting point.
- EXPECT_EQ(Animation::Running,
- controller_impl->GetAnimation(second_animation_group_id,
- Animation::Opacity)->run_state());
+ EXPECT_EQ(
+ Animation::RUNNING,
+ controller_impl->GetAnimationById(second_animation_id)->run_state());
EXPECT_EQ(1.f, pending_dummy_impl.opacity());
EXPECT_EQ(1.f, dummy_impl.opacity());
}
@@ -2306,15 +2414,14 @@ TEST(LayerAnimationControllerTest, TestIsAnimatingProperty) {
scoped_ptr<Animation> animation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller->AddAnimation(animation.Pass());
controller->Animate(kInitialTickTime);
- EXPECT_TRUE(controller->IsAnimatingProperty(Animation::Opacity));
+ EXPECT_TRUE(controller->IsAnimatingProperty(Animation::OPACITY));
controller->UpdateState(true, nullptr);
EXPECT_TRUE(controller->HasActiveAnimation());
- EXPECT_TRUE(controller->IsAnimatingProperty(Animation::Opacity));
- EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Filter));
+ EXPECT_TRUE(controller->IsAnimatingProperty(Animation::OPACITY));
+ EXPECT_FALSE(controller->IsAnimatingProperty(Animation::FILTER));
EXPECT_EQ(0.f, dummy.opacity());
}
@@ -2326,22 +2433,21 @@ TEST(LayerAnimationControllerTest, TestIsAnimatingPropertyTimeOffsetFillMode) {
scoped_ptr<Animation> animation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
- animation->set_fill_mode(Animation::FillModeNone);
+ 1, Animation::OPACITY));
+ animation->set_fill_mode(Animation::FILL_MODE_NONE);
animation->set_time_offset(TimeDelta::FromMilliseconds(-2000));
controller->AddAnimation(animation.Pass());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
- EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Opacity));
+ EXPECT_FALSE(controller->IsAnimatingProperty(Animation::OPACITY));
EXPECT_TRUE(controller->HasActiveAnimation());
- EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Opacity));
- EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Filter));
+ EXPECT_FALSE(controller->IsAnimatingProperty(Animation::OPACITY));
+ EXPECT_FALSE(controller->IsAnimatingProperty(Animation::FILTER));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, nullptr);
- EXPECT_TRUE(controller->IsAnimatingProperty(Animation::Opacity));
+ EXPECT_TRUE(controller->IsAnimatingProperty(Animation::OPACITY));
}
} // namespace
diff --git a/chromium/cc/animation/layer_animation_event_observer.h b/chromium/cc/animation/layer_animation_event_observer.h
index 9f7f04bbfea..93d606edcc8 100644
--- a/chromium/cc/animation/layer_animation_event_observer.h
+++ b/chromium/cc/animation/layer_animation_event_observer.h
@@ -9,6 +9,8 @@
namespace cc {
+struct AnimationEvent;
+
class CC_EXPORT LayerAnimationEventObserver {
public:
virtual void OnAnimationStarted(const AnimationEvent& event) = 0;
diff --git a/chromium/cc/animation/layer_animation_value_observer.h b/chromium/cc/animation/layer_animation_value_observer.h
index 420317ee8d0..fb9901d7514 100644
--- a/chromium/cc/animation/layer_animation_value_observer.h
+++ b/chromium/cc/animation/layer_animation_value_observer.h
@@ -7,9 +7,14 @@
#include "cc/base/cc_export.h"
+namespace gfx {
+class ScrollOffset;
+class Transform;
+}
+
namespace cc {
-class ScrollOffset;
+class FilterOperations;
class CC_EXPORT LayerAnimationValueObserver {
public:
diff --git a/chromium/cc/animation/layer_animation_value_provider.h b/chromium/cc/animation/layer_animation_value_provider.h
index 90708381561..219afb2f788 100644
--- a/chromium/cc/animation/layer_animation_value_provider.h
+++ b/chromium/cc/animation/layer_animation_value_provider.h
@@ -7,9 +7,11 @@
#include "cc/base/cc_export.h"
-namespace cc {
-
+namespace gfx {
class ScrollOffset;
+}
+
+namespace cc {
// A LayerAnimationValueProvider is used for determining the starting value
// for animations that start at their 'current' value rather than at a
diff --git a/chromium/cc/animation/scroll_offset_animation_curve.cc b/chromium/cc/animation/scroll_offset_animation_curve.cc
index 641c9e0186d..68761fbf8d1 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve.cc
+++ b/chromium/cc/animation/scroll_offset_animation_curve.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "cc/animation/timing_function.h"
+#include "cc/base/time_util.h"
#include "ui/gfx/animation/tween.h"
const double kDurationDivisor = 60.0;
@@ -17,11 +18,11 @@ namespace cc {
namespace {
-static float MaximumDimension(gfx::Vector2dF delta) {
+static float MaximumDimension(const gfx::Vector2dF& delta) {
return std::max(std::abs(delta.x()), std::abs(delta.y()));
}
-static base::TimeDelta DurationFromDelta(gfx::Vector2dF delta) {
+static base::TimeDelta DurationFromDelta(const gfx::Vector2dF& delta) {
// The duration of a scroll animation depends on the size of the scroll.
// The exact relationship between the size and the duration isn't specified
// by the CSSOM View smooth scroll spec and is instead left up to user agents
@@ -65,17 +66,18 @@ void ScrollOffsetAnimationCurve::SetInitialValue(
target_value_.DeltaFrom(initial_value_));
}
-gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue(double t) const {
- double duration = (total_animation_duration_ - last_retarget_).InSecondsF();
- t -= last_retarget_.InSecondsF();
+gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue(
+ base::TimeDelta t) const {
+ base::TimeDelta duration = total_animation_duration_ - last_retarget_;
+ t -= last_retarget_;
- if (t <= 0)
+ if (t <= base::TimeDelta())
return initial_value_;
if (t >= duration)
return target_value_;
- double progress = (timing_function_->GetValue(t / duration));
+ double progress = timing_function_->GetValue(TimeUtil::Divide(t, duration));
return gfx::ScrollOffset(
gfx::Tween::FloatValueBetween(
progress, initial_value_.x(), target_value_.x()),
@@ -83,12 +85,12 @@ gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue(double t) const {
progress, initial_value_.y(), target_value_.y()));
}
-double ScrollOffsetAnimationCurve::Duration() const {
- return total_animation_duration_.InSecondsF();
+base::TimeDelta ScrollOffsetAnimationCurve::Duration() const {
+ return total_animation_duration_;
}
AnimationCurve::CurveType ScrollOffsetAnimationCurve::Type() const {
- return ScrollOffset;
+ return SCROLL_OFFSET;
}
scoped_ptr<AnimationCurve> ScrollOffsetAnimationCurve::Clone() const {
@@ -105,7 +107,8 @@ scoped_ptr<AnimationCurve> ScrollOffsetAnimationCurve::Clone() const {
void ScrollOffsetAnimationCurve::UpdateTarget(
double t,
const gfx::ScrollOffset& new_target) {
- gfx::ScrollOffset current_position = GetValue(t);
+ gfx::ScrollOffset current_position =
+ GetValue(base::TimeDelta::FromSecondsD(t));
gfx::Vector2dF old_delta = target_value_.DeltaFrom(initial_value_);
gfx::Vector2dF new_delta = new_target.DeltaFrom(current_position);
diff --git a/chromium/cc/animation/scroll_offset_animation_curve.h b/chromium/cc/animation/scroll_offset_animation_curve.h
index 0c8692ad60b..c4ae70b411a 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve.h
+++ b/chromium/cc/animation/scroll_offset_animation_curve.h
@@ -24,12 +24,12 @@ class CC_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
~ScrollOffsetAnimationCurve() override;
void SetInitialValue(const gfx::ScrollOffset& initial_value);
- gfx::ScrollOffset GetValue(double t) const;
+ gfx::ScrollOffset GetValue(base::TimeDelta t) const;
gfx::ScrollOffset target_value() const { return target_value_; }
void UpdateTarget(double t, const gfx::ScrollOffset& new_target);
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
CurveType Type() const override;
scoped_ptr<AnimationCurve> Clone() const override;
diff --git a/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc
index d89784a04de..8aea905dfc2 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc
+++ b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc
@@ -5,6 +5,7 @@
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/timing_function.h"
+#include "cc/base/time_util.h"
#include "cc/test/geometry_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,39 +20,39 @@ TEST(ScrollOffsetAnimationCurveTest, Duration) {
EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(target_value);
- EXPECT_DOUBLE_EQ(0.0, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.0, curve->Duration().InSecondsF());
// x decreases, y stays the same.
curve->SetInitialValue(gfx::ScrollOffset(136.f, 200.f));
- EXPECT_DOUBLE_EQ(0.1, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.1, curve->Duration().InSecondsF());
// x increases, y stays the same.
curve->SetInitialValue(gfx::ScrollOffset(19.f, 200.f));
- EXPECT_DOUBLE_EQ(0.15, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.15, curve->Duration().InSecondsF());
// x stays the same, y decreases.
curve->SetInitialValue(gfx::ScrollOffset(100.f, 344.f));
- EXPECT_DOUBLE_EQ(0.2, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.2, curve->Duration().InSecondsF());
// x stays the same, y increases.
curve->SetInitialValue(gfx::ScrollOffset(100.f, 191.f));
- EXPECT_DOUBLE_EQ(0.05, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.05, curve->Duration().InSecondsF());
// x decreases, y decreases.
curve->SetInitialValue(gfx::ScrollOffset(32500.f, 500.f));
- EXPECT_DOUBLE_EQ(3.0, curve->Duration());
+ EXPECT_DOUBLE_EQ(3.0, curve->Duration().InSecondsF());
// x decreases, y increases.
curve->SetInitialValue(gfx::ScrollOffset(150.f, 119.f));
- EXPECT_DOUBLE_EQ(0.15, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.15, curve->Duration().InSecondsF());
// x increases, y decreases.
curve->SetInitialValue(gfx::ScrollOffset(0.f, 14600.f));
- EXPECT_DOUBLE_EQ(2.0, curve->Duration());
+ EXPECT_DOUBLE_EQ(2.0, curve->Duration().InSecondsF());
// x increases, y increases.
curve->SetInitialValue(gfx::ScrollOffset(95.f, 191.f));
- EXPECT_DOUBLE_EQ(0.05, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.05, curve->Duration().InSecondsF());
}
TEST(ScrollOffsetAnimationCurveTest, GetValue) {
@@ -63,24 +64,28 @@ TEST(ScrollOffsetAnimationCurveTest, GetValue) {
EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
- double duration = curve->Duration();
- EXPECT_GT(curve->Duration(), 0);
- EXPECT_LT(curve->Duration(), 0.1);
+ base::TimeDelta duration = curve->Duration();
+ EXPECT_GT(curve->Duration().InSecondsF(), 0);
+ EXPECT_LT(curve->Duration().InSecondsF(), 0.1);
- EXPECT_EQ(AnimationCurve::ScrollOffset, curve->Type());
+ EXPECT_EQ(AnimationCurve::SCROLL_OFFSET, curve->Type());
EXPECT_EQ(duration, curve->Duration());
- EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(-1.0));
- EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(0.0));
- EXPECT_VECTOR2DF_EQ(gfx::ScrollOffset(6.f, 30.f),
- curve->GetValue(duration/2.0));
+ EXPECT_VECTOR2DF_EQ(initial_value,
+ curve->GetValue(base::TimeDelta::FromSecondsD(-1.0)));
+ EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(base::TimeDelta()));
+ EXPECT_VECTOR2DF_NEAR(gfx::ScrollOffset(6.f, 30.f),
+ curve->GetValue(TimeUtil::Scale(duration, 0.5f)),
+ 0.00025);
EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration));
- EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration+1.0));
+ EXPECT_VECTOR2DF_EQ(
+ target_value,
+ curve->GetValue(duration + base::TimeDelta::FromSecondsD(1.0)));
// Verify that GetValue takes the timing function into account.
- gfx::ScrollOffset value = curve->GetValue(duration/4.0);
- EXPECT_NEAR(3.0333f, value.x(), 0.00015f);
- EXPECT_NEAR(37.4168f, value.y(), 0.00015f);
+ gfx::ScrollOffset value = curve->GetValue(TimeUtil::Scale(duration, 0.25f));
+ EXPECT_NEAR(3.0333f, value.x(), 0.0002f);
+ EXPECT_NEAR(37.4168f, value.y(), 0.0002f);
}
// Verify that a clone behaves exactly like the original.
@@ -92,32 +97,34 @@ TEST(ScrollOffsetAnimationCurveTest, Clone) {
target_value,
EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
- double duration = curve->Duration();
+ base::TimeDelta duration = curve->Duration();
scoped_ptr<AnimationCurve> clone(curve->Clone().Pass());
- EXPECT_EQ(AnimationCurve::ScrollOffset, clone->Type());
+ EXPECT_EQ(AnimationCurve::SCROLL_OFFSET, clone->Type());
EXPECT_EQ(duration, clone->Duration());
EXPECT_VECTOR2DF_EQ(initial_value,
- clone->ToScrollOffsetAnimationCurve()->GetValue(-1.0));
- EXPECT_VECTOR2DF_EQ(initial_value,
- clone->ToScrollOffsetAnimationCurve()->GetValue(0.0));
+ clone->ToScrollOffsetAnimationCurve()->GetValue(
+ base::TimeDelta::FromSecondsD(-1.0)));
EXPECT_VECTOR2DF_EQ(
- gfx::ScrollOffset(6.f, 30.f),
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration / 2.0));
+ initial_value,
+ clone->ToScrollOffsetAnimationCurve()->GetValue(base::TimeDelta()));
+ EXPECT_VECTOR2DF_NEAR(gfx::ScrollOffset(6.f, 30.f),
+ clone->ToScrollOffsetAnimationCurve()->GetValue(
+ TimeUtil::Scale(duration, 0.5f)),
+ 0.00025);
EXPECT_VECTOR2DF_EQ(
- target_value,
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration));
- EXPECT_VECTOR2DF_EQ(
- target_value,
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration + 1.0));
+ target_value, clone->ToScrollOffsetAnimationCurve()->GetValue(duration));
+ EXPECT_VECTOR2DF_EQ(target_value,
+ clone->ToScrollOffsetAnimationCurve()->GetValue(
+ duration + base::TimeDelta::FromSecondsD(1.f)));
// Verify that the timing function was cloned correctly.
- gfx::ScrollOffset value =
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration / 4.0);
- EXPECT_NEAR(3.0333f, value.x(), 0.00015f);
- EXPECT_NEAR(37.4168f, value.y(), 0.00015f);
+ gfx::ScrollOffset value = clone->ToScrollOffsetAnimationCurve()->GetValue(
+ TimeUtil::Scale(duration, 0.25f));
+ EXPECT_NEAR(3.0333f, value.x(), 0.0002f);
+ EXPECT_NEAR(37.4168f, value.y(), 0.0002f);
}
TEST(ScrollOffsetAnimationCurveTest, UpdateTarget) {
@@ -127,22 +134,24 @@ TEST(ScrollOffsetAnimationCurveTest, UpdateTarget) {
ScrollOffsetAnimationCurve::Create(
target_value, EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
- EXPECT_EQ(1.0, curve->Duration());
- EXPECT_EQ(1800.0, curve->GetValue(0.5).y());
- EXPECT_EQ(3600.0, curve->GetValue(1.0).y());
+ EXPECT_EQ(1.0, curve->Duration().InSecondsF());
+ EXPECT_EQ(1800.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.5)).y());
+ EXPECT_EQ(3600.0, curve->GetValue(base::TimeDelta::FromSecondsD(1.0)).y());
curve->UpdateTarget(0.5, gfx::ScrollOffset(0.0, 9900.0));
- EXPECT_EQ(2.0, curve->Duration());
- EXPECT_EQ(1800.0, curve->GetValue(0.5).y());
- EXPECT_NEAR(5566.49, curve->GetValue(1.0).y(), 0.01);
- EXPECT_EQ(9900.0, curve->GetValue(2.0).y());
+ EXPECT_EQ(2.0, curve->Duration().InSecondsF());
+ EXPECT_EQ(1800.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.5)).y());
+ EXPECT_NEAR(5566.49, curve->GetValue(base::TimeDelta::FromSecondsD(1.0)).y(),
+ 0.01);
+ EXPECT_EQ(9900.0, curve->GetValue(base::TimeDelta::FromSecondsD(2.0)).y());
curve->UpdateTarget(1.0, gfx::ScrollOffset(0.0, 7200.0));
- EXPECT_NEAR(1.674, curve->Duration(), 0.01);
- EXPECT_NEAR(5566.49, curve->GetValue(1.0).y(), 0.01);
- EXPECT_EQ(7200.0, curve->GetValue(1.674).y());
+ EXPECT_NEAR(1.674, curve->Duration().InSecondsF(), 0.01);
+ EXPECT_NEAR(5566.49, curve->GetValue(base::TimeDelta::FromSecondsD(1.0)).y(),
+ 0.01);
+ EXPECT_EQ(7200.0, curve->GetValue(base::TimeDelta::FromSecondsD(1.674)).y());
}
} // namespace
diff --git a/chromium/cc/animation/scrollbar_animation_controller.cc b/chromium/cc/animation/scrollbar_animation_controller.cc
index ffb22870825..48b199d6e66 100644
--- a/chromium/cc/animation/scrollbar_animation_controller.cc
+++ b/chromium/cc/animation/scrollbar_animation_controller.cc
@@ -7,15 +7,18 @@
#include <algorithm>
#include "base/time/time.h"
+#include "cc/trees/layer_tree_impl.h"
namespace cc {
ScrollbarAnimationController::ScrollbarAnimationController(
+ LayerImpl* scroll_layer,
ScrollbarAnimationControllerClient* client,
base::TimeDelta delay_before_starting,
base::TimeDelta resize_delay_before_starting,
base::TimeDelta duration)
- : client_(client),
+ : scroll_layer_(scroll_layer),
+ client_(client),
delay_before_starting_(delay_before_starting),
resize_delay_before_starting_(resize_delay_before_starting),
duration_(duration),
@@ -26,6 +29,8 @@ ScrollbarAnimationController::ScrollbarAnimationController(
}
ScrollbarAnimationController::~ScrollbarAnimationController() {
+ if (is_animating_)
+ client_->StopAnimatingScrollbarAnimationController(this);
}
void ScrollbarAnimationController::Animate(base::TimeTicks now) {
@@ -37,11 +42,6 @@ void ScrollbarAnimationController::Animate(base::TimeTicks now) {
float progress = AnimationProgressAtTime(now);
RunAnimationFrame(progress);
-
- if (is_animating_) {
- delayed_scrollbar_fade_.Cancel();
- client_->SetNeedsScrollbarAnimationFrame();
- }
}
float ScrollbarAnimationController::AnimationProgressAtTime(
@@ -62,38 +62,40 @@ void ScrollbarAnimationController::DidScrollUpdate(bool on_resize) {
// 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_)
- PostDelayedFade(on_resize);
+ PostDelayedAnimationTask(on_resize);
else
scroll_gesture_has_scrolled_ = true;
}
void ScrollbarAnimationController::DidScrollEnd() {
if (scroll_gesture_has_scrolled_) {
- PostDelayedFade(false);
+ PostDelayedAnimationTask(false);
scroll_gesture_has_scrolled_ = false;
}
currently_scrolling_ = false;
}
-void ScrollbarAnimationController::PostDelayedFade(bool on_resize) {
+void ScrollbarAnimationController::PostDelayedAnimationTask(bool on_resize) {
base::TimeDelta delay =
on_resize ? resize_delay_before_starting_ : delay_before_starting_;
delayed_scrollbar_fade_.Reset(
base::Bind(&ScrollbarAnimationController::StartAnimation,
weak_factory_.GetWeakPtr()));
- client_->PostDelayedScrollbarFade(delayed_scrollbar_fade_.callback(), delay);
+ client_->PostDelayedScrollbarAnimationTask(delayed_scrollbar_fade_.callback(),
+ delay);
}
void ScrollbarAnimationController::StartAnimation() {
delayed_scrollbar_fade_.Cancel();
is_animating_ = true;
last_awaken_time_ = base::TimeTicks();
- client_->SetNeedsScrollbarAnimationFrame();
+ client_->StartAnimatingScrollbarAnimationController(this);
}
void ScrollbarAnimationController::StopAnimation() {
is_animating_ = false;
+ client_->StopAnimatingScrollbarAnimationController(this);
}
} // namespace cc
diff --git a/chromium/cc/animation/scrollbar_animation_controller.h b/chromium/cc/animation/scrollbar_animation_controller.h
index 92efe755318..795c7c1766c 100644
--- a/chromium/cc/animation/scrollbar_animation_controller.h
+++ b/chromium/cc/animation/scrollbar_animation_controller.h
@@ -9,17 +9,25 @@
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "cc/base/cc_export.h"
+#include "cc/layers/layer_impl.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace cc {
+class ScrollbarAnimationController;
+
class CC_EXPORT ScrollbarAnimationControllerClient {
public:
- virtual ~ScrollbarAnimationControllerClient() {}
+ virtual void StartAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) = 0;
+ virtual void StopAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) = 0;
+ virtual void PostDelayedScrollbarAnimationTask(const base::Closure& task,
+ base::TimeDelta delay) = 0;
+ virtual void SetNeedsRedrawForScrollbarAnimation() = 0;
- virtual void PostDelayedScrollbarFade(const base::Closure& start_fade,
- base::TimeDelta delay) = 0;
- virtual void SetNeedsScrollbarAnimationFrame() = 0;
+ protected:
+ virtual ~ScrollbarAnimationControllerClient() {}
};
// This abstract class represents the compositor-side analogy of
@@ -38,7 +46,8 @@ class CC_EXPORT ScrollbarAnimationController {
virtual void DidMouseMoveNear(float distance) {}
protected:
- ScrollbarAnimationController(ScrollbarAnimationControllerClient* client,
+ ScrollbarAnimationController(LayerImpl* scroll_layer,
+ ScrollbarAnimationControllerClient* client,
base::TimeDelta delay_before_starting,
base::TimeDelta resize_delay_before_starting,
base::TimeDelta duration);
@@ -48,18 +57,21 @@ class CC_EXPORT ScrollbarAnimationController {
void StartAnimation();
void StopAnimation();
+ LayerImpl* scroll_layer_;
+ ScrollbarAnimationControllerClient* client_;
+
private:
// Returns how far through the animation we are as a progress value from
// 0 to 1.
float AnimationProgressAtTime(base::TimeTicks now);
- void PostDelayedFade(bool on_resize);
+ void PostDelayedAnimationTask(bool on_resize);
- ScrollbarAnimationControllerClient* client_;
base::TimeTicks last_awaken_time_;
base::TimeDelta delay_before_starting_;
base::TimeDelta resize_delay_before_starting_;
base::TimeDelta duration_;
+
bool is_animating_;
bool currently_scrolling_;
diff --git a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc
index 1b5dfd933da..d1049bda1cb 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc
+++ b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc
@@ -17,12 +17,9 @@ ScrollbarAnimationControllerLinearFade::Create(
base::TimeDelta delay_before_starting,
base::TimeDelta resize_delay_before_starting,
base::TimeDelta duration) {
- return make_scoped_ptr(
- new ScrollbarAnimationControllerLinearFade(scroll_layer,
- client,
- delay_before_starting,
- resize_delay_before_starting,
- duration));
+ return make_scoped_ptr(new ScrollbarAnimationControllerLinearFade(
+ scroll_layer, client, delay_before_starting, resize_delay_before_starting,
+ duration));
}
ScrollbarAnimationControllerLinearFade::ScrollbarAnimationControllerLinearFade(
@@ -31,18 +28,20 @@ ScrollbarAnimationControllerLinearFade::ScrollbarAnimationControllerLinearFade(
base::TimeDelta delay_before_starting,
base::TimeDelta resize_delay_before_starting,
base::TimeDelta duration)
- : ScrollbarAnimationController(client,
+ : ScrollbarAnimationController(scroll_layer,
+ client,
delay_before_starting,
resize_delay_before_starting,
- duration),
- scroll_layer_(scroll_layer) {
+ duration) {
}
ScrollbarAnimationControllerLinearFade::
- ~ScrollbarAnimationControllerLinearFade() {}
+ ~ScrollbarAnimationControllerLinearFade() {
+}
void ScrollbarAnimationControllerLinearFade::RunAnimationFrame(float progress) {
ApplyOpacityToScrollbars(1.f - progress);
+ client_->SetNeedsRedrawForScrollbarAnimation();
if (progress == 1.f)
StopAnimation();
}
@@ -59,8 +58,7 @@ void ScrollbarAnimationControllerLinearFade::ApplyOpacityToScrollbars(
LayerImpl::ScrollbarSet* scrollbars = scroll_layer_->scrollbars();
for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin();
- it != scrollbars->end();
- ++it) {
+ it != scrollbars->end(); ++it) {
ScrollbarLayerImplBase* scrollbar = *it;
if (scrollbar->is_overlay_scrollbar())
diff --git a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h
index 73d60311fef..05940a07ffc 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h
+++ b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h
@@ -40,8 +40,6 @@ class CC_EXPORT ScrollbarAnimationControllerLinearFade
float OpacityAtTime(base::TimeTicks now) const;
void ApplyOpacityToScrollbars(float opacity);
- LayerImpl* scroll_layer_;
-
DISALLOW_COPY_AND_ASSIGN(ScrollbarAnimationControllerLinearFade);
};
diff --git a/chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
index 3f01c54a174..6d2d3e879c0 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
+++ b/chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
@@ -9,6 +9,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -20,17 +21,27 @@ class ScrollbarAnimationControllerLinearFadeTest
public ScrollbarAnimationControllerClient {
public:
ScrollbarAnimationControllerLinearFadeTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_), needs_frame_count_(0) {}
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {}
- void PostDelayedScrollbarFade(const base::Closure& start_fade,
- base::TimeDelta delay) override {
+ void StartAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) override {
+ is_animating_ = true;
+ }
+ void StopAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) override {
+ is_animating_ = false;
+ }
+ void PostDelayedScrollbarAnimationTask(const base::Closure& start_fade,
+ base::TimeDelta delay) override {
start_fade_ = start_fade;
delay_ = delay;
}
- void SetNeedsScrollbarAnimationFrame() override { needs_frame_count_++; }
+ void SetNeedsRedrawForScrollbarAnimation() override {
+ did_request_redraw_ = true;
+ }
protected:
- virtual void SetUp() {
+ void SetUp() override {
const int kThumbThickness = 10;
const int kTrackStart = 0;
const bool kIsLeftSideVerticalScrollbar = false;
@@ -57,17 +68,15 @@ class ScrollbarAnimationControllerLinearFadeTest
scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
scrollbar_controller_ = ScrollbarAnimationControllerLinearFade::Create(
- scroll_layer_ptr,
- this,
- base::TimeDelta::FromSeconds(2),
- base::TimeDelta::FromSeconds(5),
- base::TimeDelta::FromSeconds(3));
+ scroll_layer_ptr, this, base::TimeDelta::FromSeconds(2),
+ base::TimeDelta::FromSeconds(5), base::TimeDelta::FromSeconds(3));
}
virtual ScrollbarOrientation orientation() const { return HORIZONTAL; }
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<ScrollbarAnimationControllerLinearFade> scrollbar_controller_;
scoped_ptr<LayerImpl> clip_layer_;
@@ -75,7 +84,8 @@ class ScrollbarAnimationControllerLinearFadeTest
base::Closure start_fade_;
base::TimeDelta delay_;
- int needs_frame_count_;
+ bool is_animating_;
+ bool did_request_redraw_;
};
class VerticalScrollbarAnimationControllerLinearFadeTest
@@ -104,7 +114,6 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, HiddenInBegin) {
scrollbar_layer_->SetOpacity(0.0f);
scrollbar_controller_->Animate(base::TimeTicks());
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
- EXPECT_EQ(0, needs_frame_count_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest,
@@ -123,20 +132,18 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest,
time += base::TimeDelta::FromSeconds(100);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-
- EXPECT_EQ(0, needs_frame_count_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest, HideOnResize) {
LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
ASSERT_TRUE(scroll_layer);
- EXPECT_SIZE_EQ(gfx::Size(200, 200), scroll_layer->bounds());
+ EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds());
EXPECT_EQ(HORIZONTAL, scrollbar_layer_->orientation());
// Shrink along X axis, horizontal scrollbar should appear.
clip_layer_->SetBounds(gfx::Size(100, 200));
- EXPECT_SIZE_EQ(gfx::Size(100, 200), clip_layer_->bounds());
+ EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds());
scrollbar_controller_->DidScrollBegin();
@@ -148,7 +155,7 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, HideOnResize) {
// Shrink along Y axis and expand along X, horizontal scrollbar
// should disappear.
clip_layer_->SetBounds(gfx::Size(200, 100));
- EXPECT_SIZE_EQ(gfx::Size(200, 100), clip_layer_->bounds());
+ EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds());
scrollbar_controller_->DidScrollBegin();
@@ -161,13 +168,13 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, HideOnResize) {
TEST_F(VerticalScrollbarAnimationControllerLinearFadeTest, HideOnResize) {
LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
ASSERT_TRUE(scroll_layer);
- EXPECT_SIZE_EQ(gfx::Size(200, 200), scroll_layer->bounds());
+ EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds());
EXPECT_EQ(VERTICAL, scrollbar_layer_->orientation());
// Shrink along X axis, vertical scrollbar should remain invisible.
clip_layer_->SetBounds(gfx::Size(100, 200));
- EXPECT_SIZE_EQ(gfx::Size(100, 200), clip_layer_->bounds());
+ EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds());
scrollbar_controller_->DidScrollBegin();
@@ -178,7 +185,7 @@ TEST_F(VerticalScrollbarAnimationControllerLinearFadeTest, HideOnResize) {
// Shrink along Y axis and expand along X, vertical scrollbar should appear.
clip_layer_->SetBounds(gfx::Size(200, 100));
- EXPECT_SIZE_EQ(gfx::Size(200, 100), clip_layer_->bounds());
+ EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds());
scrollbar_controller_->DidScrollBegin();
@@ -263,20 +270,24 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByScrollingGesture) {
EXPECT_TRUE(start_fade_.Equals(base::Closure()));
time += base::TimeDelta::FromSeconds(100);
+
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
scrollbar_controller_->DidScrollEnd();
start_fade_.Run();
time += base::TimeDelta::FromSeconds(2);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
@@ -285,50 +296,60 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByScrollingGesture) {
scrollbar_controller_->DidScrollBegin();
scrollbar_controller_->DidScrollUpdate(false);
scrollbar_controller_->DidScrollEnd();
+
start_fade_.Run();
time += base::TimeDelta::FromSeconds(2);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-
- EXPECT_EQ(8, needs_frame_count_);
+ EXPECT_FALSE(is_animating_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByProgrammaticScroll) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollUpdate(false);
+
start_fade_.Run();
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
scrollbar_controller_->DidScrollUpdate(false);
- start_fade_.Run();
- time += base::TimeDelta::FromSeconds(1);
+ start_fade_.Run();
+ time += base::TimeDelta::FromSeconds(2);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
@@ -336,22 +357,25 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByProgrammaticScroll) {
scrollbar_controller_->DidScrollUpdate(false);
start_fade_.Run();
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-
- EXPECT_EQ(11, needs_frame_count_);
+ EXPECT_FALSE(is_animating_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest,
@@ -360,10 +384,12 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest,
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollUpdate(false);
start_fade_.Run();
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
@@ -371,6 +397,7 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest,
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
@@ -378,12 +405,10 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest,
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-
- scrollbar_controller_->Animate(time);
-
- EXPECT_EQ(4, needs_frame_count_);
+ EXPECT_FALSE(is_animating_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest,
@@ -392,10 +417,12 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest,
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->DidScrollUpdate(false);
start_fade_.Run();
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
@@ -403,6 +430,7 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest,
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
+ EXPECT_TRUE(is_animating_);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning.cc b/chromium/cc/animation/scrollbar_animation_controller_thinning.cc
index 0405074b55a..af6987e0e0b 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_thinning.cc
+++ b/chromium/cc/animation/scrollbar_animation_controller_thinning.cc
@@ -7,6 +7,7 @@
#include "base/time/time.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/scrollbar_layer_impl_base.h"
+#include "cc/trees/layer_tree_impl.h"
namespace {
const float kIdleThicknessScale = 0.4f;
@@ -23,12 +24,9 @@ ScrollbarAnimationControllerThinning::Create(
base::TimeDelta delay_before_starting,
base::TimeDelta resize_delay_before_starting,
base::TimeDelta duration) {
- return make_scoped_ptr(
- new ScrollbarAnimationControllerThinning(scroll_layer,
- client,
- delay_before_starting,
- resize_delay_before_starting,
- duration));
+ return make_scoped_ptr(new ScrollbarAnimationControllerThinning(
+ scroll_layer, client, delay_before_starting, resize_delay_before_starting,
+ duration));
}
ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning(
@@ -37,11 +35,11 @@ ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning(
base::TimeDelta delay_before_starting,
base::TimeDelta resize_delay_before_starting,
base::TimeDelta duration)
- : ScrollbarAnimationController(client,
+ : ScrollbarAnimationController(scroll_layer,
+ client,
delay_before_starting,
resize_delay_before_starting,
duration),
- scroll_layer_(scroll_layer),
mouse_is_over_scrollbar_(false),
mouse_is_near_scrollbar_(false),
thickness_change_(NONE),
@@ -56,9 +54,10 @@ ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() {
void ScrollbarAnimationControllerThinning::RunAnimationFrame(float progress) {
float opacity = OpacityAtAnimationProgress(progress);
- float thumb_thickness_scale = ThumbThicknessScaleAtAnimationProgress(
- progress);
+ float thumb_thickness_scale =
+ ThumbThicknessScaleAtAnimationProgress(progress);
ApplyOpacityAndThumbThicknessScale(opacity, thumb_thickness_scale);
+ client_->SetNeedsRedrawForScrollbarAnimation();
if (progress == 1.f) {
opacity_change_ = NONE;
thickness_change_ = NONE;
@@ -77,7 +76,7 @@ void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar() {
void ScrollbarAnimationControllerThinning::DidScrollUpdate(bool on_resize) {
ScrollbarAnimationController::DidScrollUpdate(on_resize);
ApplyOpacityAndThumbThicknessScale(
- 1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale);
+ 1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale);
if (!mouse_is_over_scrollbar_)
opacity_change_ = DECREASE;
@@ -114,9 +113,8 @@ float ScrollbarAnimationControllerThinning::OpacityAtAnimationProgress(
return ret;
}
-float
-ScrollbarAnimationControllerThinning::ThumbThicknessScaleAtAnimationProgress(
- float progress) {
+float ScrollbarAnimationControllerThinning::
+ ThumbThicknessScaleAtAnimationProgress(float progress) {
if (thickness_change_ == NONE)
return mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale;
float factor = thickness_change_ == INCREASE ? progress : (1.f - progress);
@@ -135,14 +133,14 @@ float ScrollbarAnimationControllerThinning::AdjustScale(
}
void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale(
- float opacity, float thumb_thickness_scale) {
+ float opacity,
+ float thumb_thickness_scale) {
if (!scroll_layer_->scrollbars())
return;
LayerImpl::ScrollbarSet* scrollbars = scroll_layer_->scrollbars();
for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin();
- it != scrollbars->end();
- ++it) {
+ it != scrollbars->end(); ++it) {
ScrollbarLayerImplBase* scrollbar = *it;
if (scrollbar->is_overlay_scrollbar()) {
float effectiveOpacity =
@@ -151,10 +149,9 @@ void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale(
: 0;
scrollbar->SetOpacity(effectiveOpacity);
- scrollbar->SetThumbThicknessScaleFactor(
- AdjustScale(thumb_thickness_scale,
- scrollbar->thumb_thickness_scale_factor(),
- thickness_change_));
+ scrollbar->SetThumbThicknessScaleFactor(AdjustScale(
+ thumb_thickness_scale, scrollbar->thumb_thickness_scale_factor(),
+ thickness_change_));
}
}
}
diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning.h b/chromium/cc/animation/scrollbar_animation_controller_thinning.h
index 2cf30f5b821..f22d94c928d 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_thinning.h
+++ b/chromium/cc/animation/scrollbar_animation_controller_thinning.h
@@ -62,8 +62,6 @@ class CC_EXPORT ScrollbarAnimationControllerThinning
void ApplyOpacityAndThumbThicknessScale(float opacity,
float thumb_thickness_scale);
- LayerImpl* scroll_layer_;
-
bool mouse_is_over_scrollbar_;
bool mouse_is_near_scrollbar_;
// Are we narrowing or thickening the bars.
diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
index d46431b798f..04f81d369a4 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
+++ b/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
@@ -9,6 +9,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -20,16 +21,27 @@ class ScrollbarAnimationControllerThinningTest
public ScrollbarAnimationControllerClient {
public:
ScrollbarAnimationControllerThinningTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_) {}
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {}
- void PostDelayedScrollbarFade(const base::Closure& start_fade,
- base::TimeDelta delay) override {
+ void StartAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) override {
+ is_animating_ = true;
+ }
+ void StopAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) override {
+ is_animating_ = false;
+ }
+ void PostDelayedScrollbarAnimationTask(const base::Closure& start_fade,
+ base::TimeDelta delay) override {
start_fade_ = start_fade;
+ delay_ = delay;
+ }
+ void SetNeedsRedrawForScrollbarAnimation() override {
+ did_request_redraw_ = true;
}
- void SetNeedsScrollbarAnimationFrame() override {}
protected:
- virtual void SetUp() {
+ void SetUp() override {
scoped_ptr<LayerImpl> scroll_layer =
LayerImpl::Create(host_impl_.active_tree(), 1);
clip_layer_ = LayerImpl::Create(host_impl_.active_tree(), 3);
@@ -57,21 +69,22 @@ class ScrollbarAnimationControllerThinningTest
scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
scrollbar_controller_ = ScrollbarAnimationControllerThinning::Create(
- scroll_layer_ptr,
- this,
- base::TimeDelta::FromSeconds(2),
- base::TimeDelta::FromSeconds(5),
- base::TimeDelta::FromSeconds(3));
+ scroll_layer_ptr, this, base::TimeDelta::FromSeconds(2),
+ base::TimeDelta::FromSeconds(5), base::TimeDelta::FromSeconds(3));
}
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<ScrollbarAnimationControllerThinning> scrollbar_controller_;
scoped_ptr<LayerImpl> clip_layer_;
scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_;
base::Closure start_fade_;
+ base::TimeDelta delay_;
+ bool is_animating_;
+ bool did_request_redraw_;
};
// Check initialization of scrollbar.
@@ -85,13 +98,13 @@ TEST_F(ScrollbarAnimationControllerThinningTest, Idle) {
TEST_F(ScrollbarAnimationControllerThinningTest, HideOnResize) {
LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
ASSERT_TRUE(scroll_layer);
- EXPECT_SIZE_EQ(gfx::Size(200, 200), scroll_layer->bounds());
+ EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds());
EXPECT_EQ(HORIZONTAL, scrollbar_layer_->orientation());
// Shrink along X axis, horizontal scrollbar should appear.
clip_layer_->SetBounds(gfx::Size(100, 200));
- EXPECT_SIZE_EQ(gfx::Size(100, 200), clip_layer_->bounds());
+ EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds());
scrollbar_controller_->DidScrollBegin();
@@ -103,7 +116,7 @@ TEST_F(ScrollbarAnimationControllerThinningTest, HideOnResize) {
// Shrink along Y axis and expand along X, horizontal scrollbar
// should disappear.
clip_layer_->SetBounds(gfx::Size(200, 100));
- EXPECT_SIZE_EQ(gfx::Size(200, 100), clip_layer_->bounds());
+ EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds());
scrollbar_controller_->DidScrollBegin();
diff --git a/chromium/cc/animation/timing_function.cc b/chromium/cc/animation/timing_function.cc
index 2531cc69f36..94bf12874d3 100644
--- a/chromium/cc/animation/timing_function.cc
+++ b/chromium/cc/animation/timing_function.cc
@@ -5,6 +5,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "cc/animation/timing_function.h"
+#include "cc/base/math_util.h"
namespace cc {
@@ -63,4 +64,41 @@ scoped_ptr<TimingFunction> EaseInOutTimingFunction::Create() {
return CubicBezierTimingFunction::Create(0.42, 0.0, 0.58, 1);
}
+scoped_ptr<StepsTimingFunction> StepsTimingFunction::Create(
+ int steps,
+ float steps_start_offset) {
+ return make_scoped_ptr(new StepsTimingFunction(steps, steps_start_offset));
+}
+
+StepsTimingFunction::StepsTimingFunction(int steps, float steps_start_offset)
+ : steps_(steps), steps_start_offset_(steps_start_offset) {
+ // Restrict it to CSS presets: step_start, step_end and step_middle.
+ // See the Web Animations specification, 3.12.4. Timing in discrete steps.
+ DCHECK(steps_start_offset_ == 0 || steps_start_offset_ == 1 ||
+ steps_start_offset_ == 0.5);
+}
+
+StepsTimingFunction::~StepsTimingFunction() {
+}
+
+float StepsTimingFunction::GetValue(double t) const {
+ const double steps = static_cast<double>(steps_);
+ const double value = MathUtil::ClampToRange(
+ std::floor((steps * t) + steps_start_offset_) / steps, 0.0, 1.0);
+ return static_cast<float>(value);
+}
+
+scoped_ptr<TimingFunction> StepsTimingFunction::Clone() const {
+ return make_scoped_ptr(new StepsTimingFunction(*this));
+}
+
+void StepsTimingFunction::Range(float* min, float* max) const {
+ *min = 0.0f;
+ *max = 1.0f;
+}
+
+float StepsTimingFunction::Velocity(double x) const {
+ return 0.0f;
+}
+
} // namespace cc
diff --git a/chromium/cc/animation/timing_function.h b/chromium/cc/animation/timing_function.h
index 69d1cc9fb5c..95144a7cfd7 100644
--- a/chromium/cc/animation/timing_function.h
+++ b/chromium/cc/animation/timing_function.h
@@ -81,6 +81,28 @@ class CC_EXPORT EaseInOutTimingFunction {
DISALLOW_IMPLICIT_CONSTRUCTORS(EaseInOutTimingFunction);
};
+class CC_EXPORT StepsTimingFunction : public TimingFunction {
+ public:
+ static scoped_ptr<StepsTimingFunction> Create(int steps,
+ float steps_start_offset);
+ ~StepsTimingFunction() override;
+
+ float GetValue(double t) const override;
+ scoped_ptr<TimingFunction> Clone() const override;
+
+ void Range(float* min, float* max) const override;
+ float Velocity(double time) const override;
+
+ protected:
+ StepsTimingFunction(int steps, float steps_start_offset);
+
+ private:
+ int steps_;
+ float steps_start_offset_;
+
+ DISALLOW_ASSIGN(StepsTimingFunction);
+};
+
} // namespace cc
#endif // CC_ANIMATION_TIMING_FUNCTION_H_
diff --git a/chromium/cc/animation/transform_operation.cc b/chromium/cc/animation/transform_operation.cc
index e9ae86dd471..7421924aedc 100644
--- a/chromium/cc/animation/transform_operation.cc
+++ b/chromium/cc/animation/transform_operation.cc
@@ -99,14 +99,14 @@ bool TransformOperation::BlendTransformOperations(
return true;
TransformOperation::Type interpolation_type =
- TransformOperation::TransformOperationIdentity;
+ TransformOperation::TRANSFORM_OPERATION_IDENTITY;
if (IsOperationIdentity(to))
interpolation_type = from->type;
else
interpolation_type = to->type;
switch (interpolation_type) {
- case TransformOperation::TransformOperationTranslate: {
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: {
SkMScalar from_x = IsOperationIdentity(from) ? 0 : from->translate.x;
SkMScalar from_y = IsOperationIdentity(from) ? 0 : from->translate.y;
SkMScalar from_z = IsOperationIdentity(from) ? 0 : from->translate.z;
@@ -118,7 +118,7 @@ bool TransformOperation::BlendTransformOperations(
BlendSkMScalars(from_z, to_z, progress));
break;
}
- case TransformOperation::TransformOperationRotate: {
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
SkMScalar axis_x = 0;
SkMScalar axis_y = 0;
SkMScalar axis_z = 1;
@@ -140,7 +140,7 @@ bool TransformOperation::BlendTransformOperations(
}
break;
}
- case TransformOperation::TransformOperationScale: {
+ case TransformOperation::TRANSFORM_OPERATION_SCALE: {
SkMScalar from_x = IsOperationIdentity(from) ? 1 : from->scale.x;
SkMScalar from_y = IsOperationIdentity(from) ? 1 : from->scale.y;
SkMScalar from_z = IsOperationIdentity(from) ? 1 : from->scale.z;
@@ -152,7 +152,7 @@ bool TransformOperation::BlendTransformOperations(
BlendSkMScalars(from_z, to_z, progress));
break;
}
- case TransformOperation::TransformOperationSkew: {
+ case TransformOperation::TRANSFORM_OPERATION_SKEW: {
SkMScalar from_x = IsOperationIdentity(from) ? 0 : from->skew.x;
SkMScalar from_y = IsOperationIdentity(from) ? 0 : from->skew.y;
SkMScalar to_x = IsOperationIdentity(to) ? 0 : to->skew.x;
@@ -161,7 +161,7 @@ bool TransformOperation::BlendTransformOperations(
result->SkewY(BlendSkMScalars(from_y, to_y, progress));
break;
}
- case TransformOperation::TransformOperationPerspective: {
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: {
SkMScalar from_perspective_depth =
IsOperationIdentity(from) ? std::numeric_limits<SkMScalar>::max()
: from->perspective_depth;
@@ -180,7 +180,7 @@ bool TransformOperation::BlendTransformOperations(
result->ApplyPerspectiveDepth(1.f / blended_perspective_depth);
break;
}
- case TransformOperation::TransformOperationMatrix: {
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX: {
gfx::Transform to_matrix;
if (!IsOperationIdentity(to))
to_matrix = to->matrix;
@@ -192,7 +192,7 @@ bool TransformOperation::BlendTransformOperations(
return false;
break;
}
- case TransformOperation::TransformOperationIdentity:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
// Do nothing.
break;
}
@@ -375,20 +375,20 @@ bool TransformOperation::BlendedBoundsForBox(const gfx::BoxF& box,
}
TransformOperation::Type interpolation_type =
- TransformOperation::TransformOperationIdentity;
+ TransformOperation::TRANSFORM_OPERATION_IDENTITY;
if (is_identity_to)
interpolation_type = from->type;
else
interpolation_type = to->type;
switch (interpolation_type) {
- case TransformOperation::TransformOperationIdentity:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
*bounds = box;
return true;
- case TransformOperation::TransformOperationTranslate:
- case TransformOperation::TransformOperationSkew:
- case TransformOperation::TransformOperationPerspective:
- case TransformOperation::TransformOperationScale: {
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE: {
gfx::Transform from_transform;
gfx::Transform to_transform;
if (!BlendTransformOperations(from, to, min_progress, &from_transform) ||
@@ -404,7 +404,7 @@ bool TransformOperation::BlendedBoundsForBox(const gfx::BoxF& box,
return true;
}
- case TransformOperation::TransformOperationRotate: {
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
SkMScalar axis_x = 0;
SkMScalar axis_y = 0;
SkMScalar axis_z = 1;
@@ -429,7 +429,7 @@ bool TransformOperation::BlendedBoundsForBox(const gfx::BoxF& box,
}
return true;
}
- case TransformOperation::TransformOperationMatrix:
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
return false;
}
NOTREACHED();
diff --git a/chromium/cc/animation/transform_operation.h b/chromium/cc/animation/transform_operation.h
index 345ff295e39..3ea5fc20210 100644
--- a/chromium/cc/animation/transform_operation.h
+++ b/chromium/cc/animation/transform_operation.h
@@ -15,18 +15,16 @@ namespace cc {
struct TransformOperation {
enum Type {
- TransformOperationTranslate,
- TransformOperationRotate,
- TransformOperationScale,
- TransformOperationSkew,
- TransformOperationPerspective,
- TransformOperationMatrix,
- TransformOperationIdentity
+ TRANSFORM_OPERATION_TRANSLATE,
+ TRANSFORM_OPERATION_ROTATE,
+ TRANSFORM_OPERATION_SCALE,
+ TRANSFORM_OPERATION_SKEW,
+ TRANSFORM_OPERATION_PERSPECTIVE,
+ TRANSFORM_OPERATION_MATRIX,
+ TRANSFORM_OPERATION_IDENTITY
};
- TransformOperation()
- : type(TransformOperationIdentity) {
- }
+ TransformOperation() : type(TRANSFORM_OPERATION_IDENTITY) {}
Type type;
gfx::Transform matrix;
diff --git a/chromium/cc/animation/transform_operations.cc b/chromium/cc/animation/transform_operations.cc
index 7bc4ce2ab69..20e8c6a6587 100644
--- a/chromium/cc/animation/transform_operations.cc
+++ b/chromium/cc/animation/transform_operations.cc
@@ -85,29 +85,50 @@ bool TransformOperations::BlendedBoundsForBox(const gfx::BoxF& box,
bool TransformOperations::AffectsScale() const {
for (size_t i = 0; i < operations_.size(); ++i) {
- if (operations_[i].type == TransformOperation::TransformOperationScale)
+ if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_SCALE)
return true;
- if (operations_[i].type == TransformOperation::TransformOperationMatrix &&
+ if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_MATRIX &&
!operations_[i].matrix.IsIdentityOrTranslation())
return true;
}
return false;
}
+bool TransformOperations::PreservesAxisAlignment() const {
+ for (size_t i = 0; i < operations_.size(); ++i) {
+ switch (operations_[i].type) {
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
+ continue;
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
+ if (!operations_[i].matrix.IsIdentity() &&
+ !operations_[i].matrix.IsScaleOrTranslation())
+ return false;
+ continue;
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ return false;
+ }
+ }
+ return true;
+}
+
bool TransformOperations::IsTranslation() const {
for (size_t i = 0; i < operations_.size(); ++i) {
switch (operations_[i].type) {
- case TransformOperation::TransformOperationIdentity:
- case TransformOperation::TransformOperationTranslate:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
continue;
- case TransformOperation::TransformOperationMatrix:
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
if (!operations_[i].matrix.IsIdentityOrTranslation())
return false;
continue;
- case TransformOperation::TransformOperationRotate:
- case TransformOperation::TransformOperationScale:
- case TransformOperation::TransformOperationSkew:
- case TransformOperation::TransformOperationPerspective:
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
return false;
}
}
@@ -119,18 +140,18 @@ bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const {
bool has_scale_component = false;
for (size_t i = 0; i < operations_.size(); ++i) {
switch (operations_[i].type) {
- case TransformOperation::TransformOperationIdentity:
- case TransformOperation::TransformOperationTranslate:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
continue;
- case TransformOperation::TransformOperationMatrix:
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
if (!operations_[i].matrix.IsIdentityOrTranslation())
return false;
continue;
- case TransformOperation::TransformOperationRotate:
- case TransformOperation::TransformOperationSkew:
- case TransformOperation::TransformOperationPerspective:
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
return false;
- case TransformOperation::TransformOperationScale:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
if (has_scale_component)
return false;
has_scale_component = true;
@@ -170,7 +191,7 @@ void TransformOperations::AppendTranslate(SkMScalar x,
SkMScalar z) {
TransformOperation to_add;
to_add.matrix.Translate3d(x, y, z);
- to_add.type = TransformOperation::TransformOperationTranslate;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_TRANSLATE;
to_add.translate.x = x;
to_add.translate.y = y;
to_add.translate.z = z;
@@ -184,7 +205,7 @@ void TransformOperations::AppendRotate(SkMScalar x,
SkMScalar degrees) {
TransformOperation to_add;
to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
- to_add.type = TransformOperation::TransformOperationRotate;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_ROTATE;
to_add.rotate.axis.x = x;
to_add.rotate.axis.y = y;
to_add.rotate.axis.z = z;
@@ -196,7 +217,7 @@ void TransformOperations::AppendRotate(SkMScalar x,
void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
TransformOperation to_add;
to_add.matrix.Scale3d(x, y, z);
- to_add.type = TransformOperation::TransformOperationScale;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_SCALE;
to_add.scale.x = x;
to_add.scale.y = y;
to_add.scale.z = z;
@@ -208,7 +229,7 @@ void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
TransformOperation to_add;
to_add.matrix.SkewX(x);
to_add.matrix.SkewY(y);
- to_add.type = TransformOperation::TransformOperationSkew;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEW;
to_add.skew.x = x;
to_add.skew.y = y;
operations_.push_back(to_add);
@@ -218,7 +239,7 @@ void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
void TransformOperations::AppendPerspective(SkMScalar depth) {
TransformOperation to_add;
to_add.matrix.ApplyPerspectiveDepth(depth);
- to_add.type = TransformOperation::TransformOperationPerspective;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE;
to_add.perspective_depth = depth;
operations_.push_back(to_add);
decomposed_transform_dirty_ = true;
@@ -227,7 +248,7 @@ void TransformOperations::AppendPerspective(SkMScalar depth) {
void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
TransformOperation to_add;
to_add.matrix = matrix;
- to_add.type = TransformOperation::TransformOperationMatrix;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_MATRIX;
operations_.push_back(to_add);
decomposed_transform_dirty_ = true;
}
diff --git a/chromium/cc/animation/transform_operations.h b/chromium/cc/animation/transform_operations.h
index 1c110fffc75..65f8511d511 100644
--- a/chromium/cc/animation/transform_operations.h
+++ b/chromium/cc/animation/transform_operations.h
@@ -63,6 +63,9 @@ class CC_EXPORT TransformOperations {
// Returns true if these operations are only translations.
bool IsTranslation() const;
+ // Returns false if the operations affect 2d axis alignment.
+ bool PreservesAxisAlignment() const;
+
// Returns true if this operation and its descendants have the same types
// as other and its descendants.
bool MatchesTypes(const TransformOperations& other) const;
diff --git a/chromium/cc/base/BUILD.gn b/chromium/cc/base/BUILD.gn
new file mode 100644
index 00000000000..e41c74f1586
--- /dev/null
+++ b/chromium/cc/base/BUILD.gn
@@ -0,0 +1,50 @@
+# 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.
+
+source_set("base") {
+ visibility = [ "//cc" ]
+
+ sources = [
+ "completion_event.h",
+ "delayed_unique_notifier.cc",
+ "delayed_unique_notifier.h",
+ "invalidation_region.cc",
+ "invalidation_region.h",
+ "math_util.cc",
+ "math_util.h",
+ "region.cc",
+ "region.h",
+ "rolling_time_delta_history.cc",
+ "rolling_time_delta_history.h",
+ "scoped_ptr_algorithm.h",
+ "scoped_ptr_deque.h",
+ "scoped_ptr_vector.h",
+ "simple_enclosed_region.cc",
+ "simple_enclosed_region.h",
+ "switches.cc",
+ "switches.h",
+ "synced_property.h",
+ "tiling_data.cc",
+ "tiling_data.h",
+ "time_util.h",
+ "unique_notifier.cc",
+ "unique_notifier.h",
+ "util.h",
+ ]
+
+ deps = [
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//skia",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+
+ defines = [ "CC_IMPLEMENTATION=1" ]
+
+ if (!is_debug && (is_win || is_android)) {
+ configs -= [ "//build/config/compiler:optimize" ]
+ configs += [ "//build/config/compiler:optimize_max" ]
+ }
+}
diff --git a/chromium/cc/base/DEPS b/chromium/cc/base/DEPS
new file mode 100644
index 00000000000..33b4e8f0bac
--- /dev/null
+++ b/chromium/cc/base/DEPS
@@ -0,0 +1,12 @@
+# Things within cc/base should not depend on things in cc/ outside of cc/base.
+include_rules = [
+ "-cc",
+ "+cc/base",
+]
+
+# Tests can use things in cc/test
+specific_include_rules = {
+ ".*unittest\.cc": [
+ "+cc/test",
+ ]
+}
diff --git a/chromium/cc/base/completion_event.h b/chromium/cc/base/completion_event.h
index 96ccf5417de..6bae765dd20 100644
--- a/chromium/cc/base/completion_event.h
+++ b/chromium/cc/base/completion_event.h
@@ -19,21 +19,21 @@ class CompletionEvent {
public:
CompletionEvent()
: event_(false /* manual_reset */, false /* initially_signaled */) {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
waited_ = false;
signaled_ = false;
#endif
}
~CompletionEvent() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(waited_);
DCHECK(signaled_);
#endif
}
void Wait() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(!waited_);
waited_ = true;
#endif
@@ -42,7 +42,7 @@ class CompletionEvent {
}
void Signal() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(!signaled_);
signaled_ = true;
#endif
@@ -51,7 +51,7 @@ class CompletionEvent {
private:
base::WaitableEvent event_;
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
// Used to assert that Wait() and Signal() are each called exactly once.
bool waited_;
bool signaled_;
diff --git a/chromium/cc/base/delayed_unique_notifier_unittest.cc b/chromium/cc/base/delayed_unique_notifier_unittest.cc
index 3e41d321f3e..f30834e460f 100644
--- a/chromium/cc/base/delayed_unique_notifier_unittest.cc
+++ b/chromium/cc/base/delayed_unique_notifier_unittest.cc
@@ -35,7 +35,7 @@ class DelayedUniqueNotifierTest : public testing::Test {
public:
DelayedUniqueNotifierTest() : notification_count_(0) {}
- virtual void SetUp() override {
+ void SetUp() override {
notification_count_ = 0;
task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner);
}
diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc
index 816f6fc2c6e..969e52a6ed7 100644
--- a/chromium/cc/base/math_util.cc
+++ b/chromium/cc/base/math_util.cc
@@ -8,13 +8,14 @@
#include <cmath>
#include <limits>
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "ui/gfx/geometry/quad_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
#include "ui/gfx/transform.h"
namespace cc {
@@ -733,59 +734,85 @@ scoped_ptr<base::Value> MathUtil::AsValue(const gfx::PointF& pt) {
return res.Pass();
}
-void MathUtil::AddToTracedValue(const gfx::Size& s,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::Size& s,
+ base::trace_event::TracedValue* res) {
+ res->BeginDictionary(name);
res->SetDouble("width", s.width());
res->SetDouble("height", s.height());
+ res->EndDictionary();
}
-void MathUtil::AddToTracedValue(const gfx::SizeF& s,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::SizeF& s,
+ base::trace_event::TracedValue* res) {
+ res->BeginDictionary(name);
res->SetDouble("width", s.width());
res->SetDouble("height", s.height());
+ res->EndDictionary();
}
-void MathUtil::AddToTracedValue(const gfx::Rect& r,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::Rect& r,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
res->AppendInteger(r.x());
res->AppendInteger(r.y());
res->AppendInteger(r.width());
res->AppendInteger(r.height());
+ res->EndArray();
}
-void MathUtil::AddToTracedValue(const gfx::PointF& pt,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::PointF& pt,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
res->AppendDouble(pt.x());
res->AppendDouble(pt.y());
+ res->EndArray();
}
-void MathUtil::AddToTracedValue(const gfx::Point3F& pt,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::Point3F& pt,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
res->AppendDouble(pt.x());
res->AppendDouble(pt.y());
res->AppendDouble(pt.z());
+ res->EndArray();
}
-void MathUtil::AddToTracedValue(const gfx::Vector2d& v,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::Vector2d& v,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
res->AppendInteger(v.x());
res->AppendInteger(v.y());
+ res->EndArray();
}
-void MathUtil::AddToTracedValue(const gfx::Vector2dF& v,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::Vector2dF& v,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
res->AppendDouble(v.x());
res->AppendDouble(v.y());
+ res->EndArray();
}
-void MathUtil::AddToTracedValue(const gfx::ScrollOffset& v,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::ScrollOffset& v,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
res->AppendDouble(v.x());
res->AppendDouble(v.y());
+ res->EndArray();
}
-void MathUtil::AddToTracedValue(const gfx::QuadF& q,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::QuadF& q,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
res->AppendDouble(q.p1().x());
res->AppendDouble(q.p1().y());
res->AppendDouble(q.p2().x());
@@ -794,33 +821,43 @@ void MathUtil::AddToTracedValue(const gfx::QuadF& q,
res->AppendDouble(q.p3().y());
res->AppendDouble(q.p4().x());
res->AppendDouble(q.p4().y());
+ res->EndArray();
}
-void MathUtil::AddToTracedValue(const gfx::RectF& rect,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::RectF& rect,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
res->AppendDouble(rect.x());
res->AppendDouble(rect.y());
res->AppendDouble(rect.width());
res->AppendDouble(rect.height());
+ res->EndArray();
}
-void MathUtil::AddToTracedValue(const gfx::Transform& transform,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::Transform& transform,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
const SkMatrix44& m = transform.matrix();
for (int row = 0; row < 4; ++row) {
for (int col = 0; col < 4; ++col)
res->AppendDouble(m.getDouble(row, col));
}
+ res->EndArray();
}
-void MathUtil::AddToTracedValue(const gfx::BoxF& box,
- base::debug::TracedValue* res) {
+void MathUtil::AddToTracedValue(const char* name,
+ const gfx::BoxF& box,
+ base::trace_event::TracedValue* res) {
+ res->BeginArray(name);
res->AppendInteger(box.x());
res->AppendInteger(box.y());
res->AppendInteger(box.z());
res->AppendInteger(box.width());
res->AppendInteger(box.height());
res->AppendInteger(box.depth());
+ res->EndArray();
}
double MathUtil::AsDoubleSafely(double value) {
@@ -831,4 +868,16 @@ float MathUtil::AsFloatSafely(float value) {
return std::min(value, std::numeric_limits<float>::max());
}
+gfx::Vector3dF MathUtil::GetXAxis(const gfx::Transform& transform) {
+ return gfx::Vector3dF(transform.matrix().getFloat(0, 0),
+ transform.matrix().getFloat(1, 0),
+ transform.matrix().getFloat(2, 0));
+}
+
+gfx::Vector3dF MathUtil::GetYAxis(const gfx::Transform& transform) {
+ return gfx::Vector3dF(transform.matrix().getFloat(0, 1),
+ transform.matrix().getFloat(1, 1),
+ transform.matrix().getFloat(2, 1));
+}
+
} // namespace cc
diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h
index 50494e1ba79..749b9bdbae1 100644
--- a/chromium/cc/base/math_util.h
+++ b/chromium/cc/base/math_util.h
@@ -21,10 +21,10 @@
namespace base {
class Value;
-namespace debug {
+namespace trace_event {
class TracedValue;
}
-}
+} // namespace base
namespace gfx {
class QuadF;
@@ -33,6 +33,7 @@ class RectF;
class Transform;
class Vector2dF;
class Vector2d;
+class Vector3dF;
}
namespace cc {
@@ -199,35 +200,53 @@ class CC_EXPORT MathUtil {
static bool FromValue(const base::Value*, gfx::Rect* out_rect);
static scoped_ptr<base::Value> AsValue(const gfx::PointF& q);
- static void AddToTracedValue(const gfx::Size& s,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::SizeF& s,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::Rect& r,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::PointF& q,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::Point3F&,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::Vector2d& v,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::Vector2dF& v,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::ScrollOffset& v,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::QuadF& q,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::RectF& rect,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::Transform& transform,
- base::debug::TracedValue* res);
- static void AddToTracedValue(const gfx::BoxF& box,
- base::debug::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::Size& s,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::SizeF& s,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::Rect& r,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::PointF& q,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::Point3F&,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::Vector2d& v,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::Vector2dF& v,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::ScrollOffset& v,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::QuadF& q,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::RectF& rect,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::Transform& transform,
+ base::trace_event::TracedValue* res);
+ static void AddToTracedValue(const char* name,
+ const gfx::BoxF& box,
+ base::trace_event::TracedValue* res);
// Returns a base::Value representation of the floating point value.
// If the value is inf, returns max double/float representation.
static double AsDoubleSafely(double value);
static float AsFloatSafely(float value);
+
+ // Returns vector that x axis (1,0,0) transforms to under given transform.
+ static gfx::Vector3dF GetXAxis(const gfx::Transform& transform);
+
+ // Returns vector that y axis (0,1,0) transforms to under given transform.
+ static gfx::Vector3dF GetYAxis(const gfx::Transform& transform);
};
} // namespace cc
diff --git a/chromium/cc/base/ref_counted_managed.h b/chromium/cc/base/ref_counted_managed.h
deleted file mode 100644
index 8bb836f0159..00000000000
--- a/chromium/cc/base/ref_counted_managed.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_BASE_REF_COUNTED_MANAGED_H_
-#define CC_BASE_REF_COUNTED_MANAGED_H_
-
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "cc/base/cc_export.h"
-
-namespace cc {
-
-template <typename T> class RefCountedManaged;
-
-template <typename T>
-class CC_EXPORT RefCountedManager {
- protected:
- RefCountedManager() : live_object_count_(0) {}
- ~RefCountedManager() {
- CHECK_EQ(0, live_object_count_);
- }
-
- virtual void Release(T* object) = 0;
-
- private:
- friend class RefCountedManaged<T>;
- int live_object_count_;
-};
-
-template <typename T>
-class CC_EXPORT RefCountedManaged : public base::subtle::RefCountedBase {
- public:
- explicit RefCountedManaged(RefCountedManager<T>* manager)
- : manager_(manager) {
- manager_->live_object_count_++;
- }
-
- void AddRef() const {
- base::subtle::RefCountedBase::AddRef();
- }
-
- void Release() {
- if (base::subtle::RefCountedBase::Release()) {
- DCHECK_GT(manager_->live_object_count_, 0);
- manager_->live_object_count_--;
-
- // This must be the last statement in case manager deletes
- // the object immediately.
- manager_->Release(static_cast<T*>(this));
- }
- }
-
- protected:
- ~RefCountedManaged() {}
-
- private:
- RefCountedManager<T>* manager_;
-
- DISALLOW_COPY_AND_ASSIGN(RefCountedManaged<T>);
-};
-
-} // namespace cc
-
-#endif // CC_BASE_REF_COUNTED_MANAGED_H_
diff --git a/chromium/cc/base/region.cc b/chromium/cc/base/region.cc
index d752b205568..c048c89e571 100644
--- a/chromium/cc/base/region.cc
+++ b/chromium/cc/base/region.cc
@@ -4,7 +4,7 @@
#include "cc/base/region.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/simple_enclosed_region.h"
@@ -130,7 +130,7 @@ scoped_ptr<base::Value> Region::AsValue() const {
return result.Pass();
}
-void Region::AsValueInto(base::debug::TracedValue* result) const {
+void Region::AsValueInto(base::trace_event::TracedValue* result) const {
for (Iterator it(*this); it.has_rect(); it.next()) {
gfx::Rect rect(it.rect());
result->AppendInteger(rect.x());
diff --git a/chromium/cc/base/region.h b/chromium/cc/base/region.h
index 294ea639200..583311e09fe 100644
--- a/chromium/cc/base/region.h
+++ b/chromium/cc/base/region.h
@@ -15,7 +15,7 @@
namespace base {
class Value;
-namespace debug {
+namespace trace_event {
class TracedValue;
}
}
@@ -63,7 +63,7 @@ class CC_EXPORT Region {
std::string ToString() const;
scoped_ptr<base::Value> AsValue() const;
- void AsValueInto(base::debug::TracedValue* array) const;
+ void AsValueInto(base::trace_event::TracedValue* array) const;
class CC_EXPORT Iterator {
public:
diff --git a/chromium/cc/base/rolling_time_delta_history.cc b/chromium/cc/base/rolling_time_delta_history.cc
index 0f95cc5fe52..db04f586b0b 100644
--- a/chromium/cc/base/rolling_time_delta_history.cc
+++ b/chromium/cc/base/rolling_time_delta_history.cc
@@ -26,10 +26,6 @@ void RollingTimeDeltaHistory::InsertSample(base::TimeDelta time) {
chronological_sample_deque_.push_back(it);
}
-size_t RollingTimeDeltaHistory::SampleCount() {
- return sample_set_.size();
-}
-
void RollingTimeDeltaHistory::Clear() {
chronological_sample_deque_.clear();
sample_set_.clear();
diff --git a/chromium/cc/base/rolling_time_delta_history.h b/chromium/cc/base/rolling_time_delta_history.h
index 603c813425f..e51fb86ba96 100644
--- a/chromium/cc/base/rolling_time_delta_history.h
+++ b/chromium/cc/base/rolling_time_delta_history.h
@@ -23,8 +23,6 @@ class CC_EXPORT RollingTimeDeltaHistory {
void InsertSample(base::TimeDelta time);
- size_t SampleCount();
-
void Clear();
// Returns the smallest sample that is greater than or equal to the specified
diff --git a/chromium/cc/base/scoped_ptr_vector.h b/chromium/cc/base/scoped_ptr_vector.h
index 164b27c89bd..b552d738725 100644
--- a/chromium/cc/base/scoped_ptr_vector.h
+++ b/chromium/cc/base/scoped_ptr_vector.h
@@ -159,6 +159,30 @@ class ScopedPtrVector {
std::swap(*writable_a, *writable_b);
}
+ // This acts like std::remove_if but with one key difference. The values to be
+ // removed to will each appear exactly once at or after the returned iterator,
+ // so that erase(foo.remove_if(P), foo.end()) will not leak or double-free the
+ // pointers in the vector.
+ template <typename Predicate>
+ iterator remove_if(Predicate predicate) {
+ typename std::vector<T*>::iterator it =
+ std::find_if(data_.begin(), data_.end(), predicate);
+ typename std::vector<T*>::iterator end = data_.end();
+ if (it == end)
+ return it;
+ typename std::vector<T*>::iterator result = it;
+ ++it;
+ for (; it != end; ++it) {
+ if (!static_cast<bool>(predicate(*it))) {
+ // Swap here instead of just assign to |result| so that all the
+ // pointers are preserved to be deleted afterward.
+ std::swap(*result, *it);
+ ++result;
+ }
+ }
+ return result;
+ }
+
template<class Compare>
inline void sort(Compare comp) {
std::sort(data_.begin(), data_.end(), comp);
diff --git a/chromium/cc/base/scoped_ptr_vector_unittest.cc b/chromium/cc/base/scoped_ptr_vector_unittest.cc
index 391ab48cc06..7b9a86bd241 100644
--- a/chromium/cc/base/scoped_ptr_vector_unittest.cc
+++ b/chromium/cc/base/scoped_ptr_vector_unittest.cc
@@ -101,5 +101,84 @@ TEST(ScopedPtrVectorTest, Partition) {
EXPECT_EQ(2u, even_numbers.size());
}
+class DataWithDestruction {
+ public:
+ static scoped_ptr<DataWithDestruction> Create(int i, int* destroy_count) {
+ return make_scoped_ptr(new DataWithDestruction(i, destroy_count));
+ }
+ int data() const { return data_; }
+ ~DataWithDestruction() { ++(*destroy_count_); }
+
+ private:
+ explicit DataWithDestruction(int i, int* destroy_count)
+ : data_(i), destroy_count_(destroy_count) {}
+ int data_;
+ int* destroy_count_;
+};
+
+TEST(ScopedPtrVectorTest, RemoveIf) {
+ ScopedPtrVector<DataWithDestruction> v;
+ int destroyed[6] = {0};
+ v.push_back(DataWithDestruction::Create(1, &destroyed[0]));
+ v.push_back(DataWithDestruction::Create(2, &destroyed[1]));
+ v.push_back(DataWithDestruction::Create(3, &destroyed[2]));
+ v.push_back(DataWithDestruction::Create(3, &destroyed[3]));
+ v.push_back(DataWithDestruction::Create(4, &destroyed[4]));
+ v.push_back(DataWithDestruction::Create(5, &destroyed[5]));
+
+ int expect_destroyed[6] = {0};
+
+ // Removing more than one thing that matches.
+ auto is_three = [](DataWithDestruction* d) { return d->data() == 3; };
+ v.erase(v.remove_if(is_three), v.end());
+ EXPECT_EQ(4u, v.size());
+ expect_destroyed[2]++;
+ expect_destroyed[3]++;
+ for (size_t i = 0; i < arraysize(destroyed); ++i)
+ EXPECT_EQ(expect_destroyed[i], destroyed[i]) << i;
+ {
+ int expect_data[4] = {1, 2, 4, 5};
+ for (size_t i = 0; i < arraysize(expect_data); ++i)
+ EXPECT_EQ(expect_data[i], v[i]->data()) << i;
+ }
+
+ // Removing from the back of the vector.
+ auto is_five = [](DataWithDestruction* d) { return d->data() == 5; };
+ v.erase(v.remove_if(is_five), v.end());
+ EXPECT_EQ(3u, v.size());
+ expect_destroyed[5]++;
+ for (size_t i = 0; i < arraysize(destroyed); ++i)
+ EXPECT_EQ(expect_destroyed[i], destroyed[i]) << i;
+ {
+ int expect_data[3] = {1, 2, 4};
+ for (size_t i = 0; i < arraysize(expect_data); ++i)
+ EXPECT_EQ(expect_data[i], v[i]->data()) << i;
+ }
+
+ // Removing from the front of the vector.
+ auto is_one = [](DataWithDestruction* d) { return d->data() == 1; };
+ v.erase(v.remove_if(is_one), v.end());
+ EXPECT_EQ(2u, v.size());
+ expect_destroyed[0]++;
+ for (size_t i = 0; i < arraysize(destroyed); ++i)
+ EXPECT_EQ(expect_destroyed[i], destroyed[i]) << i;
+ {
+ int expect_data[2] = {2, 4};
+ for (size_t i = 0; i < arraysize(expect_data); ++i)
+ EXPECT_EQ(expect_data[i], v[i]->data()) << i;
+ }
+
+ // Removing things that aren't in the vector does nothing.
+ v.erase(v.remove_if(is_one), v.end());
+ EXPECT_EQ(2u, v.size());
+ for (size_t i = 0; i < arraysize(destroyed); ++i)
+ EXPECT_EQ(expect_destroyed[i], destroyed[i]) << i;
+ {
+ int expect_data[2] = {2, 4};
+ for (size_t i = 0; i < arraysize(expect_data); ++i)
+ EXPECT_EQ(expect_data[i], v[i]->data()) << i;
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/base/swap_promise.h b/chromium/cc/base/swap_promise.h
deleted file mode 100644
index a406fda6678..00000000000
--- a/chromium/cc/base/swap_promise.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_BASE_SWAP_PROMISE_H_
-#define CC_BASE_SWAP_PROMISE_H_
-
-#include "cc/output/compositor_frame_metadata.h"
-
-namespace cc {
-
-// 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
-// completed in the compositor, i.e. the compositor knows it has been sent
-// to its output or not.
-//
-// If the new compositor state is sent to the output, SwapPromise::DidSwap()
-// will be called, and if the compositor fails to send its new state to the
-// output, SwapPromise::DidNotSwap() will be called.
-//
-// Client wishes to use SwapPromise should have a subclass that defines
-// the behavior of DidSwap() and DidNotSwap(). Notice that the promise can
-// be broken at either main or impl thread, e.g. commit fails on main thread,
-// new frame data has no actual damage so LayerTreeHostImpl::SwapBuffers()
-// bails out early on impl thread, so don't assume that DidSwap() and
-// DidNotSwap() are called at a particular thread. It is better to let the
-// subclass carry thread-safe member data and operate on that member data in
-// DidSwap() and DidNotSwap().
-class CC_EXPORT SwapPromise {
- public:
- enum DidNotSwapReason {
- DID_NOT_SWAP_UNKNOWN,
- SWAP_FAILS,
- COMMIT_FAILS,
- COMMIT_NO_UPDATE,
- };
-
- SwapPromise() {}
- virtual ~SwapPromise() {}
-
- virtual void DidSwap(CompositorFrameMetadata* metadata) = 0;
- virtual void DidNotSwap(DidNotSwapReason reason) = 0;
-
- // A non-zero trace id identifies a trace flow object that is embedded in the
- // swap promise. This can be used for registering additional flow steps to
- // visualize the object's path through the system.
- virtual int64 TraceId() const = 0;
-};
-
-} // namespace cc
-
-#endif // CC_BASE_SWAP_PROMISE_H_
diff --git a/chromium/cc/base/switches.cc b/chromium/cc/base/switches.cc
index 27e63b50032..c30ab2fe7f0 100644
--- a/chromium/cc/base/switches.cc
+++ b/chromium/cc/base/switches.cc
@@ -24,12 +24,6 @@ const char kDisableMainFrameBeforeActivation[] =
const char kEnableMainFrameBeforeActivation[] =
"enable-main-frame-before-activation";
-const char kEnableTopControlsPositionCalculation[] =
- "enable-top-controls-position-calculation";
-
-// The height of the movable top controls.
-const char kTopControlsHeight[] = "top-controls-height";
-
// Percentage of the top controls need to be hidden before they will auto hide.
const char kTopControlsHideThreshold[] = "top-controls-hide-threshold";
@@ -41,9 +35,6 @@ const char kTopControlsShowThreshold[] = "top-controls-show-threshold";
// complete, such as --slow-down-raster-scale-factor=25.
const char kSlowDownRasterScaleFactor[] = "slow-down-raster-scale-factor";
-// Max tiles allowed for each tilings interest area.
-const char kMaxTilesForInterestArea[] = "max-tiles-for-interest-area";
-
// The amount of unused resource memory compositor is allowed to keep around.
const char kMaxUnusedResourceMemoryUsagePercentage[] =
"max-unused-resource-memory-usage-percentage";
@@ -61,6 +52,11 @@ const char kStrictLayerPropertyChangeChecking[] =
const char kEnablePinchVirtualViewport[] = "enable-pinch-virtual-viewport";
const char kDisablePinchVirtualViewport[] = "disable-pinch-virtual-viewport";
+// Ensures that the draw properties computed via the property trees match those
+// computed by CalcDrawProperties.
+const char kEnablePropertyTreeVerification[] =
+ "enable-property-tree-verification";
+
// Disable partial swap which is needed for some OpenGL drivers / emulators.
const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
@@ -102,16 +98,6 @@ const char kShowReplicaScreenSpaceRects[] = "show-replica-screenspace-rects";
const char kUIShowReplicaScreenSpaceRects[] =
"ui-show-replica-screenspace-rects";
-// Show rects in the HUD wherever something is known to be drawn opaque and is
-// considered occluding the pixels behind it.
-const char kShowOccludingRects[] = "show-occluding-rects";
-const char kUIShowOccludingRects[] = "ui-show-occluding-rects";
-
-// Show rects in the HUD wherever something is not known to be drawn opaque and
-// is not considered to be occluding the pixels behind it.
-const char kShowNonOccludingRects[] = "show-nonoccluding-rects";
-const char kUIShowNonOccludingRects[] = "ui-show-nonoccluding-rects";
-
// Prevents the layer tree unit tests from timing out.
const char kCCLayerTreeTestNoTimeout[] = "cc-layer-tree-test-no-timeout";
diff --git a/chromium/cc/base/switches.h b/chromium/cc/base/switches.h
index bbf680e3040..915d8e28de4 100644
--- a/chromium/cc/base/switches.h
+++ b/chromium/cc/base/switches.h
@@ -20,18 +20,16 @@ CC_EXPORT extern const char kDisableThreadedAnimation[];
CC_EXPORT extern const char kDisableCompositedAntialiasing[];
CC_EXPORT extern const char kDisableMainFrameBeforeActivation[];
CC_EXPORT extern const char kEnableMainFrameBeforeActivation[];
-CC_EXPORT extern const char kEnableTopControlsPositionCalculation[];
CC_EXPORT extern const char kJankInsteadOfCheckerboard[];
-CC_EXPORT extern const char kTopControlsHeight[];
CC_EXPORT extern const char kTopControlsHideThreshold[];
CC_EXPORT extern const char kTopControlsShowThreshold[];
CC_EXPORT extern const char kSlowDownRasterScaleFactor[];
CC_EXPORT extern const char kCompositeToMailbox[];
-CC_EXPORT extern const char kMaxTilesForInterestArea[];
CC_EXPORT extern const char kMaxUnusedResourceMemoryUsagePercentage[];
CC_EXPORT extern const char kEnablePinchVirtualViewport[];
CC_EXPORT extern const char kDisablePinchVirtualViewport[];
CC_EXPORT extern const char kStrictLayerPropertyChangeChecking[];
+CC_EXPORT extern const char kEnablePropertyTreeVerification[];
// Switches for both the renderer and ui compositors.
CC_EXPORT extern const char kUIDisablePartialSwap[];
@@ -52,10 +50,6 @@ CC_EXPORT extern const char kShowScreenSpaceRects[];
CC_EXPORT extern const char kUIShowScreenSpaceRects[];
CC_EXPORT extern const char kShowReplicaScreenSpaceRects[];
CC_EXPORT extern const char kUIShowReplicaScreenSpaceRects[];
-CC_EXPORT extern const char kShowOccludingRects[];
-CC_EXPORT extern const char kUIShowOccludingRects[];
-CC_EXPORT extern const char kShowNonOccludingRects[];
-CC_EXPORT extern const char kUIShowNonOccludingRects[];
// Unit test related.
CC_EXPORT extern const char kCCLayerTreeTestNoTimeout[];
diff --git a/chromium/cc/base/synced_property.h b/chromium/cc/base/synced_property.h
new file mode 100644
index 00000000000..6b02e7a651a
--- /dev/null
+++ b/chromium/cc/base/synced_property.h
@@ -0,0 +1,187 @@
+// Copyright 2014 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_BASE_SYNCED_PROPERTY_H_
+#define CC_BASE_SYNCED_PROPERTY_H_
+
+#include "base/memory/ref_counted.h"
+
+namespace cc {
+
+// This class is the basic primitive used for impl-thread scrolling. Its job is
+// to sanely resolve the case where both the main and impl thread are
+// concurrently updating the same value (for example, when Javascript sets the
+// scroll offset during an ongoing impl-side scroll).
+//
+// There are three trees (main, pending, and active) and therefore also three
+// places with their own idea of the scroll offsets (and analogous properties
+// like page scale). Objects of this class are meant to be held on the Impl
+// side, and contain the canonical reference for the pending and active trees,
+// as well as keeping track of the latest delta sent to the main thread (which
+// is necessary for conflict resolution).
+
+template <typename T>
+class SyncedProperty : public base::RefCounted<SyncedProperty<T>> {
+ public:
+ SyncedProperty() : clobber_active_value_(false) {}
+
+ // Returns the canonical value for the specified tree, including the sum of
+ // all deltas. The pending tree should use this for activation purposes and
+ // the active tree should use this for drawing.
+ typename T::ValueType Current(bool is_active_tree) const {
+ if (is_active_tree)
+ return active_base_.Combine(active_delta_).get();
+ else
+ return pending_base_.Combine(PendingDelta()).get();
+ }
+
+ // Sets the value on the impl thread, due to an impl-thread-originating
+ // action. Returns true if this had any effect. This will remain
+ // impl-thread-only information at first, and will get pulled back to the main
+ // thread on the next call of PullDeltaToMainThread (which happens right
+ // before the commit).
+ bool SetCurrent(typename T::ValueType current) {
+ T delta = T(current).InverseCombine(active_base_);
+ if (active_delta_.get() == delta.get())
+ return false;
+
+ active_delta_ = delta;
+ return true;
+ }
+
+ // Returns the difference between the last value that was committed and
+ // activated from the main thread, and the current total value.
+ typename T::ValueType Delta() const { return active_delta_.get(); }
+
+ // Returns the latest active tree delta and also makes a note that this value
+ // was sent to the main thread.
+ typename T::ValueType PullDeltaForMainThread() {
+ sent_delta_ = active_delta_;
+ return active_delta_.get();
+ }
+
+ // Push the latest value from the main thread onto pending tree-associated
+ // state. Returns true if this had any effect.
+ bool PushFromMainThread(typename T::ValueType main_thread_value) {
+ if (pending_base_.get() == main_thread_value)
+ return false;
+
+ pending_base_ = T(main_thread_value);
+
+ return true;
+ }
+
+ // Push the value associated with the pending tree to be the active base
+ // value. As part of this, subtract the last sent value from the active tree
+ // delta (which will make the delta zero at steady state, or make it contain
+ // only the difference since the last send).
+ bool PushPendingToActive() {
+ if (active_base_.get() == pending_base_.get() &&
+ sent_delta_.get() == T::Identity().get())
+ return false;
+
+ active_base_ = pending_base_;
+ active_delta_ = PendingDelta();
+ sent_delta_ = T::Identity();
+ clobber_active_value_ = false;
+
+ return true;
+ }
+
+ // This simulates the consequences of the sent value getting committed and
+ // activated. The value sent to the main thread ends up combined with the
+ // active value, and the sent_delta is subtracted from the delta.
+ void AbortCommit() {
+ active_base_ = active_base_.Combine(sent_delta_);
+ active_delta_ = PendingDelta();
+ sent_delta_ = T::Identity();
+ }
+
+ // Values as last pushed to the pending or active tree respectively, with no
+ // impl-thread delta applied.
+ typename T::ValueType PendingBase() const { return pending_base_.get(); }
+ typename T::ValueType ActiveBase() const { return active_base_.get(); }
+
+ // The new delta we would use if we decide to activate now. This delta
+ // excludes the amount that we expect the main thread to reflect back at the
+ // impl thread during the commit.
+ T PendingDelta() const {
+ if (clobber_active_value_)
+ return T::Identity();
+ return active_delta_.InverseCombine(sent_delta_);
+ }
+
+ void set_clobber_active_value() { clobber_active_value_ = true; }
+
+ private:
+ // Value last committed to the pending tree.
+ T pending_base_;
+ // Value last committed to the active tree (on the last activation).
+ T active_base_;
+ // The difference between the active_base_ and the user-perceived value.
+ T active_delta_;
+ // The value sent to the main thread (on the last BeginFrame); this is always
+ // identity outside of the BeginFrame-to-activation interval.
+ T sent_delta_;
+ // When true the pending delta is always identity so that it does not change
+ // and will clobber the active value on push.
+ bool clobber_active_value_;
+
+ friend class base::RefCounted<SyncedProperty<T>>;
+ ~SyncedProperty() {}
+};
+
+// SyncedProperty's delta-based conflict resolution logic makes sense for any
+// mathematical group. In practice, there are two that are useful:
+// 1. Numbers/vectors with addition and identity = 0 (like scroll offsets)
+// 2. Real numbers with multiplication and identity = 1 (like page scale)
+
+template <class V>
+class AdditionGroup {
+ public:
+ typedef V ValueType;
+
+ AdditionGroup() : value_(Identity().get()) {}
+ explicit AdditionGroup(V value) : value_(value) {}
+
+ V& get() { return value_; }
+ const V& get() const { return value_; }
+
+ static AdditionGroup<V> Identity() { return AdditionGroup(V()); } // zero
+ AdditionGroup<V> Combine(AdditionGroup<V> p) const {
+ return AdditionGroup<V>(value_ + p.value_);
+ }
+ AdditionGroup<V> InverseCombine(AdditionGroup<V> p) const {
+ return AdditionGroup<V>(value_ - p.value_);
+ }
+
+ private:
+ V value_;
+};
+
+class ScaleGroup {
+ public:
+ typedef float ValueType;
+
+ ScaleGroup() : value_(Identity().get()) {}
+ explicit ScaleGroup(float value) : value_(value) {}
+
+ float& get() { return value_; }
+ const float& get() const { return value_; }
+
+ static ScaleGroup Identity() { return ScaleGroup(1.f); }
+ ScaleGroup Combine(ScaleGroup p) const {
+ return ScaleGroup(value_ * p.value_);
+ }
+ ScaleGroup InverseCombine(ScaleGroup p) const {
+ return ScaleGroup(value_ / p.value_);
+ }
+
+ private:
+ float value_;
+};
+
+} // namespace cc
+
+#endif // CC_BASE_SYNCED_PROPERTY_H_
diff --git a/chromium/cc/base/tiling_data.cc b/chromium/cc/base/tiling_data.cc
index 7b39878b31f..cf2bb57f64c 100644
--- a/chromium/cc/base/tiling_data.cc
+++ b/chromium/cc/base/tiling_data.cc
@@ -293,40 +293,39 @@ void TilingData::RecomputeNumTiles() {
max_texture_size_.height(), tiling_size_.height(), border_texels_);
}
-TilingData::BaseIterator::BaseIterator(const TilingData* tiling_data)
- : tiling_data_(tiling_data),
- index_x_(-1),
- index_y_(-1) {
+TilingData::BaseIterator::BaseIterator() : index_x_(-1), index_y_(-1) {
}
-TilingData::Iterator::Iterator() : BaseIterator(nullptr) { done(); }
+TilingData::Iterator::Iterator() {
+ done();
+}
TilingData::Iterator::Iterator(const TilingData* tiling_data,
const gfx::Rect& consider_rect,
bool include_borders)
- : BaseIterator(tiling_data), left_(-1), right_(-1), bottom_(-1) {
- if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
+ : left_(-1), right_(-1), bottom_(-1) {
+ if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) {
done();
return;
}
- gfx::Rect tiling_bounds_rect(tiling_data_->tiling_size());
+ gfx::Rect tiling_bounds_rect(tiling_data->tiling_size());
gfx::Rect rect(consider_rect);
rect.Intersect(tiling_bounds_rect);
gfx::Rect top_left_tile;
if (include_borders) {
- index_x_ = tiling_data_->FirstBorderTileXIndexFromSrcCoord(rect.x());
- index_y_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(rect.y());
- right_ = tiling_data_->LastBorderTileXIndexFromSrcCoord(rect.right() - 1);
- bottom_ = tiling_data_->LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1);
- top_left_tile = tiling_data_->TileBoundsWithBorder(index_x_, index_y_);
+ index_x_ = tiling_data->FirstBorderTileXIndexFromSrcCoord(rect.x());
+ index_y_ = tiling_data->FirstBorderTileYIndexFromSrcCoord(rect.y());
+ right_ = tiling_data->LastBorderTileXIndexFromSrcCoord(rect.right() - 1);
+ bottom_ = tiling_data->LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1);
+ top_left_tile = tiling_data->TileBoundsWithBorder(index_x_, index_y_);
} else {
- index_x_ = tiling_data_->TileXIndexFromSrcCoord(rect.x());
- index_y_ = tiling_data_->TileYIndexFromSrcCoord(rect.y());
- right_ = tiling_data_->TileXIndexFromSrcCoord(rect.right() - 1);
- bottom_ = tiling_data_->TileYIndexFromSrcCoord(rect.bottom() - 1);
- top_left_tile = tiling_data_->TileBounds(index_x_, index_y_);
+ index_x_ = tiling_data->TileXIndexFromSrcCoord(rect.x());
+ index_y_ = tiling_data->TileYIndexFromSrcCoord(rect.y());
+ right_ = tiling_data->TileXIndexFromSrcCoord(rect.right() - 1);
+ bottom_ = tiling_data->TileYIndexFromSrcCoord(rect.bottom() - 1);
+ top_left_tile = tiling_data->TileBounds(index_x_, index_y_);
}
left_ = index_x_;
@@ -351,12 +350,15 @@ TilingData::Iterator& TilingData::Iterator::operator++() {
return *this;
}
-TilingData::DifferenceIterator::DifferenceIterator(
+TilingData::BaseDifferenceIterator::BaseDifferenceIterator() {
+ done();
+}
+
+TilingData::BaseDifferenceIterator::BaseDifferenceIterator(
const TilingData* tiling_data,
const gfx::Rect& consider_rect,
const gfx::Rect& ignore_rect)
- : BaseIterator(tiling_data),
- consider_left_(-1),
+ : consider_left_(-1),
consider_top_(-1),
consider_right_(-1),
consider_bottom_(-1),
@@ -364,42 +366,67 @@ TilingData::DifferenceIterator::DifferenceIterator(
ignore_top_(-1),
ignore_right_(-1),
ignore_bottom_(-1) {
- if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
+ if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) {
done();
return;
}
- gfx::Rect tiling_bounds_rect(tiling_data_->tiling_size());
+ gfx::Rect tiling_bounds_rect(tiling_data->tiling_size());
gfx::Rect consider(consider_rect);
- gfx::Rect ignore(ignore_rect);
consider.Intersect(tiling_bounds_rect);
- ignore.Intersect(tiling_bounds_rect);
+
if (consider.IsEmpty()) {
done();
return;
}
- consider_left_ = tiling_data_->TileXIndexFromSrcCoord(consider.x());
- consider_top_ = tiling_data_->TileYIndexFromSrcCoord(consider.y());
- consider_right_ = tiling_data_->TileXIndexFromSrcCoord(consider.right() - 1);
- consider_bottom_ =
- tiling_data_->TileYIndexFromSrcCoord(consider.bottom() - 1);
+ consider_left_ = tiling_data->TileXIndexFromSrcCoord(consider.x());
+ consider_top_ = tiling_data->TileYIndexFromSrcCoord(consider.y());
+ consider_right_ = tiling_data->TileXIndexFromSrcCoord(consider.right() - 1);
+ consider_bottom_ = tiling_data->TileYIndexFromSrcCoord(consider.bottom() - 1);
+
+ gfx::Rect ignore(ignore_rect);
+ ignore.Intersect(tiling_bounds_rect);
if (!ignore.IsEmpty()) {
- ignore_left_ = tiling_data_->TileXIndexFromSrcCoord(ignore.x());
- ignore_top_ = tiling_data_->TileYIndexFromSrcCoord(ignore.y());
- ignore_right_ = tiling_data_->TileXIndexFromSrcCoord(ignore.right() - 1);
- ignore_bottom_ = tiling_data_->TileYIndexFromSrcCoord(ignore.bottom() - 1);
+ ignore_left_ = tiling_data->TileXIndexFromSrcCoord(ignore.x());
+ ignore_top_ = tiling_data->TileYIndexFromSrcCoord(ignore.y());
+ ignore_right_ = tiling_data->TileXIndexFromSrcCoord(ignore.right() - 1);
+ ignore_bottom_ = tiling_data->TileYIndexFromSrcCoord(ignore.bottom() - 1);
// Clamp ignore indices to consider indices.
ignore_left_ = std::max(ignore_left_, consider_left_);
ignore_top_ = std::max(ignore_top_, consider_top_);
ignore_right_ = std::min(ignore_right_, consider_right_);
ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_);
+
+ if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
+ ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+ consider_left_ = consider_top_ = consider_right_ = consider_bottom_ = -1;
+ done();
+ return;
+ }
}
+}
- if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
- ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+bool TilingData::BaseDifferenceIterator::HasConsiderRect() const {
+ // Consider indices are either all valid or all equal to -1.
+ DCHECK((0 <= consider_left_ && consider_left_ <= consider_right_ &&
+ 0 <= consider_top_ && consider_top_ <= consider_bottom_) ||
+ (consider_left_ == -1 && consider_top_ == -1 &&
+ consider_right_ == -1 && consider_bottom_ == -1));
+ return consider_left_ != -1;
+}
+
+TilingData::DifferenceIterator::DifferenceIterator() {
+}
+
+TilingData::DifferenceIterator::DifferenceIterator(
+ const TilingData* tiling_data,
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect)
+ : BaseDifferenceIterator(tiling_data, consider_rect, ignore_rect) {
+ if (!HasConsiderRect()) {
done();
return;
}
@@ -440,8 +467,7 @@ TilingData::DifferenceIterator& TilingData::DifferenceIterator::operator++() {
return *this;
}
-TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator()
- : BaseIterator(nullptr) {
+TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator() {
done();
}
@@ -450,84 +476,40 @@ TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator(
const gfx::Rect& consider_rect,
const gfx::Rect& ignore_rect,
const gfx::Rect& center_rect)
- : BaseIterator(tiling_data),
- consider_left_(-1),
- consider_top_(-1),
- consider_right_(-1),
- consider_bottom_(-1),
- ignore_left_(-1),
- ignore_top_(-1),
- ignore_right_(-1),
- ignore_bottom_(-1),
+ : BaseDifferenceIterator(tiling_data, consider_rect, ignore_rect),
direction_(RIGHT),
delta_x_(1),
delta_y_(0),
current_step_(0),
horizontal_step_count_(0),
vertical_step_count_(0) {
- if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
- done();
- return;
- }
-
- gfx::Rect tiling_bounds_rect(tiling_data_->tiling_size());
- gfx::Rect consider(consider_rect);
- gfx::Rect ignore(ignore_rect);
- gfx::Rect center(center_rect);
- consider.Intersect(tiling_bounds_rect);
- ignore.Intersect(tiling_bounds_rect);
- if (consider.IsEmpty()) {
- done();
- return;
- }
-
- consider_left_ = tiling_data_->TileXIndexFromSrcCoord(consider.x());
- consider_top_ = tiling_data_->TileYIndexFromSrcCoord(consider.y());
- consider_right_ = tiling_data_->TileXIndexFromSrcCoord(consider.right() - 1);
- consider_bottom_ =
- tiling_data_->TileYIndexFromSrcCoord(consider.bottom() - 1);
-
- if (!ignore.IsEmpty()) {
- ignore_left_ = tiling_data_->TileXIndexFromSrcCoord(ignore.x());
- ignore_top_ = tiling_data_->TileYIndexFromSrcCoord(ignore.y());
- ignore_right_ = tiling_data_->TileXIndexFromSrcCoord(ignore.right() - 1);
- ignore_bottom_ = tiling_data_->TileYIndexFromSrcCoord(ignore.bottom() - 1);
-
- // Clamp ignore indices to consider indices.
- ignore_left_ = std::max(ignore_left_, consider_left_);
- ignore_top_ = std::max(ignore_top_, consider_top_);
- ignore_right_ = std::min(ignore_right_, consider_right_);
- ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_);
- }
-
- if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
- ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+ if (!HasConsiderRect()) {
done();
return;
}
// Determine around left, such that it is between -1 and num_tiles_x.
int around_left = 0;
- if (center.x() < 0 || center.IsEmpty())
+ if (center_rect.x() < 0 || center_rect.IsEmpty())
around_left = -1;
- else if (center.x() >= tiling_data->tiling_size().width())
+ else if (center_rect.x() >= tiling_data->tiling_size().width())
around_left = tiling_data->num_tiles_x();
else
- around_left = tiling_data->TileXIndexFromSrcCoord(center.x());
+ around_left = tiling_data->TileXIndexFromSrcCoord(center_rect.x());
// Determine around top, such that it is between -1 and num_tiles_y.
int around_top = 0;
- if (center.y() < 0 || center.IsEmpty())
+ if (center_rect.y() < 0 || center_rect.IsEmpty())
around_top = -1;
- else if (center.y() >= tiling_data->tiling_size().height())
+ else if (center_rect.y() >= tiling_data->tiling_size().height())
around_top = tiling_data->num_tiles_y();
else
- around_top = tiling_data->TileYIndexFromSrcCoord(center.y());
+ around_top = tiling_data->TileYIndexFromSrcCoord(center_rect.y());
// Determine around right, such that it is between -1 and num_tiles_x.
- int right_src_coord = center.right() - 1;
+ int right_src_coord = center_rect.right() - 1;
int around_right = 0;
- if (right_src_coord < 0 || center.IsEmpty()) {
+ if (right_src_coord < 0 || center_rect.IsEmpty()) {
around_right = -1;
} else if (right_src_coord >= tiling_data->tiling_size().width()) {
around_right = tiling_data->num_tiles_x();
@@ -536,9 +518,9 @@ TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator(
}
// Determine around bottom, such that it is between -1 and num_tiles_y.
- int bottom_src_coord = center.bottom() - 1;
+ int bottom_src_coord = center_rect.bottom() - 1;
int around_bottom = 0;
- if (bottom_src_coord < 0 || center.IsEmpty()) {
+ if (bottom_src_coord < 0 || center_rect.IsEmpty()) {
around_bottom = -1;
} else if (bottom_src_coord >= tiling_data->tiling_size().height()) {
around_bottom = tiling_data->num_tiles_y();
@@ -666,8 +648,7 @@ void TilingData::SpiralDifferenceIterator::switch_direction() {
}
}
-TilingData::ReverseSpiralDifferenceIterator::ReverseSpiralDifferenceIterator()
- : BaseIterator(nullptr) {
+TilingData::ReverseSpiralDifferenceIterator::ReverseSpiralDifferenceIterator() {
done();
}
@@ -676,85 +657,41 @@ TilingData::ReverseSpiralDifferenceIterator::ReverseSpiralDifferenceIterator(
const gfx::Rect& consider_rect,
const gfx::Rect& ignore_rect,
const gfx::Rect& center_rect)
- : BaseIterator(tiling_data),
- consider_left_(-1),
- consider_top_(-1),
- consider_right_(-1),
- consider_bottom_(-1),
+ : BaseDifferenceIterator(tiling_data, consider_rect, ignore_rect),
around_left_(-1),
around_top_(-1),
around_right_(-1),
around_bottom_(-1),
- ignore_left_(-1),
- ignore_top_(-1),
- ignore_right_(-1),
- ignore_bottom_(-1),
direction_(LEFT),
delta_x_(-1),
delta_y_(0),
current_step_(0),
horizontal_step_count_(0),
vertical_step_count_(0) {
- if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
- done();
- return;
- }
-
- gfx::Rect tiling_bounds_rect(tiling_data_->tiling_size());
- gfx::Rect consider(consider_rect);
- gfx::Rect ignore(ignore_rect);
- gfx::Rect center(center_rect);
- consider.Intersect(tiling_bounds_rect);
- ignore.Intersect(tiling_bounds_rect);
- if (consider.IsEmpty()) {
- done();
- return;
- }
-
- consider_left_ = tiling_data_->TileXIndexFromSrcCoord(consider.x());
- consider_top_ = tiling_data_->TileYIndexFromSrcCoord(consider.y());
- consider_right_ = tiling_data_->TileXIndexFromSrcCoord(consider.right() - 1);
- consider_bottom_ =
- tiling_data_->TileYIndexFromSrcCoord(consider.bottom() - 1);
-
- if (!ignore.IsEmpty()) {
- ignore_left_ = tiling_data_->TileXIndexFromSrcCoord(ignore.x());
- ignore_top_ = tiling_data_->TileYIndexFromSrcCoord(ignore.y());
- ignore_right_ = tiling_data_->TileXIndexFromSrcCoord(ignore.right() - 1);
- ignore_bottom_ = tiling_data_->TileYIndexFromSrcCoord(ignore.bottom() - 1);
-
- // Clamp ignore indices to consider indices.
- ignore_left_ = std::max(ignore_left_, consider_left_);
- ignore_top_ = std::max(ignore_top_, consider_top_);
- ignore_right_ = std::min(ignore_right_, consider_right_);
- ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_);
- }
-
- if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
- ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+ if (!HasConsiderRect()) {
done();
return;
}
// Determine around left, such that it is between -1 and num_tiles_x.
- if (center.x() < 0 || center.IsEmpty())
+ if (center_rect.x() < 0 || center_rect.IsEmpty())
around_left_ = -1;
- else if (center.x() >= tiling_data->tiling_size().width())
+ else if (center_rect.x() >= tiling_data->tiling_size().width())
around_left_ = tiling_data->num_tiles_x();
else
- around_left_ = tiling_data->TileXIndexFromSrcCoord(center.x());
+ around_left_ = tiling_data->TileXIndexFromSrcCoord(center_rect.x());
// Determine around top, such that it is between -1 and num_tiles_y.
- if (center.y() < 0 || center.IsEmpty())
+ if (center_rect.y() < 0 || center_rect.IsEmpty())
around_top_ = -1;
- else if (center.y() >= tiling_data->tiling_size().height())
+ else if (center_rect.y() >= tiling_data->tiling_size().height())
around_top_ = tiling_data->num_tiles_y();
else
- around_top_ = tiling_data->TileYIndexFromSrcCoord(center.y());
+ around_top_ = tiling_data->TileYIndexFromSrcCoord(center_rect.y());
// Determine around right, such that it is between -1 and num_tiles_x.
- int right_src_coord = center.right() - 1;
- if (right_src_coord < 0 || center.IsEmpty()) {
+ int right_src_coord = center_rect.right() - 1;
+ if (right_src_coord < 0 || center_rect.IsEmpty()) {
around_right_ = -1;
} else if (right_src_coord >= tiling_data->tiling_size().width()) {
around_right_ = tiling_data->num_tiles_x();
@@ -763,8 +700,8 @@ TilingData::ReverseSpiralDifferenceIterator::ReverseSpiralDifferenceIterator(
}
// Determine around bottom, such that it is between -1 and num_tiles_y.
- int bottom_src_coord = center.bottom() - 1;
- if (bottom_src_coord < 0 || center.IsEmpty()) {
+ int bottom_src_coord = center_rect.bottom() - 1;
+ if (bottom_src_coord < 0 || center_rect.IsEmpty()) {
around_bottom_ = -1;
} else if (bottom_src_coord >= tiling_data->tiling_size().height()) {
around_bottom_ = tiling_data->num_tiles_y();
diff --git a/chromium/cc/base/tiling_data.h b/chromium/cc/base/tiling_data.h
index 5e8a4d60da1..c95a6725b48 100644
--- a/chromium/cc/base/tiling_data.h
+++ b/chromium/cc/base/tiling_data.h
@@ -76,13 +76,12 @@ class CC_EXPORT TilingData {
}
protected:
- explicit BaseIterator(const TilingData* tiling_data);
+ BaseIterator();
void done() {
index_x_ = -1;
index_y_ = -1;
}
- const TilingData* tiling_data_;
int index_x_;
int index_y_;
};
@@ -102,19 +101,21 @@ class CC_EXPORT TilingData {
int bottom_;
};
- // Iterate through all indices whose bounds (not including borders) intersect
- // with |consider| but which also do not intersect with |ignore|.
- class CC_EXPORT DifferenceIterator : public BaseIterator {
- public:
- DifferenceIterator(const TilingData* tiling_data,
- const gfx::Rect& consider_rect,
- const gfx::Rect& ignore_rect);
- DifferenceIterator& operator++();
+ class CC_EXPORT BaseDifferenceIterator : public BaseIterator {
+ protected:
+ BaseDifferenceIterator();
+ BaseDifferenceIterator(const TilingData* tiling_data,
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect);
- private:
+ bool HasConsiderRect() const;
+ bool in_consider_rect() const {
+ return index_x_ >= consider_left_ && index_x_ <= consider_right_ &&
+ index_y_ >= consider_top_ && index_y_ <= consider_bottom_;
+ }
bool in_ignore_rect() const {
- return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
- index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
+ return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
+ index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
}
int consider_left_;
@@ -127,10 +128,21 @@ class CC_EXPORT TilingData {
int ignore_bottom_;
};
+ // Iterate through all indices whose bounds (not including borders) intersect
+ // with |consider| but which also do not intersect with |ignore|.
+ class CC_EXPORT DifferenceIterator : public BaseDifferenceIterator {
+ public:
+ DifferenceIterator();
+ DifferenceIterator(const TilingData* tiling_data,
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect);
+ DifferenceIterator& operator++();
+ };
+
// Iterate through all indices whose bounds + border intersect with
// |consider| but which also do not intersect with |ignore|. The iterator
// order is a counterclockwise spiral around the given center.
- class CC_EXPORT SpiralDifferenceIterator : public BaseIterator {
+ class CC_EXPORT SpiralDifferenceIterator : public BaseDifferenceIterator {
public:
SpiralDifferenceIterator();
SpiralDifferenceIterator(const TilingData* tiling_data,
@@ -140,14 +152,6 @@ class CC_EXPORT TilingData {
SpiralDifferenceIterator& operator++();
private:
- bool in_consider_rect() const {
- return index_x_ >= consider_left_ && index_x_ <= consider_right_ &&
- index_y_ >= consider_top_ && index_y_ <= consider_bottom_;
- }
- bool in_ignore_rect() const {
- return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
- index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
- }
bool valid_column() const {
return index_x_ >= consider_left_ && index_x_ <= consider_right_;
}
@@ -163,15 +167,6 @@ class CC_EXPORT TilingData {
bool needs_direction_switch() const;
void switch_direction();
- int consider_left_;
- int consider_top_;
- int consider_right_;
- int consider_bottom_;
- int ignore_left_;
- int ignore_top_;
- int ignore_right_;
- int ignore_bottom_;
-
enum Direction { UP, LEFT, DOWN, RIGHT };
Direction direction_;
@@ -182,7 +177,8 @@ class CC_EXPORT TilingData {
int vertical_step_count_;
};
- class CC_EXPORT ReverseSpiralDifferenceIterator : public BaseIterator {
+ class CC_EXPORT ReverseSpiralDifferenceIterator
+ : public BaseDifferenceIterator {
public:
ReverseSpiralDifferenceIterator();
ReverseSpiralDifferenceIterator(const TilingData* tiling_data,
@@ -192,18 +188,10 @@ class CC_EXPORT TilingData {
ReverseSpiralDifferenceIterator& operator++();
private:
- bool in_consider_rect() const {
- return index_x_ >= consider_left_ && index_x_ <= consider_right_ &&
- index_y_ >= consider_top_ && index_y_ <= consider_bottom_;
- }
bool in_around_rect() const {
return index_x_ >= around_left_ && index_x_ <= around_right_ &&
index_y_ >= around_top_ && index_y_ <= around_bottom_;
}
- bool in_ignore_rect() const {
- return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
- index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
- }
bool valid_column() const {
return index_x_ >= consider_left_ && index_x_ <= consider_right_;
}
@@ -219,18 +207,10 @@ class CC_EXPORT TilingData {
bool needs_direction_switch() const;
void switch_direction();
- int consider_left_;
- int consider_top_;
- int consider_right_;
- int consider_bottom_;
int around_left_;
int around_top_;
int around_right_;
int around_bottom_;
- int ignore_left_;
- int ignore_top_;
- int ignore_right_;
- int ignore_bottom_;
enum Direction { LEFT, UP, RIGHT, DOWN };
diff --git a/chromium/cc/base/tiling_data_unittest.cc b/chromium/cc/base/tiling_data_unittest.cc
index 667719b3b1f..732b04db056 100644
--- a/chromium/cc/base/tiling_data_unittest.cc
+++ b/chromium/cc/base/tiling_data_unittest.cc
@@ -775,26 +775,23 @@ TEST(TilingDataTest, SetMaxTextureSizeBorders) {
TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBoundsEmpty) {
TilingData empty_total_size(gfx::Size(0, 0), gfx::Size(8, 8), true);
- EXPECT_RECT_EQ(
- gfx::Rect(),
- empty_total_size.ExpandRectIgnoringBordersToTileBounds(gfx::Rect()));
- EXPECT_RECT_EQ(gfx::Rect(),
- empty_total_size.ExpandRectIgnoringBordersToTileBounds(
- gfx::Rect(100, 100, 100, 100)));
- EXPECT_RECT_EQ(gfx::Rect(),
- empty_total_size.ExpandRectIgnoringBordersToTileBounds(
- gfx::Rect(100, 100)));
+ EXPECT_EQ(gfx::Rect(), empty_total_size.ExpandRectIgnoringBordersToTileBounds(
+ gfx::Rect()));
+ EXPECT_EQ(gfx::Rect(), empty_total_size.ExpandRectIgnoringBordersToTileBounds(
+ gfx::Rect(100, 100, 100, 100)));
+ EXPECT_EQ(gfx::Rect(), empty_total_size.ExpandRectIgnoringBordersToTileBounds(
+ gfx::Rect(100, 100)));
TilingData empty_max_texture_size(gfx::Size(8, 8), gfx::Size(0, 0), true);
- EXPECT_RECT_EQ(gfx::Rect(),
- empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
- gfx::Rect()));
- EXPECT_RECT_EQ(gfx::Rect(),
- empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
- gfx::Rect(100, 100, 100, 100)));
- EXPECT_RECT_EQ(gfx::Rect(),
- empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
- gfx::Rect(100, 100)));
+ EXPECT_EQ(gfx::Rect(),
+ empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
+ gfx::Rect()));
+ EXPECT_EQ(gfx::Rect(),
+ empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
+ gfx::Rect(100, 100, 100, 100)));
+ EXPECT_EQ(gfx::Rect(),
+ empty_max_texture_size.ExpandRectIgnoringBordersToTileBounds(
+ gfx::Rect(100, 100)));
}
TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBounds) {
@@ -804,8 +801,8 @@ TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBounds) {
gfx::Rect at_origin_src(1, 1);
gfx::Rect at_origin_result(data.TileBounds(0, 0));
EXPECT_NE(at_origin_src, at_origin_result);
- EXPECT_RECT_EQ(at_origin_result,
- data.ExpandRectIgnoringBordersToTileBounds(at_origin_src));
+ EXPECT_EQ(at_origin_result,
+ data.ExpandRectIgnoringBordersToTileBounds(at_origin_src));
// Arbitrary internal rect.
gfx::Rect rect_src(6, 6, 1, 3);
@@ -814,32 +811,30 @@ TEST(TilingDataTest, ExpandRectIgnoringBordersToTileBounds) {
gfx::Rect rect_result(
gfx::UnionRects(data.TileBounds(2, 2), data.TileBounds(2, 3)));
EXPECT_NE(rect_src, rect_result);
- EXPECT_RECT_EQ(rect_result,
- data.ExpandRectIgnoringBordersToTileBounds(rect_src));
+ EXPECT_EQ(rect_result, data.ExpandRectIgnoringBordersToTileBounds(rect_src));
// On tile bounds does not round up to next tile (ignores the border).
gfx::Rect border_rect_src(
gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
gfx::Rect border_rect_result(
gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
- EXPECT_RECT_EQ(border_rect_result,
- data.ExpandRectIgnoringBordersToTileBounds(border_rect_src));
+ EXPECT_EQ(border_rect_result,
+ data.ExpandRectIgnoringBordersToTileBounds(border_rect_src));
// Equal to tiling rect.
- EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()),
- data.ExpandRectIgnoringBordersToTileBounds(
- gfx::Rect(data.tiling_size())));
+ EXPECT_EQ(gfx::Rect(data.tiling_size()),
+ data.ExpandRectIgnoringBordersToTileBounds(
+ gfx::Rect(data.tiling_size())));
// Containing, but larger than tiling rect.
- EXPECT_RECT_EQ(
- gfx::Rect(data.tiling_size()),
- data.ExpandRectIgnoringBordersToTileBounds(gfx::Rect(100, 100)));
+ EXPECT_EQ(gfx::Rect(data.tiling_size()),
+ data.ExpandRectIgnoringBordersToTileBounds(gfx::Rect(100, 100)));
// Non-intersecting with tiling rect.
gfx::Rect non_intersect(200, 200, 100, 100);
EXPECT_FALSE(non_intersect.Intersects(gfx::Rect(data.tiling_size())));
- EXPECT_RECT_EQ(gfx::Rect(),
- data.ExpandRectIgnoringBordersToTileBounds(non_intersect));
+ EXPECT_EQ(gfx::Rect(),
+ data.ExpandRectIgnoringBordersToTileBounds(non_intersect));
TilingData data2(gfx::Size(8, 8), gfx::Size(32, 64), true);
@@ -859,7 +854,7 @@ TEST(TilingDataTest, ExpandRectToTileBounds) {
gfx::Rect at_origin_src(1, 1);
gfx::Rect at_origin_result(data.TileBounds(0, 0));
EXPECT_NE(at_origin_src, at_origin_result);
- EXPECT_RECT_EQ(at_origin_result, data.ExpandRectToTileBounds(at_origin_src));
+ EXPECT_EQ(at_origin_result, data.ExpandRectToTileBounds(at_origin_src));
// Arbitrary internal rect.
gfx::Rect rect_src(6, 6, 1, 3);
@@ -868,28 +863,27 @@ TEST(TilingDataTest, ExpandRectToTileBounds) {
gfx::Rect rect_result(
gfx::UnionRects(data.TileBounds(2, 2), data.TileBounds(3, 4)));
EXPECT_NE(rect_src, rect_result);
- EXPECT_RECT_EQ(rect_result, data.ExpandRectToTileBounds(rect_src));
+ EXPECT_EQ(rect_result, data.ExpandRectToTileBounds(rect_src));
// On tile bounds rounds up to next tile (since border overlaps).
gfx::Rect border_rect_src(
gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
gfx::Rect border_rect_result(
gfx::UnionRects(data.TileBounds(0, 1), data.TileBounds(4, 5)));
- EXPECT_RECT_EQ(border_rect_result,
- data.ExpandRectToTileBounds(border_rect_src));
+ EXPECT_EQ(border_rect_result, data.ExpandRectToTileBounds(border_rect_src));
// Equal to tiling rect.
- EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()),
- data.ExpandRectToTileBounds(gfx::Rect(data.tiling_size())));
+ EXPECT_EQ(gfx::Rect(data.tiling_size()),
+ data.ExpandRectToTileBounds(gfx::Rect(data.tiling_size())));
// Containing, but larger than tiling rect.
- EXPECT_RECT_EQ(gfx::Rect(data.tiling_size()),
- data.ExpandRectToTileBounds(gfx::Rect(100, 100)));
+ EXPECT_EQ(gfx::Rect(data.tiling_size()),
+ data.ExpandRectToTileBounds(gfx::Rect(100, 100)));
// Non-intersecting with tiling rect.
gfx::Rect non_intersect(200, 200, 100, 100);
EXPECT_FALSE(non_intersect.Intersects(gfx::Rect(data.tiling_size())));
- EXPECT_RECT_EQ(gfx::Rect(), data.ExpandRectToTileBounds(non_intersect));
+ EXPECT_EQ(gfx::Rect(), data.ExpandRectToTileBounds(non_intersect));
TilingData data2(gfx::Size(8, 8), gfx::Size(32, 64), true);
@@ -953,17 +947,17 @@ TEST(TilingDataTest, LargeBorders) {
EXPECT_EQ(35, data.TileSizeY(4));
EXPECT_EQ(5, data.num_tiles_y());
- EXPECT_RECT_EQ(gfx::Rect(70, 50), data.TileBounds(0, 0));
- EXPECT_RECT_EQ(gfx::Rect(70, 50, 40, 20), data.TileBounds(1, 1));
- EXPECT_RECT_EQ(gfx::Rect(110, 110, 40, 35), data.TileBounds(2, 4));
- EXPECT_RECT_EQ(gfx::Rect(150, 70, 50, 20), data.TileBounds(3, 2));
- EXPECT_RECT_EQ(gfx::Rect(150, 110, 50, 35), data.TileBounds(3, 4));
-
- EXPECT_RECT_EQ(gfx::Rect(100, 80), data.TileBoundsWithBorder(0, 0));
- EXPECT_RECT_EQ(gfx::Rect(40, 20, 100, 80), data.TileBoundsWithBorder(1, 1));
- EXPECT_RECT_EQ(gfx::Rect(80, 80, 100, 65), data.TileBoundsWithBorder(2, 4));
- EXPECT_RECT_EQ(gfx::Rect(120, 40, 80, 80), data.TileBoundsWithBorder(3, 2));
- EXPECT_RECT_EQ(gfx::Rect(120, 80, 80, 65), data.TileBoundsWithBorder(3, 4));
+ EXPECT_EQ(gfx::Rect(70, 50), data.TileBounds(0, 0));
+ EXPECT_EQ(gfx::Rect(70, 50, 40, 20), data.TileBounds(1, 1));
+ EXPECT_EQ(gfx::Rect(110, 110, 40, 35), data.TileBounds(2, 4));
+ EXPECT_EQ(gfx::Rect(150, 70, 50, 20), data.TileBounds(3, 2));
+ EXPECT_EQ(gfx::Rect(150, 110, 50, 35), data.TileBounds(3, 4));
+
+ EXPECT_EQ(gfx::Rect(100, 80), data.TileBoundsWithBorder(0, 0));
+ EXPECT_EQ(gfx::Rect(40, 20, 100, 80), data.TileBoundsWithBorder(1, 1));
+ EXPECT_EQ(gfx::Rect(80, 80, 100, 65), data.TileBoundsWithBorder(2, 4));
+ EXPECT_EQ(gfx::Rect(120, 40, 80, 80), data.TileBoundsWithBorder(3, 2));
+ EXPECT_EQ(gfx::Rect(120, 80, 80, 65), data.TileBoundsWithBorder(3, 4));
EXPECT_EQ(0, data.TileXIndexFromSrcCoord(0));
EXPECT_EQ(0, data.TileXIndexFromSrcCoord(69));
diff --git a/chromium/cc/base/time_util.h b/chromium/cc/base/time_util.h
new file mode 100644
index 00000000000..06682c27e2f
--- /dev/null
+++ b/chromium/cc/base/time_util.h
@@ -0,0 +1,35 @@
+// Copyright 2014 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_BASE_TIME_UTIL_H_
+#define CC_BASE_TIME_UTIL_H_
+
+namespace base {
+class TimeDelta;
+}
+
+namespace cc {
+
+class CC_EXPORT TimeUtil {
+ public:
+ static base::TimeDelta Scale(base::TimeDelta time_delta, double value) {
+ return base::TimeDelta::FromInternalValue(static_cast<int64>(
+ static_cast<double>(time_delta.ToInternalValue()) * value));
+ }
+
+ static double Divide(base::TimeDelta dividend, base::TimeDelta divisor) {
+ return static_cast<double>(dividend.ToInternalValue()) /
+ static_cast<double>(divisor.ToInternalValue());
+ }
+
+ static base::TimeDelta Mod(base::TimeDelta dividend,
+ base::TimeDelta divisor) {
+ return base::TimeDelta::FromInternalValue(dividend.ToInternalValue() %
+ divisor.ToInternalValue());
+ }
+};
+
+} // namespace cc
+
+#endif // CC_BASE_TIME_UTIL_H_
diff --git a/chromium/cc/base/unique_notifier_unittest.cc b/chromium/cc/base/unique_notifier_unittest.cc
index 0ba9892348f..7b52512d6c7 100644
--- a/chromium/cc/base/unique_notifier_unittest.cc
+++ b/chromium/cc/base/unique_notifier_unittest.cc
@@ -4,9 +4,9 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/base/unique_notifier.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -17,7 +17,7 @@ class UniqueNotifierTest : public testing::Test {
public:
UniqueNotifierTest() : notification_count_(0) {}
- virtual void SetUp() override { ResetNotificationCount(); }
+ void SetUp() override { ResetNotificationCount(); }
void Notify() { ++notification_count_; }
@@ -32,7 +32,7 @@ class UniqueNotifierTest : public testing::Test {
TEST_F(UniqueNotifierTest, Schedule) {
{
UniqueNotifier notifier(
- base::MessageLoopProxy::current().get(),
+ base::ThreadTaskRunnerHandle::Get().get(),
base::Bind(&UniqueNotifierTest::Notify, base::Unretained(this)));
EXPECT_EQ(0, NotificationCount());
diff --git a/chromium/cc/base/util.h b/chromium/cc/base/util.h
index 1d716ae2a42..a16d4855283 100644
--- a/chromium/cc/base/util.h
+++ b/chromium/cc/base/util.h
@@ -12,13 +12,15 @@
namespace cc {
template <typename T> T RoundUp(T n, T mul) {
- COMPILE_ASSERT(std::numeric_limits<T>::is_integer, type_must_be_integral);
+ static_assert(std::numeric_limits<T>::is_integer,
+ "T must be an integer type");
return (n > 0) ? ((n + mul - 1) / mul) * mul
: (n / mul) * mul;
}
template <typename T> T RoundDown(T n, T mul) {
- COMPILE_ASSERT(std::numeric_limits<T>::is_integer, type_must_be_integral);
+ static_assert(std::numeric_limits<T>::is_integer,
+ "T must be an integer type");
return (n > 0) ? (n / mul) * mul
: (n == 0) ? 0
: ((n - mul + 1) / mul) * mul;
diff --git a/chromium/cc/blink/BUILD.gn b/chromium/cc/blink/BUILD.gn
index 9fd2f333ae5..4854ead1ce8 100644
--- a/chromium/cc/blink/BUILD.gn
+++ b/chromium/cc/blink/BUILD.gn
@@ -2,27 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//testing/test.gni")
+
# GYP version: //cc/blink/cc_blink.gyp:cc_blink
component("blink") {
output_name = "cc_blink"
- public_deps = [
- "//skia",
- ]
- deps = [
- "//base",
- "//base/third_party/dynamic_annotations",
- "//cc",
- "//gpu",
- "//third_party/WebKit/public:blink",
- "//ui/gfx",
- "//ui/gfx/geometry",
- ]
-
- defines = [ "CC_BLINK_IMPLEMENTATION" ]
-
sources = [
"cc_blink_export.h",
+ "context_provider_web_context.h",
"scrollbar_impl.cc",
"scrollbar_impl.h",
"web_animation_curve_common.cc",
@@ -33,6 +21,8 @@ component("blink") {
"web_compositor_support_impl.h",
"web_content_layer_impl.cc",
"web_content_layer_impl.h",
+ "web_display_item_list_impl.cc",
+ "web_display_item_list_impl.h",
"web_external_bitmap_impl.cc",
"web_external_bitmap_impl.h",
"web_external_texture_layer_impl.cc",
@@ -62,25 +52,48 @@ component("blink") {
"web_transform_operations_impl.cc",
"web_transform_operations_impl.h",
]
-}
-# GYP version: //cc/blink/cc_blink_tests.gyp:cc_blink_unittests
-test("cc_blink_unittests") {
+ defines = [ "CC_BLINK_IMPLEMENTATION" ]
+
+ public_deps = [
+ "//skia",
+ ]
+
deps = [
- ":blink",
- "//base/test:run_all_unittests",
+ "//base",
"//base/third_party/dynamic_annotations",
- "//skia",
- "//testing/gtest",
- "//ui/gfx/geometry",
- "//ui/gfx:test_support",
"//cc",
- "//cc:test_support",
+ "//gpu",
+ "//third_party/WebKit/public:blink",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
]
+}
- sources = [
- "web_animation_unittest.cc",
- "web_float_animation_curve_unittest.cc",
- "web_layer_impl_fixed_bounds_unittest.cc",
- ]
+# GYP version: //cc/blink/cc_blink_tests.gyp:cc_blink_unittests
+# TODO(GYP): make linking work on the mac.
+if (!is_mac) {
+ test("cc_blink_unittests") {
+ sources = [
+ "web_animation_unittest.cc",
+ "web_float_animation_curve_unittest.cc",
+ "web_layer_impl_fixed_bounds_unittest.cc",
+
+ # Setup.
+ "test/cc_blink_test_suite.cc",
+ "test/run_all_unittests.cc",
+ ]
+
+ deps = [
+ ":blink",
+ "//base/test:test_support",
+ "//base/third_party/dynamic_annotations",
+ "//skia",
+ "//testing/gtest",
+ "//ui/gfx/geometry",
+ "//ui/gfx:test_support",
+ "//cc",
+ "//cc:test_support",
+ ]
+ }
}
diff --git a/chromium/cc/blink/cc_blink.gyp b/chromium/cc/blink/cc_blink.gyp
index d9f19ea1f02..e9934bf9653 100644
--- a/chromium/cc/blink/cc_blink.gyp
+++ b/chromium/cc/blink/cc_blink.gyp
@@ -26,6 +26,7 @@
# This sources list is duplicated in //cc/blink/BUILD.gn
'sources': [
'cc_blink_export.h',
+ 'context_provider_web_context.h',
'scrollbar_impl.cc',
'scrollbar_impl.h',
'web_animation_curve_common.cc',
@@ -36,6 +37,8 @@
'web_compositor_support_impl.h',
'web_content_layer_impl.cc',
'web_content_layer_impl.h',
+ 'web_display_item_list_impl.cc',
+ 'web_display_item_list_impl.h',
'web_external_bitmap_impl.cc',
'web_external_bitmap_impl.h',
'web_external_texture_layer_impl.cc',
diff --git a/chromium/cc/blink/cc_blink_tests.gyp b/chromium/cc/blink/cc_blink_tests.gyp
index 003d126b243..f20c4631a32 100644
--- a/chromium/cc/blink/cc_blink_tests.gyp
+++ b/chromium/cc/blink/cc_blink_tests.gyp
@@ -20,10 +20,11 @@
'cc_blink.gyp:cc_blink',
],
'sources': [
+ 'test/cc_blink_test_suite.cc',
+ 'test/run_all_unittests.cc',
'web_animation_unittest.cc',
'web_float_animation_curve_unittest.cc',
'web_layer_impl_fixed_bounds_unittest.cc',
- '../../base/test/run_all_unittests.cc',
],
}
],
diff --git a/chromium/cc/blink/context_provider_web_context.h b/chromium/cc/blink/context_provider_web_context.h
new file mode 100644
index 00000000000..21d1df380e2
--- /dev/null
+++ b/chromium/cc/blink/context_provider_web_context.h
@@ -0,0 +1,24 @@
+// Copyright 2014 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_BLINK_CONTEXT_PROVIDER_WEB_CONTEXT_H_
+#define CC_BLINK_CONTEXT_PROVIDER_WEB_CONTEXT_H_
+
+#include "cc/output/context_provider.h"
+
+namespace blink { class WebGraphicsContext3D; }
+
+namespace cc_blink {
+
+class ContextProviderWebContext : public cc::ContextProvider {
+ public:
+ virtual blink::WebGraphicsContext3D* WebContext3D() = 0;
+
+ protected:
+ ~ContextProviderWebContext() override {}
+};
+
+} // namespace cc_blink
+
+#endif // CC_BLINK_CONTEXT_PROVIDER_WEB_CONTEXT_H_
diff --git a/chromium/cc/blink/web_animation_impl.cc b/chromium/cc/blink/web_animation_impl.cc
index 24fa4ec8cfc..705c33a9bf8 100644
--- a/chromium/cc/blink/web_animation_impl.cc
+++ b/chromium/cc/blink/web_animation_impl.cc
@@ -119,13 +119,13 @@ void WebCompositorAnimationImpl::setTimeOffset(double monotonic_time) {
blink::WebCompositorAnimation::Direction WebCompositorAnimationImpl::direction()
const {
switch (animation_->direction()) {
- case cc::Animation::Normal:
+ case cc::Animation::DIRECTION_NORMAL:
return DirectionNormal;
- case cc::Animation::Reverse:
+ case cc::Animation::DIRECTION_REVERSE:
return DirectionReverse;
- case cc::Animation::Alternate:
+ case cc::Animation::DIRECTION_ALTERNATE:
return DirectionAlternate;
- case cc::Animation::AlternateReverse:
+ case cc::Animation::DIRECTION_ALTERNATE_REVERSE:
return DirectionAlternateReverse;
default:
NOTREACHED();
@@ -136,16 +136,16 @@ blink::WebCompositorAnimation::Direction WebCompositorAnimationImpl::direction()
void WebCompositorAnimationImpl::setDirection(Direction direction) {
switch (direction) {
case DirectionNormal:
- animation_->set_direction(cc::Animation::Normal);
+ animation_->set_direction(cc::Animation::DIRECTION_NORMAL);
break;
case DirectionReverse:
- animation_->set_direction(cc::Animation::Reverse);
+ animation_->set_direction(cc::Animation::DIRECTION_REVERSE);
break;
case DirectionAlternate:
- animation_->set_direction(cc::Animation::Alternate);
+ animation_->set_direction(cc::Animation::DIRECTION_ALTERNATE);
break;
case DirectionAlternateReverse:
- animation_->set_direction(cc::Animation::AlternateReverse);
+ animation_->set_direction(cc::Animation::DIRECTION_ALTERNATE_REVERSE);
break;
}
}
@@ -161,13 +161,13 @@ void WebCompositorAnimationImpl::setPlaybackRate(double playback_rate) {
blink::WebCompositorAnimation::FillMode WebCompositorAnimationImpl::fillMode()
const {
switch (animation_->fill_mode()) {
- case cc::Animation::FillModeNone:
+ case cc::Animation::FILL_MODE_NONE:
return FillModeNone;
- case cc::Animation::FillModeForwards:
+ case cc::Animation::FILL_MODE_FORWARDS:
return FillModeForwards;
- case cc::Animation::FillModeBackwards:
+ case cc::Animation::FILL_MODE_BACKWARDS:
return FillModeBackwards;
- case cc::Animation::FillModeBoth:
+ case cc::Animation::FILL_MODE_BOTH:
return FillModeBoth;
default:
NOTREACHED();
@@ -178,16 +178,16 @@ blink::WebCompositorAnimation::FillMode WebCompositorAnimationImpl::fillMode()
void WebCompositorAnimationImpl::setFillMode(FillMode fill_mode) {
switch (fill_mode) {
case FillModeNone:
- animation_->set_fill_mode(cc::Animation::FillModeNone);
+ animation_->set_fill_mode(cc::Animation::FILL_MODE_NONE);
break;
case FillModeForwards:
- animation_->set_fill_mode(cc::Animation::FillModeForwards);
+ animation_->set_fill_mode(cc::Animation::FILL_MODE_FORWARDS);
break;
case FillModeBackwards:
- animation_->set_fill_mode(cc::Animation::FillModeBackwards);
+ animation_->set_fill_mode(cc::Animation::FILL_MODE_BACKWARDS);
break;
case FillModeBoth:
- animation_->set_fill_mode(cc::Animation::FillModeBoth);
+ animation_->set_fill_mode(cc::Animation::FILL_MODE_BOTH);
break;
}
}
diff --git a/chromium/cc/blink/web_compositor_support_impl.cc b/chromium/cc/blink/web_compositor_support_impl.cc
index ae098fc867e..e69abf69239 100644
--- a/chromium/cc/blink/web_compositor_support_impl.cc
+++ b/chromium/cc/blink/web_compositor_support_impl.cc
@@ -9,6 +9,7 @@
#include "cc/animation/transform_operations.h"
#include "cc/blink/web_animation_impl.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"
#include "cc/blink/web_filter_animation_curve_impl.h"
#include "cc/blink/web_filter_operations_impl.h"
@@ -27,6 +28,7 @@ using blink::WebCompositorAnimation;
using blink::WebCompositorAnimationCurve;
using blink::WebContentLayer;
using blink::WebContentLayerClient;
+using blink::WebDisplayItemList;
using blink::WebExternalTextureLayer;
using blink::WebExternalTextureLayerClient;
using blink::WebFilterAnimationCurve;
diff --git a/chromium/cc/blink/web_compositor_support_impl.h b/chromium/cc/blink/web_compositor_support_impl.h
index 0f6371aed81..b924be9cc09 100644
--- a/chromium/cc/blink/web_compositor_support_impl.h
+++ b/chromium/cc/blink/web_compositor_support_impl.h
@@ -10,6 +10,7 @@
#include "cc/blink/cc_blink_export.h"
#include "third_party/WebKit/public/platform/WebCompositorAnimationCurve.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/WebKit/public/platform/WebTransformOperations.h"
diff --git a/chromium/cc/blink/web_content_layer_impl.cc b/chromium/cc/blink/web_content_layer_impl.cc
index 6dfdad9c160..a480a06614c 100644
--- a/chromium/cc/blink/web_content_layer_impl.cc
+++ b/chromium/cc/blink/web_content_layer_impl.cc
@@ -4,6 +4,7 @@
#include "cc/blink/web_content_layer_impl.h"
+#include "cc/blink/web_display_item_list_impl.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/picture_layer.h"
#include "third_party/WebKit/public/platform/WebContentLayerClient.h"
@@ -18,14 +19,30 @@ using cc::PictureLayer;
namespace cc_blink {
+static blink::WebContentLayerClient::PaintingControlSetting
+PaintingControlToWeb(
+ cc::ContentLayerClient::PaintingControlSetting painting_control) {
+ switch (painting_control) {
+ case cc::ContentLayerClient::PAINTING_BEHAVIOR_NORMAL:
+ return blink::WebContentLayerClient::PaintDefaultBehavior;
+ case cc::ContentLayerClient::DISPLAY_LIST_CONSTRUCTION_DISABLED:
+ return blink::WebContentLayerClient::DisplayListConstructionDisabled;
+ case cc::ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED:
+ return blink::WebContentLayerClient::DisplayListCachingDisabled;
+ case cc::ContentLayerClient::DISPLAY_LIST_PAINTING_DISABLED:
+ return blink::WebContentLayerClient::DisplayListPaintingDisabled;
+ }
+ NOTREACHED();
+ return blink::WebContentLayerClient::PaintDefaultBehavior;
+}
+
WebContentLayerImpl::WebContentLayerImpl(blink::WebContentLayerClient* client)
- : client_(client), ignore_lcd_text_change_(false) {
+ : client_(client) {
if (WebLayerImpl::UsingPictureLayer())
layer_ = make_scoped_ptr(new WebLayerImpl(PictureLayer::Create(this)));
else
layer_ = make_scoped_ptr(new WebLayerImpl(ContentLayer::Create(this)));
layer_->layer()->SetIsDrawable(true);
- can_use_lcd_text_ = layer_->layer()->can_use_lcd_text();
}
WebContentLayerImpl::~WebContentLayerImpl() {
@@ -50,32 +67,22 @@ void WebContentLayerImpl::setDrawCheckerboardForMissingTiles(bool enable) {
void WebContentLayerImpl::PaintContents(
SkCanvas* canvas,
const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus graphics_context_status) {
+ cc::ContentLayerClient::PaintingControlSetting painting_control) {
if (!client_)
return;
- client_->paintContents(
- canvas,
- clip,
- can_use_lcd_text_,
- graphics_context_status == ContentLayerClient::GRAPHICS_CONTEXT_ENABLED
- ? blink::WebContentLayerClient::GraphicsContextEnabled
- : blink::WebContentLayerClient::GraphicsContextDisabled);
+ client_->paintContents(canvas, clip, PaintingControlToWeb(painting_control));
}
-void WebContentLayerImpl::DidChangeLayerCanUseLCDText() {
- // It is important to make this comparison because the LCD text status
- // here can get out of sync with that in the layer.
- if (can_use_lcd_text_ == layer_->layer()->can_use_lcd_text())
- return;
-
- // LCD text cannot be enabled once disabled.
- if (layer_->layer()->can_use_lcd_text() && ignore_lcd_text_change_)
+void WebContentLayerImpl::PaintContentsToDisplayList(
+ cc::DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ cc::ContentLayerClient::PaintingControlSetting painting_control) {
+ if (!client_)
return;
- can_use_lcd_text_ = layer_->layer()->can_use_lcd_text();
- ignore_lcd_text_change_ = true;
- layer_->invalidate();
+ WebDisplayItemListImpl list(display_list);
+ client_->paintContents(&list, clip, PaintingControlToWeb(painting_control));
}
bool WebContentLayerImpl::FillsBoundsCompletely() const {
diff --git a/chromium/cc/blink/web_content_layer_impl.h b/chromium/cc/blink/web_content_layer_impl.h
index b9bb8713854..e7b04b02abc 100644
--- a/chromium/cc/blink/web_content_layer_impl.h
+++ b/chromium/cc/blink/web_content_layer_impl.h
@@ -38,9 +38,11 @@ class WebContentLayerImpl : public blink::WebContentLayer,
// ContentLayerClient implementation.
void PaintContents(SkCanvas* canvas,
const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus
- graphics_context_status) override;
- void DidChangeLayerCanUseLCDText() override;
+ PaintingControlSetting painting_control) override;
+ void PaintContentsToDisplayList(
+ cc::DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ PaintingControlSetting painting_control) override;
bool FillsBoundsCompletely() const override;
scoped_ptr<WebLayerImpl> layer_;
@@ -48,9 +50,6 @@ class WebContentLayerImpl : public blink::WebContentLayer,
bool draws_content_;
private:
- bool can_use_lcd_text_;
- bool ignore_lcd_text_change_;
-
DISALLOW_COPY_AND_ASSIGN(WebContentLayerImpl);
};
diff --git a/chromium/cc/blink/web_display_item_list_impl.cc b/chromium/cc/blink/web_display_item_list_impl.cc
new file mode 100644
index 00000000000..3782358da33
--- /dev/null
+++ b/chromium/cc/blink/web_display_item_list_impl.cc
@@ -0,0 +1,136 @@
+// Copyright 2014 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/blink/web_display_item_list_impl.h"
+
+#include <vector>
+
+#include "cc/blink/web_filter_operations_impl.h"
+#include "cc/playback/clip_display_item.h"
+#include "cc/playback/clip_path_display_item.h"
+#include "cc/playback/compositing_display_item.h"
+#include "cc/playback/drawing_display_item.h"
+#include "cc/playback/filter_display_item.h"
+#include "cc/playback/float_clip_display_item.h"
+#include "cc/playback/transform_display_item.h"
+#include "skia/ext/refptr.h"
+#include "third_party/WebKit/public/platform/WebFloatRect.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/utils/SkMatrix44.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+#include "ui/gfx/transform.h"
+
+namespace cc_blink {
+
+WebDisplayItemListImpl::WebDisplayItemListImpl(
+ cc::DisplayItemList* display_list)
+ : display_item_list_(display_list) {
+}
+
+void WebDisplayItemListImpl::appendDrawingItem(const SkPicture* picture) {
+ auto* item =
+ display_item_list_->CreateAndAppendItem<cc::DrawingDisplayItem>();
+ item->SetNew(skia::SharePtr(const_cast<SkPicture*>(picture)));
+}
+
+void WebDisplayItemListImpl::appendClipItem(
+ const blink::WebRect& clip_rect,
+ const blink::WebVector<SkRRect>& rounded_clip_rects) {
+ std::vector<SkRRect> rounded_rects;
+ for (size_t i = 0; i < rounded_clip_rects.size(); ++i) {
+ rounded_rects.push_back(rounded_clip_rects[i]);
+ }
+ auto* item = display_item_list_->CreateAndAppendItem<cc::ClipDisplayItem>();
+ item->SetNew(clip_rect, rounded_rects);
+}
+
+void WebDisplayItemListImpl::appendEndClipItem() {
+ display_item_list_->CreateAndAppendItem<cc::EndClipDisplayItem>();
+}
+
+void WebDisplayItemListImpl::appendClipPathItem(const SkPath& clip_path,
+ SkRegion::Op clip_op,
+ bool antialias) {
+ auto* item =
+ display_item_list_->CreateAndAppendItem<cc::ClipPathDisplayItem>();
+ item->SetNew(clip_path, clip_op, antialias);
+}
+
+void WebDisplayItemListImpl::appendEndClipPathItem() {
+ display_item_list_->CreateAndAppendItem<cc::EndClipPathDisplayItem>();
+}
+
+void WebDisplayItemListImpl::appendFloatClipItem(
+ const blink::WebFloatRect& clip_rect) {
+ auto* item =
+ display_item_list_->CreateAndAppendItem<cc::FloatClipDisplayItem>();
+ item->SetNew(clip_rect);
+}
+
+void WebDisplayItemListImpl::appendEndFloatClipItem() {
+ display_item_list_->CreateAndAppendItem<cc::EndFloatClipDisplayItem>();
+}
+
+void WebDisplayItemListImpl::appendTransformItem(const SkMatrix44& matrix) {
+ gfx::Transform transform;
+ transform.matrix() = matrix;
+ auto* item =
+ display_item_list_->CreateAndAppendItem<cc::TransformDisplayItem>();
+ item->SetNew(transform);
+}
+
+void WebDisplayItemListImpl::appendEndTransformItem() {
+ display_item_list_->CreateAndAppendItem<cc::EndTransformDisplayItem>();
+}
+
+void WebDisplayItemListImpl::appendCompositingItem(
+ float opacity,
+ SkXfermode::Mode xfermode,
+ SkRect* bounds,
+ SkColorFilter* color_filter) {
+ DCHECK_GE(opacity, 0.f);
+ DCHECK_LE(opacity, 1.f);
+ // TODO(ajuma): This should really be rounding instead of flooring the alpha
+ // value, but that breaks slimming paint reftests.
+ auto* item =
+ display_item_list_->CreateAndAppendItem<cc::CompositingDisplayItem>();
+ item->SetNew(static_cast<uint8_t>(gfx::ToFlooredInt(255 * opacity)), xfermode,
+ bounds, skia::SharePtr(color_filter));
+}
+
+void WebDisplayItemListImpl::appendEndCompositingItem() {
+ display_item_list_->CreateAndAppendItem<cc::EndCompositingDisplayItem>();
+}
+
+void WebDisplayItemListImpl::appendFilterItem(
+ const blink::WebFilterOperations& filters,
+ const blink::WebFloatRect& bounds) {
+ const WebFilterOperationsImpl& filters_impl =
+ static_cast<const WebFilterOperationsImpl&>(filters);
+ auto* item = display_item_list_->CreateAndAppendItem<cc::FilterDisplayItem>();
+ item->SetNew(filters_impl.AsFilterOperations(), bounds);
+}
+
+void WebDisplayItemListImpl::appendEndFilterItem() {
+ display_item_list_->CreateAndAppendItem<cc::EndFilterDisplayItem>();
+}
+
+void WebDisplayItemListImpl::appendScrollItem(
+ const blink::WebSize& scrollOffset,
+ ScrollContainerId) {
+ SkMatrix44 matrix;
+ matrix.setTranslate(-scrollOffset.width, -scrollOffset.height, 0);
+ appendTransformItem(matrix);
+}
+
+void WebDisplayItemListImpl::appendEndScrollItem() {
+ appendEndTransformItem();
+}
+
+WebDisplayItemListImpl::~WebDisplayItemListImpl() {
+}
+
+} // namespace cc_blink
diff --git a/chromium/cc/blink/web_display_item_list_impl.h b/chromium/cc/blink/web_display_item_list_impl.h
new file mode 100644
index 00000000000..6b5d147b5d1
--- /dev/null
+++ b/chromium/cc/blink/web_display_item_list_impl.h
@@ -0,0 +1,71 @@
+// Copyright 2014 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_BLINK_WEB_DISPLAY_ITEM_LIST_IMPL_H_
+#define CC_BLINK_WEB_DISPLAY_ITEM_LIST_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "cc/blink/cc_blink_export.h"
+#include "cc/playback/display_item_list.h"
+#include "third_party/WebKit/public/platform/WebDisplayItemList.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/geometry/point_f.h"
+
+class SkColorFilter;
+class SkImageFilter;
+class SkMatrix44;
+class SkPath;
+class SkPicture;
+class SkRRect;
+
+namespace blink {
+class WebFilterOperations;
+struct WebFloatRect;
+struct WebRect;
+}
+
+namespace cc_blink {
+
+class WebDisplayItemListImpl : public blink::WebDisplayItemList {
+ public:
+ CC_BLINK_EXPORT WebDisplayItemListImpl(cc::DisplayItemList* display_list);
+ virtual ~WebDisplayItemListImpl();
+
+ // blink::WebDisplayItemList implementation.
+ virtual void appendDrawingItem(const SkPicture*);
+ virtual void appendClipItem(
+ const blink::WebRect& clip_rect,
+ const blink::WebVector<SkRRect>& rounded_clip_rects);
+ virtual void appendEndClipItem();
+ virtual void appendClipPathItem(const SkPath& clip_path,
+ SkRegion::Op clip_op,
+ bool antialias);
+ virtual void appendEndClipPathItem();
+ virtual void appendFloatClipItem(const blink::WebFloatRect& clip_rect);
+ virtual void appendEndFloatClipItem();
+ virtual void appendTransformItem(const SkMatrix44& matrix);
+ virtual void appendEndTransformItem();
+ virtual void appendCompositingItem(float opacity,
+ SkXfermode::Mode,
+ SkRect* bounds,
+ SkColorFilter*);
+ virtual void appendEndCompositingItem();
+ virtual void appendFilterItem(const blink::WebFilterOperations& filters,
+ const blink::WebFloatRect& bounds);
+ virtual void appendEndFilterItem();
+ virtual void appendScrollItem(const blink::WebSize& scrollOffset,
+ ScrollContainerId);
+ virtual void appendEndScrollItem();
+
+ private:
+ cc::DisplayItemList* display_item_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebDisplayItemListImpl);
+};
+
+} // namespace cc_blink
+
+#endif // CC_BLINK_WEB_DISPLAY_ITEM_LIST_IMPL_H_
diff --git a/chromium/cc/blink/web_external_bitmap_impl.cc b/chromium/cc/blink/web_external_bitmap_impl.cc
index a1010790190..e2c67e42996 100644
--- a/chromium/cc/blink/web_external_bitmap_impl.cc
+++ b/chromium/cc/blink/web_external_bitmap_impl.cc
@@ -4,18 +4,18 @@
#include "cc/blink/web_external_bitmap_impl.h"
-#include "base/memory/shared_memory.h"
+#include "cc/resources/shared_bitmap.h"
namespace cc_blink {
namespace {
-SharedMemoryAllocationFunction g_memory_allocator;
+SharedBitmapAllocationFunction g_memory_allocator;
} // namespace
-void SetSharedMemoryAllocationFunction(
- SharedMemoryAllocationFunction allocator) {
+void SetSharedBitmapAllocationFunction(
+ SharedBitmapAllocationFunction allocator) {
g_memory_allocator = allocator;
}
@@ -27,10 +27,7 @@ WebExternalBitmapImpl::~WebExternalBitmapImpl() {
void WebExternalBitmapImpl::setSize(blink::WebSize size) {
if (size != size_) {
- size_t byte_size = size.width * size.height * 4;
- shared_memory_ = g_memory_allocator(byte_size);
- if (shared_memory_)
- shared_memory_->Map(byte_size);
+ shared_bitmap_ = g_memory_allocator(gfx::Size(size));
size_ = size;
}
}
@@ -40,7 +37,7 @@ blink::WebSize WebExternalBitmapImpl::size() {
}
uint8* WebExternalBitmapImpl::pixels() {
- return static_cast<uint8*>(shared_memory_->memory());
+ return shared_bitmap_->pixels();
}
} // namespace cc_blink
diff --git a/chromium/cc/blink/web_external_bitmap_impl.h b/chromium/cc/blink/web_external_bitmap_impl.h
index 7dbfab39a28..6cada7dc3c8 100644
--- a/chromium/cc/blink/web_external_bitmap_impl.h
+++ b/chromium/cc/blink/web_external_bitmap_impl.h
@@ -10,17 +10,18 @@
#include "cc/blink/cc_blink_export.h"
#include "third_party/WebKit/public/platform/WebExternalBitmap.h"
-namespace base {
-class SharedMemory;
+namespace cc {
+class SharedBitmap;
}
namespace cc_blink {
-typedef scoped_ptr<base::SharedMemory>(*SharedMemoryAllocationFunction)(size_t);
+typedef scoped_ptr<cc::SharedBitmap>(*SharedBitmapAllocationFunction)(
+ const gfx::Size& size);
// Sets the function that this will use to allocate shared memory.
-CC_BLINK_EXPORT void SetSharedMemoryAllocationFunction(
- SharedMemoryAllocationFunction);
+CC_BLINK_EXPORT void SetSharedBitmapAllocationFunction(
+ SharedBitmapAllocationFunction);
class WebExternalBitmapImpl : public blink::WebExternalBitmap {
public:
@@ -28,14 +29,14 @@ class WebExternalBitmapImpl : public blink::WebExternalBitmap {
virtual ~WebExternalBitmapImpl();
// blink::WebExternalBitmap implementation.
- virtual blink::WebSize size() override;
- virtual void setSize(blink::WebSize size) override;
- virtual uint8* pixels() override;
+ blink::WebSize size() override;
+ void setSize(blink::WebSize size) override;
+ uint8* pixels() override;
- base::SharedMemory* shared_memory() { return shared_memory_.get(); }
+ cc::SharedBitmap* shared_bitmap() { return shared_bitmap_.get(); }
private:
- scoped_ptr<base::SharedMemory> shared_memory_;
+ scoped_ptr<cc::SharedBitmap> shared_bitmap_;
blink::WebSize size_;
DISALLOW_COPY_AND_ASSIGN(WebExternalBitmapImpl);
diff --git a/chromium/cc/blink/web_external_texture_layer_impl.cc b/chromium/cc/blink/web_external_texture_layer_impl.cc
index 85aac10fe0d..8d29aa172dd 100644
--- a/chromium/cc/blink/web_external_texture_layer_impl.cc
+++ b/chromium/cc/blink/web_external_texture_layer_impl.cc
@@ -62,6 +62,11 @@ void WebExternalTextureLayerImpl::setRateLimitContext(bool rate_limit) {
static_cast<TextureLayer*>(layer_->layer())->SetRateLimitContext(rate_limit);
}
+void WebExternalTextureLayerImpl::setNearestNeighbor(bool nearest_neighbor) {
+ static_cast<TextureLayer*>(layer_->layer())
+ ->SetNearestNeighbor(nearest_neighbor);
+}
+
bool WebExternalTextureLayerImpl::PrepareTextureMailbox(
cc::TextureMailbox* mailbox,
scoped_ptr<cc::SingleReleaseCallback>* release_callback,
@@ -79,12 +84,13 @@ bool WebExternalTextureLayerImpl::PrepareTextureMailbox(
gpu::Mailbox name;
name.SetName(client_mailbox.name);
if (bitmap) {
- *mailbox = cc::TextureMailbox(bitmap->shared_memory(), bitmap->size());
+ *mailbox = cc::TextureMailbox(bitmap->shared_bitmap(), bitmap->size());
} else {
*mailbox =
cc::TextureMailbox(name, GL_TEXTURE_2D, client_mailbox.syncPoint);
}
mailbox->set_allow_overlay(client_mailbox.allowOverlay);
+ mailbox->set_nearest_neighbor(client_mailbox.nearestNeighbor);
if (mailbox->IsValid()) {
*release_callback = cc::SingleReleaseCallback::Create(
diff --git a/chromium/cc/blink/web_external_texture_layer_impl.h b/chromium/cc/blink/web_external_texture_layer_impl.h
index 853b1a07925..a12a00b8e37 100644
--- a/chromium/cc/blink/web_external_texture_layer_impl.h
+++ b/chromium/cc/blink/web_external_texture_layer_impl.h
@@ -13,6 +13,7 @@
#include "third_party/WebKit/public/platform/WebExternalTextureLayer.h"
namespace blink {
+class WebExternalTextureLayerClient;
struct WebFloatRect;
struct WebExternalTextureMailbox;
}
@@ -43,6 +44,7 @@ class WebExternalTextureLayerImpl
virtual void setPremultipliedAlpha(bool premultiplied);
virtual void setBlendBackgroundColor(bool blend);
virtual void setRateLimitContext(bool rate_limit);
+ virtual void setNearestNeighbor(bool nearest_neighbor);
// TextureLayerClient implementation.
bool PrepareTextureMailbox(
diff --git a/chromium/cc/blink/web_filter_animation_curve_impl.cc b/chromium/cc/blink/web_filter_animation_curve_impl.cc
index 606929ea0f8..79ffdfae164 100644
--- a/chromium/cc/blink/web_filter_animation_curve_impl.cc
+++ b/chromium/cc/blink/web_filter_animation_curve_impl.cc
@@ -32,7 +32,8 @@ void WebFilterAnimationCurveImpl::add(const WebFilterKeyframe& keyframe,
static_cast<const WebFilterOperationsImpl&>(keyframe.value())
.AsFilterOperations();
curve_->AddKeyframe(cc::FilterKeyframe::Create(
- keyframe.time(), filter_operations, CreateTimingFunction(type)));
+ base::TimeDelta::FromSecondsD(keyframe.time()), filter_operations,
+ CreateTimingFunction(type)));
}
void WebFilterAnimationCurveImpl::add(const WebFilterKeyframe& keyframe,
@@ -44,23 +45,45 @@ void WebFilterAnimationCurveImpl::add(const WebFilterKeyframe& keyframe,
static_cast<const WebFilterOperationsImpl&>(keyframe.value())
.AsFilterOperations();
curve_->AddKeyframe(cc::FilterKeyframe::Create(
- keyframe.time(),
- filter_operations,
+ base::TimeDelta::FromSecondsD(keyframe.time()), filter_operations,
cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)));
}
-void WebFilterAnimationCurveImpl::setTimingFunction(TimingFunctionType type) {
+void WebFilterAnimationCurveImpl::add(const WebFilterKeyframe& keyframe,
+ int steps,
+ float steps_start_offset) {
+ const cc::FilterOperations& filter_operations =
+ static_cast<const WebFilterOperationsImpl&>(keyframe.value())
+ .AsFilterOperations();
+ curve_->AddKeyframe(cc::FilterKeyframe::Create(
+ base::TimeDelta::FromSecondsD(keyframe.time()), filter_operations,
+ cc::StepsTimingFunction::Create(steps, steps_start_offset)));
+}
+
+void WebFilterAnimationCurveImpl::setLinearTimingFunction() {
+ curve_->SetTimingFunction(nullptr);
+}
+
+void WebFilterAnimationCurveImpl::setCubicBezierTimingFunction(
+ TimingFunctionType type) {
curve_->SetTimingFunction(CreateTimingFunction(type));
}
-void WebFilterAnimationCurveImpl::setTimingFunction(double x1,
- double y1,
- double x2,
- double y2) {
+void WebFilterAnimationCurveImpl::setCubicBezierTimingFunction(double x1,
+ double y1,
+ double x2,
+ double y2) {
curve_->SetTimingFunction(
cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2).Pass());
}
+void WebFilterAnimationCurveImpl::setStepsTimingFunction(
+ int number_of_steps,
+ float steps_start_offset) {
+ curve_->SetTimingFunction(cc::StepsTimingFunction::Create(
+ number_of_steps, steps_start_offset).Pass());
+}
+
scoped_ptr<cc::AnimationCurve>
WebFilterAnimationCurveImpl::CloneToAnimationCurve() const {
return curve_->Clone();
diff --git a/chromium/cc/blink/web_filter_animation_curve_impl.h b/chromium/cc/blink/web_filter_animation_curve_impl.h
index ea75eb55c57..93dae4ed052 100644
--- a/chromium/cc/blink/web_filter_animation_curve_impl.h
+++ b/chromium/cc/blink/web_filter_animation_curve_impl.h
@@ -36,8 +36,17 @@ class WebFilterAnimationCurveImpl : public blink::WebFilterAnimationCurve {
double y1,
double x2,
double y2);
- virtual void setTimingFunction(TimingFunctionType type);
- virtual void setTimingFunction(double x1, double y1, double x2, double y2);
+ virtual void add(const blink::WebFilterKeyframe& keyframe,
+ int steps,
+ float steps_start_offset);
+ virtual void setLinearTimingFunction();
+ virtual void setCubicBezierTimingFunction(TimingFunctionType);
+ virtual void setCubicBezierTimingFunction(double x1,
+ double y1,
+ double x2,
+ double y2);
+ virtual void setStepsTimingFunction(int number_of_steps,
+ float steps_start_offset);
scoped_ptr<cc::AnimationCurve> CloneToAnimationCurve() const;
diff --git a/chromium/cc/blink/web_float_animation_curve_impl.cc b/chromium/cc/blink/web_float_animation_curve_impl.cc
index e5eee53eb87..4340ae8bdab 100644
--- a/chromium/cc/blink/web_float_animation_curve_impl.cc
+++ b/chromium/cc/blink/web_float_animation_curve_impl.cc
@@ -31,8 +31,9 @@ void WebFloatAnimationCurveImpl::add(const WebFloatKeyframe& keyframe) {
void WebFloatAnimationCurveImpl::add(const WebFloatKeyframe& keyframe,
TimingFunctionType type) {
- curve_->AddKeyframe(cc::FloatKeyframe::Create(
- keyframe.time, keyframe.value, CreateTimingFunction(type)));
+ curve_->AddKeyframe(
+ cc::FloatKeyframe::Create(base::TimeDelta::FromSecondsD(keyframe.time),
+ keyframe.value, CreateTimingFunction(type)));
}
void WebFloatAnimationCurveImpl::add(const WebFloatKeyframe& keyframe,
@@ -41,25 +42,44 @@ void WebFloatAnimationCurveImpl::add(const WebFloatKeyframe& keyframe,
double x2,
double y2) {
curve_->AddKeyframe(cc::FloatKeyframe::Create(
- keyframe.time,
- keyframe.value,
+ base::TimeDelta::FromSecondsD(keyframe.time), keyframe.value,
cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)));
}
-void WebFloatAnimationCurveImpl::setTimingFunction(TimingFunctionType type) {
+void WebFloatAnimationCurveImpl::add(const WebFloatKeyframe& keyframe,
+ int steps,
+ float steps_start_offset) {
+ curve_->AddKeyframe(cc::FloatKeyframe::Create(
+ base::TimeDelta::FromSecondsD(keyframe.time), keyframe.value,
+ cc::StepsTimingFunction::Create(steps, steps_start_offset)));
+}
+
+void WebFloatAnimationCurveImpl::setLinearTimingFunction() {
+ curve_->SetTimingFunction(nullptr);
+}
+
+void WebFloatAnimationCurveImpl::setCubicBezierTimingFunction(
+ TimingFunctionType type) {
curve_->SetTimingFunction(CreateTimingFunction(type));
}
-void WebFloatAnimationCurveImpl::setTimingFunction(double x1,
- double y1,
- double x2,
- double y2) {
+void WebFloatAnimationCurveImpl::setCubicBezierTimingFunction(double x1,
+ double y1,
+ double x2,
+ double y2) {
curve_->SetTimingFunction(
cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2).Pass());
}
+void WebFloatAnimationCurveImpl::setStepsTimingFunction(
+ int number_of_steps,
+ float steps_start_offset) {
+ curve_->SetTimingFunction(cc::StepsTimingFunction::Create(
+ number_of_steps, steps_start_offset).Pass());
+}
+
float WebFloatAnimationCurveImpl::getValue(double time) const {
- return curve_->GetValue(time);
+ return curve_->GetValue(base::TimeDelta::FromSecondsD(time));
}
scoped_ptr<cc::AnimationCurve>
diff --git a/chromium/cc/blink/web_float_animation_curve_impl.h b/chromium/cc/blink/web_float_animation_curve_impl.h
index 8e5ccd241b7..b5a97aa5db6 100644
--- a/chromium/cc/blink/web_float_animation_curve_impl.h
+++ b/chromium/cc/blink/web_float_animation_curve_impl.h
@@ -37,8 +37,17 @@ class WebFloatAnimationCurveImpl : public blink::WebFloatAnimationCurve {
double y1,
double x2,
double y2);
- virtual void setTimingFunction(TimingFunctionType type);
- virtual void setTimingFunction(double x1, double y1, double x2, double y2);
+ virtual void add(const blink::WebFloatKeyframe& keyframe,
+ int steps,
+ float steps_start_offset);
+ virtual void setLinearTimingFunction();
+ virtual void setCubicBezierTimingFunction(TimingFunctionType);
+ virtual void setCubicBezierTimingFunction(double x1,
+ double y1,
+ double x2,
+ double y2);
+ virtual void setStepsTimingFunction(int number_of_steps,
+ float steps_start_offset);
virtual float getValue(double time) const;
diff --git a/chromium/cc/blink/web_image_layer_impl.cc b/chromium/cc/blink/web_image_layer_impl.cc
index ee80ca6a044..afd551a3102 100644
--- a/chromium/cc/blink/web_image_layer_impl.cc
+++ b/chromium/cc/blink/web_image_layer_impl.cc
@@ -35,4 +35,11 @@ void WebImageLayerImpl::setImageBitmap(const SkBitmap& bitmap) {
}
}
+void WebImageLayerImpl::setNearestNeighbor(bool nearest_neighbor) {
+ if (WebLayerImpl::UsingPictureLayer()) {
+ static_cast<cc::PictureImageLayer*>(layer_->layer())
+ ->SetNearestNeighbor(nearest_neighbor);
+ }
+}
+
} // namespace cc_blink
diff --git a/chromium/cc/blink/web_image_layer_impl.h b/chromium/cc/blink/web_image_layer_impl.h
index e0591aa2bb5..48c31ea80c7 100644
--- a/chromium/cc/blink/web_image_layer_impl.h
+++ b/chromium/cc/blink/web_image_layer_impl.h
@@ -22,6 +22,7 @@ class WebImageLayerImpl : public blink::WebImageLayer {
// blink::WebImageLayer implementation.
virtual blink::WebLayer* layer();
virtual void setImageBitmap(const SkBitmap& bitmap);
+ virtual void setNearestNeighbor(bool nearest_neighbor);
private:
scoped_ptr<WebLayerImpl> layer_;
diff --git a/chromium/cc/blink/web_layer_impl.cc b/chromium/cc/blink/web_layer_impl.cc
index f73ae10429e..8bad92a002e 100644
--- a/chromium/cc/blink/web_layer_impl.cc
+++ b/chromium/cc/blink/web_layer_impl.cc
@@ -4,11 +4,14 @@
#include "cc/blink/web_layer_impl.h"
+#include <utility>
+#include <vector>
+
#include "base/bind.h"
-#include "base/debug/trace_event_impl.h"
#include "base/lazy_instance.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_checker.h"
+#include "base/trace_event/trace_event_impl.h"
#include "cc/animation/animation.h"
#include "cc/base/region.h"
#include "cc/base/switches.h"
@@ -253,7 +256,7 @@ void WebLayerImpl::removeAnimation(int animation_id) {
void WebLayerImpl::removeAnimation(
int animation_id,
blink::WebCompositorAnimation::TargetProperty target_property) {
- layer_->layer_animation_controller()->RemoveAnimation(
+ layer_->RemoveAnimation(
animation_id, static_cast<Animation::TargetProperty>(target_property));
}
@@ -273,6 +276,12 @@ void WebLayerImpl::setScrollPositionDouble(blink::WebDoublePoint position) {
layer_->SetScrollOffset(gfx::ScrollOffset(position.x, position.y));
}
+void WebLayerImpl::setScrollCompensationAdjustment(
+ blink::WebDoublePoint position) {
+ layer_->SetScrollCompensationAdjustment(
+ gfx::Vector2dF(position.x, position.y));
+}
+
blink::WebDoublePoint WebLayerImpl::scrollPositionDouble() const {
return blink::WebDoublePoint(layer_->scroll_offset().x(),
layer_->scroll_offset().y());
@@ -352,6 +361,31 @@ WebVector<WebRect> WebLayerImpl::nonFastScrollableRegion() const {
return result;
}
+void WebLayerImpl::setFrameTimingRequests(
+ const WebVector<std::pair<int64_t, WebRect>>& requests) {
+ std::vector<cc::FrameTimingRequest> frame_timing_requests(requests.size());
+ for (size_t i = 0; i < requests.size(); ++i) {
+ frame_timing_requests[i] = cc::FrameTimingRequest(
+ requests[i].first, gfx::Rect(requests[i].second));
+ }
+ layer_->SetFrameTimingRequests(frame_timing_requests);
+}
+
+WebVector<std::pair<int64_t, WebRect>> WebLayerImpl::frameTimingRequests()
+ const {
+ const std::vector<cc::FrameTimingRequest>& frame_timing_requests =
+ layer_->FrameTimingRequests();
+
+ size_t num_requests = frame_timing_requests.size();
+
+ WebVector<std::pair<int64_t, WebRect>> result(num_requests);
+ for (size_t i = 0; i < num_requests; ++i) {
+ result[i] = std::make_pair(frame_timing_requests[i].id(),
+ frame_timing_requests[i].rect());
+ }
+ return result;
+}
+
void WebLayerImpl::setTouchEventHandlerRegion(const WebVector<WebRect>& rects) {
cc::Region region;
for (size_t i = 0; i < rects.size(); ++i)
@@ -377,6 +411,28 @@ WebVector<WebRect> WebLayerImpl::touchEventHandlerRegion() const {
return result;
}
+static_assert(static_cast<ScrollBlocksOn>(blink::WebScrollBlocksOnNone) ==
+ SCROLL_BLOCKS_ON_NONE,
+ "ScrollBlocksOn and WebScrollBlocksOn enums must match");
+static_assert(static_cast<ScrollBlocksOn>(blink::WebScrollBlocksOnStartTouch) ==
+ SCROLL_BLOCKS_ON_START_TOUCH,
+ "ScrollBlocksOn and WebScrollBlocksOn enums must match");
+static_assert(static_cast<ScrollBlocksOn>(blink::WebScrollBlocksOnWheelEvent) ==
+ SCROLL_BLOCKS_ON_WHEEL_EVENT,
+ "ScrollBlocksOn and WebScrollBlocksOn enums must match");
+static_assert(
+ static_cast<ScrollBlocksOn>(blink::WebScrollBlocksOnScrollEvent) ==
+ SCROLL_BLOCKS_ON_SCROLL_EVENT,
+ "ScrollBlocksOn and WebScrollBlocksOn enums must match");
+
+void WebLayerImpl::setScrollBlocksOn(blink::WebScrollBlocksOn blocks) {
+ layer_->SetScrollBlocksOn(static_cast<ScrollBlocksOn>(blocks));
+}
+
+blink::WebScrollBlocksOn WebLayerImpl::scrollBlocksOn() const {
+ return static_cast<blink::WebScrollBlocksOn>(layer_->scroll_blocks_on());
+}
+
void WebLayerImpl::setIsContainerForFixedPositionLayers(bool enable) {
layer_->SetIsContainerForFixedPositionLayers(enable);
}
@@ -430,7 +486,7 @@ void WebLayerImpl::setWebLayerClient(blink::WebLayerClient* client) {
web_layer_client_ = client;
}
-class TracedDebugInfo : public base::debug::ConvertableToTraceFormat {
+class TracedDebugInfo : public base::trace_event::ConvertableToTraceFormat {
public:
// This object takes ownership of the debug_info object.
explicit TracedDebugInfo(blink::WebGraphicsLayerDebugInfo* debug_info)
@@ -448,7 +504,7 @@ class TracedDebugInfo : public base::debug::ConvertableToTraceFormat {
base::ThreadChecker thread_checker_;
};
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
WebLayerImpl::TakeDebugInfo() {
if (!web_layer_client_)
return nullptr;
diff --git a/chromium/cc/blink/web_layer_impl.h b/chromium/cc/blink/web_layer_impl.h
index bced59805c2..beaf3b51679 100644
--- a/chromium/cc/blink/web_layer_impl.h
+++ b/chromium/cc/blink/web_layer_impl.h
@@ -6,6 +6,7 @@
#define CC_BLINK_WEB_LAYER_IMPL_H_
#include <string>
+#include <utility>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
@@ -31,7 +32,7 @@ struct WebFloatRect;
}
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
}
}
@@ -105,6 +106,7 @@ class WebLayerImpl : public blink::WebLayer, public cc::LayerClient {
virtual void setForceRenderSurface(bool force);
virtual void setScrollPositionDouble(blink::WebDoublePoint position);
virtual blink::WebDoublePoint scrollPositionDouble() const;
+ virtual void setScrollCompensationAdjustment(blink::WebDoublePoint position);
virtual void setScrollClipLayer(blink::WebLayer* clip_layer);
virtual bool scrollable() const;
virtual void setUserScrollable(bool horizontal, bool vertical);
@@ -122,6 +124,12 @@ class WebLayerImpl : public blink::WebLayer, public cc::LayerClient {
virtual void setTouchEventHandlerRegion(
const blink::WebVector<blink::WebRect>& region);
virtual blink::WebVector<blink::WebRect> touchEventHandlerRegion() const;
+ virtual void setScrollBlocksOn(blink::WebScrollBlocksOn);
+ virtual blink::WebScrollBlocksOn scrollBlocksOn() const;
+ virtual void setFrameTimingRequests(
+ const blink::WebVector<std::pair<int64_t, blink::WebRect>>& requests);
+ virtual blink::WebVector<std::pair<int64_t, blink::WebRect>>
+ frameTimingRequests() const;
virtual void setIsContainerForFixedPositionLayers(bool is_container);
virtual bool isContainerForFixedPositionLayers() const;
virtual void setPositionConstraint(
@@ -132,7 +140,8 @@ class WebLayerImpl : public blink::WebLayer, public cc::LayerClient {
virtual void setWebLayerClient(blink::WebLayerClient* client);
// LayerClient implementation.
- scoped_refptr<base::debug::ConvertableToTraceFormat> TakeDebugInfo() override;
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> TakeDebugInfo()
+ override;
virtual void setScrollParent(blink::WebLayer* parent);
virtual void setClipParent(blink::WebLayer* parent);
diff --git a/chromium/cc/blink/web_layer_impl_fixed_bounds.h b/chromium/cc/blink/web_layer_impl_fixed_bounds.h
index 099feafa450..edfd4bbb558 100644
--- a/chromium/cc/blink/web_layer_impl_fixed_bounds.h
+++ b/chromium/cc/blink/web_layer_impl_fixed_bounds.h
@@ -24,13 +24,13 @@ class WebLayerImplFixedBounds : public WebLayerImpl {
virtual ~WebLayerImplFixedBounds();
// WebLayerImpl overrides.
- virtual void invalidateRect(const blink::WebRect& rect) override;
- virtual void setTransformOrigin(
+ void invalidateRect(const blink::WebRect& rect) override;
+ void setTransformOrigin(
const blink::WebFloatPoint3D& transform_origin) override;
- virtual void setBounds(const blink::WebSize& bounds) override;
- virtual blink::WebSize bounds() const override;
- virtual void setTransform(const SkMatrix44& transform) override;
- virtual SkMatrix44 transform() const override;
+ void setBounds(const blink::WebSize& bounds) override;
+ blink::WebSize bounds() const override;
+ void setTransform(const SkMatrix44& transform) override;
+ SkMatrix44 transform() const override;
CC_BLINK_EXPORT void SetFixedBounds(gfx::Size bounds);
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 ceeb311dc4c..c9fd4fad6dc 100644
--- a/chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc
+++ b/chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc
@@ -53,9 +53,8 @@ void CheckBoundsScaleSimple(WebLayerImplFixedBounds* layer,
original_point.y() * bounds.height / fixed_bounds.height(),
original_point.z());
// Test if the bounds scale is correctly applied in transform.
- EXPECT_POINT3F_EQ(
- scaled_point,
- TransformPoint(layer->layer()->transform(), original_point));
+ EXPECT_POINT3F_EQ(scaled_point, TransformPoint(layer->layer()->transform(),
+ original_point));
}
TEST(WebLayerImplFixedBoundsTest, BoundsScaleSimple) {
diff --git a/chromium/cc/blink/web_scroll_offset_animation_curve_impl.cc b/chromium/cc/blink/web_scroll_offset_animation_curve_impl.cc
index e7896317d00..d79b6d94ca9 100644
--- a/chromium/cc/blink/web_scroll_offset_animation_curve_impl.cc
+++ b/chromium/cc/blink/web_scroll_offset_animation_curve_impl.cc
@@ -34,12 +34,23 @@ void WebScrollOffsetAnimationCurveImpl::setInitialValue(
}
WebFloatPoint WebScrollOffsetAnimationCurveImpl::getValue(double time) const {
- gfx::ScrollOffset value = curve_->GetValue(time);
+ gfx::ScrollOffset value =
+ curve_->GetValue(base::TimeDelta::FromSecondsD(time));
return WebFloatPoint(value.x(), value.y());
}
double WebScrollOffsetAnimationCurveImpl::duration() const {
- return curve_->Duration();
+ return curve_->Duration().InSecondsF();
+}
+
+WebFloatPoint WebScrollOffsetAnimationCurveImpl::targetValue() const {
+ gfx::ScrollOffset target = curve_->target_value();
+ return WebFloatPoint(target.x(), target.y());
+}
+
+void WebScrollOffsetAnimationCurveImpl::updateTarget(double time,
+ WebFloatPoint new_target) {
+ curve_->UpdateTarget(time, gfx::ScrollOffset(new_target.x, new_target.y));
}
scoped_ptr<cc::AnimationCurve>
diff --git a/chromium/cc/blink/web_scroll_offset_animation_curve_impl.h b/chromium/cc/blink/web_scroll_offset_animation_curve_impl.h
index 8266780c72f..5f914b9ca54 100644
--- a/chromium/cc/blink/web_scroll_offset_animation_curve_impl.h
+++ b/chromium/cc/blink/web_scroll_offset_animation_curve_impl.h
@@ -31,6 +31,8 @@ class WebScrollOffsetAnimationCurveImpl
virtual void setInitialValue(blink::WebFloatPoint initial_value);
virtual blink::WebFloatPoint getValue(double time) const;
virtual double duration() const;
+ virtual blink::WebFloatPoint targetValue() const;
+ virtual void updateTarget(double time, blink::WebFloatPoint new_target);
scoped_ptr<cc::AnimationCurve> CloneToAnimationCurve() const;
diff --git a/chromium/cc/blink/web_scrollbar_layer_impl.cc b/chromium/cc/blink/web_scrollbar_layer_impl.cc
index dcc8d6fee15..c94f2c5a9cc 100644
--- a/chromium/cc/blink/web_scrollbar_layer_impl.cc
+++ b/chromium/cc/blink/web_scrollbar_layer_impl.cc
@@ -61,13 +61,15 @@ blink::WebLayer* WebScrollbarLayerImpl::layer() {
void WebScrollbarLayerImpl::setScrollLayer(blink::WebLayer* layer) {
cc::Layer* scroll_layer =
layer ? static_cast<WebLayerImpl*>(layer)->layer() : 0;
- layer_->layer()->ToScrollbarLayer()->SetScrollLayer(scroll_layer->id());
+ layer_->layer()->ToScrollbarLayer()->SetScrollLayer(
+ scroll_layer ? scroll_layer->id() : cc::Layer::INVALID_ID);
}
void WebScrollbarLayerImpl::setClipLayer(blink::WebLayer* layer) {
cc::Layer* clip_layer =
layer ? static_cast<WebLayerImpl*>(layer)->layer() : 0;
- layer_->layer()->ToScrollbarLayer()->SetClipLayer(clip_layer->id());
+ layer_->layer()->ToScrollbarLayer()->SetClipLayer(
+ clip_layer ? clip_layer->id() : cc::Layer::INVALID_ID);
}
} // namespace cc_blink
diff --git a/chromium/cc/blink/web_transform_animation_curve_impl.cc b/chromium/cc/blink/web_transform_animation_curve_impl.cc
index f91d94b27c1..4dafd1012d4 100644
--- a/chromium/cc/blink/web_transform_animation_curve_impl.cc
+++ b/chromium/cc/blink/web_transform_animation_curve_impl.cc
@@ -36,7 +36,8 @@ void WebTransformAnimationCurveImpl::add(const WebTransformKeyframe& keyframe,
static_cast<const WebTransformOperationsImpl&>(keyframe.value())
.AsTransformOperations();
curve_->AddKeyframe(cc::TransformKeyframe::Create(
- keyframe.time(), transform_operations, CreateTimingFunction(type)));
+ base::TimeDelta::FromSecondsD(keyframe.time()), transform_operations,
+ CreateTimingFunction(type)));
}
void WebTransformAnimationCurveImpl::add(const WebTransformKeyframe& keyframe,
@@ -48,24 +49,45 @@ void WebTransformAnimationCurveImpl::add(const WebTransformKeyframe& keyframe,
static_cast<const WebTransformOperationsImpl&>(keyframe.value())
.AsTransformOperations();
curve_->AddKeyframe(cc::TransformKeyframe::Create(
- keyframe.time(),
- transform_operations,
+ base::TimeDelta::FromSecondsD(keyframe.time()), transform_operations,
cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)));
}
-void WebTransformAnimationCurveImpl::setTimingFunction(
+void WebTransformAnimationCurveImpl::add(const WebTransformKeyframe& keyframe,
+ int steps,
+ float steps_start_offset) {
+ const cc::TransformOperations& transform_operations =
+ static_cast<const WebTransformOperationsImpl&>(keyframe.value())
+ .AsTransformOperations();
+ curve_->AddKeyframe(cc::TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(keyframe.time()), transform_operations,
+ cc::StepsTimingFunction::Create(steps, steps_start_offset)));
+}
+
+void WebTransformAnimationCurveImpl::setLinearTimingFunction() {
+ curve_->SetTimingFunction(nullptr);
+}
+
+void WebTransformAnimationCurveImpl::setCubicBezierTimingFunction(
TimingFunctionType type) {
curve_->SetTimingFunction(CreateTimingFunction(type));
}
-void WebTransformAnimationCurveImpl::setTimingFunction(double x1,
- double y1,
- double x2,
- double y2) {
+void WebTransformAnimationCurveImpl::setCubicBezierTimingFunction(double x1,
+ double y1,
+ double x2,
+ double y2) {
curve_->SetTimingFunction(
cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2).Pass());
}
+void WebTransformAnimationCurveImpl::setStepsTimingFunction(
+ int number_of_steps,
+ float steps_start_offset) {
+ curve_->SetTimingFunction(cc::StepsTimingFunction::Create(
+ number_of_steps, steps_start_offset).Pass());
+}
+
scoped_ptr<cc::AnimationCurve>
WebTransformAnimationCurveImpl::CloneToAnimationCurve() const {
return curve_->Clone();
diff --git a/chromium/cc/blink/web_transform_animation_curve_impl.h b/chromium/cc/blink/web_transform_animation_curve_impl.h
index a4dbe227989..81ed6073fa7 100644
--- a/chromium/cc/blink/web_transform_animation_curve_impl.h
+++ b/chromium/cc/blink/web_transform_animation_curve_impl.h
@@ -38,8 +38,17 @@ class WebTransformAnimationCurveImpl
double y1,
double x2,
double y2);
- virtual void setTimingFunction(TimingFunctionType type);
- virtual void setTimingFunction(double x1, double y1, double x2, double y2);
+ virtual void add(const blink::WebTransformKeyframe& keyframe,
+ int steps,
+ float stepsStartOffset);
+ virtual void setLinearTimingFunction();
+ virtual void setCubicBezierTimingFunction(TimingFunctionType);
+ virtual void setCubicBezierTimingFunction(double x1,
+ double y1,
+ double x2,
+ double y2);
+ virtual void setStepsTimingFunction(int number_of_steps,
+ float steps_start_offset);
scoped_ptr<cc::AnimationCurve> CloneToAnimationCurve() const;
diff --git a/chromium/cc/cc.gyp b/chromium/cc/cc.gyp
index 7ac01225de8..2a4d66a267e 100644
--- a/chromium/cc/cc.gyp
+++ b/chromium/cc/cc.gyp
@@ -20,6 +20,7 @@
'<(DEPTH)/ui/events/events.gyp:events_base',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
+ 'cc_opts',
],
'variables': {
'optimize': 'max',
@@ -52,8 +53,8 @@
'animation/layer_animation_value_provider.h',
'animation/scroll_offset_animation_curve.cc',
'animation/scroll_offset_animation_curve.h',
- 'animation/scrollbar_animation_controller.h',
'animation/scrollbar_animation_controller.cc',
+ 'animation/scrollbar_animation_controller.h',
'animation/scrollbar_animation_controller_linear_fade.cc',
'animation/scrollbar_animation_controller_linear_fade.h',
'animation/scrollbar_animation_controller_thinning.cc',
@@ -69,13 +70,8 @@
'base/delayed_unique_notifier.h',
'base/invalidation_region.cc',
'base/invalidation_region.h',
- 'base/latency_info_swap_promise.cc',
- 'base/latency_info_swap_promise.h',
- 'base/latency_info_swap_promise_monitor.cc',
- 'base/latency_info_swap_promise_monitor.h',
'base/math_util.cc',
'base/math_util.h',
- 'base/ref_counted_managed.h',
'base/region.cc',
'base/region.h',
'base/rolling_time_delta_history.cc',
@@ -85,13 +81,12 @@
'base/scoped_ptr_vector.h',
'base/simple_enclosed_region.cc',
'base/simple_enclosed_region.h',
- 'base/swap_promise.h',
- 'base/swap_promise_monitor.cc',
- 'base/swap_promise_monitor.h',
'base/switches.cc',
'base/switches.h',
+ 'base/synced_property.h',
'base/tiling_data.cc',
'base/tiling_data.h',
+ 'base/time_util.h',
'base/unique_notifier.cc',
'base/unique_notifier.h',
'base/util.h',
@@ -104,6 +99,11 @@
'debug/devtools_instrumentation.h',
'debug/frame_rate_counter.cc',
'debug/frame_rate_counter.h',
+ 'debug/frame_timing_request.cc',
+ 'debug/frame_timing_request.h',
+ 'debug/frame_timing_tracker.cc',
+ 'debug/frame_timing_tracker.h',
+ 'debug/frame_viewer_instrumentation.cc',
'debug/frame_viewer_instrumentation.h',
'debug/invalidation_benchmark.cc',
'debug/invalidation_benchmark.h',
@@ -113,14 +113,16 @@
'debug/layer_tree_debug_state.h',
'debug/micro_benchmark.cc',
'debug/micro_benchmark.h',
- 'debug/micro_benchmark_impl.cc',
- 'debug/micro_benchmark_impl.h',
'debug/micro_benchmark_controller.cc',
'debug/micro_benchmark_controller.h',
'debug/micro_benchmark_controller_impl.cc',
'debug/micro_benchmark_controller_impl.h',
+ 'debug/micro_benchmark_impl.cc',
+ 'debug/micro_benchmark_impl.h',
'debug/paint_time_counter.cc',
'debug/paint_time_counter.h',
+ 'debug/picture_debug_util.cc',
+ 'debug/picture_debug_util.h',
'debug/picture_record_benchmark.cc',
'debug/picture_record_benchmark.h',
'debug/rasterize_and_record_benchmark.cc',
@@ -142,11 +144,14 @@
'debug/unittest_only_benchmark_impl.h',
'input/input_handler.cc',
'input/input_handler.h',
- 'input/page_scale_animation.cc',
- 'input/page_scale_animation.h',
'input/layer_selection_bound.cc',
'input/layer_selection_bound.h',
+ 'input/page_scale_animation.cc',
+ 'input/page_scale_animation.h',
+ 'input/scroll_elasticity_helper.cc',
+ 'input/scroll_elasticity_helper.h',
'input/selection_bound_type.h',
+ 'input/selection.h',
'input/top_controls_manager.cc',
'input/top_controls_manager.h',
'input/top_controls_manager_client.h',
@@ -244,6 +249,8 @@
'layers/video_layer.h',
'layers/video_layer_impl.cc',
'layers/video_layer_impl.h',
+ 'layers/viewport.cc',
+ 'layers/viewport.h',
'output/begin_frame_args.cc',
'output/begin_frame_args.h',
'output/bsp_tree.cc',
@@ -262,24 +269,30 @@
'output/copy_output_request.h',
'output/copy_output_result.cc',
'output/copy_output_result.h',
- 'output/delegated_frame_data.h',
'output/delegated_frame_data.cc',
+ 'output/delegated_frame_data.h',
'output/delegating_renderer.cc',
'output/delegating_renderer.h',
'output/direct_renderer.cc',
'output/direct_renderer.h',
+ 'output/dynamic_geometry_binding.cc',
+ 'output/dynamic_geometry_binding.h',
'output/filter_operation.cc',
'output/filter_operation.h',
'output/filter_operations.cc',
'output/filter_operations.h',
'output/geometry_binding.cc',
'output/geometry_binding.h',
- 'output/gl_frame_data.h',
'output/gl_frame_data.cc',
+ 'output/gl_frame_data.h',
'output/gl_renderer.cc',
'output/gl_renderer.h',
'output/gl_renderer_draw_cache.cc',
'output/gl_renderer_draw_cache.h',
+ 'output/latency_info_swap_promise.cc',
+ 'output/latency_info_swap_promise.h',
+ 'output/layer_quad.cc',
+ 'output/layer_quad.h',
'output/managed_memory_policy.cc',
'output/managed_memory_policy.h',
'output/output_surface.cc',
@@ -290,14 +303,22 @@
'output/overlay_candidate_validator.h',
'output/overlay_processor.cc',
'output/overlay_processor.h',
+ 'output/overlay_strategy_common.cc',
+ 'output/overlay_strategy_common.h',
'output/overlay_strategy_single_on_top.cc',
'output/overlay_strategy_single_on_top.h',
+ 'output/overlay_strategy_underlay.cc',
+ 'output/overlay_strategy_underlay.h',
'output/program_binding.cc',
'output/program_binding.h',
'output/render_surface_filters.cc',
'output/render_surface_filters.h',
'output/renderer.cc',
'output/renderer.h',
+ 'output/renderer_capabilities.cc',
+ 'output/renderer_capabilities.h',
+ 'output/renderer_settings.cc',
+ 'output/renderer_settings.h',
'output/shader.cc',
'output/shader.h',
'output/software_frame_data.cc',
@@ -306,9 +327,50 @@
'output/software_output_device.h',
'output/software_renderer.cc',
'output/software_renderer.h',
+ 'output/static_geometry_binding.cc',
+ 'output/static_geometry_binding.h',
+ 'output/swap_promise.h',
+ 'output/texture_mailbox_deleter.cc',
+ 'output/texture_mailbox_deleter.h',
'output/viewport_selection_bound.cc',
'output/viewport_selection_bound.h',
'output/vsync_parameter_observer.h',
+ 'playback/clip_display_item.cc',
+ 'playback/clip_display_item.h',
+ 'playback/clip_path_display_item.cc',
+ 'playback/clip_path_display_item.h',
+ 'playback/compositing_display_item.cc',
+ 'playback/compositing_display_item.h',
+ 'playback/display_item.cc',
+ 'playback/display_item.h',
+ 'playback/display_item_list.cc',
+ 'playback/display_item_list.h',
+ 'playback/display_list_raster_source.cc',
+ 'playback/display_list_raster_source.h',
+ 'playback/display_list_recording_source.cc',
+ 'playback/display_list_recording_source.h',
+ 'playback/drawing_display_item.cc',
+ 'playback/drawing_display_item.h',
+ 'playback/filter_display_item.cc',
+ 'playback/filter_display_item.h',
+ 'playback/float_clip_display_item.cc',
+ 'playback/float_clip_display_item.h',
+ 'playback/largest_display_item.cc',
+ 'playback/largest_display_item.h',
+ 'playback/picture.cc',
+ 'playback/picture.h',
+ 'playback/picture_pile.cc',
+ 'playback/picture_pile.h',
+ 'playback/picture_pile_impl.cc',
+ 'playback/picture_pile_impl.h',
+ 'playback/pixel_ref_map.cc',
+ 'playback/pixel_ref_map.h',
+ 'playback/raster_source.h',
+ 'playback/raster_source_helper.cc',
+ 'playback/raster_source_helper.h',
+ 'playback/recording_source.h',
+ 'playback/transform_display_item.cc',
+ 'playback/transform_display_item.h',
'quads/checkerboard_draw_quad.cc',
'quads/checkerboard_draw_quad.h',
'quads/content_draw_quad_base.cc',
@@ -321,8 +383,8 @@
'quads/draw_quad.h',
'quads/io_surface_draw_quad.cc',
'quads/io_surface_draw_quad.h',
- 'quads/largest_draw_quad.h',
'quads/largest_draw_quad.cc',
+ 'quads/largest_draw_quad.h',
'quads/list_container.cc',
'quads/list_container.h',
'quads/picture_draw_quad.cc',
@@ -347,47 +409,45 @@
'quads/tile_draw_quad.h',
'quads/yuv_video_draw_quad.cc',
'quads/yuv_video_draw_quad.h',
+ 'raster/bitmap_tile_task_worker_pool.cc',
+ 'raster/bitmap_tile_task_worker_pool.h',
+ 'raster/gpu_rasterizer.cc',
+ 'raster/gpu_rasterizer.h',
+ 'raster/gpu_tile_task_worker_pool.cc',
+ 'raster/gpu_tile_task_worker_pool.h',
+ 'raster/one_copy_tile_task_worker_pool.cc',
+ 'raster/one_copy_tile_task_worker_pool.h',
+ 'raster/pixel_buffer_tile_task_worker_pool.cc',
+ 'raster/pixel_buffer_tile_task_worker_pool.h',
+ 'raster/raster_buffer.cc',
+ 'raster/raster_buffer.h',
+ 'raster/scoped_gpu_raster.cc',
+ 'raster/scoped_gpu_raster.h',
+ 'raster/task_graph_runner.cc',
+ 'raster/task_graph_runner.h',
+ 'raster/texture_compressor.cc',
+ 'raster/texture_compressor.h',
+ 'raster/texture_compressor_etc1.cc',
+ 'raster/texture_compressor_etc1.h',
+ 'raster/tile_task_runner.cc',
+ 'raster/tile_task_runner.h',
+ 'raster/tile_task_worker_pool.cc',
+ 'raster/tile_task_worker_pool.h',
+ 'raster/zero_copy_tile_task_worker_pool.cc',
+ 'raster/zero_copy_tile_task_worker_pool.h',
'resources/bitmap_content_layer_updater.cc',
'resources/bitmap_content_layer_updater.h',
- 'resources/bitmap_raster_worker_pool.cc',
- 'resources/bitmap_raster_worker_pool.h',
'resources/bitmap_skpicture_content_layer_updater.cc',
'resources/bitmap_skpicture_content_layer_updater.h',
'resources/content_layer_updater.cc',
'resources/content_layer_updater.h',
- 'resources/eviction_tile_priority_queue.cc',
- 'resources/eviction_tile_priority_queue.h',
- 'resources/gpu_raster_worker_pool.cc',
- 'resources/gpu_raster_worker_pool.h',
'resources/image_layer_updater.cc',
'resources/image_layer_updater.h',
'resources/layer_painter.h',
- 'resources/layer_quad.cc',
- 'resources/layer_quad.h',
- 'resources/layer_tiling_data.cc',
- 'resources/layer_tiling_data.h',
'resources/layer_updater.cc',
'resources/layer_updater.h',
- 'resources/managed_tile_state.cc',
- 'resources/managed_tile_state.h',
'resources/memory_history.cc',
'resources/memory_history.h',
- 'resources/one_copy_raster_worker_pool.cc',
- 'resources/one_copy_raster_worker_pool.h',
- 'resources/picture.cc',
- 'resources/picture.h',
- 'resources/picture_layer_tiling.cc',
- 'resources/picture_layer_tiling.h',
- 'resources/picture_layer_tiling_set.cc',
- 'resources/picture_layer_tiling_set.h',
- 'resources/picture_pile.cc',
- 'resources/picture_pile.h',
- 'resources/picture_pile_base.cc',
- 'resources/picture_pile_base.h',
- 'resources/picture_pile_impl.cc',
- 'resources/picture_pile_impl.h',
- 'resources/pixel_buffer_raster_worker_pool.cc',
- 'resources/pixel_buffer_raster_worker_pool.h',
'resources/platform_color.h',
'resources/prioritized_resource.cc',
'resources/prioritized_resource.h',
@@ -395,15 +455,6 @@
'resources/prioritized_resource_manager.h',
'resources/priority_calculator.cc',
'resources/priority_calculator.h',
- 'resources/raster_buffer.cc',
- 'resources/raster_buffer.h',
- 'resources/raster_source.h',
- 'resources/raster_tile_priority_queue.cc',
- 'resources/raster_tile_priority_queue.h',
- 'resources/raster_worker_pool.cc',
- 'resources/raster_worker_pool.h',
- 'resources/rasterizer.cc',
- 'resources/rasterizer.h',
'resources/release_callback.h',
'resources/resource.cc',
'resources/resource.h',
@@ -420,8 +471,6 @@
'resources/resource_update_queue.cc',
'resources/resource_update_queue.h',
'resources/returned_resource.h',
- 'resources/scoped_gpu_raster.cc',
- 'resources/scoped_gpu_raster.h',
'resources/scoped_resource.cc',
'resources/scoped_resource.h',
'resources/scoped_ui_resource.cc',
@@ -435,20 +484,10 @@
'resources/single_release_callback_impl.h',
'resources/skpicture_content_layer_updater.cc',
'resources/skpicture_content_layer_updater.h',
- 'resources/task_graph_runner.cc',
- 'resources/task_graph_runner.h',
'resources/texture_mailbox.cc',
'resources/texture_mailbox.h',
- 'resources/texture_mailbox_deleter.cc',
- 'resources/texture_mailbox_deleter.h',
'resources/texture_uploader.cc',
'resources/texture_uploader.h',
- 'resources/tile.cc',
- 'resources/tile.h',
- 'resources/tile_manager.cc',
- 'resources/tile_manager.h',
- 'resources/tile_priority.cc',
- 'resources/tile_priority.h',
'resources/transferable_resource.cc',
'resources/transferable_resource.h',
'resources/ui_resource_bitmap.cc',
@@ -458,10 +497,9 @@
'resources/ui_resource_request.h',
'resources/video_resource_updater.cc',
'resources/video_resource_updater.h',
- 'resources/zero_copy_raster_worker_pool.cc',
- 'resources/zero_copy_raster_worker_pool.h',
'scheduler/begin_frame_source.cc',
'scheduler/begin_frame_source.h',
+ 'scheduler/commit_earlyout_reason.h',
'scheduler/delay_based_time_source.cc',
'scheduler/delay_based_time_source.h',
'scheduler/draw_result.h',
@@ -471,12 +509,45 @@
'scheduler/scheduler_settings.h',
'scheduler/scheduler_state_machine.cc',
'scheduler/scheduler_state_machine.h',
+ 'scheduler/video_frame_controller.h',
+ 'tiles/eviction_tile_priority_queue.cc',
+ 'tiles/eviction_tile_priority_queue.h',
+ 'tiles/layer_tiling_data.cc',
+ 'tiles/layer_tiling_data.h',
+ 'tiles/picture_layer_tiling.cc',
+ 'tiles/picture_layer_tiling.h',
+ 'tiles/picture_layer_tiling_set.cc',
+ 'tiles/picture_layer_tiling_set.h',
+ 'tiles/prioritized_tile.cc',
+ 'tiles/prioritized_tile.h',
+ 'tiles/raster_tile_priority_queue.cc',
+ 'tiles/raster_tile_priority_queue.h',
+ 'tiles/raster_tile_priority_queue_all.cc',
+ 'tiles/raster_tile_priority_queue_all.h',
+ 'tiles/raster_tile_priority_queue_required.cc',
+ 'tiles/raster_tile_priority_queue_required.h',
+ 'tiles/tile.cc',
+ 'tiles/tile.h',
+ 'tiles/tile_draw_info.cc',
+ 'tiles/tile_draw_info.h',
+ 'tiles/tile_manager.cc',
+ 'tiles/tile_manager.h',
+ 'tiles/tile_priority.cc',
+ 'tiles/tile_priority.h',
+ 'tiles/tiling_set_eviction_queue.cc',
+ 'tiles/tiling_set_eviction_queue.h',
+ 'tiles/tiling_set_raster_queue_all.cc',
+ 'tiles/tiling_set_raster_queue_all.h',
+ 'tiles/tiling_set_raster_queue_required.cc',
+ 'tiles/tiling_set_raster_queue_required.h',
'trees/blocking_task_runner.cc',
'trees/blocking_task_runner.h',
'trees/damage_tracker.cc',
'trees/damage_tracker.h',
- 'trees/layer_sorter.cc',
- 'trees/layer_sorter.h',
+ 'trees/draw_property_utils.cc',
+ 'trees/draw_property_utils.h',
+ 'trees/latency_info_swap_promise_monitor.cc',
+ 'trees/latency_info_swap_promise_monitor.h',
'trees/layer_tree_host.cc',
'trees/layer_tree_host.h',
'trees/layer_tree_host_client.h',
@@ -484,6 +555,7 @@
'trees/layer_tree_host_common.h',
'trees/layer_tree_host_impl.cc',
'trees/layer_tree_host_impl.h',
+ 'trees/layer_tree_host_single_thread_client.h',
'trees/layer_tree_impl.cc',
'trees/layer_tree_impl.h',
'trees/layer_tree_settings.cc',
@@ -492,6 +564,10 @@
'trees/occlusion.h',
'trees/occlusion_tracker.cc',
'trees/occlusion_tracker.h',
+ 'trees/property_tree.cc',
+ 'trees/property_tree.h',
+ 'trees/property_tree_builder.cc',
+ 'trees/property_tree_builder.h',
'trees/proxy.cc',
'trees/proxy.h',
'trees/proxy_timing_history.cc',
@@ -499,6 +575,8 @@
'trees/scoped_abort_remaining_swap_promises.h',
'trees/single_thread_proxy.cc',
'trees/single_thread_proxy.h',
+ 'trees/swap_promise_monitor.cc',
+ 'trees/swap_promise_monitor.h',
'trees/thread_proxy.cc',
'trees/thread_proxy.h',
'trees/tree_synchronizer.cc',
@@ -531,10 +609,14 @@
'surfaces/display.cc',
'surfaces/display.h',
'surfaces/display_client.h',
+ 'surfaces/onscreen_display_client.cc',
+ 'surfaces/onscreen_display_client.h',
'surfaces/surface.cc',
'surfaces/surface.h',
'surfaces/surface_aggregator.cc',
'surfaces/surface_aggregator.h',
+ 'surfaces/surface_display_output_surface.cc',
+ 'surfaces/surface_display_output_surface.h',
'surfaces/surface_factory.cc',
'surfaces/surface_factory.h',
'surfaces/surface_factory_client.h',
@@ -551,5 +633,41 @@
'../build/android/increase_size_for_speed.gypi',
],
},
+ {
+ 'target_name': 'cc_opts',
+ 'type': 'static_library',
+ 'conditions': [
+ ['target_arch == "ia32" or target_arch == "x64"', {
+ 'defines': [
+ 'CC_IMPLEMENTATION=1',
+ ],
+ 'dependencies': [
+ 'cc_opts_sse',
+ ]
+ }],
+ ],
+ },
+ {
+ 'target_name': 'cc_opts_sse',
+ 'type': 'static_library',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ ],
+ 'conditions': [
+ ['target_arch == "ia32" or target_arch == "x64"', {
+ 'defines': [
+ 'CC_IMPLEMENTATION=1',
+ ],
+ 'sources': [
+ # Conditional compilation for SSE2 code on x86 and x64 machines
+ 'raster/texture_compressor_etc1_sse.cc',
+ 'raster/texture_compressor_etc1_sse.h',
+ ],
+ 'cflags': [
+ '-msse2',
+ ],
+ }],
+ ],
+ },
],
}
diff --git a/chromium/cc/cc_tests.gyp b/chromium/cc/cc_tests.gyp
index 75267ef2874..5ded2b81fc5 100644
--- a/chromium/cc/cc_tests.gyp
+++ b/chromium/cc/cc_tests.gyp
@@ -23,6 +23,7 @@
'base/tiling_data_unittest.cc',
'base/unique_notifier_unittest.cc',
'base/util_unittest.cc',
+ 'debug/frame_timing_tracker_unittest.cc',
'debug/micro_benchmark_controller_unittest.cc',
'debug/rendering_stats_unittest.cc',
'input/top_controls_manager_unittest.cc',
@@ -31,8 +32,8 @@
'layers/delegated_frame_resource_collection_unittest.cc',
'layers/delegated_renderer_layer_impl_unittest.cc',
'layers/delegated_renderer_layer_unittest.cc',
- 'layers/heads_up_display_unittest.cc',
'layers/heads_up_display_layer_impl_unittest.cc',
+ 'layers/heads_up_display_unittest.cc',
'layers/io_surface_layer_impl_unittest.cc',
'layers/layer_impl_unittest.cc',
'layers/layer_iterator_unittest.cc',
@@ -43,17 +44,18 @@
'layers/nine_patch_layer_unittest.cc',
'layers/painted_scrollbar_layer_impl_unittest.cc',
'layers/picture_image_layer_impl_unittest.cc',
+ 'layers/picture_image_layer_unittest.cc',
'layers/picture_layer_impl_unittest.cc',
'layers/picture_layer_unittest.cc',
- 'layers/render_surface_unittest.cc',
'layers/render_surface_impl_unittest.cc',
+ 'layers/render_surface_unittest.cc',
'layers/scrollbar_layer_unittest.cc',
'layers/solid_color_layer_impl_unittest.cc',
'layers/solid_color_scrollbar_layer_impl_unittest.cc',
- 'layers/surface_layer_unittest.cc',
'layers/surface_layer_impl_unittest.cc',
- 'layers/texture_layer_unittest.cc',
+ 'layers/surface_layer_unittest.cc',
'layers/texture_layer_impl_unittest.cc',
+ 'layers/texture_layer_unittest.cc',
'layers/tiled_layer_impl_unittest.cc',
'layers/tiled_layer_unittest.cc',
'layers/ui_resource_layer_impl_unittest.cc',
@@ -64,32 +66,35 @@
'output/delegating_renderer_unittest.cc',
'output/filter_operations_unittest.cc',
'output/gl_renderer_unittest.cc',
+ 'output/layer_quad_unittest.cc',
'output/output_surface_unittest.cc',
'output/overlay_unittest.cc',
'output/renderer_pixeltest.cc',
'output/renderer_unittest.cc',
'output/shader_unittest.cc',
'output/software_renderer_unittest.cc',
+ 'output/texture_mailbox_deleter_unittest.cc',
+ 'playback/display_item_list_unittest.cc',
+ 'playback/display_list_recording_source_unittest.cc',
+ 'playback/picture_pile_impl_unittest.cc',
+ 'playback/picture_pile_unittest.cc',
+ 'playback/picture_unittest.cc',
+ 'playback/pixel_ref_map_unittest.cc',
+ 'playback/recording_source_unittest.cc',
'quads/draw_polygon_unittest.cc',
'quads/draw_quad_unittest.cc',
'quads/list_container_unittest.cc',
'quads/render_pass_unittest.cc',
- 'resources/layer_quad_unittest.cc',
- 'resources/picture_layer_tiling_set_unittest.cc',
- 'resources/picture_layer_tiling_unittest.cc',
- 'resources/picture_pile_impl_unittest.cc',
- 'resources/picture_pile_unittest.cc',
- 'resources/picture_unittest.cc',
+ 'raster/scoped_gpu_raster_unittest.cc',
+ 'raster/task_graph_runner_unittest.cc',
+ 'raster/texture_compressor_etc1_unittest.cc',
+ 'raster/tile_task_worker_pool_unittest.cc',
+ 'resources/platform_color_unittest.cc',
'resources/prioritized_resource_unittest.cc',
- 'resources/raster_worker_pool_unittest.cc',
'resources/resource_provider_unittest.cc',
'resources/resource_update_controller_unittest.cc',
'resources/scoped_resource_unittest.cc',
- 'resources/task_graph_runner_unittest.cc',
- 'resources/texture_mailbox_deleter_unittest.cc',
'resources/texture_uploader_unittest.cc',
- 'resources/tile_manager_unittest.cc',
- 'resources/tile_priority_unittest.cc',
'resources/video_resource_updater_unittest.cc',
'scheduler/begin_frame_source_unittest.cc',
'scheduler/delay_based_time_source_unittest.cc',
@@ -98,15 +103,17 @@
'test/layer_tree_json_parser_unittest.cc',
'test/ordered_simple_task_runner_unittest.cc',
'test/test_web_graphics_context_3d_unittest.cc',
+ 'tiles/picture_layer_tiling_set_unittest.cc',
+ 'tiles/picture_layer_tiling_unittest.cc',
+ 'tiles/tile_manager_unittest.cc',
+ 'tiles/tile_priority_unittest.cc',
'trees/blocking_task_runner_unittest.cc',
'trees/damage_tracker_unittest.cc',
- 'trees/layer_sorter_unittest.cc',
'trees/layer_tree_host_common_unittest.cc',
'trees/layer_tree_host_impl_unittest.cc',
'trees/layer_tree_host_pixeltest_blending.cc',
'trees/layer_tree_host_pixeltest_filters.cc',
'trees/layer_tree_host_pixeltest_masks.cc',
- 'trees/layer_tree_host_pixeltest_on_demand_raster.cc',
'trees/layer_tree_host_pixeltest_readback.cc',
'trees/layer_tree_host_pixeltest_synchronous.cc',
'trees/layer_tree_host_unittest.cc',
@@ -115,8 +122,8 @@
'trees/layer_tree_host_unittest_copyrequest.cc',
'trees/layer_tree_host_unittest_damage.cc',
'trees/layer_tree_host_unittest_delegated.cc',
- 'trees/layer_tree_host_unittest_occlusion.cc',
'trees/layer_tree_host_unittest_no_message_loop.cc',
+ 'trees/layer_tree_host_unittest_occlusion.cc',
'trees/layer_tree_host_unittest_picture.cc',
'trees/layer_tree_host_unittest_proxy.cc',
'trees/layer_tree_host_unittest_scroll.cc',
@@ -124,12 +131,15 @@
'trees/layer_tree_impl_unittest.cc',
'trees/occlusion_tracker_unittest.cc',
'trees/occlusion_unittest.cc',
+ 'trees/property_tree_unittest.cc',
'trees/tree_synchronizer_unittest.cc',
],
'cc_surfaces_unit_tests_source_files': [
+ 'surfaces/display_unittest.cc',
'surfaces/surface_aggregator_test_helpers.cc',
'surfaces/surface_aggregator_test_helpers.h',
'surfaces/surface_aggregator_unittest.cc',
+ 'surfaces/surface_display_output_surface_unittest.cc',
'surfaces/surface_factory_unittest.cc',
'surfaces/surface_unittest.cc',
'surfaces/surfaces_pixeltest.cc',
@@ -139,6 +149,8 @@
'test/animation_test_common.h',
'test/begin_frame_args_test.cc',
'test/begin_frame_args_test.h',
+ 'test/failure_output_surface.cc',
+ 'test/failure_output_surface.h',
'test/fake_content_layer.cc',
'test/fake_content_layer.h',
'test/fake_content_layer_client.cc',
@@ -149,6 +161,9 @@
'test/fake_delegated_renderer_layer.h',
'test/fake_delegated_renderer_layer_impl.cc',
'test/fake_delegated_renderer_layer_impl.h',
+ 'test/fake_display_list_recording_source.h',
+ 'test/fake_external_begin_frame_source.cc',
+ 'test/fake_external_begin_frame_source.h',
'test/fake_impl_proxy.h',
'test/fake_layer_tree_host.cc',
'test/fake_layer_tree_host.h',
@@ -170,6 +185,8 @@
'test/fake_picture_layer_impl.h',
'test/fake_picture_layer_tiling_client.cc',
'test/fake_picture_layer_tiling_client.h',
+ 'test/fake_picture_pile.cc',
+ 'test/fake_picture_pile.h',
'test/fake_picture_pile_impl.cc',
'test/fake_picture_pile_impl.h',
'test/fake_proxy.cc',
@@ -191,8 +208,6 @@
'test/fake_video_frame_provider.h',
'test/geometry_test_utils.cc',
'test/geometry_test_utils.h',
- 'test/test_in_process_context_provider.cc',
- 'test/test_in_process_context_provider.h',
'test/impl_side_painting_settings.h',
'test/layer_test_common.cc',
'test/layer_test_common.h',
@@ -243,11 +258,15 @@
'test/test_gpu_memory_buffer_manager.h',
'test/test_image_factory.cc',
'test/test_image_factory.h',
+ 'test/test_in_process_context_provider.cc',
+ 'test/test_in_process_context_provider.h',
'test/test_now_source.cc',
'test/test_now_source.h',
'test/test_occlusion_tracker.h',
'test/test_shared_bitmap_manager.cc',
'test/test_shared_bitmap_manager.h',
+ 'test/test_task_graph_runner.cc',
+ 'test/test_task_graph_runner.h',
'test/test_texture.cc',
'test/test_texture.h',
'test/test_tile_priorities.cc',
@@ -279,8 +298,8 @@
'cc_test_support',
],
'sources': [
- 'test/run_all_unittests.cc',
'test/cc_test_suite.cc',
+ 'test/run_all_unittests.cc',
'<@(cc_unit_tests_source_files)',
'<@(cc_surfaces_unit_tests_source_files)',
],
@@ -330,19 +349,22 @@
'../ui/gfx/gfx.gyp:gfx',
'../ui/gfx/gfx.gyp:gfx_geometry',
'cc.gyp:cc',
+ 'cc.gyp:cc_surfaces',
'cc_test_support',
],
'sources': [
# Note: sources list duplicated in GN build.
'layers/layer_perftest.cc',
'layers/picture_layer_impl_perftest.cc',
- 'resources/picture_layer_tiling_perftest.cc',
- 'resources/picture_pile_impl_perftest.cc',
- 'resources/raster_worker_pool_perftest.cc',
- 'resources/task_graph_runner_perftest.cc',
- 'resources/tile_manager_perftest.cc',
+ 'playback/picture_pile_impl_perftest.cc',
+ 'raster/task_graph_runner_perftest.cc',
+ 'raster/texture_compressor_perftest.cc',
+ 'raster/tile_task_worker_pool_perftest.cc',
+ 'surfaces/surface_aggregator_perftest.cc',
'test/cc_test_suite.cc',
'test/run_all_perftests.cc',
+ 'tiles/picture_layer_tiling_perftest.cc',
+ 'tiles/tile_manager_perftest.cc',
'trees/layer_tree_host_common_perftest.cc',
'trees/layer_tree_host_perftest.cc',
'trees/occlusion_tracker_perftest.cc',
@@ -433,6 +455,34 @@
},
],
}
- ]
+ ],
+ ['test_isolation_mode != "noop"', {
+ 'targets': [
+ {
+ 'target_name': 'cc_unittests_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'cc_unittests',
+ ],
+ 'includes': [
+ '../build/isolate.gypi',
+ ],
+ 'sources': [
+ 'cc_unittests.isolate',
+ ],
+ 'conditions': [
+ # crbug.com/464062 xdisplaycheck is used to run cc_unittests_run on
+ # the linux try bots when using X11.
+ ['OS=="linux" and use_ozone==0',
+ {
+ 'dependencies': [
+ '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
+ ],
+ }
+ ],
+ ],
+ },
+ ],
+ }],
],
}
diff --git a/chromium/cc/cc_unittests.isolate b/chromium/cc/cc_unittests.isolate
new file mode 100644
index 00000000000..7c359d04462
--- /dev/null
+++ b/chromium/cc/cc_unittests.isolate
@@ -0,0 +1,89 @@
+# 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.
+{
+ 'conditions': [
+ ['use_x11==0', {
+ 'variables': {
+ 'command': [
+ '../testing/test_env.py',
+ '<(PRODUCT_DIR)/cc_unittests<(EXECUTABLE_SUFFIX)',
+ '--brave-new-test-launcher',
+ '--test-launcher-bot-mode',
+ '--asan=<(asan)',
+ '--msan=<(msan)',
+ '--tsan=<(tsan)',
+ ],
+ },
+ }],
+ ['use_x11==1', {
+ 'variables': {
+ 'command': [
+ '../testing/xvfb.py',
+ '<(PRODUCT_DIR)',
+ '<(PRODUCT_DIR)/cc_unittests',
+ '--brave-new-test-launcher',
+ '--test-launcher-bot-mode',
+ '--asan=<(asan)',
+ '--msan=<(msan)',
+ '--tsan=<(tsan)',
+ ],
+ 'files': [
+ '../testing/xvfb.py',
+ '<(PRODUCT_DIR)/xdisplaycheck',
+ ],
+ },
+ }],
+ ['OS=="linux" or OS=="mac" or OS=="win"', {
+ 'variables': {
+ 'files': [
+ 'test/data/',
+ '../testing/test_env.py',
+ '<(PRODUCT_DIR)/cc_unittests<(EXECUTABLE_SUFFIX)',
+ ],
+ },
+ }],
+ ['OS=="linux"', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/libffmpegsumo.so',
+ '<(PRODUCT_DIR)/libosmesa.so',
+ ],
+ },
+ }],
+ ['OS=="mac"', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/ffmpegsumo.so',
+ '<(PRODUCT_DIR)/osmesa.so',
+ ],
+ },
+ }],
+ ['OS=="win"', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/ffmpegsumo.dll',
+ '<(PRODUCT_DIR)/osmesa.dll',
+ ],
+ },
+ }],
+ ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/cc_unittests.exe.pdb',
+ ],
+ },
+ }],
+ ['OS=="mac" and asan==1 and fastbuild==0', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/cc_unittests.dSYM/',
+ ],
+ },
+ }],
+ ],
+ 'includes': [
+ '../base/base.isolate',
+ '../third_party/angle/angle.isolate',
+ ],
+}
diff --git a/chromium/cc/debug/benchmark_instrumentation.cc b/chromium/cc/debug/benchmark_instrumentation.cc
index 74caae8bcc2..5a04e214ed1 100644
--- a/chromium/cc/debug/benchmark_instrumentation.cc
+++ b/chromium/cc/debug/benchmark_instrumentation.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/debug/benchmark_instrumentation.h"
namespace cc {
@@ -12,16 +12,7 @@ namespace benchmark_instrumentation {
// tools/perf/measurements/rendering_stats.py accordingly.
// The benchmarks search for events and their arguments by name.
-void IssueMainThreadRenderingStatsEvent(
- const RenderingStats::MainThreadRenderingStats& stats) {
- TRACE_EVENT_INSTANT1("benchmark",
- "BenchmarkInstrumentation::MainThreadRenderingStats",
- TRACE_EVENT_SCOPE_THREAD,
- "data", stats.AsTraceableData());
-}
-
-void IssueImplThreadRenderingStatsEvent(
- const RenderingStats::ImplThreadRenderingStats& stats) {
+void IssueImplThreadRenderingStatsEvent(const RenderingStats& stats) {
TRACE_EVENT_INSTANT1("benchmark",
"BenchmarkInstrumentation::ImplThreadRenderingStats",
TRACE_EVENT_SCOPE_THREAD,
@@ -29,15 +20,15 @@ void IssueImplThreadRenderingStatsEvent(
}
void IssueDisplayRenderingStatsEvent() {
- scoped_refptr<base::debug::TracedValue> record_data =
- new base::debug::TracedValue();
+ scoped_refptr<base::trace_event::TracedValue> record_data =
+ new base::trace_event::TracedValue();
record_data->SetInteger("frame_count", 1);
TRACE_EVENT_INSTANT1(
"benchmark",
"BenchmarkInstrumentation::DisplayRenderingStats",
TRACE_EVENT_SCOPE_THREAD,
"data",
- scoped_refptr<base::debug::ConvertableToTraceFormat>(record_data));
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>(record_data));
}
} // namespace benchmark_instrumentation
diff --git a/chromium/cc/debug/benchmark_instrumentation.h b/chromium/cc/debug/benchmark_instrumentation.h
index bd524b99042..944ac66d216 100644
--- a/chromium/cc/debug/benchmark_instrumentation.h
+++ b/chromium/cc/debug/benchmark_instrumentation.h
@@ -42,10 +42,7 @@ class ScopedBeginFrameTask {
DISALLOW_COPY_AND_ASSIGN(ScopedBeginFrameTask);
};
-void IssueMainThreadRenderingStatsEvent(
- const RenderingStats::MainThreadRenderingStats& stats);
-void IssueImplThreadRenderingStatsEvent(
- const RenderingStats::ImplThreadRenderingStats& stats);
+void IssueImplThreadRenderingStatsEvent(const RenderingStats& stats);
void CC_EXPORT IssueDisplayRenderingStatsEvent();
} // namespace benchmark_instrumentation
diff --git a/chromium/cc/debug/debug_colors.cc b/chromium/cc/debug/debug_colors.cc
index 6cbbfe9431d..38ecf54c853 100644
--- a/chromium/cc/debug/debug_colors.cc
+++ b/chromium/cc/debug/debug_colors.cc
@@ -114,9 +114,9 @@ int DebugColors::ExtraLowResTileBorderWidth(const LayerTreeImpl* tree_impl) {
return Scale(2, tree_impl);
}
-// Missing tile borders are red.
+// Missing tile borders are dark grey.
SkColor DebugColors::MissingTileBorderColor() {
- return SkColorSetARGB(100, 255, 0, 0);
+ return SkColorSetARGB(64, 64, 64, 0);
}
int DebugColors::MissingTileBorderWidth(const LayerTreeImpl* tree_impl) {
return Scale(1, tree_impl);
@@ -130,11 +130,11 @@ int DebugColors::SolidColorTileBorderWidth(const LayerTreeImpl* tree_impl) {
return Scale(1, tree_impl);
}
-// Picture tile borders are dark grey.
-SkColor DebugColors::PictureTileBorderColor() {
- return SkColorSetARGB(64, 64, 64, 0);
+// OOM tile borders are red.
+SkColor DebugColors::OOMTileBorderColor() {
+ return SkColorSetARGB(100, 255, 0, 0);
}
-int DebugColors::PictureTileBorderWidth(const LayerTreeImpl* tree_impl) {
+int DebugColors::OOMTileBorderWidth(const LayerTreeImpl* tree_impl) {
return Scale(1, tree_impl);
}
@@ -216,24 +216,6 @@ SkColor DebugColors::ScreenSpaceSurfaceReplicaRectFillColor() {
return SkColorSetARGB(10, 100, 0, 200);
}
-// Occluding rects in pink.
-SkColor DebugColors::OccludingRectBorderColor() {
- return SkColorSetARGB(255, 245, 136, 255);
-}
-int DebugColors::OccludingRectBorderWidth() { return 2; }
-SkColor DebugColors::OccludingRectFillColor() {
- return SkColorSetARGB(10, 245, 136, 255);
-}
-
-// Non-Occluding rects in a reddish color.
-SkColor DebugColors::NonOccludingRectBorderColor() {
- return SkColorSetARGB(255, 200, 0, 100);
-}
-int DebugColors::NonOccludingRectBorderWidth() { return 2; }
-SkColor DebugColors::NonOccludingRectFillColor() {
- return SkColorSetARGB(10, 200, 0, 100);
-}
-
// Touch-event-handler rects in yellow.
SkColor DebugColors::TouchEventHandlerRectBorderColor() {
return SkColorSetARGB(255, 239, 229, 60);
diff --git a/chromium/cc/debug/debug_colors.h b/chromium/cc/debug/debug_colors.h
index 3b00d841bb2..8e4ec8dbf54 100644
--- a/chromium/cc/debug/debug_colors.h
+++ b/chromium/cc/debug/debug_colors.h
@@ -56,8 +56,8 @@ class DebugColors {
static SkColor SolidColorTileBorderColor();
static int SolidColorTileBorderWidth(const LayerTreeImpl* tree_impl);
- static SkColor PictureTileBorderColor();
- static int PictureTileBorderWidth(const LayerTreeImpl* tree_impl);
+ static SkColor OOMTileBorderColor();
+ static int OOMTileBorderWidth(const LayerTreeImpl* tree_impl);
static SkColor DirectPictureBorderColor();
static int DirectPictureBorderWidth(const LayerTreeImpl* tree_impl);
@@ -87,14 +87,6 @@ class DebugColors {
static int ScreenSpaceSurfaceReplicaRectBorderWidth();
static SkColor ScreenSpaceSurfaceReplicaRectFillColor();
- static SkColor OccludingRectBorderColor();
- static int OccludingRectBorderWidth();
- static SkColor OccludingRectFillColor();
-
- static SkColor NonOccludingRectBorderColor();
- static int NonOccludingRectBorderWidth();
- static SkColor NonOccludingRectFillColor();
-
static SkColor TouchEventHandlerRectBorderColor();
static int TouchEventHandlerRectBorderWidth();
static SkColor TouchEventHandlerRectFillColor();
diff --git a/chromium/cc/debug/debug_rect_history.cc b/chromium/cc/debug/debug_rect_history.cc
index a8c50306134..c257c60c5cf 100644
--- a/chromium/cc/debug/debug_rect_history.cc
+++ b/chromium/cc/debug/debug_rect_history.cc
@@ -29,8 +29,6 @@ void DebugRectHistory::SaveDebugRectsForCurrentFrame(
LayerImpl* root_layer,
LayerImpl* hud_layer,
const LayerImplList& render_surface_layer_list,
- const std::vector<gfx::Rect>& occluding_screen_space_rects,
- const std::vector<gfx::Rect>& non_occluding_screen_space_rects,
const LayerTreeDebugState& debug_state) {
// For now, clear all rects from previous frames. In the future we may want to
// store all debug rects for a history of many frames.
@@ -60,12 +58,6 @@ void DebugRectHistory::SaveDebugRectsForCurrentFrame(
if (debug_state.show_screen_space_rects)
SaveScreenSpaceRects(render_surface_layer_list);
- if (debug_state.show_occluding_rects)
- SaveOccludingRects(occluding_screen_space_rects);
-
- if (debug_state.show_non_occluding_rects)
- SaveNonOccludingRects(non_occluding_screen_space_rects);
-
if (debug_state.show_layer_animation_bounds_rects)
SaveLayerAnimationBoundsRects(render_surface_layer_list);
}
@@ -76,17 +68,21 @@ void DebugRectHistory::SavePaintRects(LayerImpl* layer) {
// not. Therefore we traverse recursively over all layers, not just the render
// surface list.
- if (!layer->update_rect().IsEmpty() && layer->DrawsContent()) {
+ Region invalidation_region = layer->GetInvalidationRegion();
+ if (!invalidation_region.IsEmpty() && layer->DrawsContent()) {
float width_scale = layer->content_bounds().width() /
static_cast<float>(layer->bounds().width());
float height_scale = layer->content_bounds().height() /
static_cast<float>(layer->bounds().height());
- gfx::Rect update_content_rect = gfx::ScaleToEnclosingRect(
- layer->update_rect(), width_scale, height_scale);
- debug_rects_.push_back(
- DebugRect(PAINT_RECT_TYPE,
- MathUtil::MapEnclosingClippedRect(
- layer->screen_space_transform(), update_content_rect)));
+
+ for (Region::Iterator it(invalidation_region); it.has_rect(); it.next()) {
+ gfx::Rect update_content_rect =
+ gfx::ScaleToEnclosingRect(it.rect(), width_scale, height_scale);
+ debug_rects_.push_back(
+ DebugRect(PAINT_RECT_TYPE,
+ MathUtil::MapEnclosingClippedRect(
+ layer->screen_space_transform(), update_content_rect)));
+ }
}
for (unsigned i = 0; i < layer->children().size(); ++i)
@@ -170,25 +166,10 @@ void DebugRectHistory::SaveScreenSpaceRects(
}
}
-void DebugRectHistory::SaveOccludingRects(
- const std::vector<gfx::Rect>& occluding_rects) {
- for (size_t i = 0; i < occluding_rects.size(); ++i)
- debug_rects_.push_back(DebugRect(OCCLUDING_RECT_TYPE, occluding_rects[i]));
-}
-
-void DebugRectHistory::SaveNonOccludingRects(
- const std::vector<gfx::Rect>& non_occluding_rects) {
- for (size_t i = 0; i < non_occluding_rects.size(); ++i) {
- debug_rects_.push_back(
- DebugRect(NONOCCLUDING_RECT_TYPE, non_occluding_rects[i]));
- }
-}
-
void DebugRectHistory::SaveTouchEventHandlerRects(LayerImpl* layer) {
- LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
- layer,
- base::Bind(&DebugRectHistory::SaveTouchEventHandlerRectsCallback,
- base::Unretained(this)));
+ LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) {
+ SaveTouchEventHandlerRectsCallback(layer);
+ });
}
void DebugRectHistory::SaveTouchEventHandlerRectsCallback(LayerImpl* layer) {
@@ -205,10 +186,9 @@ void DebugRectHistory::SaveTouchEventHandlerRectsCallback(LayerImpl* layer) {
}
void DebugRectHistory::SaveWheelEventHandlerRects(LayerImpl* layer) {
- LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
- layer,
- base::Bind(&DebugRectHistory::SaveWheelEventHandlerRectsCallback,
- base::Unretained(this)));
+ LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) {
+ SaveWheelEventHandlerRectsCallback(layer);
+ });
}
void DebugRectHistory::SaveWheelEventHandlerRectsCallback(LayerImpl* layer) {
@@ -226,10 +206,9 @@ void DebugRectHistory::SaveWheelEventHandlerRectsCallback(LayerImpl* layer) {
}
void DebugRectHistory::SaveScrollEventHandlerRects(LayerImpl* layer) {
- LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
- layer,
- base::Bind(&DebugRectHistory::SaveScrollEventHandlerRectsCallback,
- base::Unretained(this)));
+ LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) {
+ SaveScrollEventHandlerRectsCallback(layer);
+ });
}
void DebugRectHistory::SaveScrollEventHandlerRectsCallback(LayerImpl* layer) {
@@ -247,10 +226,9 @@ void DebugRectHistory::SaveScrollEventHandlerRectsCallback(LayerImpl* layer) {
}
void DebugRectHistory::SaveNonFastScrollableRects(LayerImpl* layer) {
- LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
- layer,
- base::Bind(&DebugRectHistory::SaveNonFastScrollableRectsCallback,
- base::Unretained(this)));
+ LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) {
+ SaveNonFastScrollableRectsCallback(layer);
+ });
}
void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) {
diff --git a/chromium/cc/debug/debug_rect_history.h b/chromium/cc/debug/debug_rect_history.h
index 6d25b2964db..6bcf4385345 100644
--- a/chromium/cc/debug/debug_rect_history.h
+++ b/chromium/cc/debug/debug_rect_history.h
@@ -34,21 +34,12 @@ class LayerTreeDebugState;
//
// - Replica screen space rects: this is the region the replica's contents
// occupy in screen space.
-//
-// - Occluding rects: these are the regions that contribute to the occluded
-// region.
-//
-// - Non-Occluding rects: these are the regions of composited layers that do not
-// contribute to the occluded region.
-//
enum DebugRectType {
PAINT_RECT_TYPE,
PROPERTY_CHANGED_RECT_TYPE,
SURFACE_DAMAGE_RECT_TYPE,
SCREEN_SPACE_RECT_TYPE,
REPLICA_SCREEN_SPACE_RECT_TYPE,
- OCCLUDING_RECT_TYPE,
- NONOCCLUDING_RECT_TYPE,
TOUCH_EVENT_HANDLER_RECT_TYPE,
WHEEL_EVENT_HANDLER_RECT_TYPE,
SCROLL_EVENT_HANDLER_RECT_TYPE,
@@ -79,8 +70,6 @@ class DebugRectHistory {
LayerImpl* root_layer,
LayerImpl* hud_layer,
const LayerImplList& render_surface_layer_list,
- const std::vector<gfx::Rect>& occluding_screen_space_rects,
- const std::vector<gfx::Rect>& non_occluding_screen_space_rects,
const LayerTreeDebugState& debug_state);
const std::vector<DebugRect>& debug_rects() { return debug_rects_; }
@@ -95,10 +84,6 @@ class DebugRectHistory {
const LayerImplList& render_surface_layer_list);
void SaveScreenSpaceRects(
const LayerImplList& render_surface_layer_list);
- void SaveOccludingRects(
- const std::vector<gfx::Rect>& occluding_screen_space_rects);
- void SaveNonOccludingRects(
- const std::vector<gfx::Rect>& non_occluding_screen_space_rects);
void SaveTouchEventHandlerRects(LayerImpl* layer);
void SaveTouchEventHandlerRectsCallback(LayerImpl* layer);
void SaveWheelEventHandlerRects(LayerImpl* layer);
diff --git a/chromium/cc/debug/devtools_instrumentation.h b/chromium/cc/debug/devtools_instrumentation.h
index 85a9850f20b..f1faf6ff424 100644
--- a/chromium/cc/debug/devtools_instrumentation.h
+++ b/chromium/cc/debug/devtools_instrumentation.h
@@ -5,7 +5,8 @@
#ifndef CC_DEBUG_DEVTOOLS_INSTRUMENTATION_H_
#define CC_DEBUG_DEVTOOLS_INSTRUMENTATION_H_
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
namespace cc {
namespace devtools_instrumentation {
@@ -14,6 +15,7 @@ namespace internal {
const char kCategory[] = TRACE_DISABLED_BY_DEFAULT("devtools.timeline");
const char kCategoryFrame[] =
TRACE_DISABLED_BY_DEFAULT("devtools.timeline.frame");
+const char kData[] = "data";
const char kFrameId[] = "frameId";
const char kLayerId[] = "layerId";
const char kLayerTreeId[] = "layerTreeId";
@@ -23,10 +25,11 @@ const char kImageDecodeTask[] = "ImageDecodeTask";
const char kBeginFrame[] = "BeginFrame";
const char kActivateLayerTree[] = "ActivateLayerTree";
const char kRequestMainThreadFrame[] = "RequestMainThreadFrame";
+const char kBeginMainThreadFrame[] = "BeginMainThreadFrame";
const char kDrawFrame[] = "DrawFrame";
+const char kCompositeLayers[] = "CompositeLayers";
} // namespace internal
-const char kRasterTask[] = "RasterTask";
const char kPaintSetup[] = "PaintSetup";
const char kUpdateLayer[] = "UpdateLayer";
@@ -78,10 +81,24 @@ class ScopedLayerTreeTask {
DISALLOW_COPY_AND_ASSIGN(ScopedLayerTreeTask);
};
+struct ScopedCommitTrace {
+ public:
+ explicit ScopedCommitTrace(int layer_tree_host_id) {
+ TRACE_EVENT_BEGIN1(internal::kCategory, internal::kCompositeLayers,
+ internal::kLayerTreeId, layer_tree_host_id);
+ }
+ ~ScopedCommitTrace() {
+ TRACE_EVENT_END0(internal::kCategory, internal::kCompositeLayers);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedCommitTrace);
+};
+
struct ScopedLayerObjectTracker
- : public base::debug::TraceScopedTrackableObject<int> {
+ : public base::trace_event::TraceScopedTrackableObject<int> {
explicit ScopedLayerObjectTracker(int layer_id)
- : base::debug::TraceScopedTrackableObject<int>(
+ : base::trace_event::TraceScopedTrackableObject<int>(
internal::kCategory,
internal::kLayerId,
layer_id) {
@@ -125,6 +142,21 @@ inline void DidRequestMainThreadFrame(int layer_tree_host_id) {
layer_tree_host_id);
}
+inline scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+BeginMainThreadFrameData(int frame_id) {
+ scoped_refptr<base::trace_event::TracedValue> value =
+ new base::trace_event::TracedValue();
+ value->SetInteger("frameId", frame_id);
+ return value;
+}
+
+inline void WillBeginMainThreadFrame(int layer_tree_host_id, int frame_id) {
+ TRACE_EVENT_INSTANT2(
+ internal::kCategoryFrame, internal::kBeginMainThreadFrame,
+ TRACE_EVENT_SCOPE_THREAD, internal::kLayerTreeId, layer_tree_host_id,
+ internal::kData, BeginMainThreadFrameData(frame_id));
+}
+
} // namespace devtools_instrumentation
} // namespace cc
diff --git a/chromium/cc/debug/frame_rate_counter.cc b/chromium/cc/debug/frame_rate_counter.cc
index 2f3b291fea9..c43270dcf1f 100644
--- a/chromium/cc/debug/frame_rate_counter.cc
+++ b/chromium/cc/debug/frame_rate_counter.cc
@@ -21,7 +21,7 @@ namespace cc {
// - if the frame is too slow, then there is probably not animating content, so
// we should not pollute the average.
static const double kFrameTooFast = 1.0 / 70.0;
-static const double kFrameTooSlow = 1.0 / 4.0;
+static const double kFrameTooSlow = 1.5;
// If a frame takes longer than this threshold (measured in seconds) then we
// (naively) assume that it missed a screen refresh; that is, we dropped a
diff --git a/chromium/cc/debug/frame_timing_request.cc b/chromium/cc/debug/frame_timing_request.cc
new file mode 100644
index 00000000000..6c54ea2817a
--- /dev/null
+++ b/chromium/cc/debug/frame_timing_request.cc
@@ -0,0 +1,17 @@
+// 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.
+
+#include "cc/debug/frame_timing_request.h"
+
+namespace cc {
+
+FrameTimingRequest::FrameTimingRequest() : id_(0) {
+}
+
+FrameTimingRequest::FrameTimingRequest(int64_t request_id,
+ const gfx::Rect& rect)
+ : id_(request_id), rect_(rect) {
+}
+
+} // namespace cc
diff --git a/chromium/cc/debug/frame_timing_request.h b/chromium/cc/debug/frame_timing_request.h
new file mode 100644
index 00000000000..09379980fa0
--- /dev/null
+++ b/chromium/cc/debug/frame_timing_request.h
@@ -0,0 +1,35 @@
+// 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_DEBUG_FRAME_TIMING_REQUEST_H_
+#define CC_DEBUG_FRAME_TIMING_REQUEST_H_
+
+#include "cc/base/cc_export.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace cc {
+
+// This class represents a request to record frame timing information about the
+// given rect (in layer space) and an associated request id. When this request
+// is propagated to the active LayerImpl, it will cause events to be saved in
+// FrameTimingTracker, which in turn can be consumed by the requester.
+class CC_EXPORT FrameTimingRequest {
+ public:
+ FrameTimingRequest();
+ FrameTimingRequest(int64_t request_id, const gfx::Rect& rect);
+
+ // Return the ID for the request.
+ int64_t id() const { return id_; }
+
+ // Return the layer space rect for this request.
+ const gfx::Rect& rect() const { return rect_; }
+
+ private:
+ int64_t id_;
+ gfx::Rect rect_;
+};
+
+} // namespace cc
+
+#endif // CC_DEBUG_FRAME_TIMING_REQUEST_H_
diff --git a/chromium/cc/debug/frame_timing_tracker.cc b/chromium/cc/debug/frame_timing_tracker.cc
new file mode 100644
index 00000000000..50aa92be5aa
--- /dev/null
+++ b/chromium/cc/debug/frame_timing_tracker.cc
@@ -0,0 +1,98 @@
+// 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.
+
+#include "cc/debug/frame_timing_tracker.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "base/metrics/histogram.h"
+#include "cc/trees/proxy.h"
+
+namespace cc {
+
+FrameTimingTracker::CompositeTimingEvent::CompositeTimingEvent(
+ int _frame_id,
+ base::TimeTicks _timestamp)
+ : frame_id(_frame_id), timestamp(_timestamp) {
+}
+
+FrameTimingTracker::CompositeTimingEvent::~CompositeTimingEvent() {
+}
+
+FrameTimingTracker::MainFrameTimingEvent::MainFrameTimingEvent(
+ int frame_id,
+ base::TimeTicks timestamp,
+ base::TimeTicks end_time)
+ : frame_id(frame_id), timestamp(timestamp), end_time(end_time) {
+}
+
+FrameTimingTracker::MainFrameTimingEvent::~MainFrameTimingEvent() {
+}
+
+// static
+scoped_ptr<FrameTimingTracker> FrameTimingTracker::Create() {
+ return make_scoped_ptr(new FrameTimingTracker);
+}
+
+FrameTimingTracker::FrameTimingTracker() {
+}
+
+FrameTimingTracker::~FrameTimingTracker() {
+}
+
+void FrameTimingTracker::SaveTimeStamps(
+ base::TimeTicks timestamp,
+ const std::vector<FrameAndRectIds>& frame_ids) {
+ if (!composite_events_)
+ composite_events_.reset(new CompositeTimingSet);
+ for (const auto& pair : frame_ids) {
+ (*composite_events_)[pair.second].push_back(
+ CompositeTimingEvent(pair.first, timestamp));
+ }
+}
+
+void FrameTimingTracker::SaveMainFrameTimeStamps(
+ const std::vector<int64_t>& request_ids,
+ base::TimeTicks main_frame_time,
+ base::TimeTicks end_time,
+ int source_frame_number) {
+ if (!main_frame_events_)
+ main_frame_events_.reset(new MainFrameTimingSet);
+ for (const auto& request : request_ids) {
+ std::vector<MainFrameTimingEvent>& events = (*main_frame_events_)[request];
+ events.push_back(
+ MainFrameTimingEvent(source_frame_number, main_frame_time, end_time));
+ }
+}
+
+scoped_ptr<FrameTimingTracker::CompositeTimingSet>
+FrameTimingTracker::GroupCompositeCountsByRectId() {
+ if (!composite_events_)
+ return make_scoped_ptr(new CompositeTimingSet);
+ for (auto& infos : *composite_events_) {
+ std::sort(
+ infos.second.begin(), infos.second.end(),
+ [](const CompositeTimingEvent& lhs, const CompositeTimingEvent& rhs) {
+ return lhs.timestamp < rhs.timestamp;
+ });
+ }
+ return composite_events_.Pass();
+}
+
+scoped_ptr<FrameTimingTracker::MainFrameTimingSet>
+FrameTimingTracker::GroupMainFrameCountsByRectId() {
+ if (!main_frame_events_)
+ return make_scoped_ptr(new MainFrameTimingSet);
+ for (auto& infos : *main_frame_events_) {
+ std::sort(
+ infos.second.begin(), infos.second.end(),
+ [](const MainFrameTimingEvent& lhs, const MainFrameTimingEvent& rhs) {
+ return lhs.timestamp < rhs.timestamp;
+ });
+ }
+ return main_frame_events_.Pass();
+}
+
+} // namespace cc
diff --git a/chromium/cc/debug/frame_timing_tracker.h b/chromium/cc/debug/frame_timing_tracker.h
new file mode 100644
index 00000000000..33649931973
--- /dev/null
+++ b/chromium/cc/debug/frame_timing_tracker.h
@@ -0,0 +1,87 @@
+// 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_DEBUG_FRAME_TIMING_TRACKER_H_
+#define CC_DEBUG_FRAME_TIMING_TRACKER_H_
+
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+// This class maintains a history of timestamps and rect IDs to communicate
+// frame events back to Blink
+// TODO(mpb): Start using this. crbug.com/442554
+class CC_EXPORT FrameTimingTracker {
+ public:
+ struct CC_EXPORT CompositeTimingEvent {
+ CompositeTimingEvent(int, base::TimeTicks);
+ ~CompositeTimingEvent();
+
+ int frame_id;
+ base::TimeTicks timestamp;
+ };
+
+ using CompositeTimingSet =
+ base::hash_map<int, std::vector<CompositeTimingEvent>>;
+
+ struct CC_EXPORT MainFrameTimingEvent {
+ MainFrameTimingEvent(int frame_id,
+ base::TimeTicks timestamp,
+ base::TimeTicks end_time);
+ ~MainFrameTimingEvent();
+
+ int frame_id;
+ base::TimeTicks timestamp;
+ base::TimeTicks end_time;
+ };
+
+ using MainFrameTimingSet =
+ base::hash_map<int, std::vector<MainFrameTimingEvent>>;
+
+ static scoped_ptr<FrameTimingTracker> Create();
+
+ ~FrameTimingTracker();
+
+ // This routine takes all of the individual CompositeEvents stored in the
+ // tracker and collects them by "rect_id", as in the example below.
+ // [ {f_id1,r_id1,t1}, {f_id2,r_id1,t2}, {f_id3,r_id2,t3} ]
+ // ====>
+ // [ {r_id1,<{f_id1,t1},{f_id2,t2}>}, {r_id2,<{f_id3,t3}>} ]
+ scoped_ptr<CompositeTimingSet> GroupCompositeCountsByRectId();
+
+ // This routine takes all of the individual MainFrameEvents stored in the
+ // tracker and collects them by "rect_id", as in the example below.
+ scoped_ptr<MainFrameTimingSet> GroupMainFrameCountsByRectId();
+
+ // This routine takes a timestamp and an array of frame_id,rect_id pairs
+ // and generates CompositeTimingEvents (frame_id, timestamp) and adds them to
+ // internal hash_map keyed on rect_id
+ using FrameAndRectIds = std::pair<int, int64_t>;
+ void SaveTimeStamps(base::TimeTicks timestamp,
+ const std::vector<FrameAndRectIds>& frame_ids);
+
+ void SaveMainFrameTimeStamps(const std::vector<int64_t>& request_ids,
+ base::TimeTicks main_frame_time,
+ base::TimeTicks end_time,
+ int source_frame_number);
+
+ private:
+ FrameTimingTracker();
+
+ scoped_ptr<CompositeTimingSet> composite_events_;
+ scoped_ptr<MainFrameTimingSet> main_frame_events_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameTimingTracker);
+};
+
+} // namespace cc
+
+#endif // CC_DEBUG_FRAME_TIMING_TRACKER_H_
diff --git a/chromium/cc/debug/frame_timing_tracker_unittest.cc b/chromium/cc/debug/frame_timing_tracker_unittest.cc
new file mode 100644
index 00000000000..b5574435fbc
--- /dev/null
+++ b/chromium/cc/debug/frame_timing_tracker_unittest.cc
@@ -0,0 +1,228 @@
+// 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.
+
+#include <set>
+#include <string>
+
+#include "base/time/time.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+#include "cc/debug/frame_timing_tracker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+std::string CompositeToString(
+ scoped_ptr<FrameTimingTracker::CompositeTimingSet> timingset) {
+ scoped_refptr<base::trace_event::TracedValue> value =
+ new base::trace_event::TracedValue();
+ value->BeginArray("values");
+ std::set<int> rect_ids;
+ for (const auto& pair : *timingset)
+ rect_ids.insert(pair.first);
+
+ for (const auto& rect_id : rect_ids) {
+ auto& events = (*timingset)[rect_id];
+ value->BeginDictionary();
+ value->SetInteger("rect_id", rect_id);
+ value->BeginArray("events");
+ for (const auto& event : events) {
+ value->BeginDictionary();
+ value->SetInteger("frame_id", event.frame_id);
+ value->SetInteger("timestamp", event.timestamp.ToInternalValue());
+ value->EndDictionary();
+ }
+ value->EndArray();
+ value->EndDictionary();
+ }
+ value->EndArray();
+ return value->ToString();
+}
+
+std::string MainFrameToString(
+ scoped_ptr<FrameTimingTracker::MainFrameTimingSet> timingset) {
+ scoped_refptr<base::trace_event::TracedValue> value =
+ new base::trace_event::TracedValue();
+ value->BeginArray("values");
+ std::set<int> rect_ids;
+ for (const auto& pair : *timingset)
+ rect_ids.insert(pair.first);
+
+ for (const auto& rect_id : rect_ids) {
+ auto& events = (*timingset)[rect_id];
+ value->BeginDictionary();
+ value->SetInteger("rect_id", rect_id);
+ value->BeginArray("events");
+ for (const auto& event : events) {
+ value->BeginDictionary();
+ value->SetInteger("end_time", event.end_time.ToInternalValue());
+ value->SetInteger("frame_id", event.frame_id);
+ value->SetInteger("timestamp", event.timestamp.ToInternalValue());
+ value->EndDictionary();
+ }
+ value->EndArray();
+ value->EndDictionary();
+ }
+ value->EndArray();
+ return value->ToString();
+}
+
+TEST(FrameTimingTrackerTest, DefaultTrackerIsEmpty) {
+ scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+ EXPECT_EQ("{\"values\":[]}",
+ CompositeToString(tracker->GroupCompositeCountsByRectId()));
+ EXPECT_EQ("{\"values\":[]}",
+ MainFrameToString(tracker->GroupMainFrameCountsByRectId()));
+}
+
+TEST(FrameTimingTrackerTest, NoFrameIdsIsEmpty) {
+ scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+ std::vector<std::pair<int, int64_t>> ids;
+ tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(100), ids);
+ EXPECT_EQ("{\"values\":[]}",
+ CompositeToString(tracker->GroupCompositeCountsByRectId()));
+}
+
+TEST(FrameTimingTrackerTest, NoRectIdsYieldsNoMainFrameEvents) {
+ scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+ tracker->SaveMainFrameTimeStamps(std::vector<int64_t>(),
+ base::TimeTicks::FromInternalValue(100),
+ base::TimeTicks::FromInternalValue(110), 1);
+ EXPECT_EQ("{\"values\":[]}",
+ MainFrameToString(tracker->GroupMainFrameCountsByRectId()));
+}
+
+TEST(FrameTimingTrackerTest, OneFrameId) {
+ scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+ std::vector<std::pair<int, int64_t>> ids;
+ ids.push_back(std::make_pair(1, 2));
+ tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(100), ids);
+ EXPECT_EQ(
+ "{\"values\":[{\"events\":["
+ "{\"frame_id\":1,\"timestamp\":100}],\"rect_id\":2}]}",
+ CompositeToString(tracker->GroupCompositeCountsByRectId()));
+}
+
+TEST(FrameTimingTrackerTest, OneMainFrameRect) {
+ scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+ std::vector<int64_t> rect_ids;
+ rect_ids.push_back(1);
+ tracker->SaveMainFrameTimeStamps(rect_ids,
+ base::TimeTicks::FromInternalValue(100),
+ base::TimeTicks::FromInternalValue(110), 2);
+ EXPECT_EQ(
+ "{\"values\":[{\"events\":["
+ "{\"end_time\":110,\"frame_id\":2,\"timestamp\":100}],\"rect_id\":1}]}",
+ MainFrameToString(tracker->GroupMainFrameCountsByRectId()));
+}
+
+TEST(FrameTimingTrackerTest, UnsortedTimestampsIds) {
+ scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+ std::vector<std::pair<int, int64_t>> ids;
+ ids.push_back(std::make_pair(1, 2));
+ tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(200), ids);
+ tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(400), ids);
+ tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(100), ids);
+ EXPECT_EQ(
+ "{\"values\":[{\"events\":["
+ "{\"frame_id\":1,\"timestamp\":100},"
+ "{\"frame_id\":1,\"timestamp\":200},"
+ "{\"frame_id\":1,\"timestamp\":400}],\"rect_id\":2}]}",
+ CompositeToString(tracker->GroupCompositeCountsByRectId()));
+}
+
+TEST(FrameTimingTrackerTest, MainFrameUnsortedTimestamps) {
+ scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+ std::vector<int64_t> rect_ids;
+ rect_ids.push_back(2);
+ tracker->SaveMainFrameTimeStamps(rect_ids,
+ base::TimeTicks::FromInternalValue(200),
+ base::TimeTicks::FromInternalValue(280), 1);
+ tracker->SaveMainFrameTimeStamps(rect_ids,
+ base::TimeTicks::FromInternalValue(400),
+ base::TimeTicks::FromInternalValue(470), 1);
+ tracker->SaveMainFrameTimeStamps(rect_ids,
+ base::TimeTicks::FromInternalValue(100),
+ base::TimeTicks::FromInternalValue(160), 1);
+ EXPECT_EQ(
+ "{\"values\":[{\"events\":["
+ "{\"end_time\":160,\"frame_id\":1,\"timestamp\":100},"
+ "{\"end_time\":280,\"frame_id\":1,\"timestamp\":200},"
+ "{\"end_time\":470,\"frame_id\":1,\"timestamp\":400}],\"rect_id\":2}]}",
+ MainFrameToString(tracker->GroupMainFrameCountsByRectId()));
+}
+
+TEST(FrameTimingTrackerTest, MultipleFrameIds) {
+ scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+
+ std::vector<std::pair<int, int64_t>> ids200;
+ ids200.push_back(std::make_pair(1, 2));
+ ids200.push_back(std::make_pair(1, 3));
+ tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(200), ids200);
+
+ std::vector<std::pair<int, int64_t>> ids400;
+ ids400.push_back(std::make_pair(2, 2));
+ tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(400), ids400);
+
+ std::vector<std::pair<int, int64_t>> ids100;
+ ids100.push_back(std::make_pair(3, 2));
+ ids100.push_back(std::make_pair(2, 3));
+ ids100.push_back(std::make_pair(3, 4));
+ tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(100), ids100);
+
+ EXPECT_EQ(
+ "{\"values\":[{\"events\":["
+ "{\"frame_id\":3,\"timestamp\":100},"
+ "{\"frame_id\":1,\"timestamp\":200},"
+ "{\"frame_id\":2,\"timestamp\":400}],\"rect_id\":2},"
+ "{\"events\":["
+ "{\"frame_id\":2,\"timestamp\":100},"
+ "{\"frame_id\":1,\"timestamp\":200}],\"rect_id\":3},"
+ "{\"events\":["
+ "{\"frame_id\":3,\"timestamp\":100}],\"rect_id\":4}"
+ "]}",
+ CompositeToString(tracker->GroupCompositeCountsByRectId()));
+}
+
+TEST(FrameTimingTrackerTest, MultipleMainFrameEvents) {
+ scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+
+ std::vector<int64_t> rect_ids200;
+ rect_ids200.push_back(2);
+ rect_ids200.push_back(3);
+ tracker->SaveMainFrameTimeStamps(rect_ids200,
+ base::TimeTicks::FromInternalValue(200),
+ base::TimeTicks::FromInternalValue(220), 1);
+
+ std::vector<int64_t> rect_ids400;
+ rect_ids400.push_back(2);
+ tracker->SaveMainFrameTimeStamps(rect_ids400,
+ base::TimeTicks::FromInternalValue(400),
+ base::TimeTicks::FromInternalValue(440), 2);
+
+ std::vector<int64_t> rect_ids100;
+ rect_ids100.push_back(2);
+ rect_ids100.push_back(3);
+ rect_ids100.push_back(4);
+ tracker->SaveMainFrameTimeStamps(rect_ids100,
+ base::TimeTicks::FromInternalValue(100),
+ base::TimeTicks::FromInternalValue(110), 3);
+
+ EXPECT_EQ(
+ "{\"values\":[{\"events\":["
+ "{\"end_time\":110,\"frame_id\":3,\"timestamp\":100},"
+ "{\"end_time\":220,\"frame_id\":1,\"timestamp\":200},"
+ "{\"end_time\":440,\"frame_id\":2,\"timestamp\":400}],\"rect_id\":2},"
+ "{\"events\":["
+ "{\"end_time\":110,\"frame_id\":3,\"timestamp\":100},"
+ "{\"end_time\":220,\"frame_id\":1,\"timestamp\":200}],\"rect_id\":3},"
+ "{\"events\":["
+ "{\"end_time\":110,\"frame_id\":3,\"timestamp\":100}],\"rect_id\":4}"
+ "]}",
+ MainFrameToString(tracker->GroupMainFrameCountsByRectId()));
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/debug/frame_viewer_instrumentation.cc b/chromium/cc/debug/frame_viewer_instrumentation.cc
new file mode 100644
index 00000000000..e12858371d6
--- /dev/null
+++ b/chromium/cc/debug/frame_viewer_instrumentation.cc
@@ -0,0 +1,78 @@
+// Copyright 2014 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/debug/frame_viewer_instrumentation.h"
+
+#include "cc/debug/traced_value.h"
+
+namespace cc {
+namespace frame_viewer_instrumentation {
+
+const char kCategoryLayerTree[] =
+ TRACE_DISABLED_BY_DEFAULT("cc.debug") ","
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.quads") ","
+ TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers");
+
+namespace {
+
+const char kCategory[] = "cc," TRACE_DISABLED_BY_DEFAULT("devtools.timeline");
+const char kTileData[] = "tileData";
+const char kLayerId[] = "layerId";
+const char kTileId[] = "tileId";
+const char kTileResolution[] = "tileResolution";
+const char kSourceFrameNumber[] = "sourceFrameNumber";
+
+const char kAnalyzeTask[] = "AnalyzeTask";
+const char kRasterTask[] = "RasterTask";
+
+scoped_refptr<base::trace_event::ConvertableToTraceFormat> TileDataAsValue(
+ const void* tile_id,
+ TileResolution tile_resolution,
+ int source_frame_number,
+ int layer_id) {
+ scoped_refptr<base::trace_event::TracedValue> res(
+ new base::trace_event::TracedValue());
+ TracedValue::SetIDRef(tile_id, res.get(), kTileId);
+ res->SetString(kTileResolution, TileResolutionToString(tile_resolution));
+ res->SetInteger(kSourceFrameNumber, source_frame_number);
+ res->SetInteger(kLayerId, layer_id);
+ return res;
+}
+
+} // namespace
+
+ScopedAnalyzeTask::ScopedAnalyzeTask(const void* tile_id,
+ TileResolution tile_resolution,
+ int source_frame_number,
+ int layer_id) {
+ TRACE_EVENT_BEGIN1(
+ kCategory, kAnalyzeTask, kTileData,
+ TileDataAsValue(tile_id, tile_resolution, source_frame_number, layer_id));
+}
+
+ScopedAnalyzeTask::~ScopedAnalyzeTask() {
+ TRACE_EVENT_END0(kCategory, kAnalyzeTask);
+}
+
+ScopedRasterTask::ScopedRasterTask(const void* tile_id,
+ TileResolution tile_resolution,
+ int source_frame_number,
+ int layer_id) {
+ TRACE_EVENT_BEGIN1(
+ kCategory, kRasterTask, kTileData,
+ TileDataAsValue(tile_id, tile_resolution, source_frame_number, layer_id));
+}
+
+ScopedRasterTask::~ScopedRasterTask() {
+ TRACE_EVENT_END0(kCategory, kRasterTask);
+}
+
+bool IsTracingLayerTreeSnapshots() {
+ bool category_enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(kCategoryLayerTree, &category_enabled);
+ return category_enabled;
+}
+
+} // namespace frame_viewer_instrumentation
+} // namespace cc
diff --git a/chromium/cc/debug/frame_viewer_instrumentation.h b/chromium/cc/debug/frame_viewer_instrumentation.h
index e0e54eb3cb8..773e8c55d1d 100644
--- a/chromium/cc/debug/frame_viewer_instrumentation.h
+++ b/chromium/cc/debug/frame_viewer_instrumentation.h
@@ -5,55 +5,22 @@
#ifndef CC_DEBUG_FRAME_VIEWER_INSTRUMENTATION_H_
#define CC_DEBUG_FRAME_VIEWER_INSTRUMENTATION_H_
-#include "base/debug/trace_event.h"
-#include "cc/resources/tile.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_priority.h"
namespace cc {
namespace frame_viewer_instrumentation {
-namespace internal {
-const char kCategory[] = "cc";
-const char kTileData[] = "tileData";
-const char kLayerId[] = "layerId";
-const char kTileId[] = "tileId";
-const char kTileResolution[] = "tileResolution";
-const char kSourceFrameNumber[] = "sourceFrameNumber";
-
-const char kAnalyzeTask[] = "AnalyzeTask";
-const char kRasterTask[] = "RasterTask";
-
-scoped_refptr<base::debug::ConvertableToTraceFormat> TileDataAsValue(
- const void* tile_id,
- TileResolution tile_resolution,
- int source_frame_number,
- int layer_id) {
- scoped_refptr<base::debug::TracedValue> res(new base::debug::TracedValue());
- TracedValue::SetIDRef(tile_id, res.get(), internal::kTileId);
- res->SetString(internal::kTileResolution,
- TileResolutionToString(tile_resolution));
- res->SetInteger(internal::kSourceFrameNumber, source_frame_number);
- res->SetInteger(internal::kLayerId, layer_id);
- return res;
-}
-
-} // namespace internal
+extern const char kCategoryLayerTree[];
class ScopedAnalyzeTask {
public:
ScopedAnalyzeTask(const void* tile_id,
TileResolution tile_resolution,
int source_frame_number,
- int layer_id) {
- TRACE_EVENT_BEGIN1(
- internal::kCategory,
- internal::kAnalyzeTask,
- internal::kTileData,
- internal::TileDataAsValue(
- tile_id, tile_resolution, source_frame_number, layer_id));
- }
- ~ScopedAnalyzeTask() {
- TRACE_EVENT_END0(internal::kCategory, internal::kAnalyzeTask);
- }
+ int layer_id);
+ ~ScopedAnalyzeTask();
private:
DISALLOW_COPY_AND_ASSIGN(ScopedAnalyzeTask);
@@ -64,22 +31,15 @@ class ScopedRasterTask {
ScopedRasterTask(const void* tile_id,
TileResolution tile_resolution,
int source_frame_number,
- int layer_id) {
- TRACE_EVENT_BEGIN1(
- internal::kCategory,
- internal::kRasterTask,
- internal::kTileData,
- internal::TileDataAsValue(
- tile_id, tile_resolution, source_frame_number, layer_id));
- }
- ~ScopedRasterTask() {
- TRACE_EVENT_END0(internal::kCategory, internal::kRasterTask);
- }
+ int layer_id);
+ ~ScopedRasterTask();
private:
DISALLOW_COPY_AND_ASSIGN(ScopedRasterTask);
};
+bool IsTracingLayerTreeSnapshots();
+
} // namespace frame_viewer_instrumentation
} // namespace cc
diff --git a/chromium/cc/debug/invalidation_benchmark.cc b/chromium/cc/debug/invalidation_benchmark.cc
index 1a6a2b83d6b..6fd3d3e2fb6 100644
--- a/chromium/cc/debug/invalidation_benchmark.cc
+++ b/chromium/cc/debug/invalidation_benchmark.cc
@@ -64,11 +64,7 @@ InvalidationBenchmark::~InvalidationBenchmark() {
void InvalidationBenchmark::DidUpdateLayers(LayerTreeHost* host) {
LayerTreeHostCommon::CallFunctionForSubtree(
host->root_layer(),
- base::Bind(&InvalidationBenchmark::Run, base::Unretained(this)));
-}
-
-void InvalidationBenchmark::Run(Layer* layer) {
- layer->RunMicroBenchmark(this);
+ [this](Layer* layer) { layer->RunMicroBenchmark(this); });
}
void InvalidationBenchmark::RunOnLayer(PictureLayer* layer) {
@@ -120,7 +116,7 @@ bool InvalidationBenchmark::ProcessMessage(scoped_ptr<base::Value> value) {
if (message->HasKey("notify_done")) {
message->GetBoolean("notify_done", &notify_done);
if (notify_done)
- NotifyDone(scoped_ptr<base::Value>(base::Value::CreateNullValue()));
+ NotifyDone(base::Value::CreateNullValue());
return true;
}
return false;
diff --git a/chromium/cc/debug/invalidation_benchmark.h b/chromium/cc/debug/invalidation_benchmark.h
index f17fdbd2fd4..9423d5d8e79 100644
--- a/chromium/cc/debug/invalidation_benchmark.h
+++ b/chromium/cc/debug/invalidation_benchmark.h
@@ -31,7 +31,6 @@ class CC_EXPORT InvalidationBenchmark : public MicroBenchmark {
private:
enum Mode { FIXED_SIZE, LAYER, VIEWPORT, RANDOM };
- void Run(Layer* layer);
float LCGRandom();
Mode mode_;
diff --git a/chromium/cc/debug/lap_timer.cc b/chromium/cc/debug/lap_timer.cc
index 27aaf3499a9..17bca3d313f 100644
--- a/chromium/cc/debug/lap_timer.cc
+++ b/chromium/cc/debug/lap_timer.cc
@@ -11,11 +11,15 @@ namespace cc {
namespace {
base::TimeTicks Now() {
- return base::TimeTicks::IsThreadNowSupported()
- ? base::TimeTicks::ThreadNow()
- : base::TimeTicks::HighResNow();
+ return base::TimeTicks::IsThreadNowSupported() ? base::TimeTicks::ThreadNow()
+ : base::TimeTicks::Now();
}
+// Default values.
+static const int kTimeLimitMillis = 3000;
+static const int kWarmupRuns = 5;
+static const int kTimeCheckInterval = 10;
+
} // namespace
LapTimer::LapTimer(int warmup_laps,
@@ -30,6 +34,12 @@ LapTimer::LapTimer(int warmup_laps,
Reset();
}
+LapTimer::LapTimer()
+ : LapTimer(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval) {
+}
+
void LapTimer::Reset() {
accumulator_ = base::TimeDelta();
num_laps_ = 0;
diff --git a/chromium/cc/debug/lap_timer.h b/chromium/cc/debug/lap_timer.h
index 7ec9a8cca5c..7662e2adb5f 100644
--- a/chromium/cc/debug/lap_timer.h
+++ b/chromium/cc/debug/lap_timer.h
@@ -23,6 +23,8 @@ namespace cc {
class CC_EXPORT LapTimer {
public:
LapTimer(int warmup_laps, base::TimeDelta time_limit, int check_interval);
+ // Create LapTimer with sensible default values.
+ LapTimer();
// Resets the timer back to it's starting state.
void Reset();
// Sets the start point to now.
diff --git a/chromium/cc/debug/layer_tree_debug_state.cc b/chromium/cc/debug/layer_tree_debug_state.cc
index d89bca38906..e840220ca6f 100644
--- a/chromium/cc/debug/layer_tree_debug_state.cc
+++ b/chromium/cc/debug/layer_tree_debug_state.cc
@@ -18,8 +18,6 @@ LayerTreeDebugState::LayerTreeDebugState()
show_surface_damage_rects(false),
show_screen_space_rects(false),
show_replica_screen_space_rects(false),
- show_occluding_rects(false),
- show_non_occluding_rects(false),
show_touch_event_handler_rects(false),
show_wheel_event_handler_rects(false),
show_scroll_event_handler_rects(false),
@@ -48,8 +46,7 @@ bool LayerTreeDebugState::ShowHudInfo() const {
bool LayerTreeDebugState::ShowHudRects() const {
return show_paint_rects || show_property_changed_rects ||
show_surface_damage_rects || show_screen_space_rects ||
- show_replica_screen_space_rects || show_occluding_rects ||
- show_non_occluding_rects || show_touch_event_handler_rects ||
+ show_replica_screen_space_rects || show_touch_event_handler_rects ||
show_wheel_event_handler_rects || show_scroll_event_handler_rects ||
show_non_fast_scrollable_rects || show_layer_animation_bounds_rects;
}
@@ -69,8 +66,6 @@ bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a,
a.show_surface_damage_rects == b.show_surface_damage_rects &&
a.show_screen_space_rects == b.show_screen_space_rects &&
a.show_replica_screen_space_rects == b.show_replica_screen_space_rects &&
- a.show_occluding_rects == b.show_occluding_rects &&
- a.show_non_occluding_rects == b.show_non_occluding_rects &&
a.show_touch_event_handler_rects == b.show_touch_event_handler_rects &&
a.show_wheel_event_handler_rects == b.show_wheel_event_handler_rects &&
a.show_scroll_event_handler_rects == b.show_scroll_event_handler_rects &&
@@ -96,8 +91,6 @@ LayerTreeDebugState LayerTreeDebugState::Unite(const LayerTreeDebugState& a,
r.show_surface_damage_rects |= b.show_surface_damage_rects;
r.show_screen_space_rects |= b.show_screen_space_rects;
r.show_replica_screen_space_rects |= b.show_replica_screen_space_rects;
- r.show_occluding_rects |= b.show_occluding_rects;
- r.show_non_occluding_rects |= b.show_non_occluding_rects;
r.show_touch_event_handler_rects |= b.show_touch_event_handler_rects;
r.show_wheel_event_handler_rects |= b.show_wheel_event_handler_rects;
r.show_scroll_event_handler_rects |= b.show_scroll_event_handler_rects;
diff --git a/chromium/cc/debug/layer_tree_debug_state.h b/chromium/cc/debug/layer_tree_debug_state.h
index c3970e16549..4b71cd9bbbe 100644
--- a/chromium/cc/debug/layer_tree_debug_state.h
+++ b/chromium/cc/debug/layer_tree_debug_state.h
@@ -24,8 +24,6 @@ class CC_EXPORT LayerTreeDebugState {
bool show_surface_damage_rects;
bool show_screen_space_rects;
bool show_replica_screen_space_rects;
- bool show_occluding_rects;
- bool show_non_occluding_rects;
bool show_touch_event_handler_rects;
bool show_wheel_event_handler_rects;
bool show_scroll_event_handler_rects;
diff --git a/chromium/cc/debug/micro_benchmark.cc b/chromium/cc/debug/micro_benchmark.cc
index 64629de165a..cf6e2698bfe 100644
--- a/chromium/cc/debug/micro_benchmark.cc
+++ b/chromium/cc/debug/micro_benchmark.cc
@@ -7,7 +7,7 @@
#include "base/callback.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/values.h"
#include "cc/debug/micro_benchmark_impl.h"
@@ -46,14 +46,14 @@ bool MicroBenchmark::ProcessedForBenchmarkImpl() const {
}
scoped_ptr<MicroBenchmarkImpl> MicroBenchmark::GetBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop) {
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) {
DCHECK(!processed_for_benchmark_impl_);
processed_for_benchmark_impl_ = true;
- return CreateBenchmarkImpl(origin_loop);
+ return CreateBenchmarkImpl(origin_task_runner);
}
scoped_ptr<MicroBenchmarkImpl> MicroBenchmark::CreateBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop) {
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) {
return make_scoped_ptr<MicroBenchmarkImpl>(nullptr);
}
diff --git a/chromium/cc/debug/micro_benchmark.h b/chromium/cc/debug/micro_benchmark.h
index 1654c368f1d..c5bbd883164 100644
--- a/chromium/cc/debug/micro_benchmark.h
+++ b/chromium/cc/debug/micro_benchmark.h
@@ -10,8 +10,8 @@
#include "cc/base/cc_export.h"
namespace base {
+class SingleThreadTaskRunner;
class Value;
-class MessageLoopProxy;
} // namespace base
namespace cc {
@@ -39,13 +39,13 @@ class CC_EXPORT MicroBenchmark {
bool ProcessedForBenchmarkImpl() const;
scoped_ptr<MicroBenchmarkImpl> GetBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop);
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner);
protected:
void NotifyDone(scoped_ptr<base::Value> result);
virtual scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop);
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner);
private:
DoneCallback callback_;
diff --git a/chromium/cc/debug/micro_benchmark_controller.cc b/chromium/cc/debug/micro_benchmark_controller.cc
index bf981005419..a38e5ad01a3 100644
--- a/chromium/cc/debug/micro_benchmark_controller.cc
+++ b/chromium/cc/debug/micro_benchmark_controller.cc
@@ -8,7 +8,7 @@
#include <string>
#include "base/callback.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
#include "base/values.h"
#include "cc/debug/invalidation_benchmark.h"
#include "cc/debug/picture_record_benchmark.h"
@@ -54,7 +54,9 @@ class IsDonePredicate {
MicroBenchmarkController::MicroBenchmarkController(LayerTreeHost* host)
: host_(host),
- main_controller_message_loop_(base::MessageLoopProxy::current().get()) {
+ main_controller_task_runner_(base::ThreadTaskRunnerHandle::IsSet()
+ ? base::ThreadTaskRunnerHandle::Get()
+ : nullptr) {
DCHECK(host_);
}
@@ -102,8 +104,7 @@ void MicroBenchmarkController::ScheduleImplBenchmarks(
++it) {
scoped_ptr<MicroBenchmarkImpl> benchmark_impl;
if (!(*it)->ProcessedForBenchmarkImpl()) {
- benchmark_impl =
- (*it)->GetBenchmarkImpl(main_controller_message_loop_);
+ benchmark_impl = (*it)->GetBenchmarkImpl(main_controller_task_runner_);
}
if (benchmark_impl.get())
diff --git a/chromium/cc/debug/micro_benchmark_controller.h b/chromium/cc/debug/micro_benchmark_controller.h
index 88f6d9adad9..198e203fa2f 100644
--- a/chromium/cc/debug/micro_benchmark_controller.h
+++ b/chromium/cc/debug/micro_benchmark_controller.h
@@ -13,8 +13,8 @@
#include "cc/debug/micro_benchmark.h"
namespace base {
+class SingleThreadTaskRunner;
class Value;
-class MessageLoopProxy;
} // namespace base
namespace cc {
@@ -44,7 +44,7 @@ class CC_EXPORT MicroBenchmarkController {
LayerTreeHost* host_;
ScopedPtrVector<MicroBenchmark> benchmarks_;
static int next_id_;
- scoped_refptr<base::MessageLoopProxy> main_controller_message_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_controller_task_runner_;
DISALLOW_COPY_AND_ASSIGN(MicroBenchmarkController);
};
diff --git a/chromium/cc/debug/micro_benchmark_controller_unittest.cc b/chromium/cc/debug/micro_benchmark_controller_unittest.cc
index a5683c4ed14..2a8dce45246 100644
--- a/chromium/cc/debug/micro_benchmark_controller_unittest.cc
+++ b/chromium/cc/debug/micro_benchmark_controller_unittest.cc
@@ -21,18 +21,18 @@ class MicroBenchmarkControllerTest : public testing::Test {
MicroBenchmarkControllerTest()
: layer_tree_host_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
- virtual void SetUp() override {
+ void SetUp() override {
impl_proxy_ = make_scoped_ptr(new FakeImplProxy);
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
layer_tree_host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(
- impl_proxy_.get(), shared_bitmap_manager_.get()));
+ impl_proxy_.get(), shared_bitmap_manager_.get(), nullptr));
layer_tree_host_ = FakeLayerTreeHost::Create(&layer_tree_host_client_);
layer_tree_host_->SetRootLayer(Layer::Create());
layer_tree_host_->InitializeForTesting(scoped_ptr<Proxy>(new FakeProxy));
}
- virtual void TearDown() override {
+ void TearDown() override {
layer_tree_host_impl_ = nullptr;
layer_tree_host_ = nullptr;
impl_proxy_ = nullptr;
diff --git a/chromium/cc/debug/micro_benchmark_impl.cc b/chromium/cc/debug/micro_benchmark_impl.cc
index 7ec58c8de0b..f20f32ee33e 100644
--- a/chromium/cc/debug/micro_benchmark_impl.cc
+++ b/chromium/cc/debug/micro_benchmark_impl.cc
@@ -6,8 +6,9 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/location.h"
#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/values.h"
namespace cc {
@@ -23,8 +24,11 @@ void RunCallback(const MicroBenchmarkImpl::DoneCallback& callback,
MicroBenchmarkImpl::MicroBenchmarkImpl(
const DoneCallback& callback,
- scoped_refptr<base::MessageLoopProxy> origin_loop)
- : callback_(callback), is_done_(false), origin_loop_(origin_loop) {}
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner)
+ : callback_(callback),
+ is_done_(false),
+ origin_task_runner_(origin_task_runner) {
+}
MicroBenchmarkImpl::~MicroBenchmarkImpl() {}
@@ -35,9 +39,8 @@ bool MicroBenchmarkImpl::IsDone() const {
void MicroBenchmarkImpl::DidCompleteCommit(LayerTreeHostImpl* host) {}
void MicroBenchmarkImpl::NotifyDone(scoped_ptr<base::Value> result) {
- origin_loop_->PostTask(
- FROM_HERE,
- base::Bind(RunCallback, callback_, base::Passed(&result)));
+ origin_task_runner_->PostTask(
+ FROM_HERE, base::Bind(RunCallback, callback_, base::Passed(&result)));
is_done_ = true;
}
diff --git a/chromium/cc/debug/micro_benchmark_impl.h b/chromium/cc/debug/micro_benchmark_impl.h
index 4f3f74f6516..ed968a39fbc 100644
--- a/chromium/cc/debug/micro_benchmark_impl.h
+++ b/chromium/cc/debug/micro_benchmark_impl.h
@@ -10,8 +10,8 @@
#include "cc/base/cc_export.h"
namespace base {
+class SingleThreadTaskRunner;
class Value;
-class MessageLoopProxy;
} // namespace base
namespace cc {
@@ -25,7 +25,7 @@ class CC_EXPORT MicroBenchmarkImpl {
explicit MicroBenchmarkImpl(
const DoneCallback& callback,
- scoped_refptr<base::MessageLoopProxy> origin_loop);
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner);
virtual ~MicroBenchmarkImpl();
bool IsDone() const;
@@ -40,7 +40,7 @@ class CC_EXPORT MicroBenchmarkImpl {
private:
DoneCallback callback_;
bool is_done_;
- scoped_refptr<base::MessageLoopProxy> origin_loop_;
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
};
} // namespace cc
diff --git a/chromium/cc/debug/picture_debug_util.cc b/chromium/cc/debug/picture_debug_util.cc
new file mode 100644
index 00000000000..e653b78e235
--- /dev/null
+++ b/chromium/cc/debug/picture_debug_util.cc
@@ -0,0 +1,73 @@
+// 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.
+
+#include "cc/debug/picture_debug_util.h"
+
+#include <vector>
+
+#include "base/base64.h"
+#include "base/memory/scoped_ptr.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkData.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/core/SkPixelSerializer.h"
+#include "third_party/skia/include/core/SkStream.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace {
+
+class BitmapSerializer : public SkPixelSerializer {
+ protected:
+ bool onUseEncodedData(const void* data, size_t len) override { return true; }
+
+ SkData* onEncodePixels(const SkImageInfo& info,
+ const void* pixels,
+ size_t row_bytes) override {
+ const int kJpegQuality = 80;
+ std::vector<unsigned char> data;
+
+ // If bitmap is opaque, encode as JPEG.
+ // Otherwise encode as PNG.
+ bool encoding_succeeded = false;
+ if (info.isOpaque()) {
+ encoding_succeeded =
+ gfx::JPEGCodec::Encode(reinterpret_cast<const unsigned char*>(pixels),
+ gfx::JPEGCodec::FORMAT_SkBitmap, info.width(),
+ info.height(), row_bytes, kJpegQuality, &data);
+ } else {
+ SkBitmap bm;
+ // The cast is ok, since we only read the bm.
+ if (!bm.installPixels(info, const_cast<void*>(pixels), row_bytes)) {
+ return nullptr;
+ }
+ encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data);
+ }
+
+ if (encoding_succeeded) {
+ return SkData::NewWithCopy(&data.front(), data.size());
+ }
+ return nullptr;
+ }
+};
+
+} // namespace
+
+namespace cc {
+
+void PictureDebugUtil::SerializeAsBase64(const SkPicture* picture,
+ std::string* output) {
+ SkDynamicMemoryWStream stream;
+ BitmapSerializer serializer;
+ picture->serialize(&stream, &serializer);
+
+ size_t serialized_size = stream.bytesWritten();
+ scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
+ stream.copyTo(serialized_picture.get());
+ base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
+ output);
+}
+
+} // namespace cc
diff --git a/chromium/cc/debug/picture_debug_util.h b/chromium/cc/debug/picture_debug_util.h
new file mode 100644
index 00000000000..1719ea27632
--- /dev/null
+++ b/chromium/cc/debug/picture_debug_util.h
@@ -0,0 +1,21 @@
+// 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_DEBUG_PICTURE_DEBUG_UTIL_H_
+#define CC_DEBUG_PICTURE_DEBUG_UTIL_H_
+
+#include <string>
+
+class SkPicture;
+
+namespace cc {
+
+class PictureDebugUtil {
+ public:
+ static void SerializeAsBase64(const SkPicture* picture, std::string* output);
+};
+
+} // namespace cc
+
+#endif // CC_DEBUG_PICTURE_DEBUG_UTIL_H_
diff --git a/chromium/cc/debug/picture_record_benchmark.cc b/chromium/cc/debug/picture_record_benchmark.cc
index 5f832ae4897..d8608c538ff 100644
--- a/chromium/cc/debug/picture_record_benchmark.cc
+++ b/chromium/cc/debug/picture_record_benchmark.cc
@@ -10,6 +10,7 @@
#include "base/values.h"
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
+#include "cc/playback/picture.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
#include "ui/gfx/geometry/rect.h"
@@ -20,7 +21,6 @@ namespace {
const int kPositionIncrement = 100;
const int kTileGridSize = 512;
-const int kTileGridBorder = 1;
} // namespace
@@ -57,7 +57,7 @@ PictureRecordBenchmark::~PictureRecordBenchmark() {}
void PictureRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) {
LayerTreeHostCommon::CallFunctionForSubtree(
host->root_layer(),
- base::Bind(&PictureRecordBenchmark::Run, base::Unretained(this)));
+ [this](Layer* layer) { layer->RunMicroBenchmark(this); });
scoped_ptr<base::ListValue> results(new base::ListValue());
for (std::map<std::pair<int, int>, TotalTime>::iterator it = times_.begin();
@@ -83,19 +83,11 @@ void PictureRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) {
NotifyDone(results.Pass());
}
-void PictureRecordBenchmark::Run(Layer* layer) {
- layer->RunMicroBenchmark(this);
-}
-
void PictureRecordBenchmark::RunOnLayer(PictureLayer* layer) {
ContentLayerClient* painter = layer->client();
gfx::Size content_bounds = layer->content_bounds();
- SkTileGridFactory::TileGridInfo tile_grid_info;
- tile_grid_info.fTileInterval.set(kTileGridSize - 2 * kTileGridBorder,
- kTileGridSize - 2 * kTileGridBorder);
- tile_grid_info.fMargin.set(kTileGridBorder, kTileGridBorder);
- tile_grid_info.fOffset.set(-kTileGridBorder, -kTileGridBorder);
+ gfx::Size tile_grid_size(kTileGridSize, kTileGridSize);
for (size_t i = 0; i < dimensions_.size(); ++i) {
std::pair<int, int> dimensions = dimensions_[i];
@@ -108,12 +100,13 @@ void PictureRecordBenchmark::RunOnLayer(PictureLayer* layer) {
for (int x = 0; x < x_limit; x += kPositionIncrement) {
gfx::Rect rect = gfx::Rect(x, y, width, height);
- base::TimeTicks start = base::TimeTicks::HighResNow();
+ base::TimeTicks start = base::TimeTicks::Now();
- scoped_refptr<Picture> picture = Picture::Create(
- rect, painter, tile_grid_info, false, Picture::RECORD_NORMALLY);
+ scoped_refptr<Picture> picture =
+ Picture::Create(rect, painter, tile_grid_size, false,
+ RecordingSource::RECORD_NORMALLY);
- base::TimeTicks end = base::TimeTicks::HighResNow();
+ base::TimeTicks end = base::TimeTicks::Now();
base::TimeDelta duration = end - start;
TotalTime& total_time = times_[dimensions];
total_time.first += duration;
diff --git a/chromium/cc/debug/picture_record_benchmark.h b/chromium/cc/debug/picture_record_benchmark.h
index d6330fe1adb..3710d83b21b 100644
--- a/chromium/cc/debug/picture_record_benchmark.h
+++ b/chromium/cc/debug/picture_record_benchmark.h
@@ -27,8 +27,6 @@ class CC_EXPORT PictureRecordBenchmark : public MicroBenchmark {
void RunOnLayer(PictureLayer* layer) override;
private:
- void Run(Layer* layer);
-
typedef std::pair<base::TimeDelta, unsigned> TotalTime;
std::map<std::pair<int, int>, TotalTime> times_;
std::vector<std::pair<int, int>> dimensions_;
diff --git a/chromium/cc/debug/rasterize_and_record_benchmark.cc b/chromium/cc/debug/rasterize_and_record_benchmark.cc
index f24dce3baf1..c8439856043 100644
--- a/chromium/cc/debug/rasterize_and_record_benchmark.cc
+++ b/chromium/cc/debug/rasterize_and_record_benchmark.cc
@@ -13,10 +13,14 @@
#include "base/values.h"
#include "cc/debug/lap_timer.h"
#include "cc/debug/rasterize_and_record_benchmark_impl.h"
+#include "cc/layers/content_layer_client.h"
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
+#include "cc/playback/display_item_list.h"
+#include "cc/playback/picture_pile.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
#include "ui/gfx/geometry/rect.h"
namespace cc {
@@ -25,10 +29,17 @@ namespace {
const int kDefaultRecordRepeatCount = 100;
-const char* kModeSuffixes[Picture::RECORDING_MODE_COUNT] = {
+// Parameters for LapTimer.
+const int kTimeLimitMillis = 1;
+const int kWarmupRuns = 0;
+const int kTimeCheckInterval = 1;
+
+const char* kModeSuffixes[RecordingSource::RECORDING_MODE_COUNT] = {
"",
"_sk_null_canvas",
- "_painting_disabled"};
+ "_painting_disabled",
+ "_caching_disabled",
+ "_construction_disabled"};
} // namespace
@@ -58,13 +69,14 @@ void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) {
host_ = host;
LayerTreeHostCommon::CallFunctionForSubtree(
host->root_layer(),
- base::Bind(&RasterizeAndRecordBenchmark::Run, base::Unretained(this)));
+ [this](Layer* layer) { layer->RunMicroBenchmark(this); });
DCHECK(!results_.get());
results_ = make_scoped_ptr(new base::DictionaryValue);
results_->SetInteger("pixels_recorded", record_results_.pixels_recorded);
+ results_->SetInteger("picture_memory_usage", record_results_.bytes_used);
- for (int i = 0; i < Picture::RECORDING_MODE_COUNT; i++) {
+ for (int i = 0; i < RecordingSource::RECORDING_MODE_COUNT; i++) {
std::string name = base::StringPrintf("record_time%s_ms", kModeSuffixes[i]);
results_->SetDouble(name,
record_results_.total_best_time[i].InMillisecondsF());
@@ -86,53 +98,140 @@ void RasterizeAndRecordBenchmark::RecordRasterResults(
}
scoped_ptr<MicroBenchmarkImpl> RasterizeAndRecordBenchmark::CreateBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop) {
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) {
return make_scoped_ptr(new RasterizeAndRecordBenchmarkImpl(
- origin_loop,
- settings_.get(),
+ origin_task_runner, settings_.get(),
base::Bind(&RasterizeAndRecordBenchmark::RecordRasterResults,
weak_ptr_factory_.GetWeakPtr())));
}
-void RasterizeAndRecordBenchmark::Run(Layer* layer) {
- layer->RunMicroBenchmark(this);
+void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
+ DCHECK(host_);
+
+ gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
+ layer->visible_content_rect(), 1.f / layer->contents_scale_x());
+ if (visible_layer_rect.IsEmpty())
+ return;
+
+ if (host_->settings().use_display_lists) {
+ RunOnDisplayListLayer(layer, visible_layer_rect);
+ } else {
+ RunOnPictureLayer(layer, visible_layer_rect);
+ }
}
-void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
+void RasterizeAndRecordBenchmark::RunOnPictureLayer(
+ PictureLayer* layer,
+ const gfx::Rect& visible_layer_rect) {
ContentLayerClient* painter = layer->client();
- gfx::Size content_bounds = layer->content_bounds();
- DCHECK(host_);
+ DCHECK(host_ && !host_->settings().use_display_lists);
+
gfx::Size tile_grid_size = host_->settings().default_tile_size;
- SkTileGridFactory::TileGridInfo tile_grid_info;
- PicturePileBase::ComputeTileGridInfo(tile_grid_size, &tile_grid_info);
+ for (int mode_index = 0; mode_index < RecordingSource::RECORDING_MODE_COUNT;
+ mode_index++) {
+ RecordingSource::RecordingMode mode =
+ static_cast<RecordingSource::RecordingMode>(mode_index);
- gfx::Rect visible_content_rect = gfx::ScaleToEnclosingRect(
- layer->visible_content_rect(), 1.f / layer->contents_scale_x());
- if (visible_content_rect.IsEmpty())
- return;
+ // Not supported for SkPicture recording.
+ if (mode == RecordingSource::RECORD_WITH_CONSTRUCTION_DISABLED)
+ continue;
- for (int mode_index = 0; mode_index < Picture::RECORDING_MODE_COUNT;
- mode_index++) {
- Picture::RecordingMode mode =
- static_cast<Picture::RecordingMode>(mode_index);
base::TimeDelta min_time = base::TimeDelta::Max();
+ size_t memory_used = 0;
- // Parameters for LapTimer.
- const int kTimeLimitMillis = 1;
- const int kWarmupRuns = 0;
- const int kTimeCheckInterval = 1;
+ for (int i = 0; i < record_repeat_count_; ++i) {
+ // Run for a minimum amount of time to avoid problems with timer
+ // quantization when the layer is very small.
+ LapTimer timer(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval);
+ scoped_refptr<Picture> picture;
+ do {
+ picture = Picture::Create(visible_layer_rect, painter, tile_grid_size,
+ false, mode);
+ if (memory_used) {
+ // Verify we are recording the same thing each time.
+ DCHECK(memory_used == picture->ApproximateMemoryUsage());
+ } else {
+ memory_used = picture->ApproximateMemoryUsage();
+ }
+ timer.NextLap();
+ } while (!timer.HasTimeLimitExpired());
+ base::TimeDelta duration =
+ base::TimeDelta::FromMillisecondsD(timer.MsPerLap());
+ if (duration < min_time)
+ min_time = duration;
+ }
+
+ if (mode == RecordingSource::RECORD_NORMALLY) {
+ record_results_.bytes_used += memory_used;
+ record_results_.pixels_recorded +=
+ visible_layer_rect.width() * visible_layer_rect.height();
+ }
+ record_results_.total_best_time[mode_index] += min_time;
+ }
+}
+
+void RasterizeAndRecordBenchmark::RunOnDisplayListLayer(
+ PictureLayer* layer,
+ const gfx::Rect& visible_layer_rect) {
+ ContentLayerClient* painter = layer->client();
+
+ DCHECK(host_ && host_->settings().use_display_lists);
+
+ for (int mode_index = 0; mode_index < RecordingSource::RECORDING_MODE_COUNT;
+ mode_index++) {
+ ContentLayerClient::PaintingControlSetting painting_control =
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL;
+ switch (static_cast<RecordingSource::RecordingMode>(mode_index)) {
+ case RecordingSource::RECORD_NORMALLY:
+ // Already setup for normal recording.
+ break;
+ case RecordingSource::RECORD_WITH_SK_NULL_CANVAS:
+ // Not supported for Display List recording.
+ continue;
+ case RecordingSource::RECORD_WITH_PAINTING_DISABLED:
+ painting_control = ContentLayerClient::DISPLAY_LIST_PAINTING_DISABLED;
+ break;
+ case RecordingSource::RECORD_WITH_CACHING_DISABLED:
+ painting_control = ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED;
+ break;
+ case RecordingSource::RECORD_WITH_CONSTRUCTION_DISABLED:
+ painting_control =
+ ContentLayerClient::DISPLAY_LIST_CONSTRUCTION_DISABLED;
+ break;
+ default:
+ NOTREACHED();
+ }
+ base::TimeDelta min_time = base::TimeDelta::Max();
+ size_t memory_used = 0;
+
+ scoped_refptr<DisplayItemList> display_list;
for (int i = 0; i < record_repeat_count_; ++i) {
// Run for a minimum amount of time to avoid problems with timer
// quantization when the layer is very small.
LapTimer timer(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval);
+
do {
- scoped_refptr<Picture> picture = Picture::Create(
- visible_content_rect, painter, tile_grid_info, false, mode);
+ const bool use_cached_picture = true;
+ display_list =
+ DisplayItemList::Create(visible_layer_rect, use_cached_picture);
+ painter->PaintContentsToDisplayList(
+ display_list.get(), visible_layer_rect, painting_control);
+ display_list->CreateAndCacheSkPicture();
+
+ if (memory_used) {
+ // Verify we are recording the same thing each time.
+ DCHECK(memory_used == display_list->PictureMemoryUsage());
+ } else {
+ memory_used = display_list->PictureMemoryUsage();
+ }
+
timer.NextLap();
} while (!timer.HasTimeLimitExpired());
base::TimeDelta duration =
@@ -141,16 +240,18 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
min_time = duration;
}
- if (mode == Picture::RECORD_NORMALLY) {
+ if (mode_index == RecordingSource::RECORD_NORMALLY) {
+ record_results_.bytes_used += memory_used;
record_results_.pixels_recorded +=
- visible_content_rect.width() * visible_content_rect.height();
+ visible_layer_rect.width() * visible_layer_rect.height();
}
record_results_.total_best_time[mode_index] += min_time;
}
}
RasterizeAndRecordBenchmark::RecordResults::RecordResults()
- : pixels_recorded(0) {}
+ : pixels_recorded(0), bytes_used(0) {
+}
RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}
diff --git a/chromium/cc/debug/rasterize_and_record_benchmark.h b/chromium/cc/debug/rasterize_and_record_benchmark.h
index 68d5d05fe6c..207254f24c6 100644
--- a/chromium/cc/debug/rasterize_and_record_benchmark.h
+++ b/chromium/cc/debug/rasterize_and_record_benchmark.h
@@ -10,9 +10,10 @@
#include <vector>
#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "cc/debug/micro_benchmark_controller.h"
-#include "cc/resources/picture.h"
+#include "cc/playback/picture.h"
namespace base {
class DictionaryValue;
@@ -34,10 +35,13 @@ class RasterizeAndRecordBenchmark : public MicroBenchmark {
void RunOnLayer(PictureLayer* layer) override;
scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop) override;
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) override;
private:
- void Run(Layer* layer);
+ void RunOnDisplayListLayer(PictureLayer* layer,
+ const gfx::Rect& visible_layer_rect);
+ void RunOnPictureLayer(PictureLayer* layer,
+ const gfx::Rect& visible_layer_rect);
void RecordRasterResults(scoped_ptr<base::Value> results);
@@ -46,7 +50,8 @@ class RasterizeAndRecordBenchmark : public MicroBenchmark {
~RecordResults();
int pixels_recorded;
- base::TimeDelta total_best_time[Picture::RECORDING_MODE_COUNT];
+ size_t bytes_used;
+ base::TimeDelta total_best_time[RecordingSource::RECORDING_MODE_COUNT];
};
RecordResults record_results_;
diff --git a/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc b/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc
index 2ffac1b38d6..22ae8daeffb 100644
--- a/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -12,9 +12,10 @@
#include "cc/debug/lap_timer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer_impl.h"
-#include "cc/resources/raster_worker_pool.h"
+#include "cc/raster/tile_task_worker_pool.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/layer_tree_impl.h"
#include "ui/gfx/geometry/rect.h"
namespace cc {
@@ -23,68 +24,45 @@ namespace {
const int kDefaultRasterizeRepeatCount = 100;
-class BenchmarkRasterTask : public Task {
- public:
- BenchmarkRasterTask(RasterSource* raster_source,
- const gfx::Rect& content_rect,
- float contents_scale,
- size_t repeat_count)
- : raster_source_(raster_source),
- content_rect_(content_rect),
- contents_scale_(contents_scale),
- repeat_count_(repeat_count),
- is_solid_color_(false),
- best_time_(base::TimeDelta::Max()) {}
-
- // Overridden from Task:
- void RunOnWorkerThread() override {
- // Parameters for LapTimer.
- const int kTimeLimitMillis = 1;
- const int kWarmupRuns = 0;
- const int kTimeCheckInterval = 1;
-
- for (size_t i = 0; i < repeat_count_; ++i) {
- // Run for a minimum amount of time to avoid problems with timer
- // quantization when the layer is very small.
- LapTimer timer(kWarmupRuns,
- base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
- kTimeCheckInterval);
- do {
- SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeN32Premul(content_rect_.width(),
- content_rect_.height()));
- SkCanvas canvas(bitmap);
- RasterSource::SolidColorAnalysis analysis;
-
- raster_source_->PerformSolidColorAnalysis(content_rect_,
- contents_scale_, &analysis);
- raster_source_->PlaybackToCanvas(&canvas, content_rect_,
- contents_scale_);
-
- is_solid_color_ = analysis.is_solid_color;
-
- timer.NextLap();
- } while (!timer.HasTimeLimitExpired());
- base::TimeDelta duration =
- base::TimeDelta::FromMillisecondsD(timer.MsPerLap());
- if (duration < best_time_)
- best_time_ = duration;
- }
+void RunBenchmark(RasterSource* raster_source,
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ size_t repeat_count,
+ base::TimeDelta* min_time,
+ bool* is_solid_color) {
+ // Parameters for LapTimer.
+ const int kTimeLimitMillis = 1;
+ const int kWarmupRuns = 0;
+ const int kTimeCheckInterval = 1;
+
+ *min_time = base::TimeDelta::Max();
+ for (size_t i = 0; i < repeat_count; ++i) {
+ // Run for a minimum amount of time to avoid problems with timer
+ // quantization when the layer is very small.
+ LapTimer timer(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval);
+ do {
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(content_rect.width(),
+ content_rect.height()));
+ SkCanvas canvas(bitmap);
+ RasterSource::SolidColorAnalysis analysis;
+
+ raster_source->PerformSolidColorAnalysis(content_rect, contents_scale,
+ &analysis);
+ raster_source->PlaybackToCanvas(&canvas, content_rect, contents_scale);
+
+ *is_solid_color = analysis.is_solid_color;
+
+ timer.NextLap();
+ } while (!timer.HasTimeLimitExpired());
+ base::TimeDelta duration =
+ base::TimeDelta::FromMillisecondsD(timer.MsPerLap());
+ if (duration < *min_time)
+ *min_time = duration;
}
-
- bool IsSolidColor() const { return is_solid_color_; }
- base::TimeDelta GetBestTime() const { return best_time_; }
-
- private:
- ~BenchmarkRasterTask() override {}
-
- RasterSource* raster_source_;
- gfx::Rect content_rect_;
- float contents_scale_;
- size_t repeat_count_;
- bool is_solid_color_;
- base::TimeDelta best_time_;
-};
+}
class FixedInvalidationPictureLayerTilingClient
: public PictureLayerTilingClient {
@@ -94,13 +72,9 @@ class FixedInvalidationPictureLayerTilingClient
const Region invalidation)
: base_client_(base_client), invalidation_(invalidation) {}
- scoped_refptr<Tile> CreateTile(PictureLayerTiling* tiling,
- const gfx::Rect& content_rect) override {
- return base_client_->CreateTile(tiling, content_rect);
- }
-
- RasterSource* GetRasterSource() override {
- return base_client_->GetRasterSource();
+ ScopedTilePtr CreateTile(float contents_scale,
+ const gfx::Rect& content_rect) override {
+ return base_client_->CreateTile(contents_scale, content_rect);
}
gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override {
@@ -116,25 +90,10 @@ class FixedInvalidationPictureLayerTilingClient
return base_client_->GetPendingOrActiveTwinTiling(tiling);
}
- PictureLayerTiling* GetRecycledTwinTiling(
- const PictureLayerTiling* tiling) override {
- return base_client_->GetRecycledTwinTiling(tiling);
- }
-
- size_t GetMaxTilesForInterestArea() const override {
- return base_client_->GetMaxTilesForInterestArea();
- }
-
- float GetSkewportTargetTimeInSeconds() const override {
- return base_client_->GetSkewportTargetTimeInSeconds();
- }
-
- int GetSkewportExtrapolationLimitInContentPixels() const override {
- return base_client_->GetSkewportExtrapolationLimitInContentPixels();
+ TilePriority::PriorityBin GetMaxTilePriorityBin() const override {
+ return base_client_->GetMaxTilePriorityBin();
}
- WhichTree GetTree() const override { return base_client_->GetTree(); }
-
bool RequiresHighResToDraw() const override {
return base_client_->RequiresHighResToDraw();
}
@@ -147,10 +106,10 @@ class FixedInvalidationPictureLayerTilingClient
} // namespace
RasterizeAndRecordBenchmarkImpl::RasterizeAndRecordBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop,
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner,
base::Value* value,
const MicroBenchmarkImpl::DoneCallback& callback)
- : MicroBenchmarkImpl(callback, origin_loop),
+ : MicroBenchmarkImpl(callback, origin_task_runner),
rasterize_repeat_count_(kDefaultRasterizeRepeatCount) {
base::DictionaryValue* settings = nullptr;
value->GetAsDictionary(&settings);
@@ -166,13 +125,16 @@ RasterizeAndRecordBenchmarkImpl::~RasterizeAndRecordBenchmarkImpl() {}
void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit(
LayerTreeHostImpl* host) {
LayerTreeHostCommon::CallFunctionForSubtree(
- host->RootLayer(),
- base::Bind(&RasterizeAndRecordBenchmarkImpl::Run,
- base::Unretained(this)));
+ host->RootLayer(), [this](LayerImpl* layer) {
+ rasterize_results_.total_layers++;
+ layer->RunMicroBenchmark(this);
+ });
scoped_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",
+ 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);
@@ -189,14 +151,9 @@ void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit(
NotifyDone(result.Pass());
}
-void RasterizeAndRecordBenchmarkImpl::Run(LayerImpl* layer) {
- rasterize_results_.total_layers++;
- layer->RunMicroBenchmark(this);
-}
-
void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) {
rasterize_results_.total_picture_layers++;
- if (!layer->DrawsContent()) {
+ if (!layer->CanHaveTilings()) {
rasterize_results_.total_picture_layers_with_no_content++;
return;
}
@@ -205,74 +162,63 @@ void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) {
return;
}
- TaskGraphRunner* task_graph_runner = RasterWorkerPool::GetTaskGraphRunner();
- DCHECK(task_graph_runner);
-
- if (!task_namespace_.IsValid())
- task_namespace_ = task_graph_runner->GetNamespaceToken();
-
FixedInvalidationPictureLayerTilingClient client(
layer, gfx::Rect(layer->content_bounds()));
- PictureLayerTilingSet tiling_set(&client);
- PictureLayerTiling* tiling =
- tiling_set.AddTiling(layer->contents_scale_x(), layer->bounds());
+ // In this benchmark, we will create a local tiling set and measure how long
+ // it takes to rasterize content. As such, the actual settings used here don't
+ // really matter.
+ const LayerTreeSettings& settings = layer->layer_tree_impl()->settings();
+ scoped_ptr<PictureLayerTilingSet> tiling_set = PictureLayerTilingSet::Create(
+ layer->GetTree(), &client,
+ settings.tiling_interest_area_viewport_multiplier,
+ settings.skewport_target_time_in_seconds,
+ settings.skewport_extrapolation_limit_in_content_pixels);
+
+ PictureLayerTiling* tiling = tiling_set->AddTiling(layer->contents_scale_x(),
+ layer->GetRasterSource());
tiling->CreateAllTilesForTesting();
+ RasterSource* raster_source = tiling->raster_source();
for (PictureLayerTiling::CoverageIterator it(
tiling, layer->contents_scale_x(), layer->visible_content_rect());
it;
++it) {
DCHECK(*it);
- RasterSource* raster_source = (*it)->raster_source();
gfx::Rect content_rect = (*it)->content_rect();
float contents_scale = (*it)->contents_scale();
- scoped_refptr<BenchmarkRasterTask> benchmark_raster_task(
- new BenchmarkRasterTask(raster_source,
- content_rect,
- contents_scale,
- rasterize_repeat_count_));
-
- TaskGraph graph;
-
- graph.nodes.push_back(
- TaskGraph::Node(benchmark_raster_task.get(),
- RasterWorkerPool::kBenchmarkRasterTaskPriority,
- 0u));
-
- task_graph_runner->ScheduleTasks(task_namespace_, &graph);
- task_graph_runner->WaitForTasksToFinishRunning(task_namespace_);
-
- Task::Vector completed_tasks;
- task_graph_runner->CollectCompletedTasks(task_namespace_, &completed_tasks);
- DCHECK_EQ(1u, completed_tasks.size());
- DCHECK_EQ(completed_tasks[0], benchmark_raster_task);
+ base::TimeDelta min_time;
+ bool is_solid_color = false;
+ RunBenchmark(raster_source, content_rect, contents_scale,
+ rasterize_repeat_count_, &min_time, &is_solid_color);
int tile_size = content_rect.width() * content_rect.height();
- base::TimeDelta min_time = benchmark_raster_task->GetBestTime();
- bool is_solid_color = benchmark_raster_task->IsSolidColor();
-
if (layer->contents_opaque())
rasterize_results_.pixels_rasterized_as_opaque += tile_size;
- if (!is_solid_color) {
+ if (!is_solid_color)
rasterize_results_.pixels_rasterized_with_non_solid_color += tile_size;
- }
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->GetPictureMemoryUsage();
}
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),
- total_picture_layers_off_screen(0) {}
+ total_picture_layers_off_screen(0) {
+}
RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {}
diff --git a/chromium/cc/debug/rasterize_and_record_benchmark_impl.h b/chromium/cc/debug/rasterize_and_record_benchmark_impl.h
index c0f26fd3704..0ab95438256 100644
--- a/chromium/cc/debug/rasterize_and_record_benchmark_impl.h
+++ b/chromium/cc/debug/rasterize_and_record_benchmark_impl.h
@@ -9,9 +9,10 @@
#include <utility>
#include <vector>
+#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "cc/debug/micro_benchmark_impl.h"
-#include "cc/resources/task_graph_runner.h"
+#include "cc/raster/task_graph_runner.h"
namespace cc {
@@ -21,7 +22,7 @@ class LayerImpl;
class RasterizeAndRecordBenchmarkImpl : public MicroBenchmarkImpl {
public:
explicit RasterizeAndRecordBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop,
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner,
base::Value* value,
const MicroBenchmarkImpl::DoneCallback& callback);
~RasterizeAndRecordBenchmarkImpl() override;
@@ -31,8 +32,6 @@ class RasterizeAndRecordBenchmarkImpl : public MicroBenchmarkImpl {
void RunOnLayer(PictureLayerImpl* layer) override;
private:
- void Run(LayerImpl* layer);
-
struct RasterizeResults {
RasterizeResults();
~RasterizeResults();
@@ -41,6 +40,7 @@ class RasterizeAndRecordBenchmarkImpl : public MicroBenchmarkImpl {
int pixels_rasterized_with_non_solid_color;
int pixels_rasterized_as_opaque;
base::TimeDelta total_best_time;
+ int total_memory_usage;
int total_layers;
int total_picture_layers;
int total_picture_layers_with_no_content;
@@ -49,7 +49,6 @@ class RasterizeAndRecordBenchmarkImpl : public MicroBenchmarkImpl {
RasterizeResults rasterize_results_;
int rasterize_repeat_count_;
- NamespaceToken task_namespace_;
};
} // namespace cc
diff --git a/chromium/cc/debug/rendering_stats.cc b/chromium/cc/debug/rendering_stats.cc
index 558c882ec7c..582c76341e2 100644
--- a/chromium/cc/debug/rendering_stats.cc
+++ b/chromium/cc/debug/rendering_stats.cc
@@ -17,11 +17,13 @@ void RenderingStats::TimeDeltaList::Append(base::TimeDelta value) {
}
void RenderingStats::TimeDeltaList::AddToTracedValue(
- base::debug::TracedValue* list_value) const {
- std::list<base::TimeDelta>::const_iterator iter;
- for (iter = values.begin(); iter != values.end(); ++iter) {
- list_value->AppendDouble(iter->InMillisecondsF());
+ const char* name,
+ base::trace_event::TracedValue* list_value) const {
+ list_value->BeginArray(name);
+ for (const auto& value : values) {
+ list_value->AppendDouble(value.InMillisecondsF());
}
+ list_value->EndArray();
}
void RenderingStats::TimeDeltaList::Add(const TimeDeltaList& other) {
@@ -32,81 +34,51 @@ base::TimeDelta RenderingStats::TimeDeltaList::GetLastTimeDelta() const {
return values.empty() ? base::TimeDelta() : values.back();
}
-RenderingStats::MainThreadRenderingStats::MainThreadRenderingStats()
- : painted_pixel_count(0), recorded_pixel_count(0) {
-}
-
-RenderingStats::MainThreadRenderingStats::~MainThreadRenderingStats() {
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-RenderingStats::MainThreadRenderingStats::AsTraceableData() const {
- scoped_refptr<base::debug::TracedValue> record_data =
- new base::debug::TracedValue();
- record_data->SetDouble("paint_time", paint_time.InSecondsF());
- record_data->SetInteger("painted_pixel_count", painted_pixel_count);
- record_data->SetDouble("record_time", record_time.InSecondsF());
- record_data->SetInteger("recorded_pixel_count", recorded_pixel_count);
- return record_data;
-}
-
-void RenderingStats::MainThreadRenderingStats::Add(
- const MainThreadRenderingStats& other) {
- paint_time += other.paint_time;
- painted_pixel_count += other.painted_pixel_count;
- record_time += other.record_time;
- recorded_pixel_count += other.recorded_pixel_count;
-}
-
-RenderingStats::ImplThreadRenderingStats::ImplThreadRenderingStats()
+RenderingStats::RenderingStats()
: frame_count(0),
visible_content_area(0),
- approximated_visible_content_area(0) {
+ approximated_visible_content_area(0),
+ checkerboarded_visible_content_area(0) {
}
-RenderingStats::ImplThreadRenderingStats::~ImplThreadRenderingStats() {
+RenderingStats::~RenderingStats() {
}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-RenderingStats::ImplThreadRenderingStats::AsTraceableData() const {
- scoped_refptr<base::debug::TracedValue> record_data =
- new base::debug::TracedValue();
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+RenderingStats::AsTraceableData() const {
+ scoped_refptr<base::trace_event::TracedValue> record_data =
+ new base::trace_event::TracedValue();
record_data->SetInteger("frame_count", frame_count);
record_data->SetInteger("visible_content_area", visible_content_area);
record_data->SetInteger("approximated_visible_content_area",
approximated_visible_content_area);
- record_data->BeginArray("draw_duration_ms");
- draw_duration.AddToTracedValue(record_data.get());
- record_data->EndArray();
+ record_data->SetInteger("checkerboarded_visible_content_area",
+ checkerboarded_visible_content_area);
+ draw_duration.AddToTracedValue("draw_duration_ms", record_data.get());
- record_data->BeginArray("draw_duration_estimate_ms");
- draw_duration_estimate.AddToTracedValue(record_data.get());
- record_data->EndArray();
+ draw_duration_estimate.AddToTracedValue("draw_duration_estimate_ms",
+ record_data.get());
- record_data->BeginArray("begin_main_frame_to_commit_duration_ms");
- begin_main_frame_to_commit_duration.AddToTracedValue(record_data.get());
- record_data->EndArray();
+ begin_main_frame_to_commit_duration.AddToTracedValue(
+ "begin_main_frame_to_commit_duration_ms", record_data.get());
- record_data->BeginArray("begin_main_frame_to_commit_duration_estimate_ms");
begin_main_frame_to_commit_duration_estimate.AddToTracedValue(
- record_data.get());
- record_data->EndArray();
+ "begin_main_frame_to_commit_duration_estimate_ms", record_data.get());
- record_data->BeginArray("commit_to_activate_duration_ms");
- commit_to_activate_duration.AddToTracedValue(record_data.get());
- record_data->EndArray();
+ commit_to_activate_duration.AddToTracedValue("commit_to_activate_duration_ms",
+ record_data.get());
- record_data->BeginArray("commit_to_activate_duration_estimate_ms");
- commit_to_activate_duration_estimate.AddToTracedValue(record_data.get());
- record_data->EndArray();
+ commit_to_activate_duration_estimate.AddToTracedValue(
+ "commit_to_activate_duration_estimate_ms", record_data.get());
return record_data;
}
-void RenderingStats::ImplThreadRenderingStats::Add(
- const ImplThreadRenderingStats& other) {
+void RenderingStats::Add(const RenderingStats& other) {
frame_count += other.frame_count;
visible_content_area += other.visible_content_area;
approximated_visible_content_area += other.approximated_visible_content_area;
+ checkerboarded_visible_content_area +=
+ other.checkerboarded_visible_content_area;
draw_duration.Add(other.draw_duration);
draw_duration_estimate.Add(other.draw_duration_estimate);
@@ -119,9 +91,4 @@ void RenderingStats::ImplThreadRenderingStats::Add(
other.commit_to_activate_duration_estimate);
}
-void RenderingStats::Add(const RenderingStats& other) {
- main_stats.Add(other.main_stats);
- impl_stats.Add(other.impl_stats);
-}
-
} // namespace cc
diff --git a/chromium/cc/debug/rendering_stats.h b/chromium/cc/debug/rendering_stats.h
index 7b1898a9daa..cb7ebb2cbab 100644
--- a/chromium/cc/debug/rendering_stats.h
+++ b/chromium/cc/debug/rendering_stats.h
@@ -5,11 +5,11 @@
#ifndef CC_DEBUG_RENDERING_STATS_H_
#define CC_DEBUG_RENDERING_STATS_H_
-#include <list>
+#include <vector>
#include "base/basictypes.h"
-#include "base/debug/trace_event_argument.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/cc_export.h"
#include "cc/debug/traced_value.h"
@@ -24,58 +24,37 @@ struct CC_EXPORT RenderingStats {
~TimeDeltaList();
void Append(base::TimeDelta value);
- void AddToTracedValue(base::debug::TracedValue* list_value) const;
+ void AddToTracedValue(const char* name,
+ base::trace_event::TracedValue* list_value) const;
void Add(const TimeDeltaList& other);
base::TimeDelta GetLastTimeDelta() const;
private:
- std::list<base::TimeDelta> values;
+ std::vector<base::TimeDelta> values;
};
- struct CC_EXPORT MainThreadRenderingStats {
- // Note: when adding new members, please remember to update Add in
- // rendering_stats.cc.
+ RenderingStats();
+ ~RenderingStats();
- base::TimeDelta paint_time;
- int64 painted_pixel_count;
- base::TimeDelta record_time;
- int64 recorded_pixel_count;
+ // Note: when adding new members, please remember to update Add in
+ // rendering_stats.cc.
- MainThreadRenderingStats();
- ~MainThreadRenderingStats();
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData()
- const;
- void Add(const MainThreadRenderingStats& other);
- };
-
- struct CC_EXPORT ImplThreadRenderingStats {
- // Note: when adding new members, please remember to update Add in
- // rendering_stats.cc.
-
- int64 frame_count;
- int64 visible_content_area;
- int64 approximated_visible_content_area;
-
- TimeDeltaList draw_duration;
- TimeDeltaList draw_duration_estimate;
- TimeDeltaList begin_main_frame_to_commit_duration;
- TimeDeltaList begin_main_frame_to_commit_duration_estimate;
- TimeDeltaList commit_to_activate_duration;
- TimeDeltaList commit_to_activate_duration_estimate;
-
- ImplThreadRenderingStats();
- ~ImplThreadRenderingStats();
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData()
- const;
- void Add(const ImplThreadRenderingStats& other);
- };
+ int64 frame_count;
+ int64 visible_content_area;
+ int64 approximated_visible_content_area;
+ int64 checkerboarded_visible_content_area;
- MainThreadRenderingStats main_stats;
- ImplThreadRenderingStats impl_stats;
+ TimeDeltaList draw_duration;
+ TimeDeltaList draw_duration_estimate;
+ TimeDeltaList begin_main_frame_to_commit_duration;
+ TimeDeltaList begin_main_frame_to_commit_duration_estimate;
+ TimeDeltaList commit_to_activate_duration;
+ TimeDeltaList commit_to_activate_duration_estimate;
- // Add fields of |other| to the fields in this structure.
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsTraceableData()
+ const;
void Add(const RenderingStats& other);
};
diff --git a/chromium/cc/debug/rendering_stats_instrumentation.cc b/chromium/cc/debug/rendering_stats_instrumentation.cc
index f5f2e07225d..7497c628ed1 100644
--- a/chromium/cc/debug/rendering_stats_instrumentation.cc
+++ b/chromium/cc/debug/rendering_stats_instrumentation.cc
@@ -18,14 +18,7 @@ RenderingStatsInstrumentation::RenderingStatsInstrumentation()
RenderingStatsInstrumentation::~RenderingStatsInstrumentation() {}
-RenderingStats::MainThreadRenderingStats
-RenderingStatsInstrumentation::main_thread_rendering_stats() {
- base::AutoLock scoped_lock(lock_);
- return main_thread_rendering_stats_;
-}
-
-RenderingStats::ImplThreadRenderingStats
-RenderingStatsInstrumentation::impl_thread_rendering_stats() {
+RenderingStats RenderingStatsInstrumentation::impl_thread_rendering_stats() {
base::AutoLock scoped_lock(lock_);
return impl_thread_rendering_stats_;
}
@@ -33,30 +26,22 @@ RenderingStatsInstrumentation::impl_thread_rendering_stats() {
RenderingStats RenderingStatsInstrumentation::GetRenderingStats() {
base::AutoLock scoped_lock(lock_);
RenderingStats rendering_stats;
- rendering_stats.main_stats = main_thread_rendering_stats_accu_;
- rendering_stats.main_stats.Add(main_thread_rendering_stats_);
- rendering_stats.impl_stats = impl_thread_rendering_stats_accu_;
- rendering_stats.impl_stats.Add(impl_thread_rendering_stats_);
+ rendering_stats = impl_thread_rendering_stats_accu_;
+ rendering_stats.Add(impl_thread_rendering_stats_);
return rendering_stats;
}
-void RenderingStatsInstrumentation::AccumulateAndClearMainThreadStats() {
- base::AutoLock scoped_lock(lock_);
- main_thread_rendering_stats_accu_.Add(main_thread_rendering_stats_);
- main_thread_rendering_stats_ = RenderingStats::MainThreadRenderingStats();
-}
-
void RenderingStatsInstrumentation::AccumulateAndClearImplThreadStats() {
base::AutoLock scoped_lock(lock_);
impl_thread_rendering_stats_accu_.Add(impl_thread_rendering_stats_);
- impl_thread_rendering_stats_ = RenderingStats::ImplThreadRenderingStats();
+ impl_thread_rendering_stats_ = RenderingStats();
}
base::TimeTicks RenderingStatsInstrumentation::StartRecording() const {
if (record_rendering_stats_) {
if (base::TimeTicks::IsThreadNowSupported())
return base::TimeTicks::ThreadNow();
- return base::TimeTicks::HighResNow();
+ return base::TimeTicks::Now();
}
return base::TimeTicks();
}
@@ -66,7 +51,7 @@ base::TimeDelta RenderingStatsInstrumentation::EndRecording(
if (!start_time.is_null()) {
if (base::TimeTicks::IsThreadNowSupported())
return base::TimeTicks::ThreadNow() - start_time;
- return base::TimeTicks::HighResNow() - start_time;
+ return base::TimeTicks::Now() - start_time;
}
return base::TimeDelta();
}
@@ -79,41 +64,30 @@ void RenderingStatsInstrumentation::IncrementFrameCount(int64 count) {
impl_thread_rendering_stats_.frame_count += count;
}
-void RenderingStatsInstrumentation::AddPaint(base::TimeDelta duration,
- int64 pixels) {
- if (!record_rendering_stats_)
- return;
-
- base::AutoLock scoped_lock(lock_);
- main_thread_rendering_stats_.paint_time += duration;
- main_thread_rendering_stats_.painted_pixel_count += pixels;
-}
-
-void RenderingStatsInstrumentation::AddRecord(base::TimeDelta duration,
- int64 pixels) {
+void RenderingStatsInstrumentation::AddVisibleContentArea(int64 area) {
if (!record_rendering_stats_)
return;
base::AutoLock scoped_lock(lock_);
- main_thread_rendering_stats_.record_time += duration;
- main_thread_rendering_stats_.recorded_pixel_count += pixels;
+ impl_thread_rendering_stats_.visible_content_area += area;
}
-void RenderingStatsInstrumentation::AddVisibleContentArea(int64 area) {
+void RenderingStatsInstrumentation::AddApproximatedVisibleContentArea(
+ int64 area) {
if (!record_rendering_stats_)
return;
base::AutoLock scoped_lock(lock_);
- impl_thread_rendering_stats_.visible_content_area += area;
+ impl_thread_rendering_stats_.approximated_visible_content_area += area;
}
-void RenderingStatsInstrumentation::AddApproximatedVisibleContentArea(
+void RenderingStatsInstrumentation::AddCheckerboardedVisibleContentArea(
int64 area) {
if (!record_rendering_stats_)
return;
base::AutoLock scoped_lock(lock_);
- impl_thread_rendering_stats_.approximated_visible_content_area += area;
+ impl_thread_rendering_stats_.checkerboarded_visible_content_area += area;
}
void RenderingStatsInstrumentation::AddDrawDuration(
diff --git a/chromium/cc/debug/rendering_stats_instrumentation.h b/chromium/cc/debug/rendering_stats_instrumentation.h
index 734583a5815..2a6e3b7eb6e 100644
--- a/chromium/cc/debug/rendering_stats_instrumentation.h
+++ b/chromium/cc/debug/rendering_stats_instrumentation.h
@@ -18,19 +18,12 @@ class CC_EXPORT RenderingStatsInstrumentation {
static scoped_ptr<RenderingStatsInstrumentation> Create();
virtual ~RenderingStatsInstrumentation();
- // Return copy of current main thread rendering stats.
- RenderingStats::MainThreadRenderingStats main_thread_rendering_stats();
-
// Return copy of current impl thread rendering stats.
- RenderingStats::ImplThreadRenderingStats impl_thread_rendering_stats();
+ RenderingStats impl_thread_rendering_stats();
// Return the accumulated, combined rendering stats.
RenderingStats GetRenderingStats();
- // Add current main thread rendering stats to accumulator and
- // clear current stats.
- void AccumulateAndClearMainThreadStats();
-
// Add current impl thread rendering stats to accumulator and
// clear current stats.
void AccumulateAndClearImplThreadStats();
@@ -48,10 +41,9 @@ class CC_EXPORT RenderingStatsInstrumentation {
base::TimeDelta EndRecording(base::TimeTicks start_time) const;
void IncrementFrameCount(int64 count);
- void AddPaint(base::TimeDelta duration, int64 pixels);
- void AddRecord(base::TimeDelta duration, int64 pixels);
void AddVisibleContentArea(int64 area);
void AddApproximatedVisibleContentArea(int64 area);
+ void AddCheckerboardedVisibleContentArea(int64 area);
void AddDrawDuration(base::TimeDelta draw_duration,
base::TimeDelta draw_duration_estimate);
void AddBeginMainFrameToCommitDuration(
@@ -65,10 +57,8 @@ class CC_EXPORT RenderingStatsInstrumentation {
RenderingStatsInstrumentation();
private:
- RenderingStats::MainThreadRenderingStats main_thread_rendering_stats_;
- RenderingStats::MainThreadRenderingStats main_thread_rendering_stats_accu_;
- RenderingStats::ImplThreadRenderingStats impl_thread_rendering_stats_;
- RenderingStats::ImplThreadRenderingStats impl_thread_rendering_stats_accu_;
+ RenderingStats impl_thread_rendering_stats_;
+ RenderingStats impl_thread_rendering_stats_accu_;
bool record_rendering_stats_;
diff --git a/chromium/cc/debug/rendering_stats_unittest.cc b/chromium/cc/debug/rendering_stats_unittest.cc
index a6340932371..6784e09f66b 100644
--- a/chromium/cc/debug/rendering_stats_unittest.cc
+++ b/chromium/cc/debug/rendering_stats_unittest.cc
@@ -13,11 +13,9 @@ namespace cc {
namespace {
static std::string ToString(const RenderingStats::TimeDeltaList& list) {
- scoped_refptr<base::debug::TracedValue> value =
- new base::debug::TracedValue();
- value->BeginArray("list_value");
- list.AddToTracedValue(value.get());
- value->EndArray();
+ scoped_refptr<base::trace_event::TracedValue> value =
+ new base::trace_event::TracedValue();
+ list.AddToTracedValue("list_value", value.get());
return value->ToString();
}
diff --git a/chromium/cc/debug/ring_buffer.h b/chromium/cc/debug/ring_buffer.h
index 94d8459acd7..f9a6749e116 100644
--- a/chromium/cc/debug/ring_buffer.h
+++ b/chromium/cc/debug/ring_buffer.h
@@ -12,9 +12,7 @@ namespace cc {
template<typename T, size_t kSize>
class RingBuffer {
public:
- explicit RingBuffer()
- : current_index_(0) {
- }
+ RingBuffer() : current_index_(0) {}
size_t BufferSize() const {
return kSize;
diff --git a/chromium/cc/debug/traced_picture.cc b/chromium/cc/debug/traced_picture.cc
index 2db549234d8..2c7622b66d5 100644
--- a/chromium/cc/debug/traced_picture.cc
+++ b/chromium/cc/debug/traced_picture.cc
@@ -16,17 +16,17 @@ TracedPicture::TracedPicture(scoped_refptr<const Picture> picture)
TracedPicture::~TracedPicture() {
}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
TracedPicture::AsTraceablePicture(const Picture* picture) {
- return scoped_refptr<base::debug::ConvertableToTraceFormat>(
+ return scoped_refptr<base::trace_event::ConvertableToTraceFormat>(
new TracedPicture(picture));
}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
TracedPicture::AsTraceablePictureAlias(const Picture* original) {
scoped_refptr<TracedPicture> ptr = new TracedPicture(original);
ptr->is_alias_ = true;
- return scoped_refptr<base::debug::ConvertableToTraceFormat>(ptr);
+ return scoped_refptr<base::trace_event::ConvertableToTraceFormat>(ptr);
}
void TracedPicture::AppendAsTraceFormat(std::string* out) const {
diff --git a/chromium/cc/debug/traced_picture.h b/chromium/cc/debug/traced_picture.h
index b5f5e3ae134..0cb044e7212 100644
--- a/chromium/cc/debug/traced_picture.h
+++ b/chromium/cc/debug/traced_picture.h
@@ -7,20 +7,20 @@
#include <string>
-#include "base/debug/trace_event.h"
#include "base/memory/scoped_ptr.h"
-#include "cc/resources/picture.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/playback/picture.h"
namespace cc {
-class TracedPicture : public base::debug::ConvertableToTraceFormat {
+class TracedPicture : public base::trace_event::ConvertableToTraceFormat {
public:
explicit TracedPicture(scoped_refptr<const Picture>);
- static scoped_refptr<base::debug::ConvertableToTraceFormat>
+ static scoped_refptr<base::trace_event::ConvertableToTraceFormat>
AsTraceablePicture(const Picture* picture);
- static scoped_refptr<base::debug::ConvertableToTraceFormat>
+ static scoped_refptr<base::trace_event::ConvertableToTraceFormat>
AsTraceablePictureAlias(const Picture* original);
void AppendAsTraceFormat(std::string* out) const override;
diff --git a/chromium/cc/debug/traced_value.cc b/chromium/cc/debug/traced_value.cc
index 5828cb8894e..c2ac7f55101 100644
--- a/chromium/cc/debug/traced_value.cc
+++ b/chromium/cc/debug/traced_value.cc
@@ -4,34 +4,36 @@
#include "cc/debug/traced_value.h"
-#include "base/debug/trace_event_argument.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
namespace cc {
-void TracedValue::AppendIDRef(const void* id, base::debug::TracedValue* state) {
+void TracedValue::AppendIDRef(const void* id,
+ base::trace_event::TracedValue* state) {
state->BeginDictionary();
state->SetString("id_ref", base::StringPrintf("%p", id));
state->EndDictionary();
}
void TracedValue::SetIDRef(const void* id,
- base::debug::TracedValue* state,
+ base::trace_event::TracedValue* state,
const char* name) {
state->BeginDictionary(name);
state->SetString("id_ref", base::StringPrintf("%p", id));
state->EndDictionary();
}
-void TracedValue::MakeDictIntoImplicitSnapshot(base::debug::TracedValue* dict,
- const char* object_name,
- const void* id) {
+void TracedValue::MakeDictIntoImplicitSnapshot(
+ base::trace_event::TracedValue* dict,
+ const char* object_name,
+ const void* id) {
dict->SetString("id", base::StringPrintf("%s/%p", object_name, id));
}
void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
const char* category,
- base::debug::TracedValue* dict,
+ base::trace_event::TracedValue* dict,
const char* object_name,
const void* id) {
dict->SetString("cat", category);
@@ -40,7 +42,7 @@ void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
const char* category,
- base::debug::TracedValue* dict,
+ base::trace_event::TracedValue* dict,
const char* object_base_type_name,
const char* object_name,
const void* id) {
diff --git a/chromium/cc/debug/traced_value.h b/chromium/cc/debug/traced_value.h
index c5ea30aedda..34e79a7a062 100644
--- a/chromium/cc/debug/traced_value.h
+++ b/chromium/cc/debug/traced_value.h
@@ -6,7 +6,7 @@
#define CC_DEBUG_TRACED_VALUE_H_
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
}
@@ -15,21 +15,22 @@ namespace cc {
class TracedValue {
public:
- static void AppendIDRef(const void* id, base::debug::TracedValue* array);
+ static void AppendIDRef(const void* id,
+ base::trace_event::TracedValue* array);
static void SetIDRef(const void* id,
- base::debug::TracedValue* dict,
+ base::trace_event::TracedValue* dict,
const char* name);
- static void MakeDictIntoImplicitSnapshot(base::debug::TracedValue* dict,
+ static void MakeDictIntoImplicitSnapshot(base::trace_event::TracedValue* dict,
const char* object_name,
const void* id);
static void MakeDictIntoImplicitSnapshotWithCategory(
const char* category,
- base::debug::TracedValue* dict,
+ base::trace_event::TracedValue* dict,
const char* object_name,
const void* id);
static void MakeDictIntoImplicitSnapshotWithCategory(
const char* category,
- base::debug::TracedValue* dict,
+ base::trace_event::TracedValue* dict,
const char* object_base_type_name,
const char* object_name,
const void* id);
diff --git a/chromium/cc/debug/unittest_only_benchmark.cc b/chromium/cc/debug/unittest_only_benchmark.cc
index 2bd5be99d98..81158122f95 100644
--- a/chromium/cc/debug/unittest_only_benchmark.cc
+++ b/chromium/cc/debug/unittest_only_benchmark.cc
@@ -5,7 +5,7 @@
#include "cc/debug/unittest_only_benchmark.h"
#include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/values.h"
#include "cc/debug/unittest_only_benchmark_impl.h"
@@ -53,13 +53,12 @@ void UnittestOnlyBenchmark::RecordImplResults(scoped_ptr<base::Value> results) {
}
scoped_ptr<MicroBenchmarkImpl> UnittestOnlyBenchmark::CreateBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop) {
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) {
if (!create_impl_benchmark_)
return make_scoped_ptr<MicroBenchmarkImpl>(nullptr);
return make_scoped_ptr(new UnittestOnlyBenchmarkImpl(
- origin_loop,
- nullptr,
+ origin_task_runner, nullptr,
base::Bind(&UnittestOnlyBenchmark::RecordImplResults,
weak_ptr_factory_.GetWeakPtr())));
}
diff --git a/chromium/cc/debug/unittest_only_benchmark.h b/chromium/cc/debug/unittest_only_benchmark.h
index 7fa2b4dcab4..4e74ec7912c 100644
--- a/chromium/cc/debug/unittest_only_benchmark.h
+++ b/chromium/cc/debug/unittest_only_benchmark.h
@@ -8,6 +8,10 @@
#include "base/memory/weak_ptr.h"
#include "cc/debug/micro_benchmark.h"
+namespace base {
+class SingleThreadIdleTaskRunner;
+}
+
namespace cc {
class CC_EXPORT UnittestOnlyBenchmark : public MicroBenchmark {
@@ -21,7 +25,7 @@ class CC_EXPORT UnittestOnlyBenchmark : public MicroBenchmark {
protected:
scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop) override;
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner) override;
private:
void RecordImplResults(scoped_ptr<base::Value> results);
diff --git a/chromium/cc/debug/unittest_only_benchmark_impl.cc b/chromium/cc/debug/unittest_only_benchmark_impl.cc
index a3b040f0d44..59e3d274738 100644
--- a/chromium/cc/debug/unittest_only_benchmark_impl.cc
+++ b/chromium/cc/debug/unittest_only_benchmark_impl.cc
@@ -4,16 +4,17 @@
#include "cc/debug/unittest_only_benchmark_impl.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "base/values.h"
namespace cc {
UnittestOnlyBenchmarkImpl::UnittestOnlyBenchmarkImpl(
- scoped_refptr<base::MessageLoopProxy> origin_loop,
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner,
base::Value* settings,
const DoneCallback& callback)
- : MicroBenchmarkImpl(callback, origin_loop) {}
+ : MicroBenchmarkImpl(callback, origin_task_runner) {
+}
UnittestOnlyBenchmarkImpl::~UnittestOnlyBenchmarkImpl() {}
diff --git a/chromium/cc/debug/unittest_only_benchmark_impl.h b/chromium/cc/debug/unittest_only_benchmark_impl.h
index f9b256d3c69..1444850fb93 100644
--- a/chromium/cc/debug/unittest_only_benchmark_impl.h
+++ b/chromium/cc/debug/unittest_only_benchmark_impl.h
@@ -9,8 +9,8 @@
#include "cc/debug/micro_benchmark_impl.h"
namespace base {
+class SingleThreadTaskRunner;
class Value;
-class MessageLoopProxy;
}
namespace cc {
@@ -18,9 +18,10 @@ namespace cc {
class LayerTreeHostImpl;
class CC_EXPORT UnittestOnlyBenchmarkImpl : public MicroBenchmarkImpl {
public:
- UnittestOnlyBenchmarkImpl(scoped_refptr<base::MessageLoopProxy> origin_loop,
- base::Value* settings,
- const DoneCallback& callback);
+ UnittestOnlyBenchmarkImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner,
+ base::Value* settings,
+ const DoneCallback& callback);
~UnittestOnlyBenchmarkImpl() override;
void DidCompleteCommit(LayerTreeHostImpl* host) override;
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index 7a9c9919687..81d91b87143 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -9,8 +9,8 @@
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "cc/base/cc_export.h"
-#include "cc/base/swap_promise_monitor.h"
#include "cc/input/scrollbar.h"
+#include "cc/trees/swap_promise_monitor.h"
namespace gfx {
class Point;
@@ -24,6 +24,7 @@ namespace ui { struct LatencyInfo; }
namespace cc {
class LayerScrollOffsetDelegate;
+class ScrollElasticityHelper;
struct CC_EXPORT InputHandlerScrollResult {
InputHandlerScrollResult();
@@ -47,6 +48,7 @@ class CC_EXPORT InputHandlerClient {
virtual void WillShutdown() = 0;
virtual void Animate(base::TimeTicks time) = 0;
virtual void MainThreadHasStoppedFlinging() = 0;
+ virtual void ReconcileElasticOverscrollAndRootScroll() = 0;
protected:
InputHandlerClient() {}
@@ -64,14 +66,14 @@ class CC_EXPORT InputHandler {
// Note these are used in a histogram. Do not reorder or delete existing
// entries.
enum ScrollStatus {
- ScrollOnMainThread = 0,
- ScrollStarted,
- ScrollIgnored,
- ScrollUnknown,
+ SCROLL_ON_MAIN_THREAD = 0,
+ SCROLL_STARTED,
+ SCROLL_IGNORED,
+ SCROLL_UNKNOWN,
// This must be the last entry.
ScrollStatusCount
};
- enum ScrollInputType { Gesture, Wheel, NonBubblingGesture };
+ enum ScrollInputType { GESTURE, WHEEL, NON_BUBBLING_GESTURE };
// Binds a client to this handler to receive notifications. Only one client
// can be bound to an InputHandler. The client must live at least until the
@@ -79,10 +81,10 @@ class CC_EXPORT InputHandler {
virtual void BindToClient(InputHandlerClient* client) = 0;
// Selects a layer to be scrolled at a given point in viewport (logical
- // pixel) coordinates. Returns ScrollStarted if the layer at the coordinates
- // can be scrolled, ScrollOnMainThread if the scroll event should instead be
- // delegated to the main thread, or ScrollIgnored if there is nothing to be
- // scrolled at the given coordinates.
+ // pixel) coordinates. Returns SCROLL_STARTED if the layer at the coordinates
+ // can be scrolled, SCROLL_ON_MAIN_THREAD if the scroll event should instead
+ // be delegated to the main thread, or SCROLL_IGNORED if there is nothing to
+ // be scrolled at the given coordinates.
virtual ScrollStatus ScrollBegin(const gfx::Point& viewport_point,
ScrollInputType type) = 0;
@@ -100,7 +102,7 @@ class CC_EXPORT InputHandler {
// If the scroll delta hits the root layer, and the layer can no longer move,
// the root overscroll accumulated within this ScrollBegin() scope is reported
// in the return value's |accumulated_overscroll| field.
- // Should only be called if ScrollBegin() returned ScrollStarted.
+ // Should only be called if ScrollBegin() returned SCROLL_STARTED.
virtual InputHandlerScrollResult ScrollBy(
const gfx::Point& viewport_point,
const gfx::Vector2dF& scroll_delta) = 0;
@@ -108,14 +110,14 @@ class CC_EXPORT InputHandler {
virtual bool ScrollVerticallyByPage(const gfx::Point& viewport_point,
ScrollDirection direction) = 0;
- // Returns ScrollStarted if a layer was being actively being scrolled,
- // ScrollIgnored if not.
+ // Returns SCROLL_STARTED if a layer was being actively being scrolled,
+ // SCROLL_IGNORED if not.
virtual ScrollStatus FlingScrollBegin() = 0;
virtual void MouseMoveAt(const gfx::Point& mouse_position) = 0;
// Stop scrolling the selected layer. Should only be called if ScrollBegin()
- // returned ScrollStarted.
+ // returned SCROLL_STARTED.
virtual void ScrollEnd() = 0;
virtual void SetRootLayerScrollOffsetDelegate(
@@ -140,7 +142,11 @@ class CC_EXPORT InputHandler {
virtual bool IsCurrentlyScrollingLayerAt(const gfx::Point& viewport_point,
ScrollInputType type) = 0;
- virtual bool HaveTouchEventHandlersAt(const gfx::Point& viewport_point) = 0;
+ virtual bool HaveWheelEventHandlersAt(const gfx::Point& viewport_point) = 0;
+
+ // Whether the page should be given the opportunity to suppress scrolling by
+ // consuming touch events that started at |viewport_point|.
+ virtual bool DoTouchEventsBlockScrollAt(const gfx::Point& viewport_point) = 0;
// Calling CreateLatencyInfoSwapPromiseMonitor() to get a scoped
// LatencyInfoSwapPromiseMonitor. During the life time of the
@@ -150,6 +156,8 @@ class CC_EXPORT InputHandler {
virtual scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
ui::LatencyInfo* latency) = 0;
+ virtual ScrollElasticityHelper* CreateScrollElasticityHelper() = 0;
+
protected:
InputHandler() {}
virtual ~InputHandler() {}
diff --git a/chromium/cc/input/layer_selection_bound.h b/chromium/cc/input/layer_selection_bound.h
index 21d52849cf3..10b14d904d2 100644
--- a/chromium/cc/input/layer_selection_bound.h
+++ b/chromium/cc/input/layer_selection_bound.h
@@ -6,6 +6,7 @@
#define CC_INPUT_LAYER_SELECTION_BOUND_H_
#include "cc/base/cc_export.h"
+#include "cc/input/selection.h"
#include "cc/input/selection_bound_type.h"
#include "ui/gfx/geometry/point_f.h"
@@ -25,6 +26,8 @@ struct CC_EXPORT LayerSelectionBound {
bool operator==(const LayerSelectionBound& lhs, const LayerSelectionBound& rhs);
bool operator!=(const LayerSelectionBound& lhs, const LayerSelectionBound& rhs);
+typedef Selection<LayerSelectionBound> LayerSelection;
+
} // namespace cc
#endif // CC_INPUT_LAYER_SELECTION_BOUND_H_
diff --git a/chromium/cc/input/page_scale_animation.h b/chromium/cc/input/page_scale_animation.h
index ce13dcf8ba7..0e430c212fe 100644
--- a/chromium/cc/input/page_scale_animation.h
+++ b/chromium/cc/input/page_scale_animation.h
@@ -10,12 +10,31 @@
#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace cc {
class TimingFunction;
+// Used in the CC to pass around a scale animation that hasn't yet been
+// initialized.
+struct PendingPageScaleAnimation {
+ PendingPageScaleAnimation(
+ const gfx::Vector2d _target_offset,
+ bool _use_anchor,
+ float _scale,
+ const base::TimeDelta& _duration)
+ : target_offset(_target_offset),
+ use_anchor(_use_anchor),
+ scale(_scale),
+ duration(_duration) {}
+ gfx::Vector2d target_offset;
+ bool use_anchor;
+ float scale;
+ base::TimeDelta duration;
+};
+
// A small helper class that does the math for zoom animations, primarily for
// double-tap zoom. Initialize it with starting and ending scroll/page scale
// positions and an animation length time, then call ...AtTime() at every frame
diff --git a/chromium/cc/input/scroll_elasticity_helper.cc b/chromium/cc/input/scroll_elasticity_helper.cc
new file mode 100644
index 00000000000..1c496d90531
--- /dev/null
+++ b/chromium/cc/input/scroll_elasticity_helper.cc
@@ -0,0 +1,91 @@
+// Copyright 2014 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/input/scroll_elasticity_helper.h"
+
+#include "cc/layers/layer_impl.h"
+#include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/layer_tree_impl.h"
+
+namespace cc {
+
+class ScrollElasticityHelperImpl : public ScrollElasticityHelper {
+ public:
+ explicit ScrollElasticityHelperImpl(LayerTreeHostImpl* layer_tree_host_impl);
+ ~ScrollElasticityHelperImpl() override;
+
+ bool IsUserScrollable() const override;
+ gfx::Vector2dF StretchAmount() const override;
+ void SetStretchAmount(const gfx::Vector2dF& stretch_amount) override;
+ gfx::ScrollOffset ScrollOffset() const override;
+ gfx::ScrollOffset MaxScrollOffset() const override;
+ void ScrollBy(const gfx::Vector2dF& delta) override;
+ void RequestAnimate() override;
+
+ private:
+ LayerTreeHostImpl* layer_tree_host_impl_;
+};
+
+ScrollElasticityHelperImpl::ScrollElasticityHelperImpl(
+ LayerTreeHostImpl* layer_tree)
+ : layer_tree_host_impl_(layer_tree) {
+}
+
+ScrollElasticityHelperImpl::~ScrollElasticityHelperImpl() {
+}
+
+bool ScrollElasticityHelperImpl::IsUserScrollable() const {
+ LayerImpl* layer = layer_tree_host_impl_->OuterViewportScrollLayer();
+ if (!layer)
+ return false;
+ return layer->user_scrollable_horizontal() ||
+ layer->user_scrollable_vertical();
+}
+
+gfx::Vector2dF ScrollElasticityHelperImpl::StretchAmount() const {
+ return layer_tree_host_impl_->active_tree()->elastic_overscroll()->Current(
+ true);
+}
+
+void ScrollElasticityHelperImpl::SetStretchAmount(
+ const gfx::Vector2dF& stretch_amount) {
+ if (stretch_amount == StretchAmount())
+ return;
+
+ layer_tree_host_impl_->active_tree()->elastic_overscroll()->SetCurrent(
+ stretch_amount);
+ layer_tree_host_impl_->active_tree()->set_needs_update_draw_properties();
+ layer_tree_host_impl_->SetNeedsCommit();
+ layer_tree_host_impl_->SetNeedsRedraw();
+ layer_tree_host_impl_->SetFullRootLayerDamage();
+}
+
+gfx::ScrollOffset ScrollElasticityHelperImpl::ScrollOffset() const {
+ return layer_tree_host_impl_->active_tree()->TotalScrollOffset();
+}
+
+gfx::ScrollOffset ScrollElasticityHelperImpl::MaxScrollOffset() const {
+ return layer_tree_host_impl_->active_tree()->TotalMaxScrollOffset();
+}
+
+void ScrollElasticityHelperImpl::ScrollBy(const gfx::Vector2dF& delta) {
+ LayerImpl* root_scroll_layer =
+ layer_tree_host_impl_->OuterViewportScrollLayer()
+ ? layer_tree_host_impl_->OuterViewportScrollLayer()
+ : layer_tree_host_impl_->InnerViewportScrollLayer();
+ if (root_scroll_layer)
+ root_scroll_layer->ScrollBy(delta);
+}
+
+void ScrollElasticityHelperImpl::RequestAnimate() {
+ layer_tree_host_impl_->SetNeedsAnimate();
+}
+
+// static
+ScrollElasticityHelper* ScrollElasticityHelper::CreateForLayerTreeHostImpl(
+ LayerTreeHostImpl* layer_tree_host_impl) {
+ return new ScrollElasticityHelperImpl(layer_tree_host_impl);
+}
+
+} // namespace cc
diff --git a/chromium/cc/input/scroll_elasticity_helper.h b/chromium/cc/input/scroll_elasticity_helper.h
new file mode 100644
index 00000000000..a2bdbfe709f
--- /dev/null
+++ b/chromium/cc/input/scroll_elasticity_helper.h
@@ -0,0 +1,73 @@
+// Copyright 2014 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_INPUT_SCROLL_ELASTICITY_HELPER_H_
+#define CC_INPUT_SCROLL_ELASTICITY_HELPER_H_
+
+#include "base/time/time.h"
+#include "cc/base/cc_export.h"
+#include "ui/gfx/geometry/scroll_offset.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace cc {
+
+class LayerTreeHostImpl;
+
+// ScrollElasticityHelper is based on
+// WebKit/Source/platform/mac/ScrollElasticityController.h
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Interface between a LayerTreeHostImpl and the ScrollElasticityController. It
+// would be possible, in principle, for LayerTreeHostImpl to implement this
+// interface itself. This artificial boundary is introduced to reduce the amount
+// of logic and state held directly inside LayerTreeHostImpl.
+class CC_EXPORT ScrollElasticityHelper {
+ public:
+ static ScrollElasticityHelper* CreateForLayerTreeHostImpl(
+ LayerTreeHostImpl* layer_tree_host_impl);
+
+ virtual ~ScrollElasticityHelper() {}
+
+ virtual bool IsUserScrollable() const = 0;
+
+ // The amount that the view is stretched past the normal allowable bounds.
+ virtual gfx::Vector2dF StretchAmount() const = 0;
+ virtual void SetStretchAmount(const gfx::Vector2dF& stretch_amount) = 0;
+
+ // Functions for the scrolling of the root scroll layer.
+ virtual gfx::ScrollOffset ScrollOffset() const = 0;
+ virtual gfx::ScrollOffset MaxScrollOffset() const = 0;
+ virtual void ScrollBy(const gfx::Vector2dF& delta) = 0;
+
+ // Request that the controller have its Animate method called for the next
+ // frame.
+ virtual void RequestAnimate() = 0;
+};
+
+} // namespace cc
+
+#endif // CC_INPUT_SCROLL_ELASTICITY_HELPER_H_
diff --git a/chromium/cc/input/selection.h b/chromium/cc/input/selection.h
new file mode 100644
index 00000000000..1f3c6ebac05
--- /dev/null
+++ b/chromium/cc/input/selection.h
@@ -0,0 +1,38 @@
+// Copyright 2014 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_INPUT_SELECTION_H_
+#define CC_INPUT_SELECTION_H_
+
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+template <typename BoundType>
+struct CC_EXPORT Selection {
+ Selection() : is_editable(false), is_empty_text_form_control(false) {}
+ ~Selection() {}
+
+ BoundType start, end;
+ bool is_editable;
+ bool is_empty_text_form_control;
+};
+
+template <typename BoundType>
+inline bool operator==(const Selection<BoundType>& lhs,
+ const Selection<BoundType>& rhs) {
+ return lhs.start == rhs.start && lhs.end == rhs.end &&
+ lhs.is_editable == rhs.is_editable &&
+ lhs.is_empty_text_form_control == rhs.is_empty_text_form_control;
+}
+
+template <typename BoundType>
+inline bool operator!=(const Selection<BoundType>& lhs,
+ const Selection<BoundType>& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace cc
+
+#endif // CC_INPUT_SELECTION_H_
diff --git a/chromium/cc/input/top_controls_manager.cc b/chromium/cc/input/top_controls_manager.cc
index cd3534c1764..c8bd5348721 100644
--- a/chromium/cc/input/top_controls_manager.cc
+++ b/chromium/cc/input/top_controls_manager.cc
@@ -26,29 +26,23 @@ const int64 kShowHideMaxDurationMs = 200;
// static
scoped_ptr<TopControlsManager> TopControlsManager::Create(
TopControlsManagerClient* client,
- float top_controls_height,
float top_controls_show_threshold,
float top_controls_hide_threshold) {
return make_scoped_ptr(new TopControlsManager(client,
- top_controls_height,
top_controls_show_threshold,
top_controls_hide_threshold));
}
TopControlsManager::TopControlsManager(TopControlsManagerClient* client,
- float top_controls_height,
float top_controls_show_threshold,
float top_controls_hide_threshold)
: client_(client),
animation_direction_(NO_ANIMATION),
permitted_state_(BOTH),
- top_controls_height_(top_controls_height),
- current_scroll_delta_(0.f),
- controls_scroll_begin_offset_(0.f),
- top_controls_show_height_(
- top_controls_height * top_controls_hide_threshold),
- top_controls_hide_height_(
- top_controls_height * (1.f - top_controls_show_threshold)),
+ accumulated_scroll_delta_(0.f),
+ baseline_content_offset_(0.f),
+ top_controls_show_threshold_(top_controls_hide_threshold),
+ top_controls_hide_threshold_(top_controls_show_threshold),
pinch_gesture_active_(false) {
CHECK(client_);
}
@@ -56,12 +50,20 @@ TopControlsManager::TopControlsManager(TopControlsManagerClient* client,
TopControlsManager::~TopControlsManager() {
}
-float TopControlsManager::ControlsTopOffset() {
- return client_->ControlsTopOffset();
+float TopControlsManager::ControlsTopOffset() const {
+ return ContentTopOffset() - TopControlsHeight();
}
-float TopControlsManager::ContentTopOffset() {
- return client_->ControlsTopOffset() + top_controls_height_;
+float TopControlsManager::ContentTopOffset() const {
+ return TopControlsShownRatio() * TopControlsHeight();
+}
+
+float TopControlsManager::TopControlsShownRatio() const {
+ return client_->CurrentTopControlsShownRatio();
+}
+
+float TopControlsManager::TopControlsHeight() const {
+ return client_->TopControlsHeight();
}
void TopControlsManager::UpdateTopControlsState(TopControlsState constraints,
@@ -77,35 +79,31 @@ void TopControlsManager::UpdateTopControlsState(TopControlsState constraints,
return;
// Don't do anything if there is no change in offset.
- float final_controls_position = 0.f;
- if (constraints == HIDDEN || current == HIDDEN) {
- final_controls_position = -top_controls_height_;
- }
- if (final_controls_position == client_->ControlsTopOffset()) {
+ float final_shown_ratio = 1.f;
+ if (constraints == HIDDEN || current == HIDDEN)
+ final_shown_ratio = 0.f;
+ if (final_shown_ratio == TopControlsShownRatio())
return;
- }
- AnimationDirection animation_direction = SHOWING_CONTROLS;
- if (constraints == HIDDEN || current == HIDDEN)
- animation_direction = HIDING_CONTROLS;
- ResetAnimations();
if (animate) {
- SetupAnimation(animation_direction);
+ SetupAnimation(final_shown_ratio ? SHOWING_CONTROLS : HIDING_CONTROLS);
} else {
- client_->SetControlsTopOffset(final_controls_position);
+ ResetAnimations();
+ client_->SetCurrentTopControlsShownRatio(final_shown_ratio);
}
- client_->DidChangeTopControlsPosition();
}
void TopControlsManager::ScrollBegin() {
DCHECK(!pinch_gesture_active_);
ResetAnimations();
- current_scroll_delta_ = 0.f;
- controls_scroll_begin_offset_ = client_->ControlsTopOffset();
+ ResetBaseline();
}
gfx::Vector2dF TopControlsManager::ScrollBy(
const gfx::Vector2dF& pending_delta) {
+ if (!TopControlsHeight())
+ return pending_delta;
+
if (pinch_gesture_active_)
return pending_delta;
@@ -114,21 +112,21 @@ gfx::Vector2dF TopControlsManager::ScrollBy(
else if (permitted_state_ == HIDDEN && pending_delta.y() < 0)
return pending_delta;
- current_scroll_delta_ += pending_delta.y();
+ accumulated_scroll_delta_ += pending_delta.y();
- float old_offset = client_->ControlsTopOffset();
- SetControlsTopOffset(controls_scroll_begin_offset_ - current_scroll_delta_);
+ float old_offset = ContentTopOffset();
+ client_->SetCurrentTopControlsShownRatio(
+ (baseline_content_offset_ - accumulated_scroll_delta_) /
+ TopControlsHeight());
// If the controls are fully visible, treat the current position as the
// new baseline even if the gesture didn't end.
- if (client_->ControlsTopOffset() == 0.f) {
- current_scroll_delta_ = 0.f;
- controls_scroll_begin_offset_ = 0.f;
- }
+ if (TopControlsShownRatio() == 1.f)
+ ResetBaseline();
ResetAnimations();
- gfx::Vector2dF applied_delta(0.f, old_offset - client_->ControlsTopOffset());
+ gfx::Vector2dF applied_delta(0.f, old_offset - ContentTopOffset());
return pending_delta - applied_delta;
}
@@ -151,31 +149,24 @@ void TopControlsManager::PinchEnd() {
ScrollBegin();
}
-void TopControlsManager::SetControlsTopOffset(float controls_top_offset) {
- controls_top_offset = std::max(controls_top_offset, -top_controls_height_);
- controls_top_offset = std::min(controls_top_offset, 0.f);
-
- if (client_->ControlsTopOffset() == controls_top_offset)
- return;
-
- client_->SetControlsTopOffset(controls_top_offset);
-
- client_->DidChangeTopControlsPosition();
+void TopControlsManager::MainThreadHasStoppedFlinging() {
+ StartAnimationIfNecessary();
}
gfx::Vector2dF TopControlsManager::Animate(base::TimeTicks monotonic_time) {
if (!top_controls_animation_ || !client_->HaveRootScrollLayer())
return gfx::Vector2dF();
- double time = (monotonic_time - base::TimeTicks()).InMillisecondsF();
+ base::TimeDelta time = monotonic_time - base::TimeTicks();
- float old_offset = client_->ControlsTopOffset();
- SetControlsTopOffset(top_controls_animation_->GetValue(time));
+ float old_offset = ContentTopOffset();
+ client_->SetCurrentTopControlsShownRatio(
+ top_controls_animation_->GetValue(time));
if (IsAnimationCompleteAtTime(monotonic_time))
ResetAnimations();
- gfx::Vector2dF scroll_delta(0.f, client_->ControlsTopOffset() - old_offset);
+ gfx::Vector2dF scroll_delta(0.f, ContentTopOffset() - old_offset);
return scroll_delta;
}
@@ -185,55 +176,48 @@ void TopControlsManager::ResetAnimations() {
}
void TopControlsManager::SetupAnimation(AnimationDirection direction) {
- DCHECK(direction != NO_ANIMATION);
+ DCHECK_NE(NO_ANIMATION, direction);
+ DCHECK_IMPLIES(direction == HIDING_CONTROLS, TopControlsShownRatio() > 0.f);
+ DCHECK_IMPLIES(direction == SHOWING_CONTROLS, TopControlsShownRatio() < 1.f);
- if (direction == SHOWING_CONTROLS && client_->ControlsTopOffset() == 0)
+ if (top_controls_animation_ && animation_direction_ == direction)
return;
- if (direction == HIDING_CONTROLS &&
- client_->ControlsTopOffset() == -top_controls_height_) {
+ if (!TopControlsHeight()) {
+ client_->SetCurrentTopControlsShownRatio(
+ direction == HIDING_CONTROLS ? 0.f : 1.f);
return;
}
- if (top_controls_animation_ && animation_direction_ == direction)
- return;
-
top_controls_animation_ = KeyframedFloatAnimationCurve::Create();
- double start_time =
- (gfx::FrameTime::Now() - base::TimeTicks()).InMillisecondsF();
- top_controls_animation_->AddKeyframe(
- FloatKeyframe::Create(start_time, client_->ControlsTopOffset(), nullptr));
- float max_ending_offset =
- (direction == SHOWING_CONTROLS ? 1 : -1) * top_controls_height_;
+ base::TimeDelta start_time = gfx::FrameTime::Now() - base::TimeTicks();
top_controls_animation_->AddKeyframe(
- FloatKeyframe::Create(start_time + kShowHideMaxDurationMs,
- client_->ControlsTopOffset() + max_ending_offset,
- EaseTimingFunction::Create()));
+ FloatKeyframe::Create(start_time, TopControlsShownRatio(), nullptr));
+ float max_ending_ratio = (direction == SHOWING_CONTROLS ? 1 : -1);
+ top_controls_animation_->AddKeyframe(FloatKeyframe::Create(
+ start_time + base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs),
+ TopControlsShownRatio() + max_ending_ratio,
+ EaseTimingFunction::Create()));
animation_direction_ = direction;
client_->DidChangeTopControlsPosition();
}
void TopControlsManager::StartAnimationIfNecessary() {
- if (client_->ControlsTopOffset() != 0
- && client_->ControlsTopOffset() != -top_controls_height_) {
- AnimationDirection show_controls = NO_ANIMATION;
-
- if (client_->ControlsTopOffset() >= -top_controls_show_height_) {
- // If we're showing so much that the hide threshold won't trigger, show.
- show_controls = SHOWING_CONTROLS;
- } else if (client_->ControlsTopOffset() <= -top_controls_hide_height_) {
- // If we're showing so little that the show threshold won't trigger, hide.
- show_controls = HIDING_CONTROLS;
- } else {
- // If we could be either showing or hiding, we determine which one to
- // do based on whether or not the total scroll delta was moving up or
- // down.
- show_controls = current_scroll_delta_ <= 0.f ?
- SHOWING_CONTROLS : HIDING_CONTROLS;
- }
-
- if (show_controls != NO_ANIMATION)
- SetupAnimation(show_controls);
+ if (TopControlsShownRatio() == 0.f || TopControlsShownRatio() == 1.f)
+ return;
+
+ if (TopControlsShownRatio() >= 1.f - top_controls_hide_threshold_) {
+ // If we're showing so much that the hide threshold won't trigger, show.
+ SetupAnimation(SHOWING_CONTROLS);
+ } else if (TopControlsShownRatio() <= top_controls_show_threshold_) {
+ // If we're showing so little that the show threshold won't trigger, hide.
+ SetupAnimation(HIDING_CONTROLS);
+ } else {
+ // If we could be either showing or hiding, we determine which one to
+ // do based on whether or not the total scroll delta was moving up or
+ // down.
+ SetupAnimation(accumulated_scroll_delta_ <= 0.f ? SHOWING_CONTROLS
+ : HIDING_CONTROLS);
}
}
@@ -241,15 +225,19 @@ bool TopControlsManager::IsAnimationCompleteAtTime(base::TimeTicks time) {
if (!top_controls_animation_)
return true;
- double time_ms = (time - base::TimeTicks()).InMillisecondsF();
- float new_offset = top_controls_animation_->GetValue(time_ms);
+ base::TimeDelta animation_time = time - base::TimeTicks();
+ float new_ratio = top_controls_animation_->GetValue(animation_time);
- if ((animation_direction_ == SHOWING_CONTROLS && new_offset >= 0) ||
- (animation_direction_ == HIDING_CONTROLS
- && new_offset <= -top_controls_height_)) {
+ if ((animation_direction_ == SHOWING_CONTROLS && new_ratio >= 1.f) ||
+ (animation_direction_ == HIDING_CONTROLS && new_ratio <= 0.f)) {
return true;
}
return false;
}
+void TopControlsManager::ResetBaseline() {
+ accumulated_scroll_delta_ = 0.f;
+ baseline_content_offset_ = ContentTopOffset();
+}
+
} // namespace cc
diff --git a/chromium/cc/input/top_controls_manager.h b/chromium/cc/input/top_controls_manager.h
index a90d33d3e4a..fc40378f5f8 100644
--- a/chromium/cc/input/top_controls_manager.h
+++ b/chromium/cc/input/top_controls_manager.h
@@ -34,14 +34,14 @@ class CC_EXPORT TopControlsManager
static scoped_ptr<TopControlsManager> Create(
TopControlsManagerClient* client,
- float top_controls_height,
float top_controls_show_threshold,
float top_controls_hide_threshold);
virtual ~TopControlsManager();
- float controls_height() { return top_controls_height_; }
- float ControlsTopOffset();
- float ContentTopOffset();
+ float ControlsTopOffset() const;
+ float ContentTopOffset() const;
+ float TopControlsShownRatio() const;
+ float TopControlsHeight() const;
KeyframedFloatAnimationCurve* animation() {
return top_controls_animation_.get();
@@ -61,13 +61,12 @@ class CC_EXPORT TopControlsManager
void PinchBegin();
void PinchEnd();
+ void MainThreadHasStoppedFlinging();
+
gfx::Vector2dF Animate(base::TimeTicks monotonic_time);
- void SetControlsTopOffset(float offset);
- float top_controls_height() { return top_controls_height_; }
protected:
TopControlsManager(TopControlsManagerClient* client,
- float top_controls_height,
float top_controls_show_threshold,
float top_controls_hide_threshold);
@@ -76,6 +75,7 @@ class CC_EXPORT TopControlsManager
void SetupAnimation(AnimationDirection direction);
void StartAnimationIfNecessary();
bool IsAnimationCompleteAtTime(base::TimeTicks time);
+ void ResetBaseline();
TopControlsManagerClient* client_; // The client manages the lifecycle of
// this.
@@ -83,18 +83,20 @@ class CC_EXPORT TopControlsManager
scoped_ptr<KeyframedFloatAnimationCurve> top_controls_animation_;
AnimationDirection animation_direction_;
TopControlsState permitted_state_;
- float top_controls_height_;
- float current_scroll_delta_;
- float controls_scroll_begin_offset_;
+ // Accumulated scroll delta since last baseline reset
+ float accumulated_scroll_delta_;
+
+ // Content offset when last baseline reset occurred
+ float baseline_content_offset_;
- // The height of the visible top control such that it must be shown when
- // the user stops the scroll.
- float top_controls_show_height_;
+ // The percent height of the visible top control such that it must be shown
+ // when the user stops the scroll.
+ float top_controls_show_threshold_;
- // The height of the visible top control such that it must be hidden when
- // the user stops the scroll.
- float top_controls_hide_height_;
+ // The percent height of the visible top control such that it must be hidden
+ // when the user stops the scroll.
+ float top_controls_hide_threshold_;
bool pinch_gesture_active_;
diff --git a/chromium/cc/input/top_controls_manager_client.h b/chromium/cc/input/top_controls_manager_client.h
index 53b5978f097..a0f2f5b16ca 100644
--- a/chromium/cc/input/top_controls_manager_client.h
+++ b/chromium/cc/input/top_controls_manager_client.h
@@ -11,8 +11,9 @@ class LayerTreeImpl;
class CC_EXPORT TopControlsManagerClient {
public:
- virtual void SetControlsTopOffset(float offset) = 0;
- virtual float ControlsTopOffset() const = 0;
+ virtual float TopControlsHeight() const = 0;
+ virtual void SetCurrentTopControlsShownRatio(float ratio) = 0;
+ virtual float CurrentTopControlsShownRatio() const = 0;
virtual void DidChangeTopControlsPosition() = 0;
virtual bool HaveRootScrollLayer() const = 0;
diff --git a/chromium/cc/input/top_controls_manager_unittest.cc b/chromium/cc/input/top_controls_manager_unittest.cc
index 77b40c9de05..52e46e674ed 100644
--- a/chromium/cc/input/top_controls_manager_unittest.cc
+++ b/chromium/cc/input/top_controls_manager_unittest.cc
@@ -4,6 +4,10 @@
#include "cc/input/top_controls_manager.h"
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "cc/input/top_controls_manager_client.h"
@@ -11,6 +15,7 @@
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/frame_time.h"
@@ -19,19 +24,21 @@
namespace cc {
namespace {
-static const float kTopControlsHeight = 100;
-
class MockTopControlsManagerClient : public TopControlsManagerClient {
public:
- MockTopControlsManagerClient(float top_controls_show_threshold,
+ MockTopControlsManagerClient(float top_controls_height,
+ float top_controls_show_threshold,
float top_controls_hide_threshold)
- : host_impl_(&proxy_, &shared_bitmap_manager_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
redraw_needed_(false),
update_draw_properties_needed_(false),
- top_controls_top_offset_(0.f),
+ top_controls_shown_ratio_(1.f),
+ top_controls_height_(top_controls_height),
top_controls_show_threshold_(top_controls_show_threshold),
top_controls_hide_threshold_(top_controls_hide_threshold) {
- active_tree_ = LayerTreeImpl::create(&host_impl_);
+ active_tree_ = LayerTreeImpl::create(
+ &host_impl_, new SyncedProperty<ScaleGroup>, new SyncedTopControls,
+ new SyncedElasticOverscroll);
root_scroll_layer_ = LayerImpl::Create(active_tree_.get(), 1);
}
@@ -44,11 +51,20 @@ class MockTopControlsManagerClient : public TopControlsManagerClient {
bool HaveRootScrollLayer() const override { return true; }
- void SetControlsTopOffset(float offset) override {
- top_controls_top_offset_ = offset;
+ float TopControlsHeight() const override { return top_controls_height_; }
+
+ void SetCurrentTopControlsShownRatio(float ratio) override {
+ ASSERT_FALSE(std::isnan(ratio));
+ ASSERT_FALSE(ratio == std::numeric_limits<float>::infinity());
+ ASSERT_FALSE(ratio == -std::numeric_limits<float>::infinity());
+ ratio = std::max(ratio, 0.f);
+ ratio = std::min(ratio, 1.f);
+ top_controls_shown_ratio_ = ratio;
}
- float ControlsTopOffset() const override { return top_controls_top_offset_; }
+ float CurrentTopControlsShownRatio() const override {
+ return top_controls_shown_ratio_;
+ }
LayerImpl* rootScrollLayer() {
return root_scroll_layer_.get();
@@ -57,16 +73,18 @@ class MockTopControlsManagerClient : public TopControlsManagerClient {
TopControlsManager* manager() {
if (!manager_) {
manager_ = TopControlsManager::Create(this,
- kTopControlsHeight,
top_controls_show_threshold_,
top_controls_hide_threshold_);
}
return manager_.get();
}
+ void SetTopControlsHeight(float height) { top_controls_height_ = height; }
+
private:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<LayerTreeImpl> active_tree_;
scoped_ptr<LayerImpl> root_scroll_layer_;
@@ -74,263 +92,264 @@ class MockTopControlsManagerClient : public TopControlsManagerClient {
bool redraw_needed_;
bool update_draw_properties_needed_;
- float top_controls_top_offset_;
+ float top_controls_shown_ratio_;
+ float top_controls_height_;
float top_controls_show_threshold_;
float top_controls_hide_threshold_;
};
TEST(TopControlsManagerTest, EnsureScrollThresholdApplied) {
- MockTopControlsManagerClient client(0.5f, 0.5f);
+ MockTopControlsManagerClient client(100.f, 0.5f, 0.5f);
TopControlsManager* manager = client.manager();
manager->ScrollBegin();
// Scroll down to hide the controls entirely.
manager->ScrollBy(gfx::Vector2dF(0.f, 30.f));
- EXPECT_EQ(-30.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-30.f, manager->ControlsTopOffset());
manager->ScrollBy(gfx::Vector2dF(0.f, 30.f));
- EXPECT_EQ(-60.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-60.f, manager->ControlsTopOffset());
manager->ScrollBy(gfx::Vector2dF(0.f, 100.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
// Scroll back up a bit and ensure the controls don't move until we cross
// the threshold.
manager->ScrollBy(gfx::Vector2dF(0.f, -10.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
manager->ScrollBy(gfx::Vector2dF(0.f, -50.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
// After hitting the threshold, further scrolling up should result in the top
// controls showing.
manager->ScrollBy(gfx::Vector2dF(0.f, -10.f));
- EXPECT_EQ(-90.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-90.f, manager->ControlsTopOffset());
manager->ScrollBy(gfx::Vector2dF(0.f, -50.f));
- EXPECT_EQ(-40.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-40.f, manager->ControlsTopOffset());
// Reset the scroll threshold by going further up the page than the initial
// threshold.
manager->ScrollBy(gfx::Vector2dF(0.f, -100.f));
- EXPECT_EQ(0.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
// See that scrolling down the page now will result in the controls hiding.
manager->ScrollBy(gfx::Vector2dF(0.f, 20.f));
- EXPECT_EQ(-20.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-20.f, manager->ControlsTopOffset());
manager->ScrollEnd();
}
TEST(TopControlsManagerTest, PartialShownHideAnimation) {
- MockTopControlsManagerClient client(0.5f, 0.5f);
+ MockTopControlsManagerClient client(100.f, 0.5f, 0.5f);
TopControlsManager* manager = client.manager();
manager->ScrollBegin();
manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
- EXPECT_EQ(0.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
manager->ScrollEnd();
manager->ScrollBegin();
manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
- EXPECT_EQ(-85.f, manager->ControlsTopOffset());
- EXPECT_EQ(15.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset());
manager->ScrollEnd();
EXPECT_TRUE(manager->animation());
base::TimeTicks time = gfx::FrameTime::Now();
- float previous_offset = manager->ControlsTopOffset();
+ float previous;
while (manager->animation()) {
+ previous = manager->TopControlsShownRatio();
time = base::TimeDelta::FromMicroseconds(100) + time;
manager->Animate(time);
- EXPECT_LT(manager->ControlsTopOffset(), previous_offset);
- previous_offset = manager->ControlsTopOffset();
+ EXPECT_LT(manager->TopControlsShownRatio(), previous);
}
EXPECT_FALSE(manager->animation());
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
- EXPECT_EQ(0.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
}
TEST(TopControlsManagerTest, PartialShownShowAnimation) {
- MockTopControlsManagerClient client(0.5f, 0.5f);
+ MockTopControlsManagerClient client(100.f, 0.5f, 0.5f);
TopControlsManager* manager = client.manager();
manager->ScrollBegin();
manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
- EXPECT_EQ(0.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
manager->ScrollEnd();
manager->ScrollBegin();
manager->ScrollBy(gfx::Vector2dF(0.f, -70.f));
- EXPECT_EQ(-30.f, manager->ControlsTopOffset());
- EXPECT_EQ(70.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-30.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(70.f, manager->ContentTopOffset());
manager->ScrollEnd();
EXPECT_TRUE(manager->animation());
base::TimeTicks time = gfx::FrameTime::Now();
- float previous_offset = manager->ControlsTopOffset();
+ float previous;
while (manager->animation()) {
+ previous = manager->TopControlsShownRatio();
time = base::TimeDelta::FromMicroseconds(100) + time;
manager->Animate(time);
- EXPECT_GT(manager->ControlsTopOffset(), previous_offset);
- previous_offset = manager->ControlsTopOffset();
+ EXPECT_GT(manager->TopControlsShownRatio(), previous);
}
EXPECT_FALSE(manager->animation());
- EXPECT_EQ(0.f, manager->ControlsTopOffset());
- EXPECT_EQ(100.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset());
}
TEST(TopControlsManagerTest, PartialHiddenWithAmbiguousThresholdShows) {
- MockTopControlsManagerClient client(0.25f, 0.25f);
+ MockTopControlsManagerClient client(100.f, 0.25f, 0.25f);
TopControlsManager* manager = client.manager();
manager->ScrollBegin();
manager->ScrollBy(gfx::Vector2dF(0.f, 20.f));
- EXPECT_EQ(-20.f, manager->ControlsTopOffset());
- EXPECT_EQ(80.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-20.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(80.f, manager->ContentTopOffset());
manager->ScrollEnd();
EXPECT_TRUE(manager->animation());
base::TimeTicks time = gfx::FrameTime::Now();
- float previous_offset = manager->ControlsTopOffset();
+ float previous;
while (manager->animation()) {
+ previous = manager->TopControlsShownRatio();
time = base::TimeDelta::FromMicroseconds(100) + time;
manager->Animate(time);
- EXPECT_GT(manager->ControlsTopOffset(), previous_offset);
- previous_offset = manager->ControlsTopOffset();
+ EXPECT_GT(manager->TopControlsShownRatio(), previous);
}
EXPECT_FALSE(manager->animation());
- EXPECT_EQ(0.f, manager->ControlsTopOffset());
- EXPECT_EQ(100.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset());
}
TEST(TopControlsManagerTest, PartialHiddenWithAmbiguousThresholdHides) {
- MockTopControlsManagerClient client(0.25f, 0.25f);
+ MockTopControlsManagerClient client(100.f, 0.25f, 0.25f);
TopControlsManager* manager = client.manager();
manager->ScrollBegin();
manager->ScrollBy(gfx::Vector2dF(0.f, 30.f));
- EXPECT_EQ(-30.f, manager->ControlsTopOffset());
- EXPECT_EQ(70.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-30.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(70.f, manager->ContentTopOffset());
manager->ScrollEnd();
EXPECT_TRUE(manager->animation());
base::TimeTicks time = gfx::FrameTime::Now();
- float previous_offset = manager->ControlsTopOffset();
+ float previous;
while (manager->animation()) {
+ previous = manager->TopControlsShownRatio();
time = base::TimeDelta::FromMicroseconds(100) + time;
manager->Animate(time);
- EXPECT_LT(manager->ControlsTopOffset(), previous_offset);
- previous_offset = manager->ControlsTopOffset();
+ EXPECT_LT(manager->TopControlsShownRatio(), previous);
}
EXPECT_FALSE(manager->animation());
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
- EXPECT_EQ(0.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
}
TEST(TopControlsManagerTest, PartialShownWithAmbiguousThresholdHides) {
- MockTopControlsManagerClient client(0.25f, 0.25f);
+ MockTopControlsManagerClient client(100.f, 0.25f, 0.25f);
TopControlsManager* manager = client.manager();
manager->ScrollBy(gfx::Vector2dF(0.f, 200.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
- EXPECT_EQ(0.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
manager->ScrollBegin();
manager->ScrollBy(gfx::Vector2dF(0.f, -20.f));
- EXPECT_EQ(-80.f, manager->ControlsTopOffset());
- EXPECT_EQ(20.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-80.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(20.f, manager->ContentTopOffset());
manager->ScrollEnd();
EXPECT_TRUE(manager->animation());
base::TimeTicks time = gfx::FrameTime::Now();
- float previous_offset = manager->ControlsTopOffset();
+ float previous;
while (manager->animation()) {
+ previous = manager->TopControlsShownRatio();
time = base::TimeDelta::FromMicroseconds(100) + time;
manager->Animate(time);
- EXPECT_LT(manager->ControlsTopOffset(), previous_offset);
- previous_offset = manager->ControlsTopOffset();
+ EXPECT_LT(manager->TopControlsShownRatio(), previous);
}
EXPECT_FALSE(manager->animation());
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
- EXPECT_EQ(0.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
}
TEST(TopControlsManagerTest, PartialShownWithAmbiguousThresholdShows) {
- MockTopControlsManagerClient client(0.25f, 0.25f);
+ MockTopControlsManagerClient client(100.f, 0.25f, 0.25f);
TopControlsManager* manager = client.manager();
manager->ScrollBy(gfx::Vector2dF(0.f, 200.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
- EXPECT_EQ(0.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
manager->ScrollBegin();
manager->ScrollBy(gfx::Vector2dF(0.f, -30.f));
- EXPECT_EQ(-70.f, manager->ControlsTopOffset());
- EXPECT_EQ(30.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-70.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(30.f, manager->ContentTopOffset());
manager->ScrollEnd();
EXPECT_TRUE(manager->animation());
base::TimeTicks time = gfx::FrameTime::Now();
- float previous_offset = manager->ControlsTopOffset();
+ float previous;
while (manager->animation()) {
+ previous = manager->TopControlsShownRatio();
time = base::TimeDelta::FromMicroseconds(100) + time;
manager->Animate(time);
- EXPECT_GT(manager->ControlsTopOffset(), previous_offset);
- previous_offset = manager->ControlsTopOffset();
+ EXPECT_GT(manager->TopControlsShownRatio(), previous);
}
EXPECT_FALSE(manager->animation());
- EXPECT_EQ(0.f, manager->ControlsTopOffset());
- EXPECT_EQ(100.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset());
}
TEST(TopControlsManagerTest, PinchIgnoresScroll) {
- MockTopControlsManagerClient client(0.5f, 0.5f);
+ MockTopControlsManagerClient client(100.f, 0.5f, 0.5f);
TopControlsManager* manager = client.manager();
// Hide the controls.
manager->ScrollBegin();
- EXPECT_EQ(0.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
manager->PinchBegin();
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
// Scrolls are ignored during pinch.
manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
manager->PinchEnd();
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
// Scrolls should no long be ignored.
manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
- EXPECT_EQ(-85.f, manager->ControlsTopOffset());
- EXPECT_EQ(15.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset());
manager->ScrollEnd();
EXPECT_TRUE(manager->animation());
}
TEST(TopControlsManagerTest, PinchBeginStartsAnimationIfNecessary) {
- MockTopControlsManagerClient client(0.5f, 0.5f);
+ MockTopControlsManagerClient client(100.f, 0.5f, 0.5f);
TopControlsManager* manager = client.manager();
manager->ScrollBegin();
manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
- EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
manager->PinchBegin();
EXPECT_FALSE(manager->animation());
@@ -339,19 +358,19 @@ TEST(TopControlsManagerTest, PinchBeginStartsAnimationIfNecessary) {
EXPECT_FALSE(manager->animation());
manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
- EXPECT_EQ(-85.f, manager->ControlsTopOffset());
- EXPECT_EQ(15.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset());
manager->PinchBegin();
EXPECT_TRUE(manager->animation());
base::TimeTicks time = base::TimeTicks::Now();
- float previous_offset = manager->ControlsTopOffset();
+ float previous;
while (manager->animation()) {
+ previous = manager->TopControlsShownRatio();
time = base::TimeDelta::FromMicroseconds(100) + time;
manager->Animate(time);
- EXPECT_LT(manager->ControlsTopOffset(), previous_offset);
- previous_offset = manager->ControlsTopOffset();
+ EXPECT_LT(manager->TopControlsShownRatio(), previous);
}
EXPECT_FALSE(manager->animation());
@@ -359,24 +378,95 @@ TEST(TopControlsManagerTest, PinchBeginStartsAnimationIfNecessary) {
EXPECT_FALSE(manager->animation());
manager->ScrollBy(gfx::Vector2dF(0.f, -55.f));
- EXPECT_EQ(-45.f, manager->ControlsTopOffset());
- EXPECT_EQ(55.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-45.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(55.f, manager->ContentTopOffset());
EXPECT_FALSE(manager->animation());
manager->ScrollEnd();
EXPECT_TRUE(manager->animation());
time = base::TimeTicks::Now();
- previous_offset = manager->ControlsTopOffset();
while (manager->animation()) {
+ previous = manager->TopControlsShownRatio();
time = base::TimeDelta::FromMicroseconds(100) + time;
manager->Animate(time);
- EXPECT_GT(manager->ControlsTopOffset(), previous_offset);
- previous_offset = manager->ControlsTopOffset();
+ EXPECT_GT(manager->TopControlsShownRatio(), previous);
}
EXPECT_FALSE(manager->animation());
- EXPECT_EQ(0.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+}
+
+TEST(TopControlsManagerTest, HeightChangeMaintainsFullyVisibleControls) {
+ MockTopControlsManagerClient client(0.f, 0.5f, 0.5f);
+ TopControlsManager* manager = client.manager();
+
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+
+ client.SetTopControlsHeight(100.f);
+ EXPECT_FALSE(manager->animation());
+ EXPECT_FLOAT_EQ(100.f, manager->TopControlsHeight());
+ EXPECT_FLOAT_EQ(0, manager->ControlsTopOffset());
+
+ client.SetTopControlsHeight(50.f);
+ EXPECT_FALSE(manager->animation());
+ EXPECT_FLOAT_EQ(50.f, manager->TopControlsHeight());
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+}
+
+TEST(TopControlsManagerTest, GrowingHeightKeepsTopControlsHidden) {
+ MockTopControlsManagerClient client(0.f, 0.5f, 0.5f);
+ TopControlsManager* manager = client.manager();
+ client.SetTopControlsHeight(1.f);
+ manager->UpdateTopControlsState(HIDDEN, HIDDEN, false);
+ EXPECT_EQ(-1.f, manager->ControlsTopOffset());
+ EXPECT_EQ(0.f, manager->ContentTopOffset());
+
+ client.SetTopControlsHeight(50.f);
+ EXPECT_FALSE(manager->animation());
+ EXPECT_EQ(-50.f, manager->ControlsTopOffset());
+ EXPECT_EQ(0.f, manager->ContentTopOffset());
+
+ client.SetTopControlsHeight(100.f);
+ EXPECT_FALSE(manager->animation());
+ EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_EQ(0.f, manager->ContentTopOffset());
+}
+
+TEST(TopControlsManagerTest, ShrinkingHeightKeepsTopControlsHidden) {
+ MockTopControlsManagerClient client(100.f, 0.5f, 0.5f);
+ TopControlsManager* manager = client.manager();
+
+ manager->ScrollBegin();
+ manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
+ EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
+ manager->ScrollEnd();
+
+ client.SetTopControlsHeight(50.f);
+ EXPECT_FALSE(manager->animation());
+ EXPECT_FLOAT_EQ(-50.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
+
+ client.SetTopControlsHeight(0.f);
+ EXPECT_FALSE(manager->animation());
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
+}
+
+TEST(TopControlsManagerTest, ScrollByWithZeroHeightControlsIsNoop) {
+ MockTopControlsManagerClient client(0.f, 0.5f, 0.5f);
+ TopControlsManager* manager = client.manager();
+ manager->UpdateTopControlsState(BOTH, BOTH, false);
+
+ manager->ScrollBegin();
+ gfx::Vector2dF pending = manager->ScrollBy(gfx::Vector2dF(0.f, 20.f));
+ EXPECT_FLOAT_EQ(20.f, pending.y());
+ EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
+ EXPECT_FLOAT_EQ(1.f, client.CurrentTopControlsShownRatio());
+ manager->ScrollEnd();
}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/append_quads_data.h b/chromium/cc/layers/append_quads_data.h
index ffe0dd9ba74..50f58775d48 100644
--- a/chromium/cc/layers/append_quads_data.h
+++ b/chromium/cc/layers/append_quads_data.h
@@ -16,14 +16,7 @@ struct AppendQuadsData {
num_missing_tiles(0),
visible_content_area(0),
approximated_visible_content_area(0),
- render_pass_id(0, 0) {}
-
- explicit AppendQuadsData(RenderPassId render_pass_id)
- : num_incomplete_tiles(0),
- num_missing_tiles(0),
- visible_content_area(0),
- approximated_visible_content_area(0),
- render_pass_id(render_pass_id) {}
+ checkerboarded_visible_content_area(0) {}
// Set by the layer appending quads.
int64 num_incomplete_tiles;
@@ -33,8 +26,8 @@ struct AppendQuadsData {
int64 visible_content_area;
// Set by the layer appending quads.
int64 approximated_visible_content_area;
- // Given to the layer appending quads.
- const RenderPassId render_pass_id;
+ // Set by the layer appending quads.
+ int64 checkerboarded_visible_content_area;
};
} // namespace cc
diff --git a/chromium/cc/layers/content_layer.cc b/chromium/cc/layers/content_layer.cc
index d3e9a2873a8..7efa1c20b00 100644
--- a/chromium/cc/layers/content_layer.cc
+++ b/chromium/cc/layers/content_layer.cc
@@ -26,9 +26,8 @@ scoped_ptr<ContentLayerPainter> ContentLayerPainter::Create(
void ContentLayerPainter::Paint(SkCanvas* canvas,
const gfx::Rect& content_rect) {
- client_->PaintContents(canvas,
- content_rect,
- ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
+ client_->PaintContents(canvas, content_rect,
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
}
scoped_refptr<ContentLayer> ContentLayer::Create(ContentLayerClient* client) {
@@ -36,9 +35,7 @@ scoped_refptr<ContentLayer> ContentLayer::Create(ContentLayerClient* client) {
}
ContentLayer::ContentLayer(ContentLayerClient* client)
- : TiledLayer(),
- client_(client),
- can_use_lcd_text_last_frame_(can_use_lcd_text()) {
+ : TiledLayer(), client_(client) {
}
ContentLayer::~ContentLayer() {}
@@ -57,13 +54,6 @@ void ContentLayer::SetLayerTreeHost(LayerTreeHost* host) {
if (!updater_.get())
return;
-
- if (host) {
- updater_->set_rendering_stats_instrumentation(
- host->rendering_stats_instrumentation());
- } else {
- updater_->set_rendering_stats_instrumentation(nullptr);
- }
}
void ContentLayer::SetTexturePriorities(
@@ -81,7 +71,6 @@ bool ContentLayer::Update(ResourceUpdateQueue* queue,
true);
CreateUpdaterIfNeeded();
- UpdateCanUseLCDText();
}
bool updated = TiledLayer::Update(queue, occlusion);
@@ -108,7 +97,6 @@ void ContentLayer::CreateUpdaterIfNeeded() {
} else {
updater_ = BitmapContentLayerUpdater::Create(
painter.Pass(),
- rendering_stats_instrumentation(),
id());
}
updater_->SetOpaque(contents_opaque());
@@ -126,19 +114,6 @@ void ContentLayer::SetContentsOpaque(bool opaque) {
updater_->SetOpaque(opaque);
}
-void ContentLayer::UpdateCanUseLCDText() {
- if (can_use_lcd_text_last_frame_ == can_use_lcd_text())
- return;
-
- can_use_lcd_text_last_frame_ = can_use_lcd_text();
- if (client_)
- client_->DidChangeLayerCanUseLCDText();
-}
-
-bool ContentLayer::SupportsLCDText() const {
- return true;
-}
-
skia::RefPtr<SkPicture> ContentLayer::GetPicture() const {
if (!DrawsContent())
return skia::RefPtr<SkPicture>();
@@ -148,10 +123,10 @@ skia::RefPtr<SkPicture> ContentLayer::GetPicture() const {
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(width, height, nullptr, 0);
- client_->PaintContents(canvas,
- gfx::Rect(width, height),
- ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
- skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
+ client_->PaintContents(canvas, gfx::Rect(width, height),
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ skia::RefPtr<SkPicture> picture =
+ skia::AdoptRef(recorder.endRecordingAsPicture());
return picture;
}
diff --git a/chromium/cc/layers/content_layer.h b/chromium/cc/layers/content_layer.h
index fe0bd37970f..5d6ac15a801 100644
--- a/chromium/cc/layers/content_layer.h
+++ b/chromium/cc/layers/content_layer.h
@@ -46,8 +46,6 @@ class CC_EXPORT ContentLayer : public TiledLayer {
void SetContentsOpaque(bool contents_opaque) override;
- bool SupportsLCDText() const override;
-
skia::RefPtr<SkPicture> GetPicture() const override;
void OnOutputSurfaceCreated() override;
@@ -65,11 +63,8 @@ class CC_EXPORT ContentLayer : public TiledLayer {
// TiledLayer implementation.
void CreateUpdaterIfNeeded() override;
- void UpdateCanUseLCDText();
-
ContentLayerClient* client_;
scoped_refptr<ContentLayerUpdater> updater_;
- bool can_use_lcd_text_last_frame_;
DISALLOW_COPY_AND_ASSIGN(ContentLayer);
};
diff --git a/chromium/cc/layers/content_layer_client.h b/chromium/cc/layers/content_layer_client.h
index 0140513cbb8..9125b9722b5 100644
--- a/chromium/cc/layers/content_layer_client.h
+++ b/chromium/cc/layers/content_layer_client.h
@@ -6,6 +6,7 @@
#define CC_LAYERS_CONTENT_LAYER_CLIENT_H_
#include "cc/base/cc_export.h"
+#include "cc/playback/display_item_list.h"
class SkCanvas;
@@ -18,18 +19,21 @@ namespace cc {
class CC_EXPORT ContentLayerClient {
public:
- enum GraphicsContextStatus {
- GRAPHICS_CONTEXT_DISABLED,
- GRAPHICS_CONTEXT_ENABLED
+ enum PaintingControlSetting {
+ PAINTING_BEHAVIOR_NORMAL,
+ DISPLAY_LIST_CONSTRUCTION_DISABLED,
+ DISPLAY_LIST_CACHING_DISABLED,
+ DISPLAY_LIST_PAINTING_DISABLED
};
virtual void PaintContents(SkCanvas* canvas,
const gfx::Rect& clip,
- GraphicsContextStatus gc_status) = 0;
+ PaintingControlSetting painting_status) = 0;
- // Called by the content layer during the update phase.
- // If the client paints LCD text, it may want to invalidate the layer.
- virtual void DidChangeLayerCanUseLCDText() = 0;
+ virtual void PaintContentsToDisplayList(
+ DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ PaintingControlSetting painting_status) = 0;
// If true the layer may skip clearing the background before rasterizing,
// because it will cover any uncleared data with content.
diff --git a/chromium/cc/layers/contents_scaling_layer.cc b/chromium/cc/layers/contents_scaling_layer.cc
index 733bac094f6..b44830f5fa7 100644
--- a/chromium/cc/layers/contents_scaling_layer.cc
+++ b/chromium/cc/layers/contents_scaling_layer.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "cc/layers/contents_scaling_layer.h"
+#include "cc/trees/layer_tree_host.h"
#include "ui/gfx/geometry/size_conversions.h"
namespace cc {
@@ -25,11 +26,23 @@ void ContentsScalingLayer::CalculateContentsScale(
float* contents_scale_x,
float* contents_scale_y,
gfx::Size* content_bounds) {
+ float old_contents_scale_x = *contents_scale_x;
+ float old_contents_scale_y = *contents_scale_y;
+ gfx::Size old_content_bounds = *content_bounds;
*contents_scale_x = ideal_contents_scale;
*contents_scale_y = ideal_contents_scale;
*content_bounds = ComputeContentBoundsForScale(
ideal_contents_scale,
ideal_contents_scale);
+
+ if (!layer_tree_host())
+ return;
+
+ if (old_contents_scale_x != *contents_scale_x ||
+ old_contents_scale_y != *contents_scale_y ||
+ old_content_bounds != *content_bounds) {
+ layer_tree_host()->property_trees()->needs_rebuild = true;
+ }
}
bool ContentsScalingLayer::Update(ResourceUpdateQueue* queue,
diff --git a/chromium/cc/layers/delegated_frame_provider.cc b/chromium/cc/layers/delegated_frame_provider.cc
index ce9ac596d06..bae5e438c0a 100644
--- a/chromium/cc/layers/delegated_frame_provider.cc
+++ b/chromium/cc/layers/delegated_frame_provider.cc
@@ -28,7 +28,7 @@ DelegatedFrameProvider::~DelegatedFrameProvider() {
}
void DelegatedFrameProvider::AddObserver(DelegatedRendererLayer* layer) {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
for (size_t i = 0; i < observers_.size(); ++i)
DCHECK(observers_[i].layer != layer);
#endif
diff --git a/chromium/cc/layers/delegated_frame_provider_unittest.cc b/chromium/cc/layers/delegated_frame_provider_unittest.cc
index 5ba92bf3276..fe8117e797a 100644
--- a/chromium/cc/layers/delegated_frame_provider_unittest.cc
+++ b/chromium/cc/layers/delegated_frame_provider_unittest.cc
@@ -59,15 +59,16 @@ class DelegatedFrameProviderTest
gfx::PointF(1.f, 1.f),
SK_ColorTRANSPARENT,
vertex_opacity,
+ false,
false);
}
- virtual void SetUp() override {
+ void SetUp() override {
resource_collection_ = new DelegatedFrameResourceCollection;
resource_collection_->SetClient(this);
}
- virtual void TearDown() override { resource_collection_->SetClient(nullptr); }
+ void TearDown() override { resource_collection_->SetClient(nullptr); }
void UnusedResourcesAreAvailable() override {
resources_available_ = true;
diff --git a/chromium/cc/layers/delegated_frame_resource_collection_unittest.cc b/chromium/cc/layers/delegated_frame_resource_collection_unittest.cc
index 3e95823cfb6..e5426a0e01a 100644
--- a/chromium/cc/layers/delegated_frame_resource_collection_unittest.cc
+++ b/chromium/cc/layers/delegated_frame_resource_collection_unittest.cc
@@ -3,8 +3,11 @@
// found in the LICENSE file.
#include "base/bind.h"
+#include "base/location.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "cc/layers/delegated_frame_resource_collection.h"
#include "cc/resources/returned_resource.h"
@@ -21,9 +24,9 @@ class DelegatedFrameResourceCollectionTest
protected:
DelegatedFrameResourceCollectionTest() : resources_available_(false) {}
- virtual void SetUp() override { CreateResourceCollection(); }
+ void SetUp() override { CreateResourceCollection(); }
- virtual void TearDown() override { DestroyResourceCollection(); }
+ void TearDown() override { DestroyResourceCollection(); }
void CreateResourceCollection() {
DCHECK(!resource_collection_.get());
@@ -95,7 +98,7 @@ TEST_F(DelegatedFrameResourceCollectionTest, Thread) {
base::Thread thread("test thread");
thread.Start();
scoped_ptr<BlockingTaskRunner> main_thread_task_runner(
- BlockingTaskRunner::Create(base::MessageLoopProxy::current()));
+ BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get()));
TransferableResourceArray resources = CreateResourceArray();
resource_collection_->ReceivedResources(resources);
@@ -110,14 +113,12 @@ TEST_F(DelegatedFrameResourceCollectionTest, Thread) {
base::RunLoop run_loop;
resources_available_closure_ = run_loop.QuitClosure();
- thread.message_loop()->PostTask(
+ thread.message_loop()->task_runner()->PostTask(
FROM_HERE,
base::Bind(
&ReturnResourcesOnThread,
resource_collection_->GetReturnResourcesCallbackForImplThread(),
- returned_resources,
- &event,
- main_thread_task_runner.get()));
+ returned_resources, &event, main_thread_task_runner.get()));
run_loop.Run();
}
@@ -152,12 +153,10 @@ TEST_F(DelegatedFrameResourceCollectionTest, Thread) {
returned_resources_.clear();
base::WaitableEvent* null_event = nullptr;
- thread.message_loop()->PostTask(FROM_HERE,
- base::Bind(&ReturnResourcesOnThread,
- return_callback,
- returned_resources,
- null_event,
- main_thread_task_runner.get()));
+ thread.message_loop()->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ReturnResourcesOnThread, return_callback, returned_resources,
+ null_event, main_thread_task_runner.get()));
thread.Stop();
}
diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.cc b/chromium/cc/layers/delegated_renderer_layer_impl.cc
index 9eca7a13954..a99cd17b2c7 100644
--- a/chromium/cc/layers/delegated_renderer_layer_impl.cc
+++ b/chromium/cc/layers/delegated_renderer_layer_impl.cc
@@ -47,9 +47,8 @@ bool DelegatedRendererLayerImpl::HasContributingDelegatedRenderPasses() const {
static ResourceProvider::ResourceId ResourceRemapHelper(
bool* invalid_frame,
const ResourceProvider::ResourceIdMap& child_to_parent_map,
- ResourceProvider::ResourceIdArray* resources_in_frame,
+ ResourceProvider::ResourceIdSet* resources_in_frame,
ResourceProvider::ResourceId id) {
-
ResourceProvider::ResourceIdMap::const_iterator it =
child_to_parent_map.find(id);
if (it == child_to_parent_map.end()) {
@@ -59,7 +58,7 @@ static ResourceProvider::ResourceId ResourceRemapHelper(
DCHECK_EQ(it->first, id);
ResourceProvider::ResourceId remapped_id = it->second;
- resources_in_frame->push_back(id);
+ resources_in_frame->insert(id);
return remapped_id;
}
@@ -79,8 +78,12 @@ void DelegatedRendererLayerImpl::PushPropertiesTo(LayerImpl* layer) {
own_child_id_ = false;
if (have_render_passes_to_push_) {
+ DCHECK(child_id_);
// This passes ownership of the render passes to the active tree.
delegated_layer->SetRenderPasses(&render_passes_in_draw_order_);
+ // Once resources are on the active tree, give them to the ResourceProvider
+ // and release unused resources from the old frame.
+ delegated_layer->TakeOwnershipOfResourcesIfOnActiveTree(resources_);
DCHECK(render_passes_in_draw_order_.empty());
have_render_passes_to_push_ = false;
}
@@ -119,7 +122,18 @@ void DelegatedRendererLayerImpl::SetFrameData(
RenderPass::CopyAll(frame_data->render_pass_list, &render_pass_list);
bool invalid_frame = false;
- ResourceProvider::ResourceIdArray resources_in_frame;
+ ResourceProvider::ResourceIdSet resources_in_frame;
+ size_t reserve_size = frame_data->resource_list.size();
+#if defined(COMPILER_MSVC)
+ resources_in_frame.reserve(reserve_size);
+#elif defined(COMPILER_GCC)
+ // Pre-standard hash-tables only implement resize, which behaves similarly
+ // to reserve for these keys. Resizing to 0 may also be broken (particularly
+ // on stlport).
+ // TODO(jbauman): Replace with reserve when C++11 is supported everywhere.
+ if (reserve_size)
+ resources_in_frame.resize(reserve_size);
+#endif
DrawQuad::ResourceIteratorCallback remap_resources_to_parent_callback =
base::Bind(&ResourceRemapHelper,
&invalid_frame,
@@ -131,14 +145,17 @@ void DelegatedRendererLayerImpl::SetFrameData(
}
if (invalid_frame) {
- // Declare we are still using the last frame's resources.
+ // Declare we are still using the last frame's resources. Drops ownership of
+ // any invalid resources, keeping only those in use by the active tree.
resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_);
return;
}
- // Declare we are using the new frame's resources.
+ // Save the new frame's resources, but don't give them to the ResourceProvider
+ // until they are active, since the resources on the active tree will still be
+ // used and we don't want to return them early.
resources_.swap(resources_in_frame);
- resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_);
+ TakeOwnershipOfResourcesIfOnActiveTree(resources_);
inverse_device_scale_factor_ = 1.0f / frame_data->device_scale_factor;
// Display size is already set so we can compute what the damage rect
@@ -156,6 +173,15 @@ void DelegatedRendererLayerImpl::SetFrameData(
have_render_passes_to_push_ = true;
}
+void DelegatedRendererLayerImpl::TakeOwnershipOfResourcesIfOnActiveTree(
+ const ResourceProvider::ResourceIdSet& resources) {
+ DCHECK(child_id_);
+ if (!layer_tree_impl()->IsActiveTree())
+ return;
+ layer_tree_impl()->resource_provider()->DeclareUsedResourcesFromChild(
+ child_id_, resources);
+}
+
void DelegatedRendererLayerImpl::SetRenderPasses(
RenderPassList* render_passes_in_draw_order) {
ClearRenderPasses();
@@ -172,6 +198,10 @@ void DelegatedRendererLayerImpl::SetRenderPasses(
// Give back an empty array instead of nulls.
render_passes_in_draw_order->clear();
+
+ // The render passes given here become part of the RenderSurfaceLayerList, so
+ // changing them requires recomputing the RenderSurfaceLayerList.
+ layer_tree_impl()->set_needs_update_draw_properties();
}
void DelegatedRendererLayerImpl::ClearRenderPasses() {
@@ -187,6 +217,7 @@ scoped_ptr<LayerImpl> DelegatedRendererLayerImpl::CreateLayerImpl(
void DelegatedRendererLayerImpl::ReleaseResources() {
ClearRenderPasses();
ClearChildId();
+ have_render_passes_to_push_ = false;
}
static inline int IndexToId(int index) { return index + 1; }
@@ -255,15 +286,14 @@ bool DelegatedRendererLayerImpl::WillDraw(DrawMode draw_mode,
void DelegatedRendererLayerImpl::AppendQuads(
RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
- AppendRainbowDebugBorder(render_pass, append_quads_data);
+ AppendRainbowDebugBorder(render_pass);
// This list will be empty after a lost context until a new frame arrives.
if (render_passes_in_draw_order_.empty())
return;
- RenderPassId target_render_pass_id = append_quads_data->render_pass_id;
+ RenderPassId target_render_pass_id = render_pass->id;
const RenderPass* root_delegated_render_pass =
render_passes_in_draw_order_.back();
@@ -282,8 +312,6 @@ void DelegatedRendererLayerImpl::AppendQuads(
DCHECK(target_render_pass_id.layer_id == render_target()->id());
AppendRenderPassQuads(render_pass,
- occlusion_in_content_space,
- append_quads_data,
root_delegated_render_pass,
frame_size);
} else {
@@ -294,16 +322,13 @@ void DelegatedRendererLayerImpl::AppendQuads(
const RenderPass* delegated_render_pass =
render_passes_in_draw_order_[render_pass_index];
AppendRenderPassQuads(render_pass,
- occlusion_in_content_space,
- append_quads_data,
delegated_render_pass,
frame_size);
}
}
void DelegatedRendererLayerImpl::AppendRainbowDebugBorder(
- RenderPass* render_pass,
- AppendQuadsData* append_quads_data) {
+ RenderPass* render_pass) {
if (!ShowDebugBorders())
return;
@@ -352,59 +377,69 @@ void DelegatedRendererLayerImpl::AppendRainbowDebugBorder(
break;
if (!top.IsEmpty()) {
+ bool force_anti_aliasing_off = false;
SolidColorDrawQuad* top_quad =
render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- top_quad->SetNew(
- shared_quad_state, top, top, colors[i % kNumColors], false);
+ top_quad->SetNew(shared_quad_state, top, top, colors[i % kNumColors],
+ force_anti_aliasing_off);
SolidColorDrawQuad* bottom_quad =
render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- bottom_quad->SetNew(shared_quad_state,
- bottom,
- bottom,
+ bottom_quad->SetNew(shared_quad_state, bottom, bottom,
colors[kNumColors - 1 - (i % kNumColors)],
- false);
+ force_anti_aliasing_off);
+
+ if (contents_opaque()) {
+ // Draws a stripe filling the layer vertically with the same color and
+ // width as the horizontal stipes along the layer's top border.
+ SolidColorDrawQuad* solid_quad =
+ render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ // The inner fill is more transparent then the border.
+ static const float kFillOpacity = 0.1f;
+ SkColor fill_color = SkColorSetA(
+ colors[i % kNumColors],
+ static_cast<uint8_t>(SkColorGetA(colors[i % kNumColors]) *
+ kFillOpacity));
+ gfx::Rect fill_rect(x, 0, width, content_bounds().height());
+ solid_quad->SetNew(shared_quad_state, fill_rect, fill_rect, fill_color,
+ force_anti_aliasing_off);
+ }
}
if (!left.IsEmpty()) {
+ bool force_anti_aliasing_off = false;
SolidColorDrawQuad* left_quad =
render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- left_quad->SetNew(shared_quad_state,
- left,
- left,
+ left_quad->SetNew(shared_quad_state, left, left,
colors[kNumColors - 1 - (i % kNumColors)],
- false);
+ force_anti_aliasing_off);
SolidColorDrawQuad* right_quad =
render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- right_quad->SetNew(
- shared_quad_state, right, right, colors[i % kNumColors], false);
+ right_quad->SetNew(shared_quad_state, right, right,
+ colors[i % kNumColors], force_anti_aliasing_off);
}
}
}
void DelegatedRendererLayerImpl::AppendRenderPassQuads(
RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
- AppendQuadsData* append_quads_data,
const RenderPass* delegated_render_pass,
const gfx::Size& frame_size) const {
const SharedQuadState* delegated_shared_quad_state = nullptr;
SharedQuadState* output_shared_quad_state = nullptr;
+ gfx::Transform delegated_frame_to_target_transform = draw_transform();
+ delegated_frame_to_target_transform.Scale(inverse_device_scale_factor_,
+ inverse_device_scale_factor_);
+ bool is_root_delegated_render_pass =
+ delegated_render_pass == render_passes_in_draw_order_.back();
for (const auto& delegated_quad : delegated_render_pass->quad_list) {
- bool is_root_delegated_render_pass =
- delegated_render_pass == render_passes_in_draw_order_.back();
-
if (delegated_quad->shared_quad_state != delegated_shared_quad_state) {
delegated_shared_quad_state = delegated_quad->shared_quad_state;
output_shared_quad_state = render_pass->CreateAndAppendSharedQuadState();
output_shared_quad_state->CopyFrom(delegated_shared_quad_state);
if (is_root_delegated_render_pass) {
- gfx::Transform delegated_frame_to_target_transform = draw_transform();
- delegated_frame_to_target_transform.Scale(inverse_device_scale_factor_,
- inverse_device_scale_factor_);
-
output_shared_quad_state->content_to_target_transform.ConcatTransform(
delegated_frame_to_target_transform);
@@ -437,12 +472,14 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
if (!is_root_delegated_render_pass) {
quad_content_to_delegated_target_space.ConcatTransform(
delegated_render_pass->transform_to_root_target);
- quad_content_to_delegated_target_space.ConcatTransform(draw_transform());
+ quad_content_to_delegated_target_space.ConcatTransform(
+ delegated_frame_to_target_transform);
}
Occlusion occlusion_in_quad_space =
- occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
- quad_content_to_delegated_target_space);
+ draw_properties()
+ .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
+ quad_content_to_delegated_target_space);
gfx::Rect quad_visible_rect =
occlusion_in_quad_space.GetUnoccludedContentRect(
@@ -455,6 +492,7 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
DrawQuad* output_quad = render_pass->CopyFromAndAppendDrawQuad(
delegated_quad, output_shared_quad_state);
output_quad->visible_rect = quad_visible_rect;
+ ValidateQuadResources(output_quad);
} else {
RenderPassId delegated_contributing_render_pass_id =
RenderPassDrawQuad::MaterialCast(delegated_quad)->render_pass_id;
@@ -463,20 +501,16 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
bool present =
ConvertDelegatedRenderPassId(delegated_contributing_render_pass_id,
&output_contributing_render_pass_id);
-
- // The frame may have a RenderPassDrawQuad that points to a RenderPass not
- // part of the frame. Just ignore these quads.
- if (present) {
- DCHECK(output_contributing_render_pass_id !=
- append_quads_data->render_pass_id);
-
- RenderPassDrawQuad* output_quad =
- render_pass->CopyFromAndAppendRenderPassDrawQuad(
- RenderPassDrawQuad::MaterialCast(delegated_quad),
- output_shared_quad_state,
- output_contributing_render_pass_id);
- output_quad->visible_rect = quad_visible_rect;
- }
+ // |present| being false means the child compositor sent an invalid frame.
+ DCHECK(present);
+ DCHECK(output_contributing_render_pass_id != render_pass->id);
+
+ RenderPassDrawQuad* output_quad =
+ render_pass->CopyFromAndAppendRenderPassDrawQuad(
+ RenderPassDrawQuad::MaterialCast(delegated_quad),
+ output_shared_quad_state, output_contributing_render_pass_id);
+ output_quad->visible_rect = quad_visible_rect;
+ ValidateQuadResources(output_quad);
}
}
}
diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.h b/chromium/cc/layers/delegated_renderer_layer_impl.h
index 1f84ffba074..617d76f3b1e 100644
--- a/chromium/cc/layers/delegated_renderer_layer_impl.h
+++ b/chromium/cc/layers/delegated_renderer_layer_impl.h
@@ -34,7 +34,6 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
void PushPropertiesTo(LayerImpl* layer) override;
@@ -59,16 +58,17 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
const RenderPassList& RenderPassesInDrawOrderForTesting() const {
return render_passes_in_draw_order_;
}
- const ResourceProvider::ResourceIdArray& ResourcesForTesting() const {
+ const ResourceProvider::ResourceIdSet& ResourcesForTesting() const {
return resources_;
}
private:
void ClearChildId();
- void AppendRainbowDebugBorder(RenderPass* render_pass,
- AppendQuadsData* append_quads_data);
+ void AppendRainbowDebugBorder(RenderPass* render_pass);
+ void TakeOwnershipOfResourcesIfOnActiveTree(
+ const ResourceProvider::ResourceIdSet& resources);
void SetRenderPasses(RenderPassList* render_passes_in_draw_order);
void ClearRenderPasses();
@@ -78,8 +78,6 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
RenderPassId* output_render_pass_id) const;
void AppendRenderPassQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
- AppendQuadsData* append_quads_data,
const RenderPass* delegated_render_pass,
const gfx::Size& frame_size) const;
@@ -90,7 +88,7 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
float inverse_device_scale_factor_;
RenderPassList render_passes_in_draw_order_;
base::hash_map<RenderPassId, int> render_passes_index_by_id_;
- ResourceProvider::ResourceIdArray resources_;
+ ResourceProvider::ResourceIdSet resources_;
int child_id_;
bool own_child_id_;
diff --git a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc
index 5a797f9ad45..cc45c53f19e 100644
--- a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -9,15 +9,16 @@
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/test/fake_delegated_renderer_layer_impl.h"
+#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_layer_tree_host_impl_client.h"
#include "cc/test/fake_output_surface.h"
-#include "cc/test/fake_proxy.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/render_pass_test_common.h"
#include "cc/test/render_pass_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
@@ -37,17 +38,18 @@ class DelegatedRendererLayerImplTest : public testing::Test {
LayerTreeSettings settings;
settings.minimum_occlusion_tracking_size = gfx::Size();
- host_impl_.reset(
- new FakeLayerTreeHostImpl(settings, &proxy_, &shared_bitmap_manager_));
+ host_impl_.reset(new FakeLayerTreeHostImpl(
+ settings, &proxy_, &shared_bitmap_manager_, &task_graph_runner_));
host_impl_->InitializeRenderer(FakeOutputSurface::Create3d());
host_impl_->SetViewportSize(gfx::Size(10, 10));
}
protected:
- FakeProxy proxy_;
+ FakeImplProxy proxy_;
DebugScopedSetImplThreadAndMainThreadBlocked
always_impl_thread_and_main_thread_blocked_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
scoped_ptr<LayerTreeHostImpl> host_impl_;
};
@@ -67,18 +69,19 @@ class DelegatedRendererLayerImplTestSimple
host_impl_->SetViewportSize(gfx::Size(100, 100));
root_layer->SetBounds(gfx::Size(100, 100));
+ root_layer->SetHasRenderSurface(true);
layer_before->SetPosition(gfx::Point(20, 20));
layer_before->SetBounds(gfx::Size(14, 14));
layer_before->SetContentBounds(gfx::Size(14, 14));
layer_before->SetDrawsContent(true);
- layer_before->SetForceRenderSurface(true);
+ layer_before->SetHasRenderSurface(true);
layer_after->SetPosition(gfx::Point(5, 5));
layer_after->SetBounds(gfx::Size(15, 15));
layer_after->SetContentBounds(gfx::Size(15, 15));
layer_after->SetDrawsContent(true);
- layer_after->SetForceRenderSurface(true);
+ layer_after->SetHasRenderSurface(true);
delegated_renderer_layer->SetPosition(gfx::Point(3, 3));
delegated_renderer_layer->SetBounds(gfx::Size(10, 10));
@@ -106,10 +109,7 @@ class DelegatedRendererLayerImplTestSimple
gfx::Transform(1, 0, 0, 1, 9, 10));
AddRenderPassQuad(pass3, pass2);
delegated_renderer_layer->SetFrameDataForRenderPasses(
- 1.f, &delegated_render_passes);
-
- // The RenderPasses should be taken by the layer.
- EXPECT_EQ(0u, delegated_render_passes.size());
+ 1.f, delegated_render_passes);
root_layer_ = root_layer.get();
layer_before_ = layer_before.get();
@@ -134,6 +134,169 @@ class DelegatedRendererLayerImplTestSimple
DelegatedRendererLayerImpl* delegated_renderer_layer_;
};
+TEST_F(DelegatedRendererLayerImplTest,
+ ChangeContributingRenderPassForNewFrame) {
+ FakeDelegatedRendererLayerImpl* fake_delegated_renderer_layer_impl;
+ {
+ scoped_ptr<LayerImpl> root_layer =
+ SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
+ scoped_ptr<FakeDelegatedRendererLayerImpl> delegated_renderer_layer =
+ FakeDelegatedRendererLayerImpl::Create(host_impl_->active_tree(), 2);
+
+ host_impl_->SetViewportSize(gfx::Size(100, 100));
+ root_layer->SetBounds(gfx::Size(100, 100));
+ root_layer->SetHasRenderSurface(true);
+
+ delegated_renderer_layer->SetPosition(gfx::Point(3, 3));
+ delegated_renderer_layer->SetBounds(gfx::Size(10, 10));
+ delegated_renderer_layer->SetContentBounds(gfx::Size(10, 10));
+ delegated_renderer_layer->SetDrawsContent(true);
+ delegated_renderer_layer->SetHasRenderSurface(true);
+ gfx::Transform transform;
+ transform.Translate(1.0, 1.0);
+ delegated_renderer_layer->SetTransform(transform);
+
+ RenderPassList delegated_render_passes;
+ TestRenderPass* pass1 =
+ AddRenderPass(&delegated_render_passes, RenderPassId(9, 6),
+ gfx::Rect(6, 6, 6, 6), gfx::Transform(1, 0, 0, 1, 5, 6));
+ AddQuad(pass1, gfx::Rect(0, 0, 6, 6), 33u);
+ TestRenderPass* pass2 =
+ AddRenderPass(&delegated_render_passes, RenderPassId(9, 7),
+ gfx::Rect(7, 7, 7, 7), gfx::Transform(1, 0, 0, 1, 7, 8));
+ AddQuad(pass2, gfx::Rect(0, 0, 7, 7), 22u);
+ AddRenderPassQuad(pass2, pass1);
+ TestRenderPass* pass3 =
+ AddRenderPass(&delegated_render_passes, RenderPassId(9, 8),
+ gfx::Rect(0, 0, 8, 8), gfx::Transform(1, 0, 0, 1, 9, 10));
+ AddRenderPassQuad(pass3, pass2);
+ delegated_renderer_layer->SetFrameDataForRenderPasses(
+ 1.f, delegated_render_passes);
+
+ fake_delegated_renderer_layer_impl = delegated_renderer_layer.get();
+
+ root_layer->AddChild(delegated_renderer_layer.Pass());
+
+ host_impl_->active_tree()->SetRootLayer(root_layer.Pass());
+
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+
+ // Root layer has one render pass, and delegated renderer layer has two
+ // contributing render passes and its own render pass.
+ ASSERT_EQ(4u, frame.render_passes.size());
+
+ host_impl_->DrawLayers(&frame);
+ host_impl_->DidDrawAllLayers(frame);
+ }
+ {
+ // New frame makes delegated renderer layer loses its contributing render
+ // passes.
+ RenderPassList delegated_render_passes;
+ AddRenderPass(&delegated_render_passes, RenderPassId(9, 8),
+ gfx::Rect(0, 0, 8, 8), gfx::Transform(1, 0, 0, 1, 9, 10));
+ fake_delegated_renderer_layer_impl->SetFrameDataForRenderPasses(
+ 1.f, delegated_render_passes);
+
+ // Force damage to redraw a new frame.
+ host_impl_->SetViewportDamage(gfx::Rect(10, 10));
+
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+
+ // Each non-DelegatedRendererLayer added one RenderPass. The
+ // DelegatedRendererLayer added two contributing passes.
+ ASSERT_EQ(1u, frame.render_passes.size());
+
+ host_impl_->DrawLayers(&frame);
+ host_impl_->DidDrawAllLayers(frame);
+ }
+}
+
+TEST_F(DelegatedRendererLayerImplTest,
+ ChangeContributingRenderPassNonFullTreeSync) {
+ FakeDelegatedRendererLayerImpl* fake_delegated_renderer_layer_impl;
+ {
+ host_impl_->CreatePendingTree();
+ scoped_ptr<LayerImpl> root_layer =
+ SolidColorLayerImpl::Create(host_impl_->pending_tree(), 1);
+ scoped_ptr<FakeDelegatedRendererLayerImpl> delegated_renderer_layer =
+ FakeDelegatedRendererLayerImpl::Create(host_impl_->pending_tree(), 2);
+
+ host_impl_->SetViewportSize(gfx::Size(100, 100));
+ root_layer->SetBounds(gfx::Size(100, 100));
+ root_layer->SetHasRenderSurface(true);
+
+ delegated_renderer_layer->SetPosition(gfx::Point(3, 3));
+ delegated_renderer_layer->SetBounds(gfx::Size(10, 10));
+ delegated_renderer_layer->SetContentBounds(gfx::Size(10, 10));
+ delegated_renderer_layer->SetDrawsContent(true);
+ delegated_renderer_layer->SetHasRenderSurface(true);
+ gfx::Transform transform;
+ transform.Translate(1.0, 1.0);
+ delegated_renderer_layer->SetTransform(transform);
+
+ RenderPassList delegated_render_passes;
+ TestRenderPass* pass1 =
+ AddRenderPass(&delegated_render_passes, RenderPassId(9, 6),
+ gfx::Rect(6, 6, 6, 6), gfx::Transform(1, 0, 0, 1, 5, 6));
+ AddQuad(pass1, gfx::Rect(0, 0, 6, 6), 33u);
+ TestRenderPass* pass2 =
+ AddRenderPass(&delegated_render_passes, RenderPassId(9, 7),
+ gfx::Rect(7, 7, 7, 7), gfx::Transform(1, 0, 0, 1, 7, 8));
+ AddQuad(pass2, gfx::Rect(0, 0, 7, 7), 22u);
+ AddRenderPassQuad(pass2, pass1);
+ TestRenderPass* pass3 =
+ AddRenderPass(&delegated_render_passes, RenderPassId(9, 8),
+ gfx::Rect(0, 0, 8, 8), gfx::Transform(1, 0, 0, 1, 9, 10));
+ AddRenderPassQuad(pass3, pass2);
+ delegated_renderer_layer->SetFrameDataForRenderPasses(
+ 1.f, delegated_render_passes);
+
+ fake_delegated_renderer_layer_impl = delegated_renderer_layer.get();
+
+ root_layer->AddChild(delegated_renderer_layer.Pass());
+
+ host_impl_->pending_tree()->SetRootLayer(root_layer.Pass());
+ host_impl_->ActivateSyncTree();
+
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+
+ // Root layer has one render pass, and delegated renderer layer has two
+ // contributing render passes and its own render pass.
+ ASSERT_EQ(4u, frame.render_passes.size());
+
+ host_impl_->DrawLayers(&frame);
+ host_impl_->DidDrawAllLayers(frame);
+ }
+ {
+ // Remove contributing render passes from the delegated renderer layer.
+ host_impl_->CreatePendingTree();
+ host_impl_->pending_tree()->set_needs_full_tree_sync(false);
+ RenderPassList delegated_render_passes;
+ AddRenderPass(&delegated_render_passes, RenderPassId(9, 8),
+ gfx::Rect(0, 0, 8, 8), gfx::Transform(1, 0, 0, 1, 9, 10));
+
+ fake_delegated_renderer_layer_impl->SetFrameDataForRenderPasses(
+ 1.f, delegated_render_passes);
+
+ // Force damage to redraw a new frame.
+
+ host_impl_->ActivateSyncTree();
+ host_impl_->SetViewportDamage(gfx::Rect(100, 100));
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+
+ // Root layer has one render pass, and delegated renderer layer no longer
+ // has contributing render passes.
+ ASSERT_EQ(1u, frame.render_passes.size());
+
+ host_impl_->DrawLayers(&frame);
+ host_impl_->DidDrawAllLayers(frame);
+ }
+}
+
TEST_F(DelegatedRendererLayerImplTestSimple, AddsContributingRenderPasses) {
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -163,7 +326,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, AddsContributingRenderPasses) {
EXPECT_EQ(gfx::Rect(7, 7, 7, 7).ToString(),
frame.render_passes[2]->output_rect.ToString());
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -199,7 +362,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple,
EXPECT_EQ(gfx::Rect(0, 0, 6, 6).ToString(),
frame.render_passes[1]->quad_list.front()->rect.ToString());
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -226,7 +389,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, AddsQuadsToTargetRenderPass) {
EXPECT_EQ(gfx::Rect(0, 0, 15, 15).ToString(),
frame.render_passes[3]->quad_list.ElementAt(1)->rect.ToString());
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -261,7 +424,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple,
gfx::Transform(),
frame.render_passes[1]->quad_list.front()->quadTransform());
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -293,56 +456,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, RenderPassTransformIsModified) {
transform * seven_eight,
frame.render_passes[2]->transform_to_root_target);
- host_impl_->DrawLayers(&frame, base::TimeTicks::Now());
- host_impl_->DidDrawAllLayers(frame);
-}
-
-TEST_F(DelegatedRendererLayerImplTestSimple, DoesNotOwnARenderSurface) {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- // If the DelegatedRendererLayer is axis aligned and has opacity 1, then it
- // has no need to be a RenderSurface for the quads it carries.
- EXPECT_FALSE(delegated_renderer_layer_->render_surface());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
-}
-
-TEST_F(DelegatedRendererLayerImplTestSimple, DoesOwnARenderSurfaceForOpacity) {
- delegated_renderer_layer_->SetOpacity(0.5f);
-
- LayerTreeHostImpl::FrameData frame;
- FakeLayerTreeHostImpl::RecursiveUpdateNumChildren(
- host_impl_->active_tree()->root_layer());
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- // This test case has quads from multiple layers in the delegated renderer, so
- // if the DelegatedRendererLayer has opacity < 1, it should end up with a
- // render surface.
- EXPECT_TRUE(delegated_renderer_layer_->render_surface());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
-}
-
-TEST_F(DelegatedRendererLayerImplTestSimple,
- DoesOwnARenderSurfaceForTransform) {
- gfx::Transform rotation;
- rotation.RotateAboutZAxis(30.0);
- delegated_renderer_layer_->SetTransform(rotation);
-
- LayerTreeHostImpl::FrameData frame;
- FakeLayerTreeHostImpl::RecursiveUpdateNumChildren(
- host_impl_->active_tree()->root_layer());
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- // This test case has quads from multiple layers in the delegated renderer, so
- // if the DelegatedRendererLayer has opacity < 1, it should end up with a
- // render surface.
- EXPECT_TRUE(delegated_renderer_layer_->render_surface());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -351,7 +465,7 @@ class DelegatedRendererLayerImplTestOwnSurface
public:
DelegatedRendererLayerImplTestOwnSurface()
: DelegatedRendererLayerImplTestSimple() {
- delegated_renderer_layer_->SetForceRenderSurface(true);
+ delegated_renderer_layer_->SetHasRenderSurface(true);
}
};
@@ -389,7 +503,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface, AddsRenderPasses) {
EXPECT_EQ(gfx::Rect(7, 7, 7, 7).ToString(),
frame.render_passes[2]->output_rect.ToString());
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -427,7 +541,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface,
EXPECT_EQ(gfx::Rect(0, 0, 6, 6).ToString(),
frame.render_passes[1]->quad_list.front()->rect.ToString());
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -452,7 +566,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface, AddsQuadsToTargetRenderPass) {
EXPECT_EQ(gfx::Rect(7, 7, 7, 7).ToString(),
frame.render_passes[3]->quad_list.front()->rect.ToString());
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -486,7 +600,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface,
gfx::Transform(),
frame.render_passes[1]->quad_list.front()->quadTransform());
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -507,6 +621,7 @@ class DelegatedRendererLayerImplTestTransform
host_impl_->SetViewportSize(gfx::Size(200, 200));
root_layer->SetBounds(gfx::Size(100, 100));
+ root_layer->SetHasRenderSurface(true);
delegated_renderer_layer->SetPosition(gfx::Point(20, 20));
delegated_renderer_layer->SetBounds(gfx::Size(75, 75));
@@ -624,10 +739,7 @@ class DelegatedRendererLayerImplTestTransform
false);
delegated_renderer_layer->SetFrameDataForRenderPasses(
- delegated_device_scale_factor_, &delegated_render_passes);
-
- // The RenderPasses should be taken by the layer.
- EXPECT_EQ(0u, delegated_render_passes.size());
+ delegated_device_scale_factor_, delegated_render_passes);
root_layer_ = root_layer.get();
delegated_renderer_layer_ = delegated_renderer_layer.get();
@@ -736,7 +848,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_NoSurface) {
expected,
contrib_delegated_shared_quad_state->content_to_target_transform);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -795,7 +907,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_NoSurface) {
expected,
contrib_delegated_shared_quad_state->content_to_target_transform);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -803,7 +915,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) {
root_delegated_render_pass_is_clipped_ = false;
SetUpTest();
- delegated_renderer_layer_->SetForceRenderSurface(true);
+ delegated_renderer_layer_->SetHasRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -816,9 +928,9 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) {
&root_delegated_shared_quad_state,
&contrib_delegated_shared_quad_state);
- // When the layer owns a surface, then its position and translation are not
- // a part of its draw transform.
- EXPECT_EQ(gfx::Rect(10, 10, 35, 35).ToString(),
+ // When the layer owns a surface, then its translation is not part of its
+ // draw transform, but its scale is.
+ EXPECT_EQ(gfx::Rect(20, 20, 70, 70).ToString(),
root_delegated_shared_quad_state->clip_rect.ToString());
// Since the layer owns a surface it doesn't need to clip its quads, so
@@ -826,8 +938,9 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) {
EXPECT_FALSE(root_delegated_shared_quad_state->is_clipped);
gfx::Transform expected;
- // This is the transform within the source frame.
- expected.Scale(1.5, 1.5);
+ // This is the transform within the source frame scaled by the delegated
+ // render layer transform.
+ expected.Scale(3.0, 3.0);
expected.Translate(7.0, 7.0);
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected, root_delegated_shared_quad_state->content_to_target_transform);
@@ -843,7 +956,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) {
expected,
contrib_delegated_shared_quad_state->content_to_target_transform);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -851,7 +964,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_Surface) {
root_delegated_render_pass_is_clipped_ = true;
SetUpTest();
- delegated_renderer_layer_->SetForceRenderSurface(true);
+ delegated_renderer_layer_->SetHasRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -864,17 +977,18 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_Surface) {
&root_delegated_shared_quad_state,
&contrib_delegated_shared_quad_state);
- // When the layer owns a surface, then its position and translation are not
- // a part of its draw transform. The clip_rect should be preserved.
- EXPECT_EQ(gfx::Rect(10, 10, 35, 35).ToString(),
+ // When the layer owns a surface, then its translation is not part of its
+ // draw transform, but its scale is.
+ EXPECT_EQ(gfx::Rect(20, 20, 70, 70).ToString(),
root_delegated_shared_quad_state->clip_rect.ToString());
// The quads had a clip and it should be preserved.
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
gfx::Transform expected;
- // This is the transform within the source frame.
- expected.Scale(1.5, 1.5);
+ // This is the transform within the source frame scaled by the delegated
+ // render layer transform.
+ expected.Scale(3.0, 3.0);
expected.Translate(7.0, 7.0);
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected, root_delegated_shared_quad_state->content_to_target_transform);
@@ -890,7 +1004,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_Surface) {
expected,
contrib_delegated_shared_quad_state->content_to_target_transform);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -929,7 +1043,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, MismatchedDeviceScaleFactor) {
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected, root_delegated_shared_quad_state->content_to_target_transform);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -948,6 +1062,7 @@ class DelegatedRendererLayerImplTestClip
host_impl_->SetViewportSize(gfx::Size(100, 100));
root_layer->SetBounds(gfx::Size(100, 100));
+ root_layer->SetHasRenderSurface(true);
delegated_renderer_layer->SetPosition(gfx::Point(20, 20));
delegated_renderer_layer->SetBounds(gfx::Size(50, 50));
@@ -1057,10 +1172,7 @@ class DelegatedRendererLayerImplTestClip
false);
delegated_renderer_layer->SetFrameDataForRenderPasses(
- 1.f, &delegated_render_passes);
-
- // The RenderPasses should be taken by the layer.
- EXPECT_EQ(0u, delegated_render_passes.size());
+ 1.f, delegated_render_passes);
root_layer_ = root_layer.get();
delegated_renderer_layer_ = delegated_renderer_layer.get();
@@ -1118,7 +1230,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
// Quads are clipped to the delegated renderer layer.
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -1147,7 +1259,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
// Quads came with a clip rect.
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -1177,7 +1289,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
// Quads are clipped to the delegated renderer layer.
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -1206,7 +1318,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
// Quads came with a clip rect.
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -1216,7 +1328,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
clip_delegated_renderer_layer_ = false;
SetUpTest();
- delegated_renderer_layer_->SetForceRenderSurface(true);
+ delegated_renderer_layer_->SetHasRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -1235,7 +1347,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
// clip rect is ignored, and they are not set as clipped.
EXPECT_FALSE(root_delegated_shared_quad_state->is_clipped);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -1245,7 +1357,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
clip_delegated_renderer_layer_ = false;
SetUpTest();
- delegated_renderer_layer_->SetForceRenderSurface(true);
+ delegated_renderer_layer_->SetHasRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -1265,7 +1377,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
// Quads came with a clip rect.
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -1275,7 +1387,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
clip_delegated_renderer_layer_ = true;
SetUpTest();
- delegated_renderer_layer_->SetForceRenderSurface(true);
+ delegated_renderer_layer_->SetHasRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -1294,7 +1406,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
// clip rect is ignored, and they are not set as clipped.
EXPECT_FALSE(root_delegated_shared_quad_state->is_clipped);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -1303,7 +1415,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, QuadsClipped_LayerClipped_Surface) {
clip_delegated_renderer_layer_ = true;
SetUpTest();
- delegated_renderer_layer_->SetForceRenderSurface(true);
+ delegated_renderer_layer_->SetHasRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -1325,59 +1437,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, QuadsClipped_LayerClipped_Surface) {
// Quads came with a clip rect.
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
-}
-
-TEST_F(DelegatedRendererLayerImplTest, InvalidRenderPassDrawQuad) {
- scoped_ptr<LayerImpl> root_layer =
- LayerImpl::Create(host_impl_->active_tree(), 1);
- scoped_ptr<FakeDelegatedRendererLayerImpl> delegated_renderer_layer =
- FakeDelegatedRendererLayerImpl::Create(host_impl_->active_tree(), 4);
-
- host_impl_->SetViewportSize(gfx::Size(100, 100));
-
- delegated_renderer_layer->SetPosition(gfx::Point(3, 3));
- delegated_renderer_layer->SetBounds(gfx::Size(10, 10));
- delegated_renderer_layer->SetContentBounds(gfx::Size(10, 10));
- delegated_renderer_layer->SetDrawsContent(true);
-
- RenderPassList delegated_render_passes;
- TestRenderPass* pass1 = AddRenderPass(&delegated_render_passes,
- RenderPassId(9, 6),
- gfx::Rect(0, 0, 10, 10),
- gfx::Transform());
- AddQuad(pass1, gfx::Rect(0, 0, 6, 6), 33u);
-
- // This render pass isn't part of the frame.
- scoped_ptr<TestRenderPass> missing_pass(TestRenderPass::Create());
- missing_pass->SetNew(RenderPassId(9, 7),
- gfx::Rect(7, 7, 7, 7),
- gfx::Rect(7, 7, 7, 7),
- gfx::Transform());
-
- // But a render pass quad refers to it.
- AddRenderPassQuad(pass1, missing_pass.get());
-
- delegated_renderer_layer->SetFrameDataForRenderPasses(
- 1.f, &delegated_render_passes);
-
- // The RenderPasses should be taken by the layer.
- EXPECT_EQ(0u, delegated_render_passes.size());
-
- root_layer->AddChild(delegated_renderer_layer.Pass());
- host_impl_->active_tree()->SetRootLayer(root_layer.Pass());
-
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- // The DelegatedRendererLayerImpl should drop the bad RenderPassDrawQuad.
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
- EXPECT_EQ(DrawQuad::SOLID_COLOR,
- frame.render_passes[0]->quad_list.front()->material);
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -1422,7 +1482,7 @@ TEST_F(DelegatedRendererLayerImplTest, Occlusion) {
transform,
SkXfermode::kSrcOver_Mode);
delegated_renderer_layer_impl->SetFrameDataForRenderPasses(
- 1.f, &delegated_render_passes);
+ 1.f, delegated_render_passes);
impl.CalcDrawProps(viewport_size);
@@ -1432,21 +1492,21 @@ TEST_F(DelegatedRendererLayerImplTest, Occlusion) {
{
SCOPED_TRACE("Root render pass");
- impl.AppendQuadsForPassWithOcclusion(
- delegated_renderer_layer_impl, pass1_id, occluded);
- LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ impl.AppendQuadsForPassWithOcclusion(delegated_renderer_layer_impl, pass1,
+ occluded);
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(pass1->quad_list,
quad_screen_rect);
- ASSERT_EQ(1u, impl.quad_list().size());
- EXPECT_EQ(DrawQuad::RENDER_PASS, impl.quad_list().front()->material);
+ ASSERT_EQ(1u, pass1->quad_list.size());
+ EXPECT_EQ(DrawQuad::RENDER_PASS, pass1->quad_list.front()->material);
}
{
SCOPED_TRACE("Contributing render pass");
- impl.AppendQuadsForPassWithOcclusion(
- delegated_renderer_layer_impl, pass2_id, occluded);
+ impl.AppendQuadsForPassWithOcclusion(delegated_renderer_layer_impl, pass2,
+ occluded);
LayerTestCommon::VerifyQuadsExactlyCoverRect(
- impl.quad_list(), gfx::Rect(quad_screen_rect.size()));
- ASSERT_EQ(1u, impl.quad_list().size());
- EXPECT_EQ(DrawQuad::SOLID_COLOR, impl.quad_list().front()->material);
+ pass2->quad_list, gfx::Rect(quad_screen_rect.size()));
+ ASSERT_EQ(1u, pass2->quad_list.size());
+ EXPECT_EQ(DrawQuad::SOLID_COLOR, pass2->quad_list.front()->material);
}
}
@@ -1456,21 +1516,21 @@ TEST_F(DelegatedRendererLayerImplTest, Occlusion) {
gfx::Rect occluded(delegated_renderer_layer_impl->visible_content_rect());
SCOPED_TRACE("Root render pass");
- impl.AppendQuadsForPassWithOcclusion(
- delegated_renderer_layer_impl, pass1_id, occluded);
- LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ impl.AppendQuadsForPassWithOcclusion(delegated_renderer_layer_impl, pass1,
+ occluded);
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(pass1->quad_list,
gfx::Rect());
- EXPECT_EQ(impl.quad_list().size(), 0u);
+ EXPECT_EQ(pass1->quad_list.size(), 0u);
}
{
gfx::Rect occluded(delegated_renderer_layer_impl->visible_content_rect());
SCOPED_TRACE("Contributing render pass");
- impl.AppendQuadsForPassWithOcclusion(
- delegated_renderer_layer_impl, pass2_id, occluded);
- LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ impl.AppendQuadsForPassWithOcclusion(delegated_renderer_layer_impl, pass2,
+ occluded);
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(pass2->quad_list,
gfx::Rect());
- EXPECT_EQ(impl.quad_list().size(), 0u);
+ EXPECT_EQ(pass2->quad_list.size(), 0u);
}
}
@@ -1480,14 +1540,14 @@ TEST_F(DelegatedRendererLayerImplTest, Occlusion) {
gfx::Rect occlusion_in_root_target(0, 0, 500, 1000);
SCOPED_TRACE("Root render pass");
- impl.AppendQuadsForPassWithOcclusion(
- delegated_renderer_layer_impl, pass1_id, occlusion_in_root_target);
+ impl.AppendQuadsForPassWithOcclusion(delegated_renderer_layer_impl, pass1,
+ occlusion_in_root_target);
size_t partially_occluded_count = 0;
- LayerTestCommon::VerifyQuadsAreOccluded(impl.quad_list(),
+ LayerTestCommon::VerifyQuadsAreOccluded(pass1->quad_list,
occlusion_in_root_target,
&partially_occluded_count);
// The layer outputs one quad, which is partially occluded.
- EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, pass1->quad_list.size());
EXPECT_EQ(1u, partially_occluded_count);
}
{
@@ -1497,21 +1557,20 @@ TEST_F(DelegatedRendererLayerImplTest, Occlusion) {
occlusion_in_root_target - quad_screen_rect.OffsetFromOrigin();
SCOPED_TRACE("Contributing render pass");
- impl.AppendQuadsForPassWithOcclusion(
- delegated_renderer_layer_impl, pass2_id, occlusion_in_root_target);
+ impl.AppendQuadsForPassWithOcclusion(delegated_renderer_layer_impl, pass2,
+ occlusion_in_root_target);
size_t partially_occluded_count = 0;
LayerTestCommon::VerifyQuadsAreOccluded(
- impl.quad_list(),
- occlusion_in_target_of_delegated_quad,
+ pass2->quad_list, occlusion_in_target_of_delegated_quad,
&partially_occluded_count);
// The layer outputs one quad, which is partially occluded.
- EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, pass2->quad_list.size());
EXPECT_EQ(1u, partially_occluded_count);
// The quad in the contributing surface is at (211,300) in the root.
// The occlusion extends to 500 in the x-axis, pushing the left of the
// visible part of the quad to 500 - 211 = 300 - 11 inside the quad.
EXPECT_EQ(gfx::Rect(300 - 11, 0, 100 + 11, 500).ToString(),
- impl.quad_list().front()->visible_rect.ToString());
+ pass2->quad_list.front()->visible_rect.ToString());
}
{
gfx::Rect occlusion_in_root_target(0, 0, 500, 1000);
@@ -1529,21 +1588,85 @@ TEST_F(DelegatedRendererLayerImplTest, Occlusion) {
impl.CalcDrawProps(viewport_size);
- impl.AppendQuadsForPassWithOcclusion(
- delegated_renderer_layer_impl, pass2_id, occlusion_in_root_target);
+ impl.AppendQuadsForPassWithOcclusion(delegated_renderer_layer_impl, pass2,
+ occlusion_in_root_target);
size_t partially_occluded_count = 0;
LayerTestCommon::VerifyQuadsAreOccluded(
- impl.quad_list(),
- occlusion_in_target_of_delegated_quad,
+ pass2->quad_list, occlusion_in_target_of_delegated_quad,
&partially_occluded_count);
// The layer outputs one quad, which is partially occluded.
- EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, pass2->quad_list.size());
EXPECT_EQ(1u, partially_occluded_count);
// The quad in the contributing surface is at (222,300) in the transformed
// root. The occlusion extends to 500 in the x-axis, pushing the left of
// the visible part of the quad to 500 - 222 = 300 - 22 inside the quad.
EXPECT_EQ(gfx::Rect(300 - 22, 0, 100 + 22, 500).ToString(),
- impl.quad_list().front()->visible_rect.ToString());
+ pass2->quad_list.front()->visible_rect.ToString());
+ }
+ }
+}
+
+TEST_F(DelegatedRendererLayerImplTest, DeviceScaleFactorOcclusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+ gfx::Rect quad_screen_rect(211, 300, 400, 500);
+
+ gfx::Transform transform;
+ transform.Translate(211.f, 300.f);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ FakeDelegatedRendererLayerImpl* delegated_renderer_layer_impl =
+ impl.AddChildToRoot<FakeDelegatedRendererLayerImpl>();
+ delegated_renderer_layer_impl->SetBounds(layer_size);
+ delegated_renderer_layer_impl->SetContentBounds(layer_size);
+ delegated_renderer_layer_impl->SetDrawsContent(true);
+
+ // Contributing render pass is offset by a transform and holds a quad that
+ // covers it entirely.
+ RenderPassList delegated_render_passes;
+ // pass2 is just the size of the quad. It contributes to |pass1| with a
+ // translation of (211,300).
+ RenderPassId pass2_id =
+ delegated_renderer_layer_impl->FirstContributingRenderPassId();
+ TestRenderPass* pass2 =
+ AddRenderPass(&delegated_render_passes, pass2_id,
+ gfx::Rect(quad_screen_rect.size()), transform);
+ AddQuad(pass2, gfx::Rect(quad_screen_rect.size()), SK_ColorRED);
+ // |pass1| covers the whole layer.
+ RenderPassId pass1_id = RenderPassId(impl.root_layer()->id(), 0);
+ TestRenderPass* pass1 =
+ AddRenderPass(&delegated_render_passes, pass1_id, gfx::Rect(layer_size),
+ gfx::Transform());
+ AddRenderPassQuad(pass1, pass2, 0, FilterOperations(), transform,
+ SkXfermode::kSrcOver_Mode);
+ delegated_renderer_layer_impl->SetFrameDataForRenderPasses(
+ 1.2f, delegated_render_passes);
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ {
+ gfx::Rect occlusion_in_root_target(0, 0, 500, 1000);
+ // Move the occlusion to where it is in the contributing surface.
+ gfx::Rect occlusion_in_target_of_delegated_quad =
+ occlusion_in_root_target - quad_screen_rect.OffsetFromOrigin();
+
+ SCOPED_TRACE("Contributing render pass");
+ impl.AppendQuadsForPassWithOcclusion(delegated_renderer_layer_impl, pass2,
+ occlusion_in_root_target);
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsAreOccluded(
+ pass2->quad_list, occlusion_in_target_of_delegated_quad,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, pass2->quad_list.size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ // The quad in the contributing surface is at (211,300) in the root.
+ // The occlusion extends to 500 * 1.2 (dsf) = 600 in the x-axis, pushing
+ // the left of the visible part of the quad to 600 - 211 = 400 - 11 inside
+ // the quad.
+ EXPECT_EQ(gfx::Rect(400 - 11, 0, 11, 500).ToString(),
+ pass2->quad_list.front()->visible_rect.ToString());
}
}
}
@@ -1565,7 +1688,7 @@ TEST_F(DelegatedRendererLayerImplTest, PushPropertiesTo) {
gfx::Rect(layer_size),
gfx::Transform());
delegated_renderer_layer_impl->SetFrameDataForRenderPasses(
- 2.f, &delegated_render_passes);
+ 2.f, delegated_render_passes);
EXPECT_EQ(0.5f, delegated_renderer_layer_impl->inverse_device_scale_factor());
scoped_ptr<DelegatedRendererLayerImpl> other_layer =
diff --git a/chromium/cc/layers/draw_properties.h b/chromium/cc/layers/draw_properties.h
index 403393e425e..3dfb203b33b 100644
--- a/chromium/cc/layers/draw_properties.h
+++ b/chromium/cc/layers/draw_properties.h
@@ -6,6 +6,8 @@
#define CC_LAYERS_DRAW_PROPERTIES_H_
#include "base/memory/scoped_ptr.h"
+#include "cc/trees/occlusion.h"
+#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/transform.h"
@@ -17,6 +19,7 @@ template <typename LayerType>
struct CC_EXPORT DrawProperties {
DrawProperties()
: opacity(0.f),
+ blend_mode(SkXfermode::kSrcOver_Mode),
opacity_is_animating(false),
screen_space_opacity_is_animating(false),
target_space_transform_is_animating(false),
@@ -29,8 +32,10 @@ struct CC_EXPORT DrawProperties {
num_unclipped_descendants(0),
layer_or_descendant_has_copy_request(false),
layer_or_descendant_has_input_handler(false),
+ layer_or_descendant_is_drawn(false),
has_child_with_a_scroll_parent(false),
sorted_for_recursion(false),
+ visited(false),
index_of_first_descendants_addition(0),
num_descendants_added(0),
index_of_first_render_surface_layer_list_addition(0),
@@ -38,6 +43,7 @@ struct CC_EXPORT DrawProperties {
last_drawn_render_surface_layer_list_id(0),
ideal_contents_scale(0.f),
maximum_animation_contents_scale(0.f),
+ starting_animation_contents_scale(0.f),
page_scale_factor(0.f),
device_scale_factor(0.f) {}
@@ -48,11 +54,18 @@ struct CC_EXPORT DrawProperties {
// Transforms objects from content space to screen space (viewport space).
gfx::Transform screen_space_transform;
+ // Known occlusion above the layer mapped to the content space of the layer.
+ Occlusion occlusion_in_content_space;
+
// DrawProperties::opacity may be different than LayerType::opacity,
// particularly in the case when a RenderSurface re-parents the layer's
// opacity, or when opacity is compounded by the hierarchy.
float opacity;
+ // DrawProperties::blend_mode may be different than LayerType::blend_mode,
+ // when a RenderSurface re-parents the layer's blend_mode.
+ SkXfermode::Mode blend_mode;
+
// xxx_is_animating flags are used to indicate whether the DrawProperties
// are actually meaningful on the main thread. When the properties are
// animating, the main thread may not have the same values that are used
@@ -73,9 +86,6 @@ struct CC_EXPORT DrawProperties {
// ancestor of this layer.
LayerType* render_target;
- // The surface that this layer and its subtree would contribute to.
- scoped_ptr<typename LayerType::RenderSurfaceType> render_surface;
-
// This rect is in the layer's content space.
gfx::Rect visible_content_rect;
@@ -106,6 +116,9 @@ struct CC_EXPORT DrawProperties {
// If true, the layer or one of its descendants has a wheel or touch handler.
bool layer_or_descendant_has_input_handler;
+ // If true, the layer or one of its descendants is drawn
+ bool layer_or_descendant_is_drawn;
+
// This is true if the layer has any direct child that has a scroll parent.
// This layer will not be the scroll parent in this case. This information
// lets us avoid work in CalculateDrawPropertiesInternal -- if none of our
@@ -116,6 +129,9 @@ struct CC_EXPORT DrawProperties {
// layer will be visited while computing draw properties has been determined.
bool sorted_for_recursion;
+ // This is used to sanity-check CDP and ensure that we don't revisit a layer.
+ bool visited;
+
// If this layer is visited out of order, its contribution to the descendant
// and render surface layer lists will be put aside in a temporary list.
// These values will allow for an efficient reordering of these additions.
@@ -141,6 +157,10 @@ struct CC_EXPORT DrawProperties {
// should be rastered at to be crisp.
float maximum_animation_contents_scale;
+ // The scale during the layer animation start at which content should be
+ // rastered at to be crisp.
+ float starting_animation_contents_scale;
+
// The page scale factor that is applied to the layer. Since some layers may
// have page scale applied and others not, this may differ between layers.
float page_scale_factor;
diff --git a/chromium/cc/layers/heads_up_display_layer.cc b/chromium/cc/layers/heads_up_display_layer.cc
index 5c91249e0de..5dd4bd24d52 100644
--- a/chromium/cc/layers/heads_up_display_layer.cc
+++ b/chromium/cc/layers/heads_up_display_layer.cc
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/trees/layer_tree_host.h"
diff --git a/chromium/cc/layers/heads_up_display_layer.h b/chromium/cc/layers/heads_up_display_layer.h
index 7ca09925102..ddc34f286d8 100644
--- a/chromium/cc/layers/heads_up_display_layer.h
+++ b/chromium/cc/layers/heads_up_display_layer.h
@@ -9,11 +9,11 @@
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
-#include "cc/layers/contents_scaling_layer.h"
+#include "cc/layers/layer.h"
namespace cc {
-class CC_EXPORT HeadsUpDisplayLayer : public ContentsScalingLayer {
+class CC_EXPORT HeadsUpDisplayLayer : public Layer {
public:
static scoped_refptr<HeadsUpDisplayLayer> Create();
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index bb685710387..986c332e406 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -7,9 +7,9 @@
#include <algorithm>
#include <vector>
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/debug/debug_colors.h"
#include "cc/debug/frame_rate_counter.h"
#include "cc/debug/paint_time_counter.h"
@@ -17,16 +17,16 @@
#include "cc/output/renderer.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/resources/memory_history.h"
+#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
#include "skia/ext/platform_canvas.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
-#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/hud_font.h"
namespace cc {
@@ -68,11 +68,16 @@ double HeadsUpDisplayLayerImpl::Graph::UpdateUpperBound() {
HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(LayerTreeImpl* tree_impl,
int id)
: LayerImpl(tree_impl, id),
- typeface_(skia::AdoptRef(
- SkTypeface::CreateFromName("monospace", SkTypeface::kBold))),
+ typeface_(gfx::GetHudTypeface()),
+ internal_contents_scale_(1.f),
fps_graph_(60.0, 80.0),
paint_time_graph_(16.0, 48.0),
- fade_step_(0) {}
+ fade_step_(0) {
+ if (!typeface_) {
+ typeface_ = skia::AdoptRef(
+ SkTypeface::CreateFromName("monospace", SkTypeface::kBold));
+ }
+}
HeadsUpDisplayLayerImpl::~HeadsUpDisplayLayerImpl() {}
@@ -94,8 +99,8 @@ void HeadsUpDisplayLayerImpl::AcquireResource(
scoped_ptr<ScopedResource> resource =
ScopedResource::Create(resource_provider);
- resource->Allocate(
- content_bounds(), ResourceProvider::TextureHintImmutable, RGBA_8888);
+ resource->Allocate(internal_content_bounds_,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
resources_.push_back(resource.Pass());
}
@@ -115,7 +120,7 @@ class ResourceSizeIsEqualTo {
void HeadsUpDisplayLayerImpl::ReleaseUnmatchedSizeResources(
ResourceProvider* resource_provider) {
ScopedPtrVector<ScopedResource>::iterator it_erase =
- resources_.partition(ResourceSizeIsEqualTo(content_bounds()));
+ resources_.partition(ResourceSizeIsEqualTo(internal_content_bounds_));
resources_.erase(it_erase, resources_.end());
}
@@ -124,6 +129,10 @@ bool HeadsUpDisplayLayerImpl::WillDraw(DrawMode draw_mode,
if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
return false;
+ internal_contents_scale_ = draw_properties().ideal_contents_scale;
+ internal_content_bounds_ =
+ gfx::ToCeiledSize(gfx::ScaleSize(bounds(), internal_contents_scale_));
+
ReleaseUnmatchedSizeResources(resource_provider);
AcquireResource(resource_provider);
return LayerImpl::WillDraw(draw_mode, resource_provider);
@@ -131,16 +140,15 @@ bool HeadsUpDisplayLayerImpl::WillDraw(DrawMode draw_mode,
void HeadsUpDisplayLayerImpl::AppendQuads(
RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
if (!resources_.back()->id())
return;
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
- PopulateSharedQuadState(shared_quad_state);
+ PopulateScaledSharedQuadState(shared_quad_state, internal_contents_scale_);
- gfx::Rect quad_rect(content_bounds());
+ gfx::Rect quad_rect(internal_content_bounds_);
gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
gfx::Rect visible_quad_rect(quad_rect);
bool premultiplied_alpha = true;
@@ -148,6 +156,7 @@ void HeadsUpDisplayLayerImpl::AppendQuads(
gfx::PointF uv_bottom_right(1.f, 1.f);
const float vertex_opacity[] = { 1.f, 1.f, 1.f, 1.f };
bool flipped = false;
+ bool nearest_neighbor = false;
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
quad->SetNew(shared_quad_state,
@@ -160,7 +169,9 @@ void HeadsUpDisplayLayerImpl::AppendQuads(
uv_bottom_right,
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
void HeadsUpDisplayLayerImpl::UpdateHudTexture(
@@ -170,50 +181,53 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
return;
SkISize canvas_size;
- if (hud_canvas_)
- canvas_size = hud_canvas_->getDeviceSize();
+ if (hud_surface_)
+ canvas_size = hud_surface_->getCanvas()->getDeviceSize();
else
canvas_size.set(0, 0);
- if (canvas_size.width() != content_bounds().width() ||
- canvas_size.height() != content_bounds().height() || !hud_canvas_) {
+ if (canvas_size.width() != internal_content_bounds_.width() ||
+ canvas_size.height() != internal_content_bounds_.height() ||
+ !hud_surface_) {
TRACE_EVENT0("cc", "ResizeHudCanvas");
- bool opaque = false;
- hud_canvas_ = make_scoped_ptr(skia::CreateBitmapCanvas(
- content_bounds().width(), content_bounds().height(), opaque));
+
+ hud_surface_ = skia::AdoptRef(SkSurface::NewRasterN32Premul(
+ internal_content_bounds_.width(), internal_content_bounds_.height()));
}
UpdateHudContents();
{
TRACE_EVENT0("cc", "DrawHudContents");
- hud_canvas_->clear(SkColorSetARGB(0, 0, 0, 0));
- hud_canvas_->save();
- hud_canvas_->scale(contents_scale_x(), contents_scale_y());
+ hud_surface_->getCanvas()->clear(SkColorSetARGB(0, 0, 0, 0));
+ hud_surface_->getCanvas()->save();
+ hud_surface_->getCanvas()->scale(internal_contents_scale_,
+ internal_contents_scale_);
- DrawHudContents(hud_canvas_.get());
+ DrawHudContents(hud_surface_->getCanvas());
- hud_canvas_->restore();
+ hud_surface_->getCanvas()->restore();
}
TRACE_EVENT0("cc", "UploadHudTexture");
SkImageInfo info;
size_t row_bytes = 0;
- const void* pixels = hud_canvas_->peekPixels(&info, &row_bytes);
+ const void* pixels = hud_surface_->getCanvas()->peekPixels(&info, &row_bytes);
DCHECK(pixels);
- gfx::Rect content_rect(content_bounds());
DCHECK(info.colorType() == kN32_SkColorType);
- resource_provider->SetPixels(resources_.back()->id(),
- static_cast<const uint8_t*>(pixels),
- content_rect,
- content_rect,
- gfx::Vector2d());
+ resource_provider->CopyToResource(resources_.back()->id(),
+ static_cast<const uint8_t*>(pixels),
+ internal_content_bounds_);
}
void HeadsUpDisplayLayerImpl::ReleaseResources() {
resources_.clear();
}
+gfx::Rect HeadsUpDisplayLayerImpl::GetEnclosingRectInTargetSpace() const {
+ return GetScaledEnclosingRectInTargetSpace(internal_contents_scale_);
+}
+
void HeadsUpDisplayLayerImpl::UpdateHudContents() {
const LayerTreeDebugState& debug_state = layer_tree_impl()->debug_state();
@@ -276,10 +290,26 @@ void HeadsUpDisplayLayerImpl::DrawHudContents(SkCanvas* canvas) {
DrawFPSDisplay(canvas, layer_tree_impl()->frame_rate_counter(), 0, 0);
}
+ if (debug_state.show_fps_counter || debug_state.continuous_painting) {
+ area = DrawGpuRasterizationStatus(canvas, 0, area.bottom(),
+ SkMaxScalar(area.width(), 150));
+ }
+
if (debug_state.ShowMemoryStats())
DrawMemoryDisplay(canvas, 0, area.bottom(), SkMaxScalar(area.width(), 150));
}
+int HeadsUpDisplayLayerImpl::MeasureText(SkPaint* paint,
+ const std::string& text,
+ int size) const {
+ const bool anti_alias = paint->isAntiAlias();
+ paint->setAntiAlias(true);
+ paint->setTextSize(size);
+ paint->setTypeface(typeface_.get());
+ SkScalar text_width = paint->measureText(text.c_str(), text.length());
+ paint->setAntiAlias(anti_alias);
+ return SkScalarCeilToInt(text_width);
+}
void HeadsUpDisplayLayerImpl::DrawText(SkCanvas* canvas,
SkPaint* paint,
const std::string& text,
@@ -529,37 +559,98 @@ SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(SkCanvas* canvas,
return area;
}
+SkRect HeadsUpDisplayLayerImpl::DrawGpuRasterizationStatus(SkCanvas* canvas,
+ int right,
+ int top,
+ int width) const {
+ std::string status;
+ SkColor color = SK_ColorRED;
+ switch (layer_tree_impl()->GetGpuRasterizationStatus()) {
+ case GpuRasterizationStatus::ON:
+ status = "on";
+ color = SK_ColorGREEN;
+ break;
+ case GpuRasterizationStatus::ON_FORCED:
+ status = "on (forced)";
+ color = SK_ColorGREEN;
+ break;
+ case GpuRasterizationStatus::OFF_DEVICE:
+ status = "off (device)";
+ color = SK_ColorRED;
+ break;
+ case GpuRasterizationStatus::OFF_VIEWPORT:
+ status = "off (viewport)";
+ color = SK_ColorYELLOW;
+ break;
+ case GpuRasterizationStatus::MSAA_CONTENT:
+ status = "MSAA (content)";
+ color = SK_ColorCYAN;
+ break;
+ case GpuRasterizationStatus::OFF_CONTENT:
+ status = "off (content)";
+ color = SK_ColorYELLOW;
+ break;
+ }
+
+ if (status.empty())
+ return SkRect::MakeEmpty();
+
+ const int kPadding = 4;
+ const int kFontHeight = 13;
+
+ const int height = 2 * kFontHeight + 3 * kPadding;
+ const int left = bounds().width() - width - right;
+ const SkRect area = SkRect::MakeXYWH(left, top, width, height);
+
+ SkPaint paint = CreatePaint();
+ DrawGraphBackground(canvas, &paint, area);
+
+ SkPoint gpu_status_pos = SkPoint::Make(left + width - kPadding,
+ top + 2 * kFontHeight + 2 * kPadding);
+
+ paint.setColor(color);
+ DrawText(canvas, &paint, "GPU raster: ", SkPaint::kLeft_Align, kFontHeight,
+ left + kPadding, top + kFontHeight + kPadding);
+ DrawText(canvas, &paint, status, SkPaint::kRight_Align, kFontHeight,
+ gpu_status_pos);
+
+ return area;
+}
+
SkRect HeadsUpDisplayLayerImpl::DrawPaintTimeDisplay(
SkCanvas* canvas,
const PaintTimeCounter* paint_time_counter,
int right,
int top) const {
const int kPadding = 4;
- const int kFontHeight = 15;
+ const int kFontHeight = 14;
const int kGraphWidth = paint_time_counter->HistorySize();
const int kGraphHeight = 40;
- const int width = kGraphWidth + 2 * kPadding;
+ SkPaint paint = CreatePaint();
+
+ const std::string title = "Compositor frame time (ms)";
+ int title_text_width = MeasureText(&paint, title, kFontHeight);
+ int contents_width = std::max(title_text_width, kGraphWidth);
+
+ const int width = contents_width + 2 * kPadding;
const int height =
kFontHeight + kGraphHeight + 4 * kPadding + 2 + kFontHeight + kPadding;
const int left = bounds().width() - width - right;
const SkRect area = SkRect::MakeXYWH(left, top, width, height);
- SkPaint paint = CreatePaint();
DrawGraphBackground(canvas, &paint, area);
- SkRect text_bounds = SkRect::MakeXYWH(
- left + kPadding, top + kPadding, kGraphWidth, kFontHeight);
- SkRect text_bounds2 = SkRect::MakeXYWH(left + kPadding,
- text_bounds.bottom() + kPadding,
- kGraphWidth,
- kFontHeight);
- SkRect graph_bounds = SkRect::MakeXYWH(left + kPadding,
+ SkRect text_bounds = SkRect::MakeXYWH(left + kPadding, top + kPadding,
+ contents_width, kFontHeight);
+ SkRect text_bounds2 =
+ SkRect::MakeXYWH(left + kPadding, text_bounds.bottom() + kPadding,
+ contents_width, kFontHeight);
+ SkRect graph_bounds = SkRect::MakeXYWH(left + (width - kGraphWidth) / 2,
text_bounds2.bottom() + 2 * kPadding,
- kGraphWidth,
- kGraphHeight);
+ kGraphWidth, kGraphHeight);
const std::string value_text =
base::StringPrintf("%.1f", paint_time_graph_.value);
@@ -567,8 +658,8 @@ SkRect HeadsUpDisplayLayerImpl::DrawPaintTimeDisplay(
"%.1f-%.1f", paint_time_graph_.min, paint_time_graph_.max);
paint.setColor(DebugColors::PaintTimeDisplayTextAndGraphColor());
- DrawText(canvas, &paint, "Compositor frame time (ms)", SkPaint::kLeft_Align,
- kFontHeight, text_bounds.left(), text_bounds.bottom());
+ DrawText(canvas, &paint, title, SkPaint::kLeft_Align, kFontHeight,
+ text_bounds.left(), text_bounds.bottom());
DrawText(canvas,
&paint,
value_text,
@@ -619,8 +710,9 @@ void HeadsUpDisplayLayerImpl::DrawDebugRect(
SkColor fill_color,
float stroke_width,
const std::string& label_text) const {
- gfx::Rect debug_layer_rect = gfx::ScaleToEnclosingRect(
- rect.rect, 1.0 / contents_scale_x(), 1.0 / contents_scale_y());
+ gfx::Rect debug_layer_rect =
+ gfx::ScaleToEnclosingRect(rect.rect, 1.0 / internal_contents_scale_,
+ 1.0 / internal_contents_scale_);
SkIRect sk_rect = RectToSkIRect(debug_layer_rect);
paint->setColor(fill_color);
paint->setStyle(SkPaint::kFill_Style);
@@ -638,7 +730,7 @@ void HeadsUpDisplayLayerImpl::DrawDebugRect(
// The debug_layer_rect may be huge, and converting to a floating point may
// be lossy, so intersect with the HUD layer bounds first to prevent that.
gfx::Rect clip_rect = debug_layer_rect;
- clip_rect.Intersect(gfx::Rect(content_bounds()));
+ clip_rect.Intersect(gfx::Rect(internal_content_bounds_));
SkRect sk_clip_rect = RectToSkRect(clip_rect);
canvas->save();
@@ -706,16 +798,6 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
fill_color = DebugColors::ScreenSpaceLayerRectFillColor();
stroke_width = DebugColors::ScreenSpaceLayerRectBorderWidth();
break;
- case OCCLUDING_RECT_TYPE:
- stroke_color = DebugColors::OccludingRectBorderColor();
- fill_color = DebugColors::OccludingRectFillColor();
- stroke_width = DebugColors::OccludingRectBorderWidth();
- break;
- case NONOCCLUDING_RECT_TYPE:
- stroke_color = DebugColors::NonOccludingRectBorderColor();
- fill_color = DebugColors::NonOccludingRectFillColor();
- stroke_width = DebugColors::NonOccludingRectBorderWidth();
- break;
case TOUCH_EVENT_HANDLER_RECT_TYPE:
stroke_color = DebugColors::TouchEventHandlerRectBorderColor();
fill_color = DebugColors::TouchEventHandlerRectFillColor();
@@ -780,7 +862,7 @@ const char* HeadsUpDisplayLayerImpl::LayerTypeAsString() const {
}
void HeadsUpDisplayLayerImpl::AsValueInto(
- base::debug::TracedValue* dict) const {
+ base::trace_event::TracedValue* dict) const {
LayerImpl::AsValueInto(dict);
dict->SetString("layer_name", "Heads Up Display Layer");
}
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h
index c826092faa7..299d91eb19d 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.h
+++ b/chromium/cc/layers/heads_up_display_layer_impl.h
@@ -39,13 +39,14 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
void UpdateHudTexture(DrawMode draw_mode,
ResourceProvider* resource_provider);
void ReleaseResources() override;
+ gfx::Rect GetEnclosingRectInTargetSpace() const override;
+
bool IsAnimatingHUDContents() const { return fade_step_ > 0; }
private:
@@ -71,11 +72,12 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
const char* LayerTypeAsString() const override;
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
void UpdateHudContents();
void DrawHudContents(SkCanvas* canvas);
+ int MeasureText(SkPaint* paint, const std::string& text, int size) const;
void DrawText(SkCanvas* canvas,
SkPaint* paint,
const std::string& text,
@@ -105,6 +107,10 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
int top,
int right,
int width) const;
+ SkRect DrawGpuRasterizationStatus(SkCanvas* canvas,
+ int right,
+ int top,
+ int width) const;
SkRect DrawPaintTimeDisplay(SkCanvas* canvas,
const PaintTimeCounter* paint_time_counter,
int top,
@@ -122,10 +128,13 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
void ReleaseUnmatchedSizeResources(ResourceProvider* resource_provider);
ScopedPtrVector<ScopedResource> resources_;
- scoped_ptr<SkCanvas> hud_canvas_;
+ skia::RefPtr<SkSurface> hud_surface_;
skia::RefPtr<SkTypeface> typeface_;
+ float internal_contents_scale_;
+ gfx::Size internal_content_bounds_;
+
Graph fps_graph_;
Graph paint_time_graph_;
MemoryHistory::Entry memory_entry_;
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 d342d4f7093..ab38fdd087d 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
@@ -20,7 +20,7 @@ void CheckDrawLayer(HeadsUpDisplayLayerImpl* layer,
AppendQuadsData data;
bool will_draw = layer->WillDraw(draw_mode, resource_provider);
if (will_draw)
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
layer->UpdateHudTexture(draw_mode, resource_provider);
if (will_draw)
layer->DidDraw(resource_provider);
@@ -32,12 +32,13 @@ void CheckDrawLayer(HeadsUpDisplayLayerImpl* layer,
TEST(HeadsUpDisplayLayerImplTest, ResourcelessSoftwareDrawAfterResourceLoss) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
host_impl.InitializeRenderer(FakeOutputSurface::Create3d());
scoped_ptr<HeadsUpDisplayLayerImpl> layer =
HeadsUpDisplayLayerImpl::Create(host_impl.pending_tree(), 1);
- layer->SetContentBounds(gfx::Size(100, 100));
+ layer->SetBounds(gfx::Size(100, 100));
+ layer->draw_properties().ideal_contents_scale = 1.f;
// Check regular hardware draw is ok.
CheckDrawLayer(
diff --git a/chromium/cc/layers/io_surface_layer_impl.cc b/chromium/cc/layers/io_surface_layer_impl.cc
index 8d221956c61..a7da986859d 100644
--- a/chromium/cc/layers/io_surface_layer_impl.cc
+++ b/chromium/cc/layers/io_surface_layer_impl.cc
@@ -5,15 +5,10 @@
#include "cc/layers/io_surface_layer_impl.h"
#include "base/strings/stringprintf.h"
-#include "cc/output/gl_renderer.h" // For the GLC() macro.
#include "cc/output/output_surface.h"
#include "cc/quads/io_surface_draw_quad.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/occlusion.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
namespace cc {
@@ -66,7 +61,6 @@ bool IOSurfaceLayerImpl::WillDraw(DrawMode draw_mode,
void IOSurfaceLayerImpl::AppendQuads(
RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
@@ -78,7 +72,8 @@ void IOSurfaceLayerImpl::AppendQuads(
gfx::Rect quad_rect(content_bounds());
gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
gfx::Rect visible_quad_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(quad_rect);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ quad_rect);
if (visible_quad_rect.IsEmpty())
return;
@@ -91,6 +86,7 @@ void IOSurfaceLayerImpl::AppendQuads(
io_surface_size_,
io_surface_resource_id_,
IOSurfaceDrawQuad::FLIPPED);
+ ValidateQuadResources(quad);
}
void IOSurfaceLayerImpl::ReleaseResources() {
diff --git a/chromium/cc/layers/io_surface_layer_impl.h b/chromium/cc/layers/io_surface_layer_impl.h
index 663bcef1d1b..8317760cd92 100644
--- a/chromium/cc/layers/io_surface_layer_impl.h
+++ b/chromium/cc/layers/io_surface_layer_impl.h
@@ -27,7 +27,6 @@ class CC_EXPORT IOSurfaceLayerImpl : public LayerImpl {
void PushPropertiesTo(LayerImpl* layer_tree_impl) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
bool WillDraw(DrawMode draw_mode,
diff --git a/chromium/cc/layers/io_surface_layer_impl_unittest.cc b/chromium/cc/layers/io_surface_layer_impl_unittest.cc
index c9efd749f4e..1c9256c2551 100644
--- a/chromium/cc/layers/io_surface_layer_impl_unittest.cc
+++ b/chromium/cc/layers/io_surface_layer_impl_unittest.cc
@@ -22,6 +22,10 @@ TEST(IOSurfaceLayerImplTest, Occlusion) {
io_surface_layer_impl->SetContentBounds(layer_size);
io_surface_layer_impl->SetDrawsContent(true);
+ io_surface_layer_impl->SetIOSurfaceProperties(1, gfx::Size(1, 1));
+ io_surface_layer_impl->WillDraw(DRAW_MODE_HARDWARE, impl.resource_provider());
+ io_surface_layer_impl->DidDraw(impl.resource_provider());
+
impl.CalcDrawProps(viewport_size);
{
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index 08f39b9a21d..5c2d6a8643d 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -7,17 +7,18 @@
#include <algorithm>
#include "base/atomic_sequence_num.h"
-#include "base/debug/trace_event.h"
#include "base/location.h"
#include "base/metrics/histogram.h"
#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "cc/animation/animation.h"
#include "cc/animation/animation_events.h"
#include "cc/animation/animation_registrar.h"
#include "cc/animation/keyframed_animation_curve.h"
#include "cc/animation/layer_animation_controller.h"
#include "cc/base/simple_enclosed_region.h"
+#include "cc/debug/frame_viewer_instrumentation.h"
#include "cc/layers/layer_client.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/scrollbar_layer_interface.h"
@@ -49,6 +50,13 @@ Layer::Layer()
layer_tree_host_(nullptr),
scroll_clip_layer_id_(INVALID_ID),
num_descendants_that_draw_content_(0),
+ transform_tree_index_(-1),
+ opacity_tree_index_(-1),
+ clip_tree_index_(-1),
+ property_tree_sequence_number_(-1),
+ num_layer_or_descendants_with_copy_request_(0),
+ num_layer_or_descendants_with_input_handler_(0),
+ should_flatten_transform_from_property_tree_(false),
should_scroll_on_main_thread_(false),
have_wheel_event_handlers_(false),
have_scroll_event_handlers_(false),
@@ -67,6 +75,8 @@ Layer::Layer()
draw_checkerboard_for_missing_tiles_(false),
force_render_surface_(false),
transform_is_invertible_(true),
+ has_render_surface_(false),
+ scroll_blocks_on_(SCROLL_BLOCKS_ON_NONE),
background_color_(0),
opacity_(1.f),
blend_mode_(SkXfermode::kSrcOver_Mode),
@@ -74,7 +84,8 @@ Layer::Layer()
clip_parent_(nullptr),
replica_layer_(nullptr),
raster_scale_(0.f),
- client_(nullptr) {
+ client_(nullptr),
+ frame_timing_requests_dirty_(false) {
layer_animation_controller_ = LayerAnimationController::Create(layer_id_);
layer_animation_controller_->AddValueObserver(this);
layer_animation_controller_->set_value_provider(this);
@@ -110,6 +121,9 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) {
if (layer_tree_host_ == host)
return;
+ if (layer_tree_host_)
+ layer_tree_host_->property_trees()->needs_rebuild = true;
+
layer_tree_host_ = host;
// When changing hosts, the layer needs to commit its properties to the impl
@@ -146,6 +160,19 @@ void Layer::SetNeedsCommit() {
return;
SetNeedsPushProperties();
+ layer_tree_host_->property_trees()->needs_rebuild = true;
+
+ if (ignore_set_needs_commit_)
+ return;
+
+ layer_tree_host_->SetNeedsCommit();
+}
+
+void Layer::SetNeedsCommitNoRebuild() {
+ if (!layer_tree_host_)
+ return;
+
+ SetNeedsPushProperties();
if (ignore_set_needs_commit_)
return;
@@ -230,6 +257,9 @@ void Layer::SetParent(Layer* layer) {
if (!layer_tree_host_)
return;
+
+ layer_tree_host_->property_trees()->needs_rebuild = true;
+
const LayerTreeSettings& settings = layer_tree_host_->settings();
if (!settings.layer_transforms_should_scale_layer_contents)
return;
@@ -327,9 +357,20 @@ void Layer::SetBounds(const gfx::Size& size) {
DCHECK(IsPropertyChangeAllowed());
if (bounds() == size)
return;
-
bounds_ = size;
- SetNeedsCommit();
+
+ if (!layer_tree_host_)
+ return;
+
+ if (ClipNode* clip_node = layer_tree_host_->property_trees()->clip_tree.Node(
+ clip_tree_index())) {
+ if (clip_node->owner_id == id()) {
+ clip_node->data.clip.set_size(size);
+ layer_tree_host_->property_trees()->clip_tree.set_needs_update(true);
+ }
+ }
+
+ SetNeedsCommitNoRebuild();
}
Layer* Layer::RootLayer() {
@@ -369,12 +410,34 @@ bool Layer::HasAncestor(const Layer* ancestor) const {
void Layer::RequestCopyOfOutput(
scoped_ptr<CopyOutputRequest> request) {
DCHECK(IsPropertyChangeAllowed());
+ int size = copy_requests_.size();
+ if (void* source = request->source()) {
+ auto it = std::find_if(
+ copy_requests_.begin(), copy_requests_.end(),
+ [source](const CopyOutputRequest* x) { return x->source() == source; });
+ if (it != copy_requests_.end())
+ copy_requests_.erase(it);
+ }
if (request->IsEmpty())
return;
copy_requests_.push_back(request.Pass());
+ if (size == 0) {
+ bool copy_request_added = true;
+ UpdateNumCopyRequestsForSubtree(copy_request_added);
+ }
SetNeedsCommit();
}
+void Layer::UpdateNumCopyRequestsForSubtree(bool add) {
+ int change = add ? 1 : -1;
+ for (Layer* layer = this; layer; layer = layer->parent()) {
+ layer->num_layer_or_descendants_with_copy_request_ += change;
+ layer->draw_properties().layer_or_descendant_has_copy_request =
+ (layer->num_layer_or_descendants_with_copy_request_ != 0);
+ DCHECK_GE(layer->num_layer_or_descendants_with_copy_request_, 0);
+ }
+}
+
void Layer::SetBackgroundColor(SkColor background_color) {
DCHECK(IsPropertyChangeAllowed());
if (background_color_ == background_color)
@@ -465,7 +528,7 @@ void Layer::SetFilters(const FilterOperations& filters) {
}
bool Layer::FilterIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Filter);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::FILTER);
}
void Layer::SetBackgroundFilters(const FilterOperations& filters) {
@@ -485,7 +548,7 @@ void Layer::SetOpacity(float opacity) {
}
bool Layer::OpacityIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Opacity);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::OPACITY);
}
bool Layer::OpacityCanAnimateOnImplThread() const {
@@ -562,6 +625,23 @@ void Layer::SetPosition(const gfx::PointF& position) {
if (position_ == position)
return;
position_ = position;
+
+ if (!layer_tree_host_)
+ return;
+
+ if (TransformNode* transform_node =
+ layer_tree_host_->property_trees()->transform_tree.Node(
+ transform_tree_index())) {
+ if (transform_node->owner_id == id()) {
+ transform_node->data.update_post_local_transform(position,
+ transform_origin());
+ transform_node->data.needs_local_transform_update = true;
+ layer_tree_host_->property_trees()->transform_tree.set_needs_update(true);
+ SetNeedsCommitNoRebuild();
+ return;
+ }
+ }
+
SetNeedsCommit();
}
@@ -573,12 +653,55 @@ bool Layer::IsContainerForFixedPositionLayers() const {
return is_container_for_fixed_position_layers_;
}
+bool Are2dAxisAligned(const gfx::Transform& a,
+ const gfx::Transform& b,
+ bool* is_invertible) {
+ if (a.IsScaleOrTranslation() && b.IsScaleOrTranslation()) {
+ *is_invertible = b.IsInvertible();
+ return true;
+ }
+
+ gfx::Transform inverse(gfx::Transform::kSkipInitialization);
+ *is_invertible = b.GetInverse(&inverse);
+
+ inverse *= a;
+ return inverse.Preserves2dAxisAlignment();
+}
+
void Layer::SetTransform(const gfx::Transform& transform) {
DCHECK(IsPropertyChangeAllowed());
if (transform_ == transform)
return;
+
+ if (layer_tree_host_) {
+ if (TransformNode* transform_node =
+ layer_tree_host_->property_trees()->transform_tree.Node(
+ transform_tree_index())) {
+ if (transform_node->owner_id == id()) {
+ // We need to trigger a rebuild if we could have affected 2d axis
+ // alignment. We'll check to see if transform and transform_ are axis
+ // align with respect to one another.
+ bool invertible = false;
+ bool preserves_2d_axis_alignment =
+ Are2dAxisAligned(transform_, transform, &invertible);
+ transform_node->data.local = transform;
+ transform_node->data.needs_local_transform_update = true;
+ layer_tree_host_->property_trees()->transform_tree.set_needs_update(
+ true);
+ if (preserves_2d_axis_alignment)
+ SetNeedsCommitNoRebuild();
+ else
+ SetNeedsCommit();
+ transform_ = transform;
+ transform_is_invertible_ = invertible;
+ return;
+ }
+ }
+ }
+
transform_ = transform;
transform_is_invertible_ = transform.IsInvertible();
+
SetNeedsCommit();
}
@@ -587,11 +710,33 @@ void Layer::SetTransformOrigin(const gfx::Point3F& transform_origin) {
if (transform_origin_ == transform_origin)
return;
transform_origin_ = transform_origin;
+
+ if (!layer_tree_host_)
+ return;
+
+ if (TransformNode* transform_node =
+ layer_tree_host_->property_trees()->transform_tree.Node(
+ transform_tree_index())) {
+ if (transform_node->owner_id == id()) {
+ transform_node->data.update_pre_local_transform(transform_origin);
+ transform_node->data.update_post_local_transform(position(),
+ transform_origin);
+ transform_node->data.needs_local_transform_update = true;
+ layer_tree_host_->property_trees()->transform_tree.set_needs_update(true);
+ SetNeedsCommitNoRebuild();
+ return;
+ }
+ }
+
SetNeedsCommit();
}
+bool Layer::AnimationsPreserveAxisAlignment() const {
+ return layer_animation_controller_->AnimationsPreserveAxisAlignment();
+}
+
bool Layer::TransformIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Transform);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::TRANSFORM);
}
void Layer::SetScrollParent(Layer* parent) {
@@ -638,6 +783,8 @@ void Layer::SetClipParent(Layer* ancestor) {
clip_parent_->AddClipChild(this);
SetNeedsCommit();
+ if (layer_tree_host_)
+ layer_tree_host_->SetNeedsMetaInfoRecomputation(true);
}
void Layer::AddClipChild(Layer* child) {
@@ -660,9 +807,38 @@ void Layer::SetScrollOffset(const gfx::ScrollOffset& scroll_offset) {
if (scroll_offset_ == scroll_offset)
return;
scroll_offset_ = scroll_offset;
+
+ if (!layer_tree_host_)
+ return;
+
+ if (TransformNode* transform_node =
+ layer_tree_host_->property_trees()->transform_tree.Node(
+ transform_tree_index())) {
+ if (transform_node->owner_id == id()) {
+ transform_node->data.scroll_offset =
+ gfx::ScrollOffsetToVector2dF(CurrentScrollOffset());
+ transform_node->data.needs_local_transform_update = true;
+ layer_tree_host_->property_trees()->transform_tree.set_needs_update(true);
+ SetNeedsCommitNoRebuild();
+ return;
+ }
+ }
+
+ SetNeedsCommit();
+}
+
+void Layer::SetScrollCompensationAdjustment(
+ const gfx::Vector2dF& scroll_compensation_adjustment) {
+ if (scroll_compensation_adjustment_ == scroll_compensation_adjustment)
+ return;
+ scroll_compensation_adjustment_ = scroll_compensation_adjustment;
SetNeedsCommit();
}
+gfx::Vector2dF Layer::ScrollCompensationAdjustment() const {
+ return scroll_compensation_adjustment_;
+}
+
void Layer::SetScrollOffsetFromImplSide(
const gfx::ScrollOffset& scroll_offset) {
DCHECK(IsPropertyChangeAllowed());
@@ -673,6 +849,23 @@ void Layer::SetScrollOffsetFromImplSide(
return;
scroll_offset_ = scroll_offset;
SetNeedsPushProperties();
+
+ bool needs_rebuild = true;
+ if (TransformNode* transform_node =
+ layer_tree_host_->property_trees()->transform_tree.Node(
+ transform_tree_index())) {
+ if (transform_node->owner_id == id()) {
+ transform_node->data.scroll_offset =
+ gfx::ScrollOffsetToVector2dF(CurrentScrollOffset());
+ transform_node->data.needs_local_transform_update = true;
+ layer_tree_host_->property_trees()->transform_tree.set_needs_update(true);
+ needs_rebuild = false;
+ }
+ }
+
+ if (needs_rebuild)
+ layer_tree_host_->property_trees()->needs_rebuild = true;
+
if (!did_scroll_callback_.is_null())
did_scroll_callback_.Run();
// The callback could potentially change the layer structure:
@@ -709,10 +902,24 @@ void Layer::SetHaveWheelEventHandlers(bool have_wheel_event_handlers) {
DCHECK(IsPropertyChangeAllowed());
if (have_wheel_event_handlers_ == have_wheel_event_handlers)
return;
+ if (touch_event_handler_region_.IsEmpty() && layer_tree_host_ &&
+ !layer_tree_host_->needs_meta_info_recomputation())
+ UpdateNumInputHandlersForSubtree(have_wheel_event_handlers);
+
have_wheel_event_handlers_ = have_wheel_event_handlers;
SetNeedsCommit();
}
+void Layer::UpdateNumInputHandlersForSubtree(bool add) {
+ int change = add ? 1 : -1;
+ for (Layer* layer = this; layer; layer = layer->parent()) {
+ layer->num_layer_or_descendants_with_input_handler_ += change;
+ layer->draw_properties().layer_or_descendant_has_input_handler =
+ (layer->num_layer_or_descendants_with_input_handler_ != 0);
+ DCHECK_GE(layer->num_layer_or_descendants_with_input_handler_, 0);
+ }
+}
+
void Layer::SetHaveScrollEventHandlers(bool have_scroll_event_handlers) {
DCHECK(IsPropertyChangeAllowed());
if (have_scroll_event_handlers_ == have_scroll_event_handlers)
@@ -733,10 +940,22 @@ void Layer::SetTouchEventHandlerRegion(const Region& region) {
DCHECK(IsPropertyChangeAllowed());
if (touch_event_handler_region_ == region)
return;
+ if (!have_wheel_event_handlers_ && layer_tree_host_ &&
+ !layer_tree_host_->needs_meta_info_recomputation())
+ UpdateNumInputHandlersForSubtree(!region.IsEmpty());
+
touch_event_handler_region_ = region;
SetNeedsCommit();
}
+void Layer::SetScrollBlocksOn(ScrollBlocksOn scroll_blocks_on) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (scroll_blocks_on_ == scroll_blocks_on)
+ return;
+ scroll_blocks_on_ = scroll_blocks_on;
+ SetNeedsCommit();
+}
+
void Layer::SetDrawCheckerboardForMissingTiles(bool checkerboard) {
DCHECK(IsPropertyChangeAllowed());
if (draw_checkerboard_for_missing_tiles_ == checkerboard)
@@ -769,6 +988,57 @@ void Layer::Set3dSortingContextId(int id) {
SetNeedsCommit();
}
+void Layer::SetTransformTreeIndex(int index) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (transform_tree_index_ == index)
+ return;
+ transform_tree_index_ = index;
+ SetNeedsPushProperties();
+}
+
+int Layer::transform_tree_index() const {
+ if (!layer_tree_host_ ||
+ layer_tree_host_->property_trees()->sequence_number !=
+ property_tree_sequence_number_) {
+ return -1;
+ }
+ return transform_tree_index_;
+}
+
+void Layer::SetClipTreeIndex(int index) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (clip_tree_index_ == index)
+ return;
+ clip_tree_index_ = index;
+ SetNeedsPushProperties();
+}
+
+int Layer::clip_tree_index() const {
+ if (!layer_tree_host_ ||
+ layer_tree_host_->property_trees()->sequence_number !=
+ property_tree_sequence_number_) {
+ return -1;
+ }
+ return clip_tree_index_;
+}
+
+void Layer::SetOpacityTreeIndex(int index) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (opacity_tree_index_ == index)
+ return;
+ opacity_tree_index_ = index;
+ SetNeedsPushProperties();
+}
+
+int Layer::opacity_tree_index() const {
+ if (!layer_tree_host_ ||
+ layer_tree_host_->property_trees()->sequence_number !=
+ property_tree_sequence_number_) {
+ return -1;
+ }
+ return opacity_tree_index_;
+}
+
void Layer::SetShouldFlattenTransform(bool should_flatten) {
DCHECK(IsPropertyChangeAllowed());
if (should_flatten_transform_ == should_flatten)
@@ -863,23 +1133,26 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetBackgroundColor(background_color_);
layer->SetBounds(use_paint_properties ? paint_properties_.bounds
: bounds_);
- layer->SetContentBounds(content_bounds());
- layer->SetContentsScale(contents_scale_x(), contents_scale_y());
-
- bool is_tracing;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(
- TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
- "devtools.timeline.layers"),
- &is_tracing);
- if (is_tracing)
+
+ // TODO(enne): This is needed because CDP does this. Once main thread CDP
+ // goes away, content scale / bounds can be removed.
+ if (layer_tree_host()->settings().impl_side_painting) {
+ layer->SetContentsScale(1.f, 1.f);
+ layer->SetContentBounds(bounds());
+ } else {
+ layer->SetContentBounds(content_bounds());
+ layer->SetContentsScale(contents_scale_x(), contents_scale_y());
+ }
+
+ if (frame_viewer_instrumentation::IsTracingLayerTreeSnapshots())
layer->SetDebugInfo(TakeDebugInfo());
layer->SetDoubleSided(double_sided_);
layer->SetDrawCheckerboardForMissingTiles(
draw_checkerboard_for_missing_tiles_);
- layer->SetForceRenderSurface(force_render_surface_);
layer->SetDrawsContent(DrawsContent());
layer->SetHideLayerAndSubtree(hide_layer_and_subtree_);
+ layer->SetHasRenderSurface(has_render_surface_ || layer->HasCopyRequest());
if (!layer->FilterIsAnimatingOnImplOnly() && !FilterIsAnimating())
layer->SetFilters(filters_);
DCHECK(!(FilterIsAnimating() && layer->FilterIsAnimatingOnImplOnly()));
@@ -890,6 +1163,7 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetHaveScrollEventHandlers(have_scroll_event_handlers_);
layer->SetNonFastScrollableRegion(non_fast_scrollable_region_);
layer->SetTouchEventHandlerRegion(touch_event_handler_region_);
+ layer->SetScrollBlocksOn(scroll_blocks_on_);
layer->SetContentsOpaque(contents_opaque_);
if (!layer->OpacityIsAnimatingOnImplOnly() && !OpacityIsAnimating())
layer->SetOpacity(opacity_);
@@ -901,12 +1175,18 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
IsContainerForFixedPositionLayers());
layer->SetPositionConstraint(position_constraint_);
layer->SetShouldFlattenTransform(should_flatten_transform_);
+ layer->set_should_flatten_transform_from_property_tree(
+ should_flatten_transform_from_property_tree_);
layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_);
if (!layer->TransformIsAnimatingOnImplOnly() && !TransformIsAnimating())
layer->SetTransformAndInvertibility(transform_, transform_is_invertible_);
DCHECK(!(TransformIsAnimating() && layer->TransformIsAnimatingOnImplOnly()));
layer->Set3dSortingContextId(sorting_context_id_);
layer->SetNumDescendantsThatDrawContent(num_descendants_that_draw_content_);
+ layer->SetTransformTreeIndex(transform_tree_index());
+ layer->SetOpacityTreeIndex(opacity_tree_index());
+ layer->SetClipTreeIndex(clip_tree_index());
+ layer->set_offset_to_transform_parent(offset_to_transform_parent_);
layer->SetScrollClipLayer(scroll_clip_layer_id_);
layer->set_user_scrollable_horizontal(user_scrollable_horizontal_);
@@ -957,19 +1237,18 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetClipChildren(nullptr);
}
- // Adjust the scroll delta to be just the scrolls that have happened since
- // the BeginMainFrame was sent. This happens for impl-side painting
- // in LayerImpl::ApplyScrollDeltasSinceBeginMainFrame in a separate tree walk.
- if (layer->layer_tree_impl()->settings().impl_side_painting) {
- layer->SetScrollOffset(scroll_offset_);
- } else {
- layer->SetScrollOffsetAndDelta(
- scroll_offset_,
- layer->ScrollDelta() - layer->sent_scroll_delta());
- layer->SetSentScrollDelta(gfx::Vector2dF());
- }
+ // When a scroll offset animation is interrupted the new scroll position on
+ // the pending tree will clobber any impl-side scrolling occuring on the
+ // active tree. To do so, avoid scrolling the pending tree along with it
+ // instead of trying to undo that scrolling later.
+ if (layer_animation_controller_->scroll_offset_animation_was_interrupted())
+ layer->PushScrollOffsetFromMainThreadAndClobberActiveValue(scroll_offset_);
+ else
+ layer->PushScrollOffsetFromMainThread(scroll_offset_);
+ layer->SetScrollCompensationAdjustment(ScrollCompensationAdjustment());
// Wrap the copy_requests_ in a PostTask to the main thread.
+ int size = copy_requests_.size();
ScopedPtrVector<CopyOutputRequest> main_thread_copy_requests;
for (ScopedPtrVector<CopyOutputRequest>::iterator it = copy_requests_.begin();
it != copy_requests_.end();
@@ -986,6 +1265,10 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
base::Passed(&original_request)));
main_thread_copy_requests.push_back(main_thread_request.Pass());
}
+ if (!copy_requests_.empty() && layer_tree_host_)
+ layer_tree_host_->property_trees()->needs_rebuild = true;
+ if (size != 0)
+ UpdateNumCopyRequestsForSubtree(false);
copy_requests_.clear();
layer->PassCopyRequests(&main_thread_copy_requests);
@@ -1001,6 +1284,11 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer_animation_controller_->PushAnimationUpdatesTo(
layer->layer_animation_controller());
+ if (frame_timing_requests_dirty_) {
+ layer->PassFrameTimingRequests(&frame_timing_requests_);
+ frame_timing_requests_dirty_ = false;
+ }
+
// Reset any state that should be cleared for the next update.
stacking_order_changed_ = false;
update_rect_ = gfx::Rect();
@@ -1010,7 +1298,8 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
}
scoped_ptr<LayerImpl> Layer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
- return LayerImpl::Create(tree_impl, layer_id_);
+ return LayerImpl::Create(tree_impl, layer_id_,
+ new LayerImpl::SyncedScrollOffset);
}
bool Layer::DrawsContent() const {
@@ -1073,30 +1362,39 @@ bool Layer::IsSuitableForGpuRasterization() const {
return true;
}
-scoped_refptr<base::debug::ConvertableToTraceFormat> Layer::TakeDebugInfo() {
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+Layer::TakeDebugInfo() {
if (client_)
return client_->TakeDebugInfo();
else
return nullptr;
}
+void Layer::SetHasRenderSurface(bool has_render_surface) {
+ if (has_render_surface_ == has_render_surface)
+ return;
+ has_render_surface_ = has_render_surface;
+ // We do not need SetNeedsCommit here, since this is only ever called
+ // during a commit, from CalculateDrawProperties.
+ SetNeedsPushProperties();
+}
+
void Layer::CreateRenderSurface() {
- DCHECK(!draw_properties_.render_surface);
- draw_properties_.render_surface = make_scoped_ptr(new RenderSurface(this));
- draw_properties_.render_target = this;
+ DCHECK(!render_surface_);
+ render_surface_ = make_scoped_ptr(new RenderSurface(this));
}
void Layer::ClearRenderSurface() {
- draw_properties_.render_surface = nullptr;
+ render_surface_ = nullptr;
}
void Layer::ClearRenderSurfaceLayerList() {
- if (draw_properties_.render_surface)
- draw_properties_.render_surface->layer_list().clear();
+ if (render_surface_)
+ render_surface_->ClearLayerLists();
}
gfx::ScrollOffset Layer::ScrollOffsetForAnimation() const {
- return TotalScrollOffset();
+ return CurrentScrollOffset();
}
// On<Property>Animated is called due to an ongoing accelerated animation.
@@ -1109,6 +1407,14 @@ void Layer::OnFilterAnimated(const FilterOperations& filters) {
void Layer::OnOpacityAnimated(float opacity) {
opacity_ = opacity;
+ if (layer_tree_host_) {
+ if (OpacityNode* node =
+ layer_tree_host_->property_trees()->opacity_tree.Node(
+ opacity_tree_index())) {
+ if (node->owner_id == id())
+ node->data = opacity;
+ }
+ }
}
void Layer::OnTransformAnimated(const gfx::Transform& transform) {
@@ -1116,6 +1422,19 @@ void Layer::OnTransformAnimated(const gfx::Transform& transform) {
return;
transform_ = transform;
transform_is_invertible_ = transform.IsInvertible();
+ if (layer_tree_host_) {
+ if (TransformNode* node =
+ layer_tree_host_->property_trees()->transform_tree.Node(
+ transform_tree_index())) {
+ if (node->owner_id == id()) {
+ node->data.local = transform;
+ node->data.needs_local_transform_update = true;
+ node->data.is_animated = true;
+ layer_tree_host_->property_trees()->transform_tree.set_needs_update(
+ true);
+ }
+ }
+ }
}
void Layer::OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset) {
@@ -1137,7 +1456,7 @@ bool Layer::AddAnimation(scoped_ptr <Animation> animation) {
if (!layer_animation_controller_->animation_registrar())
return false;
- if (animation->target_property() == Animation::ScrollOffset &&
+ if (animation->target_property() == Animation::SCROLL_OFFSET &&
!layer_animation_controller_->animation_registrar()
->supports_scroll_animations())
return false;
@@ -1160,6 +1479,12 @@ void Layer::RemoveAnimation(int animation_id) {
SetNeedsCommit();
}
+void Layer::RemoveAnimation(int animation_id,
+ Animation::TargetProperty property) {
+ layer_animation_controller_->RemoveAnimation(animation_id, property);
+ SetNeedsCommit();
+}
+
void Layer::SetLayerAnimationControllerForTest(
scoped_refptr<LayerAnimationController> controller) {
layer_animation_controller_->RemoveValueObserver(this);
@@ -1196,10 +1521,6 @@ RenderingStatsInstrumentation* Layer::rendering_stats_instrumentation() const {
return layer_tree_host_->rendering_stats_instrumentation();
}
-bool Layer::SupportsLCDText() const {
- return false;
-}
-
void Layer::RemoveFromScrollTree() {
if (scroll_children_.get()) {
std::set<Layer*> copy = *scroll_children_;
@@ -1241,4 +1562,19 @@ bool Layer::HasDelegatedContent() const {
return false;
}
+void Layer::SetFrameTimingRequests(
+ const std::vector<FrameTimingRequest>& requests) {
+ frame_timing_requests_ = requests;
+ frame_timing_requests_dirty_ = true;
+ SetNeedsCommit();
+}
+
+void Layer::DidBeginTracing() {
+ // We'll be dumping layer trees as part of trace, so make sure
+ // PushPropertiesTo() propagates layer debug info to the impl
+ // side -- otherwise this won't happen for the the layers that
+ // remain unchanged since tracing started.
+ SetNeedsPushProperties();
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index f37218642e1..9c7138e9fdc 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -7,6 +7,7 @@
#include <set>
#include <string>
+#include <vector>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
@@ -17,13 +18,16 @@
#include "cc/base/cc_export.h"
#include "cc/base/region.h"
#include "cc/base/scoped_ptr_vector.h"
+#include "cc/debug/frame_timing_request.h"
#include "cc/debug/micro_benchmark.h"
#include "cc/layers/draw_properties.h"
#include "cc/layers/layer_lists.h"
#include "cc/layers/layer_position_constraint.h"
#include "cc/layers/paint_properties.h"
#include "cc/layers/render_surface.h"
+#include "cc/layers/scroll_blocks_on.h"
#include "cc/output/filter_operations.h"
+#include "cc/trees/property_tree.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
@@ -40,7 +44,7 @@ class BoxF;
}
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
}
}
@@ -51,11 +55,11 @@ class Animation;
class AnimationDelegate;
struct AnimationEvent;
class CopyOutputRequest;
-class LayerAnimationDelegate;
class LayerAnimationEventObserver;
class LayerClient;
class LayerImpl;
class LayerTreeHost;
+class LayerTreeHostCommon;
class LayerTreeImpl;
class PriorityCalculator;
class RenderingStatsInstrumentation;
@@ -100,7 +104,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// This requests the layer and its subtree be rendered and given to the
// callback. If the copy is unable to be produced (the layer is destroyed
- // first), then the callback is called with a nullptr/empty result.
+ // first), then the callback is called with a nullptr/empty result. If the
+ // request's source property is set, any prior uncommitted requests having the
+ // same source will be aborted.
void RequestCopyOfOutput(scoped_ptr<CopyOutputRequest> request);
bool HasCopyRequest() const {
return !copy_requests_.empty();
@@ -169,6 +175,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void SetIsContainerForFixedPositionLayers(bool container);
bool IsContainerForFixedPositionLayers() const;
+ gfx::Vector2dF FixedContainerSizeDelta() const {
+ return gfx::Vector2dF();
+ }
+
void SetPositionConstraint(const LayerPositionConstraint& constraint);
const LayerPositionConstraint& position_constraint() const {
return position_constraint_;
@@ -177,10 +187,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void SetTransform(const gfx::Transform& transform);
const gfx::Transform& transform() const { return transform_; }
bool TransformIsAnimating() const;
+ bool AnimationsPreserveAxisAlignment() const;
bool transform_is_invertible() const { return transform_is_invertible_; }
void SetTransformOrigin(const gfx::Point3F&);
- gfx::Point3F transform_origin() { return transform_origin_; }
+ gfx::Point3F transform_origin() const { return transform_origin_; }
void SetScrollParent(Layer* parent);
@@ -236,7 +247,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
bool screen_space_opacity_is_animating() const {
return draw_properties_.screen_space_opacity_is_animating;
}
- bool can_use_lcd_text() const { return draw_properties_.can_use_lcd_text; }
bool is_clipped() const { return draw_properties_.is_clipped; }
gfx::Rect clip_rect() const { return draw_properties_.clip_rect; }
gfx::Rect drawable_content_rect() const {
@@ -255,14 +265,16 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
draw_properties_.render_target->render_surface());
return draw_properties_.render_target;
}
- RenderSurface* render_surface() const {
- return draw_properties_.render_surface.get();
- }
int num_unclipped_descendants() const {
return draw_properties_.num_unclipped_descendants;
}
+ RenderSurface* render_surface() const { return render_surface_.get(); }
void SetScrollOffset(const gfx::ScrollOffset& scroll_offset);
+ void SetScrollCompensationAdjustment(
+ const gfx::Vector2dF& scroll_compensation_adjustment);
+ gfx::Vector2dF ScrollCompensationAdjustment() const;
+
gfx::ScrollOffset scroll_offset() const { return scroll_offset_; }
void SetScrollOffsetFromImplSide(const gfx::ScrollOffset& scroll_offset);
@@ -298,6 +310,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
return touch_event_handler_region_;
}
+ void SetScrollBlocksOn(ScrollBlocksOn scroll_blocks_on);
+ ScrollBlocksOn scroll_blocks_on() const { return scroll_blocks_on_; }
+
void set_did_scroll_callback(const base::Closure& callback) {
did_scroll_callback_ = callback;
}
@@ -311,9 +326,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
bool force_render_surface() const { return force_render_surface_; }
gfx::Vector2dF ScrollDelta() const { return gfx::Vector2dF(); }
- gfx::ScrollOffset TotalScrollOffset() const {
- return ScrollOffsetWithDelta(scroll_offset(), ScrollDelta());
- }
+ gfx::ScrollOffset CurrentScrollOffset() const { return scroll_offset_; }
void SetDoubleSided(bool double_sided);
bool double_sided() const { return double_sided_; }
@@ -368,7 +381,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
virtual void OnOutputSurfaceCreated() {}
virtual bool IsSuitableForGpuRasterization() const;
- virtual scoped_refptr<base::debug::ConvertableToTraceFormat> TakeDebugInfo();
+ virtual scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ TakeDebugInfo();
void SetLayerClient(LayerClient* client) { client_ = client; }
@@ -376,6 +390,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void CreateRenderSurface();
void ClearRenderSurface();
+
void ClearRenderSurfaceLayerList();
// The contents scale converts from logical, non-page-scaled pixels to target
@@ -400,6 +415,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
bool AddAnimation(scoped_ptr<Animation> animation);
void PauseAnimation(int animation_id, double time_offset);
void RemoveAnimation(int animation_id);
+ void RemoveAnimation(int animation_id, Animation::TargetProperty property);
LayerAnimationController* layer_animation_controller() {
return layer_animation_controller_.get();
@@ -446,8 +462,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
float raster_scale() const { return raster_scale_; }
bool raster_scale_is_unknown() const { return raster_scale_ == 0.f; }
- virtual bool SupportsLCDText() const;
-
void SetNeedsPushProperties();
bool needs_push_properties() const { return needs_push_properties_; }
bool descendant_needs_push_properties() const {
@@ -462,6 +476,89 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void Set3dSortingContextId(int id);
int sorting_context_id() const { return sorting_context_id_; }
+ void set_property_tree_sequence_number(int sequence_number) {
+ property_tree_sequence_number_ = sequence_number;
+ }
+
+ void SetTransformTreeIndex(int index);
+ int transform_tree_index() const;
+
+ void SetClipTreeIndex(int index);
+ int clip_tree_index() const;
+
+ void SetOpacityTreeIndex(int index);
+ int opacity_tree_index() const;
+
+ void set_offset_to_transform_parent(gfx::Vector2dF offset) {
+ if (offset_to_transform_parent_ == offset)
+ return;
+ offset_to_transform_parent_ = offset;
+ SetNeedsPushProperties();
+ }
+ gfx::Vector2dF offset_to_transform_parent() const {
+ return offset_to_transform_parent_;
+ }
+
+ // TODO(vollick): Once we transition to transform and clip trees, rename these
+ // functions and related values. The "from property trees" functions below
+ // use the transform and clip trees. Eventually, we will use these functions
+ // to compute the official values, but these functions are retained for
+ // testing purposes until we've migrated.
+
+ const gfx::Rect& visible_rect_from_property_trees() const {
+ return visible_rect_from_property_trees_;
+ }
+ void set_visible_rect_from_property_trees(const gfx::Rect& rect) {
+ // No push properties here, as this acts like a draw property.
+ visible_rect_from_property_trees_ = rect;
+ }
+
+ void set_should_flatten_transform_from_property_tree(bool should_flatten) {
+ if (should_flatten_transform_from_property_tree_ == should_flatten)
+ return;
+ should_flatten_transform_from_property_tree_ = should_flatten;
+ SetNeedsPushProperties();
+ }
+ bool should_flatten_transform_from_property_tree() const {
+ return should_flatten_transform_from_property_tree_;
+ }
+
+ // TODO(vollick): These values are temporary and will be removed as soon as
+ // render surface determinations are moved out of CDP. They only exist because
+ // certain logic depends on whether or not a layer would render to a separate
+ // surface, but CDP destroys surfaces and targets it doesn't need, so without
+ // this boolean, this is impossible to determine after the fact without
+ // wastefully recomputing it. This is public for the time being so that it can
+ // be accessed from CDP.
+ bool has_render_surface() const {
+ return has_render_surface_;
+ }
+
+ // Sets new frame timing requests for this layer.
+ void SetFrameTimingRequests(const std::vector<FrameTimingRequest>& requests);
+
+ // Accessor for unit tests
+ const std::vector<FrameTimingRequest>& FrameTimingRequests() const {
+ return frame_timing_requests_;
+ }
+
+ void DidBeginTracing();
+ void set_num_layer_or_descandant_with_copy_request(
+ int num_layer_or_descendants_with_copy_request) {
+ num_layer_or_descendants_with_copy_request_ =
+ num_layer_or_descendants_with_copy_request;
+ }
+
+ void set_num_layer_or_descandant_with_input_handler(
+ int num_layer_or_descendants_with_input_handler) {
+ num_layer_or_descendants_with_input_handler_ =
+ num_layer_or_descendants_with_input_handler;
+ }
+
+ int num_layer_or_descendants_with_input_handler() {
+ return num_layer_or_descendants_with_input_handler_;
+ }
+
protected:
friend class LayerImpl;
friend class TreeSynchronizer;
@@ -479,6 +576,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// knows immediately that a commit is required. This implies SetNeedsUpdate
// as well as SetNeedsPushProperties to push that property.
void SetNeedsCommit();
+ // This is identical to SetNeedsCommit, but the former requests a rebuild of
+ // the property trees.
+ void SetNeedsCommitNoRebuild();
// Called when there's been a change in layer structure. Implies both
// SetNeedsUpdate and SetNeedsCommit, but not SetNeedsPushProperties.
void SetNeedsFullTreeSync();
@@ -541,10 +641,14 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
private:
friend class base::RefCounted<Layer>;
-
+ friend class LayerTreeHostCommon;
void SetParent(Layer* layer);
bool DescendantIsFixedToContainerLayer() const;
+ // This should only be called during BeginMainFrame since it does not
+ // trigger a Commit.
+ void SetHasRenderSurface(bool has_render_surface);
+
// Returns the index of the child or -1 if not found.
int IndexOfChild(const Layer* reference);
@@ -570,6 +674,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// children.
void RemoveFromClipTree();
+ void UpdateNumCopyRequestsForSubtree(bool add);
+ void UpdateNumInputHandlersForSubtree(bool add);
+
LayerList children_;
Layer* parent_;
@@ -584,11 +691,20 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
gfx::Size bounds_;
gfx::ScrollOffset scroll_offset_;
+ gfx::Vector2dF scroll_compensation_adjustment_;
// This variable indicates which ancestor layer (if any) whose size,
// transformed relative to this layer, defines the maximum scroll offset for
// this layer.
int scroll_clip_layer_id_;
int num_descendants_that_draw_content_;
+ int transform_tree_index_;
+ int opacity_tree_index_;
+ int clip_tree_index_;
+ int property_tree_sequence_number_;
+ int num_layer_or_descendants_with_copy_request_;
+ int num_layer_or_descendants_with_input_handler_;
+ gfx::Vector2dF offset_to_transform_parent_;
+ bool should_flatten_transform_from_property_tree_ : 1;
bool should_scroll_on_main_thread_ : 1;
bool have_wheel_event_handlers_ : 1;
bool have_scroll_event_handlers_ : 1;
@@ -607,6 +723,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
bool draw_checkerboard_for_missing_tiles_ : 1;
bool force_render_surface_ : 1;
bool transform_is_invertible_ : 1;
+ bool has_render_surface_ : 1;
+ ScrollBlocksOn scroll_blocks_on_ : 3;
Region non_fast_scrollable_region_;
Region touch_event_handler_region_;
gfx::PointF position_;
@@ -640,6 +758,14 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
DrawProperties<Layer> draw_properties_;
PaintProperties paint_properties_;
+ // TODO(awoloszyn): This is redundant with has_render_surface_,
+ // and should get removed once it is no longer needed on main thread.
+ scoped_ptr<RenderSurface> render_surface_;
+
+ gfx::Rect visible_rect_from_property_trees_;
+
+ std::vector<FrameTimingRequest> frame_timing_requests_;
+ bool frame_timing_requests_dirty_;
DISALLOW_COPY_AND_ASSIGN(Layer);
};
diff --git a/chromium/cc/layers/layer_client.h b/chromium/cc/layers/layer_client.h
index 4b98a959dca..bcdf1c3c77d 100644
--- a/chromium/cc/layers/layer_client.h
+++ b/chromium/cc/layers/layer_client.h
@@ -11,7 +11,7 @@
#include "cc/base/cc_export.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
}
}
@@ -24,7 +24,7 @@ class CC_EXPORT LayerClient {
// If not, returns nullptr.
// If the returned pointer is non-nullptr, the caller takes
// ownership of the pointer.
- virtual scoped_refptr<base::debug::ConvertableToTraceFormat>
+ virtual scoped_refptr<base::trace_event::ConvertableToTraceFormat>
TakeDebugInfo() = 0;
protected:
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index f09761bc9b7..8b3467a9128 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -4,10 +4,10 @@
#include "cc/layers/layer_impl.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/json/json_reader.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/animation/animation_registrar.h"
#include "cc/animation/scrollbar_animation_controller.h"
#include "cc/base/math_util.h"
@@ -16,7 +16,6 @@
#include "cc/debug/layer_tree_debug_state.h"
#include "cc/debug/micro_benchmark_impl.h"
#include "cc/debug/traced_value.h"
-#include "cc/input/layer_scroll_offset_delegate.h"
#include "cc/layers/layer_utils.h"
#include "cc/layers/painted_scrollbar_layer_impl.h"
#include "cc/output/copy_output_request.h"
@@ -34,7 +33,13 @@
#include "ui/gfx/geometry/vector2d_conversions.h"
namespace cc {
-LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
+LayerImpl::LayerImpl(LayerTreeImpl* layer_impl, int id)
+ : LayerImpl(layer_impl, id, new LayerImpl::SyncedScrollOffset) {
+}
+
+LayerImpl::LayerImpl(LayerTreeImpl* tree_impl,
+ int id,
+ scoped_refptr<SyncedScrollOffset> scroll_offset)
: parent_(nullptr),
scroll_parent_(nullptr),
clip_parent_(nullptr),
@@ -42,16 +47,18 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
replica_layer_id_(-1),
layer_id_(id),
layer_tree_impl_(tree_impl),
- scroll_offset_delegate_(nullptr),
+ scroll_offset_(scroll_offset),
scroll_clip_layer_(nullptr),
should_scroll_on_main_thread_(false),
have_wheel_event_handlers_(false),
have_scroll_event_handlers_(false),
+ scroll_blocks_on_(SCROLL_BLOCKS_ON_NONE),
user_scrollable_horizontal_(true),
user_scrollable_vertical_(true),
stacking_order_changed_(false),
double_sided_(true),
should_flatten_transform_(true),
+ should_flatten_transform_from_property_tree_(false),
layer_property_changed_(false),
masks_to_bounds_(false),
contents_opaque_(false),
@@ -60,22 +67,25 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
draw_checkerboard_for_missing_tiles_(false),
draws_content_(false),
hide_layer_and_subtree_(false),
- force_render_surface_(false),
transform_is_invertible_(true),
is_container_for_fixed_position_layers_(false),
background_color_(0),
opacity_(1.0),
blend_mode_(SkXfermode::kSrcOver_Mode),
num_descendants_that_draw_content_(0),
+ transform_tree_index_(-1),
+ opacity_tree_index_(-1),
+ clip_tree_index_(-1),
draw_depth_(0.f),
needs_push_properties_(false),
num_dependents_need_push_properties_(0),
sorting_context_id_(0),
- current_draw_mode_(DRAW_MODE_NONE) {
+ current_draw_mode_(DRAW_MODE_NONE),
+ frame_timing_requests_dirty_(false) {
DCHECK_GT(layer_id_, 0);
DCHECK(layer_tree_impl_);
layer_tree_impl_->RegisterLayer(this);
- AnimationRegistrar* registrar = layer_tree_impl_->animationRegistrar();
+ AnimationRegistrar* registrar = layer_tree_impl_->GetAnimationRegistrar();
layer_animation_controller_ =
registrar->GetAnimationControllerForId(layer_id_);
layer_animation_controller_->AddValueObserver(this);
@@ -156,9 +166,6 @@ void LayerImpl::SetScrollParent(LayerImpl* parent) {
if (scroll_parent_ == parent)
return;
- // Having both a scroll parent and a scroll offset delegate is unsupported.
- DCHECK(!scroll_offset_delegate_);
-
if (parent)
DCHECK_EQ(layer_tree_impl()->LayerById(parent->id()), parent);
@@ -167,7 +174,7 @@ void LayerImpl::SetScrollParent(LayerImpl* parent) {
}
void LayerImpl::SetDebugInfo(
- scoped_refptr<base::debug::ConvertableToTraceFormat> other) {
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> other) {
debug_info_ = other;
SetNeedsPushProperties();
}
@@ -201,10 +208,25 @@ void LayerImpl::SetClipChildren(std::set<LayerImpl*>* children) {
SetNeedsPushProperties();
}
+void LayerImpl::SetTransformTreeIndex(int index) {
+ transform_tree_index_ = index;
+ SetNeedsPushProperties();
+}
+
+void LayerImpl::SetClipTreeIndex(int index) {
+ clip_tree_index_ = index;
+ SetNeedsPushProperties();
+}
+
+void LayerImpl::SetOpacityTreeIndex(int index) {
+ opacity_tree_index_ = index;
+ SetNeedsPushProperties();
+}
+
void LayerImpl::PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests) {
if (requests->empty())
return;
-
+ DCHECK(render_surface());
bool was_empty = copy_requests_.empty();
copy_requests_.insert_and_take(copy_requests_.end(), requests);
requests->clear();
@@ -218,6 +240,7 @@ void LayerImpl::TakeCopyRequestsAndTransformToTarget(
ScopedPtrVector<CopyOutputRequest>* requests) {
DCHECK(!copy_requests_.empty());
DCHECK(layer_tree_impl()->IsActiveTree());
+ DCHECK_EQ(render_target(), this);
size_t first_inserted_request = requests->size();
requests->insert_and_take(requests->end(), &copy_requests_);
@@ -236,33 +259,37 @@ void LayerImpl::TakeCopyRequestsAndTransformToTarget(
}
layer_tree_impl()->RemoveLayerWithCopyOutputRequest(this);
-}
-
-void LayerImpl::CreateRenderSurface() {
- DCHECK(!draw_properties_.render_surface);
- draw_properties_.render_surface =
- make_scoped_ptr(new RenderSurfaceImpl(this));
- draw_properties_.render_target = this;
-}
-
-void LayerImpl::ClearRenderSurface() {
- draw_properties_.render_surface = nullptr;
+ layer_tree_impl()->set_needs_update_draw_properties();
}
void LayerImpl::ClearRenderSurfaceLayerList() {
- if (draw_properties_.render_surface)
- draw_properties_.render_surface->layer_list().clear();
+ if (render_surface_)
+ render_surface_->ClearLayerLists();
}
void LayerImpl::PopulateSharedQuadState(SharedQuadState* state) const {
- state->SetAll(draw_properties_.target_space_transform,
- draw_properties_.content_bounds,
- draw_properties_.visible_content_rect,
- draw_properties_.clip_rect,
- draw_properties_.is_clipped,
- draw_properties_.opacity,
- blend_mode_,
- sorting_context_id_);
+ state->SetAll(
+ draw_properties_.target_space_transform, draw_properties_.content_bounds,
+ draw_properties_.visible_content_rect, draw_properties_.clip_rect,
+ draw_properties_.is_clipped, draw_properties_.opacity,
+ draw_properties_.blend_mode, sorting_context_id_);
+}
+
+void LayerImpl::PopulateScaledSharedQuadState(SharedQuadState* state,
+ float scale) const {
+ gfx::Transform scaled_draw_transform =
+ draw_properties_.target_space_transform;
+ scaled_draw_transform.Scale(SK_MScalar1 / scale, SK_MScalar1 / scale);
+ gfx::Size scaled_content_bounds =
+ gfx::ToCeiledSize(gfx::ScaleSize(bounds(), scale));
+ gfx::Rect scaled_visible_content_rect =
+ gfx::ScaleToEnclosingRect(visible_content_rect(), scale);
+ scaled_visible_content_rect.Intersect(gfx::Rect(scaled_content_bounds));
+
+ state->SetAll(scaled_draw_transform, scaled_content_bounds,
+ scaled_visible_content_rect, draw_properties().clip_rect,
+ draw_properties().is_clipped, draw_properties().opacity,
+ draw_properties().blend_mode, sorting_context_id_);
}
bool LayerImpl::WillDraw(DrawMode draw_mode,
@@ -331,6 +358,24 @@ void LayerImpl::AppendDebugBorderQuad(RenderPass* render_pass,
render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
debug_border_quad->SetNew(
shared_quad_state, quad_rect, visible_quad_rect, color, width);
+ if (contents_opaque()) {
+ // When opaque, draw a second inner border that is thicker than the outer
+ // border, but more transparent.
+ static const float kFillOpacity = 0.3f;
+ SkColor fill_color = SkColorSetA(
+ color, static_cast<uint8_t>(SkColorGetA(color) * kFillOpacity));
+ float fill_width = width * 3;
+ gfx::Rect fill_rect = quad_rect;
+ fill_rect.Inset(fill_width / 2.f, fill_width / 2.f);
+ if (fill_rect.IsEmpty())
+ return;
+ gfx::Rect visible_fill_rect =
+ gfx::IntersectRects(visible_quad_rect, fill_rect);
+ DebugBorderDrawQuad* fill_quad =
+ render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
+ fill_quad->SetNew(shared_quad_state, fill_rect, visible_fill_rect,
+ fill_color, fill_width);
+ }
}
bool LayerImpl::HasDelegatedContent() const {
@@ -355,18 +400,8 @@ void LayerImpl::GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
*resource_id = 0;
}
-void LayerImpl::SetSentScrollDelta(const gfx::Vector2dF& sent_scroll_delta) {
- // Pending tree never has sent scroll deltas
- DCHECK(layer_tree_impl()->IsActiveTree());
-
- if (sent_scroll_delta_ == sent_scroll_delta)
- return;
-
- sent_scroll_delta_ = sent_scroll_delta;
-}
-
gfx::Vector2dF LayerImpl::ScrollBy(const gfx::Vector2dF& scroll) {
- gfx::Vector2dF adjusted_scroll = scroll;
+ gfx::ScrollOffset adjusted_scroll(scroll);
if (layer_tree_impl()->settings().use_pinch_virtual_viewport) {
if (!user_scrollable_horizontal_)
adjusted_scroll.set_x(0);
@@ -374,17 +409,14 @@ gfx::Vector2dF LayerImpl::ScrollBy(const gfx::Vector2dF& scroll) {
adjusted_scroll.set_y(0);
}
DCHECK(scrollable());
- gfx::Vector2dF min_delta = -ScrollOffsetToVector2dF(scroll_offset_);
- gfx::Vector2dF max_delta = MaxScrollOffset().DeltaFrom(scroll_offset_);
- // Clamp new_delta so that position + delta stays within scroll bounds.
- gfx::Vector2dF new_delta = (ScrollDelta() + adjusted_scroll);
- new_delta.SetToMax(min_delta);
- new_delta.SetToMin(max_delta);
- gfx::Vector2dF unscrolled =
- ScrollDelta() + scroll - new_delta;
- SetScrollDelta(new_delta);
+ gfx::ScrollOffset old_offset = CurrentScrollOffset();
+ gfx::ScrollOffset new_offset =
+ ClampScrollOffsetToLimits(old_offset + adjusted_scroll);
+ SetCurrentScrollOffset(new_offset);
- return unscrolled;
+ gfx::ScrollOffset unscrolled =
+ old_offset + gfx::ScrollOffset(scroll) - new_offset;
+ return gfx::Vector2dF(unscrolled.x(), unscrolled.y());
}
void LayerImpl::SetScrollClipLayer(int scroll_clip_layer_id) {
@@ -397,54 +429,22 @@ bool LayerImpl::user_scrollable(ScrollbarOrientation orientation) const {
}
void LayerImpl::ApplySentScrollDeltasFromAbortedCommit() {
- if (sent_scroll_delta_.IsZero())
- return;
-
- // Pending tree never has sent scroll deltas
DCHECK(layer_tree_impl()->IsActiveTree());
-
- // The combination of pending tree and aborted commits with impl scrolls
- // shouldn't happen; we don't know how to update its deltas correctly.
- DCHECK(!layer_tree_impl()->FindPendingTreeLayerById(id()));
-
- // Apply sent scroll deltas to scroll position / scroll delta as if the
- // main thread had applied them and then committed those values.
- SetScrollOffsetAndDelta(
- scroll_offset_ + gfx::ScrollOffset(sent_scroll_delta_),
- ScrollDelta() - sent_scroll_delta_);
- SetSentScrollDelta(gfx::Vector2dF());
-}
-
-void LayerImpl::ApplyScrollDeltasSinceBeginMainFrame() {
- // Only the pending tree can have missing scrolls.
- DCHECK(layer_tree_impl()->IsPendingTree());
- if (!scrollable())
- return;
-
- // Pending tree should never have sent scroll deltas.
- DCHECK(sent_scroll_delta().IsZero());
-
- LayerImpl* active_twin = layer_tree_impl()->FindActiveTreeLayerById(id());
- if (active_twin) {
- // Scrolls that happens after begin frame (where the sent scroll delta
- // comes from) and commit need to be applied to the pending tree
- // so that it is up to date with the total scroll.
- SetScrollDelta(active_twin->ScrollDelta() -
- active_twin->sent_scroll_delta());
- }
+ scroll_offset_->AbortCommit();
}
InputHandler::ScrollStatus LayerImpl::TryScroll(
const gfx::PointF& screen_space_point,
- InputHandler::ScrollInputType type) const {
+ InputHandler::ScrollInputType type,
+ ScrollBlocksOn effective_block_mode) const {
if (should_scroll_on_main_thread()) {
TRACE_EVENT0("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread");
- return InputHandler::ScrollOnMainThread;
+ return InputHandler::SCROLL_ON_MAIN_THREAD;
}
if (!screen_space_transform().IsInvertible()) {
TRACE_EVENT0("cc", "LayerImpl::TryScroll: Ignored NonInvertibleTransform");
- return InputHandler::ScrollIgnored;
+ return InputHandler::SCROLL_IGNORED;
}
if (!non_fast_scrollable_region().IsEmpty()) {
@@ -454,7 +454,7 @@ InputHandler::ScrollStatus LayerImpl::TryScroll(
if (!screen_space_transform().GetInverse(&inverse_screen_space_transform)) {
// TODO(shawnsingh): We shouldn't be applying a projection if screen space
// transform is uninvertible here. Perhaps we should be returning
- // ScrollOnMainThread in this case?
+ // SCROLL_ON_MAIN_THREAD in this case?
}
gfx::PointF hit_test_point_in_content_space =
@@ -470,18 +470,25 @@ InputHandler::ScrollStatus LayerImpl::TryScroll(
gfx::ToRoundedPoint(hit_test_point_in_layer_space))) {
TRACE_EVENT0("cc",
"LayerImpl::tryScroll: Failed NonFastScrollableRegion");
- return InputHandler::ScrollOnMainThread;
+ return InputHandler::SCROLL_ON_MAIN_THREAD;
}
}
- if (type == InputHandler::Wheel && have_wheel_event_handlers()) {
+ if (have_scroll_event_handlers() &&
+ effective_block_mode & SCROLL_BLOCKS_ON_SCROLL_EVENT) {
+ TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed ScrollEventHandlers");
+ return InputHandler::SCROLL_ON_MAIN_THREAD;
+ }
+
+ if (type == InputHandler::WHEEL && have_wheel_event_handlers() &&
+ effective_block_mode & SCROLL_BLOCKS_ON_WHEEL_EVENT) {
TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed WheelEventHandlers");
- return InputHandler::ScrollOnMainThread;
+ return InputHandler::SCROLL_ON_MAIN_THREAD;
}
if (!scrollable()) {
TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored not scrollable");
- return InputHandler::ScrollIgnored;
+ return InputHandler::SCROLL_IGNORED;
}
gfx::ScrollOffset max_scroll_offset = MaxScrollOffset();
@@ -489,10 +496,10 @@ InputHandler::ScrollStatus LayerImpl::TryScroll(
TRACE_EVENT0("cc",
"LayerImpl::tryScroll: Ignored. Technically scrollable,"
" but has no affordance in either direction.");
- return InputHandler::ScrollIgnored;
+ return InputHandler::SCROLL_IGNORED;
}
- return InputHandler::ScrollStarted;
+ return InputHandler::SCROLL_STARTED;
}
gfx::Rect LayerImpl::LayerRectToContentRect(
@@ -510,7 +517,7 @@ skia::RefPtr<SkPicture> LayerImpl::GetPicture() {
}
scoped_ptr<LayerImpl> LayerImpl::CreateLayerImpl(LayerTreeImpl* tree_impl) {
- return LayerImpl::Create(tree_impl, layer_id_);
+ return LayerImpl::Create(tree_impl, layer_id_, scroll_offset_);
}
void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
@@ -522,15 +529,16 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->SetDoubleSided(double_sided_);
layer->SetDrawCheckerboardForMissingTiles(
draw_checkerboard_for_missing_tiles_);
- layer->SetForceRenderSurface(force_render_surface_);
layer->SetDrawsContent(DrawsContent());
layer->SetHideLayerAndSubtree(hide_layer_and_subtree_);
+ layer->SetHasRenderSurface(!!render_surface() || layer->HasCopyRequest());
layer->SetFilters(filters());
layer->SetBackgroundFilters(background_filters());
layer->SetMasksToBounds(masks_to_bounds_);
layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_);
layer->SetHaveWheelEventHandlers(have_wheel_event_handlers_);
layer->SetHaveScrollEventHandlers(have_scroll_event_handlers_);
+ layer->SetScrollBlocksOn(scroll_blocks_on_);
layer->SetNonFastScrollableRegion(non_fast_scrollable_region_);
layer->SetTouchEventHandlerRegion(touch_event_handler_region_);
layer->SetContentsOpaque(contents_opaque_);
@@ -542,6 +550,8 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
is_container_for_fixed_position_layers_);
layer->SetPositionConstraint(position_constraint_);
layer->SetShouldFlattenTransform(should_flatten_transform_);
+ layer->set_should_flatten_transform_from_property_tree(
+ should_flatten_transform_from_property_tree_);
layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_);
layer->SetTransformAndInvertibility(transform_, transform_is_invertible_);
@@ -550,16 +560,18 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->set_user_scrollable_horizontal(user_scrollable_horizontal_);
layer->set_user_scrollable_vertical(user_scrollable_vertical_);
- // Save the difference but clear the sent delta so that we don't subtract
- // it again in SetScrollOffsetAndDelta's pending twin mirroring logic.
- gfx::Vector2dF remaining_delta =
- layer->ScrollDelta() - layer->sent_scroll_delta();
- layer->SetSentScrollDelta(gfx::Vector2dF());
- layer->SetScrollOffsetAndDelta(scroll_offset_, remaining_delta);
+ layer->SetScrollCompensationAdjustment(scroll_compensation_adjustment_);
+
+ layer->PushScrollOffset(nullptr);
layer->Set3dSortingContextId(sorting_context_id_);
layer->SetNumDescendantsThatDrawContent(num_descendants_that_draw_content_);
+ layer->SetTransformTreeIndex(transform_tree_index_);
+ layer->SetClipTreeIndex(clip_tree_index_);
+ layer->SetOpacityTreeIndex(opacity_tree_index_);
+ layer->set_offset_to_transform_parent(offset_to_transform_parent_);
+
LayerImpl* scroll_parent = nullptr;
if (scroll_parent_) {
scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id());
@@ -613,6 +625,11 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->SetStackingOrderChanged(stacking_order_changed_);
layer->SetDebugInfo(debug_info_);
+ if (frame_timing_requests_dirty_) {
+ layer->PassFrameTimingRequests(&frame_timing_requests_);
+ frame_timing_requests_dirty_ = false;
+ }
+
// Reset any state that should be cleared for the next update.
stacking_order_changed_ = false;
update_rect_ = gfx::Rect();
@@ -624,9 +641,6 @@ gfx::Vector2dF LayerImpl::FixedContainerSizeDelta() const {
if (!scroll_clip_layer_)
return gfx::Vector2dF();
- float scale_delta = layer_tree_impl()->page_scale_delta();
- float scale = layer_tree_impl()->page_scale_factor();
-
gfx::Vector2dF delta_from_scroll = scroll_clip_layer_->bounds_delta();
// In virtual-viewport mode, we don't need to compensate for pinch zoom or
@@ -635,6 +649,10 @@ gfx::Vector2dF LayerImpl::FixedContainerSizeDelta() const {
if (layer_tree_impl()->settings().use_pinch_virtual_viewport)
return delta_from_scroll;
+ float scale_delta = layer_tree_impl()->page_scale_delta();
+ float scale = layer_tree_impl()->current_page_scale_factor() /
+ layer_tree_impl()->page_scale_delta();
+
delta_from_scroll.Scale(1.f / scale);
// The delta-from-pinch component requires some explanation: A viewport of
@@ -675,7 +693,7 @@ base::DictionaryValue* LayerImpl::LayerTreeAsJson() const {
result->SetBoolean("DrawsContent", draws_content_);
result->SetBoolean("Is3dSorted", Is3dSorted());
- result->SetDouble("Opacity", opacity());
+ result->SetDouble("OPACITY", opacity());
result->SetBoolean("ContentsOpaque", contents_opaque_);
if (scrollable())
@@ -690,6 +708,17 @@ base::DictionaryValue* LayerImpl::LayerTreeAsJson() const {
result->Set("TouchRegion", region.release());
}
+ if (scroll_blocks_on_) {
+ list = new base::ListValue;
+ if (scroll_blocks_on_ & SCROLL_BLOCKS_ON_START_TOUCH)
+ list->AppendString("StartTouch");
+ if (scroll_blocks_on_ & SCROLL_BLOCKS_ON_WHEEL_EVENT)
+ list->AppendString("WheelEvent");
+ if (scroll_blocks_on_ & SCROLL_BLOCKS_ON_SCROLL_EVENT)
+ list->AppendString("ScrollEvent");
+ result->Set("ScrollBlocksOn", list);
+ }
+
list = new base::ListValue;
for (size_t i = 0; i < children_.size(); ++i)
list->Append(children_[i]->LayerTreeAsJson());
@@ -732,6 +761,23 @@ void LayerImpl::NoteLayerPropertyChangedForDescendants() {
SetNeedsPushProperties();
}
+#if DCHECK_IS_ON()
+// Verify that the resource id is valid.
+static ResourceProvider::ResourceId ValidateResource(
+ const ResourceProvider* provider,
+ ResourceProvider::ResourceId id) {
+ provider->ValidateResource(id);
+ return id;
+}
+#endif
+
+void LayerImpl::ValidateQuadResourcesInternal(DrawQuad* quad) const {
+#if DCHECK_IS_ON()
+ quad->IterateResources(
+ base::Bind(&ValidateResource, layer_tree_impl_->resource_provider()));
+#endif
+}
+
const char* LayerImpl::LayerTypeAsString() const {
return "cc::LayerImpl";
}
@@ -742,8 +788,8 @@ void LayerImpl::ResetAllChangeTrackingForSubtree() {
update_rect_ = gfx::Rect();
damage_rect_ = gfx::RectF();
- if (draw_properties_.render_surface)
- draw_properties_.render_surface->ResetPropertyChangedFlag();
+ if (render_surface_)
+ render_surface_->ResetPropertyChangedFlag();
if (mask_layer_)
mask_layer_->ResetAllChangeTrackingForSubtree();
@@ -761,7 +807,7 @@ void LayerImpl::ResetAllChangeTrackingForSubtree() {
}
gfx::ScrollOffset LayerImpl::ScrollOffsetForAnimation() const {
- return TotalScrollOffset();
+ return CurrentScrollOffset();
}
void LayerImpl::OnFilterAnimated(const FilterOperations& filters) {
@@ -779,11 +825,11 @@ void LayerImpl::OnTransformAnimated(const gfx::Transform& transform) {
void LayerImpl::OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset) {
// Only layers in the active tree should need to do anything here, since
// layers in the pending tree will find out about these changes as a
- // result of the call to SetScrollDelta.
+ // result of the shared SyncedProperty.
if (!IsActive())
return;
- SetScrollDelta(scroll_offset.DeltaFrom(scroll_offset_));
+ SetCurrentScrollOffset(scroll_offset);
layer_tree_impl_->DidAnimateScrollOffset();
}
@@ -938,12 +984,12 @@ void LayerImpl::SetFilters(const FilterOperations& filters) {
}
bool LayerImpl::FilterIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Filter);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::FILTER);
}
bool LayerImpl::FilterIsAnimatingOnImplOnly() const {
Animation* filter_animation =
- layer_animation_controller_->GetAnimation(Animation::Filter);
+ layer_animation_controller_->GetAnimation(Animation::FILTER);
return filter_animation && filter_animation->is_impl_only();
}
@@ -981,12 +1027,12 @@ void LayerImpl::SetOpacity(float opacity) {
}
bool LayerImpl::OpacityIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Opacity);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::OPACITY);
}
bool LayerImpl::OpacityIsAnimatingOnImplOnly() const {
Animation* opacity_animation =
- layer_animation_controller_->GetAnimation(Animation::Opacity);
+ layer_animation_controller_->GetAnimation(Animation::OPACITY);
return opacity_animation && opacity_animation->is_impl_only();
}
@@ -1029,6 +1075,18 @@ void LayerImpl::Set3dSortingContextId(int id) {
NoteLayerPropertyChangedForSubtree();
}
+void LayerImpl::PassFrameTimingRequests(
+ std::vector<FrameTimingRequest>* requests) {
+ frame_timing_requests_.swap(*requests);
+ frame_timing_requests_dirty_ = true;
+ SetNeedsPushProperties();
+}
+
+void LayerImpl::GatherFrameTimingRequestIds(std::vector<int64_t>* request_ids) {
+ for (const auto& request : frame_timing_requests_)
+ request_ids->push_back(request.id());
+}
+
void LayerImpl::SetTransform(const gfx::Transform& transform) {
if (transform_ == transform)
return;
@@ -1051,12 +1109,12 @@ void LayerImpl::SetTransformAndInvertibility(const gfx::Transform& transform,
}
bool LayerImpl::TransformIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Transform);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::TRANSFORM);
}
bool LayerImpl::TransformIsAnimatingOnImplOnly() const {
Animation* transform_animation =
- layer_animation_controller_->GetAnimation(Animation::Transform);
+ layer_animation_controller_->GetAnimation(Animation::TRANSFORM);
return transform_animation && transform_animation->is_impl_only();
}
@@ -1088,93 +1146,102 @@ void LayerImpl::SetContentsScale(float contents_scale_x,
NoteLayerPropertyChanged();
}
-void LayerImpl::SetScrollOffsetDelegate(
- ScrollOffsetDelegate* scroll_offset_delegate) {
- // Having both a scroll parent and a scroll offset delegate is unsupported.
- DCHECK(!scroll_parent_);
- if (!scroll_offset_delegate && scroll_offset_delegate_) {
- scroll_delta_ = scroll_offset_delegate_->GetTotalScrollOffset().DeltaFrom(
- scroll_offset_);
- }
- gfx::ScrollOffset total_offset = TotalScrollOffset();
- scroll_offset_delegate_ = scroll_offset_delegate;
- if (scroll_offset_delegate_)
- scroll_offset_delegate_->SetTotalScrollOffset(total_offset);
-}
-
bool LayerImpl::IsExternalFlingActive() const {
- return scroll_offset_delegate_ &&
- scroll_offset_delegate_->IsExternalFlingActive();
+ return layer_tree_impl_->IsExternalFlingActive();
}
-void LayerImpl::DidScroll() {
- NoteLayerPropertyChangedForSubtree();
- ScrollbarParametersDidChange(false);
+void LayerImpl::SetCurrentScrollOffset(const gfx::ScrollOffset& scroll_offset) {
+ DCHECK(IsActive());
+ if (scroll_offset_->SetCurrent(scroll_offset))
+ DidUpdateScrollOffset(false);
}
-void LayerImpl::SetScrollOffset(const gfx::ScrollOffset& scroll_offset) {
- SetScrollOffsetAndDelta(scroll_offset, ScrollDelta());
+void LayerImpl::SetCurrentScrollOffsetFromDelegate(
+ const gfx::ScrollOffset& scroll_offset) {
+ DCHECK(IsActive());
+ if (scroll_offset_->SetCurrent(scroll_offset))
+ DidUpdateScrollOffset(true);
}
-void LayerImpl::SetScrollOffsetAndDelta(const gfx::ScrollOffset& scroll_offset,
- const gfx::Vector2dF& scroll_delta) {
- bool changed = false;
+void LayerImpl::PushScrollOffsetFromMainThread(
+ const gfx::ScrollOffset& scroll_offset) {
+ PushScrollOffset(&scroll_offset);
+}
- last_scroll_offset_ = scroll_offset;
+void LayerImpl::PushScrollOffsetFromMainThreadAndClobberActiveValue(
+ const gfx::ScrollOffset& scroll_offset) {
+ scroll_offset_->set_clobber_active_value();
+ PushScrollOffset(&scroll_offset);
+}
- if (scroll_offset_ != scroll_offset) {
- changed = true;
- scroll_offset_ = scroll_offset;
+gfx::ScrollOffset LayerImpl::PullDeltaForMainThread() {
+ // TODO(miletus): Remove all this temporary flooring machinery when
+ // Blink fully supports fractional scrolls.
+ gfx::ScrollOffset current_offset = CurrentScrollOffset();
+ gfx::Vector2dF current_delta = ScrollDelta();
+ gfx::Vector2dF floored_delta(floor(current_delta.x()),
+ floor(current_delta.y()));
+ gfx::Vector2dF diff_delta = floored_delta - current_delta;
+ gfx::ScrollOffset tmp_offset = ScrollOffsetWithDelta(current_offset,
+ diff_delta);
+ scroll_offset_->SetCurrent(tmp_offset);
+ gfx::ScrollOffset delta = scroll_offset_->PullDeltaForMainThread();
+ scroll_offset_->SetCurrent(current_offset);
+ return delta;
+}
- if (scroll_offset_delegate_)
- scroll_offset_delegate_->SetTotalScrollOffset(TotalScrollOffset());
- }
+gfx::ScrollOffset LayerImpl::CurrentScrollOffset() const {
+ return scroll_offset_->Current(IsActive());
+}
- if (ScrollDelta() != scroll_delta) {
- changed = true;
- if (layer_tree_impl()->IsActiveTree()) {
- LayerImpl* pending_twin =
- layer_tree_impl()->FindPendingTreeLayerById(id());
- if (pending_twin) {
- // The pending twin can't mirror the scroll delta of the active
- // layer. Although the delta - sent scroll delta difference is
- // identical for both twins, the sent scroll delta for the pending
- // layer is zero, as anything that has been sent has been baked
- // into the layer's position/scroll offset as a part of commit.
- DCHECK(pending_twin->sent_scroll_delta().IsZero());
- pending_twin->SetScrollDelta(scroll_delta - sent_scroll_delta());
- }
- }
+gfx::Vector2dF LayerImpl::ScrollDelta() const {
+ if (IsActive())
+ return gfx::Vector2dF(scroll_offset_->Delta().x(),
+ scroll_offset_->Delta().y());
+ else
+ return gfx::Vector2dF(scroll_offset_->PendingDelta().get().x(),
+ scroll_offset_->PendingDelta().get().y());
+}
- if (scroll_offset_delegate_) {
- scroll_offset_delegate_->SetTotalScrollOffset(
- ScrollOffsetWithDelta(scroll_offset_, scroll_delta));
- } else {
- scroll_delta_ = scroll_delta;
- }
- }
+void LayerImpl::SetScrollDelta(const gfx::Vector2dF& delta) {
+ DCHECK(IsActive());
+ SetCurrentScrollOffset(scroll_offset_->ActiveBase() +
+ gfx::ScrollOffset(delta));
+}
- if (changed) {
- if (scroll_offset_delegate_)
- scroll_offset_delegate_->Update();
- DidScroll();
- }
+gfx::ScrollOffset LayerImpl::BaseScrollOffset() const {
+ if (IsActive())
+ return scroll_offset_->ActiveBase();
+ else
+ return scroll_offset_->PendingBase();
}
-gfx::Vector2dF LayerImpl::ScrollDelta() const {
- if (scroll_offset_delegate_) {
- return scroll_offset_delegate_->GetTotalScrollOffset().DeltaFrom(
- scroll_offset_);
+void LayerImpl::PushScrollOffset(const gfx::ScrollOffset* scroll_offset) {
+ DCHECK(scroll_offset || IsActive());
+ bool changed = false;
+ if (scroll_offset) {
+ DCHECK(!IsActive() || !layer_tree_impl_->FindPendingTreeLayerById(id()));
+ changed |= scroll_offset_->PushFromMainThread(*scroll_offset);
+ }
+ if (IsActive()) {
+ changed |= scroll_offset_->PushPendingToActive();
}
- return scroll_delta_;
-}
-void LayerImpl::SetScrollDelta(const gfx::Vector2dF& scroll_delta) {
- SetScrollOffsetAndDelta(scroll_offset_, scroll_delta);
+ if (changed)
+ DidUpdateScrollOffset(false);
}
-gfx::ScrollOffset LayerImpl::TotalScrollOffset() const {
- return ScrollOffsetWithDelta(scroll_offset_, ScrollDelta());
+void LayerImpl::DidUpdateScrollOffset(bool is_from_root_delegate) {
+ if (!is_from_root_delegate)
+ layer_tree_impl()->DidUpdateScrollOffset(id());
+ NoteLayerPropertyChangedForSubtree();
+ ScrollbarParametersDidChange(false);
+ // Inform the pending twin that a property changed.
+ if (layer_tree_impl()->IsActiveTree()) {
+ LayerImpl* pending_twin = layer_tree_impl()->FindPendingTreeLayerById(id());
+ if (pending_twin)
+ pending_twin->NoteLayerPropertyChangedForSubtree();
+ }
}
void LayerImpl::SetDoubleSided(bool double_sided) {
@@ -1195,6 +1262,9 @@ void LayerImpl::DidBeginTracing() {}
void LayerImpl::ReleaseResources() {}
+void LayerImpl::RecreateResources() {
+}
+
gfx::ScrollOffset LayerImpl::MaxScrollOffset() const {
if (!scroll_clip_layer_ || bounds().IsEmpty())
return gfx::ScrollOffset();
@@ -1204,39 +1274,16 @@ gfx::ScrollOffset LayerImpl::MaxScrollOffset() const {
DCHECK(this != layer_tree_impl()->InnerViewportScrollLayer() ||
IsContainerForFixedPositionLayers());
- gfx::SizeF scaled_scroll_bounds(BoundsForScrolling());
-
float scale_factor = 1.f;
for (LayerImpl const* current_layer = this;
- current_layer != scroll_clip_layer_;
+ current_layer != scroll_clip_layer_->parent();
current_layer = current_layer->parent()) {
- DCHECK(current_layer);
- float current_layer_scale = 1.f;
-
- const gfx::Transform& layer_transform = current_layer->transform();
- if (current_layer == page_scale_layer) {
- DCHECK(layer_transform.IsIdentity());
- current_layer_scale = layer_tree_impl()->total_page_scale_factor();
- } else {
- // TODO(wjmaclean) Should we allow for translation too?
- DCHECK(layer_transform.IsScale2d());
- gfx::Vector2dF layer_scale = layer_transform.Scale2d();
- // TODO(wjmaclean) Allow for non-isotropic scales.
- DCHECK(layer_scale.x() == layer_scale.y());
- current_layer_scale = layer_scale.x();
- }
-
- scale_factor *= current_layer_scale;
+ if (current_layer == page_scale_layer)
+ scale_factor = layer_tree_impl()->current_page_scale_factor();
}
- // TODO(wjmaclean) Once we move to a model where the two-viewport model is
- // turned on in all builds, remove the next two lines. For now however, the
- // page scale layer may coincide with the clip layer, and so this is
- // necessary.
- if (page_scale_layer == scroll_clip_layer_)
- scale_factor *= layer_tree_impl()->total_page_scale_factor();
-
- scaled_scroll_bounds.SetSize(scale_factor * scaled_scroll_bounds.width(),
- scale_factor * scaled_scroll_bounds.height());
+
+ gfx::SizeF scaled_scroll_bounds =
+ gfx::ToFlooredSize(gfx::ScaleSize(BoundsForScrolling(), scale_factor));
scaled_scroll_bounds = gfx::ToFlooredSize(scaled_scroll_bounds);
gfx::ScrollOffset max_offset(
@@ -1248,17 +1295,19 @@ gfx::ScrollOffset LayerImpl::MaxScrollOffset() const {
return max_offset;
}
-gfx::Vector2dF LayerImpl::ClampScrollToMaxScrollOffset() {
- gfx::ScrollOffset max_offset = MaxScrollOffset();
- gfx::ScrollOffset old_offset = TotalScrollOffset();
- gfx::ScrollOffset clamped_offset = old_offset;
+gfx::ScrollOffset LayerImpl::ClampScrollOffsetToLimits(
+ gfx::ScrollOffset offset) const {
+ offset.SetToMin(MaxScrollOffset());
+ offset.SetToMax(gfx::ScrollOffset());
+ return offset;
+}
- clamped_offset.SetToMin(max_offset);
- clamped_offset.SetToMax(gfx::ScrollOffset());
+gfx::Vector2dF LayerImpl::ClampScrollToMaxScrollOffset() {
+ gfx::ScrollOffset old_offset = CurrentScrollOffset();
+ gfx::ScrollOffset clamped_offset = ClampScrollOffsetToLimits(old_offset);
gfx::Vector2dF delta = clamped_offset.DeltaFrom(old_offset);
if (!delta.IsZero())
ScrollBy(delta);
-
return delta;
}
@@ -1270,8 +1319,6 @@ void LayerImpl::SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer,
DCHECK(this != page_scale_layer);
DCHECK(scrollbar_clip_layer);
- DCHECK(this != layer_tree_impl()->InnerViewportScrollLayer() ||
- IsContainerForFixedPositionLayers());
gfx::RectF clip_rect(gfx::PointF(),
scrollbar_clip_layer->BoundsForScrolling());
@@ -1282,37 +1329,17 @@ void LayerImpl::SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer,
if (scroll_rect.size().IsEmpty())
return;
- // TODO(wjmaclean) This computation is nearly identical to the one in
- // MaxScrollOffset. Find some way to combine these.
gfx::ScrollOffset current_offset;
for (LayerImpl const* current_layer = this;
- current_layer != scrollbar_clip_layer;
+ current_layer != scrollbar_clip_layer->parent();
current_layer = current_layer->parent()) {
- DCHECK(current_layer);
- const gfx::Transform& layer_transform = current_layer->transform();
+ current_offset += current_layer->CurrentScrollOffset();
if (current_layer == page_scale_layer) {
- DCHECK(layer_transform.IsIdentity());
- float scale_factor = layer_tree_impl()->total_page_scale_factor();
+ float scale_factor = layer_tree_impl()->current_page_scale_factor();
current_offset.Scale(scale_factor);
scroll_rect.Scale(scale_factor);
- } else {
- DCHECK(layer_transform.IsScale2d());
- gfx::Vector2dF layer_scale = layer_transform.Scale2d();
- DCHECK(layer_scale.x() == layer_scale.y());
- gfx::ScrollOffset new_offset = ScrollOffsetWithDelta(
- current_layer->scroll_offset(), current_layer->ScrollDelta());
- new_offset.Scale(layer_scale.x(), layer_scale.y());
- current_offset += new_offset;
}
}
- // TODO(wjmaclean) Once we move to a model where the two-viewport model is
- // turned on in all builds, remove the next two lines. For now however, the
- // page scale layer may coincide with the clip layer, and so this is
- // necessary.
- if (page_scale_layer == scrollbar_clip_layer) {
- scroll_rect.Scale(layer_tree_impl()->total_page_scale_factor());
- current_offset.Scale(layer_tree_impl()->total_page_scale_factor());
- }
bool scrollbar_needs_animation = false;
scrollbar_needs_animation |= scrollbar_layer->SetVerticalAdjust(
@@ -1327,12 +1354,18 @@ void LayerImpl::SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer,
scrollbar_layer->SetVisibleToTotalLengthRatio(visible_ratio);
} else {
float visible_ratio = clip_rect.height() / scroll_rect.height();
- scrollbar_needs_animation |=
+ bool y_offset_did_change =
scrollbar_layer->SetCurrentPos(current_offset.y());
+ scrollbar_needs_animation |= y_offset_did_change;
scrollbar_needs_animation |=
scrollbar_layer->SetMaximum(scroll_rect.height() - clip_rect.height());
scrollbar_needs_animation |=
scrollbar_layer->SetVisibleToTotalLengthRatio(visible_ratio);
+ if (y_offset_did_change && layer_tree_impl()->IsActiveTree() &&
+ this == layer_tree_impl()->InnerViewportScrollLayer()) {
+ TRACE_COUNTER_ID1("cc", "scroll_offset_y", this->id(),
+ current_offset.y());
+ }
}
if (scrollbar_needs_animation) {
layer_tree_impl()->set_needs_update_draw_properties();
@@ -1341,15 +1374,8 @@ void LayerImpl::SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer,
// scrolls that move the pinch virtual viewport (i.e. trigger from
// either inner or outer viewport).
if (scrollbar_animation_controller_) {
- // When both non-overlay and overlay scrollbars are both present, don't
- // animate the overlay scrollbars when page scale factor is at the min.
- // Non-overlay scrollbars also shouldn't trigger animations.
- bool is_animatable_scrollbar =
- scrollbar_layer->is_overlay_scrollbar() &&
- ((layer_tree_impl()->total_page_scale_factor() >
- layer_tree_impl()->min_page_scale_factor()) ||
- !layer_tree_impl()->settings().use_pinch_zoom_scrollbars);
- if (is_animatable_scrollbar)
+ // Non-overlay scrollbars shouldn't trigger animations.
+ if (scrollbar_layer->is_overlay_scrollbar())
scrollbar_animation_controller_->DidScrollUpdate(on_resize);
}
}
@@ -1357,7 +1383,7 @@ void LayerImpl::SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer,
void LayerImpl::DidBecomeActive() {
if (layer_tree_impl_->settings().scrollbar_animator ==
- LayerTreeSettings::NoAnimator) {
+ LayerTreeSettings::NO_ANIMATOR) {
return;
}
@@ -1451,10 +1477,11 @@ void LayerImpl::RemoveDependentNeedsPushProperties() {
parent_->RemoveDependentNeedsPushProperties();
}
-void LayerImpl::GetAllTilesForTracing(std::set<const Tile*>* tiles) const {
+void LayerImpl::GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const {
}
-void LayerImpl::AsValueInto(base::debug::TracedValue* state) const {
+void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const {
TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
TRACE_DISABLED_BY_DEFAULT("cc.debug"),
state,
@@ -1462,35 +1489,28 @@ void LayerImpl::AsValueInto(base::debug::TracedValue* state) const {
LayerTypeAsString(),
this);
state->SetInteger("layer_id", id());
- state->BeginDictionary("bounds");
- MathUtil::AddToTracedValue(bounds_, state);
- state->EndDictionary();
+ MathUtil::AddToTracedValue("bounds", bounds_, state);
state->SetDouble("opacity", opacity());
- state->BeginArray("position");
- MathUtil::AddToTracedValue(position_, state);
- state->EndArray();
+ MathUtil::AddToTracedValue("position", position_, state);
state->SetInteger("draws_content", DrawsContent());
state->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes());
- state->BeginArray("scroll_offset");
- MathUtil::AddToTracedValue(scroll_offset_, state);
- state->EndArray();
+ MathUtil::AddToTracedValue(
+ "scroll_offset", scroll_offset_ ? scroll_offset_->Current(IsActive())
+ : gfx::ScrollOffset(),
+ state);
- state->BeginArray("transform_origin");
- MathUtil::AddToTracedValue(transform_origin_, state);
- state->EndArray();
+ MathUtil::AddToTracedValue("transform_origin", transform_origin_, state);
bool clipped;
gfx::QuadF layer_quad = MathUtil::MapQuad(
screen_space_transform(),
gfx::QuadF(gfx::Rect(content_bounds())),
&clipped);
- state->BeginArray("layer_quad");
- MathUtil::AddToTracedValue(layer_quad, state);
- state->EndArray();
+ MathUtil::AddToTracedValue("layer_quad", layer_quad, state);
if (!touch_event_handler_region_.IsEmpty()) {
state->BeginArray("touch_event_handler_region");
touch_event_handler_region_.AsValueInto(state);
@@ -1515,6 +1535,9 @@ void LayerImpl::AsValueInto(base::debug::TracedValue* state) const {
non_fast_scrollable_region_.AsValueInto(state);
state->EndArray();
}
+ if (scroll_blocks_on_) {
+ state->SetInteger("scroll_blocks_on", scroll_blocks_on_);
+ }
state->BeginArray("children");
for (size_t i = 0; i < children_.size(); ++i) {
@@ -1548,11 +1571,8 @@ void LayerImpl::AsValueInto(base::debug::TracedValue* state) const {
layer_animation_controller()->HasAnimationThatInflatesBounds());
gfx::BoxF box;
- if (LayerUtils::GetAnimationBounds(*this, &box)) {
- state->BeginArray("animation_bounds");
- MathUtil::AddToTracedValue(box, state);
- state->EndArray();
- }
+ if (LayerUtils::GetAnimationBounds(*this, &box))
+ MathUtil::AddToTracedValue("animation_bounds", box, state);
if (debug_info_.get()) {
std::string str;
@@ -1567,12 +1587,23 @@ void LayerImpl::AsValueInto(base::debug::TracedValue* state) const {
DCHECK(converted_to_dictionary);
for (base::DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd();
it.Advance()) {
- state->SetValue(it.key().data(), it.value().DeepCopy());
+ state->SetValue(it.key().data(), it.value().CreateDeepCopy());
}
} else {
NOTREACHED();
}
}
+
+ if (!frame_timing_requests_.empty()) {
+ state->BeginArray("frame_timing_requests");
+ for (const auto& request : frame_timing_requests_) {
+ state->BeginDictionary();
+ state->SetInteger("request_id", request.id());
+ MathUtil::AddToTracedValue("request_rect", request.rect(), state);
+ state->EndDictionary();
+ }
+ state->EndArray();
+ }
}
bool LayerImpl::IsDrawnRenderSurfaceLayerListMember() const {
@@ -1594,8 +1625,41 @@ void LayerImpl::NotifyAnimationFinished(
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property,
int group) {
- if (target_property == Animation::ScrollOffset)
+ if (target_property == Animation::SCROLL_OFFSET)
layer_tree_impl_->InputScrollAnimationFinished();
}
+void LayerImpl::SetHasRenderSurface(bool should_have_render_surface) {
+ if (!!render_surface() == should_have_render_surface)
+ return;
+
+ SetNeedsPushProperties();
+ layer_tree_impl()->set_needs_update_draw_properties();
+ if (should_have_render_surface) {
+ render_surface_ = make_scoped_ptr(new RenderSurfaceImpl(this));
+ return;
+ }
+ render_surface_.reset();
+}
+
+Region LayerImpl::GetInvalidationRegion() {
+ return Region(update_rect_);
+}
+
+gfx::Rect LayerImpl::GetEnclosingRectInTargetSpace() const {
+ return MathUtil::MapEnclosingClippedRect(
+ draw_properties_.target_space_transform,
+ gfx::Rect(draw_properties_.content_bounds));
+}
+
+gfx::Rect LayerImpl::GetScaledEnclosingRectInTargetSpace(float scale) const {
+ gfx::Transform scaled_draw_transform =
+ draw_properties_.target_space_transform;
+ scaled_draw_transform.Scale(SK_MScalar1 / scale, SK_MScalar1 / scale);
+ gfx::Size scaled_content_bounds =
+ gfx::ToCeiledSize(gfx::ScaleSize(content_bounds(), scale));
+ return MathUtil::MapEnclosingClippedRect(scaled_draw_transform,
+ gfx::Rect(scaled_content_bounds));
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h
index 5fe679c30f7..08db87f1392 100644
--- a/chromium/cc/layers/layer_impl.h
+++ b/chromium/cc/layers/layer_impl.h
@@ -5,8 +5,10 @@
#ifndef CC_LAYERS_LAYER_IMPL_H_
#define CC_LAYERS_LAYER_IMPL_H_
+#include <map>
#include <set>
#include <string>
+#include <vector>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -18,15 +20,19 @@
#include "cc/base/cc_export.h"
#include "cc/base/region.h"
#include "cc/base/scoped_ptr_vector.h"
+#include "cc/base/synced_property.h"
+#include "cc/debug/frame_timing_request.h"
#include "cc/input/input_handler.h"
#include "cc/input/scrollbar.h"
#include "cc/layers/draw_properties.h"
#include "cc/layers/layer_lists.h"
#include "cc/layers/layer_position_constraint.h"
#include "cc/layers/render_surface_impl.h"
+#include "cc/layers/scroll_blocks_on.h"
#include "cc/output/filter_operations.h"
#include "cc/quads/shared_quad_state.h"
#include "cc/resources/resource_provider.h"
+#include "cc/tiles/tile_priority.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
@@ -38,11 +44,10 @@
#include "ui/gfx/transform.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
class TracedValue;
}
-
class DictionaryValue;
}
@@ -54,6 +59,8 @@ class MicroBenchmarkImpl;
class Occlusion;
template <typename LayerType>
class OcclusionTracker;
+class OpacityTree;
+class PrioritizedTile;
class RenderPass;
class RenderPassId;
class Renderer;
@@ -61,6 +68,7 @@ class ScrollbarAnimationController;
class ScrollbarLayerImplBase;
class SimpleEnclosedRegion;
class Tile;
+class TransformTree;
struct AppendQuadsData;
@@ -75,22 +83,20 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
public LayerAnimationValueProvider,
public AnimationDelegate {
public:
- // Allows for the ownership of the total scroll offset to be delegated outside
- // of the layer.
- class ScrollOffsetDelegate {
- public:
- virtual void SetTotalScrollOffset(const gfx::ScrollOffset& new_value) = 0;
- virtual gfx::ScrollOffset GetTotalScrollOffset() = 0;
- virtual bool IsExternalFlingActive() const = 0;
- virtual void Update() const = 0;
- };
-
+ typedef SyncedProperty<AdditionGroup<gfx::ScrollOffset>> SyncedScrollOffset;
typedef LayerImplList RenderSurfaceListType;
typedef LayerImplList LayerListType;
typedef RenderSurfaceImpl RenderSurfaceType;
enum RenderingContextConstants { NO_RENDERING_CONTEXT = 0 };
+ static scoped_ptr<LayerImpl> Create(
+ LayerTreeImpl* tree_impl,
+ int id,
+ scoped_refptr<SyncedScrollOffset> scroll_offset) {
+ return make_scoped_ptr(new LayerImpl(tree_impl, id, scroll_offset));
+ }
+
static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
return make_scoped_ptr(new LayerImpl(tree_impl, id));
}
@@ -145,6 +151,43 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
return scroll_children_.get();
}
+ void set_property_tree_sequence_number(int sequence_number) {}
+
+ void SetTransformTreeIndex(int index);
+ int transform_tree_index() const { return transform_tree_index_; }
+
+ void SetClipTreeIndex(int index);
+ int clip_tree_index() const { return clip_tree_index_; }
+
+ void SetOpacityTreeIndex(int index);
+ int opacity_tree_index() const { return opacity_tree_index_; }
+
+ void set_offset_to_transform_parent(const gfx::Vector2dF& offset) {
+ offset_to_transform_parent_ = offset;
+ SetNeedsPushProperties();
+ }
+ gfx::Vector2dF offset_to_transform_parent() const {
+ return offset_to_transform_parent_;
+ }
+
+ const gfx::Rect& visible_rect_from_property_trees() const {
+ return visible_rect_from_property_trees_;
+ }
+ void set_visible_rect_from_property_trees(const gfx::Rect& rect) {
+ visible_rect_from_property_trees_ = rect;
+ }
+
+ void set_should_flatten_transform_from_property_tree(bool should_flatten) {
+ should_flatten_transform_from_property_tree_ = should_flatten;
+ SetNeedsPushProperties();
+ }
+ bool should_flatten_transform_from_property_tree() const {
+ return should_flatten_transform_from_property_tree_;
+ }
+
+ // For compatibility with Layer.
+ bool has_render_surface() const { return !!render_surface(); }
+
void SetNumDescendantsThatDrawContent(int num_descendants);
void SetClipParent(LayerImpl* ancestor);
@@ -187,6 +230,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
LayerTreeImpl* layer_tree_impl() const { return layer_tree_impl_; }
void PopulateSharedQuadState(SharedQuadState* state) const;
+ void PopulateScaledSharedQuadState(SharedQuadState* state, float scale) const;
// WillDraw must be called before AppendQuads. If WillDraw returns false,
// AppendQuads and DidDraw will not be called. If WillDraw returns true,
// DidDraw is guaranteed to be called before another WillDraw or before
@@ -196,10 +240,16 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
virtual bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider);
virtual void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {}
virtual void DidDraw(ResourceProvider* resource_provider);
+ // Verify that the resource ids in the quad are valid.
+ void ValidateQuadResources(DrawQuad* quad) const {
+#if DCHECK_IS_ON()
+ ValidateQuadResourcesInternal(quad);
+#endif
+ }
+
virtual void GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
gfx::Size* resource_size) const;
@@ -208,8 +258,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
virtual RenderPassId FirstContributingRenderPassId() const;
virtual RenderPassId NextContributingRenderPassId(RenderPassId id) const;
- virtual void UpdateTiles(const Occlusion& occlusion_in_layer_space,
- bool resourceless_software_draw) {}
virtual void NotifyTileStateChanged(const Tile* tile) {}
virtual ScrollbarLayerImplBase* ToScrollbarLayer();
@@ -222,9 +270,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
void SetHideLayerAndSubtree(bool hide);
bool hide_layer_and_subtree() const { return hide_layer_and_subtree_; }
- bool force_render_surface() const { return force_render_surface_; }
- void SetForceRenderSurface(bool force) { force_render_surface_ = force; }
-
void SetTransformOrigin(const gfx::Point3F& transform_origin);
gfx::Point3F transform_origin() const { return transform_origin_; }
@@ -303,9 +348,10 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
// These invalidate the host's render surface layer list. The caller
// is responsible for calling set_needs_update_draw_properties on the tree
// so that its list can be recreated.
- void CreateRenderSurface();
- void ClearRenderSurface();
void ClearRenderSurfaceLayerList();
+ void SetHasRenderSurface(bool has_render_surface);
+
+ RenderSurfaceImpl* render_surface() const { return render_surface_.get(); }
DrawProperties<LayerImpl>& draw_properties() {
return draw_properties_;
@@ -323,6 +369,9 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
return draw_properties_.screen_space_transform;
}
float draw_opacity() const { return draw_properties_.opacity; }
+ SkXfermode::Mode draw_blend_mode() const {
+ return draw_properties_.blend_mode;
+ }
bool draw_opacity_is_animating() const {
return draw_properties_.opacity_is_animating;
}
@@ -354,9 +403,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
draw_properties_.render_target->render_surface());
return draw_properties_.render_target;
}
- RenderSurfaceImpl* render_surface() const {
- return draw_properties_.render_surface.get();
- }
+
int num_unclipped_descendants() const {
return draw_properties_.num_unclipped_descendants;
}
@@ -380,27 +427,35 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
float contents_scale_y() const { return draw_properties_.contents_scale_y; }
void SetContentsScale(float contents_scale_x, float contents_scale_y);
- void SetScrollOffsetDelegate(ScrollOffsetDelegate* scroll_offset_delegate);
- void DidScroll();
bool IsExternalFlingActive() const;
- void SetScrollOffset(const gfx::ScrollOffset& scroll_offset);
- void SetScrollOffsetAndDelta(const gfx::ScrollOffset& scroll_offset,
- const gfx::Vector2dF& scroll_delta);
- gfx::ScrollOffset scroll_offset() const { return scroll_offset_; }
+ void SetCurrentScrollOffset(const gfx::ScrollOffset& scroll_offset);
+ void SetCurrentScrollOffsetFromDelegate(
+ const gfx::ScrollOffset& scroll_offset);
+ void PushScrollOffsetFromMainThread(const gfx::ScrollOffset& scroll_offset);
+ // This method is similar to PushScrollOffsetFromMainThread but will cause the
+ // scroll offset given to clobber any scroll changes on the active tree in the
+ // time until this value is pushed to the active tree.
+ void PushScrollOffsetFromMainThreadAndClobberActiveValue(
+ const gfx::ScrollOffset& scroll_offset);
+ gfx::ScrollOffset PullDeltaForMainThread();
+ gfx::ScrollOffset CurrentScrollOffset() const;
+ gfx::ScrollOffset BaseScrollOffset() const;
+ gfx::Vector2dF ScrollDelta() const;
+ void SetScrollDelta(const gfx::Vector2dF& delta);
gfx::ScrollOffset MaxScrollOffset() const;
+ gfx::ScrollOffset ClampScrollOffsetToLimits(gfx::ScrollOffset offset) const;
gfx::Vector2dF ClampScrollToMaxScrollOffset();
void SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer,
LayerImpl* scrollbar_clip_layer,
bool on_resize) const;
- void SetScrollDelta(const gfx::Vector2dF& scroll_delta);
- gfx::Vector2dF ScrollDelta() const;
-
- gfx::ScrollOffset TotalScrollOffset() const;
-
- void SetSentScrollDelta(const gfx::Vector2dF& sent_scroll_delta);
- gfx::Vector2dF sent_scroll_delta() const { return sent_scroll_delta_; }
+ void SetScrollCompensationAdjustment(const gfx::Vector2dF& scroll_offset) {
+ scroll_compensation_adjustment_ = scroll_offset;
+ }
+ gfx::Vector2dF ScrollCompensationAdjustment() const {
+ return scroll_compensation_adjustment_;
+ }
// Returns the delta of the scroll that was outside of the bounds of the
// initial scroll
@@ -424,7 +479,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
bool user_scrollable(ScrollbarOrientation orientation) const;
void ApplySentScrollDeltasFromAbortedCommit();
- void ApplyScrollDeltasSinceBeginMainFrame();
void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) {
should_scroll_on_main_thread_ = should_scroll_on_main_thread;
@@ -459,6 +513,10 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
return touch_event_handler_region_;
}
+ void SetScrollBlocksOn(ScrollBlocksOn scroll_blocks_on) {
+ scroll_blocks_on_ = scroll_blocks_on;
+ }
+ ScrollBlocksOn scroll_blocks_on() const { return scroll_blocks_on_; }
void SetDrawCheckerboardForMissingTiles(bool checkerboard) {
draw_checkerboard_for_missing_tiles_ = checkerboard;
}
@@ -468,7 +526,8 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
InputHandler::ScrollStatus TryScroll(
const gfx::PointF& screen_space_point,
- InputHandler::ScrollInputType type) const;
+ InputHandler::ScrollInputType type,
+ ScrollBlocksOn effective_block_mode) const;
void SetDoubleSided(bool double_sided);
bool double_sided() const { return double_sided_; }
@@ -515,6 +574,10 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
// that rendered this layer was lost or a rendering mode switch has occured.
virtual void ReleaseResources();
+ // Recreate resources that are required after they were released by a
+ // ReleaseResources call.
+ virtual void RecreateResources();
+
ScrollbarAnimationController* scrollbar_animation_controller() const {
return scrollbar_animation_controller_.get();
}
@@ -537,8 +600,9 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl);
virtual void PushPropertiesTo(LayerImpl* layer);
- virtual void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
- virtual void AsValueInto(base::debug::TracedValue* dict) const;
+ virtual void GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const;
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
virtual size_t GPUMemoryUsageInBytes() const;
@@ -557,14 +621,32 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark);
virtual void SetDebugInfo(
- scoped_refptr<base::debug::ConvertableToTraceFormat> other);
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> other);
bool IsDrawnRenderSurfaceLayerListMember() const;
void Set3dSortingContextId(int id);
int sorting_context_id() { return sorting_context_id_; }
+ void PassFrameTimingRequests(
+ std::vector<FrameTimingRequest>* frame_timing_requests);
+ const std::vector<FrameTimingRequest>& frame_timing_requests() const {
+ return frame_timing_requests_;
+ }
+ void GatherFrameTimingRequestIds(std::vector<int64_t>* request_ids);
+
+ SyncedScrollOffset* synced_scroll_offset() { return scroll_offset_.get(); }
+
+ // Get the correct invalidation region instead of conservative Rect
+ // for layers that provide it.
+ virtual Region GetInvalidationRegion();
+
+ virtual gfx::Rect GetEnclosingRectInTargetSpace() const;
+
protected:
+ LayerImpl(LayerTreeImpl* layer_impl,
+ int id,
+ scoped_refptr<SyncedScrollOffset> scroll_offset);
LayerImpl(LayerTreeImpl* layer_impl, int id);
// Get the color and size of the layer's debug border.
@@ -587,7 +669,16 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
// Note carefully this does not affect the current layer.
void NoteLayerPropertyChangedForDescendants();
+ gfx::Rect GetScaledEnclosingRectInTargetSpace(float scale) const;
+
private:
+ void ValidateQuadResourcesInternal(DrawQuad* quad) const;
+
+ void PushScrollOffset(const gfx::ScrollOffset* scroll_offset);
+ // If the new scroll offset is assigned from the root scroll offset delegate,
+ // LayerImpl won't inform the root scroll offset delegate about the scroll
+ // change to avoid feedback.
+ void DidUpdateScrollOffset(bool is_from_root_delegate);
void NoteLayerPropertyChangedForDescendantsInternal();
virtual const char* LayerTypeAsString() const;
@@ -616,23 +707,32 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
int layer_id_;
LayerTreeImpl* layer_tree_impl_;
+ // Properties dynamically changeable on active tree.
+ scoped_refptr<SyncedScrollOffset> scroll_offset_;
+ gfx::Vector2dF bounds_delta_;
+
// Properties synchronized from the associated Layer.
gfx::Point3F transform_origin_;
gfx::Size bounds_;
- gfx::Vector2dF bounds_delta_;
- gfx::ScrollOffset scroll_offset_;
- ScrollOffsetDelegate* scroll_offset_delegate_;
LayerImpl* scroll_clip_layer_;
+
+ gfx::Vector2dF offset_to_transform_parent_;
+
bool scrollable_ : 1;
bool should_scroll_on_main_thread_ : 1;
bool have_wheel_event_handlers_ : 1;
bool have_scroll_event_handlers_ : 1;
+
+ static_assert(SCROLL_BLOCKS_ON_MAX < (1 << 3), "ScrollBlocksOn too big");
+ ScrollBlocksOn scroll_blocks_on_ : 3;
+
bool user_scrollable_horizontal_ : 1;
bool user_scrollable_vertical_ : 1;
bool stacking_order_changed_ : 1;
// Whether the "back" of this layer should draw.
bool double_sided_ : 1;
bool should_flatten_transform_ : 1;
+ bool should_flatten_transform_from_property_tree_ : 1;
// Tracks if drawing-related properties have changed since last redraw.
bool layer_property_changed_ : 1;
@@ -644,13 +744,13 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
bool draw_checkerboard_for_missing_tiles_ : 1;
bool draws_content_ : 1;
bool hide_layer_and_subtree_ : 1;
- bool force_render_surface_ : 1;
// Cache transform_'s invertibility.
bool transform_is_invertible_ : 1;
// Set for the layer that other layers are fixed to.
bool is_container_for_fixed_position_layers_ : 1;
+
Region non_fast_scrollable_region_;
Region touch_event_handler_region_;
SkColor background_color_;
@@ -662,12 +762,15 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
LayerPositionConstraint position_constraint_;
- gfx::Vector2dF scroll_delta_;
- gfx::Vector2dF sent_scroll_delta_;
- gfx::ScrollOffset last_scroll_offset_;
+ gfx::Vector2dF scroll_compensation_adjustment_;
int num_descendants_that_draw_content_;
+ gfx::Rect visible_rect_from_property_trees_;
+ int transform_tree_index_;
+ int opacity_tree_index_;
+ int clip_tree_index_;
+
// The global depth value of the center of the layer. This value is used
// to sort layers from back to front.
float draw_depth_;
@@ -717,7 +820,11 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
// hierarchy before layers can be drawn.
DrawProperties<LayerImpl> draw_properties_;
- scoped_refptr<base::debug::ConvertableToTraceFormat> debug_info_;
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> debug_info_;
+ scoped_ptr<RenderSurfaceImpl> render_surface_;
+
+ std::vector<FrameTimingRequest> frame_timing_requests_;
+ bool frame_timing_requests_dirty_;
DISALLOW_COPY_AND_ASSIGN(LayerImpl);
};
diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc
index c61f2c2ff55..d9811bc1553 100644
--- a/chromium/cc/layers/layer_impl_unittest.cc
+++ b/chromium/cc/layers/layer_impl_unittest.cc
@@ -5,6 +5,7 @@
#include "cc/layers/layer_impl.h"
#include "cc/layers/painted_scrollbar_layer_impl.h"
+#include "cc/layers/solid_color_scrollbar_layer_impl.h"
#include "cc/output/filter_operation.h"
#include "cc/output/filter_operations.h"
#include "cc/test/fake_impl_proxy.h"
@@ -12,8 +13,10 @@
#include "cc/test/fake_output_surface.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
+#include "cc/trees/tree_synchronizer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
@@ -85,7 +88,7 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
// Create a simple LayerImpl tree:
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
EXPECT_TRUE(host_impl.InitializeRenderer(FakeOutputSurface::Create3d()));
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl.active_tree(), 1);
@@ -99,6 +102,7 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>();
scroll_children->insert(scroll_child);
scroll_children->insert(root);
+ root->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> clip_parent =
LayerImpl::Create(host_impl.active_tree(), 5);
@@ -160,8 +164,8 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
root->SetDoubleSided(false)); // constructor initializes it to "true".
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->ScrollBy(arbitrary_vector2d));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetScrollDelta(gfx::Vector2d()));
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
- root->SetScrollOffset(gfx::ScrollOffset(arbitrary_vector2d)));
+ EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->PushScrollOffsetFromMainThread(
+ gfx::ScrollOffset(arbitrary_vector2d)));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetHideLayerAndSubtree(true));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetOpacity(arbitrary_number));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBlendMode(arbitrary_blend_mode));
@@ -220,7 +224,8 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
root->SetScrollDelta(gfx::Vector2d()));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
- root->SetScrollOffset(gfx::ScrollOffset(arbitrary_vector2d)));
+ root->PushScrollOffsetFromMainThread(
+ gfx::ScrollOffset(arbitrary_vector2d)));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
root->SetContentBounds(arbitrary_size));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
@@ -246,11 +251,12 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
EXPECT_TRUE(host_impl.InitializeRenderer(FakeOutputSurface::Create3d()));
host_impl.active_tree()->SetRootLayer(
LayerImpl::Create(host_impl.active_tree(), 1));
LayerImpl* root = host_impl.active_tree()->root_layer();
+ root->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> layer_ptr =
LayerImpl::Create(host_impl.active_tree(), 2);
LayerImpl* layer = layer_ptr.get();
@@ -274,6 +280,14 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
SkXfermode::Mode arbitrary_blend_mode = SkXfermode::kMultiply_Mode;
+ // Render surface functions.
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetHasRenderSurface(true));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetHasRenderSurface(true));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetHasRenderSurface(false));
+ // Create a render surface, because we must have a render surface if we have
+ // filters.
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetHasRenderSurface(true));
+
// Related filter functions.
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetFilters(arbitrary_filters));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetFilters(arbitrary_filters));
@@ -291,10 +305,10 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
layer->SetScrollDelta(arbitrary_vector2d));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
layer->SetScrollDelta(arbitrary_vector2d));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
- layer->SetScrollOffset(gfx::ScrollOffset(arbitrary_vector2d)));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- layer->SetScrollOffset(gfx::ScrollOffset(arbitrary_vector2d)));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->PushScrollOffsetFromMainThread(
+ gfx::ScrollOffset(arbitrary_vector2d)));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->PushScrollOffsetFromMainThread(
+ gfx::ScrollOffset(arbitrary_vector2d)));
// Unrelated functions, always set to new values, always set needs update.
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
@@ -355,7 +369,7 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
TEST(LayerImplTest, SafeOpaqueBackgroundColor) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
EXPECT_TRUE(host_impl.InitializeRenderer(FakeOutputSurface::Create3d()));
scoped_ptr<LayerImpl> layer = LayerImpl::Create(host_impl.active_tree(), 1);
@@ -386,7 +400,7 @@ TEST(LayerImplTest, SafeOpaqueBackgroundColor) {
TEST(LayerImplTest, TransformInvertibility) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> layer = LayerImpl::Create(host_impl.active_tree(), 1);
EXPECT_TRUE(layer->transform().IsInvertible());
@@ -416,7 +430,11 @@ TEST(LayerImplTest, TransformInvertibility) {
class LayerImplScrollTest : public testing::Test {
public:
LayerImplScrollTest()
- : host_impl_(settings(), &proxy_, &shared_bitmap_manager_), root_id_(7) {
+ : host_impl_(settings(),
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
+ root_id_(7) {
host_impl_.active_tree()->SetRootLayer(
LayerImpl::Create(host_impl_.active_tree(), root_id_));
host_impl_.active_tree()->root_layer()->AddChild(
@@ -447,6 +465,7 @@ class LayerImplScrollTest : public testing::Test {
private:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
int root_id_;
};
@@ -455,223 +474,71 @@ TEST_F(LayerImplScrollTest, ScrollByWithZeroOffset) {
// Test that LayerImpl::ScrollBy only affects ScrollDelta and total scroll
// offset is bounded by the range [0, max scroll offset].
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->BaseScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->ScrollDelta());
layer()->ScrollBy(gfx::Vector2dF(-100, 100));
- EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 80), layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 80), layer()->CurrentScrollOffset());
- EXPECT_VECTOR_EQ(layer()->ScrollDelta(), layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(layer()->ScrollDelta(), layer()->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->BaseScrollOffset());
layer()->ScrollBy(gfx::Vector2dF(100, -100));
- EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 0), layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 0), layer()->CurrentScrollOffset());
- EXPECT_VECTOR_EQ(layer()->ScrollDelta(), layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(layer()->ScrollDelta(), layer()->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->BaseScrollOffset());
}
TEST_F(LayerImplScrollTest, ScrollByWithNonZeroOffset) {
gfx::ScrollOffset scroll_offset(10, 5);
- layer()->SetScrollOffset(scroll_offset);
+ layer()->PushScrollOffsetFromMainThread(scroll_offset);
- EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(scroll_offset, layer()->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(scroll_offset, layer()->BaseScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->ScrollDelta());
layer()->ScrollBy(gfx::Vector2dF(-100, 100));
- EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 80), layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 80), layer()->CurrentScrollOffset());
- EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(scroll_offset,
- layer()->ScrollDelta()),
- layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(
+ gfx::ScrollOffsetWithDelta(scroll_offset, layer()->ScrollDelta()),
+ layer()->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(scroll_offset, layer()->BaseScrollOffset());
layer()->ScrollBy(gfx::Vector2dF(100, -100));
- EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 0), layer()->TotalScrollOffset());
-
- EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(scroll_offset,
- layer()->ScrollDelta()),
- layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
-}
-
-class ScrollDelegateIgnore : public LayerImpl::ScrollOffsetDelegate {
- public:
- void SetTotalScrollOffset(const gfx::ScrollOffset& new_value) override {
- last_attempted_set_offset_ = new_value;
- }
- gfx::ScrollOffset last_attempted_set_offset() const {
- return last_attempted_set_offset_;
- }
-
- gfx::ScrollOffset GetTotalScrollOffset() override {
- return gfx::ScrollOffset(fixed_offset_);
- }
- bool IsExternalFlingActive() const override { return false; }
- void Update() const override { }
-
- void set_fixed_offset(const gfx::Vector2dF& fixed_offset) {
- fixed_offset_ = fixed_offset;
- }
-
- private:
- gfx::ScrollOffset last_attempted_set_offset_;
- gfx::Vector2dF fixed_offset_;
-};
-
-TEST_F(LayerImplScrollTest, ScrollByWithIgnoringDelegate) {
- gfx::ScrollOffset scroll_offset(10, 5);
- layer()->SetScrollOffset(scroll_offset);
-
- EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->ScrollDelta());
-
- ScrollDelegateIgnore delegate;
- gfx::Vector2dF fixed_offset(32, 12);
- delegate.set_fixed_offset(fixed_offset);
- layer()->SetScrollOffsetDelegate(&delegate);
-
- EXPECT_VECTOR_EQ(fixed_offset, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
-
- layer()->ScrollBy(gfx::Vector2dF(-100, 100));
-
- EXPECT_VECTOR_EQ(fixed_offset, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
-
- layer()->SetScrollOffsetDelegate(nullptr);
-
- EXPECT_VECTOR_EQ(fixed_offset, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
-
- gfx::Vector2dF scroll_delta(1, 1);
- layer()->ScrollBy(scroll_delta);
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(50, 0), layer()->CurrentScrollOffset());
- EXPECT_VECTOR_EQ(fixed_offset + scroll_delta, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
+ EXPECT_VECTOR_EQ(
+ gfx::ScrollOffsetWithDelta(scroll_offset, layer()->ScrollDelta()),
+ layer()->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(scroll_offset, layer()->BaseScrollOffset());
}
-class ScrollDelegateAccept : public LayerImpl::ScrollOffsetDelegate {
- public:
- void SetTotalScrollOffset(const gfx::ScrollOffset& new_value) override {
- current_offset_ = new_value;
- }
- gfx::ScrollOffset GetTotalScrollOffset() override { return current_offset_; }
- bool IsExternalFlingActive() const override { return false; }
- void Update() const override { }
-
- private:
- gfx::ScrollOffset current_offset_;
-};
-
-TEST_F(LayerImplScrollTest, ScrollByWithAcceptingDelegate) {
- gfx::ScrollOffset scroll_offset(10, 5);
- layer()->SetScrollOffset(scroll_offset);
-
- EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->ScrollDelta());
-
- ScrollDelegateAccept delegate;
- layer()->SetScrollOffsetDelegate(&delegate);
-
- EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->ScrollDelta());
-
- layer()->ScrollBy(gfx::Vector2dF(-100, 100));
-
- EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 80), layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
-
- layer()->SetScrollOffsetDelegate(nullptr);
-
- EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 80), layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
-
- gfx::Vector2dF scroll_delta(1, 1);
- layer()->ScrollBy(scroll_delta);
-
- EXPECT_VECTOR_EQ(gfx::Vector2dF(1, 80), layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
-}
-
-TEST_F(LayerImplScrollTest, ApplySentScrollsNoDelegate) {
+TEST_F(LayerImplScrollTest, ApplySentScrollsNoListener) {
gfx::ScrollOffset scroll_offset(10, 5);
gfx::Vector2dF scroll_delta(20.5f, 8.5f);
gfx::Vector2d sent_scroll_delta(12, -3);
- layer()->SetScrollOffset(scroll_offset);
- layer()->ScrollBy(scroll_delta);
- layer()->SetSentScrollDelta(sent_scroll_delta);
+ layer()->PushScrollOffsetFromMainThread(scroll_offset);
+ layer()->ScrollBy(sent_scroll_delta);
+ layer()->PullDeltaForMainThread();
+ layer()->SetCurrentScrollOffset(scroll_offset +
+ gfx::ScrollOffset(scroll_delta));
EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(scroll_offset, scroll_delta),
- layer()->TotalScrollOffset());
+ layer()->CurrentScrollOffset());
EXPECT_VECTOR_EQ(scroll_delta, layer()->ScrollDelta());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
- EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
+ EXPECT_VECTOR_EQ(scroll_offset, layer()->BaseScrollOffset());
layer()->ApplySentScrollDeltasFromAbortedCommit();
EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(scroll_offset, scroll_delta),
- layer()->TotalScrollOffset());
+ layer()->CurrentScrollOffset());
EXPECT_VECTOR_EQ(scroll_delta - sent_scroll_delta, layer()->ScrollDelta());
EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(scroll_offset, sent_scroll_delta),
- layer()->scroll_offset());
- EXPECT_VECTOR_EQ(gfx::Vector2d(), layer()->sent_scroll_delta());
-}
-
-TEST_F(LayerImplScrollTest, ApplySentScrollsWithIgnoringDelegate) {
- gfx::ScrollOffset scroll_offset(10, 5);
- gfx::Vector2d sent_scroll_delta(12, -3);
- gfx::Vector2dF fixed_offset(32, 12);
-
- layer()->SetScrollOffset(scroll_offset);
- ScrollDelegateIgnore delegate;
- delegate.set_fixed_offset(fixed_offset);
- layer()->SetScrollOffsetDelegate(&delegate);
- layer()->SetSentScrollDelta(sent_scroll_delta);
-
- EXPECT_VECTOR_EQ(fixed_offset, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
- EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
-
- layer()->ApplySentScrollDeltasFromAbortedCommit();
-
- EXPECT_VECTOR_EQ(fixed_offset, delegate.last_attempted_set_offset());
-
- EXPECT_VECTOR_EQ(fixed_offset, layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(scroll_offset, sent_scroll_delta),
- layer()->scroll_offset());
- EXPECT_VECTOR_EQ(gfx::Vector2d(), layer()->sent_scroll_delta());
-}
-
-TEST_F(LayerImplScrollTest, ApplySentScrollsWithAcceptingDelegate) {
- gfx::ScrollOffset scroll_offset(10, 5);
- gfx::Vector2d sent_scroll_delta(12, -3);
- gfx::Vector2dF scroll_delta(20.5f, 8.5f);
-
- layer()->SetScrollOffset(scroll_offset);
- ScrollDelegateAccept delegate;
- layer()->SetScrollOffsetDelegate(&delegate);
- layer()->ScrollBy(scroll_delta);
- layer()->SetSentScrollDelta(sent_scroll_delta);
-
- EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(scroll_offset, scroll_delta),
- layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
- EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
-
- layer()->ApplySentScrollDeltasFromAbortedCommit();
-
- EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(scroll_offset, scroll_delta),
- layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(scroll_offset, sent_scroll_delta),
- layer()->scroll_offset());
- EXPECT_VECTOR_EQ(gfx::Vector2d(), layer()->sent_scroll_delta());
+ layer()->BaseScrollOffset());
}
TEST_F(LayerImplScrollTest, ScrollUserUnscrollableLayer) {
@@ -679,41 +546,41 @@ TEST_F(LayerImplScrollTest, ScrollUserUnscrollableLayer) {
gfx::Vector2dF scroll_delta(20.5f, 8.5f);
layer()->set_user_scrollable_vertical(false);
- layer()->SetScrollOffset(scroll_offset);
+ layer()->PushScrollOffsetFromMainThread(scroll_offset);
gfx::Vector2dF unscrolled = layer()->ScrollBy(scroll_delta);
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 8.5f), unscrolled);
- EXPECT_VECTOR_EQ(gfx::Vector2dF(30.5f, 5), layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(30.5f, 5), layer()->CurrentScrollOffset());
}
-TEST_F(LayerImplScrollTest, PushPropertiesToMirrorsTotalScrollOffset) {
+TEST_F(LayerImplScrollTest, PushPropertiesToMirrorsCurrentScrollOffset) {
gfx::ScrollOffset scroll_offset(10, 5);
gfx::Vector2dF scroll_delta(12, 18);
host_impl().CreatePendingTree();
- layer()->SetScrollOffset(scroll_offset);
+ layer()->PushScrollOffsetFromMainThread(scroll_offset);
gfx::Vector2dF unscrolled = layer()->ScrollBy(scroll_delta);
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), unscrolled);
- EXPECT_VECTOR_EQ(gfx::Vector2dF(22, 23), layer()->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(22, 23), layer()->CurrentScrollOffset());
- layer()->SetSentScrollDelta(scroll_delta);
+ layer()->PullDeltaForMainThread();
- scoped_ptr<LayerImpl> pending_layer =
- LayerImpl::Create(host_impl().sync_tree(), layer()->id());
- pending_layer->SetScrollOffset(layer()->TotalScrollOffset());
+ scoped_ptr<LayerImpl> pending_layer = LayerImpl::Create(
+ host_impl().sync_tree(), layer()->id(), layer()->synced_scroll_offset());
+ pending_layer->PushScrollOffsetFromMainThread(layer()->CurrentScrollOffset());
pending_layer->PushPropertiesTo(layer());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(22, 23), layer()->TotalScrollOffset());
- EXPECT_VECTOR_EQ(layer()->TotalScrollOffset(),
- pending_layer->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(22, 23), layer()->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(layer()->CurrentScrollOffset(),
+ pending_layer->CurrentScrollOffset());
}
TEST_F(LayerImplScrollTest, SetNewScrollbarParameters) {
gfx::ScrollOffset scroll_offset(10, 5);
- layer()->SetScrollOffset(scroll_offset);
+ layer()->PushScrollOffsetFromMainThread(scroll_offset);
scoped_ptr<PaintedScrollbarLayerImpl> vertical_scrollbar(
PaintedScrollbarLayerImpl::Create(tree(), 100, VERTICAL));
@@ -736,5 +603,135 @@ TEST_F(LayerImplScrollTest, SetNewScrollbarParameters) {
EXPECT_EQ(scroll_offset.x(), horizontal_scrollbar->current_pos());
}
+class LayerImplScrollbarSyncTest : public testing::Test {
+ public:
+ enum {
+ ROOT = 1,
+ IV_CLIP = 2,
+ PAGE = 3,
+ IV_SCROLL = 4,
+ SCROLLBAR = 5,
+ OLD_ROOT = 6,
+ OV_CLIP = 7,
+ OV_SCROLL = 8,
+ };
+ enum TreeID {
+ PENDING,
+ ACTIVE
+ };
+
+ LayerImplScrollbarSyncTest()
+ : host_impl_(settings(),
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_) {
+ host_impl_.CreatePendingTree();
+
+ CreateLayers(host_impl_.pending_tree());
+ CreateLayers(host_impl_.active_tree());
+ }
+
+ void CreateLayers(LayerTreeImpl * tree) {
+ tree->SetRootLayer(LayerImpl::Create(tree, ROOT));
+ LayerImpl * root = tree->root_layer();
+ ASSERT_TRUE(root != nullptr);
+
+ int hierarchy[] = {IV_CLIP, PAGE, IV_SCROLL, OLD_ROOT, OV_CLIP, OV_SCROLL};
+ LayerImpl * parent = root;
+ for (int child_id : hierarchy) {
+ parent->AddChild(LayerImpl::Create(tree, child_id));
+ parent = tree->LayerById(child_id);
+ ASSERT_TRUE(parent != nullptr);
+ }
+
+ root->AddChild(
+ SolidColorScrollbarLayerImpl::Create(tree, SCROLLBAR, HORIZONTAL,
+ 5, 5, false, true));
+ }
+
+ LayerImpl* layer(int id, TreeID tree_id) {
+ LayerTreeImpl* tree =
+ ((tree_id == PENDING) ?
+ host_impl_.pending_tree() : host_impl_.active_tree());
+
+ assert(tree);
+ return tree->LayerById(id);
+ }
+
+ bool LayerHasScrollbar(int id, TreeID tree_id) {
+ return layer(id, tree_id)->HasScrollbar(HORIZONTAL);
+ }
+
+ ScrollbarLayerImplBase* pending_scrollbar() {
+ LayerImpl* layer_impl = layer(SCROLLBAR, PENDING);
+ assert(layer_impl);
+ return layer_impl->ToScrollbarLayer();
+ }
+
+ LayerImpl* pending_root() {
+ LayerImpl * result = layer(ROOT, PENDING);
+ assert(result);
+ return result;
+ }
+
+ LayerImpl* active_root() {
+ LayerImpl * result = layer(ROOT, ACTIVE);
+ assert(result);
+ return result;
+ }
+
+ LayerTreeSettings settings() {
+ LayerTreeSettings settings;
+ settings.use_pinch_virtual_viewport = true;
+ return settings;
+ }
+
+ private:
+ FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
+ FakeLayerTreeHostImpl host_impl_;
+};
+
+TEST_F(LayerImplScrollbarSyncTest, LayerImplBecomesScrollable) {
+ // In the beginning IV_SCROLL layer is not scrollable.
+ ASSERT_FALSE(layer(IV_SCROLL, PENDING)->scrollable());
+
+ // For pinch virtual viewport the clip layer is the inner viewport
+ // clip layer (IV_CLIP) and the scroll one is the outer viewport
+ // scroll layer (OV_SCROLL).
+ pending_scrollbar()->SetScrollLayerAndClipLayerByIds(OV_SCROLL, IV_CLIP);
+
+ ASSERT_TRUE(LayerHasScrollbar(OV_SCROLL, PENDING));
+ ASSERT_TRUE(LayerHasScrollbar(IV_CLIP, PENDING));
+
+ // Synchronize with the active tree.
+ TreeSynchronizer::PushProperties(pending_root(), active_root());
+
+ ASSERT_TRUE(LayerHasScrollbar(OV_SCROLL, ACTIVE));
+ ASSERT_TRUE(LayerHasScrollbar(IV_CLIP, ACTIVE));
+
+ // Make IV_SCROLL layer scrollable.
+ layer(IV_SCROLL, PENDING)->SetScrollClipLayer(IV_CLIP);
+ layer(IV_SCROLL, PENDING)->SetNeedsPushProperties();
+ ASSERT_TRUE(layer(IV_SCROLL, PENDING)->scrollable());
+
+ pending_scrollbar()->SetScrollLayerAndClipLayerByIds(OV_SCROLL, IV_CLIP);
+
+ // Now IV_CLIP layer should also receive the scrollbar.
+ ASSERT_TRUE(LayerHasScrollbar(OV_SCROLL, PENDING));
+ ASSERT_TRUE(LayerHasScrollbar(IV_CLIP, PENDING));
+ ASSERT_TRUE(LayerHasScrollbar(IV_SCROLL, PENDING));
+
+ // Synchronize with the active tree.
+ TreeSynchronizer::PushProperties(pending_root(), active_root());
+
+ ASSERT_TRUE(layer(IV_SCROLL, ACTIVE)->scrollable());
+
+ ASSERT_TRUE(LayerHasScrollbar(OV_SCROLL, ACTIVE));
+ ASSERT_TRUE(LayerHasScrollbar(IV_CLIP, ACTIVE));
+ ASSERT_TRUE(LayerHasScrollbar(IV_SCROLL, ACTIVE));
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/layer_perftest.cc b/chromium/cc/layers/layer_perftest.cc
index fcd08446f40..c7cac01f5b2 100644
--- a/chromium/cc/layers/layer_perftest.cc
+++ b/chromium/cc/layers/layer_perftest.cc
@@ -4,13 +4,14 @@
#include "cc/layers/layer.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/debug/lap_timer.h"
#include "cc/resources/layer_painter.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_layer_tree_host_impl.h"
-
+#include "cc/test/test_task_graph_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -30,26 +31,27 @@ class MockLayerPainter : public LayerPainter {
class LayerPerfTest : public testing::Test {
public:
LayerPerfTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
fake_client_(FakeLayerTreeHostClient::DIRECT_3D),
timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval) {}
protected:
- virtual void SetUp() override {
+ void SetUp() override {
layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
layer_tree_host_->InitializeSingleThreaded(
- &fake_client_, base::MessageLoopProxy::current());
+ &fake_client_, base::ThreadTaskRunnerHandle::Get(), nullptr);
}
- virtual void TearDown() override {
+ void TearDown() override {
layer_tree_host_->SetRootLayer(nullptr);
layer_tree_host_ = nullptr;
}
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
FakeLayerTreeHostClient fake_client_;
diff --git a/chromium/cc/layers/layer_position_constraint_unittest.cc b/chromium/cc/layers/layer_position_constraint_unittest.cc
index 5953f108389..1eea9c98b44 100644
--- a/chromium/cc/layers/layer_position_constraint_unittest.cc
+++ b/chromium/cc/layers/layer_position_constraint_unittest.cc
@@ -11,6 +11,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_common.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -63,7 +64,8 @@ void ExecuteCalculateDrawProperties(LayerImpl* root_layer) {
class LayerPositionConstraintTest : public testing::Test {
public:
- LayerPositionConstraintTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {
+ LayerPositionConstraintTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {
root_ = CreateTreeForTest();
scroll_ = root_->children()[0];
fixed_to_top_left_.set_is_fixed_position(true);
@@ -84,6 +86,7 @@ class LayerPositionConstraintTest : public testing::Test {
scoped_ptr<LayerImpl> great_grand_child =
LayerImpl::Create(host_impl_.active_tree(), 4);
+ root->SetHasRenderSurface(true);
gfx::Transform IdentityMatrix;
gfx::Point3F transform_origin;
gfx::PointF position;
@@ -126,6 +129,7 @@ class LayerPositionConstraintTest : public testing::Test {
protected:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<LayerImpl> root_;
LayerImpl* scroll_;
@@ -599,7 +603,7 @@ TEST_F(LayerPositionConstraintTest,
child->SetIsContainerForFixedPositionLayers(true);
grand_child->SetPosition(gfx::PointF(8.f, 6.f));
- grand_child->SetForceRenderSurface(true);
+ grand_child->SetHasRenderSurface(true);
great_grand_child->SetPositionConstraint(fixed_to_top_left_);
great_grand_child->SetDrawsContent(true);
@@ -739,9 +743,9 @@ TEST_F(LayerPositionConstraintTest,
// Actually set up the scenario here.
child->SetIsContainerForFixedPositionLayers(true);
grand_child->SetPosition(gfx::PointF(8.f, 6.f));
- grand_child->SetForceRenderSurface(true);
+ grand_child->SetHasRenderSurface(true);
great_grand_child->SetPosition(gfx::PointF(40.f, 60.f));
- great_grand_child->SetForceRenderSurface(true);
+ great_grand_child->SetHasRenderSurface(true);
fixed_position_child->SetPositionConstraint(fixed_to_top_left_);
fixed_position_child->SetDrawsContent(true);
@@ -907,7 +911,7 @@ TEST_F(LayerPositionConstraintTest,
LayerImpl* grand_child = child->children()[0];
child->SetIsContainerForFixedPositionLayers(true);
- child->SetForceRenderSurface(true);
+ child->SetHasRenderSurface(true);
grand_child->SetPositionConstraint(fixed_to_top_left_);
grand_child->SetDrawsContent(true);
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index ecdd9160736..6b4d36b9412 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -4,9 +4,12 @@
#include "cc/layers/layer.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/animation/keyframed_animation_curve.h"
#include "cc/base/math_util.h"
#include "cc/layers/layer_impl.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/resources/layer_painter.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/fake_impl_proxy.h"
@@ -16,6 +19,7 @@
#include "cc/test/layer_test_common.h"
#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -40,9 +44,11 @@ namespace {
class MockLayerTreeHost : public LayerTreeHost {
public:
- explicit MockLayerTreeHost(FakeLayerTreeHostClient* client)
- : LayerTreeHost(client, nullptr, nullptr, LayerTreeSettings()) {
- InitializeSingleThreaded(client, base::MessageLoopProxy::current());
+ MockLayerTreeHost(LayerTreeHostSingleThreadClient* single_thread_client,
+ LayerTreeHost::InitParams* params)
+ : LayerTreeHost(params) {
+ InitializeSingleThreaded(single_thread_client,
+ base::ThreadTaskRunnerHandle::Get(), nullptr);
}
MOCK_METHOD0(SetNeedsCommit, void());
@@ -58,15 +64,20 @@ class MockLayerPainter : public LayerPainter {
class LayerTest : public testing::Test {
public:
LayerTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
protected:
- virtual void SetUp() override {
- layer_tree_host_.reset(new StrictMock<MockLayerTreeHost>(&fake_client_));
+ void SetUp() override {
+ LayerTreeHost::InitParams params;
+ LayerTreeSettings settings;
+ params.client = &fake_client_;
+ params.settings = &settings;
+ layer_tree_host_.reset(
+ new StrictMock<MockLayerTreeHost>(&fake_client_, &params));
}
- virtual void TearDown() override {
+ void TearDown() override {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber());
parent_ = nullptr;
@@ -129,6 +140,7 @@ class LayerTest : public testing::Test {
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
FakeLayerTreeHostClient fake_client_;
@@ -736,8 +748,9 @@ TEST_F(LayerTest,
1.0,
0,
100);
- impl_layer->layer_animation_controller()->GetAnimation(Animation::Transform)->
- set_is_impl_only(true);
+ impl_layer->layer_animation_controller()
+ ->GetAnimation(Animation::TRANSFORM)
+ ->set_is_impl_only(true);
transform.Rotate(45.0);
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform));
@@ -777,8 +790,9 @@ TEST_F(LayerTest,
0.3f,
0.7f,
false);
- impl_layer->layer_animation_controller()->GetAnimation(Animation::Opacity)->
- set_is_impl_only(true);
+ impl_layer->layer_animation_controller()
+ ->GetAnimation(Animation::OPACITY)
+ ->set_is_impl_only(true);
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.75f));
EXPECT_FALSE(impl_layer->LayerPropertyChanged());
@@ -813,8 +827,9 @@ TEST_F(LayerTest,
impl_layer->ResetAllChangeTrackingForSubtree();
AddAnimatedFilterToController(
impl_layer->layer_animation_controller(), 1.0, 1.f, 2.f);
- impl_layer->layer_animation_controller()->GetAnimation(Animation::Filter)->
- set_is_impl_only(true);
+ impl_layer->layer_animation_controller()
+ ->GetAnimation(Animation::FILTER)
+ ->set_is_impl_only(true);
filters.Append(FilterOperation::CreateSepiaFilter(0.5f));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFilters(filters));
@@ -928,24 +943,16 @@ class LayerTreeHostFactory {
shared_bitmap_manager_(new TestSharedBitmapManager),
gpu_memory_buffer_manager_(new TestGpuMemoryBufferManager) {}
- scoped_ptr<LayerTreeHost> Create() {
- return LayerTreeHost::CreateSingleThreaded(
- &client_,
- &client_,
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
- LayerTreeSettings(),
- base::MessageLoopProxy::current()).Pass();
- }
+ scoped_ptr<LayerTreeHost> Create() { return Create(LayerTreeSettings()); }
scoped_ptr<LayerTreeHost> Create(LayerTreeSettings settings) {
- return LayerTreeHost::CreateSingleThreaded(
- &client_,
- &client_,
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
- settings,
- base::MessageLoopProxy::current()).Pass();
+ LayerTreeHost::InitParams params;
+ params.client = &client_;
+ params.shared_bitmap_manager = shared_bitmap_manager_.get();
+ params.gpu_memory_buffer_manager = gpu_memory_buffer_manager_.get();
+ params.settings = &settings;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ return LayerTreeHost::CreateSingleThreaded(&client_, &params);
}
private:
@@ -1140,10 +1147,11 @@ TEST(LayerLayerTreeHostTest, DestroyHostWithNonNullRootLayer) {
static bool AddTestAnimation(Layer* layer) {
scoped_ptr<KeyframedFloatAnimationCurve> curve =
KeyframedFloatAnimationCurve::Create();
- curve->AddKeyframe(FloatKeyframe::Create(0.0, 0.3f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(1.0, 0.7f, nullptr));
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.3f, nullptr));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 0.7f, nullptr));
scoped_ptr<Animation> animation =
- Animation::Create(curve.Pass(), 0, 0, Animation::Opacity);
+ Animation::Create(curve.Pass(), 0, 0, Animation::OPACITY);
return layer->AddAnimation(animation.Pass());
}
@@ -1249,5 +1257,73 @@ TEST_F(LayerTest, DrawsContentChangedInSetLayerTreeHost) {
EXPECT_EQ(1, root_layer->NumDescendantsThatDrawContent());
}
+void ReceiveCopyOutputResult(int* result_count,
+ scoped_ptr<CopyOutputResult> result) {
+ ++(*result_count);
+}
+
+TEST_F(LayerTest, DedupesCopyOutputRequestsBySource) {
+ scoped_refptr<Layer> layer = Layer::Create();
+ int result_count = 0;
+
+ // Create identical requests without the source being set, and expect the
+ // layer does not abort either one.
+ scoped_ptr<CopyOutputRequest> request = CopyOutputRequest::CreateRequest(
+ base::Bind(&ReceiveCopyOutputResult, &result_count));
+ layer->RequestCopyOfOutput(request.Pass());
+ EXPECT_EQ(0, result_count);
+ request = CopyOutputRequest::CreateRequest(
+ base::Bind(&ReceiveCopyOutputResult, &result_count));
+ layer->RequestCopyOfOutput(request.Pass());
+ EXPECT_EQ(0, result_count);
+
+ // When the layer is destroyed, expect both requests to be aborted.
+ layer = nullptr;
+ EXPECT_EQ(2, result_count);
+
+ layer = Layer::Create();
+ result_count = 0;
+
+ // Create identical requests, but this time the source is being set. Expect
+ // the first request from |this| source aborts immediately when the second
+ // request from |this| source is made.
+ int did_receive_first_result_from_this_source = 0;
+ request = CopyOutputRequest::CreateRequest(base::Bind(
+ &ReceiveCopyOutputResult, &did_receive_first_result_from_this_source));
+ request->set_source(this);
+ layer->RequestCopyOfOutput(request.Pass());
+ EXPECT_EQ(0, did_receive_first_result_from_this_source);
+ // Make a request from a different source.
+ int did_receive_result_from_different_source = 0;
+ request = CopyOutputRequest::CreateRequest(base::Bind(
+ &ReceiveCopyOutputResult, &did_receive_result_from_different_source));
+ request->set_source(reinterpret_cast<void*>(0xdeadbee0));
+ layer->RequestCopyOfOutput(request.Pass());
+ EXPECT_EQ(0, did_receive_result_from_different_source);
+ // Make a request without specifying the source.
+ int did_receive_result_from_anonymous_source = 0;
+ request = CopyOutputRequest::CreateRequest(base::Bind(
+ &ReceiveCopyOutputResult, &did_receive_result_from_anonymous_source));
+ layer->RequestCopyOfOutput(request.Pass());
+ EXPECT_EQ(0, did_receive_result_from_anonymous_source);
+ // Make the second request from |this| source.
+ int did_receive_second_result_from_this_source = 0;
+ request = CopyOutputRequest::CreateRequest(base::Bind(
+ &ReceiveCopyOutputResult, &did_receive_second_result_from_this_source));
+ request->set_source(this);
+ layer->RequestCopyOfOutput(request.Pass()); // First request to be aborted.
+ EXPECT_EQ(1, did_receive_first_result_from_this_source);
+ EXPECT_EQ(0, did_receive_result_from_different_source);
+ EXPECT_EQ(0, did_receive_result_from_anonymous_source);
+ EXPECT_EQ(0, did_receive_second_result_from_this_source);
+
+ // When the layer is destroyed, the other three requests should be aborted.
+ layer = nullptr;
+ EXPECT_EQ(1, did_receive_first_result_from_this_source);
+ EXPECT_EQ(1, did_receive_result_from_different_source);
+ EXPECT_EQ(1, did_receive_result_from_anonymous_source);
+ EXPECT_EQ(1, did_receive_second_result_from_this_source);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/layer_utils.h b/chromium/cc/layers/layer_utils.h
index 396f0704109..bef37f4c7c6 100644
--- a/chromium/cc/layers/layer_utils.h
+++ b/chromium/cc/layers/layer_utils.h
@@ -8,21 +8,21 @@
#include "cc/base/cc_export.h"
namespace gfx {
- class BoxF;
+class BoxF;
} // namespace gfx
namespace cc {
- class LayerImpl;
+class LayerImpl;
- class CC_EXPORT LayerUtils {
- public:
- // Computes a box in screen space that should entirely contain the layer's
- // bounds through the entirety of the layer's current animation. Returns
- // true and sets |out| to the inflation if there are animations that can
- // inflate bounds in the path to the root layer and that it was able to
- // inflate correctly. Returns false otherwise.
- static bool GetAnimationBounds(const LayerImpl& layer, gfx::BoxF* out);
- };
+class CC_EXPORT LayerUtils {
+ public:
+ // Computes a box in screen space that should entirely contain the layer's
+ // bounds through the entirety of the layer's current animation. Returns
+ // true and sets |out| to the inflation if there are animations that can
+ // inflate bounds in the path to the root layer and that it was able to
+ // inflate correctly. Returns false otherwise.
+ static bool GetAnimationBounds(const LayerImpl& layer, gfx::BoxF* out);
+};
} // namespace cc
diff --git a/chromium/cc/layers/layer_utils_unittest.cc b/chromium/cc/layers/layer_utils_unittest.cc
index 1eb1986eace..534a691e47b 100644
--- a/chromium/cc/layers/layer_utils_unittest.cc
+++ b/chromium/cc/layers/layer_utils_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/test/gfx_util.h"
@@ -24,8 +25,8 @@ float diagonal(float width, float height) {
class LayerUtilsGetAnimationBoundsTest : public testing::Test {
public:
LayerUtilsGetAnimationBoundsTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_),
- root_(CreateThreeNodeTree(host_impl_)),
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
+ root_(CreateThreeNodeTree(&host_impl_)),
parent_(root_->children()[0]),
child_(parent_->children()[0]) {}
@@ -35,16 +36,17 @@ class LayerUtilsGetAnimationBoundsTest : public testing::Test {
private:
static scoped_ptr<LayerImpl> CreateThreeNodeTree(
- LayerTreeHostImpl& host_impl) {
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
- root->AddChild(LayerImpl::Create(host_impl.active_tree(), 2));
- root->children()[0]
- ->AddChild(LayerImpl::Create(host_impl.active_tree(), 3));
+ LayerTreeHostImpl* host_impl) {
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl->active_tree(), 1);
+ root->AddChild(LayerImpl::Create(host_impl->active_tree(), 2));
+ root->children()[0]->AddChild(
+ LayerImpl::Create(host_impl->active_tree(), 3));
return root.Pass();
}
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<LayerImpl> root_;
LayerImpl* parent_;
diff --git a/chromium/cc/layers/nine_patch_layer_impl.cc b/chromium/cc/layers/nine_patch_layer_impl.cc
index 1c76d110a9f..fc2f4575262 100644
--- a/chromium/cc/layers/nine_patch_layer_impl.cc
+++ b/chromium/cc/layers/nine_patch_layer_impl.cc
@@ -82,7 +82,6 @@ void NinePatchLayerImpl::CheckGeometryLimitations() {
void NinePatchLayerImpl::AppendQuads(
RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
CheckGeometryLimitations();
SharedQuadState* shared_quad_state =
@@ -102,6 +101,7 @@ void NinePatchLayerImpl::AppendQuads(
return;
static const bool flipped = false;
+ static const bool nearest_neighbor = false;
static const bool premultiplied_alpha = true;
DCHECK(!bounds().IsEmpty());
@@ -207,14 +207,15 @@ void NinePatchLayerImpl::AppendQuads(
uv_top.width(),
uv_left.height());
- // Nothing is opaque here.
- // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness?
gfx::Rect opaque_rect;
gfx::Rect visible_rect;
const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const bool opaque = layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_);
visible_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(layer_top_left);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ layer_top_left);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -228,11 +229,15 @@ void NinePatchLayerImpl::AppendQuads(
uv_top_left.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
visible_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(layer_top_right);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ layer_top_right);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -246,11 +251,15 @@ void NinePatchLayerImpl::AppendQuads(
uv_top_right.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
visible_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom_left);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ layer_bottom_left);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -264,11 +273,15 @@ void NinePatchLayerImpl::AppendQuads(
uv_bottom_left.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
visible_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom_right);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ layer_bottom_right);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -282,10 +295,15 @@ void NinePatchLayerImpl::AppendQuads(
uv_bottom_right.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
- visible_rect = occlusion_in_content_space.GetUnoccludedContentRect(layer_top);
+ visible_rect =
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ layer_top);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -299,11 +317,15 @@ void NinePatchLayerImpl::AppendQuads(
uv_top.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
visible_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(layer_left);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ layer_left);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -317,11 +339,15 @@ void NinePatchLayerImpl::AppendQuads(
uv_left.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
visible_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(layer_right);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ layer_right);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -335,11 +361,15 @@ void NinePatchLayerImpl::AppendQuads(
uv_right.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
visible_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ layer_bottom);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -353,12 +383,16 @@ void NinePatchLayerImpl::AppendQuads(
uv_bottom.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
if (fill_center_) {
visible_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(layer_center);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ layer_center);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -372,7 +406,9 @@ void NinePatchLayerImpl::AppendQuads(
uv_center.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
}
}
diff --git a/chromium/cc/layers/nine_patch_layer_impl.h b/chromium/cc/layers/nine_patch_layer_impl.h
index 5320d398c32..948758a876a 100644
--- a/chromium/cc/layers/nine_patch_layer_impl.h
+++ b/chromium/cc/layers/nine_patch_layer_impl.h
@@ -61,7 +61,6 @@ class CC_EXPORT NinePatchLayerImpl : public UIResourceLayerImpl {
void PushPropertiesTo(LayerImpl* layer) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
base::DictionaryValue* LayerTreeAsJson() const override;
diff --git a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
index 695d827675d..a71f92ef0dd 100644
--- a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -9,6 +9,7 @@
#include "cc/resources/ui_resource_bitmap.h"
#include "cc/resources/ui_resource_client.h"
#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_ui_resource_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_test_common.h"
@@ -45,12 +46,14 @@ void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size,
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ host_impl.InitializeRenderer(FakeOutputSurface::Create3d());
+
scoped_ptr<NinePatchLayerImpl> layer =
NinePatchLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
layer->SetBounds(layer_size);
layer->SetContentBounds(layer_size);
- layer->CreateRenderSurface();
+ layer->SetHasRenderSurface(true);
layer->draw_properties().render_target = layer.get();
UIResourceId uid = 1;
@@ -62,7 +65,7 @@ void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size,
layer->SetImageBounds(bitmap_size);
layer->SetLayout(aperture_rect, border, fill_center);
AppendQuadsData data;
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
// Verify quad rects
const QuadList& quads = render_pass->quad_list;
@@ -80,7 +83,7 @@ void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size,
// Check if the left-over quad is the same size as the mapped aperture quad in
// layer space.
if (!fill_center) {
- EXPECT_RECT_EQ(expected_remaining, gfx::ToEnclosedRect(remaining.bounds()));
+ EXPECT_EQ(expected_remaining, gfx::ToEnclosedRect(remaining.bounds()));
} else {
EXPECT_TRUE(remaining.bounds().IsEmpty());
}
@@ -97,7 +100,7 @@ void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size,
}
if (!fill_center) {
- EXPECT_RECT_EQ(aperture_rect, tex_remaining.bounds());
+ EXPECT_EQ(aperture_rect, tex_remaining.bounds());
Region aperture_region(aperture_rect);
EXPECT_EQ(aperture_region, tex_remaining);
} else {
@@ -271,5 +274,70 @@ TEST(NinePatchLayerImplTest, Occlusion) {
}
}
+TEST(NinePatchLayerImplTest, OpaqueRect) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ SkBitmap sk_bitmap_opaque;
+ sk_bitmap_opaque.allocN32Pixels(10, 10);
+ sk_bitmap_opaque.setImmutable();
+ sk_bitmap_opaque.setAlphaType(kOpaque_SkAlphaType);
+
+ UIResourceId uid_opaque = 6;
+ UIResourceBitmap bitmap_opaque(sk_bitmap_opaque);
+ impl.host_impl()->CreateUIResource(uid_opaque, bitmap_opaque);
+
+ SkBitmap sk_bitmap_alpha;
+ sk_bitmap_alpha.allocN32Pixels(10, 10);
+ sk_bitmap_alpha.setImmutable();
+ sk_bitmap_alpha.setAlphaType(kUnpremul_SkAlphaType);
+
+ UIResourceId uid_alpha = 7;
+ UIResourceBitmap bitmap_alpha(sk_bitmap_alpha);
+
+ impl.host_impl()->CreateUIResource(uid_alpha, bitmap_alpha);
+
+ NinePatchLayerImpl *nine_patch_layer_impl =
+ impl.AddChildToRoot<NinePatchLayerImpl>();
+ nine_patch_layer_impl->SetBounds(layer_size);
+ nine_patch_layer_impl->SetContentBounds(layer_size);
+ nine_patch_layer_impl->SetDrawsContent(true);
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("Use opaque image");
+
+ nine_patch_layer_impl->SetUIResourceId(uid_opaque);
+ nine_patch_layer_impl->SetImageBounds(gfx::Size(10, 10));
+
+ gfx::Rect aperture = gfx::Rect(3, 3, 4, 4);
+ gfx::Rect border = gfx::Rect(300, 300, 400, 400);
+ nine_patch_layer_impl->SetLayout(aperture, border, true);
+
+ impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, gfx::Rect());
+
+ const QuadList &quad_list = impl.quad_list();
+ for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin();
+ it != quad_list.BackToFrontEnd(); ++it)
+ EXPECT_FALSE(it->ShouldDrawWithBlending());
+ }
+
+ {
+ SCOPED_TRACE("Use tranparent image");
+
+ nine_patch_layer_impl->SetUIResourceId(uid_alpha);
+
+ impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, gfx::Rect());
+
+ const QuadList &quad_list = impl.quad_list();
+ for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin();
+ it != quad_list.BackToFrontEnd(); ++it)
+ EXPECT_TRUE(it->ShouldDrawWithBlending());
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/nine_patch_layer_unittest.cc b/chromium/cc/layers/nine_patch_layer_unittest.cc
index 587fb07c452..1783ba9fa41 100644
--- a/chromium/cc/layers/nine_patch_layer_unittest.cc
+++ b/chromium/cc/layers/nine_patch_layer_unittest.cc
@@ -34,11 +34,11 @@ class NinePatchLayerTest : public testing::Test {
NinePatchLayerTest() : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
protected:
- virtual void SetUp() {
+ void SetUp() override {
layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
}
- virtual void TearDown() {
+ void TearDown() override {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
}
diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc
index 83c12e86509..d82ef989589 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer.cc
@@ -4,11 +4,15 @@
#include "cc/layers/painted_scrollbar_layer.h"
+#include <algorithm>
+
#include "base/auto_reset.h"
#include "base/basictypes.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/base/math_util.h"
#include "cc/layers/painted_scrollbar_layer_impl.h"
#include "cc/resources/ui_resource_bitmap.h"
+#include "cc/trees/draw_property_utils.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "skia/ext/platform_canvas.h"
@@ -16,6 +20,7 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSize.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/skia_util.h"
namespace cc {
@@ -38,6 +43,7 @@ PaintedScrollbarLayer::PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar,
: scrollbar_(scrollbar.Pass()),
scroll_layer_id_(scroll_layer_id),
clip_layer_id_(Layer::INVALID_ID),
+ internal_contents_scale_(0.f),
thumb_thickness_(scrollbar_->ThumbThickness()),
thumb_length_(scrollbar_->ThumbLength()),
is_overlay_(scrollbar_->IsOverlay()),
@@ -82,10 +88,10 @@ int PaintedScrollbarLayer::MaxTextureSize() {
}
float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
- // If the scaled content_bounds() is bigger than the max texture size of the
- // device, we need to clamp it by rescaling, since content_bounds() is used
+ // If the scaled bounds() is bigger than the max texture size of the
+ // device, we need to clamp it by rescaling, since this is used
// below to set the texture size.
- gfx::Size scaled_bounds = ComputeContentBoundsForScale(scale, scale);
+ gfx::Size scaled_bounds = gfx::ToCeiledSize(gfx::ScaleSize(bounds(), scale));
if (scaled_bounds.width() > MaxTextureSize() ||
scaled_bounds.height() > MaxTextureSize()) {
if (scaled_bounds.width() > scaled_bounds.height())
@@ -96,26 +102,17 @@ float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
return scale;
}
-void PaintedScrollbarLayer::CalculateContentsScale(
- float ideal_contents_scale,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) {
- ContentsScalingLayer::CalculateContentsScale(
- ClampScaleToMaxTextureSize(ideal_contents_scale),
- contents_scale_x,
- contents_scale_y,
- content_bounds);
-}
-
void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
- ContentsScalingLayer::PushPropertiesTo(layer);
+ Layer::PushPropertiesTo(layer);
PushScrollClipPropertiesTo(layer);
PaintedScrollbarLayerImpl* scrollbar_layer =
static_cast<PaintedScrollbarLayerImpl*>(layer);
+ scrollbar_layer->set_internal_contents_scale_and_bounds(
+ internal_contents_scale_, internal_content_bounds_);
+
scrollbar_layer->SetThumbThickness(thumb_thickness_);
scrollbar_layer->SetThumbLength(thumb_length_);
if (orientation() == HORIZONTAL) {
@@ -160,7 +157,7 @@ void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
thumb_resource_ = nullptr;
}
- ContentsScalingLayer::SetLayerTreeHost(host);
+ Layer::SetLayerTreeHost(host);
}
gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect(
@@ -168,10 +165,10 @@ gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect(
// Don't intersect with the bounds as in LayerRectToContentRect() because
// layer_rect here might be in coordinates of the containing layer.
gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect(
- layer_rect, contents_scale_x(), contents_scale_y());
- // We should never return a rect bigger than the content_bounds().
+ layer_rect, internal_contents_scale_, internal_contents_scale_);
+ // We should never return a rect bigger than the content bounds.
gfx::Size clamped_size = expanded_rect.size();
- clamped_size.SetToMin(content_bounds());
+ clamped_size.SetToMin(internal_content_bounds_);
expanded_rect.set_size(clamped_size);
return expanded_rect;
}
@@ -202,8 +199,44 @@ void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() {
}
}
+void PaintedScrollbarLayer::UpdateInternalContentScale() {
+ float scale = layer_tree_host()->device_scale_factor();
+ if (layer_tree_host()
+ ->settings()
+ .layer_transforms_should_scale_layer_contents) {
+ gfx::Transform transform;
+ if (layer_tree_host()->using_only_property_trees()) {
+ transform = DrawTransformFromPropertyTrees(
+ this, layer_tree_host()->property_trees()->transform_tree);
+ } else {
+ transform = draw_transform();
+ }
+
+ gfx::Vector2dF transform_scales =
+ MathUtil::ComputeTransform2dScaleComponents(transform, scale);
+ scale = std::max(transform_scales.x(), transform_scales.y());
+ }
+ bool changed = false;
+ changed |= UpdateProperty(ClampScaleToMaxTextureSize(scale),
+ &internal_contents_scale_);
+ changed |= UpdateProperty(
+ gfx::ToCeiledSize(gfx::ScaleSize(bounds(), internal_contents_scale_)),
+ &internal_content_bounds_);
+ if (changed) {
+ // If the content scale or bounds change, repaint.
+ SetNeedsDisplay();
+ }
+}
+
bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
const OcclusionTracker<Layer>* occlusion) {
+ {
+ base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
+ true);
+ Layer::Update(queue, occlusion);
+ UpdateInternalContentScale();
+ }
+
UpdateThumbAndTrackGeometry();
gfx::Rect track_layer_rect = gfx::Rect(location_, bounds());
@@ -225,12 +258,7 @@ bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
if (!has_thumb_ && thumb_resource_) {
thumb_resource_ = nullptr;
SetNeedsPushProperties();
- }
-
- {
- base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
- true);
- ContentsScalingLayer::Update(queue, occlusion);
+ updated = true;
}
if (update_rect_.IsEmpty() && track_resource_)
diff --git a/chromium/cc/layers/painted_scrollbar_layer.h b/chromium/cc/layers/painted_scrollbar_layer.h
index 950c165c341..ae2b125e785 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.h
+++ b/chromium/cc/layers/painted_scrollbar_layer.h
@@ -7,7 +7,7 @@
#include "cc/base/cc_export.h"
#include "cc/input/scrollbar.h"
-#include "cc/layers/contents_scaling_layer.h"
+#include "cc/layers/layer.h"
#include "cc/layers/scrollbar_layer_interface.h"
#include "cc/layers/scrollbar_theme_painter.h"
#include "cc/resources/layer_updater.h"
@@ -17,7 +17,7 @@ namespace cc {
class ScrollbarThemeComposite;
class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
- public ContentsScalingLayer {
+ public Layer {
public:
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -41,10 +41,10 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
void SetLayerTreeHost(LayerTreeHost* host) override;
void PushPropertiesTo(LayerImpl* layer) override;
void PushScrollClipPropertiesTo(LayerImpl* layer) override;
- void CalculateContentsScale(float ideal_contents_scale,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) override;
+
+ const gfx::Size& internal_content_bounds() const {
+ return internal_content_bounds_;
+ }
protected:
PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar, int scroll_layer_id);
@@ -57,17 +57,20 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
UIResourceId thumb_resource_id() {
return thumb_resource_.get() ? thumb_resource_->id() : 0;
}
+ void UpdateInternalContentScale();
void UpdateThumbAndTrackGeometry();
private:
gfx::Rect ScrollbarLayerRectToContentRect(const gfx::Rect& layer_rect) const;
gfx::Rect OriginThumbRect() const;
- template<typename T> void UpdateProperty(T value, T* prop) {
+ template <typename T>
+ bool UpdateProperty(T value, T* prop) {
if (*prop == value)
- return;
+ return false;
*prop = value;
SetNeedsPushProperties();
+ return true;
}
int MaxTextureSize();
@@ -81,6 +84,9 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
int scroll_layer_id_;
int clip_layer_id_;
+ float internal_contents_scale_;
+ gfx::Size internal_content_bounds_;
+
// Snapshot of properties taken in UpdateThumbAndTrackGeometry and used in
// PushPropertiesTo.
int thumb_thickness_;
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
index ea48086fbcf..005e0876948 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
@@ -32,12 +32,12 @@ PaintedScrollbarLayerImpl::PaintedScrollbarLayerImpl(
: ScrollbarLayerImplBase(tree_impl, id, orientation, false, false),
track_ui_resource_id_(0),
thumb_ui_resource_id_(0),
+ internal_contents_scale_(1.f),
thumb_thickness_(0),
thumb_length_(0),
track_start_(0),
- track_length_(0),
- vertical_adjust_(0.f),
- scroll_layer_id_(Layer::INVALID_ID) {}
+ track_length_(0) {
+}
PaintedScrollbarLayerImpl::~PaintedScrollbarLayerImpl() {}
@@ -52,6 +52,9 @@ void PaintedScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
PaintedScrollbarLayerImpl* scrollbar_layer =
static_cast<PaintedScrollbarLayerImpl*>(layer);
+ scrollbar_layer->set_internal_contents_scale_and_bounds(
+ internal_contents_scale_, internal_content_bounds_);
+
scrollbar_layer->SetThumbThickness(thumb_thickness_);
scrollbar_layer->SetThumbLength(thumb_length_);
scrollbar_layer->SetTrackStart(track_start_);
@@ -69,25 +72,28 @@ bool PaintedScrollbarLayerImpl::WillDraw(DrawMode draw_mode,
void PaintedScrollbarLayerImpl::AppendQuads(
RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
bool premultipled_alpha = true;
bool flipped = false;
+ bool nearest_neighbor = false;
gfx::PointF uv_top_left(0.f, 0.f);
gfx::PointF uv_bottom_right(1.f, 1.f);
- gfx::Rect bounds_rect(bounds());
- gfx::Rect content_bounds_rect(content_bounds());
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
- PopulateSharedQuadState(shared_quad_state);
+ PopulateScaledSharedQuadState(shared_quad_state, internal_contents_scale_);
- AppendDebugBorderQuad(
- render_pass, content_bounds(), shared_quad_state, append_quads_data);
+ AppendDebugBorderQuad(render_pass, internal_content_bounds_,
+ shared_quad_state, append_quads_data);
gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
+ gfx::Rect scaled_thumb_quad_rect =
+ gfx::ScaleToEnclosingRect(thumb_quad_rect, internal_contents_scale_);
gfx::Rect visible_thumb_quad_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(thumb_quad_rect);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ thumb_quad_rect);
+ gfx::Rect scaled_visible_thumb_quad_rect = gfx::ScaleToEnclosingRect(
+ visible_thumb_quad_rect, internal_contents_scale_);
ResourceProvider::ResourceId thumb_resource_id =
layer_tree_impl()->ResourceIdForUIResource(thumb_ui_resource_id_);
@@ -99,41 +105,38 @@ void PaintedScrollbarLayerImpl::AppendQuads(
const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- quad->SetNew(shared_quad_state,
- thumb_quad_rect,
- opaque_rect,
- visible_thumb_quad_rect,
- thumb_resource_id,
- premultipled_alpha,
- uv_top_left,
- uv_bottom_right,
- SK_ColorTRANSPARENT,
- opacity,
- flipped);
+ quad->SetNew(shared_quad_state, scaled_thumb_quad_rect, opaque_rect,
+ scaled_visible_thumb_quad_rect, thumb_resource_id,
+ premultipled_alpha, uv_top_left, uv_bottom_right,
+ SK_ColorTRANSPARENT, opacity, flipped, nearest_neighbor);
+ ValidateQuadResources(quad);
}
- gfx::Rect track_quad_rect = content_bounds_rect;
+ gfx::Rect track_quad_rect(bounds());
+ gfx::Rect scaled_track_quad_rect(internal_content_bounds_);
gfx::Rect visible_track_quad_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(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, internal_contents_scale_);
if (track_resource_id && !visible_track_quad_rect.IsEmpty()) {
- gfx::Rect opaque_rect(contents_opaque() ? track_quad_rect : gfx::Rect());
+ gfx::Rect opaque_rect(contents_opaque() ? scaled_track_quad_rect
+ : gfx::Rect());
const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- quad->SetNew(shared_quad_state,
- track_quad_rect,
- opaque_rect,
- visible_track_quad_rect,
- track_resource_id,
- premultipled_alpha,
- uv_top_left,
- uv_bottom_right,
- SK_ColorTRANSPARENT,
- opacity,
- flipped);
+ quad->SetNew(shared_quad_state, scaled_track_quad_rect, opaque_rect,
+ scaled_visible_track_quad_rect, track_resource_id,
+ premultipled_alpha, uv_top_left, uv_bottom_right,
+ SK_ColorTRANSPARENT, opacity, flipped, nearest_neighbor);
+ ValidateQuadResources(quad);
}
}
+gfx::Rect PaintedScrollbarLayerImpl::GetEnclosingRectInTargetSpace() const {
+ return GetScaledEnclosingRectInTargetSpace(internal_contents_scale_);
+}
+
void PaintedScrollbarLayerImpl::SetThumbThickness(int thumb_thickness) {
if (thumb_thickness_ == thumb_thickness)
return;
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.h b/chromium/cc/layers/painted_scrollbar_layer_impl.h
index d54de6b38ac..65d28aea050 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.h
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.h
@@ -30,8 +30,8 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase {
bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
+ gfx::Rect GetEnclosingRectInTargetSpace() const override;
void SetThumbThickness(int thumb_thickness);
void SetThumbLength(int thumb_length);
@@ -45,6 +45,12 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase {
thumb_ui_resource_id_ = uid;
}
+ void set_internal_contents_scale_and_bounds(float content_scale,
+ const gfx::Size& content_bounds) {
+ internal_contents_scale_ = content_scale;
+ internal_content_bounds_ = content_bounds;
+ }
+
protected:
PaintedScrollbarLayerImpl(LayerTreeImpl* tree_impl,
int id,
@@ -63,17 +69,14 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase {
UIResourceId track_ui_resource_id_;
UIResourceId thumb_ui_resource_id_;
+ float internal_contents_scale_;
+ gfx::Size internal_content_bounds_;
+
int thumb_thickness_;
int thumb_length_;
int track_start_;
int track_length_;
- // Difference between the clip layer's height and the visible viewport
- // height (which may differ in the presence of top-controls hiding).
- float vertical_adjust_;
-
- int scroll_layer_id_;
-
DISALLOW_COPY_AND_ASSIGN(PaintedScrollbarLayerImpl);
};
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc
index 3994cc36ca1..3fb3fb22bd1 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/layers/painted_scrollbar_layer_impl.h"
+#include "cc/quads/draw_quad.h"
#include "cc/test/layer_test_common.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -12,6 +13,8 @@ namespace {
TEST(PaintedScrollbarLayerImplTest, Occlusion) {
gfx::Size layer_size(10, 1000);
+ float scale = 2.f;
+ gfx::Size scaled_layer_size(20, 2000);
gfx::Size viewport_size(1000, 1000);
LayerTestCommon::LayerImplTest impl;
@@ -36,6 +39,9 @@ TEST(PaintedScrollbarLayerImplTest, Occlusion) {
impl.AddChildToRoot<PaintedScrollbarLayerImpl>(orientation);
scrollbar_layer_impl->SetBounds(layer_size);
scrollbar_layer_impl->SetContentBounds(layer_size);
+ scrollbar_layer_impl->SetContentsOpaque(true);
+ scrollbar_layer_impl->set_internal_contents_scale_and_bounds(
+ scale, scaled_layer_size);
scrollbar_layer_impl->SetDrawsContent(true);
scrollbar_layer_impl->SetThumbThickness(layer_size.width());
scrollbar_layer_impl->SetThumbLength(500);
@@ -62,6 +68,23 @@ TEST(PaintedScrollbarLayerImplTest, Occlusion) {
impl.quad_list(), occluded, &partially_occluded_count);
EXPECT_EQ(2u, impl.quad_list().size());
EXPECT_EQ(0u, partially_occluded_count);
+
+ // Note: this is also testing that the thumb and track are both
+ // scaled by the internal contents scale. It's not occlusion-related
+ // but is easy to verify here.
+ const DrawQuad* thumb_quad = impl.quad_list().ElementAt(0);
+ const DrawQuad* track_quad = impl.quad_list().ElementAt(1);
+
+ gfx::Rect scaled_thumb_rect = gfx::ScaleToEnclosingRect(thumb_rect, scale);
+ EXPECT_EQ(track_quad->rect.ToString(),
+ gfx::Rect(scaled_layer_size).ToString());
+ EXPECT_EQ(track_quad->opaque_rect.ToString(),
+ gfx::Rect(scaled_layer_size).ToString());
+ EXPECT_EQ(track_quad->visible_rect.ToString(),
+ gfx::Rect(scaled_layer_size).ToString());
+ EXPECT_EQ(thumb_quad->rect.ToString(), scaled_thumb_rect.ToString());
+ EXPECT_EQ(thumb_quad->visible_rect.ToString(),
+ scaled_thumb_rect.ToString());
}
{
diff --git a/chromium/cc/layers/picture_image_layer.cc b/chromium/cc/layers/picture_image_layer.cc
index dba506ec843..345ee2b4e95 100644
--- a/chromium/cc/layers/picture_image_layer.cc
+++ b/chromium/cc/layers/picture_image_layer.cc
@@ -5,7 +5,10 @@
#include "cc/layers/picture_image_layer.h"
#include "cc/layers/picture_image_layer_impl.h"
+#include "cc/playback/drawing_display_item.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "ui/gfx/skia_util.h"
namespace cc {
@@ -21,7 +24,7 @@ PictureImageLayer::~PictureImageLayer() {
scoped_ptr<LayerImpl> PictureImageLayer::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return PictureImageLayerImpl::Create(tree_impl, id());
+ return PictureImageLayerImpl::Create(tree_impl, id(), is_mask());
}
bool PictureImageLayer::HasDrawableContent() const {
@@ -44,7 +47,7 @@ void PictureImageLayer::SetBitmap(const SkBitmap& bitmap) {
void PictureImageLayer::PaintContents(
SkCanvas* canvas,
const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus gc_status) {
+ ContentLayerClient::PaintingControlSetting painting_control) {
if (!bitmap_.width() || !bitmap_.height())
return;
@@ -60,6 +63,20 @@ void PictureImageLayer::PaintContents(
canvas->drawBitmap(bitmap_, 0, 0);
}
+void PictureImageLayer::PaintContentsToDisplayList(
+ DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ ContentLayerClient::PaintingControlSetting painting_control) {
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(clip));
+ PaintContents(canvas, clip, painting_control);
+
+ skia::RefPtr<SkPicture> picture =
+ skia::AdoptRef(recorder.endRecordingAsPicture());
+ auto* item = display_list->CreateAndAppendItem<DrawingDisplayItem>();
+ item->SetNew(picture.Pass());
+}
+
bool PictureImageLayer::FillsBoundsCompletely() const {
return false;
}
diff --git a/chromium/cc/layers/picture_image_layer.h b/chromium/cc/layers/picture_image_layer.h
index 3575d8821c8..a12a1b9085d 100644
--- a/chromium/cc/layers/picture_image_layer.h
+++ b/chromium/cc/layers/picture_image_layer.h
@@ -26,8 +26,11 @@ class CC_EXPORT PictureImageLayer : public PictureLayer, ContentLayerClient {
void PaintContents(
SkCanvas* canvas,
const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus gc_status) override;
- void DidChangeLayerCanUseLCDText() override {}
+ ContentLayerClient::PaintingControlSetting painting_control) override;
+ void PaintContentsToDisplayList(
+ DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ ContentLayerClient::PaintingControlSetting painting_control) override;
bool FillsBoundsCompletely() const override;
protected:
diff --git a/chromium/cc/layers/picture_image_layer_impl.cc b/chromium/cc/layers/picture_image_layer_impl.cc
index a72ab01e655..03ef5ae6fe9 100644
--- a/chromium/cc/layers/picture_image_layer_impl.cc
+++ b/chromium/cc/layers/picture_image_layer_impl.cc
@@ -11,8 +11,13 @@
namespace cc {
-PictureImageLayerImpl::PictureImageLayerImpl(LayerTreeImpl* tree_impl, int id)
- : PictureLayerImpl(tree_impl, id) {
+PictureImageLayerImpl::PictureImageLayerImpl(LayerTreeImpl* tree_impl,
+ int id,
+ bool is_mask)
+ : PictureLayerImpl(tree_impl,
+ id,
+ is_mask,
+ new LayerImpl::SyncedScrollOffset) {
}
PictureImageLayerImpl::~PictureImageLayerImpl() {
@@ -24,7 +29,7 @@ const char* PictureImageLayerImpl::LayerTypeAsString() const {
scoped_ptr<LayerImpl> PictureImageLayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return PictureImageLayerImpl::Create(tree_impl, id());
+ return PictureImageLayerImpl::Create(tree_impl, id(), is_mask_);
}
void PictureImageLayerImpl::GetDebugBorderProperties(
diff --git a/chromium/cc/layers/picture_image_layer_impl.h b/chromium/cc/layers/picture_image_layer_impl.h
index 7a363a17a84..f478951592f 100644
--- a/chromium/cc/layers/picture_image_layer_impl.h
+++ b/chromium/cc/layers/picture_image_layer_impl.h
@@ -12,8 +12,9 @@ namespace cc {
class CC_EXPORT PictureImageLayerImpl : public PictureLayerImpl {
public:
static scoped_ptr<PictureImageLayerImpl> Create(LayerTreeImpl* tree_impl,
- int id) {
- return make_scoped_ptr(new PictureImageLayerImpl(tree_impl, id));
+ int id,
+ bool is_mask) {
+ return make_scoped_ptr(new PictureImageLayerImpl(tree_impl, id, is_mask));
}
~PictureImageLayerImpl() override;
@@ -22,7 +23,7 @@ class CC_EXPORT PictureImageLayerImpl : public PictureLayerImpl {
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
protected:
- PictureImageLayerImpl(LayerTreeImpl* tree_impl, int id);
+ PictureImageLayerImpl(LayerTreeImpl* tree_impl, int id, bool is_mask);
bool ShouldAdjustRasterScale() const override;
void RecalculateRasterScales() override;
diff --git a/chromium/cc/layers/picture_image_layer_impl_unittest.cc b/chromium/cc/layers/picture_image_layer_impl_unittest.cc
index fcaacc77cf8..fa4cb6e7e06 100644
--- a/chromium/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_image_layer_impl_unittest.cc
@@ -4,15 +4,17 @@
#include "cc/layers/picture_image_layer_impl.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/layers/append_quads_data.h"
#include "cc/quads/draw_quad.h"
-#include "cc/resources/tile_priority.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
+#include "cc/tiles/tile_priority.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,11 +24,9 @@ namespace {
class TestablePictureImageLayerImpl : public PictureImageLayerImpl {
public:
TestablePictureImageLayerImpl(LayerTreeImpl* tree_impl, int id)
- : PictureImageLayerImpl(tree_impl, id) {
- }
+ : PictureImageLayerImpl(tree_impl, id, false) {}
using PictureLayerImpl::UpdateIdealScales;
using PictureLayerImpl::MaximumTilingContentsScale;
- using PictureLayerImpl::DoPostCommitInitializationIfNeeded;
PictureLayerTilingSet* tilings() { return tilings_.get(); }
@@ -36,10 +36,11 @@ class TestablePictureImageLayerImpl : public PictureImageLayerImpl {
class PictureImageLayerImplTest : public testing::Test {
public:
PictureImageLayerImplTest()
- : proxy_(base::MessageLoopProxy::current()),
+ : proxy_(base::ThreadTaskRunnerHandle::Get()),
host_impl_(ImplSidePaintingSettings(),
&proxy_,
- &shared_bitmap_manager_) {
+ &shared_bitmap_manager_,
+ &task_graph_runner_) {
host_impl_.CreatePendingTree();
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
}
@@ -54,15 +55,12 @@ class PictureImageLayerImplTest : public testing::Test {
case PENDING_TREE:
tree = host_impl_.pending_tree();
break;
- case NUM_TREES:
- NOTREACHED();
- break;
}
TestablePictureImageLayerImpl* layer =
new TestablePictureImageLayerImpl(tree, id);
- layer->pile_ = FakePicturePileImpl::CreateInfiniteFilledPile();
- layer->SetBounds(layer->pile_->tiling_size());
- layer->SetContentBounds(layer->pile_->tiling_size());
+ layer->raster_source_ = FakePicturePileImpl::CreateInfiniteFilledPile();
+ layer->SetBounds(layer->raster_source_->GetSize());
+ layer->SetContentBounds(layer->raster_source_->GetSize());
return make_scoped_ptr(layer);
}
@@ -82,19 +80,19 @@ class PictureImageLayerImplTest : public testing::Test {
animating_transform_to_screen;
layer->draw_properties().visible_content_rect = viewport_rect;
bool resourceless_software_draw = false;
- layer->UpdateTiles(Occlusion(), resourceless_software_draw);
+ layer->UpdateTiles(resourceless_software_draw);
}
protected:
FakeImplProxy proxy_;
- FakeLayerTreeHostImpl host_impl_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
+ FakeLayerTreeHostImpl host_impl_;
};
TEST_F(PictureImageLayerImplTest, CalculateContentsScale) {
scoped_ptr<TestablePictureImageLayerImpl> layer(CreateLayer(1, PENDING_TREE));
layer->SetDrawsContent(true);
- layer->DoPostCommitInitializationIfNeeded();
gfx::Rect viewport(100, 200);
SetupDrawPropertiesAndUpdateTiles(
@@ -152,7 +150,7 @@ TEST_F(PictureImageLayerImplTest, IgnoreIdealContentScale) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
active_layer->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
- active_layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer->AppendQuads(render_pass.get(), &data);
active_layer->DidDraw(nullptr);
EXPECT_EQ(DrawQuad::TILED_CONTENT, render_pass->quad_list.front()->material);
diff --git a/chromium/cc/layers/picture_image_layer_unittest.cc b/chromium/cc/layers/picture_image_layer_unittest.cc
new file mode 100644
index 00000000000..786e30979a3
--- /dev/null
+++ b/chromium/cc/layers/picture_image_layer_unittest.cc
@@ -0,0 +1,83 @@
+// 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.
+
+#include "cc/layers/picture_image_layer.h"
+
+#include "cc/playback/display_item.h"
+#include "cc/test/skia_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace cc {
+namespace {
+
+TEST(PictureImageLayerTest, PaintContentsToDisplayList) {
+ scoped_refptr<PictureImageLayer> layer = PictureImageLayer::Create();
+ gfx::Rect layer_rect(200, 200);
+
+ SkBitmap image_bitmap;
+ unsigned char image_pixels[4 * 200 * 200] = {0};
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ image_bitmap.installPixels(info, image_pixels, info.minRowBytes());
+ SkCanvas image_canvas(image_bitmap);
+ image_canvas.clear(SK_ColorRED);
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ image_canvas.drawRectCoords(0.f, 0.f, 100.f, 100.f, blue_paint);
+ image_canvas.drawRectCoords(100.f, 100.f, 200.f, 200.f, blue_paint);
+
+ layer->SetBitmap(image_bitmap);
+ layer->SetBounds(gfx::Size(layer_rect.width(), layer_rect.height()));
+
+ bool use_cached_picture = false;
+ scoped_refptr<DisplayItemList> display_list =
+ DisplayItemList::Create(layer_rect, use_cached_picture);
+ layer->PaintContentsToDisplayList(
+ display_list.get(), layer_rect,
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->ProcessAppendedItems();
+ unsigned char actual_pixels[4 * 200 * 200] = {0};
+ DrawDisplayList(actual_pixels, layer_rect, display_list);
+
+ EXPECT_EQ(0, memcmp(actual_pixels, image_pixels, 4 * 200 * 200));
+}
+
+TEST(PictureImageLayerTest, PaintContentsToCachedDisplayList) {
+ scoped_refptr<PictureImageLayer> layer = PictureImageLayer::Create();
+ gfx::Rect layer_rect(200, 200);
+
+ SkBitmap image_bitmap;
+ unsigned char image_pixels[4 * 200 * 200] = {0};
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ image_bitmap.installPixels(info, image_pixels, info.minRowBytes());
+ SkCanvas image_canvas(image_bitmap);
+ image_canvas.clear(SK_ColorRED);
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ image_canvas.drawRectCoords(0.f, 0.f, 100.f, 100.f, blue_paint);
+ image_canvas.drawRectCoords(100.f, 100.f, 200.f, 200.f, blue_paint);
+
+ layer->SetBitmap(image_bitmap);
+ layer->SetBounds(gfx::Size(layer_rect.width(), layer_rect.height()));
+
+ bool use_cached_picture = true;
+ scoped_refptr<DisplayItemList> display_list =
+ DisplayItemList::Create(layer_rect, use_cached_picture);
+ layer->PaintContentsToDisplayList(
+ display_list.get(), layer_rect,
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->ProcessAppendedItems();
+ display_list->CreateAndCacheSkPicture();
+ unsigned char actual_pixels[4 * 200 * 200] = {0};
+ DrawDisplayList(actual_pixels, layer_rect, display_list);
+
+ EXPECT_EQ(0, memcmp(actual_pixels, image_pixels, 4 * 200 * 200));
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/picture_layer.cc b/chromium/cc/layers/picture_layer.cc
index c56ff8be082..999363282a0 100644
--- a/chromium/cc/layers/picture_layer.cc
+++ b/chromium/cc/layers/picture_layer.cc
@@ -7,6 +7,9 @@
#include "base/auto_reset.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/picture_layer_impl.h"
+#include "cc/playback/display_list_recording_source.h"
+#include "cc/playback/picture_pile.h"
+#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -21,55 +24,83 @@ PictureLayer::PictureLayer(ContentLayerClient* client)
: client_(client),
instrumentation_object_tracker_(id()),
update_source_frame_number_(-1),
- can_use_lcd_text_last_frame_(can_use_lcd_text()) {
+ is_mask_(false),
+ nearest_neighbor_(false) {
+}
+
+PictureLayer::PictureLayer(ContentLayerClient* client,
+ scoped_ptr<RecordingSource> source)
+ : PictureLayer(client) {
+ recording_source_ = source.Pass();
}
PictureLayer::~PictureLayer() {
}
scoped_ptr<LayerImpl> PictureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
- return PictureLayerImpl::Create(tree_impl, id());
+ return PictureLayerImpl::Create(tree_impl, id(), is_mask_,
+ new LayerImpl::SyncedScrollOffset);
}
void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
Layer::PushPropertiesTo(base_layer);
PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
+ // TODO(danakj): Make is_mask_ a constructor parameter for PictureLayer.
+ DCHECK_EQ(layer_impl->is_mask(), is_mask_);
int source_frame_number = layer_tree_host()->source_frame_number();
gfx::Size impl_bounds = layer_impl->bounds();
- gfx::Size pile_bounds = pile_.tiling_size();
+ gfx::Size recording_source_bounds = recording_source_->GetSize();
- // If update called, then pile size must match bounds pushed to impl layer.
+ // If update called, then recording source size must match bounds pushed to
+ // impl layer.
DCHECK_IMPLIES(update_source_frame_number_ == source_frame_number,
- impl_bounds == pile_bounds)
- << " bounds " << impl_bounds.ToString() << " pile "
- << pile_bounds.ToString();
+ impl_bounds == recording_source_bounds)
+ << " bounds " << impl_bounds.ToString() << " recording source "
+ << recording_source_bounds.ToString();
if (update_source_frame_number_ != source_frame_number &&
- pile_bounds != impl_bounds) {
+ recording_source_bounds != impl_bounds) {
// Update may not get called for the layer (if it's not in the viewport
- // for example, even though it has resized making the pile no longer
- // valid. In this case just destroy the pile.
- pile_.SetEmptyBounds();
+ // for example, even though it has resized making the recording source no
+ // longer valid. In this case just destroy the recording source.
+ recording_source_->SetEmptyBounds();
}
- // Unlike other properties, invalidation must always be set on layer_impl.
- // See PictureLayerImpl::PushPropertiesTo for more details.
- layer_impl->invalidation_.Clear();
- layer_impl->invalidation_.Swap(&pile_invalidation_);
- layer_impl->UpdatePile(PicturePileImpl::CreateFromOther(&pile_));
+ layer_impl->SetNearestNeighbor(nearest_neighbor_);
+
+ // Preserve lcd text settings from the current raster source.
+ bool can_use_lcd_text = layer_impl->RasterSourceUsesLCDText();
+ scoped_refptr<RasterSource> raster_source =
+ recording_source_->CreateRasterSource(can_use_lcd_text);
+ layer_impl->set_gpu_raster_max_texture_size(
+ layer_tree_host()->device_viewport_size());
+ layer_impl->UpdateRasterSource(raster_source, &recording_invalidation_,
+ nullptr);
+ DCHECK(recording_invalidation_.IsEmpty());
}
void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
Layer::SetLayerTreeHost(host);
- if (host) {
- pile_.SetMinContentsScale(host->settings().minimum_contents_scale);
- pile_.SetTileGridSize(host->settings().default_tile_grid_size);
- pile_.set_slow_down_raster_scale_factor(
- host->debug_state().slow_down_raster_scale_factor);
- pile_.set_show_debug_picture_borders(
- host->debug_state().show_picture_borders);
+ if (!host)
+ return;
+
+ const LayerTreeSettings& settings = layer_tree_host()->settings();
+ if (!recording_source_) {
+ if (settings.use_display_lists) {
+ recording_source_.reset(new DisplayListRecordingSource(
+ settings.default_tile_grid_size,
+ settings.use_cached_picture_in_display_list));
+ } else {
+ recording_source_.reset(new PicturePile(settings.minimum_contents_scale,
+ settings.default_tile_grid_size));
+ }
}
+ recording_source_->SetSlowdownRasterScaleFactor(
+ host->debug_state().slow_down_raster_scale_factor);
+ recording_source_->SetGatherPixelRefs(settings.gather_pixel_refs);
+
+ DCHECK(settings.raster_enabled);
}
void PictureLayer::SetNeedsDisplayRect(const gfx::Rect& layer_rect) {
@@ -86,22 +117,21 @@ bool PictureLayer::Update(ResourceUpdateQueue* queue,
update_source_frame_number_ = layer_tree_host()->source_frame_number();
bool updated = Layer::Update(queue, occlusion);
- {
- base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
- true);
- UpdateCanUseLCDText();
- }
-
gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
visible_content_rect(), 1.f / contents_scale_x());
gfx::Size layer_size = paint_properties().bounds;
if (last_updated_visible_content_rect_ == visible_content_rect() &&
- pile_.tiling_size() == layer_size && pending_invalidation_.IsEmpty()) {
+ recording_source_->GetSize() == layer_size &&
+ pending_invalidation_.IsEmpty()) {
// Only early out if the visible content rect of this layer hasn't changed.
return updated;
}
+ recording_source_->SetBackgroundColor(SafeOpaqueBackgroundColor());
+ recording_source_->SetRequiresClear(!contents_opaque() &&
+ !client_->FillsBoundsCompletely());
+
TRACE_EVENT1("cc", "PictureLayer::Update",
"source_frame_number",
layer_tree_host()->source_frame_number());
@@ -110,7 +140,7 @@ bool PictureLayer::Update(ResourceUpdateQueue* queue,
// Calling paint in WebKit can sometimes cause invalidations, so save
// off the invalidation prior to calling update.
- pending_invalidation_.Swap(&pile_invalidation_);
+ pending_invalidation_.Swap(&recording_invalidation_);
pending_invalidation_.Clear();
if (layer_tree_host()->settings().record_full_layer) {
@@ -124,68 +154,66 @@ bool PictureLayer::Update(ResourceUpdateQueue* queue,
// to the impl side so that it drops tiles that may not have a recording
// for them.
DCHECK(client_);
- updated |=
- pile_.UpdateAndExpandInvalidation(client_,
- &pile_invalidation_,
- SafeOpaqueBackgroundColor(),
- contents_opaque(),
- client_->FillsBoundsCompletely(),
- layer_size,
- visible_layer_rect,
- update_source_frame_number_,
- Picture::RECORD_NORMALLY,
- rendering_stats_instrumentation());
+ updated |= recording_source_->UpdateAndExpandInvalidation(
+ client_, &recording_invalidation_, layer_size, visible_layer_rect,
+ update_source_frame_number_, RecordingSource::RECORD_NORMALLY);
last_updated_visible_content_rect_ = visible_content_rect();
if (updated) {
SetNeedsPushProperties();
} else {
- // If this invalidation did not affect the pile, then it can be cleared as
- // an optimization.
- pile_invalidation_.Clear();
+ // If this invalidation did not affect the recording source, then it can be
+ // cleared as an optimization.
+ recording_invalidation_.Clear();
}
return updated;
}
void PictureLayer::SetIsMask(bool is_mask) {
- pile_.set_is_mask(is_mask);
-}
-
-bool PictureLayer::SupportsLCDText() const {
- return true;
-}
-
-void PictureLayer::UpdateCanUseLCDText() {
- if (can_use_lcd_text_last_frame_ == can_use_lcd_text())
- return;
-
- can_use_lcd_text_last_frame_ = can_use_lcd_text();
- if (client_)
- client_->DidChangeLayerCanUseLCDText();
+ is_mask_ = is_mask;
}
skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
- // We could either flatten the PicturePile into a single SkPicture,
+ // We could either flatten the RecordingSource into a single SkPicture,
// or paint a fresh one depending on what we intend to do with the
// picture. For now we just paint a fresh one to get consistent results.
if (!DrawsContent())
return skia::RefPtr<SkPicture>();
- int width = bounds().width();
- int height = bounds().height();
+ gfx::Size layer_size = bounds();
+ const LayerTreeSettings& settings = layer_tree_host()->settings();
+
+ if (settings.use_display_lists) {
+ scoped_ptr<RecordingSource> recording_source;
+ recording_source.reset(new DisplayListRecordingSource(
+ settings.default_tile_grid_size,
+ settings.use_cached_picture_in_display_list));
+ Region recording_invalidation;
+ recording_source->UpdateAndExpandInvalidation(
+ client_, &recording_invalidation, layer_size, gfx::Rect(layer_size),
+ update_source_frame_number_, RecordingSource::RECORD_NORMALLY);
+
+ scoped_refptr<RasterSource> raster_source =
+ recording_source->CreateRasterSource(false);
+
+ return raster_source->GetFlattenedPicture();
+ }
+
+ int width = layer_size.width();
+ int height = layer_size.height();
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(width, height, nullptr, 0);
- client_->PaintContents(canvas,
- gfx::Rect(width, height),
- ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
- skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
+ client_->PaintContents(canvas, gfx::Rect(width, height),
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ skia::RefPtr<SkPicture> picture =
+ skia::AdoptRef(recorder.endRecordingAsPicture());
return picture;
}
bool PictureLayer::IsSuitableForGpuRasterization() const {
- return pile_.is_suitable_for_gpu_rasterization();
+ return recording_source_->IsSuitableForGpuRasterization();
}
void PictureLayer::ClearClient() {
@@ -193,6 +221,14 @@ void PictureLayer::ClearClient() {
UpdateDrawsContent(HasDrawableContent());
}
+void PictureLayer::SetNearestNeighbor(bool nearest_neighbor) {
+ if (nearest_neighbor_ == nearest_neighbor)
+ return;
+
+ nearest_neighbor_ = nearest_neighbor;
+ SetNeedsCommit();
+}
+
bool PictureLayer::HasDrawableContent() const {
return client_ && Layer::HasDrawableContent();
}
diff --git a/chromium/cc/layers/picture_layer.h b/chromium/cc/layers/picture_layer.h
index 232dba23ba7..767de273302 100644
--- a/chromium/cc/layers/picture_layer.h
+++ b/chromium/cc/layers/picture_layer.h
@@ -9,12 +9,12 @@
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/micro_benchmark_controller.h"
#include "cc/layers/layer.h"
-#include "cc/resources/picture_pile.h"
#include "cc/trees/occlusion_tracker.h"
namespace cc {
class ContentLayerClient;
+class RecordingSource;
class ResourceUpdateQueue;
class CC_EXPORT PictureLayer : public Layer {
@@ -23,6 +23,8 @@ class CC_EXPORT PictureLayer : public Layer {
void ClearClient();
+ void SetNearestNeighbor(bool nearest_neighbor);
+
// Layer interface.
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
void SetLayerTreeHost(LayerTreeHost* host) override;
@@ -31,7 +33,6 @@ class CC_EXPORT PictureLayer : public Layer {
bool Update(ResourceUpdateQueue* queue,
const OcclusionTracker<Layer>* occlusion) override;
void SetIsMask(bool is_mask) override;
- bool SupportsLCDText() const override;
skia::RefPtr<SkPicture> GetPicture() const override;
bool IsSuitableForGpuRasterization() const override;
@@ -39,28 +40,34 @@ class CC_EXPORT PictureLayer : public Layer {
ContentLayerClient* client() { return client_; }
- PicturePile* GetPicturePileForTesting() { return &pile_; }
+ RecordingSource* GetRecordingSourceForTesting() {
+ return recording_source_.get();
+ }
protected:
explicit PictureLayer(ContentLayerClient* client);
+ // Allow tests to inject a recording source.
+ PictureLayer(ContentLayerClient* client, scoped_ptr<RecordingSource> source);
~PictureLayer() override;
bool HasDrawableContent() const override;
- void UpdateCanUseLCDText();
+
+ bool is_mask() const { return is_mask_; }
private:
ContentLayerClient* client_;
- PicturePile pile_;
+ scoped_ptr<RecordingSource> recording_source_;
devtools_instrumentation::
ScopedLayerObjectTracker instrumentation_object_tracker_;
// Invalidation to use the next time update is called.
InvalidationRegion pending_invalidation_;
// Invalidation from the last time update was called.
- Region pile_invalidation_;
+ Region recording_invalidation_;
gfx::Rect last_updated_visible_content_rect_;
int update_source_frame_number_;
- bool can_use_lcd_text_last_frame_;
+ bool is_mask_;
+ bool nearest_neighbor_;
DISALLOW_COPY_AND_ASSIGN(PictureLayer);
};
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index 822fcf3dc21..11014402c8f 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -5,11 +5,12 @@
#include "cc/layers/picture_layer_impl.h"
#include <algorithm>
+#include <cmath>
#include <limits>
#include <set>
-#include "base/debug/trace_event_argument.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/base/math_util.h"
#include "cc/base/util.h"
#include "cc/debug/debug_colors.h"
@@ -23,7 +24,8 @@
#include "cc/quads/picture_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
-#include "cc/resources/tile_manager.h"
+#include "cc/tiles/tile_manager.h"
+#include "cc/tiles/tiling_set_raster_queue_all.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/occlusion.h"
#include "ui/gfx/geometry/quad_f.h"
@@ -31,19 +33,14 @@
#include "ui/gfx/geometry/size_conversions.h"
namespace {
+// This must be > 1 as we multiply or divide by this to find a new raster
+// scale during pinch.
const float kMaxScaleRatioDuringPinch = 2.0f;
// When creating a new tiling during pinch, snap to an existing
// tiling's scale if the desired scale is within this ratio.
const float kSnapToExistingTilingRatio = 1.2f;
-// Estimate skewport 60 frames ahead for pre-rasterization on the CPU.
-const float kCpuSkewportTargetTimeInFrames = 60.0f;
-
-// Don't pre-rasterize on the GPU (except for kBackflingGuardDistancePixels in
-// TileManager::BinFromTilePriority).
-const float kGpuSkewportTargetTimeInFrames = 0.0f;
-
// Even for really wide viewports, at some point GPU raster should use
// less than 4 tiles to fill the viewport. This is set to 256 as a
// sane minimum for now, but we might want to tune this for low-end.
@@ -57,21 +54,14 @@ const int kTileRoundUp = 64;
namespace cc {
-PictureLayerImpl::Pair::Pair() : active(nullptr), pending(nullptr) {
-}
-
-PictureLayerImpl::Pair::Pair(PictureLayerImpl* active_layer,
- PictureLayerImpl* pending_layer)
- : active(active_layer), pending(pending_layer) {
-}
-
-PictureLayerImpl::Pair::~Pair() {
-}
-
-PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
- : LayerImpl(tree_impl, id),
+PictureLayerImpl::PictureLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ bool is_mask,
+ scoped_refptr<SyncedScrollOffset> scroll_offset)
+ : LayerImpl(tree_impl, id, scroll_offset),
twin_layer_(nullptr),
- pile_(PicturePileImpl::Create()),
+ tilings_(CreatePictureLayerTilingSet()),
ideal_page_scale_(0.f),
ideal_device_scale_(0.f),
ideal_source_scale_(0.f),
@@ -83,9 +73,9 @@ PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
low_res_raster_contents_scale_(0.f),
raster_source_scale_is_fixed_(false),
was_screen_space_transform_animating_(false),
- needs_post_commit_initialization_(true),
- should_update_tile_priorities_(false),
- only_used_low_res_last_append_quads_(false) {
+ only_used_low_res_last_append_quads_(false),
+ is_mask_(is_mask),
+ nearest_neighbor_(false) {
layer_tree_impl()->RegisterPictureLayerImpl(this);
}
@@ -101,14 +91,13 @@ const char* PictureLayerImpl::LayerTypeAsString() const {
scoped_ptr<LayerImpl> PictureLayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return PictureLayerImpl::Create(tree_impl, id());
+ return PictureLayerImpl::Create(tree_impl, id(), is_mask_,
+ synced_scroll_offset());
}
void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
- // It's possible this layer was never drawn or updated (e.g. because it was
- // a descendant of an opacity 0 layer).
- DoPostCommitInitializationIfNeeded();
PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
+ DCHECK_EQ(layer_impl->is_mask_, is_mask_);
LayerImpl::PushPropertiesTo(base_layer);
@@ -122,159 +111,114 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
twin_layer_ = layer_impl;
layer_impl->twin_layer_ = this;
- layer_impl->UpdatePile(pile_);
+ layer_impl->SetNearestNeighbor(nearest_neighbor_);
- DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
- // Tilings would be expensive to push, so we swap.
- layer_impl->tilings_.swap(tilings_);
- layer_impl->tilings_->SetClient(layer_impl);
- if (tilings_)
- tilings_->SetClient(this);
+ // Solid color layers have no tilings.
+ DCHECK_IMPLIES(raster_source_->IsSolidColor(), tilings_->num_tilings() == 0);
+ // The pending tree should only have a high res (and possibly low res) tiling.
+ DCHECK_LE(tilings_->num_tilings(),
+ layer_tree_impl()->create_low_res_tiling() ? 2u : 1u);
- // Ensure that the recycle tree doesn't have any unshared tiles.
- if (tilings_ && pile_->is_solid_color())
- tilings_->RemoveAllTilings();
+ layer_impl->set_gpu_raster_max_texture_size(gpu_raster_max_texture_size_);
+ layer_impl->UpdateRasterSource(raster_source_, &invalidation_,
+ tilings_.get());
+ DCHECK(invalidation_.IsEmpty());
- // Remove invalidated tiles from what will become a recycle tree.
- if (tilings_)
- tilings_->RemoveTilesInRegion(invalidation_);
+ // After syncing a solid color layer, the active layer has no tilings.
+ DCHECK_IMPLIES(raster_source_->IsSolidColor(),
+ layer_impl->tilings_->num_tilings() == 0);
layer_impl->raster_page_scale_ = raster_page_scale_;
layer_impl->raster_device_scale_ = raster_device_scale_;
layer_impl->raster_source_scale_ = raster_source_scale_;
layer_impl->raster_contents_scale_ = raster_contents_scale_;
layer_impl->low_res_raster_contents_scale_ = low_res_raster_contents_scale_;
- layer_impl->needs_post_commit_initialization_ = false;
- // The invalidation on this soon-to-be-recycled layer must be cleared to
- // mirror clearing the invalidation in PictureLayer's version of this function
- // in case push properties is skipped.
- layer_impl->invalidation_.Swap(&invalidation_);
- invalidation_.Clear();
- needs_post_commit_initialization_ = true;
+ layer_impl->SanityCheckTilingState();
// We always need to push properties.
// See http://crbug.com/303943
+ // TODO(danakj): Stop always pushing properties since we don't swap tilings.
needs_push_properties_ = true;
}
-void PictureLayerImpl::UpdatePile(scoped_refptr<PicturePileImpl> pile) {
- bool could_have_tilings = CanHaveTilings();
- pile_.swap(pile);
-
- // Need to call UpdateTiles again if CanHaveTilings changed.
- if (could_have_tilings != CanHaveTilings()) {
- layer_tree_impl()->set_needs_update_draw_properties();
- }
-}
-
void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
- DCHECK(!needs_post_commit_initialization_);
// The bounds and the pile size may differ if the pile wasn't updated (ie.
// PictureLayer::Update didn't happen). In that case the pile will be empty.
- DCHECK_IMPLIES(!pile_->tiling_size().IsEmpty(),
- bounds() == pile_->tiling_size())
+ DCHECK_IMPLIES(!raster_source_->GetSize().IsEmpty(),
+ bounds() == raster_source_->GetSize())
<< " bounds " << bounds().ToString() << " pile "
- << pile_->tiling_size().ToString();
+ << raster_source_->GetSize().ToString();
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
- if (pile_->is_solid_color()) {
+ if (raster_source_->IsSolidColor()) {
PopulateSharedQuadState(shared_quad_state);
AppendDebugBorderQuad(
render_pass, bounds(), shared_quad_state, append_quads_data);
- SolidColorLayerImpl::AppendSolidQuads(render_pass,
- occlusion_in_content_space,
- shared_quad_state,
- visible_content_rect(),
- pile_->solid_color(),
- append_quads_data);
+ SolidColorLayerImpl::AppendSolidQuads(
+ render_pass, draw_properties().occlusion_in_content_space,
+ shared_quad_state, visible_content_rect(),
+ raster_source_->GetSolidColor(), append_quads_data);
return;
}
float max_contents_scale = MaximumTilingContentsScale();
- gfx::Transform scaled_draw_transform = draw_transform();
- scaled_draw_transform.Scale(SK_MScalar1 / max_contents_scale,
- SK_MScalar1 / max_contents_scale);
- gfx::Size scaled_content_bounds =
- gfx::ToCeiledSize(gfx::ScaleSize(bounds(), max_contents_scale));
- gfx::Rect scaled_visible_content_rect =
- gfx::ScaleToEnclosingRect(visible_content_rect(), max_contents_scale);
- scaled_visible_content_rect.Intersect(gfx::Rect(scaled_content_bounds));
+ PopulateScaledSharedQuadState(shared_quad_state, max_contents_scale);
Occlusion scaled_occlusion =
- occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
- scaled_draw_transform);
-
- shared_quad_state->SetAll(scaled_draw_transform,
- scaled_content_bounds,
- scaled_visible_content_rect,
- draw_properties().clip_rect,
- draw_properties().is_clipped,
- draw_properties().opacity,
- blend_mode(),
- sorting_context_id_);
+ draw_properties()
+ .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
+ shared_quad_state->content_to_target_transform);
if (current_draw_mode_ == DRAW_MODE_RESOURCELESS_SOFTWARE) {
AppendDebugBorderQuad(
- render_pass,
- scaled_content_bounds,
- shared_quad_state,
- append_quads_data,
- DebugColors::DirectPictureBorderColor(),
+ render_pass, shared_quad_state->content_bounds, shared_quad_state,
+ append_quads_data, DebugColors::DirectPictureBorderColor(),
DebugColors::DirectPictureBorderWidth(layer_tree_impl()));
- gfx::Rect geometry_rect = scaled_visible_content_rect;
+ gfx::Rect geometry_rect = shared_quad_state->visible_content_rect;
gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect();
gfx::Rect visible_geometry_rect =
scaled_occlusion.GetUnoccludedContentRect(geometry_rect);
if (visible_geometry_rect.IsEmpty())
return;
- gfx::Size texture_size = scaled_visible_content_rect.size();
+ gfx::Rect quad_content_rect = shared_quad_state->visible_content_rect;
+ gfx::Size texture_size = quad_content_rect.size();
gfx::RectF texture_rect = gfx::RectF(texture_size);
- gfx::Rect quad_content_rect = scaled_visible_content_rect;
PictureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- opaque_rect,
- visible_geometry_rect,
- texture_rect,
- texture_size,
- RGBA_8888,
- quad_content_rect,
- max_contents_scale,
- pile_);
+ quad->SetNew(shared_quad_state, geometry_rect, opaque_rect,
+ visible_geometry_rect, texture_rect, texture_size,
+ nearest_neighbor_, RGBA_8888, quad_content_rect,
+ max_contents_scale, raster_source_);
+ ValidateQuadResources(quad);
return;
}
- AppendDebugBorderQuad(
- render_pass, scaled_content_bounds, shared_quad_state, append_quads_data);
+ AppendDebugBorderQuad(render_pass, shared_quad_state->content_bounds,
+ shared_quad_state, append_quads_data);
if (ShowDebugBorders()) {
for (PictureLayerTilingSet::CoverageIterator iter(
- tilings_.get(),
- max_contents_scale,
- scaled_visible_content_rect,
- ideal_contents_scale_);
- iter;
- ++iter) {
+ tilings_.get(), max_contents_scale,
+ shared_quad_state->visible_content_rect, ideal_contents_scale_);
+ iter; ++iter) {
SkColor color;
float width;
- if (*iter && iter->IsReadyToDraw()) {
- ManagedTileState::DrawInfo::Mode mode = iter->draw_info().mode();
- if (mode == ManagedTileState::DrawInfo::SOLID_COLOR_MODE) {
+ if (*iter && iter->draw_info().IsReadyToDraw()) {
+ TileDrawInfo::Mode mode = iter->draw_info().mode();
+ if (mode == TileDrawInfo::SOLID_COLOR_MODE) {
color = DebugColors::SolidColorTileBorderColor();
width = DebugColors::SolidColorTileBorderWidth(layer_tree_impl());
- } else if (mode == ManagedTileState::DrawInfo::PICTURE_PILE_MODE) {
- color = DebugColors::PictureTileBorderColor();
- width = DebugColors::PictureTileBorderWidth(layer_tree_impl());
+ } else if (mode == TileDrawInfo::OOM_MODE) {
+ color = DebugColors::OOMTileBorderColor();
+ width = DebugColors::OOMTileBorderWidth(layer_tree_impl());
} else if (iter.resolution() == HIGH_RESOLUTION) {
color = DebugColors::HighResTileBorderColor();
width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
@@ -307,23 +251,21 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
// Keep track of the tilings that were used so that tilings that are
// unused can be considered for removal.
- std::vector<PictureLayerTiling*> seen_tilings;
+ last_append_quads_tilings_.clear();
// Ignore missing tiles outside of viewport for tile priority. This is
// normally the same as draw viewport but can be independently overridden by
// embedders like Android WebView with SetExternalDrawConstraints.
gfx::Rect scaled_viewport_for_tile_priority = gfx::ScaleToEnclosingRect(
- GetViewportForTilePriorityInContentSpace(), max_contents_scale);
+ viewport_rect_for_tile_priority_in_content_space_, max_contents_scale);
size_t missing_tile_count = 0u;
size_t on_demand_missing_tile_count = 0u;
only_used_low_res_last_append_quads_ = true;
- for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(),
- max_contents_scale,
- scaled_visible_content_rect,
- ideal_contents_scale_);
- iter;
- ++iter) {
+ for (PictureLayerTilingSet::CoverageIterator iter(
+ tilings_.get(), max_contents_scale,
+ shared_quad_state->visible_content_rect, ideal_contents_scale_);
+ iter; ++iter) {
gfx::Rect geometry_rect = iter.geometry_rect();
gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect();
gfx::Rect visible_geometry_rect =
@@ -335,10 +277,10 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
visible_geometry_rect.width() * visible_geometry_rect.height();
bool has_draw_quad = false;
- if (*iter && iter->IsReadyToDraw()) {
- const ManagedTileState::DrawInfo& draw_info = iter->draw_info();
+ if (*iter && iter->draw_info().IsReadyToDraw()) {
+ const TileDrawInfo& draw_info = iter->draw_info();
switch (draw_info.mode()) {
- case ManagedTileState::DrawInfo::RESOURCE_MODE: {
+ case TileDrawInfo::RESOURCE_MODE: {
gfx::RectF texture_rect = iter.texture_rect();
// The raster_contents_scale_ is the best scale that the layer is
@@ -355,57 +297,25 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
TileDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- opaque_rect,
- visible_geometry_rect,
- draw_info.get_resource_id(),
- texture_rect,
- iter.texture_size(),
- draw_info.contents_swizzled());
+ quad->SetNew(shared_quad_state, geometry_rect, opaque_rect,
+ visible_geometry_rect, draw_info.resource_id(),
+ texture_rect, draw_info.resource_size(),
+ draw_info.contents_swizzled(), nearest_neighbor_);
+ ValidateQuadResources(quad);
has_draw_quad = true;
break;
}
- case ManagedTileState::DrawInfo::PICTURE_PILE_MODE: {
- if (!layer_tree_impl()
- ->GetRendererCapabilities()
- .allow_rasterize_on_demand) {
- ++on_demand_missing_tile_count;
- break;
- }
-
- gfx::RectF texture_rect = iter.texture_rect();
-
- ResourceProvider* resource_provider =
- layer_tree_impl()->resource_provider();
- ResourceFormat format =
- resource_provider->memory_efficient_texture_format();
- PictureDrawQuad* quad =
- render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- opaque_rect,
- visible_geometry_rect,
- texture_rect,
- iter.texture_size(),
- format,
- iter->content_rect(),
- iter->contents_scale(),
- pile_);
- has_draw_quad = true;
- break;
- }
- case ManagedTileState::DrawInfo::SOLID_COLOR_MODE: {
+ case TileDrawInfo::SOLID_COLOR_MODE: {
SolidColorDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- visible_geometry_rect,
- draw_info.get_solid_color(),
- false);
+ quad->SetNew(shared_quad_state, geometry_rect, visible_geometry_rect,
+ draw_info.solid_color(), false);
+ ValidateQuadResources(quad);
has_draw_quad = true;
break;
}
+ case TileDrawInfo::OOM_MODE:
+ break; // Checkerboard.
}
}
@@ -414,8 +324,8 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
CheckerboardDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
SkColor color = DebugColors::DefaultCheckerboardColor();
- quad->SetNew(
- shared_quad_state, geometry_rect, visible_geometry_rect, color);
+ quad->SetNew(shared_quad_state, geometry_rect, visible_geometry_rect,
+ color, draw_properties().device_scale_factor);
} else {
SkColor color = SafeOpaqueBackgroundColor();
SolidColorDrawQuad* quad =
@@ -425,6 +335,7 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
visible_geometry_rect,
color,
false);
+ ValidateQuadResources(quad);
}
if (geometry_rect.Intersects(scaled_viewport_for_tile_priority)) {
@@ -433,6 +344,8 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
}
append_quads_data->approximated_visible_content_area +=
visible_geometry_rect.width() * visible_geometry_rect.height();
+ append_quads_data->checkerboarded_visible_content_area +=
+ visible_geometry_rect.width() * visible_geometry_rect.height();
continue;
}
@@ -446,8 +359,10 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
if (iter.resolution() != LOW_RESOLUTION)
only_used_low_res_last_append_quads_ = false;
- if (seen_tilings.empty() || seen_tilings.back() != iter.CurrentTiling())
- seen_tilings.push_back(iter.CurrentTiling());
+ if (last_append_quads_tilings_.empty() ||
+ last_append_quads_tilings_.back() != iter.CurrentTiling()) {
+ last_append_quads_tilings_.push_back(iter.CurrentTiling());
+ }
}
if (missing_tile_count) {
@@ -464,16 +379,13 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
// that this is at the expense of doing cause more frequent re-painting. A
// better scheme would be to maintain a tighter visible_content_rect for the
// finer tilings.
- CleanUpTilingsOnActiveLayer(seen_tilings);
+ CleanUpTilingsOnActiveLayer(last_append_quads_tilings_);
}
-void PictureLayerImpl::UpdateTiles(const Occlusion& occlusion_in_content_space,
- bool resourceless_software_draw) {
+bool PictureLayerImpl::UpdateTiles(bool resourceless_software_draw) {
DCHECK_EQ(1.f, contents_scale_x());
DCHECK_EQ(1.f, contents_scale_y());
- DoPostCommitInitializationIfNeeded();
-
if (!resourceless_software_draw) {
visible_rect_for_tile_priority_ = visible_content_rect();
}
@@ -484,13 +396,19 @@ void PictureLayerImpl::UpdateTiles(const Occlusion& occlusion_in_content_space,
ideal_contents_scale_ = 0.f;
ideal_source_scale_ = 0.f;
SanityCheckTilingState();
- return;
+ return false;
}
+ // Remove any non-ideal tilings that were not used last time we generated
+ // quads to save memory and processing time. Note that pending tree should
+ // only have one or two tilings (high and low res), so only clean up the
+ // active layer. This cleans it up here in case AppendQuads didn't run.
+ // If it did run, this would not remove any additional tilings.
+ if (layer_tree_impl()->IsActiveTree())
+ CleanUpTilingsOnActiveLayer(last_append_quads_tilings_);
+
UpdateIdealScales();
- DCHECK(tilings_->num_tilings() > 0 || raster_contents_scale_ == 0.f)
- << "A layer with no tilings shouldn't have valid raster scales";
if (!raster_contents_scale_ || ShouldAdjustRasterScale()) {
RecalculateRasterScales();
AddTilingsForRasterScale();
@@ -506,59 +424,45 @@ void PictureLayerImpl::UpdateTiles(const Occlusion& occlusion_in_content_space,
draw_properties().screen_space_transform_is_animating;
if (draw_transform_is_animating())
- pile_->set_likely_to_be_used_for_transform_animation();
-
- should_update_tile_priorities_ = true;
+ raster_source_->SetShouldAttemptToUseDistanceFieldText();
- UpdateTilePriorities(occlusion_in_content_space);
-}
-
-void PictureLayerImpl::UpdateTilePriorities(
- const Occlusion& occlusion_in_content_space) {
- DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
double current_frame_time_in_seconds =
(layer_tree_impl()->CurrentBeginFrameArgs().frame_time -
base::TimeTicks()).InSecondsF();
-
- gfx::Rect viewport_rect_in_layer_space =
- GetViewportForTilePriorityInContentSpace();
- bool tiling_needs_update = false;
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- if (tilings_->tiling_at(i)->NeedsUpdateForFrameAtTimeAndViewport(
- current_frame_time_in_seconds, viewport_rect_in_layer_space)) {
- tiling_needs_update = true;
- break;
- }
- }
- if (!tiling_needs_update)
- return;
-
- WhichTree tree =
- layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
+ UpdateViewportRectForTilePriorityInContentSpace();
+
+ // The tiling set can require tiles for activation any of the following
+ // conditions are true:
+ // - This layer produced a high-res or non-ideal-res tile last frame.
+ // - We're in requires high res to draw mode.
+ // - We're not in smoothness takes priority mode.
+ // To put different, the tiling set can't require tiles for activation if
+ // we're in smoothness mode and only used low-res or checkerboard to draw last
+ // frame and we don't need high res to draw.
+ //
+ // The reason for this is that we should be able to activate sooner and get a
+ // more up to date recording, so we don't run out of recording on the active
+ // tree.
bool can_require_tiles_for_activation =
!only_used_low_res_last_append_quads_ || RequiresHighResToDraw() ||
!layer_tree_impl()->SmoothnessTakesPriority();
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = tilings_->tiling_at(i);
-
- tiling->set_can_require_tiles_for_activation(
- can_require_tiles_for_activation);
-
- // Pass |occlusion_in_content_space| for |occlusion_in_layer_space| since
- // they are the same space in picture layer, as contents scale is always 1.
- tiling->ComputeTilePriorityRects(tree,
- viewport_rect_in_layer_space,
- ideal_contents_scale_,
- current_frame_time_in_seconds,
- occlusion_in_content_space);
- }
- // Tile priorities were modified.
- // TODO(vmpstr): See if this can be removed in favour of calling it from LTHI
- layer_tree_impl()->DidModifyTilePriorities();
+ static const Occlusion kEmptyOcclusion;
+ const Occlusion& occlusion_in_content_space =
+ layer_tree_impl()->settings().use_occlusion_for_tile_prioritization
+ ? draw_properties().occlusion_in_content_space
+ : kEmptyOcclusion;
+
+ // Pass |occlusion_in_content_space| for |occlusion_in_layer_space| since
+ // they are the same space in picture layer, as contents scale is always 1.
+ bool updated = tilings_->UpdateTilePriorities(
+ viewport_rect_for_tile_priority_in_content_space_, ideal_contents_scale_,
+ current_frame_time_in_seconds, occlusion_in_content_space,
+ can_require_tiles_for_activation);
+ return updated;
}
-gfx::Rect PictureLayerImpl::GetViewportForTilePriorityInContentSpace() const {
+void PictureLayerImpl::UpdateViewportRectForTilePriorityInContentSpace() {
// If visible_rect_for_tile_priority_ is empty or
// viewport_rect_for_tile_priority is set to be different from the device
// viewport, try to inverse project the viewport into layer space and use
@@ -566,7 +470,6 @@ gfx::Rect PictureLayerImpl::GetViewportForTilePriorityInContentSpace() const {
gfx::Rect visible_rect_in_content_space = visible_rect_for_tile_priority_;
gfx::Rect viewport_rect_for_tile_priority =
layer_tree_impl()->ViewportRectForTilePriority();
-
if (visible_rect_in_content_space.IsEmpty() ||
layer_tree_impl()->DeviceViewport() != viewport_rect_for_tile_priority) {
gfx::Transform view_to_layer(gfx::Transform::kSkipInitialization);
@@ -577,7 +480,8 @@ gfx::Rect PictureLayerImpl::GetViewportForTilePriorityInContentSpace() const {
view_to_layer, viewport_rect_for_tile_priority));
}
}
- return visible_rect_in_content_space;
+ viewport_rect_for_tile_priority_in_content_space_ =
+ visible_rect_in_content_space;
}
PictureLayerImpl* PictureLayerImpl::GetPendingOrActiveTwinLayer() const {
@@ -592,6 +496,87 @@ PictureLayerImpl* PictureLayerImpl::GetRecycledTwinLayer() const {
return twin_layer_;
}
+void PictureLayerImpl::UpdateRasterSource(
+ scoped_refptr<RasterSource> raster_source,
+ Region* new_invalidation,
+ const PictureLayerTilingSet* pending_set) {
+ // The bounds and the pile size may differ if the pile wasn't updated (ie.
+ // PictureLayer::Update didn't happen). In that case the pile will be empty.
+ DCHECK_IMPLIES(!raster_source->GetSize().IsEmpty(),
+ bounds() == raster_source->GetSize())
+ << " bounds " << bounds().ToString() << " pile "
+ << raster_source->GetSize().ToString();
+
+ // The |raster_source_| is initially null, so have to check for that for the
+ // first frame.
+ bool could_have_tilings = raster_source_.get() && CanHaveTilings();
+ raster_source_.swap(raster_source);
+
+ // The |new_invalidation| must be cleared before updating tilings since they
+ // access the invalidation through the PictureLayerTilingClient interface.
+ invalidation_.Clear();
+ invalidation_.Swap(new_invalidation);
+
+ bool can_have_tilings = CanHaveTilings();
+ DCHECK_IMPLIES(
+ pending_set,
+ can_have_tilings == GetPendingOrActiveTwinLayer()->CanHaveTilings());
+
+ // Need to call UpdateTiles again if CanHaveTilings changed.
+ if (could_have_tilings != can_have_tilings)
+ layer_tree_impl()->set_needs_update_draw_properties();
+
+ if (!can_have_tilings) {
+ RemoveAllTilings();
+ return;
+ }
+
+ // We could do this after doing UpdateTiles, which would avoid doing this for
+ // tilings that are going to disappear on the pending tree (if scale changed).
+ // But that would also be more complicated, so we just do it here for now.
+ if (pending_set) {
+ tilings_->UpdateTilingsToCurrentRasterSourceForActivation(
+ raster_source_, pending_set, invalidation_, MinimumContentsScale(),
+ MaximumContentsScale());
+ } else {
+ tilings_->UpdateTilingsToCurrentRasterSourceForCommit(
+ raster_source_, invalidation_, MinimumContentsScale(),
+ MaximumContentsScale());
+ }
+}
+
+void PictureLayerImpl::UpdateCanUseLCDTextAfterCommit() {
+ // This function is only allowed to be called after commit, due to it not
+ // being smart about sharing tiles and because otherwise it would cause
+ // flashes by switching out tiles in place that may be currently on screen.
+ DCHECK(layer_tree_impl()->IsSyncTree());
+
+ // Don't allow the LCD text state to change once disabled.
+ if (!RasterSourceUsesLCDText())
+ return;
+ if (can_use_lcd_text() == RasterSourceUsesLCDText())
+ return;
+
+ // Raster sources are considered const, so in order to update the state
+ // a new one must be created and all tiles recreated.
+ scoped_refptr<RasterSource> new_raster_source =
+ raster_source_->CreateCloneWithoutLCDText();
+ raster_source_.swap(new_raster_source);
+
+ // Synthetically invalidate everything.
+ gfx::Rect bounds_rect(bounds());
+ invalidation_ = Region(bounds_rect);
+ tilings_->UpdateRasterSourceDueToLCDChange(raster_source_, invalidation_);
+ SetUpdateRect(bounds_rect);
+
+ DCHECK(!RasterSourceUsesLCDText());
+}
+
+bool PictureLayerImpl::RasterSourceUsesLCDText() const {
+ return raster_source_ ? raster_source_->CanUseLCDText()
+ : layer_tree_impl()->settings().can_use_lcd_text;
+}
+
void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
if (layer_tree_impl()->IsActiveTree()) {
gfx::RectF layer_damage_rect =
@@ -600,21 +585,19 @@ void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
}
}
-void PictureLayerImpl::DidBecomeActive() {
- LayerImpl::DidBecomeActive();
- // TODO(vmpstr): See if this can be removed in favour of calling it from LTHI
- layer_tree_impl()->DidModifyTilePriorities();
-}
-
void PictureLayerImpl::DidBeginTracing() {
- pile_->DidBeginTracing();
+ raster_source_->DidBeginTracing();
}
void PictureLayerImpl::ReleaseResources() {
- if (tilings_)
- RemoveAllTilings();
-
+ // Recreate tilings with new settings, since some of those might change when
+ // we release resources.
+ tilings_ = nullptr;
ResetRasterScale();
+}
+
+void PictureLayerImpl::RecreateResources() {
+ tilings_ = CreatePictureLayerTilingSet();
// To avoid an edge case after lost context where the tree is up to date but
// the tilings have not been managed, request an update draw properties
@@ -623,43 +606,37 @@ void PictureLayerImpl::ReleaseResources() {
}
skia::RefPtr<SkPicture> PictureLayerImpl::GetPicture() {
- return pile_->GetFlattenedPicture();
+ return raster_source_->GetFlattenedPicture();
}
-scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling,
- const gfx::Rect& content_rect) {
- DCHECK(!pile_->is_solid_color());
- if (!pile_->CoversRect(content_rect, tiling->contents_scale()))
- return scoped_refptr<Tile>();
+Region PictureLayerImpl::GetInvalidationRegion() {
+ // |invalidation_| gives the invalidation contained in the source frame, but
+ // is not cleared after drawing from the layer. However, update_rect() is
+ // cleared once the invalidation is drawn, which is useful for debugging
+ // visualizations. This method intersects the two to give a more exact
+ // representation of what was invalidated that is cleared after drawing.
+ return IntersectRegions(invalidation_, update_rect());
+}
+ScopedTilePtr PictureLayerImpl::CreateTile(float contents_scale,
+ const gfx::Rect& content_rect) {
int flags = 0;
- // TODO(vmpstr): Revisit this. For now, enabling analysis means that we get as
- // much savings on memory as we can. However, for some cases like ganesh or
- // small layers, the amount of time we spend analyzing might not justify
- // memory savings that we can get. Note that we don't handle solid color
- // masks, so we shouldn't bother analyzing those.
- // Bugs: crbug.com/397198, crbug.com/396908
- if (!pile_->is_mask())
+ // We don't handle solid color masks, so we shouldn't bother analyzing those.
+ // Otherwise, always analyze to maximize memory savings.
+ if (!is_mask_)
flags = Tile::USE_PICTURE_ANALYSIS;
return layer_tree_impl()->tile_manager()->CreateTile(
- pile_.get(),
- content_rect.size(),
- content_rect,
- tiling->contents_scale(),
- id(),
- layer_tree_impl()->source_frame_number(),
- flags);
-}
-
-RasterSource* PictureLayerImpl::GetRasterSource() {
- return pile_.get();
+ content_rect.size(), content_rect, contents_scale, id(),
+ layer_tree_impl()->source_frame_number(), flags);
}
const Region* PictureLayerImpl::GetPendingInvalidation() {
if (layer_tree_impl()->IsPendingTree())
return &invalidation_;
+ if (layer_tree_impl()->IsRecycleTree())
+ return nullptr;
DCHECK(layer_tree_impl()->IsActiveTree());
if (PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer())
return &twin_layer->invalidation_;
@@ -671,55 +648,33 @@ const PictureLayerTiling* PictureLayerImpl::GetPendingOrActiveTwinTiling(
PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer();
if (!twin_layer)
return nullptr;
- // TODO(danakj): Remove this when no longer swapping tilings.
- if (!twin_layer->tilings_)
- return nullptr;
- return twin_layer->tilings_->TilingAtScale(tiling->contents_scale());
-}
-
-PictureLayerTiling* PictureLayerImpl::GetRecycledTwinTiling(
- const PictureLayerTiling* tiling) {
- PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
- if (!recycled_twin || !recycled_twin->tilings_)
- return nullptr;
- return recycled_twin->tilings_->TilingAtScale(tiling->contents_scale());
-}
-
-size_t PictureLayerImpl::GetMaxTilesForInterestArea() const {
- return layer_tree_impl()->settings().max_tiles_for_interest_area;
+ return twin_layer->tilings_->FindTilingWithScale(tiling->contents_scale());
}
-float PictureLayerImpl::GetSkewportTargetTimeInSeconds() const {
- float skewport_target_time_in_frames =
- layer_tree_impl()->use_gpu_rasterization()
- ? kGpuSkewportTargetTimeInFrames
- : kCpuSkewportTargetTimeInFrames;
- return skewport_target_time_in_frames *
- layer_tree_impl()->begin_impl_frame_interval().InSecondsF() *
- layer_tree_impl()->settings().skewport_target_time_multiplier;
-}
-
-int PictureLayerImpl::GetSkewportExtrapolationLimitInContentPixels() const {
- return layer_tree_impl()
- ->settings()
- .skewport_extrapolation_limit_in_content_pixels;
+TilePriority::PriorityBin PictureLayerImpl::GetMaxTilePriorityBin() const {
+ if (!HasValidTilePriorities())
+ return TilePriority::EVENTUALLY;
+ return TilePriority::NOW;
}
bool PictureLayerImpl::RequiresHighResToDraw() const {
return layer_tree_impl()->RequiresHighResToDraw();
}
+gfx::Rect PictureLayerImpl::GetEnclosingRectInTargetSpace() const {
+ return GetScaledEnclosingRectInTargetSpace(MaximumTilingContentsScale());
+}
+
gfx::Size PictureLayerImpl::CalculateTileSize(
const gfx::Size& content_bounds) const {
int max_texture_size =
layer_tree_impl()->resource_provider()->max_texture_size();
- if (pile_->is_mask()) {
+ if (is_mask_) {
// Masks are not tiled, so if we can't cover the whole mask with one tile,
- // don't make any tiles at all. Returning an empty size signals this.
- if (content_bounds.width() > max_texture_size ||
- content_bounds.height() > max_texture_size)
- return gfx::Size();
+ // we shouldn't have such a tiling at all.
+ DCHECK_LE(content_bounds.width(), max_texture_size);
+ DCHECK_LE(content_bounds.height(), max_texture_size);
return content_bounds;
}
@@ -729,9 +684,10 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
// For GPU rasterization, we pick an ideal tile size using the viewport
// so we don't need any settings. The current approach uses 4 tiles
// to cover the viewport vertically.
- int viewport_width = layer_tree_impl()->device_viewport_size().width();
- int viewport_height = layer_tree_impl()->device_viewport_size().height();
+ int viewport_width = gpu_raster_max_texture_size_.width();
+ int viewport_height = gpu_raster_max_texture_size_.height();
default_tile_width = viewport_width;
+
// Also, increase the height proportionally as the width decreases, and
// pad by our border texels to make the tiles exactly match the viewport.
int divisor = 4;
@@ -740,7 +696,11 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
if (content_bounds.width() <= viewport_width / 4)
divisor = 1;
default_tile_height = RoundUp(viewport_height, divisor) / divisor;
+
+ // Grow default sizes to account for overlapping border texels.
+ default_tile_width += 2 * PictureLayerTiling::kBorderTexels;
default_tile_height += 2 * PictureLayerTiling::kBorderTexels;
+
default_tile_height =
std::max(default_tile_height, kMinHeightForGpuRasteredTile);
} else {
@@ -786,70 +746,15 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
return gfx::Size(tile_width, tile_height);
}
-void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
- DCHECK(!other->needs_post_commit_initialization_);
- DCHECK(other->tilings_);
-
- if (!DrawsContent()) {
- RemoveAllTilings();
- return;
- }
-
- raster_page_scale_ = other->raster_page_scale_;
- raster_device_scale_ = other->raster_device_scale_;
- raster_source_scale_ = other->raster_source_scale_;
- raster_contents_scale_ = other->raster_contents_scale_;
- low_res_raster_contents_scale_ = other->low_res_raster_contents_scale_;
-
- bool synced_high_res_tiling = false;
- if (CanHaveTilings()) {
- synced_high_res_tiling = tilings_->SyncTilings(*other->tilings_,
- pile_->tiling_size(),
- invalidation_,
- MinimumContentsScale());
- } else {
- RemoveAllTilings();
- }
-
- // If our MinimumContentsScale has changed to prevent the twin's high res
- // tiling from being synced, we should reset the raster scale and let it be
- // recalculated (1) again. This can happen if our bounds shrink to the point
- // where min contents scale grows.
- // (1) - TODO(vmpstr) Instead of hoping that this will be recalculated, we
- // should refactor this code a little bit and actually recalculate this.
- // However, this is a larger undertaking, so this will work for now.
- if (!synced_high_res_tiling)
- ResetRasterScale();
- else
- SanityCheckTilingState();
-}
-
-void PictureLayerImpl::SyncTiling(
- const PictureLayerTiling* tiling) {
- if (!tilings_)
- return;
- if (!CanHaveTilingWithScale(tiling->contents_scale()))
- return;
- tilings_->AddTiling(tiling->contents_scale(), pile_->tiling_size());
-
- // If this tree needs update draw properties, then the tiling will
- // get updated prior to drawing or activation. If this tree does not
- // need update draw properties, then its transforms are up to date and
- // we can create tiles for this tiling immediately.
- if (!layer_tree_impl()->needs_update_draw_properties() &&
- should_update_tile_priorities_) {
- // TODO(danakj): Add a DCHECK() that we are not using occlusion tracking
- // when we stop using the pending tree in the browser compositor. If we want
- // to support occlusion tracking here, we need to dirty the draw properties
- // or save occlusion as a draw property.
- UpdateTilePriorities(Occlusion());
- }
-}
-
void PictureLayerImpl::GetContentsResourceId(
ResourceProvider::ResourceId* resource_id,
gfx::Size* resource_size) const {
- DCHECK_EQ(bounds().ToString(), pile_->tiling_size().ToString());
+ // The bounds and the pile size may differ if the pile wasn't updated (ie.
+ // PictureLayer::Update didn't happen). In that case the pile will be empty.
+ DCHECK_IMPLIES(!raster_source_->GetSize().IsEmpty(),
+ bounds() == raster_source_->GetSize())
+ << " bounds " << bounds().ToString() << " pile "
+ << raster_source_->GetSize().ToString();
gfx::Rect content_rect(bounds());
PictureLayerTilingSet::CoverageIterator iter(
tilings_.get(), 1.f, content_rect, ideal_contents_scale_);
@@ -865,111 +770,65 @@ void PictureLayerImpl::GetContentsResourceId(
<< "iter rect " << iter.geometry_rect().ToString() << " content rect "
<< content_rect.ToString();
- const ManagedTileState::DrawInfo& draw_info = iter->draw_info();
+ const TileDrawInfo& draw_info = iter->draw_info();
if (!draw_info.IsReadyToDraw() ||
- draw_info.mode() != ManagedTileState::DrawInfo::RESOURCE_MODE) {
+ draw_info.mode() != TileDrawInfo::RESOURCE_MODE) {
*resource_id = 0;
return;
}
- *resource_id = draw_info.get_resource_id();
- *resource_size = iter.texture_size();
+ *resource_id = draw_info.resource_id();
+ *resource_size = draw_info.resource_size();
}
-void PictureLayerImpl::DoPostCommitInitialization() {
- DCHECK(needs_post_commit_initialization_);
- DCHECK(layer_tree_impl()->IsPendingTree());
-
- if (!tilings_)
- tilings_ = make_scoped_ptr(new PictureLayerTilingSet(this));
-
- PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer();
- if (twin_layer) {
- // If the twin has never been pushed to, do not sync from it.
- // This can happen if this function is called during activation.
- if (!twin_layer->needs_post_commit_initialization_)
- SyncFromActiveLayer(twin_layer);
- }
+void PictureLayerImpl::SetNearestNeighbor(bool nearest_neighbor) {
+ if (nearest_neighbor_ == nearest_neighbor)
+ return;
- needs_post_commit_initialization_ = false;
+ nearest_neighbor_ = nearest_neighbor;
+ NoteLayerPropertyChanged();
}
PictureLayerTiling* PictureLayerImpl::AddTiling(float contents_scale) {
- DCHECK(CanHaveTilingWithScale(contents_scale)) <<
- "contents_scale: " << contents_scale;
-
- PictureLayerTiling* tiling =
- tilings_->AddTiling(contents_scale, pile_->tiling_size());
-
- DCHECK(pile_->HasRecordings());
-
- if (PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer())
- twin_layer->SyncTiling(tiling);
-
- return tiling;
-}
-
-void PictureLayerImpl::RemoveTiling(float contents_scale) {
- if (!tilings_ || tilings_->num_tilings() == 0)
- return;
-
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = tilings_->tiling_at(i);
- if (tiling->contents_scale() == contents_scale) {
- tilings_->Remove(tiling);
- break;
- }
- }
- if (tilings_->num_tilings() == 0)
- ResetRasterScale();
- SanityCheckTilingState();
+ DCHECK(CanHaveTilings());
+ DCHECK_GE(contents_scale, MinimumContentsScale());
+ DCHECK_LE(contents_scale, MaximumContentsScale());
+ DCHECK(raster_source_->HasRecordings());
+ return tilings_->AddTiling(contents_scale, raster_source_);
}
void PictureLayerImpl::RemoveAllTilings() {
- if (tilings_)
- tilings_->RemoveAllTilings();
+ tilings_->RemoveAllTilings();
// If there are no tilings, then raster scales are no longer meaningful.
ResetRasterScale();
}
-namespace {
-
-inline float PositiveRatio(float float1, float float2) {
- DCHECK_GT(float1, 0);
- DCHECK_GT(float2, 0);
- return float1 > float2 ? float1 / float2 : float2 / float1;
-}
-
-} // namespace
-
void PictureLayerImpl::AddTilingsForRasterScale() {
- PictureLayerTiling* high_res = nullptr;
- PictureLayerTiling* low_res = nullptr;
-
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = tilings_->tiling_at(i);
- if (tiling->contents_scale() == raster_contents_scale_)
- high_res = tiling;
- if (tiling->contents_scale() == low_res_raster_contents_scale_)
- low_res = tiling;
-
- // Reset all tilings to non-ideal until the end of this function.
- tiling->set_resolution(NON_IDEAL_RESOLUTION);
- }
-
- if (!high_res) {
+ // Reset all resolution enums on tilings, we'll be setting new values in this
+ // function.
+ tilings_->MarkAllTilingsNonIdeal();
+
+ PictureLayerTiling* high_res =
+ tilings_->FindTilingWithScale(raster_contents_scale_);
+ // We always need a high res tiling, so create one if it doesn't exist.
+ if (!high_res)
high_res = AddTiling(raster_contents_scale_);
- if (raster_contents_scale_ == low_res_raster_contents_scale_)
- low_res = high_res;
- }
+
+ // Try and find a low res tiling.
+ PictureLayerTiling* low_res = nullptr;
+ if (raster_contents_scale_ == low_res_raster_contents_scale_)
+ low_res = high_res;
+ else
+ low_res = tilings_->FindTilingWithScale(low_res_raster_contents_scale_);
// Only create new low res tilings when the transform is static. This
// prevents wastefully creating a paired low res tiling for every new high res
// tiling during a pinch or a CSS animation.
+ bool can_have_low_res = layer_tree_impl()->create_low_res_tiling();
+ bool needs_low_res = !low_res;
bool is_pinching = layer_tree_impl()->PinchGestureActive();
- if (layer_tree_impl()->create_low_res_tiling() && !is_pinching &&
- !draw_properties().screen_space_transform_is_animating && !low_res &&
- low_res != high_res)
+ bool is_animating = draw_properties().screen_space_transform_is_animating;
+ if (can_have_low_res && needs_low_res && !is_pinching && !is_animating)
low_res = AddTiling(low_res_raster_contents_scale_);
// Set low-res if we have one.
@@ -979,6 +838,12 @@ void PictureLayerImpl::AddTilingsForRasterScale() {
// Make sure we always have one high-res (even if high == low).
high_res->set_resolution(HIGH_RESOLUTION);
+ if (layer_tree_impl()->IsPendingTree()) {
+ // On the pending tree, drop any tilings that are non-ideal since we don't
+ // need them to activate anyway.
+ tilings_->RemoveNonIdealTilings();
+ }
+
SanityCheckTilingState();
}
@@ -1020,22 +885,12 @@ bool PictureLayerImpl::ShouldAdjustRasterScale() const {
raster_source_scale_ != ideal_source_scale_)
return true;
- return false;
-}
+ if (raster_contents_scale_ > MaximumContentsScale())
+ return true;
+ if (raster_contents_scale_ < MinimumContentsScale())
+ return true;
-float PictureLayerImpl::SnappedContentsScale(float scale) {
- // If a tiling exists within the max snapping ratio, snap to its scale.
- float snapped_contents_scale = scale;
- float snapped_ratio = kSnapToExistingTilingRatio;
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- float tiling_contents_scale = tilings_->tiling_at(i)->contents_scale();
- float ratio = PositiveRatio(tiling_contents_scale, scale);
- if (ratio < snapped_ratio) {
- snapped_contents_scale = tiling_contents_scale;
- snapped_ratio = ratio;
- }
- }
- return snapped_contents_scale;
+ return false;
}
void PictureLayerImpl::RecalculateRasterScales() {
@@ -1068,17 +923,22 @@ void PictureLayerImpl::RecalculateRasterScales() {
// During pinch we completely ignore the current ideal scale, and just use
// a multiple of the previous scale.
- // TODO(danakj): This seems crazy, we should use the current ideal, no?
bool is_pinching = layer_tree_impl()->PinchGestureActive();
if (is_pinching && old_raster_contents_scale) {
// See ShouldAdjustRasterScale:
// - When zooming out, preemptively create new tiling at lower resolution.
// - When zooming in, approximate ideal using multiple of kMaxScaleRatio.
bool zooming_out = old_raster_page_scale > ideal_page_scale_;
- float desired_contents_scale =
- zooming_out ? old_raster_contents_scale / kMaxScaleRatioDuringPinch
- : old_raster_contents_scale * kMaxScaleRatioDuringPinch;
- raster_contents_scale_ = SnappedContentsScale(desired_contents_scale);
+ float desired_contents_scale = old_raster_contents_scale;
+ if (zooming_out) {
+ while (desired_contents_scale > ideal_contents_scale_)
+ desired_contents_scale /= kMaxScaleRatioDuringPinch;
+ } else {
+ while (desired_contents_scale < ideal_contents_scale_)
+ desired_contents_scale *= kMaxScaleRatioDuringPinch;
+ }
+ raster_contents_scale_ = tilings_->GetSnappedContentsScale(
+ desired_contents_scale, kSnapToExistingTilingRatio);
raster_page_scale_ =
raster_contents_scale_ / raster_device_scale_ / raster_source_scale_;
}
@@ -1092,23 +952,37 @@ void PictureLayerImpl::RecalculateRasterScales() {
if (draw_properties().screen_space_transform_is_animating &&
!ShouldAdjustRasterScaleDuringScaleAnimations()) {
bool can_raster_at_maximum_scale = false;
- // TODO(ajuma): If we need to deal with scale-down animations starting right
- // as a layer gets promoted, then we'd want to have the
- // |starting_animation_contents_scale| passed in here as a separate draw
- // property so we could try use that when the max is too large.
- // See crbug.com/422341.
+ bool should_raster_at_starting_scale = false;
float maximum_scale = draw_properties().maximum_animation_contents_scale;
+ float starting_scale = draw_properties().starting_animation_contents_scale;
if (maximum_scale) {
gfx::Size bounds_at_maximum_scale = gfx::ToCeiledSize(
- gfx::ScaleSize(pile_->tiling_size(), maximum_scale));
- if (bounds_at_maximum_scale.GetArea() <=
- layer_tree_impl()->device_viewport_size().GetArea())
+ gfx::ScaleSize(raster_source_->GetSize(), maximum_scale));
+ int64 maximum_area = static_cast<int64>(bounds_at_maximum_scale.width()) *
+ static_cast<int64>(bounds_at_maximum_scale.height());
+ gfx::Size viewport = layer_tree_impl()->device_viewport_size();
+ int64 viewport_area = static_cast<int64>(viewport.width()) *
+ static_cast<int64>(viewport.height());
+ if (maximum_area <= viewport_area)
can_raster_at_maximum_scale = true;
}
+ if (starting_scale && starting_scale > maximum_scale) {
+ gfx::Size bounds_at_starting_scale = gfx::ToCeiledSize(
+ gfx::ScaleSize(raster_source_->GetSize(), starting_scale));
+ int64 start_area = static_cast<int64>(bounds_at_starting_scale.width()) *
+ static_cast<int64>(bounds_at_starting_scale.height());
+ gfx::Size viewport = layer_tree_impl()->device_viewport_size();
+ int64 viewport_area = static_cast<int64>(viewport.width()) *
+ static_cast<int64>(viewport.height());
+ if (start_area <= viewport_area)
+ should_raster_at_starting_scale = true;
+ }
// Use the computed scales for the raster scale directly, do not try to use
// the ideal scale here. The current ideal scale may be way too large in the
// case of an animation with scale, and will be constantly changing.
- if (can_raster_at_maximum_scale)
+ if (should_raster_at_starting_scale)
+ raster_contents_scale_ = starting_scale;
+ else if (can_raster_at_maximum_scale)
raster_contents_scale_ = maximum_scale;
else
raster_contents_scale_ = 1.f * ideal_page_scale_ * ideal_device_scale_;
@@ -1116,11 +990,15 @@ void PictureLayerImpl::RecalculateRasterScales() {
raster_contents_scale_ =
std::max(raster_contents_scale_, MinimumContentsScale());
+ raster_contents_scale_ =
+ std::min(raster_contents_scale_, MaximumContentsScale());
+ DCHECK_GE(raster_contents_scale_, MinimumContentsScale());
+ DCHECK_LE(raster_contents_scale_, MaximumContentsScale());
// If this layer would create zero or one tiles at this content scale,
// don't create a low res tiling.
gfx::Size raster_bounds = gfx::ToCeiledSize(
- gfx::ScaleSize(pile_->tiling_size(), raster_contents_scale_));
+ gfx::ScaleSize(raster_source_->GetSize(), raster_contents_scale_));
gfx::Size tile_size = CalculateTileSize(raster_bounds);
bool tile_covers_bounds = tile_size.width() >= raster_bounds.width() &&
tile_size.height() >= raster_bounds.height();
@@ -1131,15 +1009,15 @@ void PictureLayerImpl::RecalculateRasterScales() {
float low_res_factor =
layer_tree_impl()->settings().low_res_contents_scale_factor;
- low_res_raster_contents_scale_ = std::max(
- raster_contents_scale_ * low_res_factor,
- MinimumContentsScale());
+ low_res_raster_contents_scale_ =
+ std::max(raster_contents_scale_ * low_res_factor, MinimumContentsScale());
DCHECK_LE(low_res_raster_contents_scale_, raster_contents_scale_);
DCHECK_GE(low_res_raster_contents_scale_, MinimumContentsScale());
+ DCHECK_LE(low_res_raster_contents_scale_, MaximumContentsScale());
}
void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
- std::vector<PictureLayerTiling*> used_tilings) {
+ const std::vector<PictureLayerTiling*>& used_tilings) {
DCHECK(layer_tree_impl()->IsActiveTree());
if (tilings_->num_tilings() == 0)
return;
@@ -1148,7 +1026,6 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
raster_contents_scale_, ideal_contents_scale_);
float max_acceptable_high_res_scale = std::max(
raster_contents_scale_, ideal_contents_scale_);
- float twin_low_res_scale = 0.f;
PictureLayerImpl* twin = GetPendingOrActiveTwinLayer();
if (twin && twin->CanHaveTilings()) {
@@ -1158,63 +1035,21 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
max_acceptable_high_res_scale = std::max(
max_acceptable_high_res_scale,
std::max(twin->raster_contents_scale_, twin->ideal_contents_scale_));
-
- // TODO(danakj): Remove the tilings_ check when we create them in the
- // constructor.
- if (twin->tilings_) {
- for (size_t i = 0; i < twin->tilings_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = twin->tilings_->tiling_at(i);
- if (tiling->resolution() == LOW_RESOLUTION)
- twin_low_res_scale = tiling->contents_scale();
- }
- }
}
- std::vector<PictureLayerTiling*> to_remove;
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = tilings_->tiling_at(i);
-
- // Keep multiple high resolution tilings even if not used to help
- // activate earlier at non-ideal resolutions.
- if (tiling->contents_scale() >= min_acceptable_high_res_scale &&
- tiling->contents_scale() <= max_acceptable_high_res_scale)
- continue;
-
- // Keep low resolution tilings, if the layer should have them.
- if (layer_tree_impl()->create_low_res_tiling()) {
- if (tiling->resolution() == LOW_RESOLUTION ||
- tiling->contents_scale() == twin_low_res_scale)
- continue;
- }
-
- // Don't remove tilings that are being used (and thus would cause a flash.)
- if (std::find(used_tilings.begin(), used_tilings.end(), tiling) !=
- used_tilings.end())
- continue;
-
- to_remove.push_back(tiling);
- }
+ PictureLayerTilingSet* twin_set = twin ? twin->tilings_.get() : nullptr;
+ // TODO(vmpstr): See if this step is required without tile sharing.
+ PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
+ PictureLayerTilingSet* recycled_twin_set =
+ recycled_twin ? recycled_twin->tilings_.get() : nullptr;
- if (to_remove.empty())
- return;
+ tilings_->CleanUpTilings(min_acceptable_high_res_scale,
+ max_acceptable_high_res_scale, used_tilings,
+ layer_tree_impl()->create_low_res_tiling(), twin_set,
+ recycled_twin_set);
- PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
- // Remove tilings on this tree and the twin tree.
- for (size_t i = 0; i < to_remove.size(); ++i) {
- const PictureLayerTiling* twin_tiling =
- GetPendingOrActiveTwinTiling(to_remove[i]);
- // Only remove tilings from the twin layer if they have
- // NON_IDEAL_RESOLUTION.
- if (twin_tiling && twin_tiling->resolution() == NON_IDEAL_RESOLUTION)
- twin->RemoveTiling(to_remove[i]->contents_scale());
- // Remove the tiling from the recycle tree. Note that we ignore resolution,
- // since we don't need to maintain high/low res on the recycle tree.
- if (recycled_twin)
- recycled_twin->RemoveTiling(to_remove[i]->contents_scale());
- // TODO(enne): temporary sanity CHECK for http://crbug.com/358350
- CHECK_NE(HIGH_RESOLUTION, to_remove[i]->resolution());
- tilings_->Remove(to_remove[i]);
- }
+ if (recycled_twin_set && recycled_twin_set->num_tilings() == 0)
+ recycled_twin->ResetRasterScale();
DCHECK_GT(tilings_->num_tilings(), 0u);
SanityCheckTilingState();
@@ -1227,14 +1062,37 @@ float PictureLayerImpl::MinimumContentsScale() const {
// then it will end up having less than one pixel of content in that
// dimension. Bump the minimum contents scale up in this case to prevent
// this from happening.
- int min_dimension =
- std::min(pile_->tiling_size().width(), pile_->tiling_size().height());
+ int min_dimension = std::min(raster_source_->GetSize().width(),
+ raster_source_->GetSize().height());
if (!min_dimension)
return setting_min;
return std::max(1.f / min_dimension, setting_min);
}
+float PictureLayerImpl::MaximumContentsScale() const {
+ // Masks can not have tilings that would become larger than the
+ // max_texture_size since they use a single tile for the entire
+ // tiling. Other layers can have tilings of any scale.
+ if (!is_mask_)
+ return std::numeric_limits<float>::max();
+
+ int max_texture_size =
+ layer_tree_impl()->resource_provider()->max_texture_size();
+ float max_scale_width =
+ static_cast<float>(max_texture_size) / bounds().width();
+ float max_scale_height =
+ static_cast<float>(max_texture_size) / bounds().height();
+ float max_scale = std::min(max_scale_width, max_scale_height);
+ // We require that multiplying the layer size by the contents scale and
+ // ceiling produces a value <= |max_texture_size|. Because for large layer
+ // sizes floating point ambiguity may crop up, making the result larger or
+ // smaller than expected, we use a slightly smaller floating point value for
+ // the scale, to help ensure that the resulting content bounds will never end
+ // up larger than |max_texture_size|.
+ return nextafterf(max_scale, 0.f);
+}
+
void PictureLayerImpl::ResetRasterScale() {
raster_page_scale_ = 0.f;
raster_device_scale_ = 0.f;
@@ -1242,32 +1100,24 @@ void PictureLayerImpl::ResetRasterScale() {
raster_contents_scale_ = 0.f;
low_res_raster_contents_scale_ = 0.f;
raster_source_scale_is_fixed_ = false;
-
- // When raster scales aren't valid, don't update tile priorities until
- // this layer has been updated via UpdateDrawProperties.
- should_update_tile_priorities_ = false;
}
bool PictureLayerImpl::CanHaveTilings() const {
- if (pile_->is_solid_color())
+ if (raster_source_->IsSolidColor())
return false;
if (!DrawsContent())
return false;
- if (!pile_->HasRecordings())
+ if (!raster_source_->HasRecordings())
return false;
- return true;
-}
-
-bool PictureLayerImpl::CanHaveTilingWithScale(float contents_scale) const {
- if (!CanHaveTilings())
- return false;
- if (contents_scale < MinimumContentsScale())
+ // If the |raster_source_| has a recording it should have non-empty bounds.
+ DCHECK(!raster_source_->GetSize().IsEmpty());
+ if (MaximumContentsScale() < MinimumContentsScale())
return false;
return true;
}
void PictureLayerImpl::SanityCheckTilingState() const {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
// Recycle tree doesn't have any restrictions.
if (layer_tree_impl()->IsRecycleTree())
return;
@@ -1289,12 +1139,19 @@ bool PictureLayerImpl::ShouldAdjustRasterScaleDuringScaleAnimations() const {
}
float PictureLayerImpl::MaximumTilingContentsScale() const {
- float max_contents_scale = MinimumContentsScale();
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- const PictureLayerTiling* tiling = tilings_->tiling_at(i);
- max_contents_scale = std::max(max_contents_scale, tiling->contents_scale());
- }
- return max_contents_scale;
+ float max_contents_scale = tilings_->GetMaximumContentsScale();
+ return std::max(max_contents_scale, MinimumContentsScale());
+}
+
+scoped_ptr<PictureLayerTilingSet>
+PictureLayerImpl::CreatePictureLayerTilingSet() {
+ const LayerTreeSettings& settings = layer_tree_impl()->settings();
+ return PictureLayerTilingSet::Create(
+ GetTree(), this, settings.tiling_interest_area_viewport_multiplier,
+ layer_tree_impl()->use_gpu_rasterization()
+ ? settings.gpu_rasterization_skewport_target_time_in_seconds
+ : settings.skewport_target_time_in_seconds,
+ settings.skewport_extrapolation_limit_in_content_pixels);
}
void PictureLayerImpl::UpdateIdealScales() {
@@ -1326,17 +1183,15 @@ void PictureLayerImpl::GetDebugBorderProperties(
*width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
}
-void PictureLayerImpl::GetAllTilesForTracing(
- std::set<const Tile*>* tiles) const {
+void PictureLayerImpl::GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const {
if (!tilings_)
return;
-
- for (size_t i = 0; i < tilings_->num_tilings(); ++i)
- tilings_->tiling_at(i)->GetAllTilesForTracing(tiles);
+ tilings_->GetAllPrioritizedTilesForTracing(prioritized_tiles);
}
-void PictureLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
- const_cast<PictureLayerImpl*>(this)->DoPostCommitInitializationIfNeeded();
+void PictureLayerImpl::AsValueInto(
+ base::trace_event::TracedValue* state) const {
LayerImpl::AsValueInto(state);
state->SetDouble("ideal_contents_scale", ideal_contents_scale_);
state->SetDouble("geometry_contents_scale", MaximumTilingContentsScale());
@@ -1344,16 +1199,13 @@ void PictureLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
tilings_->AsValueInto(state);
state->EndArray();
- state->BeginArray("tile_priority_rect");
- MathUtil::AddToTracedValue(GetViewportForTilePriorityInContentSpace(), state);
- state->EndArray();
-
- state->BeginArray("visible_rect");
- MathUtil::AddToTracedValue(visible_content_rect(), state);
- state->EndArray();
+ MathUtil::AddToTracedValue("tile_priority_rect",
+ viewport_rect_for_tile_priority_in_content_space_,
+ state);
+ MathUtil::AddToTracedValue("visible_rect", visible_content_rect(), state);
state->BeginArray("pictures");
- pile_->AsValueInto(state);
+ raster_source_->AsValueInto(state);
state->EndArray();
state->BeginArray("invalidation");
@@ -1362,17 +1214,12 @@ void PictureLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
state->BeginArray("coverage_tiles");
for (PictureLayerTilingSet::CoverageIterator iter(
- tilings_.get(),
- 1.f,
- gfx::Rect(pile_->tiling_size()),
+ tilings_.get(), 1.f, gfx::Rect(raster_source_->GetSize()),
ideal_contents_scale_);
- iter;
- ++iter) {
+ iter; ++iter) {
state->BeginDictionary();
- state->BeginArray("geometry_rect");
- MathUtil::AddToTracedValue(iter.geometry_rect(), state);
- state->EndArray();
+ MathUtil::AddToTracedValue("geometry_rect", iter.geometry_rect(), state);
if (*iter)
TracedValue::SetIDRef(*iter, state, "tile");
@@ -1383,7 +1230,6 @@ void PictureLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
}
size_t PictureLayerImpl::GPUMemoryUsageInBytes() const {
- const_cast<PictureLayerImpl*>(this)->DoPostCommitInitializationIfNeeded();
return tilings_->GPUMemoryUsageInBytes();
}
@@ -1403,325 +1249,4 @@ bool PictureLayerImpl::HasValidTilePriorities() const {
return IsOnActiveOrPendingTree() && IsDrawnRenderSurfaceLayerListMember();
}
-bool PictureLayerImpl::AllTilesRequiredForActivationAreReadyToDraw() const {
- if (!layer_tree_impl()->IsPendingTree())
- return true;
-
- if (!HasValidTilePriorities())
- return true;
-
- if (!tilings_)
- return true;
-
- if (visible_rect_for_tile_priority_.IsEmpty())
- return true;
-
- gfx::Rect rect = GetViewportForTilePriorityInContentSpace();
- rect.Intersect(visible_rect_for_tile_priority_);
-
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = tilings_->tiling_at(i);
- if (tiling->resolution() != HIGH_RESOLUTION &&
- tiling->resolution() != LOW_RESOLUTION)
- continue;
-
- for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
- ++iter) {
- const Tile* tile = *iter;
- // A null tile (i.e. missing recording) can just be skipped.
- // TODO(vmpstr): Verify this is true if we create tiles in raster
- // iterators.
- if (!tile)
- continue;
-
- // We can't check tile->required_for_activation, because that value might
- // be out of date. It is updated in the raster/eviction iterators.
- // TODO(vmpstr): Remove the comment once you can't access this information
- // from the tile.
- if (tiling->IsTileRequiredForActivation(tile) && !tile->IsReadyToDraw()) {
- TRACE_EVENT_INSTANT0("cc",
- "PictureLayerImpl::"
- "AllTilesRequiredForActivationAreReadyToDraw not "
- "ready to activate",
- TRACE_EVENT_SCOPE_THREAD);
- return false;
- }
- }
- }
-
- return true;
-}
-
-PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator()
- : layer_(nullptr), current_stage_(arraysize(stages_)) {
-}
-
-PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator(
- PictureLayerImpl* layer,
- bool prioritize_low_res)
- : layer_(layer), current_stage_(0) {
- DCHECK(layer_);
-
- // Early out if the layer has no tilings.
- if (!layer_->tilings_ || !layer_->tilings_->num_tilings()) {
- current_stage_ = arraysize(stages_);
- return;
- }
-
- // Tiles without valid priority are treated as having lowest priority and
- // never considered for raster.
- if (!layer_->HasValidTilePriorities()) {
- current_stage_ = arraysize(stages_);
- return;
- }
-
- // Find high and low res tilings and initialize the iterators.
- for (size_t i = 0; i < layer_->tilings_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = layer_->tilings_->tiling_at(i);
- if (tiling->resolution() == HIGH_RESOLUTION) {
- iterators_[HIGH_RES] =
- PictureLayerTiling::TilingRasterTileIterator(tiling);
- }
-
- if (prioritize_low_res && tiling->resolution() == LOW_RESOLUTION) {
- iterators_[LOW_RES] =
- PictureLayerTiling::TilingRasterTileIterator(tiling);
- }
- }
-
- if (prioritize_low_res) {
- stages_[0].iterator_type = LOW_RES;
- stages_[0].tile_type = TilePriority::NOW;
-
- stages_[1].iterator_type = HIGH_RES;
- stages_[1].tile_type = TilePriority::NOW;
- } else {
- stages_[0].iterator_type = HIGH_RES;
- stages_[0].tile_type = TilePriority::NOW;
-
- stages_[1].iterator_type = LOW_RES;
- stages_[1].tile_type = TilePriority::NOW;
- }
-
- stages_[2].iterator_type = HIGH_RES;
- stages_[2].tile_type = TilePriority::SOON;
-
- stages_[3].iterator_type = HIGH_RES;
- stages_[3].tile_type = TilePriority::EVENTUALLY;
-
- IteratorType index = stages_[current_stage_].iterator_type;
- TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
- if (!iterators_[index] || iterators_[index].get_type() != tile_type)
- AdvanceToNextStage();
-}
-
-PictureLayerImpl::LayerRasterTileIterator::~LayerRasterTileIterator() {}
-
-PictureLayerImpl::LayerRasterTileIterator::operator bool() const {
- return current_stage_ < arraysize(stages_);
-}
-
-PictureLayerImpl::LayerRasterTileIterator&
-PictureLayerImpl::LayerRasterTileIterator::
-operator++() {
- IteratorType index = stages_[current_stage_].iterator_type;
- TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
-
- // First advance the iterator.
- DCHECK(iterators_[index]);
- DCHECK(iterators_[index].get_type() == tile_type);
- ++iterators_[index];
-
- if (!iterators_[index] || iterators_[index].get_type() != tile_type)
- AdvanceToNextStage();
-
- return *this;
-}
-
-Tile* PictureLayerImpl::LayerRasterTileIterator::operator*() {
- DCHECK(*this);
-
- IteratorType index = stages_[current_stage_].iterator_type;
- DCHECK(iterators_[index]);
- DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type);
-
- return *iterators_[index];
-}
-
-const Tile* PictureLayerImpl::LayerRasterTileIterator::operator*() const {
- DCHECK(*this);
-
- IteratorType index = stages_[current_stage_].iterator_type;
- DCHECK(iterators_[index]);
- DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type);
-
- return *iterators_[index];
-}
-
-void PictureLayerImpl::LayerRasterTileIterator::AdvanceToNextStage() {
- DCHECK_LT(current_stage_, arraysize(stages_));
- ++current_stage_;
- while (current_stage_ < arraysize(stages_)) {
- IteratorType index = stages_[current_stage_].iterator_type;
- TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
-
- if (iterators_[index] && iterators_[index].get_type() == tile_type)
- break;
- ++current_stage_;
- }
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator()
- : layer_(nullptr),
- tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),
- current_category_(PictureLayerTiling::EVENTUALLY),
- current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
- current_tiling_(0u) {
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator(
- PictureLayerImpl* layer,
- TreePriority tree_priority)
- : layer_(layer),
- tree_priority_(tree_priority),
- current_category_(PictureLayerTiling::EVENTUALLY),
- current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
- current_tiling_(CurrentTilingRange().start - 1u) {
- // TODO(vmpstr): Once tile priorities are determined by the iterators, ensure
- // that layers that don't have valid tile priorities have lowest priorities so
- // they evict their tiles first (crbug.com/381704)
- DCHECK(layer_->tilings_);
- do {
- if (!AdvanceToNextTiling())
- break;
-
- current_iterator_ = PictureLayerTiling::TilingEvictionTileIterator(
- layer_->tilings_->tiling_at(CurrentTilingIndex()),
- tree_priority,
- current_category_);
- } while (!current_iterator_);
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::~LayerEvictionTileIterator() {
-}
-
-Tile* PictureLayerImpl::LayerEvictionTileIterator::operator*() {
- DCHECK(*this);
- return *current_iterator_;
-}
-
-const Tile* PictureLayerImpl::LayerEvictionTileIterator::operator*() const {
- DCHECK(*this);
- return *current_iterator_;
-}
-
-PictureLayerImpl::LayerEvictionTileIterator&
-PictureLayerImpl::LayerEvictionTileIterator::
-operator++() {
- DCHECK(*this);
- ++current_iterator_;
- while (!current_iterator_) {
- if (!AdvanceToNextTiling())
- break;
-
- current_iterator_ = PictureLayerTiling::TilingEvictionTileIterator(
- layer_->tilings_->tiling_at(CurrentTilingIndex()),
- tree_priority_,
- current_category_);
- }
- return *this;
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::operator bool() const {
- return !!current_iterator_;
-}
-
-bool PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextCategory() {
- switch (current_category_) {
- case PictureLayerTiling::EVENTUALLY:
- current_category_ =
- PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION;
- return true;
- case PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
- current_category_ = PictureLayerTiling::SOON;
- return true;
- case PictureLayerTiling::SOON:
- current_category_ = PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION;
- return true;
- case PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION:
- current_category_ = PictureLayerTiling::NOW;
- return true;
- case PictureLayerTiling::NOW:
- current_category_ = PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION;
- return true;
- case PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION:
- return false;
- }
- NOTREACHED();
- return false;
-}
-
-bool
-PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextTilingRangeType() {
- switch (current_tiling_range_type_) {
- case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
- current_tiling_range_type_ = PictureLayerTilingSet::LOWER_THAN_LOW_RES;
- return true;
- case PictureLayerTilingSet::LOWER_THAN_LOW_RES:
- current_tiling_range_type_ =
- PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES;
- return true;
- case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
- current_tiling_range_type_ = PictureLayerTilingSet::LOW_RES;
- return true;
- case PictureLayerTilingSet::LOW_RES:
- current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
- return true;
- case PictureLayerTilingSet::HIGH_RES:
- if (!AdvanceToNextCategory())
- return false;
-
- current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
- return true;
- }
- NOTREACHED();
- return false;
-}
-
-bool PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextTiling() {
- DCHECK_NE(current_tiling_, CurrentTilingRange().end);
- ++current_tiling_;
- while (current_tiling_ == CurrentTilingRange().end) {
- if (!AdvanceToNextTilingRangeType())
- return false;
-
- current_tiling_ = CurrentTilingRange().start;
- }
- return true;
-}
-
-PictureLayerTilingSet::TilingRange
-PictureLayerImpl::LayerEvictionTileIterator::CurrentTilingRange() const {
- return layer_->tilings_->GetTilingRange(current_tiling_range_type_);
-}
-
-size_t PictureLayerImpl::LayerEvictionTileIterator::CurrentTilingIndex() const {
- DCHECK_NE(current_tiling_, CurrentTilingRange().end);
- switch (current_tiling_range_type_) {
- case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
- case PictureLayerTilingSet::LOW_RES:
- case PictureLayerTilingSet::HIGH_RES:
- return current_tiling_;
- // Tilings in the following ranges are accessed in reverse order.
- case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
- case PictureLayerTilingSet::LOWER_THAN_LOW_RES: {
- PictureLayerTilingSet::TilingRange tiling_range = CurrentTilingRange();
- size_t current_tiling_range_offset = current_tiling_ - tiling_range.start;
- return tiling_range.end - 1 - current_tiling_range_offset;
- }
- }
- NOTREACHED();
- return 0;
-}
-
} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h
index 024e31527e9..bca8224974c 100644
--- a/chromium/cc/layers/picture_layer_impl.h
+++ b/chromium/cc/layers/picture_layer_impl.h
@@ -5,16 +5,17 @@
#ifndef CC_LAYERS_PICTURE_LAYER_IMPL_H_
#define CC_LAYERS_PICTURE_LAYER_IMPL_H_
-#include <set>
+#include <map>
#include <string>
#include <vector>
#include "cc/base/cc_export.h"
#include "cc/base/scoped_ptr_vector.h"
#include "cc/layers/layer_impl.h"
-#include "cc/resources/picture_layer_tiling.h"
-#include "cc/resources/picture_layer_tiling_set.h"
-#include "cc/resources/picture_pile_impl.h"
+#include "cc/playback/picture_pile_impl.h"
+#include "cc/tiles/picture_layer_tiling.h"
+#include "cc/tiles/picture_layer_tiling_set.h"
+#include "cc/tiles/tiling_set_eviction_queue.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkPicture.h"
@@ -28,172 +29,113 @@ class CC_EXPORT PictureLayerImpl
: public LayerImpl,
NON_EXPORTED_BASE(public PictureLayerTilingClient) {
public:
- struct CC_EXPORT Pair {
- Pair();
- Pair(PictureLayerImpl* active_layer, PictureLayerImpl* pending_layer);
- ~Pair();
-
- PictureLayerImpl* active;
- PictureLayerImpl* pending;
- };
-
- class CC_EXPORT LayerRasterTileIterator {
- public:
- LayerRasterTileIterator();
- LayerRasterTileIterator(PictureLayerImpl* layer, bool prioritize_low_res);
- ~LayerRasterTileIterator();
-
- Tile* operator*();
- const Tile* operator*() const;
- LayerRasterTileIterator& operator++();
- operator bool() const;
-
- private:
- enum IteratorType { LOW_RES, HIGH_RES, NUM_ITERATORS };
-
- void AdvanceToNextStage();
-
- PictureLayerImpl* layer_;
-
- struct IterationStage {
- IteratorType iterator_type;
- TilePriority::PriorityBin tile_type;
- };
-
- size_t current_stage_;
-
- // One low res stage, and three high res stages.
- IterationStage stages_[4];
- PictureLayerTiling::TilingRasterTileIterator iterators_[NUM_ITERATORS];
- };
-
- class CC_EXPORT LayerEvictionTileIterator {
- public:
- LayerEvictionTileIterator();
- LayerEvictionTileIterator(PictureLayerImpl* layer,
- TreePriority tree_priority);
- ~LayerEvictionTileIterator();
-
- Tile* operator*();
- const Tile* operator*() const;
- LayerEvictionTileIterator& operator++();
- operator bool() const;
-
- private:
- bool AdvanceToNextCategory();
- bool AdvanceToNextTilingRangeType();
- bool AdvanceToNextTiling();
-
- PictureLayerTilingSet::TilingRange CurrentTilingRange() const;
- size_t CurrentTilingIndex() const;
-
- PictureLayerImpl* layer_;
- TreePriority tree_priority_;
-
- PictureLayerTiling::EvictionCategory current_category_;
- PictureLayerTilingSet::TilingRangeType current_tiling_range_type_;
- size_t current_tiling_;
- PictureLayerTiling::TilingEvictionTileIterator current_iterator_;
- };
-
- static scoped_ptr<PictureLayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
- return make_scoped_ptr(new PictureLayerImpl(tree_impl, id));
+ static scoped_ptr<PictureLayerImpl> Create(
+ LayerTreeImpl* tree_impl,
+ int id,
+ bool is_mask,
+ scoped_refptr<SyncedScrollOffset> scroll_offset) {
+ return make_scoped_ptr(
+ new PictureLayerImpl(tree_impl, id, is_mask, scroll_offset));
}
~PictureLayerImpl() override;
+ bool is_mask() const { return is_mask_; }
+
// LayerImpl overrides.
const char* LayerTypeAsString() const override;
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
void PushPropertiesTo(LayerImpl* layer) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
- void UpdateTiles(const Occlusion& occlusion_in_content_space,
- bool resourceless_software_draw) override;
void NotifyTileStateChanged(const Tile* tile) override;
- void DidBecomeActive() override;
void DidBeginTracing() override;
void ReleaseResources() override;
+ void RecreateResources() override;
skia::RefPtr<SkPicture> GetPicture() override;
+ Region GetInvalidationRegion() override;
// PictureLayerTilingClient overrides.
- scoped_refptr<Tile> CreateTile(PictureLayerTiling* tiling,
- const gfx::Rect& content_rect) override;
- RasterSource* GetRasterSource() override;
+ ScopedTilePtr CreateTile(float contents_scale,
+ const gfx::Rect& content_rect) override;
gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override;
const Region* GetPendingInvalidation() override;
const PictureLayerTiling* GetPendingOrActiveTwinTiling(
const PictureLayerTiling* tiling) const override;
- PictureLayerTiling* GetRecycledTwinTiling(
- const PictureLayerTiling* tiling) override;
- size_t GetMaxTilesForInterestArea() const override;
- float GetSkewportTargetTimeInSeconds() const override;
- int GetSkewportExtrapolationLimitInContentPixels() const override;
- WhichTree GetTree() const override;
+ TilePriority::PriorityBin GetMaxTilePriorityBin() const override;
bool RequiresHighResToDraw() const override;
+ gfx::Rect GetEnclosingRectInTargetSpace() const override;
- // PushPropertiesTo active tree => pending tree.
- void SyncTiling(const PictureLayerTiling* tiling);
+ void set_gpu_raster_max_texture_size(gfx::Size gpu_raster_max_texture_size) {
+ gpu_raster_max_texture_size_ = gpu_raster_max_texture_size;
+ }
+ void UpdateRasterSource(scoped_refptr<RasterSource> raster_source,
+ Region* new_invalidation,
+ const PictureLayerTilingSet* pending_set);
+ bool UpdateTiles(bool resourceless_software_draw);
+ void UpdateCanUseLCDTextAfterCommit();
+ bool RasterSourceUsesLCDText() const;
+ WhichTree GetTree() const;
// Mask-related functions.
void GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
gfx::Size* resource_size) const override;
+ void SetNearestNeighbor(bool nearest_neighbor);
+
size_t GPUMemoryUsageInBytes() const override;
void RunMicroBenchmark(MicroBenchmarkImpl* benchmark) override;
+ bool CanHaveTilings() const;
+
+ PictureLayerTilingSet* picture_layer_tiling_set() { return tilings_.get(); }
+
// Functions used by tile manager.
PictureLayerImpl* GetPendingOrActiveTwinLayer() const;
bool IsOnActiveOrPendingTree() const;
// Virtual for testing.
virtual bool HasValidTilePriorities() const;
- bool AllTilesRequiredForActivationAreReadyToDraw() const;
+
+ // Used for benchmarking
+ RasterSource* GetRasterSource() const { return raster_source_.get(); }
protected:
friend class LayerRasterTileIterator;
+ using TileRequirementCheck = bool (PictureLayerTiling::*)(const Tile*) const;
- PictureLayerImpl(LayerTreeImpl* tree_impl, int id);
+ PictureLayerImpl(LayerTreeImpl* tree_impl,
+ int id,
+ bool is_mask,
+ scoped_refptr<SyncedScrollOffset> scroll_offset);
PictureLayerTiling* AddTiling(float contents_scale);
- void RemoveTiling(float contents_scale);
void RemoveAllTilings();
- void SyncFromActiveLayer(const PictureLayerImpl* other);
void AddTilingsForRasterScale();
- void UpdateTilePriorities(const Occlusion& occlusion_in_content_space);
virtual bool ShouldAdjustRasterScale() const;
virtual void RecalculateRasterScales();
void CleanUpTilingsOnActiveLayer(
- std::vector<PictureLayerTiling*> used_tilings);
+ const std::vector<PictureLayerTiling*>& used_tilings);
float MinimumContentsScale() const;
- float SnappedContentsScale(float new_contents_scale);
+ float MaximumContentsScale() const;
void ResetRasterScale();
- gfx::Rect GetViewportForTilePriorityInContentSpace() const;
+ void UpdateViewportRectForTilePriorityInContentSpace();
PictureLayerImpl* GetRecycledTwinLayer() const;
- void UpdatePile(scoped_refptr<PicturePileImpl> pile);
- void DoPostCommitInitializationIfNeeded() {
- if (needs_post_commit_initialization_)
- DoPostCommitInitialization();
- }
- void DoPostCommitInitialization();
-
- bool CanHaveTilings() const;
- bool CanHaveTilingWithScale(float contents_scale) const;
void SanityCheckTilingState() const;
-
bool ShouldAdjustRasterScaleDuringScaleAnimations() const;
void GetDebugBorderProperties(SkColor* color, float* width) const override;
- void GetAllTilesForTracing(std::set<const Tile*>* tiles) const override;
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
virtual void UpdateIdealScales();
float MaximumTilingContentsScale() const;
+ scoped_ptr<PictureLayerTilingSet> CreatePictureLayerTilingSet();
PictureLayerImpl* twin_layer_;
scoped_ptr<PictureLayerTilingSet> tilings_;
- scoped_refptr<PicturePileImpl> pile_;
+ scoped_refptr<RasterSource> raster_source_;
Region invalidation_;
float ideal_page_scale_;
@@ -209,11 +151,10 @@ class CC_EXPORT PictureLayerImpl
bool raster_source_scale_is_fixed_;
bool was_screen_space_transform_animating_;
- bool needs_post_commit_initialization_;
- // A sanity state check to make sure UpdateTilePriorities only gets called
- // after a CalculateContentsScale/ManageTilings.
- bool should_update_tile_priorities_;
bool only_used_low_res_last_append_quads_;
+ const bool is_mask_;
+
+ bool nearest_neighbor_;
// Any draw properties derived from |transform|, |viewport|, and |clip|
// parameters in LayerTreeHostImpl::SetExternalDrawConstraints are not valid
@@ -222,8 +163,17 @@ class CC_EXPORT PictureLayerImpl
// from regular draws. Save a copy of the required draw properties of the last
// frame that has a valid viewport for prioritizing tiles.
gfx::Rect visible_rect_for_tile_priority_;
+ gfx::Rect viewport_rect_for_tile_priority_in_content_space_;
+
+ gfx::Size gpu_raster_max_texture_size_;
+
+ // List of tilings that were used last time we appended quads. This can be
+ // used as an optimization not to remove tilings if they are still being
+ // drawn. Note that accessing this vector should only be done in the context
+ // of comparing pointers, since objects pointed to are not guaranteed to
+ // exist.
+ std::vector<PictureLayerTiling*> last_append_quads_tilings_;
- friend class PictureLayer;
DISALLOW_COPY_AND_ASSIGN(PictureLayerImpl);
};
diff --git a/chromium/cc/layers/picture_layer_impl_perftest.cc b/chromium/cc/layers/picture_layer_impl_perftest.cc
index aeea2bb7fee..7c3bbbb552e 100644
--- a/chromium/cc/layers/picture_layer_impl_perftest.cc
+++ b/chromium/cc/layers/picture_layer_impl_perftest.cc
@@ -4,6 +4,7 @@
#include "cc/layers/picture_layer_impl.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/debug/lap_timer.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
@@ -12,6 +13,8 @@
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
+#include "cc/tiles/tiling_set_raster_queue_all.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -37,15 +40,16 @@ void AddTiling(float scale,
class PictureLayerImplPerfTest : public testing::Test {
public:
PictureLayerImplPerfTest()
- : proxy_(base::MessageLoopProxy::current()),
- host_impl_(ImplSidePaintingSettings(),
+ : proxy_(base::ThreadTaskRunnerHandle::Get()),
+ host_impl_(ImplSidePaintingSettings(10000),
&proxy_,
- &shared_bitmap_manager_),
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval) {}
- virtual void SetUp() override {
+ void SetUp() override {
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
}
@@ -58,125 +62,106 @@ class PictureLayerImplPerfTest : public testing::Test {
pending_tree->DetachLayerTree();
scoped_ptr<FakePictureLayerImpl> pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, 7, pile);
+ FakePictureLayerImpl::CreateWithRasterSource(pending_tree, 7, pile);
pending_layer->SetDrawsContent(true);
+ pending_layer->SetHasRenderSurface(true);
pending_tree->SetRootLayer(pending_layer.Pass());
pending_layer_ = static_cast<FakePictureLayerImpl*>(
host_impl_.pending_tree()->LayerById(7));
- pending_layer_->DoPostCommitInitializationIfNeeded();
}
- void RunRasterIteratorConstructAndIterateTest(
- const std::string& test_name,
- int num_tiles,
- const gfx::Size& viewport_size) {
+ void RunRasterQueueConstructAndIterateTest(const std::string& test_name,
+ int num_tiles,
+ const gfx::Size& viewport_size) {
host_impl_.SetViewportSize(viewport_size);
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
timer_.Reset();
do {
int count = num_tiles;
- PictureLayerImpl::LayerRasterTileIterator it(pending_layer_, false);
+ scoped_ptr<TilingSetRasterQueueAll> queue(new TilingSetRasterQueueAll(
+ pending_layer_->picture_layer_tiling_set(), false));
while (count--) {
- ASSERT_TRUE(it) << "count: " << count;
- ASSERT_TRUE(*it != nullptr) << "count: " << count;
- ++it;
+ ASSERT_TRUE(!queue->IsEmpty()) << "count: " << count;
+ ASSERT_TRUE(queue->Top().tile()) << "count: " << count;
+ queue->Pop();
}
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
- perf_test::PrintResult("layer_raster_tile_iterator_construct_and_iterate",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
+ perf_test::PrintResult("tiling_set_raster_queue_construct_and_iterate", "",
+ test_name, timer_.LapsPerSecond(), "runs/s", true);
}
- void RunRasterIteratorConstructTest(const std::string& test_name,
- const gfx::Rect& viewport) {
+ void RunRasterQueueConstructTest(const std::string& test_name,
+ const gfx::Rect& viewport) {
host_impl_.SetViewportSize(viewport.size());
- pending_layer_->SetScrollOffset(
+ pending_layer_->PushScrollOffsetFromMainThread(
gfx::ScrollOffset(viewport.x(), viewport.y()));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
timer_.Reset();
do {
- PictureLayerImpl::LayerRasterTileIterator it(pending_layer_, false);
+ scoped_ptr<TilingSetRasterQueueAll> queue(new TilingSetRasterQueueAll(
+ pending_layer_->picture_layer_tiling_set(), false));
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
- perf_test::PrintResult("layer_raster_tile_iterator_construct",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
+ perf_test::PrintResult("tiling_set_raster_queue_construct", "", test_name,
+ timer_.LapsPerSecond(), "runs/s", true);
}
- void RunEvictionIteratorConstructAndIterateTest(
+ void RunEvictionQueueConstructAndIterateTest(
const std::string& test_name,
int num_tiles,
const gfx::Size& viewport_size) {
host_impl_.SetViewportSize(viewport_size);
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
- TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
- SMOOTHNESS_TAKES_PRIORITY,
- NEW_CONTENT_TAKES_PRIORITY};
- int priority_count = 0;
timer_.Reset();
do {
int count = num_tiles;
- PictureLayerImpl::LayerEvictionTileIterator it(
- pending_layer_, priorities[priority_count]);
+ scoped_ptr<TilingSetEvictionQueue> queue(new TilingSetEvictionQueue(
+ pending_layer_->picture_layer_tiling_set()));
while (count--) {
- ASSERT_TRUE(it) << "count: " << count;
- ASSERT_TRUE(*it != nullptr) << "count: " << count;
- ++it;
+ ASSERT_TRUE(!queue->IsEmpty()) << "count: " << count;
+ ASSERT_TRUE(queue->Top().tile()) << "count: " << count;
+ queue->Pop();
}
- priority_count = (priority_count + 1) % arraysize(priorities);
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
- perf_test::PrintResult("layer_eviction_tile_iterator_construct_and_iterate",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
+ perf_test::PrintResult("tiling_set_eviction_queue_construct_and_iterate",
+ "", test_name, timer_.LapsPerSecond(), "runs/s",
true);
}
- void RunEvictionIteratorConstructTest(const std::string& test_name,
- const gfx::Rect& viewport) {
+ void RunEvictionQueueConstructTest(const std::string& test_name,
+ const gfx::Rect& viewport) {
host_impl_.SetViewportSize(viewport.size());
- pending_layer_->SetScrollOffset(
+ pending_layer_->PushScrollOffsetFromMainThread(
gfx::ScrollOffset(viewport.x(), viewport.y()));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
- TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
- SMOOTHNESS_TAKES_PRIORITY,
- NEW_CONTENT_TAKES_PRIORITY};
- int priority_count = 0;
timer_.Reset();
do {
- PictureLayerImpl::LayerEvictionTileIterator it(
- pending_layer_, priorities[priority_count]);
- priority_count = (priority_count + 1) % arraysize(priorities);
+ scoped_ptr<TilingSetEvictionQueue> queue(new TilingSetEvictionQueue(
+ pending_layer_->picture_layer_tiling_set()));
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
- perf_test::PrintResult("layer_eviction_tile_iterator_construct",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
+ perf_test::PrintResult("tiling_set_eviction_queue_construct", "", test_name,
+ timer_.LapsPerSecond(), "runs/s", true);
}
protected:
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeImplProxy proxy_;
FakeLayerTreeHostImpl host_impl_;
FakePictureLayerImpl* pending_layer_;
@@ -186,7 +171,7 @@ class PictureLayerImplPerfTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(PictureLayerImplPerfTest);
};
-TEST_F(PictureLayerImplPerfTest, LayerRasterTileIteratorConstructAndIterate) {
+TEST_F(PictureLayerImplPerfTest, TilingSetRasterQueueConstructAndIterate) {
SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
@@ -197,17 +182,13 @@ TEST_F(PictureLayerImplPerfTest, LayerRasterTileIteratorConstructAndIterate) {
pending_layer_->AddTiling(1.0f);
pending_layer_->AddTiling(2.0f);
- RunRasterIteratorConstructAndIterateTest(
- "32_100x100", 32, gfx::Size(100, 100));
- RunRasterIteratorConstructAndIterateTest(
- "32_500x500", 32, gfx::Size(500, 500));
- RunRasterIteratorConstructAndIterateTest(
- "64_100x100", 64, gfx::Size(100, 100));
- RunRasterIteratorConstructAndIterateTest(
- "64_500x500", 64, gfx::Size(500, 500));
+ RunRasterQueueConstructAndIterateTest("32_100x100", 32, gfx::Size(100, 100));
+ RunRasterQueueConstructAndIterateTest("32_500x500", 32, gfx::Size(500, 500));
+ RunRasterQueueConstructAndIterateTest("64_100x100", 64, gfx::Size(100, 100));
+ RunRasterQueueConstructAndIterateTest("64_500x500", 64, gfx::Size(500, 500));
}
-TEST_F(PictureLayerImplPerfTest, LayerRasterTileIteratorConstruct) {
+TEST_F(PictureLayerImplPerfTest, TilingSetRasterQueueConstruct) {
SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
@@ -218,14 +199,12 @@ TEST_F(PictureLayerImplPerfTest, LayerRasterTileIteratorConstruct) {
pending_layer_->AddTiling(1.0f);
pending_layer_->AddTiling(2.0f);
- RunRasterIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
- RunRasterIteratorConstructTest("5000_0_100x100",
- gfx::Rect(5000, 0, 100, 100));
- RunRasterIteratorConstructTest("9999_0_100x100",
- gfx::Rect(9999, 0, 100, 100));
+ RunRasterQueueConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
+ RunRasterQueueConstructTest("5000_0_100x100", gfx::Rect(5000, 0, 100, 100));
+ RunRasterQueueConstructTest("9999_0_100x100", gfx::Rect(9999, 0, 100, 100));
}
-TEST_F(PictureLayerImplPerfTest, LayerEvictionTileIteratorConstructAndIterate) {
+TEST_F(PictureLayerImplPerfTest, TilingSetEvictionQueueConstructAndIterate) {
SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
@@ -240,17 +219,17 @@ TEST_F(PictureLayerImplPerfTest, LayerEvictionTileIteratorConstructAndIterate) {
ASSERT_TRUE(host_impl_.tile_manager() != nullptr);
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
- RunEvictionIteratorConstructAndIterateTest(
+ RunEvictionQueueConstructAndIterateTest(
"32_100x100", 32, gfx::Size(100, 100));
- RunEvictionIteratorConstructAndIterateTest(
+ RunEvictionQueueConstructAndIterateTest(
"32_500x500", 32, gfx::Size(500, 500));
- RunEvictionIteratorConstructAndIterateTest(
+ RunEvictionQueueConstructAndIterateTest(
"64_100x100", 64, gfx::Size(100, 100));
- RunEvictionIteratorConstructAndIterateTest(
+ RunEvictionQueueConstructAndIterateTest(
"64_500x500", 64, gfx::Size(500, 500));
}
-TEST_F(PictureLayerImplPerfTest, LayerEvictionTileIteratorConstruct) {
+TEST_F(PictureLayerImplPerfTest, TilingSetEvictionQueueConstruct) {
SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
@@ -265,11 +244,9 @@ TEST_F(PictureLayerImplPerfTest, LayerEvictionTileIteratorConstruct) {
ASSERT_TRUE(host_impl_.tile_manager() != nullptr);
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
- RunEvictionIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
- RunEvictionIteratorConstructTest("5000_0_100x100",
- gfx::Rect(5000, 0, 100, 100));
- RunEvictionIteratorConstructTest("9999_0_100x100",
- gfx::Rect(9999, 0, 100, 100));
+ RunEvictionQueueConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
+ RunEvictionQueueConstructTest("5000_0_100x100", gfx::Rect(5000, 0, 100, 100));
+ RunEvictionQueueConstructTest("9999_0_100x100", gfx::Rect(9999, 0, 100, 100));
}
} // namespace
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index 4b42eca413f..2bf369684a2 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -9,6 +9,8 @@
#include <set>
#include <utility>
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/base/math_util.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/picture_layer.h"
@@ -22,10 +24,13 @@
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/geometry_test_utils.h"
-#include "cc/test/impl_side_painting_settings.h"
+#include "cc/test/gpu_rasterization_enabled_settings.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/tiles/tiling_set_raster_queue_all.h"
+#include "cc/tiles/tiling_set_raster_queue_required.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -34,11 +39,23 @@
namespace cc {
namespace {
+#define EXPECT_BOTH_EQ(expression, x) \
+ do { \
+ EXPECT_EQ(x, pending_layer_->expression); \
+ EXPECT_EQ(x, active_layer_->expression); \
+ } while (false)
+
+#define EXPECT_BOTH_NE(expression, x) \
+ do { \
+ EXPECT_NE(x, pending_layer_->expression); \
+ EXPECT_NE(x, active_layer_->expression); \
+ } while (false)
+
class MockCanvas : public SkCanvas {
public:
explicit MockCanvas(int w, int h) : SkCanvas(w, h) {}
- void drawRect(const SkRect& rect, const SkPaint& paint) override {
+ void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
// Capture calls before SkCanvas quickReject() kicks in.
rects_.push_back(rect);
}
@@ -46,9 +63,9 @@ class MockCanvas : public SkCanvas {
std::vector<SkRect> rects_;
};
-class NoLowResTilingsSettings : public ImplSidePaintingSettings {};
+class NoLowResTilingsSettings : public GpuRasterizationEnabledSettings {};
-class LowResTilingsSettings : public ImplSidePaintingSettings {
+class LowResTilingsSettings : public GpuRasterizationEnabledSettings {
public:
LowResTilingsSettings() { create_low_res_tiling = true; }
};
@@ -56,24 +73,33 @@ class LowResTilingsSettings : public ImplSidePaintingSettings {
class PictureLayerImplTest : public testing::Test {
public:
PictureLayerImplTest()
- : proxy_(base::MessageLoopProxy::current()),
- host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_),
+ : proxy_(base::ThreadTaskRunnerHandle::Get()),
+ host_impl_(LowResTilingsSettings(),
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
+ root_id_(6),
id_(7),
pending_layer_(nullptr),
old_pending_layer_(nullptr),
- active_layer_(nullptr) {}
+ active_layer_(nullptr) {
+ host_impl_.SetViewportSize(gfx::Size(10000, 10000));
+ }
explicit PictureLayerImplTest(const LayerTreeSettings& settings)
- : proxy_(base::MessageLoopProxy::current()),
- host_impl_(settings, &proxy_, &shared_bitmap_manager_),
- id_(7) {}
-
- virtual ~PictureLayerImplTest() {
+ : proxy_(base::ThreadTaskRunnerHandle::Get()),
+ host_impl_(settings,
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
+ root_id_(6),
+ id_(7) {
+ host_impl_.SetViewportSize(gfx::Size(10000, 10000));
}
- virtual void SetUp() override {
- InitializeRenderer();
- }
+ ~PictureLayerImplTest() override {}
+
+ void SetUp() override { InitializeRenderer(); }
virtual void InitializeRenderer() {
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
@@ -90,6 +116,18 @@ class PictureLayerImplTest : public testing::Test {
SetupTrees(pending_pile, active_pile);
}
+ void SetupDefaultTreesWithInvalidation(const gfx::Size& layer_bounds,
+ const Region& invalidation) {
+ gfx::Size tile_size(100, 100);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTreesWithInvalidation(pending_pile, active_pile, invalidation);
+ }
+
void ActivateTree() {
host_impl_.ActivateSyncTree();
CHECK(!host_impl_.pending_tree());
@@ -98,13 +136,23 @@ class PictureLayerImplTest : public testing::Test {
pending_layer_ = nullptr;
active_layer_ = static_cast<FakePictureLayerImpl*>(
host_impl_.active_tree()->LayerById(id_));
+
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
}
void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds,
- const gfx::Size& tile_size) {
- SetupDefaultTrees(layer_bounds);
- pending_layer_->set_fixed_tile_size(tile_size);
- active_layer_->set_fixed_tile_size(tile_size);
+ const gfx::Size& tile_size,
+ const Region& invalidation) {
+ gfx::Size pile_tile_size(100, 100);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(pile_tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(pile_tile_size, layer_bounds);
+
+ SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size,
+ invalidation);
}
void SetupTrees(
@@ -112,75 +160,108 @@ class PictureLayerImplTest : public testing::Test {
scoped_refptr<PicturePileImpl> active_pile) {
SetupPendingTree(active_pile);
ActivateTree();
- SetupPendingTree(pending_pile);
+ SetupPendingTreeInternal(pending_pile, gfx::Size(), Region());
+ }
+
+ void SetupTreesWithInvalidation(scoped_refptr<PicturePileImpl> pending_pile,
+ scoped_refptr<PicturePileImpl> active_pile,
+ const Region& pending_invalidation) {
+ SetupPendingTreeInternal(active_pile, gfx::Size(), Region());
+ ActivateTree();
+ SetupPendingTreeInternal(pending_pile, gfx::Size(), pending_invalidation);
+ }
+
+ void SetupTreesWithFixedTileSize(scoped_refptr<PicturePileImpl> pending_pile,
+ scoped_refptr<PicturePileImpl> active_pile,
+ const gfx::Size& tile_size,
+ const Region& pending_invalidation) {
+ SetupPendingTreeInternal(active_pile, tile_size, Region());
+ ActivateTree();
+ SetupPendingTreeInternal(pending_pile, tile_size, pending_invalidation);
+ }
+
+ void SetupPendingTree(scoped_refptr<RasterSource> raster_source) {
+ SetupPendingTreeInternal(raster_source, gfx::Size(), Region());
}
- void CreateHighLowResAndSetAllTilesVisible() {
- // Active layer must get updated first so pending layer can share from it.
- active_layer_->CreateDefaultTilingsAndTiles();
- active_layer_->SetAllTilesVisible();
- pending_layer_->CreateDefaultTilingsAndTiles();
- pending_layer_->SetAllTilesVisible();
+ void SetupPendingTreeWithInvalidation(
+ scoped_refptr<RasterSource> raster_source,
+ const Region& invalidation) {
+ SetupPendingTreeInternal(raster_source, gfx::Size(), invalidation);
}
- void AddDefaultTilingsWithInvalidation(const Region& invalidation) {
- active_layer_->AddTiling(2.3f);
- active_layer_->AddTiling(1.0f);
- active_layer_->AddTiling(0.5f);
- for (size_t i = 0; i < active_layer_->tilings()->num_tilings(); ++i)
- active_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
- pending_layer_->set_invalidation(invalidation);
- for (size_t i = 0; i < pending_layer_->tilings()->num_tilings(); ++i)
- pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
+ void SetupPendingTreeWithFixedTileSize(
+ scoped_refptr<RasterSource> raster_source,
+ const gfx::Size& tile_size,
+ const Region& invalidation) {
+ SetupPendingTreeInternal(raster_source, tile_size, invalidation);
}
- void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
+ void SetupPendingTreeInternal(scoped_refptr<RasterSource> raster_source,
+ const gfx::Size& tile_size,
+ const Region& invalidation) {
host_impl_.CreatePendingTree();
- host_impl_.pending_tree()->SetPageScaleFactorAndLimits(1.f, 0.25f, 100.f);
+ host_impl_.pending_tree()->PushPageScaleFromMainThread(1.f, 0.25f, 100.f);
LayerTreeImpl* pending_tree = host_impl_.pending_tree();
- // Steal from the recycled tree.
- scoped_ptr<LayerImpl> old_pending_root = pending_tree->DetachLayerTree();
- DCHECK_IMPLIES(old_pending_root, old_pending_root->id() == id_);
-
+ // Steal from the recycled tree if possible.
+ scoped_ptr<LayerImpl> pending_root = pending_tree->DetachLayerTree();
scoped_ptr<FakePictureLayerImpl> pending_layer;
- if (old_pending_root) {
- pending_layer.reset(
- static_cast<FakePictureLayerImpl*>(old_pending_root.release()));
- pending_layer->SetPile(pile);
- } else {
- pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+ DCHECK_IMPLIES(pending_root, pending_root->id() == root_id_);
+ if (!pending_root) {
+ pending_root = LayerImpl::Create(pending_tree, root_id_);
+ pending_layer = FakePictureLayerImpl::Create(pending_tree, id_);
+ if (!tile_size.IsEmpty())
+ pending_layer->set_fixed_tile_size(tile_size);
pending_layer->SetDrawsContent(true);
+ } else {
+ pending_layer.reset(static_cast<FakePictureLayerImpl*>(
+ pending_root->RemoveChild(pending_root->children()[0]).release()));
+ if (!tile_size.IsEmpty())
+ pending_layer->set_fixed_tile_size(tile_size);
}
+ pending_root->SetHasRenderSurface(true);
// The bounds() just mirror the pile size.
- pending_layer->SetBounds(pending_layer->pile()->tiling_size());
- pending_tree->SetRootLayer(pending_layer.Pass());
+ pending_layer->SetBounds(raster_source->GetSize());
+ pending_layer->SetContentBounds(raster_source->GetSize());
+ pending_layer->SetRasterSourceOnPending(raster_source, invalidation);
+
+ pending_root->AddChild(pending_layer.Pass());
+ pending_tree->SetRootLayer(pending_root.Pass());
pending_layer_ = static_cast<FakePictureLayerImpl*>(
host_impl_.pending_tree()->LayerById(id_));
- pending_layer_->DoPostCommitInitializationIfNeeded();
+
+ // Add tilings/tiles for the layer.
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
}
- void SetupDrawPropertiesAndUpdateTiles(FakePictureLayerImpl* layer,
- float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- float maximum_animation_contents_scale,
- bool animating_transform_to_screen) {
+ void SetupDrawPropertiesAndUpdateTiles(
+ FakePictureLayerImpl* layer,
+ float ideal_contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_contents_scale,
+ float starting_animation_contents_scale,
+ bool animating_transform_to_screen) {
layer->draw_properties().ideal_contents_scale = ideal_contents_scale;
layer->draw_properties().device_scale_factor = device_scale_factor;
layer->draw_properties().page_scale_factor = page_scale_factor;
layer->draw_properties().maximum_animation_contents_scale =
maximum_animation_contents_scale;
+ layer->draw_properties().starting_animation_contents_scale =
+ starting_animation_contents_scale;
layer->draw_properties().screen_space_transform_is_animating =
animating_transform_to_screen;
bool resourceless_software_draw = false;
- layer->UpdateTiles(Occlusion(), resourceless_software_draw);
+ layer->UpdateTiles(resourceless_software_draw);
}
- static void VerifyAllTilesExistAndHavePile(
+ static void VerifyAllPrioritizedTilesExistAndHavePile(
const PictureLayerTiling* tiling,
PicturePileImpl* pile) {
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
for (PictureLayerTiling::CoverageIterator iter(
tiling,
tiling->contents_scale(),
@@ -188,7 +269,7 @@ class PictureLayerImplTest : public testing::Test {
iter;
++iter) {
EXPECT_TRUE(*iter);
- EXPECT_EQ(pile, iter->raster_source());
+ EXPECT_EQ(pile, prioritized_tiles[*iter].raster_source());
}
}
@@ -196,25 +277,43 @@ class PictureLayerImplTest : public testing::Test {
float device_scale_factor,
float page_scale_factor,
float maximum_animation_contents_scale,
+ float starting_animation_contents_scale,
bool animating_transform) {
- SetupDrawPropertiesAndUpdateTiles(pending_layer_,
- contents_scale,
- device_scale_factor,
- page_scale_factor,
- maximum_animation_contents_scale,
- animating_transform);
-
- SetupDrawPropertiesAndUpdateTiles(active_layer_,
- contents_scale,
- device_scale_factor,
- page_scale_factor,
- maximum_animation_contents_scale,
- animating_transform);
+ SetupDrawPropertiesAndUpdateTiles(
+ pending_layer_, contents_scale, device_scale_factor, page_scale_factor,
+ maximum_animation_contents_scale, starting_animation_contents_scale,
+ animating_transform);
+
+ SetupDrawPropertiesAndUpdateTiles(
+ active_layer_, contents_scale, device_scale_factor, page_scale_factor,
+ maximum_animation_contents_scale, starting_animation_contents_scale,
+ animating_transform);
}
void ResetTilingsAndRasterScales() {
- pending_layer_->ReleaseResources();
- active_layer_->ReleaseResources();
+ if (pending_layer_) {
+ pending_layer_->ReleaseResources();
+ EXPECT_FALSE(pending_layer_->tilings());
+ pending_layer_->RecreateResources();
+ EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+ }
+
+ if (active_layer_) {
+ active_layer_->ReleaseResources();
+ EXPECT_FALSE(active_layer_->tilings());
+ active_layer_->RecreateResources();
+ EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+ }
+ }
+
+ size_t NumberOfTilesRequired(PictureLayerTiling* tiling) {
+ size_t num_required = 0;
+ std::vector<Tile*> tiles = tiling->AllTilesForTesting();
+ for (size_t i = 0; i < tiles.size(); ++i) {
+ if (tiles[i]->required_for_activation())
+ num_required++;
+ }
+ return num_required;
}
void AssertAllTilesRequired(PictureLayerTiling* tiling) {
@@ -232,60 +331,13 @@ class PictureLayerImplTest : public testing::Test {
}
protected:
- void TestTileGridAlignmentCommon() {
- // Layer to span 4 raster tiles in x and in y
- ImplSidePaintingSettings settings;
- gfx::Size layer_size(
- settings.default_tile_size.width() * 7 / 2,
- settings.default_tile_size.height() * 7 / 2);
-
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(layer_size, layer_size);
- scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateFilledPile(layer_size, layer_size);
-
- SetupTrees(pending_pile, active_pile);
-
- SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
-
- // Add 1x1 rects at the centers of each tile, then re-record pile contents
- active_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
- std::vector<Tile*> tiles =
- active_layer_->tilings()->tiling_at(0)->AllTilesForTesting();
- EXPECT_EQ(16u, tiles.size());
- std::vector<SkRect> rects;
- std::vector<Tile*>::const_iterator tile_iter;
- for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
- gfx::Point tile_center = (*tile_iter)->content_rect().CenterPoint();
- gfx::Rect rect(tile_center.x(), tile_center.y(), 1, 1);
- active_pile->add_draw_rect(rect);
- rects.push_back(SkRect::MakeXYWH(rect.x(), rect.y(), 1, 1));
- }
- // Force re-record with newly injected content
- active_pile->RemoveRecordingAt(0, 0);
- active_pile->AddRecordingAt(0, 0);
-
- std::vector<SkRect>::const_iterator rect_iter = rects.begin();
- for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
- MockCanvas mock_canvas(1000, 1000);
- active_pile->RasterDirect(&mock_canvas, (*tile_iter)->content_rect(),
- 1.0f);
-
- // This test verifies that when drawing the contents of a specific tile
- // at content scale 1.0, the playback canvas never receives content from
- // neighboring tiles which indicates that the tile grid embedded in
- // SkPicture is perfectly aligned with the compositor's tiles.
- EXPECT_EQ(1u, mock_canvas.rects_.size());
- EXPECT_EQ(*rect_iter, mock_canvas.rects_[0]);
- rect_iter++;
- }
- }
-
void TestQuadsForSolidColor(bool test_for_solid);
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
+ int root_id_;
int id_;
FakePictureLayerImpl* pending_layer_;
FakePictureLayerImpl* old_pending_layer_;
@@ -295,14 +347,63 @@ class PictureLayerImplTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(PictureLayerImplTest);
};
+class NoLowResPictureLayerImplTest : public PictureLayerImplTest {
+ public:
+ NoLowResPictureLayerImplTest()
+ : PictureLayerImplTest(NoLowResTilingsSettings()) {}
+};
+
TEST_F(PictureLayerImplTest, TileGridAlignment) {
- host_impl_.SetDeviceScaleFactor(1.f);
- TestTileGridAlignmentCommon();
-}
+ // Layer to span 4 raster tiles in x and in y
+ ImplSidePaintingSettings settings;
+ gfx::Size layer_size(settings.default_tile_size.width() * 7 / 2,
+ settings.default_tile_size.height() * 7 / 2);
-TEST_F(PictureLayerImplTest, TileGridAlignmentHiDPI) {
- host_impl_.SetDeviceScaleFactor(2.f);
- TestTileGridAlignmentCommon();
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(layer_size, layer_size);
+
+ scoped_ptr<FakePicturePile> active_recording =
+ FakePicturePile::CreateFilledPile(layer_size, layer_size);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFromPile(active_recording.get(), nullptr);
+
+ SetupTrees(pending_pile, active_pile);
+
+ // Add 1x1 rects at the centers of each tile, then re-record pile contents
+ active_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
+ std::vector<Tile*> tiles =
+ active_layer_->tilings()->tiling_at(0)->AllTilesForTesting();
+ EXPECT_EQ(16u, tiles.size());
+ std::vector<SkRect> rects;
+ std::vector<Tile*>::const_iterator tile_iter;
+ for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
+ gfx::Point tile_center = (*tile_iter)->content_rect().CenterPoint();
+ gfx::Rect rect(tile_center.x(), tile_center.y(), 1, 1);
+ active_recording->add_draw_rect(rect);
+ rects.push_back(SkRect::MakeXYWH(rect.x(), rect.y(), 1, 1));
+ }
+
+ // Force re-raster with newly injected content
+ active_recording->RemoveRecordingAt(0, 0);
+ active_recording->AddRecordingAt(0, 0);
+
+ scoped_refptr<FakePicturePileImpl> updated_active_pile =
+ FakePicturePileImpl::CreateFromPile(active_recording.get(), nullptr);
+
+ std::vector<SkRect>::const_iterator rect_iter = rects.begin();
+ for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
+ MockCanvas mock_canvas(1000, 1000);
+ updated_active_pile->PlaybackToSharedCanvas(
+ &mock_canvas, (*tile_iter)->content_rect(), 1.0f);
+
+ // This test verifies that when drawing the contents of a specific tile
+ // at content scale 1.0, the playback canvas never receives content from
+ // neighboring tiles which indicates that the tile grid embedded in
+ // SkPicture is perfectly aligned with the compositor's tiles.
+ EXPECT_EQ(1u, mock_canvas.rects_.size());
+ EXPECT_EQ(*rect_iter, mock_canvas.rects_[0]);
+ rect_iter++;
+ }
}
TEST_F(PictureLayerImplTest, CloneNoInvalidation) {
@@ -314,10 +415,7 @@ TEST_F(PictureLayerImplTest, CloneNoInvalidation) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
-
- Region invalidation;
- AddDefaultTilingsWithInvalidation(invalidation);
+ SetupTreesWithInvalidation(pending_pile, active_pile, Region());
EXPECT_EQ(pending_layer_->tilings()->num_tilings(),
active_layer_->tilings()->num_tilings());
@@ -325,14 +423,14 @@ TEST_F(PictureLayerImplTest, CloneNoInvalidation) {
const PictureLayerTilingSet* tilings = pending_layer_->tilings();
EXPECT_GT(tilings->num_tilings(), 0u);
for (size_t i = 0; i < tilings->num_tilings(); ++i)
- VerifyAllTilesExistAndHavePile(tilings->tiling_at(i), active_pile.get());
+ EXPECT_TRUE(tilings->tiling_at(i)->AllTilesForTesting().empty());
}
TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -341,15 +439,14 @@ TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
+ SetupTreesWithInvalidation(pending_pile, active_pile, Region());
- Region invalidation;
- AddDefaultTilingsWithInvalidation(invalidation);
- SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
// Update tiles with viewport for tile priority as (0, 0, 100, 100) and the
// identify transform for tile priority.
@@ -364,14 +461,15 @@ TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) {
viewport_rect_for_tile_priority,
transform_for_tile_priority,
resourceless_software_draw);
- host_impl_.active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
gfx::Rect viewport_rect_for_tile_priority_in_view_space =
viewport_rect_for_tile_priority;
// Verify the viewport rect for tile priority is used in picture layer tiling.
EXPECT_EQ(viewport_rect_for_tile_priority_in_view_space,
- active_layer_->GetViewportForTilePriorityInContentSpace());
+ active_layer_->viewport_rect_for_tile_priority_in_content_space());
PictureLayerTilingSet* tilings = active_layer_->tilings();
for (size_t i = 0; i < tilings->num_tilings(); i++) {
PictureLayerTiling* tiling = tilings->tiling_at(i);
@@ -387,7 +485,7 @@ TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) {
// should be (200, 200, 100, 100) applied with the said transform.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
viewport_rect_for_tile_priority = gfx::Rect(200, 200, 100, 100);
transform_for_tile_priority.Translate(100, 100);
@@ -398,7 +496,7 @@ TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) {
viewport_rect_for_tile_priority,
transform_for_tile_priority,
resourceless_software_draw);
- host_impl_.active_tree()->UpdateDrawProperties();
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
gfx::Transform screen_to_view(gfx::Transform::kSkipInitialization);
bool success = transform_for_tile_priority.GetInverse(&screen_to_view);
@@ -413,7 +511,7 @@ TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) {
screen_to_view, viewport_rect_for_tile_priority));
EXPECT_EQ(viewport_rect_for_tile_priority_in_view_space,
- active_layer_->GetViewportForTilePriorityInContentSpace());
+ active_layer_->viewport_rect_for_tile_priority_in_content_space());
tilings = active_layer_->tilings();
for (size_t i = 0; i < tilings->num_tilings(); i++) {
PictureLayerTiling* tiling = tilings->tiling_at(i);
@@ -428,7 +526,7 @@ TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -438,11 +536,10 @@ TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
+ SetupTreesWithInvalidation(pending_pile, active_pile, Region());
- Region invalidation;
- AddDefaultTilingsWithInvalidation(invalidation);
- SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
// UpdateTiles with valid viewport. Should update tile viewport.
// Note viewport is considered invalid if and only if in resourceless
@@ -458,7 +555,7 @@ TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
resourceless_software_draw);
active_layer_->draw_properties().visible_content_rect = viewport;
active_layer_->draw_properties().screen_space_transform = transform;
- active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+ active_layer_->UpdateTiles(resourceless_software_draw);
gfx::Rect visible_rect_for_tile_priority =
active_layer_->visible_rect_for_tile_priority();
@@ -470,7 +567,7 @@ TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
// Should update viewport and transform, but not update visible rect.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
resourceless_software_draw = true;
viewport = gfx::ScaleToEnclosingRect(viewport, 2);
transform.Translate(1.f, 1.f);
@@ -482,7 +579,7 @@ TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
viewport,
transform,
resourceless_software_draw);
- active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+ active_layer_->UpdateTiles(resourceless_software_draw);
// Transform for tile priority is updated.
EXPECT_TRANSFORMATION_MATRIX_EQ(transform,
@@ -494,7 +591,7 @@ TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
// Keep expanded viewport but mark it valid. Should update tile viewport.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
resourceless_software_draw = false;
host_impl_.SetExternalDrawConstraints(transform,
viewport,
@@ -502,13 +599,70 @@ TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
viewport,
transform,
resourceless_software_draw);
- active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+ active_layer_->UpdateTiles(resourceless_software_draw);
EXPECT_TRANSFORMATION_MATRIX_EQ(transform,
active_layer_->screen_space_transform());
EXPECT_EQ(viewport, active_layer_->visible_rect_for_tile_priority());
}
+TEST_F(PictureLayerImplTest, ViewportRectForTilePriorityIsCached) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(400, 400);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTreesWithInvalidation(pending_pile, active_pile, Region());
+
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
+
+ time_ticks += base::TimeDelta::FromMilliseconds(200);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ bool resourceless_software_draw = false;
+ gfx::Rect viewport = gfx::Rect(layer_bounds);
+ gfx::Rect viewport_rect_for_tile_priority(0, 0, 100, 100);
+ gfx::Transform transform, transform_for_tile_priority;
+
+ host_impl_.SetExternalDrawConstraints(
+ transform, viewport, viewport, viewport_rect_for_tile_priority,
+ transform_for_tile_priority, resourceless_software_draw);
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
+
+ EXPECT_EQ(viewport_rect_for_tile_priority,
+ active_layer_->viewport_rect_for_tile_priority_in_content_space());
+
+ time_ticks += base::TimeDelta::FromMilliseconds(200);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ gfx::Rect another_viewport_rect_for_tile_priority(11, 11, 50, 50);
+ host_impl_.SetExternalDrawConstraints(
+ transform, viewport, viewport, another_viewport_rect_for_tile_priority,
+ transform_for_tile_priority, resourceless_software_draw);
+
+ // Didn't call UpdateDrawProperties yet. The viewport rect for tile priority
+ // should remain to be the previously cached value.
+ EXPECT_EQ(viewport_rect_for_tile_priority,
+ active_layer_->viewport_rect_for_tile_priority_in_content_space());
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
+
+ // Now the UpdateDrawProperties is called. The viewport rect for tile
+ // priority should be the latest value.
+ EXPECT_EQ(another_viewport_rect_for_tile_priority,
+ active_layer_->viewport_rect_for_tile_priority_in_content_space());
+}
+
TEST_F(PictureLayerImplTest, ClonePartialInvalidation) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -518,11 +672,24 @@ TEST_F(PictureLayerImplTest, ClonePartialInvalidation) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> lost_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
+ SetupPendingTreeWithFixedTileSize(lost_pile, gfx::Size(50, 50), Region());
+ ActivateTree();
+ // Add a unique tiling on the active tree.
+ PictureLayerTiling* tiling = active_layer_->AddTiling(3.f);
+ tiling->CreateAllTilesForTesting();
- Region invalidation(layer_invalidation);
- AddDefaultTilingsWithInvalidation(invalidation);
+ // Ensure UpdateTiles won't remove any tilings.
+ active_layer_->MarkAllTilingsUsed();
+
+ // Then setup a new pending tree and activate it.
+ SetupTreesWithFixedTileSize(pending_pile, active_pile, gfx::Size(50, 50),
+ layer_invalidation);
+
+ EXPECT_EQ(2u, pending_layer_->num_tilings());
+ EXPECT_EQ(3u, active_layer_->num_tilings());
const PictureLayerTilingSet* tilings = pending_layer_->tilings();
EXPECT_GT(tilings->num_tilings(), 0u);
@@ -531,69 +698,35 @@ TEST_F(PictureLayerImplTest, ClonePartialInvalidation) {
gfx::Rect content_invalidation = gfx::ScaleToEnclosingRect(
layer_invalidation,
tiling->contents_scale());
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
for (PictureLayerTiling::CoverageIterator iter(
tiling,
tiling->contents_scale(),
gfx::Rect(tiling->tiling_size()));
iter;
++iter) {
- EXPECT_TRUE(*iter);
- EXPECT_FALSE(iter.geometry_rect().IsEmpty());
- if (iter.geometry_rect().Intersects(content_invalidation))
- EXPECT_EQ(pending_pile.get(), iter->raster_source());
- else
- EXPECT_EQ(active_pile.get(), iter->raster_source());
+ // We don't always have a tile, but when we do it's because it was
+ // invalidated and it has the latest raster source.
+ if (*iter) {
+ EXPECT_FALSE(iter.geometry_rect().IsEmpty());
+ EXPECT_EQ(pending_pile.get(), prioritized_tiles[*iter].raster_source());
+ EXPECT_TRUE(iter.geometry_rect().Intersects(content_invalidation));
+ } else {
+ // We don't create tiles in non-invalidated regions.
+ EXPECT_FALSE(iter.geometry_rect().Intersects(content_invalidation));
+ }
}
}
-}
-
-TEST_F(PictureLayerImplTest, CloneFullInvalidation) {
- gfx::Size tile_size(90, 80);
- gfx::Size layer_bounds(300, 500);
-
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
- SetupTrees(pending_pile, active_pile);
-
- Region invalidation((gfx::Rect(layer_bounds)));
- AddDefaultTilingsWithInvalidation(invalidation);
-
- EXPECT_EQ(pending_layer_->tilings()->num_tilings(),
- active_layer_->tilings()->num_tilings());
- const PictureLayerTilingSet* tilings = pending_layer_->tilings();
- EXPECT_GT(tilings->num_tilings(), 0u);
- for (size_t i = 0; i < tilings->num_tilings(); ++i)
- VerifyAllTilesExistAndHavePile(tilings->tiling_at(i), pending_pile.get());
-}
-
-TEST_F(PictureLayerImplTest, NoInvalidationBoundsChange) {
- gfx::Size tile_size(90, 80);
- gfx::Size active_layer_bounds(300, 500);
- gfx::Size pending_layer_bounds(400, 800);
-
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size,
- pending_layer_bounds);
- scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, active_layer_bounds);
-
- SetupTrees(pending_pile, active_pile);
- pending_layer_->set_fixed_tile_size(gfx::Size(100, 100));
-
- Region invalidation;
- AddDefaultTilingsWithInvalidation(invalidation);
-
- const PictureLayerTilingSet* tilings = pending_layer_->tilings();
+ tilings = active_layer_->tilings();
EXPECT_GT(tilings->num_tilings(), 0u);
for (size_t i = 0; i < tilings->num_tilings(); ++i) {
const PictureLayerTiling* tiling = tilings->tiling_at(i);
- gfx::Rect active_content_bounds = gfx::ScaleToEnclosingRect(
- gfx::Rect(active_layer_bounds),
- tiling->contents_scale());
+ gfx::Rect content_invalidation =
+ gfx::ScaleToEnclosingRect(layer_invalidation, tiling->contents_scale());
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
for (PictureLayerTiling::CoverageIterator iter(
tiling,
tiling->contents_scale(),
@@ -602,94 +735,111 @@ TEST_F(PictureLayerImplTest, NoInvalidationBoundsChange) {
++iter) {
EXPECT_TRUE(*iter);
EXPECT_FALSE(iter.geometry_rect().IsEmpty());
- std::vector<Tile*> active_tiles =
- active_layer_->tilings()->tiling_at(i)->AllTilesForTesting();
- std::vector<Tile*> pending_tiles = tiling->AllTilesForTesting();
- if (iter.geometry_rect().right() >= active_content_bounds.width() ||
- iter.geometry_rect().bottom() >= active_content_bounds.height() ||
- active_tiles[0]->content_rect().size() !=
- pending_tiles[0]->content_rect().size()) {
- EXPECT_EQ(pending_pile.get(), iter->raster_source());
- } else {
- EXPECT_EQ(active_pile.get(), iter->raster_source());
- }
+ // Pile will be updated upon activation.
+ EXPECT_EQ(active_pile.get(), prioritized_tiles[*iter].raster_source());
}
}
}
-TEST_F(PictureLayerImplTest, AddTilesFromNewRecording) {
- gfx::Size tile_size(400, 400);
- gfx::Size layer_bounds(1300, 1900);
+TEST_F(PictureLayerImplTest, CloneFullInvalidation) {
+ gfx::Size tile_size(90, 80);
+ gfx::Size layer_bounds(300, 500);
scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- // Fill in some of active pile, but more of pending pile.
- int hole_count = 0;
- for (int x = 0; x < active_pile->tiling().num_tiles_x(); ++x) {
- for (int y = 0; y < active_pile->tiling().num_tiles_y(); ++y) {
- if ((x + y) % 2) {
- pending_pile->AddRecordingAt(x, y);
- active_pile->AddRecordingAt(x, y);
- } else {
- hole_count++;
- if (hole_count % 2)
- pending_pile->AddRecordingAt(x, y);
- }
- }
- }
+ SetupTreesWithInvalidation(pending_pile, active_pile,
+ gfx::Rect(layer_bounds));
- SetupTrees(pending_pile, active_pile);
- Region invalidation;
- AddDefaultTilingsWithInvalidation(invalidation);
+ EXPECT_EQ(pending_layer_->tilings()->num_tilings(),
+ active_layer_->tilings()->num_tilings());
const PictureLayerTilingSet* tilings = pending_layer_->tilings();
EXPECT_GT(tilings->num_tilings(), 0u);
- for (size_t i = 0; i < tilings->num_tilings(); ++i) {
- const PictureLayerTiling* tiling = tilings->tiling_at(i);
-
- for (PictureLayerTiling::CoverageIterator iter(
- tiling,
- tiling->contents_scale(),
- gfx::Rect(tiling->tiling_size()));
- iter;
- ++iter) {
- EXPECT_FALSE(iter.full_tile_geometry_rect().IsEmpty());
- // Ensure there is a recording for this tile.
- bool in_pending = pending_pile->CoversRect(iter.full_tile_geometry_rect(),
- tiling->contents_scale());
- bool in_active = active_pile->CoversRect(iter.full_tile_geometry_rect(),
- tiling->contents_scale());
-
- if (in_pending && !in_active)
- EXPECT_EQ(pending_pile.get(), iter->raster_source());
- else if (in_active)
- EXPECT_EQ(active_pile.get(), iter->raster_source());
- else
- EXPECT_FALSE(*iter);
- }
- }
+ for (size_t i = 0; i < tilings->num_tilings(); ++i)
+ VerifyAllPrioritizedTilesExistAndHavePile(tilings->tiling_at(i),
+ pending_pile.get());
}
-TEST_F(PictureLayerImplTest, ManageTilingsWithNoRecording) {
+TEST_F(PictureLayerImplTest, UpdateTilesCreatesTilings) {
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(1300, 1900);
scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupTrees(pending_pile, active_pile);
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+ EXPECT_LT(low_res_factor, 1.f);
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+ active_layer_->ReleaseResources();
+ EXPECT_FALSE(active_layer_->tilings());
+ active_layer_->RecreateResources();
+ EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ 6.f, // ideal contents scale
+ 3.f, // device scale
+ 2.f, // page scale
+ 1.f, // maximum animation scale
+ 0.f, // starting animation scale
+ false);
+ ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(6.f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(6.f * low_res_factor,
+ active_layer_->tilings()->tiling_at(1)->contents_scale());
+
+ // If we change the page scale factor, then we should get new tilings.
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ 6.6f, // ideal contents scale
+ 3.f, // device scale
+ 2.2f, // page scale
+ 1.f, // maximum animation scale
+ 0.f, // starting animation scale
+ false);
+ ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(6.6f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(6.6f * low_res_factor,
+ active_layer_->tilings()->tiling_at(2)->contents_scale());
+
+ // If we change the device scale factor, then we should get new tilings.
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ 7.26f, // ideal contents scale
+ 3.3f, // device scale
+ 2.2f, // page scale
+ 1.f, // maximum animation scale
+ 0.f, // starting animation scale
+ false);
+ ASSERT_EQ(6u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(7.26f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(7.26f * low_res_factor,
+ active_layer_->tilings()->tiling_at(3)->contents_scale());
+
+ // If we change the device scale factor, but end up at the same total scale
+ // factor somehow, then we don't get new tilings.
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ 7.26f, // ideal contents scale
+ 2.2f, // device scale
+ 3.3f, // page scale
+ 1.f, // maximum animation scale
+ 0.f, // starting animation scale
+ false);
+ ASSERT_EQ(6u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(7.26f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(7.26f * low_res_factor,
+ active_layer_->tilings()->tiling_at(3)->contents_scale());
}
-TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) {
+TEST_F(PictureLayerImplTest, PendingLayerOnlyHasHighAndLowResTiling) {
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(1300, 1900);
@@ -699,16 +849,21 @@ TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupTrees(pending_pile, active_pile);
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
EXPECT_LT(low_res_factor, 1.f);
+ pending_layer_->ReleaseResources();
+ EXPECT_FALSE(pending_layer_->tilings());
+ pending_layer_->RecreateResources();
+ EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
SetupDrawPropertiesAndUpdateTiles(pending_layer_,
6.f, // ideal contents scale
3.f, // device scale
2.f, // page scale
1.f, // maximum animation scale
+ 0.f, // starting animation scale
false);
ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(6.f,
@@ -722,12 +877,13 @@ TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) {
3.f, // device scale
2.2f, // page scale
1.f, // maximum animation scale
+ 0.f, // starting animation scale
false);
- ASSERT_EQ(4u, pending_layer_->tilings()->num_tilings());
+ ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(6.6f,
pending_layer_->tilings()->tiling_at(0)->contents_scale());
EXPECT_FLOAT_EQ(6.6f * low_res_factor,
- pending_layer_->tilings()->tiling_at(2)->contents_scale());
+ pending_layer_->tilings()->tiling_at(1)->contents_scale());
// If we change the device scale factor, then we should get new tilings.
SetupDrawPropertiesAndUpdateTiles(pending_layer_,
@@ -735,12 +891,13 @@ TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) {
3.3f, // device scale
2.2f, // page scale
1.f, // maximum animation scale
+ 0.f, // starting animation scale
false);
- ASSERT_EQ(6u, pending_layer_->tilings()->num_tilings());
+ ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(7.26f,
pending_layer_->tilings()->tiling_at(0)->contents_scale());
EXPECT_FLOAT_EQ(7.26f * low_res_factor,
- pending_layer_->tilings()->tiling_at(3)->contents_scale());
+ pending_layer_->tilings()->tiling_at(1)->contents_scale());
// If we change the device scale factor, but end up at the same total scale
// factor somehow, then we don't get new tilings.
@@ -749,12 +906,13 @@ TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) {
2.2f, // device scale
3.3f, // page scale
1.f, // maximum animation scale
+ 0.f, // starting animation scale
false);
- ASSERT_EQ(6u, pending_layer_->tilings()->num_tilings());
+ ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(7.26f,
pending_layer_->tilings()->tiling_at(0)->contents_scale());
EXPECT_FLOAT_EQ(7.26f * low_res_factor,
- pending_layer_->tilings()->tiling_at(3)->contents_scale());
+ pending_layer_->tilings()->tiling_at(1)->contents_scale());
}
TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
@@ -769,63 +927,22 @@ TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
scoped_refptr<FakePicturePileImpl> valid_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
- EXPECT_LT(low_res_factor, 1.f);
-
- float high_res_scale = 1.3f;
- float low_res_scale = high_res_scale * low_res_factor;
- float device_scale = 1.7f;
- float page_scale = 3.2f;
- float maximum_animation_scale = 1.f;
-
SetupPendingTree(valid_pile);
- SetupDrawPropertiesAndUpdateTiles(pending_layer_,
- high_res_scale,
- device_scale,
- page_scale,
- maximum_animation_scale,
- false);
ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(high_res_scale,
- pending_layer_->HighResTiling()->contents_scale());
- EXPECT_FLOAT_EQ(low_res_scale,
- pending_layer_->LowResTiling()->contents_scale());
ActivateTree();
SetupPendingTree(empty_pile);
EXPECT_FALSE(pending_layer_->CanHaveTilings());
- SetupDrawPropertiesAndUpdateTiles(pending_layer_,
- high_res_scale,
- device_scale,
- page_scale,
- maximum_animation_scale,
- false);
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
ASSERT_EQ(0u, pending_layer_->tilings()->num_tilings());
ActivateTree();
EXPECT_FALSE(active_layer_->CanHaveTilings());
- SetupDrawPropertiesAndUpdateTiles(active_layer_,
- high_res_scale,
- device_scale,
- page_scale,
- maximum_animation_scale,
- false);
ASSERT_EQ(0u, active_layer_->tilings()->num_tilings());
SetupPendingTree(valid_pile);
- SetupDrawPropertiesAndUpdateTiles(pending_layer_,
- high_res_scale,
- device_scale,
- page_scale,
- maximum_animation_scale,
- false);
ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
ASSERT_EQ(0u, active_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(high_res_scale,
- pending_layer_->HighResTiling()->contents_scale());
- EXPECT_FLOAT_EQ(low_res_scale,
- pending_layer_->LowResTiling()->contents_scale());
}
TEST_F(PictureLayerImplTest, ZoomOutCrash) {
@@ -839,11 +956,13 @@ TEST_F(PictureLayerImplTest, ZoomOutCrash) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupTrees(pending_pile, active_pile);
+ ResetTilingsAndRasterScales();
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, 1.0f, false);
+ SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, 1.0f, 0.f, false);
+ EXPECT_EQ(32.f, active_layer_->HighResTiling()->contents_scale());
host_impl_.PinchGestureBegin();
- SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, false);
- SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, false);
+ SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, 0.f, false);
EXPECT_EQ(active_layer_->tilings()->NumHighResTilings(), 1);
}
@@ -851,6 +970,8 @@ TEST_F(PictureLayerImplTest, PinchGestureTilings) {
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(1300, 1900);
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
@@ -858,21 +979,23 @@ TEST_F(PictureLayerImplTest, PinchGestureTilings) {
// Set up the high and low res tilings before pinch zoom.
SetupTrees(pending_pile, active_pile);
- EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(2.0f, 1.0f, 1.0f, 1.0f, false);
- float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
- EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(2.0f,
- active_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_FLOAT_EQ(2.0f * low_res_factor,
- active_layer_->tilings()->tiling_at(1)->contents_scale());
+ ResetTilingsAndRasterScales();
+
+ SetContentsScaleOnBothLayers(2.f, 1.0f, 2.f, 1.0f, 0.f, false);
+ EXPECT_BOTH_EQ(num_tilings(), 2u);
+ EXPECT_BOTH_EQ(tilings()->tiling_at(0)->contents_scale(), 2.f);
+ EXPECT_BOTH_EQ(tilings()->tiling_at(1)->contents_scale(),
+ 2.f * low_res_factor);
+
+ // Ensure UpdateTiles won't remove any tilings.
+ active_layer_->MarkAllTilingsUsed();
// Start a pinch gesture.
host_impl_.PinchGestureBegin();
// Zoom out by a small amount. We should create a tiling at half
// the scale (2/kMaxScaleRatioDuringPinch).
- SetContentsScaleOnBothLayers(1.8f, 1.0f, 0.9f, 1.0f, false);
+ SetContentsScaleOnBothLayers(1.8f, 1.0f, 1.8f, 1.0f, 0.f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(2.0f,
active_layer_->tilings()->tiling_at(0)->contents_scale());
@@ -881,20 +1004,18 @@ TEST_F(PictureLayerImplTest, PinchGestureTilings) {
EXPECT_FLOAT_EQ(2.0f * low_res_factor,
active_layer_->tilings()->tiling_at(2)->contents_scale());
+ // Ensure UpdateTiles won't remove any tilings.
+ active_layer_->MarkAllTilingsUsed();
+
// Zoom out further, close to our low-res scale factor. We should
// use that tiling as high-res, and not create a new tiling.
- SetContentsScaleOnBothLayers(
- low_res_factor, 1.0f, low_res_factor / 2.0f, 1.0f, false);
+ SetContentsScaleOnBothLayers(low_res_factor * 2.1f, 1.0f,
+ low_res_factor * 2.1f, 1.0f, 0.f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
// Zoom in a lot now. Since we increase by increments of
- // kMaxScaleRatioDuringPinch, this will first use 1.0, then 2.0
- // and then finally create a new tiling at 4.0.
- SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
- EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
- EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
+ // kMaxScaleRatioDuringPinch, this will create a new tiling at 4.0.
+ SetContentsScaleOnBothLayers(3.8f, 1.0f, 3.8f, 1.f, 0.f, false);
EXPECT_EQ(4u, active_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(4.0f,
active_layer_->tilings()->tiling_at(0)->contents_scale());
@@ -909,22 +1030,28 @@ TEST_F(PictureLayerImplTest, SnappedTilingDuringZoom) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- // Set up the high and low res tilings before pinch zoom.
SetupTrees(pending_pile, active_pile);
+
+ ResetTilingsAndRasterScales();
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(0.24f, 1.0f, 0.24f, 1.0f, false);
+
+ // Set up the high and low res tilings before pinch zoom.
+ SetContentsScaleOnBothLayers(0.24f, 1.0f, 0.24f, 1.0f, 0.f, false);
EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(0.24f,
active_layer_->tilings()->tiling_at(0)->contents_scale());
EXPECT_FLOAT_EQ(0.0625f,
active_layer_->tilings()->tiling_at(1)->contents_scale());
+ // Ensure UpdateTiles won't remove any tilings.
+ active_layer_->MarkAllTilingsUsed();
+
// Start a pinch gesture.
host_impl_.PinchGestureBegin();
// Zoom out by a small amount. We should create a tiling at half
// the scale (1/kMaxScaleRatioDuringPinch).
- SetContentsScaleOnBothLayers(0.2f, 1.0f, 0.2f, 1.0f, false);
+ SetContentsScaleOnBothLayers(0.2f, 1.0f, 0.2f, 1.0f, 0.f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(0.24f,
active_layer_->tilings()->tiling_at(0)->contents_scale());
@@ -933,15 +1060,25 @@ TEST_F(PictureLayerImplTest, SnappedTilingDuringZoom) {
EXPECT_FLOAT_EQ(0.0625,
active_layer_->tilings()->tiling_at(2)->contents_scale());
+ // Ensure UpdateTiles won't remove any tilings.
+ active_layer_->MarkAllTilingsUsed();
+
// Zoom out further, close to our low-res scale factor. We should
// use that tiling as high-res, and not create a new tiling.
- SetContentsScaleOnBothLayers(0.1f, 1.0f, 0.1f, 1.0f, false);
+ SetContentsScaleOnBothLayers(0.1f, 1.0f, 0.1f, 1.0f, 0.f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
- // Zoom in. 0.125(desired_scale) should be snapped to 0.12 during zoom-in
- // because 0.125(desired_scale) is within the ratio(1.2)
- SetContentsScaleOnBothLayers(0.5f, 1.0f, 0.5f, 1.0f, false);
+ // Zoom in. 0.25(desired_scale) should be snapped to 0.24 during zoom-in
+ // because 0.25(desired_scale) is within the ratio(1.2).
+ SetContentsScaleOnBothLayers(0.25f, 1.0f, 0.25f, 1.0f, 0.f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
+
+ // Zoom in a lot. Since we move in factors of two, we should get a scale that
+ // is a power of 2 times 0.24.
+ SetContentsScaleOnBothLayers(1.f, 1.0f, 1.f, 1.0f, 0.f, false);
+ EXPECT_EQ(4u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(1.92f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
}
TEST_F(PictureLayerImplTest, CleanUpTilings) {
@@ -955,31 +1092,33 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
std::vector<PictureLayerTiling*> used_tilings;
- SetupTrees(pending_pile, active_pile);
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
EXPECT_LT(low_res_factor, 1.f);
- float device_scale = 1.7f;
- float page_scale = 3.2f;
float scale = 1.f;
+ float page_scale = 1.f;
- SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
- ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+ SetupTrees(pending_pile, active_pile);
+ EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
+ EXPECT_EQ(1.f, active_layer_->HighResTiling()->contents_scale());
+
+ // Ensure UpdateTiles won't remove any tilings. Note this is unrelated to
+ // |used_tilings| variable, and it's here only to ensure that active_layer_
+ // won't remove tilings before the test has a chance to verify behavior.
+ active_layer_->MarkAllTilingsUsed();
// We only have ideal tilings, so they aren't removed.
used_tilings.clear();
active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
- ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+ EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
host_impl_.PinchGestureBegin();
// Changing the ideal but not creating new tilings.
- scale *= 1.5f;
- page_scale *= 1.5f;
- SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
- ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+ scale = 1.5f;
+ page_scale = 1.5f;
+ SetContentsScaleOnBothLayers(scale, 1.f, page_scale, 1.f, 0.f, false);
+ EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
// The tilings are still our target scale, so they aren't removed.
used_tilings.clear();
@@ -989,9 +1128,9 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
host_impl_.PinchGestureEnd();
// Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
- scale /= 4.f;
- page_scale /= 4.f;
- SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, 1.f, false);
+ scale = 1.2f;
+ page_scale = 1.2f;
+ SetContentsScaleOnBothLayers(1.2f, 1.f, page_scale, 1.f, 0.f, false);
ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
1.f,
@@ -1000,6 +1139,9 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
1.f * low_res_factor,
active_layer_->tilings()->tiling_at(3)->contents_scale());
+ // Ensure UpdateTiles won't remove any tilings.
+ active_layer_->MarkAllTilingsUsed();
+
// Mark the non-ideal tilings as used. They won't be removed.
used_tilings.clear();
used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
@@ -1008,7 +1150,7 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
// Now move the ideal scale to 0.5. Our target stays 1.2.
- SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, 1.f, false);
+ SetContentsScaleOnBothLayers(0.5f, 1.f, page_scale, 1.f, 0.f, false);
// The high resolution tiling is between target and ideal, so is not
// removed. The low res tiling for the old ideal=1.0 scale is removed.
@@ -1017,7 +1159,7 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
// Now move the ideal scale to 1.0. Our target stays 1.2.
- SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, 1.f, false);
+ SetContentsScaleOnBothLayers(1.f, 1.f, page_scale, 1.f, 0.f, false);
// All the tilings are between are target and the ideal, so they are not
// removed.
@@ -1026,8 +1168,8 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
// Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2.
- SetupDrawPropertiesAndUpdateTiles(
- active_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.1f, 1.f, page_scale, 1.f,
+ 0.f, false);
// Because the pending layer's ideal scale is still 1.0, our tilings fall
// in the range [1.0,1.2] and are kept.
@@ -1037,8 +1179,8 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
// Move the ideal scale on the pending layer to 1.1 as well. Our target stays
// 1.2 still.
- SetupDrawPropertiesAndUpdateTiles(
- pending_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.1f, 1.f, page_scale, 1.f,
+ 0.f, false);
// Our 1.0 tiling now falls outside the range between our ideal scale and our
// target raster scale. But it is in our used tilings set, so nothing is
@@ -1055,80 +1197,68 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
}
-#define EXPECT_BOTH_EQ(expression, x) \
- do { \
- EXPECT_EQ(x, pending_layer_->expression); \
- EXPECT_EQ(x, active_layer_->expression); \
- } while (false)
-
-#define EXPECT_BOTH_NE(expression, x) \
- do { \
- EXPECT_NE(x, pending_layer_->expression); \
- EXPECT_NE(x, active_layer_->expression); \
- } while (false)
-
TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) {
// Make sure this layer covers multiple tiles, since otherwise low
// res won't get created because it is too small.
gfx::Size tile_size(host_impl_.settings().default_tile_size);
- SetupDefaultTrees(gfx::Size(tile_size.width() + 1, tile_size.height() + 1));
// Avoid max untiled layer size heuristics via fixed tile size.
- pending_layer_->set_fixed_tile_size(tile_size);
- active_layer_->set_fixed_tile_size(tile_size);
+ gfx::Size layer_bounds(tile_size.width() + 1, tile_size.height() + 1);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
float contents_scale = 1.f;
float device_scale = 1.f;
float page_scale = 1.f;
float maximum_animation_scale = 1.f;
+ float starting_animation_scale = 0.f;
bool animating_transform = true;
+ ResetTilingsAndRasterScales();
+
// Animating, so don't create low res even if there isn't one already.
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
EXPECT_BOTH_EQ(num_tilings(), 1u);
// Stop animating, low res gets created.
animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), low_res_factor);
EXPECT_BOTH_EQ(num_tilings(), 2u);
+ // Ensure UpdateTiles won't remove any tilings.
+ active_layer_->MarkAllTilingsUsed();
+
// Page scale animation, new high res, but no low res. We still have
- // a tiling at the previous scale, it's just not marked as low res.
+ // a tiling at the previous scale, it's just not marked as low res on the
+ // active layer. The pending layer drops non-ideal tilings.
contents_scale = 2.f;
page_scale = 2.f;
maximum_animation_scale = 2.f;
animating_transform = true;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
EXPECT_FALSE(active_layer_->LowResTiling());
EXPECT_FALSE(pending_layer_->LowResTiling());
- EXPECT_BOTH_EQ(num_tilings(), 3u);
+ EXPECT_EQ(3u, active_layer_->num_tilings());
+ EXPECT_EQ(1u, pending_layer_->num_tilings());
// Stop animating, new low res gets created for final page scale.
animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), 2.f * low_res_factor);
- EXPECT_BOTH_EQ(num_tilings(), 4u);
+ EXPECT_EQ(4u, active_layer_->num_tilings());
+ EXPECT_EQ(2u, pending_layer_->num_tilings());
}
TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
@@ -1146,15 +1276,14 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
float device_scale = 1.f;
float page_scale = 1.f;
float maximum_animation_scale = 1.f;
+ float starting_animation_scale = 0.f;
bool animating_transform = false;
// Contents exactly fit on one tile at scale 1, no low res.
float contents_scale = 1.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
EXPECT_BOTH_EQ(num_tilings(), 1u);
@@ -1162,11 +1291,9 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
// Contents that are smaller than one tile, no low res.
contents_scale = 0.123f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
EXPECT_BOTH_EQ(num_tilings(), 1u);
@@ -1175,112 +1302,222 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
// Any content bounds that would create more than one tile will
// generate a low res tiling.
contents_scale = 2.5f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
EXPECT_BOTH_EQ(LowResTiling()->contents_scale(),
contents_scale * low_res_factor);
EXPECT_BOTH_EQ(num_tilings(), 2u);
- ResetTilingsAndRasterScales();
-
// Mask layers dont create low res since they always fit on one tile.
- pending_pile->SetIsMask(true);
- active_pile->SetIsMask(true);
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
- maximum_animation_scale,
- animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
- EXPECT_BOTH_EQ(num_tilings(), 1u);
+ scoped_ptr<FakePictureLayerImpl> mask =
+ FakePictureLayerImpl::CreateMaskWithRasterSource(
+ host_impl_.pending_tree(), 3, pending_pile);
+ mask->SetBounds(layer_bounds);
+ mask->SetContentBounds(layer_bounds);
+ mask->SetDrawsContent(true);
+
+ SetupDrawPropertiesAndUpdateTiles(
+ mask.get(), contents_scale, device_scale, page_scale,
+ maximum_animation_scale, starting_animation_scale, animating_transform);
+ EXPECT_EQ(mask->HighResTiling()->contents_scale(), contents_scale);
+ EXPECT_EQ(mask->num_tilings(), 1u);
}
-TEST_F(PictureLayerImplTest, HugeMasksDontGetTiles) {
+TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1000, 1000);
scoped_refptr<FakePicturePileImpl> valid_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
- valid_pile->SetIsMask(true);
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupPendingTree(valid_pile);
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
- EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
- EXPECT_EQ(1u, pending_layer_->num_tilings());
+ scoped_ptr<FakePictureLayerImpl> mask_ptr =
+ FakePictureLayerImpl::CreateMaskWithRasterSource(
+ host_impl_.pending_tree(), 3, valid_pile);
+ mask_ptr->SetBounds(layer_bounds);
+ mask_ptr->SetContentBounds(layer_bounds);
+ mask_ptr->SetDrawsContent(true);
+ pending_layer_->SetMaskLayer(mask_ptr.Pass());
+ pending_layer_->SetHasRenderSurface(true);
+
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+
+ FakePictureLayerImpl* pending_mask =
+ static_cast<FakePictureLayerImpl*>(pending_layer_->mask_layer());
+
+ EXPECT_EQ(1.f, pending_mask->HighResTiling()->contents_scale());
+ EXPECT_EQ(1u, pending_mask->num_tilings());
- pending_layer_->HighResTiling()->CreateAllTilesForTesting();
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
- pending_layer_->HighResTiling()->AllTilesForTesting());
+ pending_mask->HighResTiling()->AllTilesForTesting());
ActivateTree();
+ FakePictureLayerImpl* active_mask =
+ static_cast<FakePictureLayerImpl*>(active_layer_->mask_layer());
+
// Mask layers have a tiling with a single tile in it.
- EXPECT_EQ(1u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+ EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
// The mask resource exists.
ResourceProvider::ResourceId mask_resource_id;
gfx::Size mask_texture_size;
- active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+ active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
EXPECT_NE(0u, mask_resource_id);
- EXPECT_EQ(mask_texture_size, active_layer_->bounds());
+ EXPECT_EQ(active_mask->bounds(), mask_texture_size);
+
+ // Drop resources and recreate them, still the same.
+ pending_mask->ReleaseResources();
+ active_mask->ReleaseResources();
+ pending_mask->RecreateResources();
+ active_mask->RecreateResources();
+ SetupDrawPropertiesAndUpdateTiles(active_mask, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
+ active_mask->HighResTiling()->CreateAllTilesForTesting();
+ EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
+ EXPECT_NE(0u, mask_resource_id);
+ EXPECT_EQ(active_mask->bounds(), mask_texture_size);
// Resize larger than the max texture size.
int max_texture_size = host_impl_.GetRendererCapabilities().max_texture_size;
+ gfx::Size huge_bounds(max_texture_size + 1, 10);
scoped_refptr<FakePicturePileImpl> huge_pile =
- FakePicturePileImpl::CreateFilledPile(
- tile_size, gfx::Size(max_texture_size + 1, 10));
- huge_pile->SetIsMask(true);
+ FakePicturePileImpl::CreateFilledPile(tile_size, huge_bounds);
+
SetupPendingTree(huge_pile);
+ pending_mask->SetBounds(huge_bounds);
+ pending_mask->SetContentBounds(huge_bounds);
+ pending_mask->SetRasterSourceOnPending(huge_pile, Region());
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
- EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
- EXPECT_EQ(1u, pending_layer_->num_tilings());
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+
+ // The mask tiling gets scaled down.
+ EXPECT_LT(pending_mask->HighResTiling()->contents_scale(), 1.f);
+ EXPECT_EQ(1u, pending_mask->num_tilings());
- pending_layer_->HighResTiling()->CreateAllTilesForTesting();
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
- pending_layer_->HighResTiling()->AllTilesForTesting());
+ pending_mask->HighResTiling()->AllTilesForTesting());
ActivateTree();
- // Mask layers have a tiling, but there should be no tiles in it.
- EXPECT_EQ(0u, active_layer_->HighResTiling()->AllTilesForTesting().size());
- // The mask resource is empty.
+ // Mask layers have a tiling with a single tile in it.
+ EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
+ // The mask resource exists.
+ active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+ EXPECT_NE(0u, mask_resource_id);
+ gfx::Size expected_size = active_mask->bounds();
+ expected_size.SetToMin(gfx::Size(max_texture_size, max_texture_size));
+ EXPECT_EQ(expected_size, mask_texture_size);
+
+ // Drop resources and recreate them, still the same.
+ pending_mask->ReleaseResources();
+ active_mask->ReleaseResources();
+ pending_mask->RecreateResources();
+ active_mask->RecreateResources();
+ SetupDrawPropertiesAndUpdateTiles(active_mask, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
+ active_mask->HighResTiling()->CreateAllTilesForTesting();
+ EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
+ EXPECT_NE(0u, mask_resource_id);
+ EXPECT_EQ(expected_size, mask_texture_size);
+
+ // Do another activate, the same holds.
+ SetupPendingTree(huge_pile);
+ ActivateTree();
+ EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+ EXPECT_EQ(expected_size, mask_texture_size);
EXPECT_EQ(0u, mask_resource_id);
+
+ // Resize even larger, so that the scale would be smaller than the minimum
+ // contents scale. Then the layer should no longer have any tiling.
+ float min_contents_scale = host_impl_.settings().minimum_contents_scale;
+ gfx::Size extra_huge_bounds(max_texture_size / min_contents_scale + 1, 10);
+ scoped_refptr<FakePicturePileImpl> extra_huge_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, extra_huge_bounds);
+
+ SetupPendingTree(extra_huge_pile);
+ pending_mask->SetBounds(extra_huge_bounds);
+ pending_mask->SetContentBounds(extra_huge_bounds);
+ pending_mask->SetRasterSourceOnPending(extra_huge_pile, Region());
+
+ EXPECT_FALSE(pending_mask->CanHaveTilings());
+
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+
+ EXPECT_EQ(0u, pending_mask->num_tilings());
}
TEST_F(PictureLayerImplTest, ScaledMaskLayer) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1000, 1000);
+
+ host_impl_.SetDeviceScaleFactor(1.3f);
scoped_refptr<FakePicturePileImpl> valid_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
- valid_pile->SetIsMask(true);
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupPendingTree(valid_pile);
- float ideal_contents_scale = 1.3f;
- SetupDrawPropertiesAndUpdateTiles(
- pending_layer_, ideal_contents_scale, 1.f, 1.f, 1.f, false);
- EXPECT_EQ(ideal_contents_scale,
- pending_layer_->HighResTiling()->contents_scale());
- EXPECT_EQ(1u, pending_layer_->num_tilings());
+ scoped_ptr<FakePictureLayerImpl> mask_ptr =
+ FakePictureLayerImpl::CreateMaskWithRasterSource(
+ host_impl_.pending_tree(), 3, valid_pile);
+ mask_ptr->SetBounds(layer_bounds);
+ mask_ptr->SetContentBounds(layer_bounds);
+ mask_ptr->SetDrawsContent(true);
+ pending_layer_->SetMaskLayer(mask_ptr.Pass());
+ pending_layer_->SetHasRenderSurface(true);
+
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+
+ FakePictureLayerImpl* pending_mask =
+ static_cast<FakePictureLayerImpl*>(pending_layer_->mask_layer());
+
+ // Masks are scaled, and do not have a low res tiling.
+ EXPECT_EQ(1.3f, pending_mask->HighResTiling()->contents_scale());
+ EXPECT_EQ(1u, pending_mask->num_tilings());
- pending_layer_->HighResTiling()->CreateAllTilesForTesting();
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
- pending_layer_->HighResTiling()->AllTilesForTesting());
+ pending_mask->HighResTiling()->AllTilesForTesting());
ActivateTree();
+ FakePictureLayerImpl* active_mask =
+ static_cast<FakePictureLayerImpl*>(active_layer_->mask_layer());
+
// Mask layers have a tiling with a single tile in it.
- EXPECT_EQ(1u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+ EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
// The mask resource exists.
ResourceProvider::ResourceId mask_resource_id;
gfx::Size mask_texture_size;
- active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+ active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
EXPECT_NE(0u, mask_resource_id);
- gfx::Size expected_mask_texture_size = gfx::ToCeiledSize(
- gfx::ScaleSize(active_layer_->bounds(), ideal_contents_scale));
+ gfx::Size expected_mask_texture_size =
+ gfx::ToCeiledSize(gfx::ScaleSize(active_mask->bounds(), 1.3f));
EXPECT_EQ(mask_texture_size, expected_mask_texture_size);
}
@@ -1294,47 +1531,39 @@ TEST_F(PictureLayerImplTest, ReleaseResources) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupTrees(pending_pile, active_pile);
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
- SetupDrawPropertiesAndUpdateTiles(pending_layer_,
- 1.3f, // ideal contents scale
- 2.7f, // device scale
- 3.2f, // page scale
- 1.f, // maximum animation scale
- false);
EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
// All tilings should be removed when losing output surface.
active_layer_->ReleaseResources();
+ EXPECT_FALSE(active_layer_->tilings());
+ active_layer_->RecreateResources();
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
pending_layer_->ReleaseResources();
+ EXPECT_FALSE(pending_layer_->tilings());
+ pending_layer_->RecreateResources();
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
// This should create new tilings.
SetupDrawPropertiesAndUpdateTiles(pending_layer_,
- 1.3f, // ideal contents scale
- 2.7f, // device scale
- 3.2f, // page scale
- 1.f, // maximum animation scale
+ 1.f, // ideal contents scale
+ 1.f, // device scale
+ 1.f, // page scale
+ 1.f, // maximum animation scale
+ 0.f, // starting animation_scale
false);
EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
}
-TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) {
+TEST_F(PictureLayerImplTest, ClampTilesToMaxTileSize) {
// The default max tile size is larger than 400x400.
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(5000, 5000);
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
- ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+ SetupPendingTree(pending_pile);
+ EXPECT_GE(pending_layer_->tilings()->num_tilings(), 1u);
pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1346,7 +1575,7 @@ TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) {
EXPECT_EQ(gfx::Size(256, 256).ToString(),
tile->content_rect().size().ToString());
- pending_layer_->ReleaseResources();
+ ResetTilingsAndRasterScales();
// Change the max texture size on the output surface context.
scoped_ptr<TestWebGraphicsContext3D> context =
@@ -1356,7 +1585,8 @@ TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) {
host_impl_.InitializeRenderer(
FakeOutputSurface::Create3d(context.Pass()).Pass());
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1378,22 +1608,19 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupTrees(pending_pile, active_pile);
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
- ASSERT_LE(1u, pending_layer_->tilings()->num_tilings());
+ EXPECT_GE(active_layer_->tilings()->num_tilings(), 1u);
- pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
+ active_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
// The default value. The layer is smaller than this.
EXPECT_EQ(gfx::Size(512, 512).ToString(),
host_impl_.settings().max_untiled_layer_size.ToString());
// There should be a single tile since the layer is small.
- PictureLayerTiling* high_res_tiling = pending_layer_->tilings()->tiling_at(0);
+ PictureLayerTiling* high_res_tiling = active_layer_->tilings()->tiling_at(0);
EXPECT_EQ(1u, high_res_tiling->AllTilesForTesting().size());
- pending_layer_->ReleaseResources();
+ ResetTilingsAndRasterScales();
// Change the max texture size on the output surface context.
scoped_ptr<TestWebGraphicsContext3D> context =
@@ -1403,18 +1630,19 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
host_impl_.InitializeRenderer(
FakeOutputSurface::Create3d(context.Pass()).Pass());
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
- ASSERT_LE(1u, pending_layer_->tilings()->num_tilings());
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
+ ASSERT_LE(1u, active_layer_->tilings()->num_tilings());
- pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
+ active_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
// There should be more than one tile since the max texture size won't cover
// the layer.
- high_res_tiling = pending_layer_->tilings()->tiling_at(0);
+ high_res_tiling = active_layer_->tilings()->tiling_at(0);
EXPECT_LT(1u, high_res_tiling->AllTilesForTesting().size());
// Verify the tiles are not larger than the context's max texture size.
- Tile* tile = pending_layer_->tilings()->tiling_at(0)->AllTilesForTesting()[0];
+ Tile* tile = active_layer_->tilings()->tiling_at(0)->AllTilesForTesting()[0];
EXPECT_GE(140, tile->content_rect().width());
EXPECT_GE(140, tile->content_rect().height());
}
@@ -1430,18 +1658,15 @@ TEST_F(PictureLayerImplTest, DisallowTileDrawQuads) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
+ gfx::Rect layer_invalidation(150, 200, 30, 180);
+ SetupTreesWithInvalidation(pending_pile, active_pile, layer_invalidation);
active_layer_->draw_properties().visible_content_rect =
gfx::Rect(layer_bounds);
- gfx::Rect layer_invalidation(150, 200, 30, 180);
- Region invalidation(layer_invalidation);
- AddDefaultTilingsWithInvalidation(invalidation);
-
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_RESOURCELESS_SOFTWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
ASSERT_EQ(1U, render_pass->quad_list.size());
@@ -1456,13 +1681,14 @@ TEST_F(PictureLayerImplTest, SolidColorLayerHasVisibleFullCoverage) {
gfx::Size layer_bounds(1500, 1500);
gfx::Rect visible_rect(250, 250, 1000, 1000);
+ scoped_ptr<FakePicturePile> empty_recording =
+ FakePicturePile::CreateEmptyPile(tile_size, layer_bounds);
+ empty_recording->SetIsSolidColor(true);
+
scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
+ FakePicturePileImpl::CreateFromPile(empty_recording.get(), nullptr);
scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
-
- pending_pile->set_is_solid_color(true);
- active_pile->set_is_solid_color(true);
+ FakePicturePileImpl::CreateFromPile(empty_recording.get(), nullptr);
SetupTrees(pending_pile, active_pile);
@@ -1470,7 +1696,7 @@ TEST_F(PictureLayerImplTest, SolidColorLayerHasVisibleFullCoverage) {
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
Region remaining = visible_rect;
@@ -1488,41 +1714,26 @@ TEST_F(PictureLayerImplTest, TileScalesWithSolidColorPile) {
gfx::Size tile_size(host_impl_.settings().default_tile_size);
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
- tile_size, layer_bounds);
+ tile_size, layer_bounds, false);
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
- tile_size, layer_bounds);
+ tile_size, layer_bounds, true);
- pending_pile->set_is_solid_color(false);
- active_pile->set_is_solid_color(true);
SetupTrees(pending_pile, active_pile);
- // Solid color layer should not have tilings.
- ASSERT_FALSE(active_layer_->CanHaveTilings());
-
- // Update properties with solid color pile should not allow tilings at any
- // scale.
- host_impl_.active_tree()->UpdateDrawProperties();
+ // Solid color pile should not allow tilings at any scale.
EXPECT_FALSE(active_layer_->CanHaveTilings());
EXPECT_EQ(0.f, active_layer_->ideal_contents_scale());
- // Push non-solid-color pending pile makes active layer can have tilings.
- active_layer_->UpdatePile(pending_pile);
- ASSERT_TRUE(active_layer_->CanHaveTilings());
-
- // Update properties with non-solid color pile should allow tilings.
- host_impl_.active_tree()->UpdateDrawProperties();
+ // Activate non-solid-color pending pile makes active layer can have tilings.
+ ActivateTree();
EXPECT_TRUE(active_layer_->CanHaveTilings());
EXPECT_GT(active_layer_->ideal_contents_scale(), 0.f);
}
-TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
+TEST_F(NoLowResPictureLayerImplTest, MarkRequiredOffscreenTiles) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupPendingTree(pending_pile);
-
gfx::Transform transform;
gfx::Transform transform_for_tile_priority;
bool resourceless_software_draw = false;
@@ -1534,31 +1745,32 @@ TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
transform,
resourceless_software_draw);
- pending_layer_->set_fixed_tile_size(tile_size);
- ASSERT_TRUE(pending_layer_->CanHaveTilings());
- PictureLayerTiling* tiling = pending_layer_->AddTiling(1.f);
- host_impl_.pending_tree()->UpdateDrawProperties();
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
+
+ EXPECT_EQ(1u, pending_layer_->num_tilings());
EXPECT_EQ(viewport, pending_layer_->visible_rect_for_tile_priority());
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
- pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
- EXPECT_EQ(HIGH_RESOLUTION, tiling->resolution());
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ pending_layer_->UpdateTiles(resourceless_software_draw);
int num_visible = 0;
int num_offscreen = 0;
- for (PictureLayerTiling::TilingRasterTileIterator iter(tiling); iter;
- ++iter) {
- const Tile* tile = *iter;
- DCHECK(tile);
- if (tile->priority(PENDING_TREE).distance_to_visible == 0.f) {
- EXPECT_TRUE(tile->required_for_activation());
+ scoped_ptr<TilingSetRasterQueueAll> queue(new TilingSetRasterQueueAll(
+ pending_layer_->picture_layer_tiling_set(), false));
+ for (; !queue->IsEmpty(); queue->Pop()) {
+ const PrioritizedTile& prioritized_tile = queue->Top();
+ DCHECK(prioritized_tile.tile());
+ if (prioritized_tile.priority().distance_to_visible == 0.f) {
+ EXPECT_TRUE(prioritized_tile.tile()->required_for_activation());
num_visible++;
} else {
- EXPECT_FALSE(tile->required_for_activation());
+ EXPECT_FALSE(prioritized_tile.tile()->required_for_activation());
num_offscreen++;
}
}
@@ -1567,11 +1779,12 @@ TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
EXPECT_GT(num_offscreen, 0);
}
-TEST_F(PictureLayerImplTest, TileOutsideOfViewportForTilePriorityNotRequired) {
+TEST_F(NoLowResPictureLayerImplTest,
+ TileOutsideOfViewportForTilePriorityNotRequired) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -1582,12 +1795,10 @@ TEST_F(PictureLayerImplTest, TileOutsideOfViewportForTilePriorityNotRequired) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
+ SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
- active_layer_->set_fixed_tile_size(tile_size);
- pending_layer_->set_fixed_tile_size(tile_size);
- ASSERT_TRUE(pending_layer_->CanHaveTilings());
- PictureLayerTiling* tiling = pending_layer_->AddTiling(1.f);
+ ASSERT_EQ(1u, pending_layer_->num_tilings());
+ ASSERT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
// Set external viewport for tile priority.
gfx::Rect viewport = gfx::Rect(layer_bounds);
@@ -1600,35 +1811,40 @@ TEST_F(PictureLayerImplTest, TileOutsideOfViewportForTilePriorityNotRequired) {
external_viewport_for_tile_priority,
transform_for_tile_priority,
resourceless_software_draw);
- host_impl_.pending_tree()->UpdateDrawProperties();
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
// Set visible content rect that is different from
// external_viewport_for_tile_priority.
pending_layer_->draw_properties().visible_content_rect = visible_content_rect;
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
- pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ pending_layer_->UpdateTiles(resourceless_software_draw);
// Intersect the two rects. Any tile outside should not be required for
// activation.
gfx::Rect viewport_for_tile_priority =
- pending_layer_->GetViewportForTilePriorityInContentSpace();
+ pending_layer_->viewport_rect_for_tile_priority_in_content_space();
viewport_for_tile_priority.Intersect(pending_layer_->visible_content_rect());
+ EXPECT_TRUE(pending_layer_->HighResTiling()->AllTilesForTesting().empty());
+
int num_inside = 0;
int num_outside = 0;
- for (PictureLayerTiling::CoverageIterator iter(
- tiling, pending_layer_->contents_scale_x(), gfx::Rect(layer_bounds));
- iter;
- ++iter) {
+ for (PictureLayerTiling::CoverageIterator iter(active_layer_->HighResTiling(),
+ 1.f, gfx::Rect(layer_bounds));
+ iter; ++iter) {
if (!*iter)
continue;
Tile* tile = *iter;
if (viewport_for_tile_priority.Intersects(iter.geometry_rect())) {
num_inside++;
// Mark everything in viewport for tile priority as ready to draw.
- ManagedTileState::DrawInfo& draw_info = tile->draw_info();
+ TileDrawInfo& draw_info = tile->draw_info();
draw_info.SetSolidColorForTesting(SK_ColorRED);
} else {
num_outside++;
@@ -1641,13 +1857,13 @@ TEST_F(PictureLayerImplTest, TileOutsideOfViewportForTilePriorityNotRequired) {
// Activate and draw active layer.
host_impl_.ActivateSyncTree();
- host_impl_.active_tree()->UpdateDrawProperties();
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
active_layer_->draw_properties().visible_content_rect = visible_content_rect;
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
// All tiles in activation rect is ready to draw.
@@ -1660,21 +1876,18 @@ TEST_F(PictureLayerImplTest, HighResTileIsComplete) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
- host_impl_.SetViewportSize(layer_bounds);
-
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupPendingTree(pending_pile);
+
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
ActivateTree();
// All high res tiles have resources.
- active_layer_->set_fixed_tile_size(tile_size);
- host_impl_.active_tree()->UpdateDrawProperties();
std::vector<Tile*> tiles =
active_layer_->tilings()->tiling_at(0)->AllTilesForTesting();
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
@@ -1682,7 +1895,7 @@ TEST_F(PictureLayerImplTest, HighResTileIsComplete) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
// All high res tiles drew, nothing was incomplete.
@@ -1696,25 +1909,20 @@ TEST_F(PictureLayerImplTest, HighResTileIsIncomplete) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
- host_impl_.SetViewportSize(layer_bounds);
-
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupPendingTree(pending_pile);
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
ActivateTree();
- active_layer_->set_fixed_tile_size(tile_size);
- host_impl_.active_tree()->UpdateDrawProperties();
-
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
EXPECT_EQ(1u, render_pass->quad_list.size());
@@ -1727,20 +1935,16 @@ TEST_F(PictureLayerImplTest, HighResTileIsIncompleteLowResComplete) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
- host_impl_.SetViewportSize(layer_bounds);
-
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupPendingTree(pending_pile);
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
ActivateTree();
- active_layer_->set_fixed_tile_size(tile_size);
- host_impl_.active_tree()->UpdateDrawProperties();
std::vector<Tile*> low_tiles =
active_layer_->tilings()->tiling_at(1)->AllTilesForTesting();
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(low_tiles);
@@ -1748,7 +1952,7 @@ TEST_F(PictureLayerImplTest, HighResTileIsIncompleteLowResComplete) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
EXPECT_EQ(1u, render_pass->quad_list.size());
@@ -1761,21 +1965,17 @@ TEST_F(PictureLayerImplTest, LowResTileIsIncomplete) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
- host_impl_.SetViewportSize(layer_bounds);
-
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupPendingTree(pending_pile);
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
ActivateTree();
// All high res tiles have resources except one.
- active_layer_->set_fixed_tile_size(tile_size);
- host_impl_.active_tree()->UpdateDrawProperties();
std::vector<Tile*> high_tiles =
active_layer_->tilings()->tiling_at(0)->AllTilesForTesting();
high_tiles.erase(high_tiles.begin());
@@ -1789,7 +1989,7 @@ TEST_F(PictureLayerImplTest, LowResTileIsIncomplete) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
// The missing high res tile was replaced by a low res tile.
@@ -1804,24 +2004,20 @@ TEST_F(PictureLayerImplTest,
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
+ gfx::Size viewport_size(400, 400);
- host_impl_.SetViewportSize(layer_bounds);
+ host_impl_.SetViewportSize(viewport_size);
+ host_impl_.SetDeviceScaleFactor(2.f);
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
-
- active_layer_->set_fixed_tile_size(tile_size);
-
- active_layer_->draw_properties().visible_content_rect =
- gfx::Rect(layer_bounds);
- SetupDrawPropertiesAndUpdateTiles(active_layer_, 2.f, 1.f, 1.f, 1.f, false);
+ SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
// One ideal tile exists, this will get used when drawing.
std::vector<Tile*> ideal_tiles;
@@ -1832,8 +2028,10 @@ TEST_F(PictureLayerImplTest,
// Due to layer scale throttling, the raster contents scale is changed to 1,
// while the ideal is still 2.
- SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
- SetupDrawPropertiesAndUpdateTiles(active_layer_, 2.f, 1.f, 1.f, 1.f, false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 2.f, 1.f, 1.f, 1.f, 0.f,
+ false);
EXPECT_EQ(1.f, active_layer_->HighResTiling()->contents_scale());
EXPECT_EQ(1.f, active_layer_->raster_contents_scale());
@@ -1851,7 +2049,7 @@ TEST_F(PictureLayerImplTest,
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
// All high res tiles drew, and the one ideal res tile drew.
@@ -1869,22 +2067,19 @@ TEST_F(PictureLayerImplTest,
EXPECT_FALSE(active_layer_->only_used_low_res_last_append_quads());
}
-TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) {
+TEST_F(PictureLayerImplTest, HighResRequiredWhenActiveAllReady) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
- // No tiles shared.
- pending_layer_->set_invalidation(gfx::Rect(layer_bounds));
-
- CreateHighLowResAndSetAllTilesVisible();
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size,
+ gfx::Rect(layer_bounds));
active_layer_->SetAllTilesReady();
- // No shared tiles and all active tiles ready, so pending can only
- // activate with all high res tiles.
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
- pending_layer_->LowResTiling()->UpdateAllTilePrioritiesForTesting();
+ // All active tiles ready, so pending can only activate with all high res
+ // tiles.
+ pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+ pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
AssertAllTilesRequired(pending_layer_->HighResTiling());
AssertNoTilesRequired(pending_layer_->LowResTiling());
@@ -1893,86 +2088,92 @@ TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) {
TEST_F(PictureLayerImplTest, HighResRequiredWhenMissingHighResFlagOn) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
- // All tiles shared (no invalidation).
- CreateHighLowResAndSetAllTilesVisible();
+ // No invalidation.
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
// Verify active tree not ready.
Tile* some_active_tile =
active_layer_->HighResTiling()->AllTilesForTesting()[0];
- EXPECT_FALSE(some_active_tile->IsReadyToDraw());
+ EXPECT_FALSE(some_active_tile->draw_info().IsReadyToDraw());
- // When high res are required, even if the active tree is not ready,
- // the high res tiles must be ready.
+ // When high res are required, all tiles in active high res tiling should be
+ // required for activation.
host_impl_.SetRequiresHighResToDraw();
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
- pending_layer_->LowResTiling()->UpdateAllTilePrioritiesForTesting();
+ pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+ pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
+ active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+ active_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
- AssertAllTilesRequired(pending_layer_->HighResTiling());
- AssertNoTilesRequired(pending_layer_->LowResTiling());
+ EXPECT_TRUE(pending_layer_->HighResTiling()->AllTilesForTesting().empty());
+ EXPECT_TRUE(pending_layer_->LowResTiling()->AllTilesForTesting().empty());
+ AssertAllTilesRequired(active_layer_->HighResTiling());
+ AssertNoTilesRequired(active_layer_->LowResTiling());
}
-TEST_F(PictureLayerImplTest, AllHighResRequiredEvenIfShared) {
+TEST_F(PictureLayerImplTest, AllHighResRequiredEvenIfNotChanged) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
- CreateHighLowResAndSetAllTilesVisible();
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
Tile* some_active_tile =
active_layer_->HighResTiling()->AllTilesForTesting()[0];
- EXPECT_FALSE(some_active_tile->IsReadyToDraw());
+ EXPECT_FALSE(some_active_tile->draw_info().IsReadyToDraw());
- // All tiles shared (no invalidation), so even though the active tree's
- // tiles aren't ready, the high res tiles are required for activation.
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
- pending_layer_->LowResTiling()->UpdateAllTilePrioritiesForTesting();
+ // Since there are no invalidations, pending tree should have no tiles.
+ EXPECT_TRUE(pending_layer_->HighResTiling()->AllTilesForTesting().empty());
+ EXPECT_TRUE(pending_layer_->LowResTiling()->AllTilesForTesting().empty());
- AssertAllTilesRequired(pending_layer_->HighResTiling());
- AssertNoTilesRequired(pending_layer_->LowResTiling());
+ active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+ active_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
+
+ AssertAllTilesRequired(active_layer_->HighResTiling());
+ AssertNoTilesRequired(active_layer_->LowResTiling());
}
TEST_F(PictureLayerImplTest, DisallowRequiredForActivation) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
- CreateHighLowResAndSetAllTilesVisible();
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
Tile* some_active_tile =
active_layer_->HighResTiling()->AllTilesForTesting()[0];
- EXPECT_FALSE(some_active_tile->IsReadyToDraw());
+ EXPECT_FALSE(some_active_tile->draw_info().IsReadyToDraw());
+ EXPECT_TRUE(pending_layer_->HighResTiling()->AllTilesForTesting().empty());
+ EXPECT_TRUE(pending_layer_->LowResTiling()->AllTilesForTesting().empty());
+ active_layer_->HighResTiling()->set_can_require_tiles_for_activation(false);
+ active_layer_->LowResTiling()->set_can_require_tiles_for_activation(false);
pending_layer_->HighResTiling()->set_can_require_tiles_for_activation(false);
pending_layer_->LowResTiling()->set_can_require_tiles_for_activation(false);
// If we disallow required for activation, no tiles can be required.
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
- pending_layer_->LowResTiling()->UpdateAllTilePrioritiesForTesting();
+ active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+ active_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
- AssertNoTilesRequired(pending_layer_->HighResTiling());
- AssertNoTilesRequired(pending_layer_->LowResTiling());
+ AssertNoTilesRequired(active_layer_->HighResTiling());
+ AssertNoTilesRequired(active_layer_->LowResTiling());
}
TEST_F(PictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
// This pile will create tilings, but has no recordings so will not create any
// tiles. This is attempting to simulate scrolling past the end of recorded
// content on the active layer, where the recordings are so far away that
// no tiles are created.
+ bool is_solid_color = false;
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
- tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
- pending_layer_->set_fixed_tile_size(tile_size);
- active_layer_->set_fixed_tile_size(tile_size);
+ tile_size, layer_bounds, is_solid_color);
- CreateHighLowResAndSetAllTilesVisible();
+ SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
// Active layer has tilings, but no tiles due to missing recordings.
EXPECT_TRUE(active_layer_->CanHaveTilings());
@@ -1981,8 +2182,8 @@ TEST_F(PictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
// Since the active layer has no tiles at all, the pending layer doesn't
// need content in order to activate.
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
- pending_layer_->LowResTiling()->UpdateAllTilePrioritiesForTesting();
+ pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+ pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
AssertNoTilesRequired(pending_layer_->HighResTiling());
AssertNoTilesRequired(pending_layer_->LowResTiling());
@@ -1991,15 +2192,12 @@ TEST_F(PictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
TEST_F(PictureLayerImplTest, HighResRequiredIfActiveCantHaveTiles) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
- pending_layer_->set_fixed_tile_size(tile_size);
- active_layer_->set_fixed_tile_size(tile_size);
-
- CreateHighLowResAndSetAllTilesVisible();
+ SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
// Active layer can't have tiles.
EXPECT_FALSE(active_layer_->CanHaveTilings());
@@ -2008,37 +2206,39 @@ TEST_F(PictureLayerImplTest, HighResRequiredIfActiveCantHaveTiles) {
// to the case where there is no active layer, to avoid flashing content.
// This can happen if a layer exists for a while and switches from
// not being able to have content to having content.
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
- pending_layer_->LowResTiling()->UpdateAllTilePrioritiesForTesting();
+ pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+ pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
AssertAllTilesRequired(pending_layer_->HighResTiling());
AssertNoTilesRequired(pending_layer_->LowResTiling());
}
TEST_F(PictureLayerImplTest, HighResRequiredWhenActiveHasDifferentBounds) {
- gfx::Size layer_bounds(200, 200);
- gfx::Size tile_size(100, 100);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
gfx::Size pending_layer_bounds(400, 400);
- pending_layer_->SetBounds(pending_layer_bounds);
+ gfx::Size active_layer_bounds(200, 200);
+ gfx::Size tile_size(100, 100);
- CreateHighLowResAndSetAllTilesVisible();
- // TODO(vmpstr): This is confusing. Rework the test to create different bounds
- // on different trees instead of fudging tilings.
- pending_layer_->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, gfx::Rect(pending_layer_bounds), 1.f, 1.f, Occlusion());
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, pending_layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, active_layer_bounds);
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
- active_layer_->SetAllTilesReady();
+ SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
// Since the active layer has different bounds, the pending layer needs all
// high res tiles in order to activate.
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
- pending_layer_->LowResTiling()->UpdateAllTilePrioritiesForTesting();
+ pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+ pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
+ active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+ active_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
AssertAllTilesRequired(pending_layer_->HighResTiling());
- AssertNoTilesRequired(pending_layer_->LowResTiling());
+ AssertAllTilesRequired(active_layer_->HighResTiling());
+ AssertNoTilesRequired(active_layer_->LowResTiling());
+ // Since the test doesn't invalidate the resized region, we expect that the
+ // same low res tile would exist (which means we don't create a new one of the
+ // pending tree).
+ EXPECT_TRUE(pending_layer_->LowResTiling()->AllTilesForTesting().empty());
}
TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
@@ -2051,7 +2251,8 @@ TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
LayerTreeImpl* pending_tree = host_impl_.pending_tree();
scoped_ptr<FakePictureLayerImpl> pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pending_pile);
+ FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_,
+ pending_pile);
pending_layer->SetDrawsContent(true);
pending_tree->SetRootLayer(pending_layer.Pass());
@@ -2064,7 +2265,6 @@ TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
// to sync from the active layer.
float raster_page_scale = 10.f * pending_layer_->raster_page_scale();
pending_layer_->set_raster_page_scale(raster_page_scale);
- EXPECT_TRUE(pending_layer_->needs_post_commit_initialization());
host_impl_.ActivateSyncTree();
@@ -2073,13 +2273,18 @@ TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
EXPECT_EQ(0u, active_layer_->num_tilings());
EXPECT_EQ(raster_page_scale, active_layer_->raster_page_scale());
- EXPECT_FALSE(active_layer_->needs_post_commit_initialization());
}
TEST_F(PictureLayerImplTest, ShareTilesOnNextFrame) {
- SetupDefaultTrees(gfx::Size(1500, 1500));
+ gfx::Size layer_bounds(1500, 1500);
+ gfx::Size tile_size(100, 100);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupPendingTree(pending_pile);
- PictureLayerTiling* tiling = pending_layer_->AddTiling(1.f);
+ PictureLayerTiling* tiling = pending_layer_->HighResTiling();
gfx::Rect first_invalidate = tiling->TilingDataForTesting().TileBounds(0, 0);
first_invalidate.Inset(tiling->TilingDataForTesting().border_texels(),
tiling->TilingDataForTesting().border_texels());
@@ -2087,321 +2292,284 @@ TEST_F(PictureLayerImplTest, ShareTilesOnNextFrame) {
second_invalidate.Inset(tiling->TilingDataForTesting().border_texels(),
tiling->TilingDataForTesting().border_texels());
+ ActivateTree();
+
// Make a pending tree with an invalidated raster tile 0,0.
- tiling->CreateAllTilesForTesting();
- pending_layer_->set_invalidation(first_invalidate);
+ SetupPendingTreeWithInvalidation(pending_pile, first_invalidate);
// Activate and make a pending tree with an invalidated raster tile 1,1.
ActivateTree();
- host_impl_.CreatePendingTree();
- pending_layer_ = static_cast<FakePictureLayerImpl*>(
- host_impl_.pending_tree()->root_layer());
- pending_layer_->set_invalidation(second_invalidate);
+ SetupPendingTreeWithInvalidation(pending_pile, second_invalidate);
PictureLayerTiling* pending_tiling = pending_layer_->tilings()->tiling_at(0);
PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(0);
- pending_tiling->CreateAllTilesForTesting();
+ // pending_tiling->CreateAllTilesForTesting();
- // Tile 0,0 should be shared, but tile 1,1 should not be.
- EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
- EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
- EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
+ // Tile 0,0 not exist on pending, but tile 1,1 should.
+ EXPECT_TRUE(active_tiling->TileAt(0, 0));
+ EXPECT_TRUE(active_tiling->TileAt(1, 0));
+ EXPECT_TRUE(active_tiling->TileAt(0, 1));
+ EXPECT_FALSE(pending_tiling->TileAt(0, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(1, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(0, 1));
EXPECT_NE(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
- EXPECT_TRUE(pending_tiling->TileAt(0, 0)->is_shared());
- EXPECT_TRUE(pending_tiling->TileAt(1, 0)->is_shared());
- EXPECT_TRUE(pending_tiling->TileAt(0, 1)->is_shared());
- EXPECT_FALSE(pending_tiling->TileAt(1, 1)->is_shared());
-
- // Drop the tiles on the active tree and recreate them. The same tiles
- // should be shared or not.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(), 1.f, 1.0, Occlusion());
+ EXPECT_TRUE(active_tiling->TileAt(1, 1));
+ EXPECT_TRUE(pending_tiling->TileAt(1, 1));
+
+ // Drop the tiles on the active tree and recreate them.
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(), 1.f, 1.0, Occlusion());
EXPECT_TRUE(active_tiling->AllTilesForTesting().empty());
active_tiling->CreateAllTilesForTesting();
- // Tile 0,0 should be shared, but tile 1,1 should not be.
- EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
- EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
- EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
+ // Tile 0,0 not exist on pending, but tile 1,1 should.
+ EXPECT_TRUE(active_tiling->TileAt(0, 0));
+ EXPECT_TRUE(active_tiling->TileAt(1, 0));
+ EXPECT_TRUE(active_tiling->TileAt(0, 1));
+ EXPECT_FALSE(pending_tiling->TileAt(0, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(1, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(0, 1));
EXPECT_NE(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
- EXPECT_TRUE(pending_tiling->TileAt(0, 0)->is_shared());
- EXPECT_TRUE(pending_tiling->TileAt(1, 0)->is_shared());
- EXPECT_TRUE(pending_tiling->TileAt(0, 1)->is_shared());
- EXPECT_FALSE(pending_tiling->TileAt(1, 1)->is_shared());
+ EXPECT_TRUE(active_tiling->TileAt(1, 1));
+ EXPECT_TRUE(pending_tiling->TileAt(1, 1));
}
-TEST_F(PictureLayerImplTest, ShareTilesOnSync) {
+TEST_F(PictureLayerImplTest, PendingHasNoTilesWithNoInvalidation) {
SetupDefaultTrees(gfx::Size(1500, 1500));
- AddDefaultTilingsWithInvalidation(gfx::Rect());
- host_impl_.ActivateSyncTree();
- host_impl_.CreatePendingTree();
- active_layer_ = static_cast<FakePictureLayerImpl*>(
- host_impl_.active_tree()->LayerById(id_));
-
- // Force the active tree to sync to the pending tree "post-commit".
- pending_layer_->DoPostCommitInitializationIfNeeded();
+ EXPECT_GE(active_layer_->num_tilings(), 1u);
+ EXPECT_GE(pending_layer_->num_tilings(), 1u);
- // Both invalidations should drop tiles from the pending tree.
- EXPECT_EQ(3u, active_layer_->num_tilings());
- EXPECT_EQ(3u, pending_layer_->num_tilings());
- for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
- PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
- PictureLayerTiling* pending_tiling =
- pending_layer_->tilings()->tiling_at(i);
-
- ASSERT_TRUE(active_tiling);
- ASSERT_TRUE(pending_tiling);
-
- EXPECT_TRUE(active_tiling->TileAt(0, 0));
- EXPECT_TRUE(active_tiling->TileAt(1, 0));
- EXPECT_TRUE(active_tiling->TileAt(0, 1));
- EXPECT_TRUE(active_tiling->TileAt(1, 1));
-
- EXPECT_TRUE(pending_tiling->TileAt(0, 0));
- EXPECT_TRUE(pending_tiling->TileAt(1, 0));
- EXPECT_TRUE(pending_tiling->TileAt(0, 1));
- EXPECT_TRUE(pending_tiling->TileAt(1, 1));
-
- EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
- EXPECT_TRUE(active_tiling->TileAt(0, 0)->is_shared());
- EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
- EXPECT_TRUE(active_tiling->TileAt(1, 0)->is_shared());
- EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
- EXPECT_TRUE(active_tiling->TileAt(0, 1)->is_shared());
- EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
- EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
- }
+ // No invalidation.
+ PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(0);
+ PictureLayerTiling* pending_tiling = pending_layer_->tilings()->tiling_at(0);
+ ASSERT_TRUE(active_tiling);
+ ASSERT_TRUE(pending_tiling);
+
+ EXPECT_TRUE(active_tiling->TileAt(0, 0));
+ EXPECT_TRUE(active_tiling->TileAt(1, 0));
+ EXPECT_TRUE(active_tiling->TileAt(0, 1));
+ EXPECT_TRUE(active_tiling->TileAt(1, 1));
+
+ EXPECT_FALSE(pending_tiling->TileAt(0, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(1, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(0, 1));
+ EXPECT_FALSE(pending_tiling->TileAt(1, 1));
}
-TEST_F(PictureLayerImplTest, ShareInvalidActiveTreeTilesOnSync) {
- SetupDefaultTrees(gfx::Size(1500, 1500));
- AddDefaultTilingsWithInvalidation(gfx::Rect(0, 0, 1, 1));
+TEST_F(PictureLayerImplTest, ShareInvalidActiveTreeTiles) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1500, 1500);
- // This activates the 0,0,1,1 invalidation.
- host_impl_.ActivateSyncTree();
- host_impl_.CreatePendingTree();
- active_layer_ = static_cast<FakePictureLayerImpl*>(
- host_impl_.active_tree()->LayerById(id_));
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ SetupTreesWithInvalidation(pending_pile, active_pile, gfx::Rect(1, 1));
+ // Activate the invalidation.
+ ActivateTree();
+ // Make another pending tree without any invalidation in it.
+ scoped_refptr<FakePicturePileImpl> pending_pile2 =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ SetupPendingTree(pending_pile2);
- // Force the active tree to sync to the pending tree "post-commit".
- pending_layer_->DoPostCommitInitializationIfNeeded();
+ EXPECT_GE(active_layer_->num_tilings(), 1u);
+ EXPECT_GE(pending_layer_->num_tilings(), 1u);
- // The active tree invalidation was handled by the active tiles, so they
- // can be shared with the pending tree.
- EXPECT_EQ(3u, active_layer_->num_tilings());
- EXPECT_EQ(3u, pending_layer_->num_tilings());
- for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
- PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
- PictureLayerTiling* pending_tiling =
- pending_layer_->tilings()->tiling_at(i);
-
- ASSERT_TRUE(active_tiling);
- ASSERT_TRUE(pending_tiling);
-
- EXPECT_TRUE(active_tiling->TileAt(0, 0));
- EXPECT_TRUE(active_tiling->TileAt(1, 0));
- EXPECT_TRUE(active_tiling->TileAt(0, 1));
- EXPECT_TRUE(active_tiling->TileAt(1, 1));
-
- EXPECT_TRUE(pending_tiling->TileAt(0, 0));
- EXPECT_TRUE(pending_tiling->TileAt(1, 0));
- EXPECT_TRUE(pending_tiling->TileAt(0, 1));
- EXPECT_TRUE(pending_tiling->TileAt(1, 1));
-
- EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
- EXPECT_TRUE(active_tiling->TileAt(0, 0)->is_shared());
- EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
- EXPECT_TRUE(active_tiling->TileAt(1, 0)->is_shared());
- EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
- EXPECT_TRUE(active_tiling->TileAt(0, 1)->is_shared());
- EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
- EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
- }
+ // The active tree invalidation was handled by the active tiles.
+ PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(0);
+ PictureLayerTiling* pending_tiling = pending_layer_->tilings()->tiling_at(0);
+ ASSERT_TRUE(active_tiling);
+ ASSERT_TRUE(pending_tiling);
+
+ EXPECT_TRUE(active_tiling->TileAt(0, 0));
+ EXPECT_TRUE(active_tiling->TileAt(1, 0));
+ EXPECT_TRUE(active_tiling->TileAt(0, 1));
+ EXPECT_TRUE(active_tiling->TileAt(1, 1));
+
+ EXPECT_FALSE(pending_tiling->TileAt(0, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(1, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(0, 1));
+ EXPECT_FALSE(pending_tiling->TileAt(1, 1));
}
-TEST_F(PictureLayerImplTest, RemoveInvalidPendingTreeTilesOnSync) {
- SetupDefaultTrees(gfx::Size(1500, 1500));
- AddDefaultTilingsWithInvalidation(gfx::Rect());
-
- host_impl_.ActivateSyncTree();
- host_impl_.CreatePendingTree();
- active_layer_ = static_cast<FakePictureLayerImpl*>(
- host_impl_.active_tree()->LayerById(id_));
+TEST_F(PictureLayerImplTest, RecreateInvalidPendingTreeTiles) {
+ // Set some invalidation on the pending tree. We should replace raster tiles
+ // that touch this.
+ SetupDefaultTreesWithInvalidation(gfx::Size(1500, 1500), gfx::Rect(1, 1));
- // Set some invalidation on the pending tree "during commit". We should
- // replace raster tiles that touch this.
- pending_layer_->set_invalidation(gfx::Rect(1, 1));
+ EXPECT_GE(active_layer_->num_tilings(), 1u);
+ EXPECT_GE(pending_layer_->num_tilings(), 1u);
- // Force the active tree to sync to the pending tree "post-commit".
- pending_layer_->DoPostCommitInitializationIfNeeded();
+ // The pending tree invalidation creates tiles on the pending tree.
+ PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(0);
+ PictureLayerTiling* pending_tiling = pending_layer_->tilings()->tiling_at(0);
+ ASSERT_TRUE(active_tiling);
+ ASSERT_TRUE(pending_tiling);
- // The pending tree invalidation means tiles can not be shared with the
- // active tree.
- EXPECT_EQ(3u, active_layer_->num_tilings());
- EXPECT_EQ(3u, pending_layer_->num_tilings());
- for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
- PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
- PictureLayerTiling* pending_tiling =
- pending_layer_->tilings()->tiling_at(i);
-
- ASSERT_TRUE(active_tiling);
- ASSERT_TRUE(pending_tiling);
-
- EXPECT_TRUE(active_tiling->TileAt(0, 0));
- EXPECT_TRUE(active_tiling->TileAt(1, 0));
- EXPECT_TRUE(active_tiling->TileAt(0, 1));
- EXPECT_TRUE(active_tiling->TileAt(1, 1));
-
- EXPECT_TRUE(pending_tiling->TileAt(0, 0));
- EXPECT_TRUE(pending_tiling->TileAt(1, 0));
- EXPECT_TRUE(pending_tiling->TileAt(0, 1));
- EXPECT_TRUE(pending_tiling->TileAt(1, 1));
-
- EXPECT_NE(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
- EXPECT_FALSE(active_tiling->TileAt(0, 0)->is_shared());
- EXPECT_FALSE(pending_tiling->TileAt(0, 0)->is_shared());
- EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
- EXPECT_TRUE(active_tiling->TileAt(1, 0)->is_shared());
- EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
- EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
- EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
- EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
- }
-}
+ EXPECT_TRUE(active_tiling->TileAt(0, 0));
+ EXPECT_TRUE(active_tiling->TileAt(1, 0));
+ EXPECT_TRUE(active_tiling->TileAt(0, 1));
+ EXPECT_TRUE(active_tiling->TileAt(1, 1));
-TEST_F(PictureLayerImplTest, SyncTilingAfterReleaseResource) {
- SetupDefaultTrees(gfx::Size(10, 10));
- host_impl_.active_tree()->UpdateDrawProperties();
- EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
+ EXPECT_TRUE(pending_tiling->TileAt(0, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(1, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(0, 1));
+ EXPECT_FALSE(pending_tiling->TileAt(1, 1));
- // Contrived unit test of a real crash. A layer is transparent during a
- // context loss, and later becomes opaque, causing active layer SyncTiling to
- // be called.
- float new_scale = 1.f;
- active_layer_->ReleaseResources();
- pending_layer_->ReleaseResources();
- EXPECT_FALSE(active_layer_->tilings()->TilingAtScale(new_scale));
- pending_layer_->AddTiling(new_scale);
- EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(new_scale));
-
- // UpdateDrawProperties early-outs if the tree doesn't need it. It is also
- // responsible for calling ManageTilings. These checks verify that
- // ReleaseResources has set needs update draw properties so that the
- // new tiling gets the appropriate resolution set in ManageTilings.
- EXPECT_TRUE(host_impl_.active_tree()->needs_update_draw_properties());
- host_impl_.active_tree()->UpdateDrawProperties();
- PictureLayerTiling* high_res =
- active_layer_->tilings()->TilingAtScale(new_scale);
- ASSERT_TRUE(!!high_res);
- EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
+ EXPECT_NE(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
}
TEST_F(PictureLayerImplTest, SyncTilingAfterGpuRasterizationToggles) {
- SetupDefaultTrees(gfx::Size(10, 10));
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(10, 10);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
- const float kScale = 1.f;
- pending_layer_->AddTiling(kScale);
- EXPECT_TRUE(pending_layer_->tilings()->TilingAtScale(kScale));
- EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(kScale));
+ EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.f));
+ EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(1.f));
// Gpu rasterization is disabled by default.
EXPECT_FALSE(host_impl_.use_gpu_rasterization());
// Toggling the gpu rasterization clears all tilings on both trees.
- host_impl_.SetUseGpuRasterization(true);
+ host_impl_.SetHasGpuRasterizationTrigger(true);
+ host_impl_.SetContentIsSuitableForGpuRasterization(true);
+ host_impl_.UpdateTreeResourcesForGpuRasterizationIfNeeded();
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
// Make sure that we can still add tiling to the pending layer,
// that gets synced to the active layer.
- pending_layer_->AddTiling(kScale);
- EXPECT_TRUE(pending_layer_->tilings()->TilingAtScale(kScale));
- EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(kScale));
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+ EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.f));
+
+ ActivateTree();
+ EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(1.f));
+
+ SetupPendingTree(pending_pile);
+ EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.f));
// Toggling the gpu rasterization clears all tilings on both trees.
EXPECT_TRUE(host_impl_.use_gpu_rasterization());
- host_impl_.SetUseGpuRasterization(false);
+ host_impl_.SetHasGpuRasterizationTrigger(false);
+ host_impl_.UpdateTreeResourcesForGpuRasterizationIfNeeded();
+ EXPECT_EQ(GpuRasterizationStatus::OFF_VIEWPORT,
+ host_impl_.gpu_rasterization_status());
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+
+ host_impl_.SetHasGpuRasterizationTrigger(true);
+ host_impl_.SetContentIsSuitableForGpuRasterization(false);
+ EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+ host_impl_.gpu_rasterization_status());
}
TEST_F(PictureLayerImplTest, HighResCreatedWhenBoundsShrink) {
gfx::Size tile_size(100, 100);
- scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(10, 10));
- SetupPendingTree(active_pile);
- ActivateTree();
- host_impl_.active_tree()->UpdateDrawProperties();
- EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
+ // Put 0.5 as high res.
+ host_impl_.SetDeviceScaleFactor(0.5f);
- SetupDrawPropertiesAndUpdateTiles(
- active_layer_, 0.5f, 0.5f, 0.5f, 0.5f, false);
- active_layer_->tilings()->RemoveAllTilings();
- PictureLayerTiling* tiling = active_layer_->AddTiling(0.5f);
- active_layer_->AddTiling(1.5f);
- active_layer_->AddTiling(0.25f);
- tiling->set_resolution(HIGH_RESOLUTION);
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(10, 10));
+ SetupPendingTree(pending_pile);
// Sanity checks.
- ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
- ASSERT_EQ(tiling, active_layer_->tilings()->TilingAtScale(0.5f));
+ EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+ EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(0.5f));
- // Now, set the bounds to be 1x1 (so that minimum contents scale becomes
- // 1.0f). Note that we should also ensure that the pending layer needs post
- // commit initialization, since this is what would happen during commit. In
- // other words we want the pending layer to sync from the active layer.
- scoped_refptr<FakePicturePileImpl> pending_pile =
+ ActivateTree();
+
+ // Now, set the bounds to be 1x1, so that minimum contents scale becomes 1.
+ pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1, 1));
SetupPendingTree(pending_pile);
- // Update the draw properties: sync from active tree should happen here.
- host_impl_.pending_tree()->UpdateDrawProperties();
- EXPECT_FALSE(pending_layer_->needs_post_commit_initialization());
-
// Another sanity check.
- ASSERT_EQ(1.f, pending_layer_->MinimumContentsScale());
+ EXPECT_EQ(1.f, pending_layer_->MinimumContentsScale());
- // Now we should've synced 1.5f tiling, since that's the only one that doesn't
- // violate minimum contents scale. At the same time, we should've created a
- // new high res tiling at scale 1.0f.
- EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
- ASSERT_TRUE(pending_layer_->tilings()->TilingAtScale(1.0f));
- EXPECT_EQ(HIGH_RESOLUTION,
- pending_layer_->tilings()->TilingAtScale(1.0f)->resolution());
- ASSERT_TRUE(pending_layer_->tilings()->TilingAtScale(1.5f));
- EXPECT_EQ(NON_IDEAL_RESOLUTION,
- pending_layer_->tilings()->TilingAtScale(1.5f)->resolution());
+ // Since the MinContentsScale is 1, the 0.5 tiling should be replaced by a 1.0
+ // tiling.
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 0.5f, 1.f, 1.f, 1.f, 0.f,
+ false);
+
+ EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+ PictureLayerTiling* tiling =
+ pending_layer_->tilings()->FindTilingWithScale(1.0f);
+ ASSERT_TRUE(tiling);
+ EXPECT_EQ(HIGH_RESOLUTION, tiling->resolution());
}
-TEST_F(PictureLayerImplTest, NoLowResTilingWithGpuRasterization) {
+TEST_F(PictureLayerImplTest, LowResTilingWithoutGpuRasterization) {
gfx::Size default_tile_size(host_impl_.settings().default_tile_size);
gfx::Size layer_bounds(default_tile_size.width() * 4,
default_tile_size.height() * 4);
+ host_impl_.SetHasGpuRasterizationTrigger(false);
+
SetupDefaultTrees(layer_bounds);
EXPECT_FALSE(host_impl_.use_gpu_rasterization());
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
// Should have a low-res and a high-res tiling.
- ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+ EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
+}
- ResetTilingsAndRasterScales();
+TEST_F(PictureLayerImplTest, NoLowResTilingWithGpuRasterization) {
+ gfx::Size default_tile_size(host_impl_.settings().default_tile_size);
+ gfx::Size layer_bounds(default_tile_size.width() * 4,
+ default_tile_size.height() * 4);
+
+ host_impl_.SetHasGpuRasterizationTrigger(true);
+ host_impl_.SetContentIsSuitableForGpuRasterization(true);
+
+ SetupDefaultTrees(layer_bounds);
+ EXPECT_TRUE(host_impl_.use_gpu_rasterization());
+ // Should only have the high-res tiling.
+ EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+}
+
+TEST_F(PictureLayerImplTest, RequiredTilesWithGpuRasterization) {
+ host_impl_.SetHasGpuRasterizationTrigger(true);
+ host_impl_.SetContentIsSuitableForGpuRasterization(true);
+
+ gfx::Size viewport_size(1000, 1000);
+ host_impl_.SetViewportSize(viewport_size);
- host_impl_.SetUseGpuRasterization(true);
+ gfx::Size layer_bounds(4000, 4000);
+ SetupDefaultTrees(layer_bounds);
EXPECT_TRUE(host_impl_.use_gpu_rasterization());
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
// Should only have the high-res tiling.
- ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
+ EXPECT_EQ(1u, active_layer_->tilings()->num_tilings());
+
+ active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
+
+ // High res tiling should have 36 tiles (3X12 tile grid).
+ EXPECT_EQ(36u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+
+ // Visible viewport should be covered by 4 tiles. No other
+ // tiles should be required for activation.
+ EXPECT_EQ(4u, NumberOfTilesRequired(active_layer_->HighResTiling()));
}
TEST_F(PictureLayerImplTest, NoTilingIfDoesNotDrawContent) {
// Set up layers with tilings.
SetupDefaultTrees(gfx::Size(10, 10));
- SetContentsScaleOnBothLayers(1.f, 1.f, 1.f, 1.f, false);
+ SetContentsScaleOnBothLayers(1.f, 1.f, 1.f, 1.f, 0.f, false);
pending_layer_->PushPropertiesTo(active_layer_);
EXPECT_TRUE(pending_layer_->DrawsContent());
EXPECT_TRUE(pending_layer_->CanHaveTilings());
@@ -2420,33 +2588,41 @@ TEST_F(PictureLayerImplTest, NoTilingIfDoesNotDrawContent) {
TEST_F(PictureLayerImplTest, FirstTilingDuringPinch) {
SetupDefaultTrees(gfx::Size(10, 10));
+
+ // We start with a tiling at scale 1.
+ EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
+
+ // When we scale up by 2.3, we get a new tiling that is a power of 2, in this
+ // case 4.
host_impl_.PinchGestureBegin();
float high_res_scale = 2.3f;
- SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, 1.f, false);
-
- ASSERT_GE(pending_layer_->num_tilings(), 0u);
- EXPECT_FLOAT_EQ(high_res_scale,
- pending_layer_->HighResTiling()->contents_scale());
+ SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, 1.f, 0.f, false);
+ EXPECT_EQ(4.f, pending_layer_->HighResTiling()->contents_scale());
}
-TEST_F(PictureLayerImplTest, FirstTilingTooSmall) {
+TEST_F(PictureLayerImplTest, PinchingTooSmall) {
SetupDefaultTrees(gfx::Size(10, 10));
+
+ // We start with a tiling at scale 1.
+ EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
+
host_impl_.PinchGestureBegin();
float high_res_scale = 0.0001f;
- EXPECT_GT(pending_layer_->MinimumContentsScale(), high_res_scale);
+ EXPECT_LT(high_res_scale, pending_layer_->MinimumContentsScale());
- SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, 1.f, false);
-
- ASSERT_GE(pending_layer_->num_tilings(), 0u);
+ SetContentsScaleOnBothLayers(high_res_scale, 1.f, high_res_scale, 1.f, 0.f,
+ false);
EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
pending_layer_->HighResTiling()->contents_scale());
}
-TEST_F(PictureLayerImplTest, PinchingTooSmall) {
+TEST_F(PictureLayerImplTest, PinchingTooSmallWithContentsScale) {
SetupDefaultTrees(gfx::Size(10, 10));
+ ResetTilingsAndRasterScales();
+
float contents_scale = 0.15f;
- SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, 1.f, false);
+ SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, 1.f, 0.f, false);
ASSERT_GE(pending_layer_->num_tilings(), 0u);
EXPECT_FLOAT_EQ(contents_scale,
@@ -2458,75 +2634,85 @@ TEST_F(PictureLayerImplTest, PinchingTooSmall) {
EXPECT_LT(page_scale * contents_scale,
pending_layer_->MinimumContentsScale());
- SetContentsScaleOnBothLayers(contents_scale, 1.f, page_scale, 1.f, false);
+ SetContentsScaleOnBothLayers(contents_scale * page_scale, 1.f, page_scale,
+ 1.f, 0.f, false);
ASSERT_GE(pending_layer_->num_tilings(), 0u);
EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
pending_layer_->HighResTiling()->contents_scale());
}
-class DeferredInitPictureLayerImplTest : public PictureLayerImplTest {
- public:
- void InitializeRenderer() override {
- bool delegated_rendering = false;
- host_impl_.InitializeRenderer(FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice),
- delegated_rendering));
- }
+TEST_F(PictureLayerImplTest, ConsiderAnimationStartScaleForRasterScale) {
+ gfx::Size viewport_size(1000, 1000);
+ host_impl_.SetViewportSize(viewport_size);
- virtual void SetUp() override {
- PictureLayerImplTest::SetUp();
+ gfx::Size layer_bounds(100, 100);
+ SetupDefaultTrees(layer_bounds);
- // Create some default active and pending trees.
- gfx::Size tile_size(100, 100);
- gfx::Size layer_bounds(400, 400);
+ float contents_scale = 2.f;
+ float device_scale = 1.f;
+ float page_scale = 1.f;
+ float maximum_animation_scale = 3.f;
+ float starting_animation_scale = 1.f;
+ bool animating_transform = true;
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
- SetupTrees(pending_pile, active_pile);
- }
-};
+ // Maximum animation scale is greater than starting animation scale
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
+ maximum_animation_scale,
+ starting_animation_scale, animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
-// This test is really a LayerTreeHostImpl test, in that it makes sure
-// that trees need update draw properties after deferred initialization.
-// However, this is also a regression test for PictureLayerImpl in that
-// not having this update will cause a crash.
-TEST_F(DeferredInitPictureLayerImplTest, PreventUpdateTilesDuringLostContext) {
- host_impl_.pending_tree()->UpdateDrawProperties();
- host_impl_.active_tree()->UpdateDrawProperties();
- EXPECT_FALSE(host_impl_.pending_tree()->needs_update_draw_properties());
- EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
-
- FakeOutputSurface* fake_output_surface =
- static_cast<FakeOutputSurface*>(host_impl_.output_surface());
- ASSERT_TRUE(fake_output_surface->InitializeAndSetContext3d(
- TestContextProvider::Create()));
-
- // These will crash PictureLayerImpl if this is not true.
- ASSERT_TRUE(host_impl_.pending_tree()->needs_update_draw_properties());
- ASSERT_TRUE(host_impl_.active_tree()->needs_update_draw_properties());
- host_impl_.active_tree()->UpdateDrawProperties();
+ animating_transform = false;
+
+ // Once we stop animating, a new high-res tiling should be created.
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
+ maximum_animation_scale,
+ starting_animation_scale, animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+ // Starting animation scale greater than maximum animation scale
+ // Bounds at starting scale within the viewport
+ animating_transform = true;
+ starting_animation_scale = 5.f;
+
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
+ maximum_animation_scale,
+ starting_animation_scale, animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 5.f);
+
+ // Once we stop animating, a new high-res tiling should be created.
+ animating_transform = false;
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
+ maximum_animation_scale,
+ starting_animation_scale, animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+ // Starting Animation scale greater than maximum animation scale
+ // Bounds at starting scale outisde the viewport
+ animating_transform = true;
+ starting_animation_scale = 11.f;
+
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
+ maximum_animation_scale,
+ starting_animation_scale, animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
}
TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
- gfx::Size layer_bounds(100, 100);
gfx::Size viewport_size(1000, 1000);
- SetupDefaultTrees(layer_bounds);
host_impl_.SetViewportSize(viewport_size);
+ gfx::Size layer_bounds(100, 100);
+ SetupDefaultTrees(layer_bounds);
+
float contents_scale = 1.f;
- float device_scale = 1.3f;
- float page_scale = 1.4f;
+ float device_scale = 1.f;
+ float page_scale = 1.f;
float maximum_animation_scale = 1.f;
+ float starting_animation_scale = 0.f;
bool animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
- maximum_animation_scale,
- animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
// Since we're CPU-rasterizing, starting an animation should cause tiling
@@ -2535,11 +2721,9 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
maximum_animation_scale = 3.f;
contents_scale = 2.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
// Further changes to scale during the animation should not cause a new
@@ -2547,21 +2731,17 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
contents_scale = 4.f;
maximum_animation_scale = 5.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
// Once we stop animating, a new high-res tiling should be created.
animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
// When animating with an unknown maximum animation scale factor, a new
@@ -2570,33 +2750,27 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
contents_scale = 2.f;
maximum_animation_scale = 0.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), page_scale * device_scale);
// Further changes to scale during the animation should not cause a new
// high-res tiling to get created.
contents_scale = 3.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), page_scale * device_scale);
// Once we stop animating, a new high-res tiling should be created.
animating_transform = false;
contents_scale = 4.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
// When animating with a maxmium animation scale factor that is so large
@@ -2607,22 +2781,18 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
contents_scale = 2.f;
maximum_animation_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), page_scale * device_scale);
// Once we stop animating, a new high-res tiling should be created.
animating_transform = false;
contents_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 11.f);
// When animating with a maxmium animation scale factor that is so large
@@ -2633,22 +2803,18 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
contents_scale = 0.1f;
maximum_animation_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), device_scale * page_scale);
// Once we stop animating, a new high-res tiling should be created.
animating_transform = false;
contents_scale = 12.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 12.f);
// When animating toward a smaller scale, but that is still so large that the
@@ -2658,22 +2824,18 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
contents_scale = 11.f;
maximum_animation_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), device_scale * page_scale);
// Once we stop animating, a new high-res tiling should be created.
animating_transform = false;
contents_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 11.f);
}
@@ -2682,19 +2844,20 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForGpuRasterization) {
gfx::Size viewport_size(1000, 1000);
SetupDefaultTrees(layer_bounds);
host_impl_.SetViewportSize(viewport_size);
- host_impl_.SetUseGpuRasterization(true);
+ host_impl_.SetHasGpuRasterizationTrigger(true);
+ host_impl_.SetContentIsSuitableForGpuRasterization(true);
+ host_impl_.UpdateTreeResourcesForGpuRasterizationIfNeeded();
float contents_scale = 1.f;
float device_scale = 1.3f;
float page_scale = 1.4f;
float maximum_animation_scale = 1.f;
+ float starting_animation_scale = 0.f;
bool animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
// Since we're GPU-rasterizing, starting an animation should cause tiling
@@ -2703,137 +2866,143 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForGpuRasterization) {
contents_scale = 2.f;
maximum_animation_scale = 4.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
// Further changes to scale during the animation should cause a new high-res
// tiling to get created.
contents_scale = 3.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
// Since we're re-rasterizing during the animation, scales smaller than 1
// should be respected.
contents_scale = 0.25f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 0.25f);
// Once we stop animating, a new high-res tiling should be created.
contents_scale = 4.f;
animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
}
-TEST_F(PictureLayerImplTest, LayerRasterTileIterator) {
+TEST_F(PictureLayerImplTest, TilingSetRasterQueue) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- gfx::Size tile_size(100, 100);
+ host_impl_.SetViewportSize(gfx::Size(500, 500));
+
+ gfx::Size recording_tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ FakePicturePileImpl::CreateFilledPile(recording_tile_size, layer_bounds);
SetupPendingTree(pending_pile);
-
- ASSERT_TRUE(pending_layer_->CanHaveTilings());
-
- float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
-
- // Empty iterator
- PictureLayerImpl::LayerRasterTileIterator it;
- EXPECT_FALSE(it);
-
- // No tilings.
- it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
- EXPECT_FALSE(it);
-
- pending_layer_->AddTiling(low_res_factor);
- pending_layer_->AddTiling(0.3f);
- pending_layer_->AddTiling(0.7f);
- PictureLayerTiling* high_res_tiling = pending_layer_->AddTiling(1.0f);
- pending_layer_->AddTiling(2.0f);
-
- host_impl_.SetViewportSize(gfx::Size(500, 500));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ EXPECT_EQ(2u, pending_layer_->num_tilings());
std::set<Tile*> unique_tiles;
bool reached_prepaint = false;
- size_t non_ideal_tile_count = 0u;
- size_t low_res_tile_count = 0u;
- size_t high_res_tile_count = 0u;
- for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
- it;
- ++it) {
- Tile* tile = *it;
- TilePriority priority = tile->priority(PENDING_TREE);
-
- EXPECT_TRUE(tile);
+ int non_ideal_tile_count = 0u;
+ int low_res_tile_count = 0u;
+ int high_res_tile_count = 0u;
+ int high_res_now_tiles = 0u;
+ scoped_ptr<TilingSetRasterQueueAll> queue(new TilingSetRasterQueueAll(
+ pending_layer_->picture_layer_tiling_set(), false));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ TilePriority priority = prioritized_tile.priority();
+
+ EXPECT_TRUE(prioritized_tile.tile());
// Non-high res tiles only get visible tiles. Also, prepaint should only
// come at the end of the iteration.
- if (priority.resolution != HIGH_RESOLUTION)
+ if (priority.resolution != HIGH_RESOLUTION) {
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
- else if (reached_prepaint)
+ } else if (reached_prepaint) {
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- else
+ } else {
reached_prepaint = priority.priority_bin != TilePriority::NOW;
+ if (!reached_prepaint)
+ ++high_res_now_tiles;
+ }
non_ideal_tile_count += priority.resolution == NON_IDEAL_RESOLUTION;
low_res_tile_count += priority.resolution == LOW_RESOLUTION;
high_res_tile_count += priority.resolution == HIGH_RESOLUTION;
- unique_tiles.insert(tile);
+ unique_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
}
EXPECT_TRUE(reached_prepaint);
- EXPECT_EQ(0u, non_ideal_tile_count);
- EXPECT_EQ(0u, low_res_tile_count);
- EXPECT_EQ(16u, high_res_tile_count);
+ EXPECT_EQ(0, non_ideal_tile_count);
+ EXPECT_EQ(0, low_res_tile_count);
+
+ // With layer size being 1000x1000 and default tile size 256x256, we expect to
+ // see 4 now tiles out of 16 total high res tiles.
+ EXPECT_EQ(16, high_res_tile_count);
+ EXPECT_EQ(4, high_res_now_tiles);
EXPECT_EQ(low_res_tile_count + high_res_tile_count + non_ideal_tile_count,
- unique_tiles.size());
+ static_cast<int>(unique_tiles.size()));
+
+ scoped_ptr<TilingSetRasterQueueRequired> required_queue(
+ new TilingSetRasterQueueRequired(
+ pending_layer_->picture_layer_tiling_set(),
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW));
+ EXPECT_TRUE(required_queue->IsEmpty());
+
+ required_queue.reset(new TilingSetRasterQueueRequired(
+ pending_layer_->picture_layer_tiling_set(),
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
+ EXPECT_FALSE(required_queue->IsEmpty());
+ int required_for_activation_count = 0;
+ while (!required_queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = required_queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile()->required_for_activation());
+ EXPECT_FALSE(prioritized_tile.tile()->draw_info().IsReadyToDraw());
+ ++required_for_activation_count;
+ required_queue->Pop();
+ }
+
+ // All of the high res tiles should be required for activation, since there is
+ // no active twin.
+ EXPECT_EQ(high_res_now_tiles, required_for_activation_count);
// No NOW tiles.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
pending_layer_->draw_properties().visible_content_rect =
gfx::Rect(1100, 1100, 500, 500);
bool resourceless_software_draw = false;
- pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+ pending_layer_->UpdateTiles(resourceless_software_draw);
unique_tiles.clear();
high_res_tile_count = 0u;
- for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
- it;
- ++it) {
- Tile* tile = *it;
- TilePriority priority = tile->priority(PENDING_TREE);
+ queue.reset(new TilingSetRasterQueueAll(
+ pending_layer_->picture_layer_tiling_set(), false));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ TilePriority priority = prioritized_tile.priority();
- EXPECT_TRUE(tile);
+ EXPECT_TRUE(prioritized_tile.tile());
// Non-high res tiles only get visible tiles.
EXPECT_EQ(HIGH_RESOLUTION, priority.resolution);
@@ -2841,50 +3010,61 @@ TEST_F(PictureLayerImplTest, LayerRasterTileIterator) {
high_res_tile_count += priority.resolution == HIGH_RESOLUTION;
- unique_tiles.insert(tile);
+ unique_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
}
- EXPECT_EQ(16u, high_res_tile_count);
- EXPECT_EQ(high_res_tile_count, unique_tiles.size());
+ EXPECT_EQ(16, high_res_tile_count);
+ EXPECT_EQ(high_res_tile_count, static_cast<int>(unique_tiles.size()));
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
pending_layer_->draw_properties().visible_content_rect =
gfx::Rect(0, 0, 500, 500);
- pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+ pending_layer_->UpdateTiles(resourceless_software_draw);
- std::vector<Tile*> high_res_tiles = high_res_tiling->AllTilesForTesting();
+ std::vector<Tile*> high_res_tiles =
+ pending_layer_->HighResTiling()->AllTilesForTesting();
for (std::vector<Tile*>::iterator tile_it = high_res_tiles.begin();
tile_it != high_res_tiles.end();
++tile_it) {
Tile* tile = *tile_it;
- ManagedTileState::DrawInfo& draw_info = tile->draw_info();
+ TileDrawInfo& draw_info = tile->draw_info();
draw_info.SetSolidColorForTesting(SK_ColorRED);
}
non_ideal_tile_count = 0;
low_res_tile_count = 0;
high_res_tile_count = 0;
- for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, true); it;
- ++it) {
- Tile* tile = *it;
- TilePriority priority = tile->priority(PENDING_TREE);
+ queue.reset(new TilingSetRasterQueueAll(
+ pending_layer_->picture_layer_tiling_set(), true));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ TilePriority priority = prioritized_tile.priority();
- EXPECT_TRUE(tile);
+ EXPECT_TRUE(prioritized_tile.tile());
non_ideal_tile_count += priority.resolution == NON_IDEAL_RESOLUTION;
low_res_tile_count += priority.resolution == LOW_RESOLUTION;
high_res_tile_count += priority.resolution == HIGH_RESOLUTION;
+ queue->Pop();
}
- EXPECT_EQ(0u, non_ideal_tile_count);
- EXPECT_EQ(1u, low_res_tile_count);
- EXPECT_EQ(0u, high_res_tile_count);
+ EXPECT_EQ(0, non_ideal_tile_count);
+ EXPECT_EQ(1, low_res_tile_count);
+ EXPECT_EQ(0, high_res_tile_count);
}
-TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
+TEST_F(PictureLayerImplTest, TilingSetRasterQueueActiveTree) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ host_impl_.SetViewportSize(gfx::Size(500, 500));
+
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
@@ -2892,28 +3072,68 @@ TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupPendingTree(pending_pile);
+ ActivateTree();
+ EXPECT_EQ(2u, active_layer_->num_tilings());
+
+ scoped_ptr<TilingSetRasterQueueRequired> queue(
+ new TilingSetRasterQueueRequired(
+ active_layer_->picture_layer_tiling_set(),
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW));
+ EXPECT_FALSE(queue->IsEmpty());
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile()->required_for_draw());
+ EXPECT_FALSE(prioritized_tile.tile()->draw_info().IsReadyToDraw());
+ queue->Pop();
+ }
- ASSERT_TRUE(pending_layer_->CanHaveTilings());
+ queue.reset(new TilingSetRasterQueueRequired(
+ active_layer_->picture_layer_tiling_set(),
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
+ EXPECT_TRUE(queue->IsEmpty());
+}
- float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+TEST_F(PictureLayerImplTest, TilingSetRasterQueueRequiredNoHighRes) {
+ scoped_ptr<FakePicturePile> empty_recording =
+ FakePicturePile::CreateEmptyPile(gfx::Size(256, 256),
+ gfx::Size(1024, 1024));
+ empty_recording->SetIsSolidColor(true);
- std::vector<PictureLayerTiling*> tilings;
- tilings.push_back(pending_layer_->AddTiling(low_res_factor));
- tilings.push_back(pending_layer_->AddTiling(0.3f));
- tilings.push_back(pending_layer_->AddTiling(0.7f));
- tilings.push_back(pending_layer_->AddTiling(1.0f));
- tilings.push_back(pending_layer_->AddTiling(2.0f));
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFromPile(empty_recording.get(), nullptr);
+
+ SetupPendingTree(pending_pile);
+ EXPECT_FALSE(
+ pending_layer_->picture_layer_tiling_set()->FindTilingWithResolution(
+ HIGH_RESOLUTION));
+
+ scoped_ptr<TilingSetRasterQueueRequired> queue(
+ new TilingSetRasterQueueRequired(
+ pending_layer_->picture_layer_tiling_set(),
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
+ EXPECT_TRUE(queue->IsEmpty());
+}
+
+TEST_F(PictureLayerImplTest, TilingSetEvictionQueue) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1000, 1000);
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
host_impl_.SetViewportSize(gfx::Size(500, 500));
- host_impl_.pending_tree()->UpdateDrawProperties();
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ // TODO(vmpstr): Add a test with tilings other than high/low res on the active
+ // tree.
+ SetupPendingTree(pending_pile);
+ EXPECT_EQ(2u, pending_layer_->num_tilings());
std::vector<Tile*> all_tiles;
- for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
- tilings.begin();
- tiling_iterator != tilings.end();
- ++tiling_iterator) {
- std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
- std::copy(tiles.begin(), tiles.end(), std::back_inserter(all_tiles));
+ for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+ std::vector<Tile*> tiles = tiling->AllTilesForTesting();
+ all_tiles.insert(all_tiles.end(), tiles.begin(), tiles.end());
}
std::set<Tile*> all_tiles_set(all_tiles.begin(), all_tiles.end());
@@ -2921,8 +3141,8 @@ TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
bool mark_required = false;
size_t number_of_marked_tiles = 0u;
size_t number_of_unmarked_tiles = 0u;
- for (size_t i = 0; i < tilings.size(); ++i) {
- PictureLayerTiling* tiling = tilings.at(i);
+ for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
for (PictureLayerTiling::CoverageIterator iter(
tiling,
pending_layer_->contents_scale_x(),
@@ -2940,42 +3160,40 @@ TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
}
// Sanity checks.
- EXPECT_EQ(91u, all_tiles.size());
- EXPECT_EQ(91u, all_tiles_set.size());
+ EXPECT_EQ(17u, all_tiles.size());
+ EXPECT_EQ(17u, all_tiles_set.size());
EXPECT_GT(number_of_marked_tiles, 1u);
EXPECT_GT(number_of_unmarked_tiles, 1u);
- // Empty iterator.
- PictureLayerImpl::LayerEvictionTileIterator it;
- EXPECT_FALSE(it);
-
// Tiles don't have resources yet.
- it = PictureLayerImpl::LayerEvictionTileIterator(
- pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
- EXPECT_FALSE(it);
+ scoped_ptr<TilingSetEvictionQueue> queue(
+ new TilingSetEvictionQueue(pending_layer_->picture_layer_tiling_set()));
+ EXPECT_TRUE(queue->IsEmpty());
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
std::set<Tile*> unique_tiles;
- float expected_scales[] = {2.0f, 0.3f, 0.7f, low_res_factor, 1.0f};
+ float expected_scales[] = {low_res_factor, 1.f};
size_t scale_index = 0;
bool reached_visible = false;
- Tile* last_tile = nullptr;
- for (it = PictureLayerImpl::LayerEvictionTileIterator(
- pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
- it;
- ++it) {
- Tile* tile = *it;
- if (!last_tile)
- last_tile = tile;
+ PrioritizedTile last_tile;
+ size_t distance_decreasing = 0;
+ size_t distance_increasing = 0;
+ queue.reset(
+ new TilingSetEvictionQueue(pending_layer_->picture_layer_tiling_set()));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ Tile* tile = prioritized_tile.tile();
+ if (!last_tile.tile())
+ last_tile = prioritized_tile;
EXPECT_TRUE(tile);
- TilePriority priority = tile->priority(PENDING_TREE);
+ TilePriority priority = prioritized_tile.priority();
if (priority.priority_bin == TilePriority::NOW) {
reached_visible = true;
- last_tile = tile;
+ last_tile = prioritized_tile;
break;
}
@@ -2990,31 +3208,35 @@ TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
EXPECT_FLOAT_EQ(tile->contents_scale(), expected_scales[scale_index]);
unique_tiles.insert(tile);
- // If the tile is the same rough bin as last tile (same activation, bin, and
- // scale), then distance should be decreasing.
if (tile->required_for_activation() ==
- last_tile->required_for_activation() &&
- priority.priority_bin ==
- last_tile->priority(PENDING_TREE).priority_bin &&
- std::abs(tile->contents_scale() - last_tile->contents_scale()) <
+ last_tile.tile()->required_for_activation() &&
+ std::abs(tile->contents_scale() - last_tile.tile()->contents_scale()) <
std::numeric_limits<float>::epsilon()) {
- EXPECT_LE(priority.distance_to_visible,
- last_tile->priority(PENDING_TREE).distance_to_visible);
+ if (priority.distance_to_visible <=
+ last_tile.priority().distance_to_visible)
+ ++distance_decreasing;
+ else
+ ++distance_increasing;
}
- last_tile = tile;
+ last_tile = prioritized_tile;
+ queue->Pop();
}
+ // 4 high res tiles are inside the viewport, the rest are evicted.
EXPECT_TRUE(reached_visible);
- EXPECT_EQ(65u, unique_tiles.size());
+ EXPECT_EQ(12u, unique_tiles.size());
+ EXPECT_EQ(1u, distance_increasing);
+ EXPECT_EQ(11u, distance_decreasing);
scale_index = 0;
bool reached_required = false;
- for (; it; ++it) {
- Tile* tile = *it;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ Tile* tile = prioritized_tile.tile();
EXPECT_TRUE(tile);
- TilePriority priority = tile->priority(PENDING_TREE);
+ TilePriority priority = prioritized_tile.priority();
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
if (reached_required) {
@@ -3032,6 +3254,7 @@ TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
EXPECT_FLOAT_EQ(tile->contents_scale(), expected_scales[scale_index]);
unique_tiles.insert(tile);
+ queue->Pop();
}
EXPECT_TRUE(reached_required);
@@ -3044,16 +3267,12 @@ TEST_F(PictureLayerImplTest, Occlusion) {
gfx::Size viewport_size(1000, 1000);
LayerTestCommon::LayerImplTest impl;
+ host_impl_.SetViewportSize(viewport_size);
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(layer_bounds, layer_bounds);
- SetupPendingTree(pending_pile);
- pending_layer_->SetBounds(layer_bounds);
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
ActivateTree();
- active_layer_->set_fixed_tile_size(tile_size);
-
- host_impl_.SetViewportSize(viewport_size);
- host_impl_.active_tree()->UpdateDrawProperties();
std::vector<Tile*> tiles =
active_layer_->HighResTiling()->AllTilesForTesting();
@@ -3096,39 +3315,36 @@ TEST_F(PictureLayerImplTest, RasterScaleChangeWithoutAnimation) {
gfx::Size tile_size(host_impl_.settings().default_tile_size);
SetupDefaultTrees(tile_size);
+ ResetTilingsAndRasterScales();
+
float contents_scale = 2.f;
float device_scale = 1.f;
float page_scale = 1.f;
float maximum_animation_scale = 1.f;
+ float starting_animation_scale = 0.f;
bool animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
// Changing the source scale without being in an animation will cause
// the layer to reset its source scale to 1.f.
contents_scale = 3.f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
// Further changes to the source scale will no longer be reflected in the
// contents scale.
contents_scale = 0.5f;
- SetContentsScaleOnBothLayers(contents_scale,
- device_scale,
- page_scale,
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
maximum_animation_scale,
- animating_transform);
+ starting_animation_scale, animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
}
@@ -3136,104 +3352,87 @@ TEST_F(PictureLayerImplTest, LowResReadyToDrawNotEnoughToActivate) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
- // Make sure some tiles are not shared.
- pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
-
- CreateHighLowResAndSetAllTilesVisible();
- active_layer_->SetAllTilesReady();
+ // Make sure pending tree has tiles.
+ gfx::Rect invalidation(gfx::Point(50, 50), tile_size);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, invalidation);
// All pending layer tiles required are not ready.
- EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ EXPECT_FALSE(host_impl_.tile_manager()->IsReadyToActivate());
// Initialize all low-res tiles.
pending_layer_->SetAllTilesReadyInTiling(pending_layer_->LowResTiling());
+ pending_layer_->SetAllTilesReadyInTiling(active_layer_->LowResTiling());
// Low-res tiles should not be enough.
- EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ EXPECT_FALSE(host_impl_.tile_manager()->IsReadyToActivate());
// Initialize remaining tiles.
pending_layer_->SetAllTilesReady();
+ active_layer_->SetAllTilesReady();
- EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ EXPECT_TRUE(host_impl_.tile_manager()->IsReadyToActivate());
}
TEST_F(PictureLayerImplTest, HighResReadyToDrawEnoughToActivate) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
- // Make sure some tiles are not shared.
- pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
-
- CreateHighLowResAndSetAllTilesVisible();
- active_layer_->SetAllTilesReady();
+ // Make sure pending tree has tiles.
+ gfx::Rect invalidation(gfx::Point(50, 50), tile_size);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, invalidation);
// All pending layer tiles required are not ready.
- EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ EXPECT_FALSE(host_impl_.tile_manager()->IsReadyToActivate());
// Initialize all high-res tiles.
pending_layer_->SetAllTilesReadyInTiling(pending_layer_->HighResTiling());
+ active_layer_->SetAllTilesReadyInTiling(active_layer_->HighResTiling());
// High-res tiles should be enough, since they cover everything visible.
- EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ EXPECT_TRUE(host_impl_.tile_manager()->IsReadyToActivate());
}
TEST_F(PictureLayerImplTest,
- SharedActiveHighResReadyAndPendingLowResReadyNotEnoughToActivate) {
+ ActiveHighResReadyAndPendingLowResReadyNotEnoughToActivate) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
- // Make sure some tiles are not shared.
- pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
-
- CreateHighLowResAndSetAllTilesVisible();
+ // Make sure pending tree has tiles.
+ gfx::Rect invalidation(gfx::Point(50, 50), tile_size);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, invalidation);
// Initialize all high-res tiles in the active layer.
active_layer_->SetAllTilesReadyInTiling(active_layer_->HighResTiling());
// And all the low-res tiles in the pending layer.
pending_layer_->SetAllTilesReadyInTiling(pending_layer_->LowResTiling());
- // The unshared high-res tiles are not ready, so we cannot activate.
- EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ // The pending high-res tiles are not ready, so we cannot activate.
+ EXPECT_FALSE(host_impl_.tile_manager()->IsReadyToActivate());
- // When the unshared pending high-res tiles are ready, we can activate.
+ // When the pending high-res tiles are ready, we can activate.
pending_layer_->SetAllTilesReadyInTiling(pending_layer_->HighResTiling());
- EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ EXPECT_TRUE(host_impl_.tile_manager()->IsReadyToActivate());
}
-TEST_F(PictureLayerImplTest, SharedActiveHighResReadyNotEnoughToActivate) {
+TEST_F(PictureLayerImplTest, ActiveHighResReadyNotEnoughToActivate) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(1000, 1000);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
- // Make sure some tiles are not shared.
- pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
-
- CreateHighLowResAndSetAllTilesVisible();
+ // Make sure pending tree has tiles.
+ gfx::Rect invalidation(gfx::Point(50, 50), tile_size);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, invalidation);
// Initialize all high-res tiles in the active layer.
active_layer_->SetAllTilesReadyInTiling(active_layer_->HighResTiling());
- // The unshared high-res tiles are not ready, so we cannot activate.
- EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ // The pending high-res tiles are not ready, so we cannot activate.
+ EXPECT_FALSE(host_impl_.tile_manager()->IsReadyToActivate());
- // When the unshared pending high-res tiles are ready, we can activate.
+ // When the pending pending high-res tiles are ready, we can activate.
pending_layer_->SetAllTilesReadyInTiling(pending_layer_->HighResTiling());
- EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ EXPECT_TRUE(host_impl_.tile_manager()->IsReadyToActivate());
}
-class NoLowResPictureLayerImplTest : public PictureLayerImplTest {
- public:
- NoLowResPictureLayerImplTest()
- : PictureLayerImplTest(NoLowResTilingsSettings()) {}
-};
-
TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(1300, 1900);
@@ -3244,16 +3443,83 @@ TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupTrees(pending_pile, active_pile);
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
EXPECT_LT(low_res_factor, 1.f);
+ ResetTilingsAndRasterScales();
+
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ 6.f, // ideal contents scale
+ 3.f, // device scale
+ 2.f, // page scale
+ 1.f, // maximum animation scale
+ 0.f, // starting animation scale
+ false);
+ ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(6.f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+
+ // If we change the page scale factor, then we should get new tilings.
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ 6.6f, // ideal contents scale
+ 3.f, // device scale
+ 2.2f, // page scale
+ 1.f, // maximum animation scale
+ 0.f, // starting animation scale
+ false);
+ ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(6.6f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+
+ // If we change the device scale factor, then we should get new tilings.
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ 7.26f, // ideal contents scale
+ 3.3f, // device scale
+ 2.2f, // page scale
+ 1.f, // maximum animation scale
+ 0.f, // starting animation scale
+ false);
+ ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(7.26f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+
+ // If we change the device scale factor, but end up at the same total scale
+ // factor somehow, then we don't get new tilings.
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ 7.26f, // ideal contents scale
+ 2.2f, // device scale
+ 3.3f, // page scale
+ 1.f, // maximum animation scale
+ 0.f, // starting animation scale
+ false);
+ ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(7.26f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, PendingLayerOnlyHasHighResTiling) {
+ gfx::Size tile_size(400, 400);
+ gfx::Size layer_bounds(1300, 1900);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+ EXPECT_LT(low_res_factor, 1.f);
+
+ ResetTilingsAndRasterScales();
+
SetupDrawPropertiesAndUpdateTiles(pending_layer_,
6.f, // ideal contents scale
3.f, // device scale
2.f, // page scale
1.f, // maximum animation scale
+ 0.f, // starting animation scale
false);
ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(6.f,
@@ -3265,8 +3531,9 @@ TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
3.f, // device scale
2.2f, // page scale
1.f, // maximum animation scale
+ 0.f, // starting animation scale
false);
- ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+ ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(6.6f,
pending_layer_->tilings()->tiling_at(0)->contents_scale());
@@ -3276,8 +3543,9 @@ TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
3.3f, // device scale
2.2f, // page scale
1.f, // maximum animation scale
+ 0.f, // starting animation scale
false);
- ASSERT_EQ(3u, pending_layer_->tilings()->num_tilings());
+ ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(7.26f,
pending_layer_->tilings()->tiling_at(0)->contents_scale());
@@ -3288,51 +3556,53 @@ TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
2.2f, // device scale
3.3f, // page scale
1.f, // maximum animation scale
+ 0.f, // starting animation scale
false);
- ASSERT_EQ(3u, pending_layer_->tilings()->num_tilings());
+ ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(7.26f,
pending_layer_->tilings()->tiling_at(0)->contents_scale());
}
-TEST_F(NoLowResPictureLayerImplTest, AllHighResRequiredEvenIfShared) {
+TEST_F(NoLowResPictureLayerImplTest, AllHighResRequiredEvenIfNotChanged) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
- SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
- CreateHighLowResAndSetAllTilesVisible();
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
Tile* some_active_tile =
active_layer_->HighResTiling()->AllTilesForTesting()[0];
- EXPECT_FALSE(some_active_tile->IsReadyToDraw());
+ EXPECT_FALSE(some_active_tile->draw_info().IsReadyToDraw());
- // All tiles shared (no invalidation), so even though the active tree's
- // tiles aren't ready, there is nothing required.
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
+ // Since there is no invalidation, pending tree should have no tiles.
+ EXPECT_TRUE(pending_layer_->HighResTiling()->AllTilesForTesting().empty());
if (host_impl_.settings().create_low_res_tiling)
- pending_layer_->LowResTiling()->UpdateAllTilePrioritiesForTesting();
+ EXPECT_TRUE(pending_layer_->LowResTiling()->AllTilesForTesting().empty());
- AssertAllTilesRequired(pending_layer_->HighResTiling());
+ active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
if (host_impl_.settings().create_low_res_tiling)
- AssertNoTilesRequired(pending_layer_->LowResTiling());
+ active_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
+
+ AssertAllTilesRequired(active_layer_->HighResTiling());
+ if (host_impl_.settings().create_low_res_tiling)
+ AssertNoTilesRequired(active_layer_->LowResTiling());
}
TEST_F(NoLowResPictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
// This pile will create tilings, but has no recordings so will not create any
// tiles. This is attempting to simulate scrolling past the end of recorded
// content on the active layer, where the recordings are so far away that
// no tiles are created.
+ bool is_solid_color = false;
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
- tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
- pending_layer_->set_fixed_tile_size(tile_size);
- active_layer_->set_fixed_tile_size(tile_size);
+ tile_size, layer_bounds, is_solid_color);
- CreateHighLowResAndSetAllTilesVisible();
+ SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
// Active layer has tilings, but no tiles due to missing recordings.
EXPECT_TRUE(active_layer_->CanHaveTilings());
@@ -3342,9 +3612,9 @@ TEST_F(NoLowResPictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
// Since the active layer has no tiles at all, the pending layer doesn't
// need content in order to activate.
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
+ pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
if (host_impl_.settings().create_low_res_tiling)
- pending_layer_->LowResTiling()->UpdateAllTilePrioritiesForTesting();
+ pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting();
AssertNoTilesRequired(pending_layer_->HighResTiling());
if (host_impl_.settings().create_low_res_tiling)
@@ -3355,7 +3625,7 @@ TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -3365,11 +3635,10 @@ TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
+ SetupTreesWithInvalidation(pending_pile, active_pile, Region());
- Region invalidation;
- AddDefaultTilingsWithInvalidation(invalidation);
- SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
// UpdateTiles with valid viewport. Should update tile viewport.
// Note viewport is considered invalid if and only if in resourceless
@@ -3385,7 +3654,7 @@ TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
resourceless_software_draw);
active_layer_->draw_properties().visible_content_rect = viewport;
active_layer_->draw_properties().screen_space_transform = transform;
- active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+ active_layer_->UpdateTiles(resourceless_software_draw);
gfx::Rect visible_rect_for_tile_priority =
active_layer_->visible_rect_for_tile_priority();
@@ -3397,7 +3666,7 @@ TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
// Should update viewport and transform, but not update visible rect.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
resourceless_software_draw = true;
viewport = gfx::ScaleToEnclosingRect(viewport, 2);
transform.Translate(1.f, 1.f);
@@ -3409,7 +3678,7 @@ TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
viewport,
transform,
resourceless_software_draw);
- active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+ active_layer_->UpdateTiles(resourceless_software_draw);
// Transform for tile priority is updated.
EXPECT_TRANSFORMATION_MATRIX_EQ(transform,
@@ -3421,7 +3690,7 @@ TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
// Keep expanded viewport but mark it valid. Should update tile viewport.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
resourceless_software_draw = false;
host_impl_.SetExternalDrawConstraints(transform,
viewport,
@@ -3429,7 +3698,7 @@ TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
viewport,
transform,
resourceless_software_draw);
- active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+ active_layer_->UpdateTiles(resourceless_software_draw);
EXPECT_TRANSFORMATION_MATRIX_EQ(transform,
active_layer_->screen_space_transform());
@@ -3448,7 +3717,6 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
std::vector<PictureLayerTiling*> used_tilings;
SetupTrees(pending_pile, active_pile);
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
EXPECT_LT(low_res_factor, 1.f);
@@ -3457,9 +3725,17 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
float page_scale = 3.2f;
float scale = 1.f;
- SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
+ ResetTilingsAndRasterScales();
+
+ SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, 0.f,
+ false);
ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+ // Ensure UpdateTiles won't remove any tilings. Note this is unrelated to
+ // |used_tilings| variable, and it's here only to ensure that active_layer_
+ // won't remove tilings before the test has a chance to verify behavior.
+ active_layer_->MarkAllTilingsUsed();
+
// We only have ideal tilings, so they aren't removed.
used_tilings.clear();
active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
@@ -3470,7 +3746,8 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
// Changing the ideal but not creating new tilings.
scale *= 1.5f;
page_scale *= 1.5f;
- SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
+ SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, 0.f,
+ false);
ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
// The tilings are still our target scale, so they aren't removed.
@@ -3483,11 +3760,14 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
// Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
scale /= 4.f;
page_scale /= 4.f;
- SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, 1.f, false);
+ SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, 1.f, 0.f, false);
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(1.f,
active_layer_->tilings()->tiling_at(1)->contents_scale());
+ // Ensure UpdateTiles won't remove any tilings.
+ active_layer_->MarkAllTilingsUsed();
+
// Mark the non-ideal tilings as used. They won't be removed.
used_tilings.clear();
used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
@@ -3495,7 +3775,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
// Now move the ideal scale to 0.5. Our target stays 1.2.
- SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, 1.f, false);
+ SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, 1.f, 0.f, false);
// The high resolution tiling is between target and ideal, so is not
// removed. The low res tiling for the old ideal=1.0 scale is removed.
@@ -3504,7 +3784,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
// Now move the ideal scale to 1.0. Our target stays 1.2.
- SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, 1.f, false);
+ SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, 1.f, 0.f, false);
// All the tilings are between are target and the ideal, so they are not
// removed.
@@ -3513,8 +3793,8 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
// Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2.
- SetupDrawPropertiesAndUpdateTiles(
- active_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.1f, device_scale,
+ page_scale, 1.f, 0.f, false);
// Because the pending layer's ideal scale is still 1.0, our tilings fall
// in the range [1.0,1.2] and are kept.
@@ -3524,8 +3804,8 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
// Move the ideal scale on the pending layer to 1.1 as well. Our target stays
// 1.2 still.
- SetupDrawPropertiesAndUpdateTiles(
- pending_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.1f, device_scale,
+ page_scale, 1.f, 0.f, false);
// Our 1.0 tiling now falls outside the range between our ideal scale and our
// target raster scale. But it is in our used tilings set, so nothing is
@@ -3542,80 +3822,6 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
}
-TEST_F(PictureLayerImplTest, ScaleCollision) {
- gfx::Size tile_size(400, 400);
- gfx::Size layer_bounds(1300, 1900);
-
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
- std::vector<PictureLayerTiling*> used_tilings;
-
- SetupTrees(pending_pile, active_pile);
-
- float pending_contents_scale = 1.f;
- float active_contents_scale = 2.f;
- float device_scale_factor = 1.f;
- float page_scale_factor = 1.f;
- float maximum_animation_contents_scale = 1.f;
- bool animating_transform = false;
-
- EXPECT_TRUE(host_impl_.settings().create_low_res_tiling);
- float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
- EXPECT_LT(low_res_factor, 1.f);
-
- SetupDrawPropertiesAndUpdateTiles(pending_layer_,
- pending_contents_scale,
- device_scale_factor,
- page_scale_factor,
- maximum_animation_contents_scale,
- animating_transform);
- SetupDrawPropertiesAndUpdateTiles(active_layer_,
- active_contents_scale,
- device_scale_factor,
- page_scale_factor,
- maximum_animation_contents_scale,
- animating_transform);
-
- ASSERT_EQ(4u, pending_layer_->tilings()->num_tilings());
- ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
-
- EXPECT_EQ(active_contents_scale,
- pending_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_EQ(pending_contents_scale,
- pending_layer_->tilings()->tiling_at(1)->contents_scale());
- EXPECT_EQ(active_contents_scale * low_res_factor,
- pending_layer_->tilings()->tiling_at(2)->contents_scale());
- EXPECT_EQ(pending_contents_scale * low_res_factor,
- pending_layer_->tilings()->tiling_at(3)->contents_scale());
-
- EXPECT_EQ(active_contents_scale,
- active_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_EQ(pending_contents_scale,
- active_layer_->tilings()->tiling_at(1)->contents_scale());
- EXPECT_EQ(active_contents_scale * low_res_factor,
- active_layer_->tilings()->tiling_at(2)->contents_scale());
- EXPECT_EQ(pending_contents_scale * low_res_factor,
- active_layer_->tilings()->tiling_at(3)->contents_scale());
-
- // The unused low res tiling from the pending tree must be kept or we may add
- // it again on the active tree and collide with the pending tree.
- used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
- active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
- ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
-
- EXPECT_EQ(active_contents_scale,
- active_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_EQ(pending_contents_scale,
- active_layer_->tilings()->tiling_at(1)->contents_scale());
- EXPECT_EQ(active_contents_scale * low_res_factor,
- active_layer_->tilings()->tiling_at(2)->contents_scale());
- EXPECT_EQ(pending_contents_scale * low_res_factor,
- active_layer_->tilings()->tiling_at(3)->contents_scale());
-}
-
TEST_F(NoLowResPictureLayerImplTest, ReleaseResources) {
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(1300, 1900);
@@ -3626,20 +3832,17 @@ TEST_F(NoLowResPictureLayerImplTest, ReleaseResources) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupTrees(pending_pile, active_pile);
- EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
- SetupDrawPropertiesAndUpdateTiles(pending_layer_,
- 1.3f, // ideal contents scale
- 2.7f, // device scale
- 3.2f, // page scale
- 1.f, // maximum animation scale
- false);
EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+ EXPECT_EQ(1u, active_layer_->tilings()->num_tilings());
// All tilings should be removed when losing output surface.
active_layer_->ReleaseResources();
+ EXPECT_FALSE(active_layer_->tilings());
+ active_layer_->RecreateResources();
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
pending_layer_->ReleaseResources();
+ EXPECT_FALSE(pending_layer_->tilings());
+ pending_layer_->RecreateResources();
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
// This should create new tilings.
@@ -3648,6 +3851,7 @@ TEST_F(NoLowResPictureLayerImplTest, ReleaseResources) {
2.7f, // device scale
3.2f, // page scale
1.f, // maximum animation scale
+ 0.f, // starting animation scale
false);
EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
}
@@ -3658,6 +3862,8 @@ TEST_F(PictureLayerImplTest, SharedQuadStateContainsMaxTilingScale) {
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(1000, 2000);
+ host_impl_.SetViewportSize(gfx::Size(10000, 20000));
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
@@ -3665,20 +3871,19 @@ TEST_F(PictureLayerImplTest, SharedQuadStateContainsMaxTilingScale) {
SetupTrees(pending_pile, active_pile);
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 2.5f, 1.f, 1.f, 1.f, false);
- host_impl_.pending_tree()->UpdateDrawProperties();
-
- active_layer_->draw_properties().visible_content_rect =
- gfx::Rect(layer_bounds);
- host_impl_.active_tree()->UpdateDrawProperties();
+ ResetTilingsAndRasterScales();
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 2.5f, 1.f, 1.f, 1.f, 0.f,
+ false);
float max_contents_scale = active_layer_->MaximumTilingContentsScale();
+ EXPECT_EQ(2.5f, max_contents_scale);
+
gfx::Transform scaled_draw_transform = active_layer_->draw_transform();
scaled_draw_transform.Scale(SK_MScalar1 / max_contents_scale,
SK_MScalar1 / max_contents_scale);
AppendQuadsData data;
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
// SharedQuadState should have be of size 1, as we are doing AppenQuad once.
EXPECT_EQ(1u, render_pass->shared_quad_state_list.size());
@@ -3699,51 +3904,6 @@ TEST_F(PictureLayerImplTest, SharedQuadStateContainsMaxTilingScale) {
->visible_content_rect.ToString());
}
-TEST_F(PictureLayerImplTest, UpdateTilesForMasksWithNoVisibleContent) {
- gfx::Size tile_size(400, 400);
- gfx::Size bounds(100000, 100);
-
- host_impl_.CreatePendingTree();
-
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_.pending_tree(), 1);
-
- scoped_ptr<FakePictureLayerImpl> layer_with_mask =
- FakePictureLayerImpl::Create(host_impl_.pending_tree(), 2);
-
- layer_with_mask->SetBounds(bounds);
- layer_with_mask->SetContentBounds(bounds);
-
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, bounds);
- pending_pile->SetIsMask(true);
- scoped_ptr<FakePictureLayerImpl> mask = FakePictureLayerImpl::CreateWithPile(
- host_impl_.pending_tree(), 3, pending_pile);
-
- mask->SetBounds(bounds);
- mask->SetContentBounds(bounds);
- mask->SetDrawsContent(true);
-
- FakePictureLayerImpl* pending_mask_content = mask.get();
- layer_with_mask->SetMaskLayer(mask.Pass());
-
- scoped_ptr<FakePictureLayerImpl> child_of_layer_with_mask =
- FakePictureLayerImpl::Create(host_impl_.pending_tree(), 4);
-
- child_of_layer_with_mask->SetBounds(bounds);
- child_of_layer_with_mask->SetContentBounds(bounds);
- child_of_layer_with_mask->SetDrawsContent(true);
-
- layer_with_mask->AddChild(child_of_layer_with_mask.Pass());
-
- root->AddChild(layer_with_mask.Pass());
-
- host_impl_.pending_tree()->SetRootLayer(root.Pass());
-
- EXPECT_FALSE(pending_mask_content->tilings());
- host_impl_.pending_tree()->UpdateDrawProperties();
- EXPECT_NE(0u, pending_mask_content->num_tilings());
-}
-
class PictureLayerImplTestWithDelegatingRenderer : public PictureLayerImplTest {
public:
PictureLayerImplTestWithDelegatingRenderer() : PictureLayerImplTest() {}
@@ -3765,9 +3925,9 @@ TEST_F(PictureLayerImplTestWithDelegatingRenderer,
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
SetupPendingTree(pending_pile);
pending_layer_->SetBounds(layer_bounds);
- host_impl_.SetViewportSize(layer_bounds);
ActivateTree();
- host_impl_.active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
std::vector<Tile*> tiles =
active_layer_->HighResTiling()->AllTilesForTesting();
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
@@ -3785,12 +3945,12 @@ TEST_F(PictureLayerImplTestWithDelegatingRenderer,
resource_limit);
host_impl_.SetMemoryPolicy(policy);
host_impl_.SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
- host_impl_.ManageTiles();
+ host_impl_.PrepareTiles();
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_HARDWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
// Even when OOM, quads should be produced, and should be different material
@@ -3812,52 +3972,47 @@ class OcclusionTrackingPictureLayerImplTest : public PictureLayerImplTest {
OcclusionTrackingPictureLayerImplTest()
: PictureLayerImplTest(OcclusionTrackingSettings()) {}
- void VerifyEvictionConsidersOcclusion(
- PictureLayerImpl* layer,
- size_t expected_occluded_tile_count[NUM_TREE_PRIORITIES]) {
- for (int priority_count = 0; priority_count < NUM_TREE_PRIORITIES;
- ++priority_count) {
- TreePriority tree_priority = static_cast<TreePriority>(priority_count);
- size_t occluded_tile_count = 0u;
- Tile* last_tile = nullptr;
-
- for (PictureLayerImpl::LayerEvictionTileIterator it =
- PictureLayerImpl::LayerEvictionTileIterator(layer,
- tree_priority);
- it;
- ++it) {
- Tile* tile = *it;
- if (!last_tile)
- last_tile = tile;
-
- // The only way we will encounter an occluded tile after an unoccluded
- // tile is if the priorty bin decreased, the tile is required for
- // activation, or the scale changed.
- bool tile_is_occluded =
- tile->is_occluded_for_tree_priority(tree_priority);
- if (tile_is_occluded) {
- occluded_tile_count++;
-
- bool last_tile_is_occluded =
- last_tile->is_occluded_for_tree_priority(tree_priority);
- if (!last_tile_is_occluded) {
- TilePriority::PriorityBin tile_priority_bin =
- tile->priority_for_tree_priority(tree_priority).priority_bin;
- TilePriority::PriorityBin last_tile_priority_bin =
- last_tile->priority_for_tree_priority(tree_priority)
- .priority_bin;
-
- EXPECT_TRUE(
- (tile_priority_bin < last_tile_priority_bin) ||
- tile->required_for_activation() ||
- (tile->contents_scale() != last_tile->contents_scale()));
- }
+ void VerifyEvictionConsidersOcclusion(FakePictureLayerImpl* layer,
+ WhichTree tree,
+ size_t expected_occluded_tile_count,
+ int source_line) {
+ size_t occluded_tile_count = 0u;
+ PrioritizedTile last_tile;
+
+ scoped_ptr<TilingSetEvictionQueue> queue(
+ new TilingSetEvictionQueue(layer->picture_layer_tiling_set()));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ Tile* tile = prioritized_tile.tile();
+ if (!last_tile.tile())
+ last_tile = prioritized_tile;
+
+ // The only way we will encounter an occluded tile after an unoccluded
+ // tile is if the priorty bin decreased, the tile is required for
+ // activation, or the scale changed.
+ bool tile_is_occluded = prioritized_tile.is_occluded();
+ if (tile_is_occluded) {
+ occluded_tile_count++;
+
+ bool last_tile_is_occluded = last_tile.is_occluded();
+ if (!last_tile_is_occluded) {
+ TilePriority::PriorityBin tile_priority_bin =
+ prioritized_tile.priority().priority_bin;
+ TilePriority::PriorityBin last_tile_priority_bin =
+ last_tile.priority().priority_bin;
+
+ EXPECT_TRUE(tile_priority_bin < last_tile_priority_bin ||
+ tile->required_for_activation() ||
+ tile->contents_scale() !=
+ last_tile.tile()->contents_scale())
+ << "line: " << source_line;
}
- last_tile = tile;
}
- EXPECT_EQ(expected_occluded_tile_count[priority_count],
- occluded_tile_count);
+ last_tile = prioritized_tile;
+ queue->Pop();
}
+ EXPECT_EQ(expected_occluded_tile_count, occluded_tile_count)
+ << "line: " << source_line;
}
};
@@ -3866,31 +4021,29 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(102, 102);
gfx::Size layer_bounds(1000, 1000);
gfx::Size viewport_size(500, 500);
gfx::Point occluding_layer_position(310, 0);
+ host_impl_.SetViewportSize(viewport_size);
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupPendingTree(pending_pile);
- pending_layer_->set_fixed_tile_size(tile_size);
-
- host_impl_.SetViewportSize(viewport_size);
- host_impl_.pending_tree()->UpdateDrawProperties();
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
// No occlusion.
int unoccluded_tile_count = 0;
- for (PictureLayerImpl::LayerRasterTileIterator it =
- PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
- it;
- ++it) {
- Tile* tile = *it;
+ scoped_ptr<TilingSetRasterQueueAll> queue(new TilingSetRasterQueueAll(
+ pending_layer_->picture_layer_tiling_set(), false));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ Tile* tile = prioritized_tile.tile();
// Occluded tiles should not be iterated over.
- EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
+ EXPECT_FALSE(prioritized_tile.is_occluded());
// Some tiles may not be visible (i.e. outside the viewport). The rest are
// visible and at least partially unoccluded, verified by the above expect.
@@ -3898,6 +4051,7 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
tile->content_rect().Intersects(pending_layer_->visible_content_rect());
if (tile_is_visible)
unoccluded_tile_count++;
+ queue->Pop();
}
EXPECT_EQ(unoccluded_tile_count, 25);
@@ -3912,22 +4066,24 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
unoccluded_tile_count = 0;
- for (PictureLayerImpl::LayerRasterTileIterator it =
- PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
- it;
- ++it) {
- Tile* tile = *it;
+ queue.reset(new TilingSetRasterQueueAll(
+ pending_layer_->picture_layer_tiling_set(), false));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ Tile* tile = prioritized_tile.tile();
- EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
+ EXPECT_FALSE(prioritized_tile.is_occluded());
bool tile_is_visible =
tile->content_rect().Intersects(pending_layer_->visible_content_rect());
if (tile_is_visible)
unoccluded_tile_count++;
+ queue->Pop();
}
EXPECT_EQ(20, unoccluded_tile_count);
@@ -3936,22 +4092,23 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
unoccluded_tile_count = 0;
- for (PictureLayerImpl::LayerRasterTileIterator it =
- PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
- it;
- ++it) {
- Tile* tile = *it;
+ queue.reset(new TilingSetRasterQueueAll(
+ pending_layer_->picture_layer_tiling_set(), false));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ Tile* tile = prioritized_tile.tile();
- EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
+ EXPECT_FALSE(prioritized_tile.is_occluded());
bool tile_is_visible =
tile->content_rect().Intersects(pending_layer_->visible_content_rect());
if (tile_is_visible)
unoccluded_tile_count++;
+ queue->Pop();
}
EXPECT_EQ(unoccluded_tile_count, 0);
}
@@ -3961,25 +4118,25 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(102, 102);
gfx::Size layer_bounds(1000, 1000);
gfx::Size viewport_size(500, 500);
gfx::Point occluding_layer_position(310, 0);
+ host_impl_.SetViewportSize(viewport_size);
+
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupPendingTree(pending_pile);
- pending_layer_->set_fixed_tile_size(tile_size);
-
- host_impl_.SetViewportSize(viewport_size);
- host_impl_.pending_tree()->UpdateDrawProperties();
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
// No occlusion.
int occluded_tile_count = 0;
for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
occluded_tile_count = 0;
for (PictureLayerTiling::CoverageIterator iter(
@@ -3993,7 +4150,7 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
const Tile* tile = *iter;
// Fully occluded tiles are not required for activation.
- if (tile->is_occluded(PENDING_TREE)) {
+ if (prioritized_tiles[tile].is_occluded()) {
EXPECT_FALSE(tile->required_for_activation());
occluded_tile_count++;
}
@@ -4012,12 +4169,14 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
- tiling->UpdateAllTilePrioritiesForTesting();
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
occluded_tile_count = 0;
for (PictureLayerTiling::CoverageIterator iter(
@@ -4030,7 +4189,7 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
continue;
const Tile* tile = *iter;
- if (tile->is_occluded(PENDING_TREE)) {
+ if (prioritized_tiles[tile].is_occluded()) {
EXPECT_FALSE(tile->required_for_activation());
occluded_tile_count++;
}
@@ -4052,12 +4211,13 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
- tiling->UpdateAllTilePrioritiesForTesting();
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
occluded_tile_count = 0;
for (PictureLayerTiling::CoverageIterator iter(
@@ -4070,7 +4230,7 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
continue;
const Tile* tile = *iter;
- if (tile->is_occluded(PENDING_TREE)) {
+ if (prioritized_tiles[tile].is_occluded()) {
EXPECT_FALSE(tile->required_for_activation());
occluded_tile_count++;
}
@@ -4089,6 +4249,11 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
}
TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForDifferentScales) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
gfx::Size tile_size(102, 102);
gfx::Size layer_bounds(1000, 1000);
gfx::Size viewport_size(500, 500);
@@ -4096,19 +4261,11 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForDifferentScales) {
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupPendingTree(pending_pile);
- pending_layer_->set_fixed_tile_size(tile_size);
- ASSERT_TRUE(pending_layer_->CanHaveTilings());
-
- float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+ host_impl_.SetViewportSize(viewport_size);
- std::vector<PictureLayerTiling*> tilings;
- tilings.push_back(pending_layer_->AddTiling(low_res_factor));
- tilings.push_back(pending_layer_->AddTiling(0.3f));
- tilings.push_back(pending_layer_->AddTiling(0.7f));
- tilings.push_back(pending_layer_->AddTiling(1.0f));
- tilings.push_back(pending_layer_->AddTiling(2.0f));
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
+ ASSERT_TRUE(pending_layer_->CanHaveTilings());
pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1));
LayerImpl* layer1 = pending_layer_->children()[0];
@@ -4118,49 +4275,58 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForDifferentScales) {
layer1->SetContentsOpaque(true);
layer1->SetPosition(occluding_layer_position);
- host_impl_.SetViewportSize(viewport_size);
- host_impl_.pending_tree()->UpdateDrawProperties();
+ pending_layer_->tilings()->RemoveAllTilings();
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+ pending_layer_->AddTiling(low_res_factor);
+ pending_layer_->AddTiling(0.3f);
+ pending_layer_->AddTiling(0.7f);
+ pending_layer_->AddTiling(1.0f);
+ pending_layer_->AddTiling(2.0f);
+
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ // UpdateDrawProperties with the occluding layer.
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+
+ EXPECT_EQ(5u, pending_layer_->num_tilings());
- int tiling_count = 0;
int occluded_tile_count = 0;
- for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
- tilings.begin();
- tiling_iterator != tilings.end();
- ++tiling_iterator) {
- (*tiling_iterator)->UpdateAllTilePrioritiesForTesting();
- std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
+ for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
+ std::vector<Tile*> tiles = tiling->AllTilesForTesting();
occluded_tile_count = 0;
- for (size_t i = 0; i < tiles.size(); ++i) {
- if (tiles[i]->is_occluded(PENDING_TREE)) {
+ for (size_t j = 0; j < tiles.size(); ++j) {
+ if (prioritized_tiles[tiles[j]].is_occluded()) {
gfx::Rect scaled_content_rect = ScaleToEnclosingRect(
- tiles[i]->content_rect(), 1.0f / tiles[i]->contents_scale());
+ tiles[j]->content_rect(), 1.0f / tiles[j]->contents_scale());
EXPECT_GE(scaled_content_rect.x(), occluding_layer_position.x());
occluded_tile_count++;
}
}
- switch (tiling_count) {
+
+ switch (i) {
case 0:
+ EXPECT_EQ(occluded_tile_count, 30);
+ break;
case 1:
- EXPECT_EQ(occluded_tile_count, 2);
+ EXPECT_EQ(occluded_tile_count, 5);
break;
case 2:
EXPECT_EQ(occluded_tile_count, 4);
break;
- case 3:
- EXPECT_EQ(occluded_tile_count, 5);
- break;
case 4:
- EXPECT_EQ(occluded_tile_count, 30);
+ case 3:
+ EXPECT_EQ(occluded_tile_count, 2);
break;
default:
NOTREACHED();
}
-
- tiling_count++;
}
-
- EXPECT_EQ(tiling_count, 5);
}
TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) {
@@ -4174,66 +4340,50 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) {
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
+
+ host_impl_.SetViewportSize(viewport_size);
+ SetupPendingTree(active_pile);
// Partially occlude the active layer.
- active_layer_->AddChild(LayerImpl::Create(host_impl_.active_tree(), 2));
- LayerImpl* layer1 = active_layer_->children()[0];
+ pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 2));
+ LayerImpl* layer1 = pending_layer_->children()[0];
layer1->SetBounds(layer_bounds);
layer1->SetContentBounds(layer_bounds);
layer1->SetDrawsContent(true);
layer1->SetContentsOpaque(true);
layer1->SetPosition(occluding_layer_position);
- // Partially invalidate the pending layer.
- pending_layer_->set_invalidation(invalidation_rect);
-
- host_impl_.SetViewportSize(viewport_size);
-
- active_layer_->CreateDefaultTilingsAndTiles();
- pending_layer_->CreateDefaultTilingsAndTiles();
+ ActivateTree();
- for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
- tiling->UpdateAllTilePrioritiesForTesting();
+ for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = active_layer_->tilings()->tiling_at(i);
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
- for (PictureLayerTiling::CoverageIterator iter(
- tiling,
- pending_layer_->contents_scale_x(),
- gfx::Rect(layer_bounds));
- iter;
- ++iter) {
+ for (
+ PictureLayerTiling::CoverageIterator iter(
+ tiling, active_layer_->contents_scale_x(), gfx::Rect(layer_bounds));
+ iter; ++iter) {
if (!*iter)
continue;
const Tile* tile = *iter;
- // All tiles are unoccluded on the pending tree.
- EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
-
- Tile* twin_tile = pending_layer_->GetPendingOrActiveTwinTiling(tiling)
- ->TileAt(iter.i(), iter.j());
gfx::Rect scaled_content_rect = ScaleToEnclosingRect(
tile->content_rect(), 1.0f / tile->contents_scale());
-
- if (scaled_content_rect.Intersects(invalidation_rect)) {
- // Tiles inside the invalidation rect are only on the pending tree.
- EXPECT_NE(tile, twin_tile);
-
- // Unshared tiles should be unoccluded on the active tree by default.
- EXPECT_FALSE(tile->is_occluded(ACTIVE_TREE));
- } else {
- // Tiles outside the invalidation rect are shared between both trees.
- EXPECT_EQ(tile, twin_tile);
- // Shared tiles are occluded on the active tree iff they lie beneath the
- // occluding layer.
- EXPECT_EQ(tile->is_occluded(ACTIVE_TREE),
- scaled_content_rect.x() >= occluding_layer_position.x());
- }
+ // Tiles are occluded on the active tree iff they lie beneath the
+ // occluding layer.
+ EXPECT_EQ(prioritized_tiles[tile].is_occluded(),
+ scaled_content_rect.x() >= occluding_layer_position.x());
}
}
+ // Partially invalidate the pending layer.
+ SetupPendingTreeWithInvalidation(pending_pile, invalidation_rect);
+
for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
PictureLayerTiling* tiling = active_layer_->tilings()->tiling_at(i);
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
for (PictureLayerTiling::CoverageIterator iter(
tiling,
@@ -4245,24 +4395,23 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) {
continue;
const Tile* tile = *iter;
+ // All tiles are unoccluded, because the pending tree has no occlusion.
+ EXPECT_FALSE(prioritized_tiles[tile].is_occluded());
+
Tile* twin_tile = active_layer_->GetPendingOrActiveTwinTiling(tiling)
->TileAt(iter.i(), iter.j());
gfx::Rect scaled_content_rect = ScaleToEnclosingRect(
tile->content_rect(), 1.0f / tile->contents_scale());
- // Since we've already checked the shared tiles, only consider tiles in
- // the invalidation rect.
if (scaled_content_rect.Intersects(invalidation_rect)) {
- // Tiles inside the invalidation rect are only on the active tree.
+ // Tiles inside the invalidation rect exist on both trees.
+ EXPECT_TRUE(tile);
+ EXPECT_TRUE(twin_tile);
EXPECT_NE(tile, twin_tile);
-
- // Unshared tiles should be unoccluded on the pending tree by default.
- EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
-
- // Unshared tiles are occluded on the active tree iff they lie beneath
- // the occluding layer.
- EXPECT_EQ(tile->is_occluded(ACTIVE_TREE),
- scaled_content_rect.x() >= occluding_layer_position.x());
+ } else {
+ // Tiles outside the invalidation rect only exist on the active tree.
+ EXPECT_TRUE(tile);
+ EXPECT_FALSE(twin_tile);
}
}
}
@@ -4270,36 +4419,45 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) {
TEST_F(OcclusionTrackingPictureLayerImplTest,
OccludedTilesConsideredDuringEviction) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
gfx::Size tile_size(102, 102);
gfx::Size layer_bounds(1000, 1000);
- gfx::Size viewport_size(500, 500);
+ gfx::Size viewport_size(1000, 1000);
gfx::Point pending_occluding_layer_position(310, 0);
gfx::Point active_occluding_layer_position(0, 310);
- gfx::Rect invalidation_rect(230, 230, 102, 102);
+ gfx::Rect invalidation_rect(230, 230, 152, 152);
+
+ host_impl_.SetViewportSize(viewport_size);
+ host_impl_.SetDeviceScaleFactor(2.f);
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupTrees(pending_pile, active_pile);
- pending_layer_->set_fixed_tile_size(tile_size);
- active_layer_->set_fixed_tile_size(tile_size);
+ SetupPendingTreeWithFixedTileSize(active_pile, tile_size, Region());
- float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+ // Partially occlude the active layer.
+ pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 2));
+ LayerImpl* active_occluding_layer = pending_layer_->children()[0];
+ active_occluding_layer->SetBounds(layer_bounds);
+ active_occluding_layer->SetContentBounds(layer_bounds);
+ active_occluding_layer->SetDrawsContent(true);
+ active_occluding_layer->SetContentsOpaque(true);
+ active_occluding_layer->SetPosition(active_occluding_layer_position);
- std::vector<PictureLayerTiling*> tilings;
- tilings.push_back(pending_layer_->AddTiling(low_res_factor));
- tilings.push_back(pending_layer_->AddTiling(0.3f));
- tilings.push_back(pending_layer_->AddTiling(0.7f));
- tilings.push_back(pending_layer_->AddTiling(1.0f));
- tilings.push_back(pending_layer_->AddTiling(2.0f));
+ ActivateTree();
- EXPECT_EQ(5u, pending_layer_->num_tilings());
- EXPECT_EQ(5u, active_layer_->num_tilings());
+ // Partially invalidate the pending layer. Tiles inside the invalidation rect
+ // are created.
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, invalidation_rect);
- // Partially occlude the pending layer.
- pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1));
+ // Partially occlude the pending layer in a different way.
+ pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 3));
LayerImpl* pending_occluding_layer = pending_layer_->children()[0];
pending_occluding_layer->SetBounds(layer_bounds);
pending_occluding_layer->SetContentBounds(layer_bounds);
@@ -4307,79 +4465,56 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
pending_occluding_layer->SetContentsOpaque(true);
pending_occluding_layer->SetPosition(pending_occluding_layer_position);
- // Partially occlude the active layer.
- active_layer_->AddChild(LayerImpl::Create(host_impl_.active_tree(), 2));
- LayerImpl* active_occluding_layer = active_layer_->children()[0];
- active_occluding_layer->SetBounds(layer_bounds);
- active_occluding_layer->SetContentBounds(layer_bounds);
- active_occluding_layer->SetDrawsContent(true);
- active_occluding_layer->SetContentsOpaque(true);
- active_occluding_layer->SetPosition(active_occluding_layer_position);
-
- // Partially invalidate the pending layer. Tiles inside the invalidation rect
- // are not shared between trees.
- pending_layer_->set_invalidation(invalidation_rect);
+ EXPECT_EQ(2u, pending_layer_->num_tilings());
+ EXPECT_EQ(2u, active_layer_->num_tilings());
- host_impl_.SetViewportSize(viewport_size);
- host_impl_.active_tree()->UpdateDrawProperties();
- host_impl_.pending_tree()->UpdateDrawProperties();
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ // UpdateDrawProperties with the occluding layer.
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
- // The expected number of occluded tiles on each of the 5 tilings for each of
+ // The expected number of occluded tiles on each of the 2 tilings for each of
// the 3 tree priorities.
- size_t expected_occluded_tile_count_on_both[] = {9u, 1u, 1u, 1u, 1u};
- size_t expected_occluded_tile_count_on_active[] = {30u, 5u, 4u, 2u, 2u};
- size_t expected_occluded_tile_count_on_pending[] = {30u, 5u, 4u, 2u, 2u};
-
- // The total expected number of occluded tiles on all tilings for each of the
- // 3 tree priorities.
- size_t total_expected_occluded_tile_count[] = {13u, 43u, 43u};
-
- ASSERT_EQ(arraysize(total_expected_occluded_tile_count), NUM_TREE_PRIORITIES);
+ size_t expected_occluded_tile_count_on_pending[] = {4u, 0u};
+ size_t expected_occluded_tile_count_on_active[] = {12u, 1u};
+ size_t total_expected_occluded_tile_count_on_trees[] = {13u, 4u};
// Verify number of occluded tiles on the pending layer for each tiling.
for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
- tiling->CreateAllTilesForTesting();
- tiling->UpdateAllTilePrioritiesForTesting();
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
size_t occluded_tile_count_on_pending = 0u;
- size_t occluded_tile_count_on_active = 0u;
- size_t occluded_tile_count_on_both = 0u;
- for (PictureLayerTiling::CoverageIterator iter(
- tiling,
- pending_layer_->contents_scale_x(),
- gfx::Rect(layer_bounds));
- iter;
- ++iter) {
+ for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f,
+ gfx::Rect(layer_bounds));
+ iter; ++iter) {
Tile* tile = *iter;
- if (tile->is_occluded(PENDING_TREE))
+ if (invalidation_rect.Intersects(iter.geometry_rect()))
+ EXPECT_TRUE(tile);
+ else
+ EXPECT_FALSE(tile);
+
+ if (!tile)
+ continue;
+ if (prioritized_tiles[tile].is_occluded())
occluded_tile_count_on_pending++;
- if (tile->is_occluded(ACTIVE_TREE))
- occluded_tile_count_on_active++;
- if (tile->is_occluded(PENDING_TREE) && tile->is_occluded(ACTIVE_TREE))
- occluded_tile_count_on_both++;
}
EXPECT_EQ(expected_occluded_tile_count_on_pending[i],
occluded_tile_count_on_pending)
- << i;
- EXPECT_EQ(expected_occluded_tile_count_on_active[i],
- occluded_tile_count_on_active)
- << i;
- EXPECT_EQ(expected_occluded_tile_count_on_both[i],
- occluded_tile_count_on_both)
- << i;
+ << tiling->contents_scale();
}
// Verify number of occluded tiles on the active layer for each tiling.
for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
PictureLayerTiling* tiling = active_layer_->tilings()->tiling_at(i);
- tiling->CreateAllTilesForTesting();
- tiling->UpdateAllTilePrioritiesForTesting();
+ auto prioritized_tiles =
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
- size_t occluded_tile_count_on_pending = 0u;
size_t occluded_tile_count_on_active = 0u;
- size_t occluded_tile_count_on_both = 0u;
for (PictureLayerTiling::CoverageIterator iter(
tiling,
pending_layer_->contents_scale_x(),
@@ -4388,39 +4523,56 @@ TEST_F(OcclusionTrackingPictureLayerImplTest,
++iter) {
Tile* tile = *iter;
- if (tile->is_occluded(PENDING_TREE))
- occluded_tile_count_on_pending++;
- if (tile->is_occluded(ACTIVE_TREE))
+ if (!tile)
+ continue;
+ if (prioritized_tiles[tile].is_occluded())
occluded_tile_count_on_active++;
- if (tile->is_occluded(PENDING_TREE) && tile->is_occluded(ACTIVE_TREE))
- occluded_tile_count_on_both++;
}
- EXPECT_EQ(expected_occluded_tile_count_on_pending[i],
- occluded_tile_count_on_pending)
- << i;
EXPECT_EQ(expected_occluded_tile_count_on_active[i],
occluded_tile_count_on_active)
<< i;
- EXPECT_EQ(expected_occluded_tile_count_on_both[i],
- occluded_tile_count_on_both)
- << i;
}
std::vector<Tile*> all_tiles;
- for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
- tilings.begin();
- tiling_iterator != tilings.end();
- ++tiling_iterator) {
- std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
- std::copy(tiles.begin(), tiles.end(), std::back_inserter(all_tiles));
+ for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+ std::vector<Tile*> tiles = tiling->AllTilesForTesting();
+ all_tiles.insert(all_tiles.end(), tiles.begin(), tiles.end());
+ }
+ for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = active_layer_->tilings()->tiling_at(i);
+ std::vector<Tile*> tiles = tiling->AllTilesForTesting();
+ all_tiles.insert(all_tiles.end(), tiles.begin(), tiles.end());
}
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
- VerifyEvictionConsidersOcclusion(pending_layer_,
- total_expected_occluded_tile_count);
- VerifyEvictionConsidersOcclusion(active_layer_,
- total_expected_occluded_tile_count);
+ VerifyEvictionConsidersOcclusion(
+ pending_layer_, PENDING_TREE,
+ total_expected_occluded_tile_count_on_trees[PENDING_TREE], __LINE__);
+ VerifyEvictionConsidersOcclusion(
+ active_layer_, ACTIVE_TREE,
+ total_expected_occluded_tile_count_on_trees[ACTIVE_TREE], __LINE__);
+
+ // Repeat the tests without valid active tree priorities.
+ active_layer_->set_has_valid_tile_priorities(false);
+ VerifyEvictionConsidersOcclusion(
+ pending_layer_, PENDING_TREE,
+ total_expected_occluded_tile_count_on_trees[PENDING_TREE], __LINE__);
+ VerifyEvictionConsidersOcclusion(
+ active_layer_, ACTIVE_TREE,
+ total_expected_occluded_tile_count_on_trees[ACTIVE_TREE], __LINE__);
+ active_layer_->set_has_valid_tile_priorities(true);
+
+ // Repeat the tests without valid pending tree priorities.
+ pending_layer_->set_has_valid_tile_priorities(false);
+ VerifyEvictionConsidersOcclusion(
+ active_layer_, ACTIVE_TREE,
+ total_expected_occluded_tile_count_on_trees[ACTIVE_TREE], __LINE__);
+ VerifyEvictionConsidersOcclusion(
+ pending_layer_, PENDING_TREE,
+ total_expected_occluded_tile_count_on_trees[PENDING_TREE], __LINE__);
+ pending_layer_->set_has_valid_tile_priorities(true);
}
TEST_F(PictureLayerImplTest, PendingOrActiveTwinLayer) {
@@ -4481,7 +4633,7 @@ void PictureLayerImplTest::TestQuadsForSolidColor(bool test_for_solid) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
@@ -4492,35 +4644,23 @@ void PictureLayerImplTest::TestQuadsForSolidColor(bool test_for_solid) {
FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client);
host->SetRootLayer(layer);
- PicturePile* pile = layer->GetPicturePileForTesting();
-
- host_impl_.SetViewportSize(layer_bounds);
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
int frame_number = 0;
- FakeRenderingStatsInstrumentation stats_instrumentation;
client.set_fill_with_nonsolid_color(!test_for_solid);
Region invalidation(layer_rect);
- pile->UpdateAndExpandInvalidation(&client,
- &invalidation,
- SK_ColorWHITE,
- false,
- false,
- layer_bounds,
- layer_rect,
- frame_number++,
- Picture::RECORD_NORMALLY,
- &stats_instrumentation);
-
- scoped_refptr<PicturePileImpl> pending_pile =
- PicturePileImpl::CreateFromOther(pile);
+ recording_source->UpdateAndExpandInvalidation(
+ &client, &invalidation, layer_bounds, layer_rect, frame_number++,
+ RecordingSource::RECORD_NORMALLY);
- SetupPendingTree(pending_pile);
+ scoped_refptr<RasterSource> pending_raster_source =
+ recording_source->CreateRasterSource(true);
+
+ SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region());
ActivateTree();
- active_layer_->set_fixed_tile_size(tile_size);
- host_impl_.active_tree()->UpdateDrawProperties();
if (test_for_solid) {
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
} else {
@@ -4535,7 +4675,7 @@ void PictureLayerImplTest::TestQuadsForSolidColor(bool test_for_solid) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
- active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+ active_layer_->AppendQuads(render_pass.get(), &data);
active_layer_->DidDraw(nullptr);
DrawQuad::Material expected = test_for_solid
@@ -4556,7 +4696,7 @@ TEST_F(PictureLayerImplTest, NonSolidToSolidNoTilings) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(200, 200);
@@ -4567,33 +4707,24 @@ TEST_F(PictureLayerImplTest, NonSolidToSolidNoTilings) {
FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client);
host->SetRootLayer(layer);
- PicturePile* pile = layer->GetPicturePileForTesting();
-
- host_impl_.SetViewportSize(layer_bounds);
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
int frame_number = 0;
- FakeRenderingStatsInstrumentation stats_instrumentation;
client.set_fill_with_nonsolid_color(true);
Region invalidation1(layer_rect);
- pile->UpdateAndExpandInvalidation(&client,
- &invalidation1,
- SK_ColorWHITE,
- false,
- false,
- layer_bounds,
- layer_rect,
- frame_number++,
- Picture::RECORD_NORMALLY,
- &stats_instrumentation);
-
- scoped_refptr<PicturePileImpl> pending_pile1 =
- PicturePileImpl::CreateFromOther(pile);
-
- SetupPendingTree(pending_pile1);
+ recording_source->UpdateAndExpandInvalidation(
+ &client, &invalidation1, layer_bounds, layer_rect, frame_number++,
+ RecordingSource::RECORD_NORMALLY);
+
+ scoped_refptr<RasterSource> raster_source1 =
+ recording_source->CreateRasterSource(true);
+
+ SetupPendingTree(raster_source1);
ActivateTree();
- host_impl_.active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
// We've started with a solid layer that contains some tilings.
ASSERT_TRUE(active_layer_->tilings());
@@ -4602,21 +4733,14 @@ TEST_F(PictureLayerImplTest, NonSolidToSolidNoTilings) {
client.set_fill_with_nonsolid_color(false);
Region invalidation2(layer_rect);
- pile->UpdateAndExpandInvalidation(&client,
- &invalidation2,
- SK_ColorWHITE,
- false,
- false,
- layer_bounds,
- layer_rect,
- frame_number++,
- Picture::RECORD_NORMALLY,
- &stats_instrumentation);
-
- scoped_refptr<PicturePileImpl> pending_pile2 =
- PicturePileImpl::CreateFromOther(pile);
+ recording_source->UpdateAndExpandInvalidation(
+ &client, &invalidation2, layer_bounds, layer_rect, frame_number++,
+ RecordingSource::RECORD_NORMALLY);
- SetupPendingTree(pending_pile2);
+ scoped_refptr<RasterSource> raster_source2 =
+ recording_source->CreateRasterSource(true);
+
+ SetupPendingTree(raster_source2);
ActivateTree();
// We've switched to a solid color, so we should end up with no tilings.
@@ -4628,7 +4752,7 @@ TEST_F(PictureLayerImplTest, ChangeInViewportAllowsTilingUpdates) {
base::TimeTicks time_ticks;
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
- CreateBeginFrameArgsForTesting(time_ticks));
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 4000);
@@ -4649,11 +4773,12 @@ TEST_F(PictureLayerImplTest, ChangeInViewportAllowsTilingUpdates) {
// Update tiles.
pending_layer_->draw_properties().visible_content_rect = viewport;
pending_layer_->draw_properties().screen_space_transform = transform;
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
+ pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
// Ensure we can't activate.
- EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ EXPECT_FALSE(host_impl_.tile_manager()->IsReadyToActivate());
// Now in the same frame, move the viewport (this can happen during
// animation).
@@ -4662,8 +4787,9 @@ TEST_F(PictureLayerImplTest, ChangeInViewportAllowsTilingUpdates) {
// Update tiles.
pending_layer_->draw_properties().visible_content_rect = viewport;
pending_layer_->draw_properties().screen_space_transform = transform;
- SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
- pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, 0.f,
+ false);
+ pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting();
// Make sure all viewport tiles (viewport from the tiling) are ready to draw.
std::vector<Tile*> tiles;
@@ -4676,14 +4802,220 @@ TEST_F(PictureLayerImplTest, ChangeInViewportAllowsTilingUpdates) {
if (*iter)
tiles.push_back(*iter);
}
+ for (PictureLayerTiling::CoverageIterator iter(
+ active_layer_->HighResTiling(), 1.f,
+ active_layer_->HighResTiling()->GetCurrentVisibleRectForTesting());
+ iter; ++iter) {
+ if (*iter)
+ tiles.push_back(*iter);
+ }
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
// Ensure we can activate.
- EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+ EXPECT_TRUE(host_impl_.tile_manager()->IsReadyToActivate());
}
-class TileSizeSettings : public ImplSidePaintingSettings {
+TEST_F(PictureLayerImplTest, CloneMissingRecordings) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(400, 400);
+
+ scoped_refptr<FakePicturePileImpl> filled_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ scoped_ptr<FakePicturePile> partial_recording =
+ FakePicturePile::CreateEmptyPile(tile_size, layer_bounds);
+ for (int i = 1; i < partial_recording->tiling().num_tiles_x(); ++i) {
+ for (int j = 1; j < partial_recording->tiling().num_tiles_y(); ++j)
+ partial_recording->AddRecordingAt(i, j);
+ }
+ scoped_refptr<FakePicturePileImpl> partial_pile =
+ FakePicturePileImpl::CreateFromPile(partial_recording.get(), nullptr);
+
+ SetupPendingTreeWithFixedTileSize(filled_pile, tile_size, Region());
+ ActivateTree();
+
+ PictureLayerTiling* pending_tiling = old_pending_layer_->HighResTiling();
+ PictureLayerTiling* active_tiling = active_layer_->HighResTiling();
+
+ // We should have all tiles on active, and none on pending.
+ EXPECT_EQ(0u, pending_tiling->AllTilesForTesting().size());
+ EXPECT_EQ(5u * 5u, active_tiling->AllTilesForTesting().size());
+
+ // Now put a partially-recorded pile on the pending tree (and invalidate
+ // everything, since the main thread PicturePile will invalidate dropped
+ // recordings). This will cause us to be missing some tiles.
+ SetupPendingTreeWithFixedTileSize(partial_pile, tile_size,
+ Region(gfx::Rect(layer_bounds)));
+ EXPECT_EQ(3u * 3u, pending_tiling->AllTilesForTesting().size());
+ EXPECT_FALSE(pending_tiling->TileAt(0, 0));
+ EXPECT_FALSE(pending_tiling->TileAt(1, 1));
+ EXPECT_TRUE(pending_tiling->TileAt(2, 2));
+
+ // Active is not affected yet.
+ EXPECT_EQ(5u * 5u, active_tiling->AllTilesForTesting().size());
+
+ // Activate the tree. The same tiles go missing on the active tree.
+ ActivateTree();
+ EXPECT_EQ(3u * 3u, active_tiling->AllTilesForTesting().size());
+ EXPECT_FALSE(active_tiling->TileAt(0, 0));
+ EXPECT_FALSE(active_tiling->TileAt(1, 1));
+ EXPECT_TRUE(active_tiling->TileAt(2, 2));
+
+ // Now put a full recording on the pending tree again. We'll get all our tiles
+ // back.
+ SetupPendingTreeWithFixedTileSize(filled_pile, tile_size,
+ Region(gfx::Rect(layer_bounds)));
+ EXPECT_EQ(5u * 5u, pending_tiling->AllTilesForTesting().size());
+ Tile* tile00 = pending_tiling->TileAt(0, 0);
+ Tile* tile11 = pending_tiling->TileAt(1, 1);
+ Tile* tile22 = pending_tiling->TileAt(2, 2);
+
+ // Active is not affected yet.
+ EXPECT_EQ(3u * 3u, active_tiling->AllTilesForTesting().size());
+
+ // Activate the tree. The tiles are moved to the active tree.
+ ActivateTree();
+ EXPECT_EQ(5u * 5u, active_tiling->AllTilesForTesting().size());
+ EXPECT_EQ(tile00, active_tiling->TileAt(0, 0));
+ EXPECT_EQ(tile11, active_tiling->TileAt(1, 1));
+ EXPECT_EQ(tile22, active_tiling->TileAt(2, 2));
+}
+
+TEST_F(PictureLayerImplTest, ScrollPastLiveTilesRectAndBack) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ gfx::Size tile_size(102, 102);
+ gfx::Size layer_bounds(100, 100);
+ gfx::Size viewport_size(100, 100);
+
+ host_impl_.SetViewportSize(viewport_size);
+ host_impl_.SetDeviceScaleFactor(1.f);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupPendingTreeWithFixedTileSize(active_pile, tile_size, Region());
+
+ ActivateTree();
+ EXPECT_TRUE(active_layer_->HighResTiling()->has_tiles());
+
+ host_impl_.SetExternalDrawConstraints(
+ gfx::Transform(), // transform
+ gfx::Rect(), // clip
+ gfx::Rect(), // viewport
+ gfx::Rect(0, 1000, 100, 100), // viewport_rect_for_tile_priority
+ gfx::Transform(), // transform_for_tile_priority
+ false);
+
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, gfx::Rect());
+
+ EXPECT_FALSE(pending_layer_->HighResTiling()->has_tiles());
+ EXPECT_TRUE(pending_layer_->HighResTiling()->live_tiles_rect().IsEmpty());
+ ActivateTree();
+ EXPECT_FALSE(active_layer_->HighResTiling()->has_tiles());
+ EXPECT_TRUE(active_layer_->HighResTiling()->live_tiles_rect().IsEmpty());
+
+ host_impl_.SetExternalDrawConstraints(
+ gfx::Transform(), // transform
+ gfx::Rect(), // clip
+ gfx::Rect(), // viewport
+ gfx::Rect(0, 110, 100, 100), // viewport_rect_for_tile_priority
+ gfx::Transform(), // transform_for_tile_priority
+ false);
+
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, gfx::Rect());
+
+ EXPECT_FALSE(pending_layer_->HighResTiling()->has_tiles());
+ EXPECT_FALSE(pending_layer_->HighResTiling()->live_tiles_rect().IsEmpty());
+ ActivateTree();
+ EXPECT_TRUE(active_layer_->HighResTiling()->has_tiles());
+ EXPECT_FALSE(active_layer_->HighResTiling()->live_tiles_rect().IsEmpty());
+}
+
+TEST_F(PictureLayerImplTest, ScrollPropagatesToPending) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ gfx::Size tile_size(102, 102);
+ gfx::Size layer_bounds(1000, 1000);
+ gfx::Size viewport_size(100, 100);
+
+ host_impl_.SetViewportSize(viewport_size);
+ host_impl_.SetDeviceScaleFactor(1.f);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+
+ active_layer_->SetCurrentScrollOffset(gfx::ScrollOffset(0.0, 50.0));
+ host_impl_.active_tree()->UpdateDrawProperties(false);
+ EXPECT_EQ("0,50 100x100", active_layer_->HighResTiling()
+ ->GetCurrentVisibleRectForTesting()
+ .ToString());
+
+ EXPECT_EQ("0,0 100x100", pending_layer_->HighResTiling()
+ ->GetCurrentVisibleRectForTesting()
+ .ToString());
+ host_impl_.pending_tree()->UpdateDrawProperties(false);
+ EXPECT_EQ("0,50 100x100", pending_layer_->HighResTiling()
+ ->GetCurrentVisibleRectForTesting()
+ .ToString());
+}
+
+TEST_F(PictureLayerImplTest, UpdateLCDInvalidatesPendingTree) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ gfx::Size tile_size(102, 102);
+ gfx::Size layer_bounds(100, 100);
+ gfx::Size viewport_size(100, 100);
+
+ host_impl_.SetViewportSize(viewport_size);
+ host_impl_.SetDeviceScaleFactor(1.f);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
+
+ EXPECT_TRUE(pending_layer_->RasterSourceUsesLCDText());
+ EXPECT_TRUE(pending_layer_->HighResTiling()->has_tiles());
+ std::vector<Tile*> tiles =
+ pending_layer_->HighResTiling()->AllTilesForTesting();
+ auto prioritized_tiles = pending_layer_->HighResTiling()
+ ->UpdateAndGetAllPrioritizedTilesForTesting();
+
+ for (Tile* tile : tiles)
+ EXPECT_EQ(pending_layer_->raster_source(),
+ prioritized_tiles[tile].raster_source());
+
+ pending_layer_->draw_properties().can_use_lcd_text = false;
+ pending_layer_->UpdateCanUseLCDTextAfterCommit();
+
+ EXPECT_FALSE(pending_layer_->RasterSourceUsesLCDText());
+ EXPECT_NE(pending_pile.get(), pending_layer_->raster_source());
+ EXPECT_TRUE(pending_layer_->HighResTiling()->has_tiles());
+ tiles = pending_layer_->HighResTiling()->AllTilesForTesting();
+ prioritized_tiles = pending_layer_->HighResTiling()
+ ->UpdateAndGetAllPrioritizedTilesForTesting();
+ for (Tile* tile : tiles)
+ EXPECT_EQ(pending_layer_->raster_source(),
+ prioritized_tiles[tile].raster_source());
+}
+
+class TileSizeSettings : public GpuRasterizationEnabledSettings {
public:
TileSizeSettings() {
default_tile_size = gfx::Size(100, 100);
@@ -4706,7 +5038,10 @@ TEST_F(TileSizeTest, TileSizes) {
host_impl_.SetViewportSize(gfx::Size(1000, 1000));
gfx::Size result;
- host_impl_.SetUseGpuRasterization(false);
+ host_impl_.SetContentIsSuitableForGpuRasterization(true);
+ host_impl_.SetHasGpuRasterizationTrigger(false);
+ EXPECT_EQ(host_impl_.gpu_rasterization_status(),
+ GpuRasterizationStatus::OFF_VIEWPORT);
// Default tile-size for large layers.
result = layer->CalculateTileSize(gfx::Size(10000, 10000));
@@ -4725,15 +5060,19 @@ TEST_F(TileSizeTest, TileSizes) {
// Gpu-rasterization uses 25% viewport-height tiles.
// The +2's below are for border texels.
- host_impl_.SetUseGpuRasterization(true);
+ host_impl_.SetHasGpuRasterizationTrigger(true);
+ EXPECT_EQ(host_impl_.gpu_rasterization_status(), GpuRasterizationStatus::ON);
host_impl_.SetViewportSize(gfx::Size(2000, 2000));
+
+ layer->set_gpu_raster_max_texture_size(host_impl_.device_viewport_size());
result = layer->CalculateTileSize(gfx::Size(10000, 10000));
- EXPECT_EQ(result.width(), 2000);
+ EXPECT_EQ(result.width(), 2000 + 2 * PictureLayerTiling::kBorderTexels);
EXPECT_EQ(result.height(), 500 + 2);
// Clamp and round-up, when smaller than viewport.
// Tile-height doubles to 50% when width shrinks to <= 50%.
host_impl_.SetViewportSize(gfx::Size(1000, 1000));
+ layer->set_gpu_raster_max_texture_size(host_impl_.device_viewport_size());
result = layer->CalculateTileSize(gfx::Size(447, 10000));
EXPECT_EQ(result.width(), 448);
EXPECT_EQ(result.height(), 500 + 2);
diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc
index ca622aa3c0b..37070127a77 100644
--- a/chromium/cc/layers/picture_layer_unittest.cc
+++ b/chromium/cc/layers/picture_layer_unittest.cc
@@ -4,10 +4,12 @@
#include "cc/layers/picture_layer.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/picture_layer_impl.h"
#include "cc/resources/resource_update_queue.h"
#include "cc/test/fake_layer_tree_host.h"
+#include "cc/test/fake_picture_layer.h"
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/fake_proxy.h"
#include "cc/test/impl_side_painting_settings.h"
@@ -20,11 +22,15 @@ namespace {
class MockContentLayerClient : public ContentLayerClient {
public:
- void PaintContents(
- SkCanvas* canvas,
+ void PaintContents(SkCanvas* canvas,
+ const gfx::Rect& clip,
+ PaintingControlSetting picture_control) override {}
+ void PaintContentsToDisplayList(
+ DisplayItemList* display_list,
const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus gc_status) override {}
- void DidChangeLayerCanUseLCDText() override {}
+ PaintingControlSetting picture_control) override {
+ NOTIMPLEMENTED();
+ }
bool FillsBoundsCompletely() const override { return false; };
};
@@ -57,8 +63,8 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
DebugScopedSetImplThread impl_thread(&proxy);
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(
- ImplSidePaintingSettings(), &proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(ImplSidePaintingSettings(), &proxy,
+ &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
scoped_ptr<FakePictureLayerImpl> layer_impl =
FakePictureLayerImpl::Create(host_impl.pending_tree(), 1);
@@ -66,23 +72,26 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
layer->PushPropertiesTo(layer_impl.get());
EXPECT_FALSE(layer_impl->CanHaveTilings());
EXPECT_TRUE(layer_impl->bounds() == gfx::Size(0, 0));
- EXPECT_EQ(gfx::Size(), layer_impl->pile()->tiling_size());
- EXPECT_FALSE(layer_impl->pile()->HasRecordings());
+ EXPECT_EQ(gfx::Size(), layer_impl->raster_source()->GetSize());
+ EXPECT_FALSE(layer_impl->raster_source()->HasRecordings());
}
}
TEST(PictureLayerTest, SuitableForGpuRasterization) {
MockContentLayerClient client;
scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
- PicturePile* pile = layer->GetPicturePileForTesting();
+ FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client);
+ host->SetRootLayer(layer);
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
// Layer is suitable for gpu rasterization by default.
- EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
// Veto gpu rasterization.
- pile->SetUnsuitableForGpuRasterizationForTesting();
- EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+ recording_source->SetUnsuitableForGpuRasterizationForTesting();
+ EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
}
@@ -98,10 +107,67 @@ TEST(PictureLayerTest, UseTileGridSize) {
host->SetRootLayer(layer);
// Tile-grid is set according to its setting.
- SkTileGridFactory::TileGridInfo info =
- layer->GetPicturePileForTesting()->GetTileGridInfoForTesting();
- EXPECT_EQ(info.fTileInterval.width(), 123 - 2 * info.fMargin.width());
- EXPECT_EQ(info.fTileInterval.height(), 123 - 2 * info.fMargin.height());
+ gfx::Size size =
+ layer->GetRecordingSourceForTesting()->GetTileGridSizeForTesting();
+ EXPECT_EQ(size.width(), 123);
+ EXPECT_EQ(size.height(), 123);
+}
+
+// PicturePile uses the source frame number as a unit for measuring invalidation
+// frequency. When a pile moves between compositors, the frame number increases
+// non-monotonically. This executes that code path under this scenario allowing
+// for the code to verify correctness with DCHECKs.
+TEST(PictureLayerTest, NonMonotonicSourceFrameNumber) {
+ LayerTreeSettings settings;
+ settings.single_thread_proxy_scheduler = false;
+
+ FakeLayerTreeHostClient host_client1(FakeLayerTreeHostClient::DIRECT_3D);
+ FakeLayerTreeHostClient host_client2(FakeLayerTreeHostClient::DIRECT_3D);
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+
+ MockContentLayerClient client;
+ scoped_refptr<FakePictureLayer> layer = FakePictureLayer::Create(&client);
+
+ LayerTreeHost::InitParams params;
+ params.client = &host_client1;
+ params.shared_bitmap_manager = shared_bitmap_manager.get();
+ params.settings = &settings;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ scoped_ptr<LayerTreeHost> host1 =
+ LayerTreeHost::CreateSingleThreaded(&host_client1, &params);
+ host_client1.SetLayerTreeHost(host1.get());
+
+ params.client = &host_client2;
+ scoped_ptr<LayerTreeHost> host2 =
+ LayerTreeHost::CreateSingleThreaded(&host_client2, &params);
+ host_client2.SetLayerTreeHost(host2.get());
+
+ // The PictureLayer is put in one LayerTreeHost.
+ host1->SetRootLayer(layer);
+ // Do a main frame, record the picture layers.
+ EXPECT_EQ(0u, layer->update_count());
+ layer->SetNeedsDisplay();
+ host1->Composite(base::TimeTicks::Now());
+ EXPECT_EQ(1u, layer->update_count());
+ EXPECT_EQ(1, host1->source_frame_number());
+
+ // The source frame number in |host1| is now higher than host2.
+ layer->SetNeedsDisplay();
+ host1->Composite(base::TimeTicks::Now());
+ EXPECT_EQ(2u, layer->update_count());
+ EXPECT_EQ(2, host1->source_frame_number());
+
+ // Then moved to another LayerTreeHost.
+ host1->SetRootLayer(nullptr);
+ host2->SetRootLayer(layer);
+
+ // Do a main frame, record the picture layers. The frame number has changed
+ // non-monotonically.
+ layer->SetNeedsDisplay();
+ host2->Composite(base::TimeTicks::Now());
+ EXPECT_EQ(3u, layer->update_count());
+ EXPECT_EQ(1, host2->source_frame_number());
}
} // namespace
diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc
index 9d36235bece..2ca1241f719 100644
--- a/chromium/cc/layers/render_surface_impl.cc
+++ b/chromium/cc/layers/render_surface_impl.cc
@@ -18,7 +18,7 @@
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/shared_quad_state.h"
#include "cc/trees/damage_tracker.h"
-#include "cc/trees/occlusion_tracker.h"
+#include "cc/trees/occlusion.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/transform.h"
@@ -53,6 +53,23 @@ gfx::RectF RenderSurfaceImpl::DrawableContentRect() const {
return drawable_content_rect;
}
+SkColor RenderSurfaceImpl::GetDebugBorderColor() const {
+ return DebugColors::SurfaceBorderColor();
+}
+
+SkColor RenderSurfaceImpl::GetReplicaDebugBorderColor() const {
+ return DebugColors::SurfaceReplicaBorderColor();
+}
+
+float RenderSurfaceImpl::GetDebugBorderWidth() const {
+ return DebugColors::SurfaceBorderWidth(owning_layer_->layer_tree_impl());
+}
+
+float RenderSurfaceImpl::GetReplicaDebugBorderWidth() const {
+ return DebugColors::SurfaceReplicaBorderWidth(
+ owning_layer_->layer_tree_impl());
+}
+
int RenderSurfaceImpl::OwningLayerId() const {
return owning_layer_ ? owning_layer_->id() : 0;
}
@@ -132,71 +149,39 @@ void RenderSurfaceImpl::AppendRenderPasses(RenderPassSink* pass_sink) {
pass_sink->AppendRenderPass(pass.Pass());
}
-void RenderSurfaceImpl::AppendQuads(
- RenderPass* render_pass,
- const OcclusionTracker<LayerImpl>& occlusion_tracker,
- AppendQuadsData* append_quads_data,
- bool for_replica,
- RenderPassId render_pass_id) {
- DCHECK(!for_replica || owning_layer_->has_replica());
-
- const gfx::Transform& draw_transform =
- for_replica ? replica_draw_transform_ : draw_transform_;
+void RenderSurfaceImpl::AppendQuads(RenderPass* render_pass,
+ const gfx::Transform& draw_transform,
+ const Occlusion& occlusion_in_content_space,
+ SkColor debug_border_color,
+ float debug_border_width,
+ LayerImpl* mask_layer,
+ AppendQuadsData* append_quads_data,
+ RenderPassId render_pass_id) {
gfx::Rect visible_content_rect =
- occlusion_tracker.UnoccludedContributingSurfaceContentRect(
- content_rect_, draw_transform);
+ occlusion_in_content_space.GetUnoccludedContentRect(content_rect_);
if (visible_content_rect.IsEmpty())
return;
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->SetAll(draw_transform,
- content_rect_.size(),
- content_rect_,
- clip_rect_,
- is_clipped_,
- draw_opacity_,
+ shared_quad_state->SetAll(draw_transform, content_rect_.size(), content_rect_,
+ clip_rect_, is_clipped_, draw_opacity_,
owning_layer_->blend_mode(),
owning_layer_->sorting_context_id());
if (owning_layer_->ShowDebugBorders()) {
- SkColor color = for_replica ?
- DebugColors::SurfaceReplicaBorderColor() :
- DebugColors::SurfaceBorderColor();
- float width = for_replica ?
- DebugColors::SurfaceReplicaBorderWidth(
- owning_layer_->layer_tree_impl()) :
- DebugColors::SurfaceBorderWidth(
- owning_layer_->layer_tree_impl());
DebugBorderDrawQuad* debug_border_quad =
render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
- debug_border_quad->SetNew(
- shared_quad_state, content_rect_, visible_content_rect, color, width);
- }
-
- // TODO(shawnsingh): By using the same RenderSurfaceImpl for both the content
- // and its reflection, it's currently not possible to apply a separate mask to
- // the reflection layer or correctly handle opacity in reflections (opacity
- // must be applied after drawing both the layer and its reflection). The
- // solution is to introduce yet another RenderSurfaceImpl to draw the layer
- // and its reflection in. For now we only apply a separate reflection mask if
- // the contents don't have a mask of their own.
- LayerImpl* mask_layer = owning_layer_->mask_layer();
- if (mask_layer &&
- (!mask_layer->DrawsContent() || mask_layer->bounds().IsEmpty()))
- mask_layer = nullptr;
-
- if (!mask_layer && for_replica) {
- mask_layer = owning_layer_->replica_layer()->mask_layer();
- if (mask_layer &&
- (!mask_layer->DrawsContent() || mask_layer->bounds().IsEmpty()))
- mask_layer = nullptr;
+ debug_border_quad->SetNew(shared_quad_state, content_rect_,
+ visible_content_rect, debug_border_color,
+ debug_border_width);
}
ResourceProvider::ResourceId mask_resource_id = 0;
gfx::Size mask_texture_size;
gfx::Vector2dF mask_uv_scale;
- if (mask_layer) {
+ if (mask_layer && mask_layer->DrawsContent() &&
+ !mask_layer->bounds().IsEmpty()) {
mask_layer->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
gfx::Vector2dF owning_layer_draw_scale =
MathUtil::ComputeTransform2dScaleComponents(
diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h
index 3303e94a48b..2035e28b127 100644
--- a/chromium/cc/layers/render_surface_impl.h
+++ b/chromium/cc/layers/render_surface_impl.h
@@ -14,6 +14,7 @@
#include "cc/layers/layer_lists.h"
#include "cc/quads/render_pass.h"
#include "cc/quads/shared_quad_state.h"
+#include "cc/trees/occlusion.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/transform.h"
@@ -22,8 +23,7 @@ namespace cc {
class DamageTracker;
class DelegatedRendererLayerImpl;
-template <typename LayerType>
-class OcclusionTracker;
+class Occlusion;
class RenderPassId;
class RenderPassSink;
class LayerImpl;
@@ -60,6 +60,12 @@ class CC_EXPORT RenderSurfaceImpl {
}
bool draw_opacity_is_animating() const { return draw_opacity_is_animating_; }
+ SkColor GetDebugBorderColor() const;
+ SkColor GetReplicaDebugBorderColor() const;
+
+ float GetDebugBorderWidth() const;
+ float GetReplicaDebugBorderWidth() const;
+
void SetDrawTransform(const gfx::Transform& draw_transform) {
draw_transform_ = draw_transform;
}
@@ -120,6 +126,13 @@ class CC_EXPORT RenderSurfaceImpl {
void SetContentRect(const gfx::Rect& content_rect);
gfx::Rect content_rect() const { return content_rect_; }
+ const Occlusion& occlusion_in_content_space() const {
+ return occlusion_in_content_space_;
+ }
+ void set_occlusion_in_content_space(const Occlusion& occlusion) {
+ occlusion_in_content_space_ = occlusion;
+ }
+
LayerImplList& layer_list() { return layer_list_; }
void AddContributingDelegatedRenderPassLayer(LayerImpl* layer);
void ClearLayerLists();
@@ -136,9 +149,12 @@ class CC_EXPORT RenderSurfaceImpl {
void AppendRenderPasses(RenderPassSink* pass_sink);
void AppendQuads(RenderPass* render_pass,
- const OcclusionTracker<LayerImpl>& occlusion_tracker,
+ const gfx::Transform& draw_transform,
+ const Occlusion& occlusion_in_content_space,
+ SkColor debug_border_color,
+ float debug_border_width,
+ LayerImpl* mask_layer,
AppendQuadsData* append_quads_data,
- bool for_replica,
RenderPassId render_pass_id);
private:
@@ -166,6 +182,7 @@ class CC_EXPORT RenderSurfaceImpl {
LayerImplList layer_list_;
std::vector<DelegatedRendererLayerImpl*>
contributing_delegated_render_pass_layer_list_;
+ Occlusion occlusion_in_content_space_;
// The nearest ancestor target surface that will contain the contents of this
// surface, and that ignores outside occlusion. This can point to itself.
diff --git a/chromium/cc/layers/render_surface_impl_unittest.cc b/chromium/cc/layers/render_surface_impl_unittest.cc
index 6a96ba31f68..9934cd652ba 100644
--- a/chromium/cc/layers/render_surface_impl_unittest.cc
+++ b/chromium/cc/layers/render_surface_impl_unittest.cc
@@ -20,7 +20,7 @@ TEST(RenderSurfaceLayerImplTest, Occlusion) {
owning_layer_impl->SetBounds(layer_size);
owning_layer_impl->SetContentBounds(layer_size);
owning_layer_impl->SetDrawsContent(true);
- owning_layer_impl->SetForceRenderSurface(true);
+ owning_layer_impl->SetHasRenderSurface(true);
impl.CalcDrawProps(viewport_size);
diff --git a/chromium/cc/layers/render_surface_unittest.cc b/chromium/cc/layers/render_surface_unittest.cc
index 68398fe52e6..929407c4fe5 100644
--- a/chromium/cc/layers/render_surface_unittest.cc
+++ b/chromium/cc/layers/render_surface_unittest.cc
@@ -38,10 +38,10 @@ TEST(RenderSurfaceTest, VerifySurfaceChangesAreTrackedProperly) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> owning_layer =
LayerImpl::Create(host_impl.active_tree(), 1);
- owning_layer->CreateRenderSurface();
+ owning_layer->SetHasRenderSurface(true);
ASSERT_TRUE(owning_layer->render_surface());
RenderSurfaceImpl* render_surface = owning_layer->render_surface();
gfx::Rect test_rect(3, 4, 5, 6);
@@ -83,15 +83,18 @@ TEST(RenderSurfaceTest, VerifySurfaceChangesAreTrackedProperly) {
TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectSharedQuadState) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> root_layer =
LayerImpl::Create(host_impl.active_tree(), 1);
scoped_ptr<LayerImpl> owning_layer =
LayerImpl::Create(host_impl.active_tree(), 2);
- owning_layer->CreateRenderSurface();
+ owning_layer->SetHasRenderSurface(true);
ASSERT_TRUE(owning_layer->render_surface());
owning_layer->draw_properties().render_target = owning_layer.get();
+
+ SkXfermode::Mode blend_mode = SkXfermode::kSoftLight_Mode;
+ owning_layer->SetBlendMode(blend_mode);
RenderSurfaceImpl* render_surface = owning_layer->render_surface();
root_layer->AddChild(owning_layer.Pass());
@@ -99,23 +102,17 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectSharedQuadState) {
gfx::Rect content_rect(0, 0, 50, 50);
gfx::Rect clip_rect(5, 5, 40, 40);
gfx::Transform origin;
-
origin.Translate(30, 40);
- render_surface->SetDrawTransform(origin);
render_surface->SetContentRect(content_rect);
render_surface->SetClipRect(clip_rect);
render_surface->SetDrawOpacity(1.f);
- MockOcclusionTracker<LayerImpl> occlusion_tracker;
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData append_quads_data;
- bool for_replica = false;
- render_surface->AppendQuads(render_pass.get(),
- occlusion_tracker,
- &append_quads_data,
- for_replica,
+ render_surface->AppendQuads(render_pass.get(), origin, Occlusion(),
+ SK_ColorBLACK, 1.f, nullptr, &append_quads_data,
RenderPassId(2, 0));
ASSERT_EQ(1u, render_pass->shared_quad_state_list.size());
@@ -128,9 +125,9 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectSharedQuadState) {
EXPECT_EQ(
40.0,
shared_quad_state->content_to_target_transform.matrix().getDouble(1, 3));
- EXPECT_RECT_EQ(content_rect,
- gfx::Rect(shared_quad_state->visible_content_rect));
+ EXPECT_EQ(content_rect, gfx::Rect(shared_quad_state->visible_content_rect));
EXPECT_EQ(1.f, shared_quad_state->opacity);
+ EXPECT_EQ(blend_mode, shared_quad_state->blend_mode);
}
class TestRenderPassSink : public RenderPassSink {
@@ -150,13 +147,13 @@ class TestRenderPassSink : public RenderPassSink {
TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectRenderPass) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> root_layer =
LayerImpl::Create(host_impl.active_tree(), 1);
scoped_ptr<LayerImpl> owning_layer =
LayerImpl::Create(host_impl.active_tree(), 2);
- owning_layer->CreateRenderSurface();
+ owning_layer->SetHasRenderSurface(true);
ASSERT_TRUE(owning_layer->render_surface());
owning_layer->draw_properties().render_target = owning_layer.get();
RenderSurfaceImpl* render_surface = owning_layer->render_surface();
@@ -178,7 +175,7 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectRenderPass) {
RenderPass* pass = pass_sink.RenderPasses()[0];
EXPECT_EQ(RenderPassId(2, 0), pass->id);
- EXPECT_RECT_EQ(content_rect, pass->output_rect);
+ EXPECT_EQ(content_rect, pass->output_rect);
EXPECT_EQ(origin, pass->transform_to_root_target);
}
diff --git a/chromium/cc/layers/scroll_blocks_on.h b/chromium/cc/layers/scroll_blocks_on.h
new file mode 100644
index 00000000000..f41e7fdd20f
--- /dev/null
+++ b/chromium/cc/layers/scroll_blocks_on.h
@@ -0,0 +1,26 @@
+// 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_LAYERS_SCROLL_BLOCKS_ON_H_
+#define CC_LAYERS_SCROLL_BLOCKS_ON_H_
+
+enum ScrollBlocksOn {
+ SCROLL_BLOCKS_ON_NONE = 0x0,
+ SCROLL_BLOCKS_ON_START_TOUCH = 0x1,
+ SCROLL_BLOCKS_ON_WHEEL_EVENT = 0x2,
+ SCROLL_BLOCKS_ON_SCROLL_EVENT = 0x4,
+ SCROLL_BLOCKS_ON_MAX = SCROLL_BLOCKS_ON_START_TOUCH |
+ SCROLL_BLOCKS_ON_WHEEL_EVENT |
+ SCROLL_BLOCKS_ON_SCROLL_EVENT
+};
+
+inline ScrollBlocksOn operator|(ScrollBlocksOn a, ScrollBlocksOn b) {
+ return ScrollBlocksOn(static_cast<int>(a) | static_cast<int>(b));
+}
+
+inline ScrollBlocksOn& operator|=(ScrollBlocksOn& a, ScrollBlocksOn b) {
+ return a = a | b;
+}
+
+#endif // CC_LAYERS_SCROLL_BLOCKS_ON_H_
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.cc b/chromium/cc/layers/scrollbar_layer_impl_base.cc
index 4248617f5bc..35e716bdbd8 100644
--- a/chromium/cc/layers/scrollbar_layer_impl_base.cc
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.cc
@@ -33,8 +33,10 @@ ScrollbarLayerImplBase::~ScrollbarLayerImplBase() {}
void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) {
float active_opacity = layer->opacity();
+ bool active_hidden = layer->hide_layer_and_subtree();
LayerImpl::PushPropertiesTo(layer);
layer->SetOpacity(active_opacity);
+ layer->SetHideLayerAndSubtree(active_hidden);
DCHECK(layer->ToScrollbarLayer());
layer->ToScrollbarLayer()->set_is_overlay_scrollbar(is_overlay_scrollbar_);
PushScrollClipPropertiesTo(layer);
@@ -69,11 +71,7 @@ void RegisterScrollbarWithLayers(ScrollbarLayerImplBase* scrollbar,
for (LayerImpl* current_layer = scroll_layer;
current_layer && current_layer != container_layer->parent();
current_layer = current_layer->parent()) {
- // TODO(wjmaclean) We shouldn't need to exempt the scroll_layer from the
- // scrollable() test below. https://crbug.com/367858.
- if (current_layer->scrollable() || current_layer == container_layer ||
- current_layer == scroll_layer)
- (current_layer->*operation)(scrollbar);
+ (current_layer->*operation)(scrollbar);
}
}
} // namespace
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.h b/chromium/cc/layers/scrollbar_layer_impl_base.h
index 4a96b49028f..d905c88f8c7 100644
--- a/chromium/cc/layers/scrollbar_layer_impl_base.h
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.h
@@ -51,6 +51,7 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
void PushScrollClipPropertiesTo(LayerImpl* layer);
bool SetVisibleToTotalLengthRatio(float ratio);
+ // Thumb quad rect in layer space.
virtual gfx::Rect ComputeThumbQuadRect() const;
float thumb_thickness_scale_factor() {
diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc
index 25fa7080c1e..97d1c80a992 100644
--- a/chromium/cc/layers/scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/scrollbar_layer_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/containers/hash_tables.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/animation/scrollbar_animation_controller.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/painted_scrollbar_layer.h"
@@ -21,6 +22,7 @@
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/mock_occlusion_tracker.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
@@ -59,12 +61,89 @@ LayerImpl* LayerImplForScrollAreaAndScrollbar(FakeLayerTreeHost* host,
return host->CommitAndCreateLayerImplTree();
}
-TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
- FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
- scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
+class FakeResourceTrackingLayerTreeHost : public FakeLayerTreeHost {
+ public:
+ FakeResourceTrackingLayerTreeHost(FakeLayerTreeHostClient* client,
+ LayerTreeHost::InitParams* params)
+ : FakeLayerTreeHost(client, params),
+ next_id_(1),
+ total_ui_resource_created_(0),
+ total_ui_resource_deleted_(0) {
+ InitializeSingleThreaded(client, base::ThreadTaskRunnerHandle::Get(),
+ nullptr);
+ }
+
+ UIResourceId CreateUIResource(UIResourceClient* content) override {
+ total_ui_resource_created_++;
+ UIResourceId nid = next_id_++;
+ ui_resource_bitmap_map_.insert(
+ std::make_pair(nid, content->GetBitmap(nid, false)));
+ return nid;
+ }
+
+ // Deletes a UI resource. May safely be called more than once.
+ void DeleteUIResource(UIResourceId id) override {
+ UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+ if (iter != ui_resource_bitmap_map_.end()) {
+ ui_resource_bitmap_map_.erase(iter);
+ total_ui_resource_deleted_++;
+ }
+ }
+
+ size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); }
+ int TotalUIResourceDeleted() { return total_ui_resource_deleted_; }
+ int TotalUIResourceCreated() { return total_ui_resource_created_; }
+
+ gfx::Size ui_resource_size(UIResourceId id) {
+ UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+ if (iter != ui_resource_bitmap_map_.end())
+ return iter->second.GetSize();
+ return gfx::Size();
+ }
+
+ UIResourceBitmap* ui_resource_bitmap(UIResourceId id) {
+ UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+ if (iter != ui_resource_bitmap_map_.end())
+ return &iter->second;
+ return nullptr;
+ }
+
+ private:
+ using UIResourceBitmapMap = base::hash_map<UIResourceId, UIResourceBitmap>;
+ UIResourceBitmapMap ui_resource_bitmap_map_;
+
+ int next_id_;
+ int total_ui_resource_created_;
+ int total_ui_resource_deleted_;
+};
+
+class ScrollbarLayerTest : public testing::Test {
+ public:
+ ScrollbarLayerTest() : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {
+ layer_tree_settings_.single_thread_proxy_scheduler = false;
+
+ LayerTreeHost::InitParams params;
+ params.client = &fake_client_;
+ params.settings = &layer_tree_settings_;
+
+ layer_tree_host_.reset(
+ new FakeResourceTrackingLayerTreeHost(&fake_client_, &params));
+ fake_client_.SetLayerTreeHost(layer_tree_host_.get());
+ // Force output surface creation for renderer capabilities.
+ layer_tree_host_->Composite(base::TimeTicks());
+ EXPECT_FALSE(layer_tree_host_->output_surface_lost());
+ }
+
+ protected:
+ FakeLayerTreeHostClient fake_client_;
+ LayerTreeSettings layer_tree_settings_;
+ scoped_ptr<FakeResourceTrackingLayerTreeHost> layer_tree_host_;
+};
+
+TEST_F(ScrollbarLayerTest, ResolveScrollLayerPointer) {
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), false, false, 0, 0);
+ layer_tree_host_.get(), scrollbar.Pass(), false, false, 0, 0);
LayerImpl* cc_child1 = layer_impl_tree_root->children()[0];
PaintedScrollbarLayerImpl* cc_child2 =
@@ -75,12 +154,10 @@ TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
EXPECT_EQ(*(cc_child1->scrollbars()->begin()), cc_child2);
}
-TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
- FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
- scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
+TEST_F(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), true, false, 0, 0);
+ layer_tree_host_.get(), scrollbar.Pass(), true, false, 0, 0);
PaintedScrollbarLayerImpl* cc_child1 =
static_cast<PaintedScrollbarLayerImpl*>(
@@ -91,14 +168,11 @@ TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
EXPECT_EQ(*(cc_child2->scrollbars()->begin()), cc_child1);
}
-TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
- FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
- scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
-
+TEST_F(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
// Create and attach a non-overlay scrollbar.
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), false, false, 0, 0);
+ layer_tree_host_.get(), scrollbar.Pass(), false, false, 0, 0);
PaintedScrollbarLayerImpl* scrollbar_layer_impl =
static_cast<PaintedScrollbarLayerImpl*>(
layer_impl_tree_root->children()[1]);
@@ -106,29 +180,28 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
// When the scrollbar is not an overlay scrollbar, the scroll should be
// responded to on the main thread as the compositor does not yet implement
// scrollbar scrolling.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- scrollbar_layer_impl->TryScroll(gfx::Point(0, 0),
- InputHandler::Gesture));
+ EXPECT_EQ(
+ InputHandler::SCROLL_ON_MAIN_THREAD,
+ scrollbar_layer_impl->TryScroll(gfx::Point(0, 0), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
// Create and attach an overlay scrollbar.
scrollbar.reset(new FakeScrollbar(false, false, true));
layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), false, false, 0, 0);
+ layer_tree_host_.get(), scrollbar.Pass(), false, false, 0, 0);
scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
layer_impl_tree_root->children()[1]);
// The user shouldn't be able to drag an overlay scrollbar and the scroll
// may be handled in the compositor.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- scrollbar_layer_impl->TryScroll(gfx::Point(0, 0),
- InputHandler::Gesture));
+ EXPECT_EQ(
+ InputHandler::SCROLL_IGNORED,
+ scrollbar_layer_impl->TryScroll(gfx::Point(0, 0), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
}
-TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
- FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
- scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
-
+TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) {
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_layer = Layer::Create();
@@ -143,7 +216,7 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
scroll_layer->SetBounds(gfx::Size(100, 200));
content_layer->SetBounds(gfx::Size(100, 200));
- host->SetRootLayer(layer_tree_root);
+ layer_tree_host_->SetRootLayer(layer_tree_root);
layer_tree_root->AddChild(scroll_layer);
scroll_layer->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
@@ -153,7 +226,8 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
layer_tree_root->SavePaintProperties();
content_layer->SavePaintProperties();
- LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
+ LayerImpl* layer_impl_tree_root =
+ layer_tree_host_->CommitAndCreateLayerImplTree();
ScrollbarLayerImplBase* cc_scrollbar_layer =
static_cast<PaintedScrollbarLayerImpl*>(
@@ -172,7 +246,7 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
ScrollbarAnimationController* scrollbar_controller =
layer_impl_tree_root->scrollbar_animation_controller();
- layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
+ layer_impl_tree_root = layer_tree_host_->CommitAndCreateLayerImplTree();
EXPECT_EQ(scrollbar_controller,
layer_impl_tree_root->scrollbar_animation_controller());
@@ -186,19 +260,18 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
EXPECT_EQ(300, cc_scrollbar_layer->maximum());
}
-#define UPDATE_AND_EXTRACT_LAYER_POINTERS() \
- do { \
- scrollbar_layer->UpdateThumbAndTrackGeometry(); \
- root_clip_layer_impl = host->CommitAndCreateLayerImplTree(); \
- root_layer_impl = root_clip_layer_impl->children()[0]; \
- scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \
- root_layer_impl->children()[1]); \
- scrollbar_layer_impl->ScrollbarParametersDidChange(false); \
+#define UPDATE_AND_EXTRACT_LAYER_POINTERS() \
+ do { \
+ scrollbar_layer->UpdateInternalContentScale(); \
+ scrollbar_layer->UpdateThumbAndTrackGeometry(); \
+ root_clip_layer_impl = layer_tree_host_->CommitAndCreateLayerImplTree(); \
+ root_layer_impl = root_clip_layer_impl->children()[0]; \
+ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \
+ root_layer_impl->children()[1]); \
+ scrollbar_layer_impl->ScrollbarParametersDidChange(false); \
} while (false)
-TEST(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
- FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
- scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
+TEST_F(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
scoped_refptr<Layer> root_clip_layer = Layer::Create();
scoped_refptr<Layer> root_layer = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
@@ -211,7 +284,7 @@ TEST(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
root_layer->SetBounds(gfx::Size(100, 50));
content_layer->SetBounds(gfx::Size(100, 50));
- host->SetRootLayer(root_clip_layer);
+ layer_tree_host_->SetRootLayer(root_clip_layer);
root_clip_layer->AddChild(root_layer);
root_layer->AddChild(content_layer);
root_layer->AddChild(scrollbar_layer);
@@ -224,8 +297,6 @@ TEST(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
-
- scrollbar_layer->UpdateThumbAndTrackGeometry();
LayerImpl* root_clip_layer_impl = nullptr;
LayerImpl* root_layer_impl = nullptr;
PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
@@ -241,9 +312,7 @@ TEST(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
}
-TEST(ScrollbarLayerTest, ThumbRect) {
- FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
- scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
+TEST_F(ScrollbarLayerTest, ThumbRect) {
scoped_refptr<Layer> root_clip_layer = Layer::Create();
scoped_refptr<Layer> root_layer = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
@@ -256,7 +325,7 @@ TEST(ScrollbarLayerTest, ThumbRect) {
root_layer->SetBounds(gfx::Size(100, 50));
content_layer->SetBounds(gfx::Size(100, 50));
- host->SetRootLayer(root_clip_layer);
+ layer_tree_host_->SetRootLayer(root_clip_layer);
root_clip_layer->AddChild(root_layer);
root_layer->AddChild(content_layer);
root_layer->AddChild(scrollbar_layer);
@@ -269,7 +338,6 @@ TEST(ScrollbarLayerTest, ThumbRect) {
scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
- scrollbar_layer->UpdateThumbAndTrackGeometry();
LayerImpl* root_clip_layer_impl = nullptr;
LayerImpl* root_layer_impl = nullptr;
PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
@@ -322,19 +390,15 @@ TEST(ScrollbarLayerTest, ThumbRect) {
scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
}
-TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
+TEST_F(ScrollbarLayerTest, SolidColorDrawQuads) {
const int kThumbThickness = 3;
const int kTrackStart = 1;
const int kTrackLength = 100;
- FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
- LayerTreeSettings layer_tree_settings;
- scoped_ptr<FakeLayerTreeHost> host =
- FakeLayerTreeHost::Create(&client, layer_tree_settings);
-
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), false, true, kThumbThickness, kTrackStart);
+ layer_tree_host_.get(), scrollbar.Pass(), false, true, kThumbThickness,
+ kTrackStart);
ScrollbarLayerImplBase* scrollbar_layer_impl =
static_cast<SolidColorScrollbarLayerImpl*>(
layer_impl_tree_root->children()[1]);
@@ -347,12 +411,12 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
{
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+ scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
const QuadList& quads = render_pass->quad_list;
ASSERT_EQ(1u, quads.size());
EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
- EXPECT_RECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect);
+ EXPECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect);
}
// Contents scale should scale the draw quad.
@@ -361,12 +425,12 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
{
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+ scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
const QuadList& quads = render_pass->quad_list;
ASSERT_EQ(1u, quads.size());
EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
- EXPECT_RECT_EQ(gfx::Rect(12, 0, 78, 6), quads.front()->rect);
+ EXPECT_EQ(gfx::Rect(12, 0, 78, 6), quads.front()->rect);
}
scrollbar_layer_impl->draw_properties().contents_scale_x = 1.f;
scrollbar_layer_impl->draw_properties().contents_scale_y = 1.f;
@@ -377,12 +441,12 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
{
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+ scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
const QuadList& quads = render_pass->quad_list;
ASSERT_EQ(1u, quads.size());
EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
- EXPECT_RECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect);
+ EXPECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect);
}
// We shouldn't attempt div-by-zero when the maximum is zero.
@@ -391,25 +455,20 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
{
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+ scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
const QuadList& quads = render_pass->quad_list;
ASSERT_EQ(1u, quads.size());
EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
- EXPECT_RECT_EQ(gfx::Rect(1, 0, 19, 3), quads.front()->rect);
+ EXPECT_EQ(gfx::Rect(1, 0, 19, 3), quads.front()->rect);
}
}
-TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
+TEST_F(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
const int kThumbThickness = 3;
const int kTrackStart = 0;
const int kTrackLength = 10;
- FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
- LayerTreeSettings layer_tree_settings;
- scoped_ptr<FakeLayerTreeHost> host =
- FakeLayerTreeHost::Create(&client, layer_tree_settings);
-
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
{
@@ -429,9 +488,10 @@ TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
scroll_layer->AddChild(child1);
scroll_layer->InsertChild(child2, 1);
layer_tree_root->AddChild(scroll_layer);
- host->SetRootLayer(layer_tree_root);
+ layer_tree_host_->SetRootLayer(layer_tree_root);
}
- LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
+ LayerImpl* layer_impl_tree_root =
+ layer_tree_host_->CommitAndCreateLayerImplTree();
LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0];
ScrollbarLayerImplBase* scrollbar_layer_impl =
@@ -450,12 +510,12 @@ TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+ scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
const QuadList& quads = render_pass->quad_list;
ASSERT_EQ(1u, quads.size());
EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
- EXPECT_RECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect);
+ EXPECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect);
}
}
@@ -463,8 +523,9 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test {
public:
ScrollbarLayerSolidColorThumbTest() {
LayerTreeSettings layer_tree_settings;
- host_impl_.reset(new FakeLayerTreeHostImpl(
- layer_tree_settings, &proxy_, &shared_bitmap_manager_));
+ host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_));
const int kThumbThickness = 3;
const int kTrackStart = 0;
@@ -492,6 +553,7 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test {
protected:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
scoped_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer_;
scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer_;
@@ -544,10 +606,10 @@ TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) {
layers[0]->SetBounds(gfx::Size(100, 3));
layers[1]->SetBounds(gfx::Size(3, 100));
- EXPECT_RECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f),
- horizontal_scrollbar_layer_->ComputeThumbQuadRect());
- EXPECT_RECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f),
- vertical_scrollbar_layer_->ComputeThumbQuadRect());
+ EXPECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f),
+ horizontal_scrollbar_layer_->ComputeThumbQuadRect());
+ EXPECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f),
+ vertical_scrollbar_layer_->ComputeThumbQuadRect());
horizontal_scrollbar_layer_->SetVerticalAdjust(10.f);
vertical_scrollbar_layer_->SetVerticalAdjust(10.f);
@@ -556,10 +618,10 @@ TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) {
// 1.) Moves the horizontal scrollbar down
// 2.) Increases the vertical scrollbar's effective track length which both
// increases the thumb's length and its position within the track.
- EXPECT_RECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f),
- horizontal_scrollbar_layer_->ComputeThumbQuadRect());
- EXPECT_RECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f),
- vertical_scrollbar_layer_->ComputeThumbQuadRect());
+ EXPECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f),
+ horizontal_scrollbar_layer_->ComputeThumbQuadRect());
+ EXPECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f),
+ vertical_scrollbar_layer_->ComputeThumbQuadRect());
}
class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
@@ -578,6 +640,7 @@ class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
scrollbar_layer_->SetScrollLayer(scroll_layer_->id());
scrollbar_layer_->SetLayerTreeHost(layer_tree_host());
scrollbar_layer_->SetBounds(bounds_);
+ scrollbar_layer_->SetIsDrawable(true);
layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
PostSetNeedsCommitToMainThread();
@@ -590,9 +653,9 @@ class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
// Check first that we're actually testing something.
EXPECT_GT(scrollbar_layer_->bounds().width(), kMaxTextureSize);
- EXPECT_EQ(scrollbar_layer_->content_bounds().width(),
+ EXPECT_EQ(scrollbar_layer_->internal_content_bounds().width(),
kMaxTextureSize - 1);
- EXPECT_EQ(scrollbar_layer_->content_bounds().height(),
+ EXPECT_EQ(scrollbar_layer_->internal_content_bounds().height(),
kMaxTextureSize - 1);
EndTest();
@@ -624,75 +687,13 @@ TEST_F(ScrollbarLayerTestMaxTextureSize, DelegatingRenderer) {
RunTest(true, true, true);
}
-class FakeLayerTreeHost : public LayerTreeHost {
- public:
- FakeLayerTreeHost(FakeLayerTreeHostClient* client,
- const LayerTreeSettings& settings)
- : LayerTreeHost(client, nullptr, nullptr, settings),
- next_id_(1),
- total_ui_resource_created_(0),
- total_ui_resource_deleted_(0) {
- InitializeSingleThreaded(client, base::MessageLoopProxy::current());
- }
-
- UIResourceId CreateUIResource(UIResourceClient* content) override {
- total_ui_resource_created_++;
- UIResourceId nid = next_id_++;
- ui_resource_bitmap_map_.insert(
- std::make_pair(nid, content->GetBitmap(nid, false)));
- return nid;
- }
-
- // Deletes a UI resource. May safely be called more than once.
- void DeleteUIResource(UIResourceId id) override {
- UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
- if (iter != ui_resource_bitmap_map_.end()) {
- ui_resource_bitmap_map_.erase(iter);
- total_ui_resource_deleted_++;
- }
- }
-
- size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); }
- int TotalUIResourceDeleted() { return total_ui_resource_deleted_; }
- int TotalUIResourceCreated() { return total_ui_resource_created_; }
-
- gfx::Size ui_resource_size(UIResourceId id) {
- UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
- if (iter != ui_resource_bitmap_map_.end())
- return iter->second.GetSize();
- return gfx::Size();
- }
-
- UIResourceBitmap* ui_resource_bitmap(UIResourceId id) {
- UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
- if (iter != ui_resource_bitmap_map_.end())
- return &iter->second;
- return nullptr;
- }
-
- private:
- typedef base::hash_map<UIResourceId, UIResourceBitmap>
- UIResourceBitmapMap;
- UIResourceBitmapMap ui_resource_bitmap_map_;
-
- int next_id_;
- int total_ui_resource_created_;
- int total_ui_resource_deleted_;
-};
-
-class ScrollbarLayerTestResourceCreationAndRelease : public testing::Test {
+class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
public:
- ScrollbarLayerTestResourceCreationAndRelease()
- : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
-
void TestResourceUpload(int num_updates,
size_t expected_resources,
int expected_created,
int expected_deleted,
bool use_solid_color_scrollbar) {
- layer_tree_host_.reset(
- new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
-
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false));
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
@@ -747,22 +748,18 @@ class ScrollbarLayerTestResourceCreationAndRelease : public testing::Test {
scrollbar_layer->ClearRenderSurface();
}
-
- protected:
- FakeLayerTreeHostClient fake_client_;
- LayerTreeSettings layer_tree_settings_;
- scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
};
TEST_F(ScrollbarLayerTestResourceCreationAndRelease, ResourceUpload) {
bool use_solid_color_scrollbars = false;
TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
int num_updates[3] = {1, 5, 10};
+ int created = 0;
+ int deleted = 0;
for (int j = 0; j < 3; j++) {
- TestResourceUpload(num_updates[j],
- 2,
- num_updates[j] * 2,
- (num_updates[j] - 1) * 2,
+ created += num_updates[j] * 2;
+ deleted = created - 2;
+ TestResourceUpload(num_updates[j], 2, created, deleted,
use_solid_color_scrollbars);
}
}
@@ -775,13 +772,6 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease,
}
TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
- FakeLayerTreeHostClient fake_client_(FakeLayerTreeHostClient::DIRECT_3D);
- LayerTreeSettings layer_tree_settings_;
- scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
-
- layer_tree_host_.reset(
- new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
-
gfx::Point scrollbar_location(0, 185);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
@@ -916,15 +906,9 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
scrollbar_layer->ClearRenderSurface();
}
-class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
+class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
public:
- ScaledScrollbarLayerTestResourceCreation()
- : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
-
void TestResourceUpload(const float test_scale) {
- layer_tree_host_.reset(
- new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
-
gfx::Point scrollbar_location(0, 185);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
@@ -974,20 +958,19 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
gfx::Size thumb_size = layer_tree_host_->ui_resource_size(
scrollbar_layer->thumb_resource_id());
- EXPECT_LE(track_size.width(), scrollbar_layer->content_bounds().width());
- EXPECT_LE(track_size.height(), scrollbar_layer->content_bounds().height());
- EXPECT_LE(thumb_size.width(), scrollbar_layer->content_bounds().width());
- EXPECT_LE(thumb_size.height(), scrollbar_layer->content_bounds().height());
+ EXPECT_LE(track_size.width(),
+ scrollbar_layer->internal_content_bounds().width());
+ EXPECT_LE(track_size.height(),
+ scrollbar_layer->internal_content_bounds().height());
+ EXPECT_LE(thumb_size.width(),
+ scrollbar_layer->internal_content_bounds().width());
+ EXPECT_LE(thumb_size.height(),
+ scrollbar_layer->internal_content_bounds().height());
testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
scrollbar_layer->ClearRenderSurface();
}
-
- protected:
- FakeLayerTreeHostClient fake_client_;
- LayerTreeSettings layer_tree_settings_;
- scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
};
TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
@@ -998,15 +981,9 @@ TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
TestResourceUpload(4.1f);
}
-class ScaledScrollbarLayerTestScaledRasterization : public testing::Test {
+class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
public:
- ScaledScrollbarLayerTestScaledRasterization()
- : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
-
void TestScale(const gfx::Rect scrollbar_rect, const float test_scale) {
- layer_tree_host_.reset(
- new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
-
bool paint_during_update = true;
bool has_thumb = false;
scoped_refptr<Layer> layer_tree_root = Layer::Create();
@@ -1080,10 +1057,6 @@ class ScaledScrollbarLayerTestScaledRasterization : public testing::Test {
(SkColorGetG(c) << SK_G32_SHIFT) |
(SkColorGetB(c) << SK_B32_SHIFT);
}
-
- FakeLayerTreeHostClient fake_client_;
- LayerTreeSettings layer_tree_settings_;
- scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
};
TEST_F(ScaledScrollbarLayerTestScaledRasterization, TestLostPrecisionInClip) {
diff --git a/chromium/cc/layers/solid_color_layer_impl.cc b/chromium/cc/layers/solid_color_layer_impl.cc
index 33766933613..276249744e8 100644
--- a/chromium/cc/layers/solid_color_layer_impl.cc
+++ b/chromium/cc/layers/solid_color_layer_impl.cc
@@ -64,7 +64,6 @@ void SolidColorLayerImpl::AppendSolidQuads(
void SolidColorLayerImpl::AppendQuads(
RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
@@ -75,12 +74,9 @@ void SolidColorLayerImpl::AppendQuads(
// TODO(hendrikw): We need to pass the visible content rect rather than
// |content_bounds()| here.
- AppendSolidQuads(render_pass,
- occlusion_in_content_space,
- shared_quad_state,
- gfx::Rect(content_bounds()),
- background_color(),
- append_quads_data);
+ AppendSolidQuads(render_pass, draw_properties().occlusion_in_content_space,
+ shared_quad_state, gfx::Rect(content_bounds()),
+ background_color(), append_quads_data);
}
const char* SolidColorLayerImpl::LayerTypeAsString() const {
diff --git a/chromium/cc/layers/solid_color_layer_impl.h b/chromium/cc/layers/solid_color_layer_impl.h
index 379348176b3..213e3f13a72 100644
--- a/chromium/cc/layers/solid_color_layer_impl.h
+++ b/chromium/cc/layers/solid_color_layer_impl.h
@@ -30,7 +30,6 @@ class CC_EXPORT SolidColorLayerImpl : public LayerImpl {
// LayerImpl overrides.
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
protected:
diff --git a/chromium/cc/layers/solid_color_layer_impl_unittest.cc b/chromium/cc/layers/solid_color_layer_impl_unittest.cc
index 768fae44f92..f35b82a848d 100644
--- a/chromium/cc/layers/solid_color_layer_impl_unittest.cc
+++ b/chromium/cc/layers/solid_color_layer_impl_unittest.cc
@@ -28,17 +28,17 @@ TEST(SolidColorLayerImplTest, VerifyTilingCompleteAndNoOverlap) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
layer->SetBounds(layer_size);
layer->SetContentBounds(layer_size);
- layer->CreateRenderSurface();
+ layer->SetHasRenderSurface(true);
layer->draw_properties().render_target = layer.get();
AppendQuadsData data;
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
LayerTestCommon::VerifyQuadsExactlyCoverRect(render_pass->quad_list,
visible_content_rect);
@@ -54,18 +54,18 @@ TEST(SolidColorLayerImplTest, VerifyCorrectBackgroundColorInQuad) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
layer->SetBounds(layer_size);
layer->SetContentBounds(layer_size);
layer->SetBackgroundColor(test_color);
- layer->CreateRenderSurface();
+ layer->SetHasRenderSurface(true);
layer->draw_properties().render_target = layer.get();
AppendQuadsData data;
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
ASSERT_EQ(render_pass->quad_list.size(), 1U);
EXPECT_EQ(
@@ -83,18 +83,18 @@ TEST(SolidColorLayerImplTest, VerifyCorrectOpacityInQuad) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
layer->SetBounds(layer_size);
layer->SetContentBounds(layer_size);
layer->draw_properties().opacity = opacity;
- layer->CreateRenderSurface();
+ layer->SetHasRenderSurface(true);
layer->draw_properties().render_target = layer.get();
AppendQuadsData data;
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
ASSERT_EQ(render_pass->quad_list.size(), 1U);
EXPECT_EQ(opacity,
@@ -102,6 +102,31 @@ TEST(SolidColorLayerImplTest, VerifyCorrectOpacityInQuad) {
->opacity());
}
+TEST(SolidColorLayerImplTest, VerifyCorrectBlendModeInQuad) {
+ const SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode;
+
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+
+ gfx::Size layer_size = gfx::Size(100, 100);
+ gfx::Rect visible_content_rect = gfx::Rect(layer_size);
+
+ FakeImplProxy proxy;
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+ scoped_ptr<SolidColorLayerImpl> layer =
+ SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
+ layer->SetBounds(layer_size);
+ layer->SetContentBounds(layer_size);
+ layer->draw_properties().blend_mode = blend_mode;
+
+ AppendQuadsData data;
+ layer->AppendQuads(render_pass.get(), &data);
+
+ ASSERT_EQ(render_pass->quad_list.size(), 1U);
+ EXPECT_EQ(blend_mode,
+ render_pass->quad_list.front()->shared_quad_state->blend_mode);
+}
+
TEST(SolidColorLayerImplTest, VerifyOpaqueRect) {
gfx::Size layer_size = gfx::Size(100, 100);
gfx::Rect visible_content_rect = gfx::Rect(layer_size);
@@ -141,7 +166,7 @@ TEST(SolidColorLayerImplTest, VerifyOpaqueRect) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer_impl->AppendQuads(render_pass.get(), &data);
ASSERT_EQ(render_pass->quad_list.size(), 1U);
EXPECT_EQ(visible_content_rect.ToString(),
@@ -167,7 +192,7 @@ TEST(SolidColorLayerImplTest, VerifyOpaqueRect) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer_impl->AppendQuads(render_pass.get(), &data);
ASSERT_EQ(render_pass->quad_list.size(), 1U);
EXPECT_EQ(gfx::Rect().ToString(),
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
index db6a502e0e6..fa1849e86e8 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
@@ -95,7 +95,6 @@ bool SolidColorScrollbarLayerImpl::IsThumbResizable() const {
void SolidColorScrollbarLayerImpl::AppendQuads(
RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
@@ -106,7 +105,8 @@ void SolidColorScrollbarLayerImpl::AppendQuads(
gfx::Rect thumb_quad_rect(ComputeThumbQuadRect());
gfx::Rect visible_quad_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(thumb_quad_rect);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ thumb_quad_rect);
if (visible_quad_rect.IsEmpty())
return;
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.h b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h
index 1abf552b793..df6179d3ef6 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.h
+++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h
@@ -27,7 +27,6 @@ class CC_EXPORT SolidColorScrollbarLayerImpl : public ScrollbarLayerImplBase {
void PushPropertiesTo(LayerImpl* layer) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
protected:
diff --git a/chromium/cc/layers/surface_layer.cc b/chromium/cc/layers/surface_layer.cc
index ee376aad4e0..67a263229de 100644
--- a/chromium/cc/layers/surface_layer.cc
+++ b/chromium/cc/layers/surface_layer.cc
@@ -4,8 +4,8 @@
#include "cc/layers/surface_layer.h"
-#include "cc/base/swap_promise.h"
#include "cc/layers/surface_layer_impl.h"
+#include "cc/output/swap_promise.h"
#include "cc/trees/layer_tree_host.h"
namespace cc {
@@ -19,6 +19,7 @@ class SatisfySwapPromise : public SwapPromise {
~SatisfySwapPromise() override {}
private:
+ void DidActivate() override {}
void DidSwap(CompositorFrameMetadata* metadata) override {
metadata->satisfies_sequences.push_back(sequence_.sequence);
}
@@ -44,6 +45,7 @@ scoped_refptr<SurfaceLayer> SurfaceLayer::Create(
SurfaceLayer::SurfaceLayer(const SatisfyCallback& satisfy_callback,
const RequireCallback& require_callback)
: Layer(),
+ surface_scale_(1.f),
satisfy_callback_(satisfy_callback),
require_callback_(require_callback) {
}
@@ -53,10 +55,13 @@ SurfaceLayer::~SurfaceLayer() {
DCHECK(destroy_sequence_.is_null());
}
-void SurfaceLayer::SetSurfaceId(SurfaceId surface_id, const gfx::Size& size) {
+void SurfaceLayer::SetSurfaceId(SurfaceId surface_id,
+ float scale,
+ const gfx::Size& size) {
SatisfyDestroySequence();
surface_id_ = surface_id;
surface_size_ = size;
+ surface_scale_ = scale;
CreateNewDestroySequence();
UpdateDrawsContent(HasDrawableContent());
@@ -94,12 +99,8 @@ void SurfaceLayer::CalculateContentsScale(float ideal_contents_scale,
float* contents_scale_y,
gfx::Size* content_bounds) {
*content_bounds = surface_size_;
- *contents_scale_x =
- bounds().IsEmpty() ? 1.f : static_cast<float>(content_bounds->width()) /
- bounds().width();
- *contents_scale_y =
- bounds().IsEmpty() ? 1.f : static_cast<float>(content_bounds->height()) /
- bounds().height();
+ *contents_scale_x = surface_scale_;
+ *contents_scale_y = surface_scale_;
}
void SurfaceLayer::CreateNewDestroySequence() {
diff --git a/chromium/cc/layers/surface_layer.h b/chromium/cc/layers/surface_layer.h
index 29d821f53d3..381369f5c61 100644
--- a/chromium/cc/layers/surface_layer.h
+++ b/chromium/cc/layers/surface_layer.h
@@ -9,7 +9,7 @@
#include "cc/layers/layer.h"
#include "cc/surfaces/surface_id.h"
#include "cc/surfaces/surface_sequence.h"
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
namespace cc {
@@ -30,7 +30,7 @@ class CC_EXPORT SurfaceLayer : public Layer {
const SatisfyCallback& satisfy_callback,
const RequireCallback& require_callback);
- void SetSurfaceId(SurfaceId surface_id, const gfx::Size& size);
+ void SetSurfaceId(SurfaceId surface_id, float scale, const gfx::Size& size);
// Layer overrides.
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -53,6 +53,7 @@ class CC_EXPORT SurfaceLayer : public Layer {
SurfaceId surface_id_;
gfx::Size surface_size_;
+ float surface_scale_;
SurfaceSequence destroy_sequence_;
SatisfyCallback satisfy_callback_;
RequireCallback require_callback_;
diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc
index 4fb9d95cd4e..966112d7f54 100644
--- a/chromium/cc/layers/surface_layer_impl.cc
+++ b/chromium/cc/layers/surface_layer_impl.cc
@@ -4,7 +4,7 @@
#include "cc/layers/surface_layer_impl.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/debug/debug_colors.h"
#include "cc/quads/surface_draw_quad.h"
#include "cc/trees/occlusion.h"
@@ -38,7 +38,6 @@ void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) {
}
void SurfaceLayerImpl::AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
@@ -52,7 +51,8 @@ void SurfaceLayerImpl::AppendQuads(RenderPass* render_pass,
gfx::Rect quad_rect(content_bounds());
gfx::Rect visible_quad_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(quad_rect);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ quad_rect);
if (visible_quad_rect.IsEmpty())
return;
SurfaceDrawQuad* quad =
@@ -66,7 +66,7 @@ void SurfaceLayerImpl::GetDebugBorderProperties(SkColor* color,
*width = DebugColors::SurfaceLayerBorderWidth(layer_tree_impl());
}
-void SurfaceLayerImpl::AsValueInto(base::debug::TracedValue* dict) const {
+void SurfaceLayerImpl::AsValueInto(base::trace_event::TracedValue* dict) const {
LayerImpl::AsValueInto(dict);
dict->SetInteger("surface_id", surface_id_.id);
}
diff --git a/chromium/cc/layers/surface_layer_impl.h b/chromium/cc/layers/surface_layer_impl.h
index 9ef3c6d3482..90c0f4565c6 100644
--- a/chromium/cc/layers/surface_layer_impl.h
+++ b/chromium/cc/layers/surface_layer_impl.h
@@ -25,7 +25,6 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
void PushPropertiesTo(LayerImpl* layer) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
protected:
@@ -33,7 +32,7 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
private:
void GetDebugBorderProperties(SkColor* color, float* width) const override;
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
const char* LayerTypeAsString() const override;
SurfaceId surface_id_;
diff --git a/chromium/cc/layers/surface_layer_unittest.cc b/chromium/cc/layers/surface_layer_unittest.cc
index 7323bf4c455..6661a1a243a 100644
--- a/chromium/cc/layers/surface_layer_unittest.cc
+++ b/chromium/cc/layers/surface_layer_unittest.cc
@@ -2,7 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/message_loop/message_loop_proxy.h"
+#include <set>
+#include <vector>
+
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/surface_layer.h"
#include "cc/test/fake_impl_proxy.h"
@@ -26,12 +31,12 @@ class SurfaceLayerTest : public testing::Test {
FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)) {}
protected:
- virtual void SetUp() {
+ void SetUp() override {
layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
layer_tree_host_->SetViewportSize(gfx::Size(10, 10));
}
- virtual void TearDown() {
+ void TearDown() override {
if (layer_tree_host_) {
layer_tree_host_->SetRootLayer(nullptr);
layer_tree_host_ = nullptr;
@@ -65,7 +70,7 @@ TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) {
scoped_refptr<SurfaceLayer> layer(SurfaceLayer::Create(
base::Bind(&SatisfyCallback, &blank_change),
base::Bind(&RequireCallback, &required_id, &required_seq)));
- layer->SetSurfaceId(SurfaceId(1), gfx::Size(1, 1));
+ layer->SetSurfaceId(SurfaceId(1), 1.f, gfx::Size(1, 1));
layer_tree_host_->set_surface_id_namespace(1);
layer_tree_host_->SetRootLayer(layer);
@@ -74,7 +79,7 @@ TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) {
scoped_refptr<SurfaceLayer> layer2(SurfaceLayer::Create(
base::Bind(&SatisfyCallback, &blank_change),
base::Bind(&RequireCallback, &required_id, &required_seq)));
- layer2->SetSurfaceId(SurfaceId(1), gfx::Size(1, 1));
+ layer2->SetSurfaceId(SurfaceId(1), 1.f, gfx::Size(1, 1));
layer_tree_host2->set_surface_id_namespace(2);
layer_tree_host2->SetRootLayer(layer2);
@@ -110,6 +115,14 @@ TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) {
EXPECT_EQ(2u, required_seq.size());
}
+static void CalcDrawProps(FakeLayerTreeHost* host, float device_scale_factor) {
+ RenderSurfaceLayerList render_surface_layer_list;
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ host->root_layer(), gfx::Size(500, 500), &render_surface_layer_list);
+ inputs.device_scale_factor = device_scale_factor;
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+}
+
// Check that setting content scale on the surface works.
TEST_F(SurfaceLayerTest, ScaleSurface) {
SurfaceSequence blank_change;
@@ -119,22 +132,17 @@ TEST_F(SurfaceLayerTest, ScaleSurface) {
base::Bind(&SatisfyCallback, &blank_change),
base::Bind(&RequireCallback, &required_id, &required_seq)));
gfx::Size surface_size(10, 15);
- layer->SetSurfaceId(SurfaceId(1), surface_size);
+ layer->SetSurfaceId(SurfaceId(1), 2.f, surface_size);
layer->SetBounds(gfx::Size(25, 45));
+ layer_tree_host_->SetRootLayer(layer);
- float scale_x;
- float scale_y;
- gfx::Size bounds;
- layer->CalculateContentsScale(2.f, &scale_x, &scale_y, &bounds);
- EXPECT_EQ(10.f / 25.f, scale_x);
- EXPECT_EQ(15.f / 45.f, scale_y);
- EXPECT_EQ(surface_size.ToString(), bounds.ToString());
-
- layer->SetBounds(gfx::Size(0, 0));
- layer->CalculateContentsScale(2.f, &scale_x, &scale_y, &bounds);
- EXPECT_EQ(1.f, scale_x);
- EXPECT_EQ(1.f, scale_y);
- EXPECT_EQ(surface_size.ToString(), bounds.ToString());
+ CalcDrawProps(layer_tree_host_.get(), 5.f);
+ EXPECT_EQ(2.f, layer->contents_scale_x());
+ EXPECT_EQ(2.f, layer->contents_scale_y());
+ EXPECT_EQ(surface_size.ToString(), layer->content_bounds().ToString());
+
+ layer_tree_host_->SetRootLayer(nullptr);
+ layer_tree_host_.reset();
}
// Check that SurfaceSequence is sent through swap promise.
@@ -148,7 +156,7 @@ class SurfaceLayerSwapPromise : public LayerTreeTest {
layer_ = SurfaceLayer::Create(
base::Bind(&SatisfyCallback, &satisfied_sequence_),
base::Bind(&RequireCallback, &required_id_, &required_set_));
- layer_->SetSurfaceId(SurfaceId(1), gfx::Size(1, 1));
+ layer_->SetSurfaceId(SurfaceId(1), 1.f, gfx::Size(1, 1));
// Layer hasn't been added to tree so no SurfaceSequence generated yet.
EXPECT_EQ(0u, required_set_.size());
@@ -166,8 +174,8 @@ class SurfaceLayerSwapPromise : public LayerTreeTest {
PostSetNeedsCommitToMainThread();
}
- void DidCommit() override {
- base::MessageLoopProxy::current()->PostTask(
+ void DidCommitAndDrawFrame() override {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&SurfaceLayerSwapPromise::ChangeTree,
base::Unretained(this)));
}
diff --git a/chromium/cc/layers/texture_layer.cc b/chromium/cc/layers/texture_layer.cc
index d53cfbe40ef..cf1149b5161 100644
--- a/chromium/cc/layers/texture_layer.cc
+++ b/chromium/cc/layers/texture_layer.cc
@@ -27,6 +27,7 @@ TextureLayer::TextureLayer(TextureLayerClient* client)
: Layer(),
client_(client),
flipped_(true),
+ nearest_neighbor_(false),
uv_top_left_(0.f, 0.f),
uv_bottom_right_(1.f, 1.f),
premultiplied_alpha_(true),
@@ -65,6 +66,13 @@ void TextureLayer::SetFlipped(bool flipped) {
SetNeedsCommit();
}
+void TextureLayer::SetNearestNeighbor(bool nearest_neighbor) {
+ if (nearest_neighbor_ == nearest_neighbor)
+ return;
+ nearest_neighbor_ = nearest_neighbor;
+ SetNeedsCommit();
+}
+
void TextureLayer::SetUV(const gfx::PointF& top_left,
const gfx::PointF& bottom_right) {
if (uv_top_left_ == top_left && uv_bottom_right_ == bottom_right)
@@ -238,6 +246,7 @@ void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
texture_layer->SetFlipped(flipped_);
+ texture_layer->SetNearestNeighbor(nearest_neighbor_);
texture_layer->SetUVTopLeft(uv_top_left_);
texture_layer->SetUVBottomRight(uv_bottom_right_);
texture_layer->SetVertexOpacity(vertex_opacity_);
diff --git a/chromium/cc/layers/texture_layer.h b/chromium/cc/layers/texture_layer.h
index fa52a8c11ff..00c9e7452ad 100644
--- a/chromium/cc/layers/texture_layer.h
+++ b/chromium/cc/layers/texture_layer.h
@@ -99,6 +99,11 @@ class CC_EXPORT TextureLayer : public Layer {
// Sets whether this texture should be Y-flipped at draw time. Defaults to
// true.
void SetFlipped(bool flipped);
+ bool flipped() const { return flipped_; }
+
+ // Sets whether this texture should use nearest neighbor interpolation as
+ // opposed to bilinear. Defaults to false.
+ void SetNearestNeighbor(bool nearest_neighbor);
// Sets a UV transform to be used at draw time. Defaults to (0, 0) and (1, 1).
void SetUV(const gfx::PointF& top_left, const gfx::PointF& bottom_right);
@@ -156,6 +161,7 @@ class CC_EXPORT TextureLayer : public Layer {
TextureLayerClient* client_;
bool flipped_;
+ bool nearest_neighbor_;
gfx::PointF uv_top_left_;
gfx::PointF uv_bottom_right_;
// [bottom left, top left, top right, bottom right]
diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc
index bcde7cd49ec..8728b89db9c 100644
--- a/chromium/cc/layers/texture_layer_impl.cc
+++ b/chromium/cc/layers/texture_layer_impl.cc
@@ -23,6 +23,7 @@ TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* tree_impl, int id)
premultiplied_alpha_(true),
blend_background_color_(false),
flipped_(true),
+ nearest_neighbor_(false),
uv_top_left_(0.f, 0.f),
uv_bottom_right_(1.f, 1.f),
own_mailbox_(false),
@@ -62,6 +63,7 @@ void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) {
texture_layer->SetVertexOpacity(vertex_opacity_);
texture_layer->SetPremultipliedAlpha(premultiplied_alpha_);
texture_layer->SetBlendBackgroundColor(blend_background_color_);
+ texture_layer->SetNearestNeighbor(nearest_neighbor_);
if (own_mailbox_) {
texture_layer->SetTextureMailbox(texture_mailbox_,
release_callback_.Pass());
@@ -103,14 +105,13 @@ bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
if (!texture_copy_->id()) {
texture_copy_->Allocate(texture_mailbox_.shared_memory_size(),
- ResourceProvider::TextureHintImmutable,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
}
if (texture_copy_->id()) {
std::vector<uint8> swizzled;
- uint8* pixels =
- static_cast<uint8*>(texture_mailbox_.shared_memory()->memory());
+ uint8* pixels = texture_mailbox_.shared_bitmap()->pixels();
if (!PlatformColor::SameComponentOrder(texture_copy_->format())) {
// Swizzle colors. This is slow, but should be really uncommon.
@@ -140,7 +141,6 @@ bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
}
void TextureLayerImpl::AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
DCHECK(external_texture_resource_ || valid_texture_copy_);
@@ -158,7 +158,8 @@ void TextureLayerImpl::AppendQuads(RenderPass* render_pass,
gfx::Rect quad_rect(content_bounds());
gfx::Rect opaque_rect = opaque ? quad_rect : gfx::Rect();
gfx::Rect visible_quad_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(quad_rect);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ quad_rect);
if (visible_quad_rect.IsEmpty())
return;
@@ -176,7 +177,9 @@ void TextureLayerImpl::AppendQuads(RenderPass* render_pass,
uv_bottom_right_,
bg_color,
vertex_opacity_,
- flipped_);
+ flipped_,
+ nearest_neighbor_);
+ ValidateQuadResources(quad);
}
SimpleEnclosedRegion TextureLayerImpl::VisibleContentOpaqueRegion() const {
@@ -211,12 +214,17 @@ void TextureLayerImpl::SetFlipped(bool flipped) {
SetNeedsPushProperties();
}
-void TextureLayerImpl::SetUVTopLeft(const gfx::PointF top_left) {
+void TextureLayerImpl::SetNearestNeighbor(bool nearest_neighbor) {
+ nearest_neighbor_ = nearest_neighbor;
+ SetNeedsPushProperties();
+}
+
+void TextureLayerImpl::SetUVTopLeft(const gfx::PointF& top_left) {
uv_top_left_ = top_left;
SetNeedsPushProperties();
}
-void TextureLayerImpl::SetUVBottomRight(const gfx::PointF bottom_right) {
+void TextureLayerImpl::SetUVBottomRight(const gfx::PointF& bottom_right) {
uv_bottom_right_ = bottom_right;
SetNeedsPushProperties();
}
diff --git a/chromium/cc/layers/texture_layer_impl.h b/chromium/cc/layers/texture_layer_impl.h
index 6d38ae1f445..56def7a0541 100644
--- a/chromium/cc/layers/texture_layer_impl.h
+++ b/chromium/cc/layers/texture_layer_impl.h
@@ -29,7 +29,6 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
SimpleEnclosedRegion VisibleContentOpaqueRegion() const override;
void ReleaseResources() override;
@@ -41,8 +40,9 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
void SetPremultipliedAlpha(bool premultiplied_alpha);
void SetBlendBackgroundColor(bool blend);
void SetFlipped(bool flipped);
- void SetUVTopLeft(const gfx::PointF top_left);
- void SetUVBottomRight(const gfx::PointF bottom_right);
+ void SetNearestNeighbor(bool nearest_neighbor);
+ void SetUVTopLeft(const gfx::PointF& top_left);
+ void SetUVBottomRight(const gfx::PointF& bottom_right);
// 1--2
// | |
@@ -63,6 +63,7 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
bool premultiplied_alpha_;
bool blend_background_color_;
bool flipped_;
+ bool nearest_neighbor_;
gfx::PointF uv_top_left_;
gfx::PointF uv_bottom_right_;
float vertex_opacity_[4];
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index d355b6274f3..c33db7c3b1c 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -9,7 +9,10 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "cc/layers/solid_color_layer.h"
@@ -24,6 +27,7 @@
#include "cc/test/fake_output_surface.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/blocking_task_runner.h"
#include "cc/trees/layer_tree_host.h"
@@ -50,15 +54,26 @@ gpu::Mailbox MailboxFromChar(char value) {
class MockLayerTreeHost : public LayerTreeHost {
public:
- explicit MockLayerTreeHost(FakeLayerTreeHostClient* client)
- : LayerTreeHost(client, nullptr, nullptr, LayerTreeSettings()) {
- InitializeSingleThreaded(client, base::MessageLoopProxy::current());
+ static scoped_ptr<MockLayerTreeHost> Create(FakeLayerTreeHostClient* client) {
+ LayerTreeHost::InitParams params;
+ params.client = client;
+ LayerTreeSettings settings;
+ params.settings = &settings;
+ return make_scoped_ptr(new MockLayerTreeHost(client, &params));
}
MOCK_METHOD0(SetNeedsCommit, void());
MOCK_METHOD0(SetNeedsUpdateLayers, void());
MOCK_METHOD0(StartRateLimiter, void());
MOCK_METHOD0(StopRateLimiter, void());
+
+ private:
+ MockLayerTreeHost(FakeLayerTreeHostClient* client,
+ LayerTreeHost::InitParams* params)
+ : LayerTreeHost(params) {
+ InitializeSingleThreaded(client, base::ThreadTaskRunnerHandle::Get(),
+ nullptr);
+ }
};
class FakeTextureLayerClient : public TextureLayerClient {
@@ -99,7 +114,7 @@ class MockMailboxCallback {
uint32 sync_point,
bool lost_resource));
MOCK_METHOD3(Release2,
- void(base::SharedMemory* shared_memory,
+ void(SharedBitmap* shared_bitmap,
uint32 sync_point,
bool lost_resource));
MOCK_METHOD4(ReleaseImpl,
@@ -108,19 +123,18 @@ class MockMailboxCallback {
bool lost_resource,
BlockingTaskRunner* main_thread_task_runner));
MOCK_METHOD4(ReleaseImpl2,
- void(base::SharedMemory* shared_memory,
+ void(SharedBitmap* shared_bitmap,
uint32 sync_point,
bool lost_resource,
BlockingTaskRunner* main_thread_task_runner));
};
struct CommonMailboxObjects {
- CommonMailboxObjects()
+ explicit CommonMailboxObjects(SharedBitmapManager* manager)
: mailbox_name1_(MailboxFromChar('1')),
mailbox_name2_(MailboxFromChar('2')),
sync_point1_(1),
- sync_point2_(2),
- shared_memory_(new base::SharedMemory) {
+ sync_point2_(2) {
release_mailbox1_ = base::Bind(&MockMailboxCallback::Release,
base::Unretained(&mock_callback_),
mailbox_name1_);
@@ -138,14 +152,15 @@ struct CommonMailboxObjects {
mailbox1_ = TextureMailbox(mailbox_name1_, arbitrary_target1, sync_point1_);
mailbox2_ = TextureMailbox(mailbox_name2_, arbitrary_target2, sync_point2_);
gfx::Size size(128, 128);
- EXPECT_TRUE(shared_memory_->CreateAndMapAnonymous(4 * size.GetArea()));
- release_mailbox3_ = base::Bind(&MockMailboxCallback::Release2,
- base::Unretained(&mock_callback_),
- shared_memory_.get());
- release_mailbox3_impl_ = base::Bind(&MockMailboxCallback::ReleaseImpl2,
- base::Unretained(&mock_callback_),
- shared_memory_.get());
- mailbox3_ = TextureMailbox(shared_memory_.get(), size);
+ shared_bitmap_ = manager->AllocateSharedBitmap(size);
+ DCHECK(shared_bitmap_);
+ release_mailbox3_ =
+ base::Bind(&MockMailboxCallback::Release2,
+ base::Unretained(&mock_callback_), shared_bitmap_.get());
+ release_mailbox3_impl_ =
+ base::Bind(&MockMailboxCallback::ReleaseImpl2,
+ base::Unretained(&mock_callback_), shared_bitmap_.get());
+ mailbox3_ = TextureMailbox(shared_bitmap_.get(), size);
}
gpu::Mailbox mailbox_name1_;
@@ -162,7 +177,7 @@ struct CommonMailboxObjects {
TextureMailbox mailbox3_;
uint32 sync_point1_;
uint32 sync_point2_;
- scoped_ptr<base::SharedMemory> shared_memory_;
+ scoped_ptr<SharedBitmap> shared_bitmap_;
};
class TextureLayerTest : public testing::Test {
@@ -170,17 +185,18 @@ class TextureLayerTest : public testing::Test {
TextureLayerTest()
: fake_client_(
FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)),
- host_impl_(&proxy_, &shared_bitmap_manager_) {}
+ host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
+ test_data_(&shared_bitmap_manager_) {}
protected:
- virtual void SetUp() {
- layer_tree_host_.reset(new MockLayerTreeHost(&fake_client_));
+ void SetUp() override {
+ layer_tree_host_ = MockLayerTreeHost::Create(&fake_client_);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
layer_tree_host_->SetViewportSize(gfx::Size(10, 10));
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
}
- virtual void TearDown() {
+ void TearDown() override {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
@@ -192,7 +208,9 @@ class TextureLayerTest : public testing::Test {
FakeImplProxy proxy_;
FakeLayerTreeHostClient fake_client_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
+ CommonMailboxObjects test_data_;
};
TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
@@ -203,6 +221,7 @@ TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
// Test properties that should call SetNeedsCommit. All properties need to
// be set to new values in order for SetNeedsCommit to be called.
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFlipped(false));
+ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetNearestNeighbor(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUV(
gfx::PointF(0.25f, 0.25f), gfx::PointF(0.75f, 0.75f)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetVertexOpacity(
@@ -298,7 +317,7 @@ class TestMailboxHolder : public TextureLayer::TextureMailboxHolder {
class TextureLayerWithMailboxTest : public TextureLayerTest {
protected:
- virtual void TearDown() {
+ void TearDown() override {
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_,
@@ -306,8 +325,6 @@ class TextureLayerWithMailboxTest : public TextureLayerTest {
false)).Times(1);
TextureLayerTest::TearDown();
}
-
- CommonMailboxObjects test_data_;
};
TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
@@ -356,9 +373,7 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
EXPECT_CALL(test_data_.mock_callback_,
- Release2(test_data_.shared_memory_.get(),
- 0, false))
- .Times(1);
+ Release2(test_data_.shared_bitmap_.get(), 0, false)).Times(1);
test_layer->SetTextureMailbox(TextureMailbox(), nullptr);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -400,10 +415,9 @@ class TextureLayerMailboxHolderTest : public TextureLayerTest {
TextureLayerMailboxHolderTest()
: main_thread_("MAIN") {
main_thread_.Start();
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::InitializeOnMain,
- base::Unretained(this)));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::InitializeOnMain,
+ base::Unretained(this)));
Wait(main_thread_);
}
@@ -411,7 +425,7 @@ class TextureLayerMailboxHolderTest : public TextureLayerTest {
bool manual_reset = false;
bool initially_signaled = false;
base::WaitableEvent event(manual_reset, initially_signaled);
- thread.message_loop()->PostTask(
+ thread.message_loop()->task_runner()->PostTask(
FROM_HERE,
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)));
event.Wait();
@@ -442,14 +456,13 @@ class TextureLayerMailboxHolderTest : public TextureLayerTest {
protected:
void InitializeOnMain() {
main_thread_task_runner_ =
- BlockingTaskRunner::Create(main_thread_.message_loop_proxy());
+ BlockingTaskRunner::Create(main_thread_.task_runner());
}
scoped_ptr<TestMailboxHolder::MainThreadReference>
main_ref_;
base::Thread main_thread_;
scoped_ptr<BlockingTaskRunner> main_thread_task_runner_;
- CommonMailboxObjects test_data_;
};
TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_BothReleaseThenMain) {
@@ -457,30 +470,25 @@ TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_BothReleaseThenMain) {
TextureLayer::CreateForMailbox(nullptr);
ASSERT_TRUE(test_layer.get());
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
- base::Unretained(this)));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
Wait(main_thread_);
// The texture layer is attached to compositor1, and passes a reference to its
// impl tree.
scoped_ptr<SingleReleaseCallbackImpl> compositor1;
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
- base::Unretained(this),
- &compositor1));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this), &compositor1));
// Then the texture layer is removed and attached to compositor2, and passes a
// reference to its impl tree.
scoped_ptr<SingleReleaseCallbackImpl> compositor2;
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
- base::Unretained(this),
- &compositor2));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this), &compositor2));
Wait(main_thread_);
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -500,10 +508,9 @@ TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_BothReleaseThenMain) {
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_, 200, false)).Times(1);
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
- base::Unretained(this)));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
Wait(main_thread_);
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
}
@@ -513,30 +520,25 @@ TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleaseBetween) {
TextureLayer::CreateForMailbox(nullptr);
ASSERT_TRUE(test_layer.get());
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
- base::Unretained(this)));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
Wait(main_thread_);
// The texture layer is attached to compositor1, and passes a reference to its
// impl tree.
scoped_ptr<SingleReleaseCallbackImpl> compositor1;
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
- base::Unretained(this),
- &compositor1));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this), &compositor1));
// Then the texture layer is removed and attached to compositor2, and passes a
// reference to its impl tree.
scoped_ptr<SingleReleaseCallbackImpl> compositor2;
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
- base::Unretained(this),
- &compositor2));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this), &compositor2));
Wait(main_thread_);
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -545,10 +547,9 @@ TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleaseBetween) {
compositor1->Run(100, false, main_thread_task_runner_.get());
// Then the main thread reference is destroyed.
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
- base::Unretained(this)));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
Wait(main_thread_);
@@ -570,39 +571,33 @@ TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_MainReleasedFirst) {
TextureLayer::CreateForMailbox(nullptr);
ASSERT_TRUE(test_layer.get());
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
- base::Unretained(this)));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
Wait(main_thread_);
// The texture layer is attached to compositor1, and passes a reference to its
// impl tree.
scoped_ptr<SingleReleaseCallbackImpl> compositor1;
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
- base::Unretained(this),
- &compositor1));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this), &compositor1));
// Then the texture layer is removed and attached to compositor2, and passes a
// reference to its impl tree.
scoped_ptr<SingleReleaseCallbackImpl> compositor2;
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
- base::Unretained(this),
- &compositor2));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this), &compositor2));
Wait(main_thread_);
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
// The main thread reference is destroyed first.
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
- base::Unretained(this)));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
// One compositor destroys their impl tree.
compositor2->Run(200, false, main_thread_task_runner_.get());
@@ -627,39 +622,33 @@ TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_SecondImplRefShortcut) {
TextureLayer::CreateForMailbox(nullptr);
ASSERT_TRUE(test_layer.get());
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
- base::Unretained(this)));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateMainRef,
+ base::Unretained(this)));
Wait(main_thread_);
// The texture layer is attached to compositor1, and passes a reference to its
// impl tree.
scoped_ptr<SingleReleaseCallbackImpl> compositor1;
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
- base::Unretained(this),
- &compositor1));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this), &compositor1));
// Then the texture layer is removed and attached to compositor2, and passes a
// reference to its impl tree.
scoped_ptr<SingleReleaseCallbackImpl> compositor2;
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
- base::Unretained(this),
- &compositor2));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::CreateImplRef,
+ base::Unretained(this), &compositor2));
Wait(main_thread_);
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
// The main thread reference is destroyed first.
- main_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
- base::Unretained(this)));
+ main_thread_.message_loop()->task_runner()->PostTask(
+ FROM_HERE, base::Bind(&TextureLayerMailboxHolderTest::ReleaseMainRef,
+ base::Unretained(this)));
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_, 200, true)).Times(1);
@@ -672,12 +661,10 @@ TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_SecondImplRefShortcut) {
// Post a task to start capturing tasks on the main thread. This will block
// the main thread until we signal the |stop_capture| event.
- main_thread_.message_loop()->PostTask(
+ main_thread_.message_loop()->task_runner()->PostTask(
FROM_HERE,
base::Bind(&TextureLayerMailboxHolderTest::CapturePostTasksAndWait,
- base::Unretained(this),
- &begin_capture,
- &wait_for_capture,
+ base::Unretained(this), &begin_capture, &wait_for_capture,
&stop_capture));
// Before the main thread capturing starts, one compositor destroys their
@@ -929,9 +916,9 @@ class TextureLayerImplWithMailboxTest : public TextureLayerTest {
: fake_client_(
FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)) {}
- virtual void SetUp() {
+ void SetUp() override {
TextureLayerTest::SetUp();
- layer_tree_host_.reset(new MockLayerTreeHost(&fake_client_));
+ layer_tree_host_ = MockLayerTreeHost::Create(&fake_client_);
EXPECT_TRUE(host_impl_.InitializeRenderer(FakeOutputSurface::Create3d()));
}
@@ -943,7 +930,6 @@ class TextureLayerImplWithMailboxTest : public TextureLayerTest {
return will_draw;
}
- CommonMailboxObjects test_data_;
FakeLayerTreeHostClient fake_client_;
};
@@ -955,7 +941,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
ReleaseImpl(test_data_.mailbox_name1_, test_data_.sync_point1_, false, _))
.Times(AnyNumber());
EXPECT_CALL(test_data_.mock_callback_,
- ReleaseImpl2(test_data_.shared_memory_.get(), 0, false, _))
+ ReleaseImpl2(test_data_.shared_bitmap_.get(), 0, false, _))
.Times(AnyNumber());
// Hardware mode.
{
@@ -1403,10 +1389,7 @@ class TextureLayerReleaseResourcesAfterCommit
public:
void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
LayerTreeImpl* tree = nullptr;
- if (host_impl->settings().impl_side_painting)
- tree = host_impl->pending_tree();
- else
- tree = host_impl->active_tree();
+ tree = host_impl->sync_tree();
tree->root_layer()->children()[0]->ReleaseResources();
}
};
diff --git a/chromium/cc/layers/tiled_layer.cc b/chromium/cc/layers/tiled_layer.cc
index 2a327417c61..55143befe93 100644
--- a/chromium/cc/layers/tiled_layer.cc
+++ b/chromium/cc/layers/tiled_layer.cc
@@ -18,7 +18,6 @@
#include "cc/resources/priority_calculator.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/occlusion_tracker.h"
-#include "third_party/khronos/GLES2/gl2.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
diff --git a/chromium/cc/layers/tiled_layer.h b/chromium/cc/layers/tiled_layer.h
index d48ebe44082..80697607ee6 100644
--- a/chromium/cc/layers/tiled_layer.h
+++ b/chromium/cc/layers/tiled_layer.h
@@ -7,8 +7,8 @@
#include "cc/base/cc_export.h"
#include "cc/layers/contents_scaling_layer.h"
-#include "cc/resources/layer_tiling_data.h"
#include "cc/resources/resource_format.h"
+#include "cc/tiles/layer_tiling_data.h"
namespace cc {
class LayerUpdater;
diff --git a/chromium/cc/layers/tiled_layer_impl.cc b/chromium/cc/layers/tiled_layer_impl.cc
index c66e124ca92..66aee5282c6 100644
--- a/chromium/cc/layers/tiled_layer_impl.cc
+++ b/chromium/cc/layers/tiled_layer_impl.cc
@@ -5,8 +5,8 @@
#include "cc/layers/tiled_layer_impl.h"
#include "base/basictypes.h"
-#include "base/debug/trace_event_argument.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/base/math_util.h"
#include "cc/base/simple_enclosed_region.h"
#include "cc/debug/debug_colors.h"
@@ -15,9 +15,9 @@
#include "cc/quads/debug_border_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
-#include "cc/resources/layer_tiling_data.h"
+#include "cc/tiles/layer_tiling_data.h"
+#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/occlusion.h"
-#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/quad_f.h"
@@ -48,7 +48,15 @@ class DrawableTile : public LayerTilingData::Tile {
};
TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id)
- : LayerImpl(tree_impl, id), skips_draw_(true) {}
+ : TiledLayerImpl(tree_impl, id, new LayerImpl::SyncedScrollOffset) {
+}
+
+TiledLayerImpl::TiledLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ scoped_refptr<LayerImpl::SyncedScrollOffset> synced_scroll_offset)
+ : LayerImpl(tree_impl, id, synced_scroll_offset), skips_draw_(true) {
+}
TiledLayerImpl::~TiledLayerImpl() {
}
@@ -102,14 +110,12 @@ void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return TiledLayerImpl::Create(tree_impl, id());
+ return TiledLayerImpl::Create(tree_impl, id(), synced_scroll_offset());
}
-void TiledLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
+void TiledLayerImpl::AsValueInto(base::trace_event::TracedValue* state) const {
LayerImpl::AsValueInto(state);
- state->BeginArray("invalidation");
- MathUtil::AddToTracedValue(update_rect(), state);
- state->EndArray();
+ MathUtil::AddToTracedValue("invalidation", update_rect(), state);
}
size_t TiledLayerImpl::GPUMemoryUsageInBytes() const {
@@ -160,7 +166,6 @@ bool TiledLayerImpl::WillDraw(DrawMode draw_mode,
}
void TiledLayerImpl::AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
DCHECK(tiler_);
DCHECK(!tiler_->has_empty_bounds());
@@ -219,7 +224,8 @@ void TiledLayerImpl::AppendQuads(RenderPass* render_pass,
continue;
gfx::Rect visible_tile_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(tile_rect);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ tile_rect);
if (visible_tile_rect.IsEmpty())
continue;
@@ -235,8 +241,8 @@ void TiledLayerImpl::AppendQuads(RenderPass* render_pass,
CheckerboardDrawQuad* checkerboard_quad =
render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
- checkerboard_quad->SetNew(
- shared_quad_state, tile_rect, visible_tile_rect, checker_color);
+ checkerboard_quad->SetNew(shared_quad_state, tile_rect,
+ visible_tile_rect, checker_color, 1.f);
append_quads_data->num_missing_tiles++;
continue;
}
@@ -262,7 +268,9 @@ void TiledLayerImpl::AppendQuads(RenderPass* render_pass,
tile->resource_id(),
tex_coord_rect,
texture_size,
- tile->contents_swizzled());
+ tile->contents_swizzled(),
+ false);
+ ValidateQuadResources(quad);
}
}
}
diff --git a/chromium/cc/layers/tiled_layer_impl.h b/chromium/cc/layers/tiled_layer_impl.h
index e3ace3497a5..c292790d0a5 100644
--- a/chromium/cc/layers/tiled_layer_impl.h
+++ b/chromium/cc/layers/tiled_layer_impl.h
@@ -18,7 +18,15 @@ class DrawableTile;
class CC_EXPORT TiledLayerImpl : public LayerImpl {
public:
static scoped_ptr<TiledLayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
- return make_scoped_ptr(new TiledLayerImpl(tree_impl, id));
+ return make_scoped_ptr(
+ new TiledLayerImpl(tree_impl, id, new LayerImpl::SyncedScrollOffset));
+ }
+ static scoped_ptr<TiledLayerImpl> Create(
+ LayerTreeImpl* tree_impl,
+ int id,
+ scoped_refptr<LayerImpl::SyncedScrollOffset> synced_scroll_offset) {
+ return make_scoped_ptr(
+ new TiledLayerImpl(tree_impl, id, synced_scroll_offset));
}
~TiledLayerImpl() override;
@@ -28,7 +36,6 @@ class CC_EXPORT TiledLayerImpl : public LayerImpl {
bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
void GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
@@ -51,12 +58,16 @@ class CC_EXPORT TiledLayerImpl : public LayerImpl {
protected:
TiledLayerImpl(LayerTreeImpl* tree_impl, int id);
+ TiledLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ scoped_refptr<LayerImpl::SyncedScrollOffset> synced_scroll_offset);
// Exposed for testing.
bool HasTileAt(int i, int j) const;
bool HasResourceIdForTileAt(int i, int j) const;
void GetDebugBorderProperties(SkColor* color, float* width) const override;
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
private:
const char* LayerTypeAsString() const override;
diff --git a/chromium/cc/layers/tiled_layer_impl_unittest.cc b/chromium/cc/layers/tiled_layer_impl_unittest.cc
index 689416acf3a..6e662568bcd 100644
--- a/chromium/cc/layers/tiled_layer_impl_unittest.cc
+++ b/chromium/cc/layers/tiled_layer_impl_unittest.cc
@@ -6,10 +6,12 @@
#include "cc/layers/append_quads_data.h"
#include "cc/quads/tile_draw_quad.h"
-#include "cc/resources/layer_tiling_data.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_output_surface.h"
#include "cc/test/layer_test_common.h"
+#include "cc/test/test_task_graph_runner.h"
+#include "cc/tiles/layer_tiling_data.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,7 +21,10 @@ namespace {
class TiledLayerImplTest : public testing::Test {
public:
- TiledLayerImplTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {}
+ TiledLayerImplTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {
+ host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
+ }
scoped_ptr<TiledLayerImpl> CreateLayerNoTiles(
const gfx::Size& tile_size,
@@ -37,7 +42,7 @@ class TiledLayerImplTest : public testing::Test {
layer->draw_properties().opacity = 1;
layer->SetBounds(layer_size);
layer->SetContentBounds(layer_size);
- layer->CreateRenderSurface();
+ layer->SetHasRenderSurface(true);
layer->draw_properties().render_target = layer.get();
return layer.Pass();
}
@@ -51,10 +56,14 @@ class TiledLayerImplTest : public testing::Test {
scoped_ptr<TiledLayerImpl> layer =
CreateLayerNoTiles(tile_size, layer_size, border_texels);
- ResourceProvider::ResourceId resource_id = 1;
for (int i = 0; i < layer->TilingForTesting()->num_tiles_x(); ++i) {
- for (int j = 0; j < layer->TilingForTesting()->num_tiles_y(); ++j)
- layer->PushTileProperties(i, j, resource_id++, false);
+ for (int j = 0; j < layer->TilingForTesting()->num_tiles_y(); ++j) {
+ ResourceProvider::ResourceId resource_id =
+ host_impl_.resource_provider()->CreateResource(
+ gfx::Size(1, 1), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
+ layer->PushTileProperties(i, j, resource_id, false);
+ }
}
return layer.Pass();
@@ -71,12 +80,13 @@ class TiledLayerImplTest : public testing::Test {
layer->SetBounds(layer_size);
AppendQuadsData data;
- layer->AppendQuads(render_pass, Occlusion(), &data);
+ layer->AppendQuads(render_pass, &data);
}
protected:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
};
@@ -95,7 +105,7 @@ TEST_F(TiledLayerImplTest, EmptyQuadList) {
AppendQuadsData data;
EXPECT_TRUE(layer->WillDraw(DRAW_MODE_HARDWARE, nullptr));
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
layer->DidDraw(nullptr);
unsigned num_tiles = num_tiles_x * num_tiles_y;
EXPECT_EQ(render_pass->quad_list.size(), num_tiles);
@@ -124,7 +134,7 @@ TEST_F(TiledLayerImplTest, EmptyQuadList) {
AppendQuadsData data;
EXPECT_TRUE(layer->WillDraw(DRAW_MODE_HARDWARE, nullptr));
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
layer->DidDraw(nullptr);
EXPECT_EQ(render_pass->quad_list.size(), 0u);
}
@@ -138,7 +148,7 @@ TEST_F(TiledLayerImplTest, EmptyQuadList) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
EXPECT_EQ(render_pass->quad_list.size(), 0u);
}
}
@@ -158,7 +168,7 @@ TEST_F(TiledLayerImplTest, Checkerboarding) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
EXPECT_EQ(render_pass->quad_list.size(), 4u);
EXPECT_EQ(0u, data.num_missing_tiles);
@@ -175,7 +185,7 @@ TEST_F(TiledLayerImplTest, Checkerboarding) {
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
EXPECT_LT(0u, data.num_missing_tiles);
EXPECT_EQ(render_pass->quad_list.size(), 4u);
for (const auto& quad : render_pass->quad_list)
@@ -330,10 +340,14 @@ TEST_F(TiledLayerImplTest, Occlusion) {
tiler->SetTilingSize(layer_bounds);
tiled_layer->SetTilingData(*tiler);
- ResourceProvider::ResourceId resource_id = 1;
for (int i = 0; i < tiled_layer->TilingForTesting()->num_tiles_x(); ++i) {
- for (int j = 0; j < tiled_layer->TilingForTesting()->num_tiles_y(); ++j)
- tiled_layer->PushTileProperties(i, j, resource_id++, false);
+ for (int j = 0; j < tiled_layer->TilingForTesting()->num_tiles_y(); ++j) {
+ ResourceProvider::ResourceId resource_id =
+ impl.resource_provider()->CreateResource(
+ gfx::Size(1, 1), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
+ tiled_layer->PushTileProperties(i, j, resource_id, false);
+ }
}
impl.CalcDrawProps(viewport_size);
diff --git a/chromium/cc/layers/tiled_layer_unittest.cc b/chromium/cc/layers/tiled_layer_unittest.cc
index 9c814be4c85..7dbab998d1d 100644
--- a/chromium/cc/layers/tiled_layer_unittest.cc
+++ b/chromium/cc/layers/tiled_layer_unittest.cc
@@ -7,7 +7,10 @@
#include <limits>
#include <vector>
+#include "base/location.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/resources/bitmap_content_layer_updater.h"
#include "cc/resources/layer_painter.h"
#include "cc/resources/prioritized_resource_manager.h"
@@ -45,46 +48,31 @@ class TestOcclusionTracker : public OcclusionTracker<Layer> {
}
};
-class SynchronousOutputSurfaceLayerTreeHost : public LayerTreeHost {
+class SynchronousOutputSurfaceClient : public FakeLayerTreeHostClient {
public:
- static scoped_ptr<SynchronousOutputSurfaceLayerTreeHost> Create(
- LayerTreeHostClient* client,
- SharedBitmapManager* manager,
- const LayerTreeSettings& settings,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
- return make_scoped_ptr(new SynchronousOutputSurfaceLayerTreeHost(
- client, manager, settings, impl_task_runner));
- }
-
- ~SynchronousOutputSurfaceLayerTreeHost() override {}
+ SynchronousOutputSurfaceClient()
+ : FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D) {}
bool EnsureOutputSurfaceCreated() {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- run_loop_.QuitClosure(),
- base::TimeDelta::FromSeconds(5));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop_.QuitClosure(), base::TimeDelta::FromSeconds(5));
run_loop_.Run();
return output_surface_created_;
}
- void OnCreateAndInitializeOutputSurfaceAttempted(bool success) override {
- LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted(success);
- output_surface_created_ = success;
+ void DidInitializeOutputSurface() override {
+ FakeLayerTreeHostClient::DidInitializeOutputSurface();
+ output_surface_created_ = true;
run_loop_.Quit();
}
- private:
- SynchronousOutputSurfaceLayerTreeHost(
- LayerTreeHostClient* client,
- SharedBitmapManager* manager,
- const LayerTreeSettings& settings,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
- : LayerTreeHost(client, manager, NULL, settings),
- output_surface_created_(false) {
- LayerTreeHost::InitializeThreaded(base::MessageLoopProxy::current(),
- impl_task_runner);
+ void DidFailToInitializeOutputSurface() override {
+ FakeLayerTreeHostClient::DidFailToInitializeOutputSurface();
+ output_surface_created_ = false;
+ run_loop_.Quit();
}
+ private:
bool output_surface_created_;
base::RunLoop run_loop_;
};
@@ -96,25 +84,30 @@ class TiledLayerTest : public testing::Test {
output_surface_(FakeOutputSurface::Create3d()),
queue_(make_scoped_ptr(new ResourceUpdateQueue)),
impl_thread_("ImplThread"),
- fake_layer_tree_host_client_(FakeLayerTreeHostClient::DIRECT_3D),
occlusion_(nullptr) {
settings_.max_partial_texture_updates = std::numeric_limits<size_t>::max();
settings_.layer_transforms_should_scale_layer_contents = true;
+ settings_.impl_side_painting = false;
+ settings_.verify_property_trees = false;
}
- virtual void SetUp() {
+ void SetUp() override {
impl_thread_.Start();
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
- layer_tree_host_ = SynchronousOutputSurfaceLayerTreeHost::Create(
- &fake_layer_tree_host_client_,
- shared_bitmap_manager_.get(),
- settings_,
- impl_thread_.message_loop_proxy());
- fake_layer_tree_host_client_.SetLayerTreeHost(layer_tree_host_.get());
+ LayerTreeHost::InitParams params;
+ params.client = &synchronous_output_surface_client_;
+ params.shared_bitmap_manager = shared_bitmap_manager_.get();
+ params.settings = &settings_;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+
+ layer_tree_host_ =
+ LayerTreeHost::CreateThreaded(impl_thread_.task_runner(), &params);
+ synchronous_output_surface_client_.SetLayerTreeHost(layer_tree_host_.get());
proxy_ = layer_tree_host_->proxy();
resource_manager_ = PrioritizedResourceManager::Create(proxy_);
layer_tree_host_->SetLayerTreeHostClientReady();
- CHECK(layer_tree_host_->EnsureOutputSurfaceCreated());
+ CHECK(synchronous_output_surface_client_.EnsureOutputSurfaceCreated());
+
layer_tree_host_->SetRootLayer(Layer::Create());
CHECK(output_surface_->BindToClient(&output_surface_client_));
@@ -128,11 +121,11 @@ class TiledLayerTest : public testing::Test {
0,
false,
1);
- host_impl_ = make_scoped_ptr(
- new FakeLayerTreeHostImpl(proxy_, shared_bitmap_manager_.get()));
+ host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(
+ proxy_, shared_bitmap_manager_.get(), nullptr));
}
- virtual ~TiledLayerTest() {
+ ~TiledLayerTest() override {
ResourceManagerClearAllMemory(resource_manager_.get(),
resource_provider_.get());
@@ -192,6 +185,7 @@ class TiledLayerTest : public testing::Test {
inputs.max_texture_size =
layer_tree_host_->GetRendererCapabilities().max_texture_size;
inputs.can_adjust_raster_scales = true;
+ inputs.verify_property_trees = false;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
}
@@ -252,14 +246,16 @@ class TiledLayerTest : public testing::Test {
scoped_ptr<ResourceUpdateQueue> queue_;
PriorityCalculator priority_calculator_;
base::Thread impl_thread_;
- FakeLayerTreeHostClient fake_layer_tree_host_client_;
- scoped_ptr<SynchronousOutputSurfaceLayerTreeHost> layer_tree_host_;
+ SynchronousOutputSurfaceClient synchronous_output_surface_client_;
+ scoped_ptr<LayerTreeHost> layer_tree_host_;
scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
scoped_ptr<PrioritizedResourceManager> resource_manager_;
TestOcclusionTracker* occlusion_;
};
TEST_F(TiledLayerTest, PushDirtyTiles) {
+ layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
scoped_refptr<FakeTiledLayer> layer =
make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
scoped_ptr<FakeTiledLayerImpl> layer_impl =
@@ -289,6 +285,8 @@ TEST_F(TiledLayerTest, PushDirtyTiles) {
}
TEST_F(TiledLayerTest, Scale) {
+ layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
layer_tree_host_->SetDeviceScaleFactor(1.5);
scoped_refptr<FakeTiledLayer> layer =
@@ -351,6 +349,8 @@ TEST_F(TiledLayerTest, PushOccludedDirtyTiles) {
}
TEST_F(TiledLayerTest, PushDeletedTiles) {
+ layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
scoped_refptr<FakeTiledLayer> layer =
make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
scoped_ptr<FakeTiledLayerImpl> layer_impl =
@@ -1200,6 +1200,8 @@ TEST_F(TiledLayerPartialUpdateTest, PartialUpdates) {
}
TEST_F(TiledLayerTest, TilesPaintedWithoutOcclusion) {
+ layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
scoped_refptr<FakeTiledLayer> layer =
make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
RenderSurfaceLayerList render_surface_layer_list;
@@ -1663,8 +1665,7 @@ class UpdateTrackingTiledLayer : public FakeTiledLayer {
: FakeTiledLayer(manager) {
scoped_ptr<TrackingLayerPainter> painter(TrackingLayerPainter::Create());
tracking_layer_painter_ = painter.get();
- layer_updater_ = BitmapContentLayerUpdater::Create(
- painter.Pass(), &stats_instrumentation_, 0);
+ layer_updater_ = BitmapContentLayerUpdater::Create(painter.Pass(), 0);
}
TrackingLayerPainter* tracking_layer_painter() const {
@@ -1677,7 +1678,6 @@ class UpdateTrackingTiledLayer : public FakeTiledLayer {
TrackingLayerPainter* tracking_layer_painter_;
scoped_refptr<BitmapContentLayerUpdater> layer_updater_;
- FakeRenderingStatsInstrumentation stats_instrumentation_;
};
TEST_F(TiledLayerTest, NonIntegerContentsScaleIsNotDistortedDuringPaint) {
@@ -1704,7 +1704,7 @@ TEST_F(TiledLayerTest, NonIntegerContentsScaleIsNotDistortedDuringPaint) {
layer->Update(queue_.get(), nullptr);
layer->tracking_layer_painter()->ResetPaintedRect();
- EXPECT_RECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect());
+ EXPECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect());
UpdateTextures();
// Invalidate the entire layer in content space. When painting, the rect given
@@ -1715,8 +1715,8 @@ TEST_F(TiledLayerTest, NonIntegerContentsScaleIsNotDistortedDuringPaint) {
// Rounding leads to an extra pixel.
gfx::Rect expanded_layer_rect(layer_rect);
expanded_layer_rect.set_height(32);
- EXPECT_RECT_EQ(expanded_layer_rect,
- layer->tracking_layer_painter()->PaintedRect());
+ EXPECT_EQ(expanded_layer_rect,
+ layer->tracking_layer_painter()->PaintedRect());
}
TEST_F(TiledLayerTest,
@@ -1743,7 +1743,7 @@ TEST_F(TiledLayerTest,
layer->Update(queue_.get(), nullptr);
layer->tracking_layer_painter()->ResetPaintedRect();
- EXPECT_RECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect());
+ EXPECT_EQ(gfx::Rect(), layer->tracking_layer_painter()->PaintedRect());
UpdateTextures();
// Invalidate the entire layer in layer space. When painting, the rect given
@@ -1754,8 +1754,8 @@ TEST_F(TiledLayerTest,
// Rounding leads to an extra pixel.
gfx::Rect expanded_layer_rect(layer_rect);
expanded_layer_rect.set_height(32);
- EXPECT_RECT_EQ(expanded_layer_rect,
- layer->tracking_layer_painter()->PaintedRect());
+ EXPECT_EQ(expanded_layer_rect,
+ layer->tracking_layer_painter()->PaintedRect());
}
} // namespace
diff --git a/chromium/cc/layers/ui_resource_layer.cc b/chromium/cc/layers/ui_resource_layer.cc
index 944cf7d5484..fd107b1ed07 100644
--- a/chromium/cc/layers/ui_resource_layer.cc
+++ b/chromium/cc/layers/ui_resource_layer.cc
@@ -107,23 +107,26 @@ void UIResourceLayer::SetLayerTreeHost(LayerTreeHost* host) {
Layer::SetLayerTreeHost(host);
- // Recreate the resource hold against the new LTH.
+ // Recreate the resource held against the new LTH.
RecreateUIResourceHolder();
+
+ UpdateDrawsContent(HasDrawableContent());
}
void UIResourceLayer::RecreateUIResourceHolder() {
- ui_resource_holder_ = nullptr;
+ if (!bitmap_.empty())
+ SetBitmap(bitmap_);
+}
+
+void UIResourceLayer::SetBitmap(const SkBitmap& skbitmap) {
+ bitmap_ = skbitmap;
if (layer_tree_host() && !bitmap_.empty()) {
ui_resource_holder_ =
ScopedUIResourceHolder::Create(layer_tree_host(), bitmap_);
+ } else {
+ ui_resource_holder_ = nullptr;
}
UpdateDrawsContent(HasDrawableContent());
-}
-
-void UIResourceLayer::SetBitmap(const SkBitmap& skbitmap) {
- bitmap_ = skbitmap;
-
- RecreateUIResourceHolder();
SetNeedsCommit();
}
@@ -131,6 +134,9 @@ void UIResourceLayer::SetUIResourceId(UIResourceId resource_id) {
if (ui_resource_holder_ && ui_resource_holder_->id() == resource_id)
return;
+ if (!bitmap_.isNull())
+ bitmap_.reset();
+
if (resource_id)
ui_resource_holder_ = SharedUIResourceHolder::Create(resource_id);
else
diff --git a/chromium/cc/layers/ui_resource_layer.h b/chromium/cc/layers/ui_resource_layer.h
index 3bfd9b2f109..dc2006e12bf 100644
--- a/chromium/cc/layers/ui_resource_layer.h
+++ b/chromium/cc/layers/ui_resource_layer.h
@@ -26,7 +26,9 @@ class CC_EXPORT UIResourceLayer : public Layer {
void SetBitmap(const SkBitmap& skbitmap);
- // An alternative way of setting the resource to allow for sharing.
+ // An alternative way of setting the resource to allow for sharing. If you use
+ // this method, you are responsible for updating the ID if the layer moves
+ // between compositors.
void SetUIResourceId(UIResourceId resource_id);
// Sets a UV transform to be used at draw time. Defaults to (0, 0) and (1, 1).
@@ -62,8 +64,6 @@ class CC_EXPORT UIResourceLayer : public Layer {
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
void RecreateUIResourceHolder();
-
-
DISALLOW_COPY_AND_ASSIGN(UIResourceLayer);
};
diff --git a/chromium/cc/layers/ui_resource_layer_impl.cc b/chromium/cc/layers/ui_resource_layer_impl.cc
index 35d242bee87..582ea9eb924 100644
--- a/chromium/cc/layers/ui_resource_layer_impl.cc
+++ b/chromium/cc/layers/ui_resource_layer_impl.cc
@@ -93,7 +93,6 @@ bool UIResourceLayerImpl::WillDraw(DrawMode draw_mode,
void UIResourceLayerImpl::AppendQuads(
RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
@@ -112,6 +111,7 @@ void UIResourceLayerImpl::AppendQuads(
return;
static const bool flipped = false;
+ static const bool nearest_neighbor = false;
static const bool premultiplied_alpha = true;
DCHECK(!bounds().IsEmpty());
@@ -122,7 +122,8 @@ void UIResourceLayerImpl::AppendQuads(
gfx::Rect quad_rect(bounds());
gfx::Rect opaque_rect(opaque ? quad_rect : gfx::Rect());
gfx::Rect visible_quad_rect =
- occlusion_in_content_space.GetUnoccludedContentRect(quad_rect);
+ draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+ quad_rect);
if (visible_quad_rect.IsEmpty())
return;
@@ -138,7 +139,9 @@ void UIResourceLayerImpl::AppendQuads(
uv_bottom_right_,
SK_ColorTRANSPARENT,
vertex_opacity_,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(quad);
}
const char* UIResourceLayerImpl::LayerTypeAsString() const {
diff --git a/chromium/cc/layers/ui_resource_layer_impl.h b/chromium/cc/layers/ui_resource_layer_impl.h
index d98f1fb69dd..87d77e85a20 100644
--- a/chromium/cc/layers/ui_resource_layer_impl.h
+++ b/chromium/cc/layers/ui_resource_layer_impl.h
@@ -45,7 +45,6 @@ class CC_EXPORT UIResourceLayerImpl : public LayerImpl {
bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
base::DictionaryValue* LayerTreeAsJson() const override;
diff --git a/chromium/cc/layers/ui_resource_layer_impl_unittest.cc b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc
index dc24e1dd5c0..b725e6d44e9 100644
--- a/chromium/cc/layers/ui_resource_layer_impl_unittest.cc
+++ b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc
@@ -9,6 +9,7 @@
#include "cc/resources/ui_resource_client.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_ui_resource_layer_tree_host_impl.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/test_shared_bitmap_manager.h"
@@ -32,7 +33,7 @@ scoped_ptr<UIResourceLayerImpl> GenerateUIResourceLayer(
layer->draw_properties().visible_content_rect = visible_content_rect;
layer->SetBounds(layer_size);
layer->SetContentBounds(layer_size);
- layer->CreateRenderSurface();
+ layer->SetHasRenderSurface(true);
layer->draw_properties().render_target = layer.get();
UIResourceBitmap bitmap(bitmap_size, opaque);
@@ -48,7 +49,7 @@ void QuadSizeTest(scoped_ptr<UIResourceLayerImpl> layer,
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
// Verify quad rects
const QuadList& quads = render_pass->quad_list;
@@ -59,6 +60,8 @@ TEST(UIResourceLayerImplTest, VerifyDrawQuads) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ host_impl.InitializeRenderer(FakeOutputSurface::Create3d());
+
// Make sure we're appending quads when there are valid values.
gfx::Size bitmap_size(100, 100);
gfx::Size layer_size(100, 100);;
@@ -88,7 +91,7 @@ void OpaqueBoundsTest(scoped_ptr<UIResourceLayerImpl> layer,
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
- layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+ layer->AppendQuads(render_pass.get(), &data);
// Verify quad rects
const QuadList& quads = render_pass->quad_list;
@@ -101,6 +104,7 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnSkBitmap) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ host_impl.InitializeRenderer(FakeOutputSurface::Create3d());
gfx::Size bitmap_size(100, 100);
gfx::Size layer_size(100, 100);;
@@ -128,6 +132,7 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnLayer) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ host_impl.InitializeRenderer(FakeOutputSurface::Create3d());
gfx::Size bitmap_size(100, 100);
gfx::Size layer_size(100, 100);
diff --git a/chromium/cc/layers/ui_resource_layer_unittest.cc b/chromium/cc/layers/ui_resource_layer_unittest.cc
index 784ff3586c8..d0d356d6c5a 100644
--- a/chromium/cc/layers/ui_resource_layer_unittest.cc
+++ b/chromium/cc/layers/ui_resource_layer_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/layers/ui_resource_layer.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/resource_update_queue.h"
@@ -28,18 +29,35 @@ using ::testing::AnyNumber;
namespace cc {
namespace {
+class TestUIResourceLayer : public UIResourceLayer {
+ public:
+ static scoped_refptr<TestUIResourceLayer> Create() {
+ return make_scoped_refptr(new TestUIResourceLayer());
+ }
+
+ UIResourceId GetUIResourceId() {
+ if (ui_resource_holder_)
+ return ui_resource_holder_->id();
+ return 0;
+ }
+
+ protected:
+ TestUIResourceLayer() : UIResourceLayer() { SetIsDrawable(true); }
+ ~TestUIResourceLayer() override {}
+};
+
class UIResourceLayerTest : public testing::Test {
public:
UIResourceLayerTest() : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
protected:
- virtual void SetUp() {
+ void SetUp() override {
layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
layer_tree_host_->InitializeSingleThreaded(
- &fake_client_, base::MessageLoopProxy::current());
+ &fake_client_, base::ThreadTaskRunnerHandle::Get(), nullptr);
}
- virtual void TearDown() {
+ void TearDown() override {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
}
@@ -48,9 +66,8 @@ class UIResourceLayerTest : public testing::Test {
};
TEST_F(UIResourceLayerTest, SetBitmap) {
- scoped_refptr<UIResourceLayer> test_layer = UIResourceLayer::Create();
+ scoped_refptr<UIResourceLayer> test_layer = TestUIResourceLayer::Create();
ASSERT_TRUE(test_layer.get());
- test_layer->SetIsDrawable(true);
test_layer->SetBounds(gfx::Size(100, 100));
layer_tree_host_->SetRootLayer(test_layer);
@@ -76,9 +93,8 @@ TEST_F(UIResourceLayerTest, SetBitmap) {
}
TEST_F(UIResourceLayerTest, SetUIResourceId) {
- scoped_refptr<UIResourceLayer> test_layer = UIResourceLayer::Create();
+ scoped_refptr<TestUIResourceLayer> test_layer = TestUIResourceLayer::Create();
ASSERT_TRUE(test_layer.get());
- test_layer->SetIsDrawable(true);
test_layer->SetBounds(gfx::Size(100, 100));
layer_tree_host_->SetRootLayer(test_layer);
@@ -100,6 +116,33 @@ TEST_F(UIResourceLayerTest, SetUIResourceId) {
test_layer->Update(&queue, &occlusion_tracker);
EXPECT_TRUE(test_layer->DrawsContent());
+
+ // ID is preserved even when you set ID first and attach it to the tree.
+ layer_tree_host_->SetRootLayer(nullptr);
+ scoped_ptr<ScopedUIResource> shared_resource = ScopedUIResource::Create(
+ layer_tree_host_.get(), UIResourceBitmap(gfx::Size(5, 5), is_opaque));
+ test_layer->SetUIResourceId(shared_resource->id());
+ layer_tree_host_->SetRootLayer(test_layer);
+ EXPECT_EQ(shared_resource->id(), test_layer->GetUIResourceId());
+ EXPECT_TRUE(test_layer->DrawsContent());
+}
+
+TEST_F(UIResourceLayerTest, BitmapClearedOnSetUIResourceId) {
+ scoped_refptr<UIResourceLayer> test_layer = TestUIResourceLayer::Create();
+ ASSERT_TRUE(test_layer.get());
+ test_layer->SetBounds(gfx::Size(100, 100));
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(10, 10);
+ bitmap.setImmutable();
+ ASSERT_FALSE(bitmap.isNull());
+ ASSERT_TRUE(bitmap.pixelRef()->unique());
+
+ test_layer->SetBitmap(bitmap);
+ ASSERT_FALSE(bitmap.pixelRef()->unique());
+
+ test_layer->SetUIResourceId(0);
+ EXPECT_TRUE(bitmap.pixelRef()->unique());
}
} // namespace
diff --git a/chromium/cc/layers/video_frame_provider.h b/chromium/cc/layers/video_frame_provider.h
index 784d951fe52..f747a88315d 100644
--- a/chromium/cc/layers/video_frame_provider.h
+++ b/chromium/cc/layers/video_frame_provider.h
@@ -6,6 +6,8 @@
#define CC_LAYERS_VIDEO_FRAME_PROVIDER_H_
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "cc/base/cc_export.h"
namespace media {
class VideoFrame;
@@ -13,27 +15,39 @@ class VideoFrame;
namespace cc {
-// Threading notes: This class may be used in a multi threaded manner.
-// Specifically, the implementation may call GetCurrentFrame() or
-// PutCurrentFrame() from the compositor thread. If so, the caller is
-// responsible for making sure Client::DidReceiveFrame() and
-// Client::DidUpdateMatrix() are only called from this same thread.
-class VideoFrameProvider {
+// VideoFrameProvider and VideoFrameProvider::Client define the relationship by
+// which video frames are exchanged between a provider and client.
+//
+// Threading notes: This class may be used in a multithreaded manner. However,
+// if the Client implementation calls GetCurrentFrame()/PutCurrentFrame() from
+// one thread, the provider must ensure that all client methods (except
+// StopUsingProvider()) are called from that thread (typically the compositor
+// thread).
+class CC_EXPORT VideoFrameProvider {
public:
- virtual ~VideoFrameProvider() {}
-
- class Client {
+ class CC_EXPORT Client {
public:
- // Provider will call this method to tell the client to stop using it.
+ // The provider will call this method to tell the client to stop using it.
// StopUsingProvider() may be called from any thread. The client should
// block until it has PutCurrentFrame() any outstanding frames.
virtual void StopUsingProvider() = 0;
- // Notifies the provider's client that a call to GetCurrentFrame() will
- // return new data.
+ // Notifies the client that it should start or stop making regular
+ // UpdateCurrentFrame() calls to the provider. No further calls to
+ // UpdateCurrentFrame() should be made once StopRendering() returns.
+ //
+ // Callers should use these methods to indicate when it expects and no
+ // longer expects (respectively) to have new frames for the client. Clients
+ // may use this information for power conservation.
+ virtual void StartRendering() = 0;
+ virtual void StopRendering() = 0;
+
+ // Notifies the client that GetCurrentFrame() will return new data.
+ // TODO(dalecurtis): Nuke this once VideoFrameProviderClientImpl is using a
+ // BeginFrameObserver based approach. http://crbug.com/336733
virtual void DidReceiveFrame() = 0;
- // Notifies the provider's client of a new UV transform matrix to be used.
+ // Notifies the client of a new UV transform matrix to be used.
virtual void DidUpdateMatrix(const float* matrix) = 0;
protected:
@@ -44,18 +58,40 @@ class VideoFrameProvider {
// that the provider is not destroyed before this call returns.
virtual void SetVideoFrameProviderClient(Client* client) = 0;
- // This function places a lock on the current frame and returns a pointer to
- // it. Calls to this method should always be followed with a call to
- // PutCurrentFrame().
- // Only the current provider client should call this function.
+ // Called by the client on a regular interval. Returns true if a new frame
+ // will be available via GetCurrentFrame() which should be displayed within
+ // the presentation interval [|deadline_min|, |deadline_max|].
+ //
+ // Implementations may use this to drive frame acquisition from underlying
+ // sources, so it must be called by clients before calling GetCurrentFrame().
+ virtual bool UpdateCurrentFrame(base::TimeTicks deadline_min,
+ base::TimeTicks deadline_max) = 0;
+
+ // Returns true if GetCurrentFrame() will return a non-null frame and false
+ // otherwise. Aside from thread locks, the state won't change.
+ virtual bool HasCurrentFrame() = 0;
+
+ // Returns the current frame, which may have been updated by a recent call to
+ // UpdateCurrentFrame(). A call to this method does not ensure that the frame
+ // will be rendered. A subsequent call to PutCurrentFrame() must be made if
+ // the frame is expected to be rendered.
+ //
+ // Clients should call this in response to UpdateCurrentFrame() returning true
+ // or in response to a DidReceiveFrame() call.
+ //
+ // TODO(dalecurtis): Remove text about DidReceiveFrame() once the old path
+ // has been removed. http://crbug.com/439548
virtual scoped_refptr<media::VideoFrame> GetCurrentFrame() = 0;
- // This function releases the lock on the video frame. It should always be
- // called after GetCurrentFrame(). Frames passed into this method
- // should no longer be referenced after the call is made. Only the current
- // provider client should call this function.
- virtual void PutCurrentFrame(
- const scoped_refptr<media::VideoFrame>& frame) = 0;
+ // Called in response to DidReceiveFrame() or a return value of true from
+ // UpdateCurrentFrame() if the current frame was considered for rendering; the
+ // frame may not been rendered for a variety of reasons (occlusion, etc).
+ // Providers may use the absence of this call as a signal to detect when a new
+ // frame missed its intended deadline.
+ virtual void PutCurrentFrame() = 0;
+
+ protected:
+ virtual ~VideoFrameProvider() {}
};
} // namespace cc
diff --git a/chromium/cc/layers/video_frame_provider_client_impl.cc b/chromium/cc/layers/video_frame_provider_client_impl.cc
index 50333c12aae..cdddd124e14 100644
--- a/chromium/cc/layers/video_frame_provider_client_impl.cc
+++ b/chromium/cc/layers/video_frame_provider_client_impl.cc
@@ -4,7 +4,7 @@
#include "cc/layers/video_frame_provider_client_impl.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
#include "cc/layers/video_layer_impl.h"
#include "media/base/video_frame.h"
@@ -13,17 +13,20 @@ namespace cc {
// static
scoped_refptr<VideoFrameProviderClientImpl>
- VideoFrameProviderClientImpl::Create(
- VideoFrameProvider* provider) {
- return make_scoped_refptr(
- new VideoFrameProviderClientImpl(provider));
+VideoFrameProviderClientImpl::Create(VideoFrameProvider* provider,
+ VideoFrameControllerClient* client) {
+ return make_scoped_refptr(new VideoFrameProviderClientImpl(provider, client));
}
-VideoFrameProviderClientImpl::~VideoFrameProviderClientImpl() {}
-
VideoFrameProviderClientImpl::VideoFrameProviderClientImpl(
- VideoFrameProvider* provider)
- : active_video_layer_(nullptr), provider_(provider) {
+ VideoFrameProvider* provider,
+ VideoFrameControllerClient* client)
+ : provider_(provider),
+ client_(client),
+ active_video_layer_(nullptr),
+ stopped_(false),
+ rendering_(false),
+ needs_put_current_frame_(false) {
// This only happens during a commit on the compositor thread while the main
// thread is blocked. That makes this a thread-safe call to set the video
// frame provider client that does not require a lock. The same is true of
@@ -39,15 +42,44 @@ VideoFrameProviderClientImpl::VideoFrameProviderClientImpl(
0.0, 0.0, 0.0, 1.0);
}
+VideoFrameProviderClientImpl::~VideoFrameProviderClientImpl() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(stopped_);
+}
+
+VideoLayerImpl* VideoFrameProviderClientImpl::ActiveVideoLayer() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return active_video_layer_;
+}
+
+void VideoFrameProviderClientImpl::SetActiveVideoLayer(
+ VideoLayerImpl* video_layer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(video_layer);
+ active_video_layer_ = video_layer;
+}
+
void VideoFrameProviderClientImpl::Stop() {
- if (!provider_)
- return;
- provider_->SetVideoFrameProviderClient(nullptr);
- provider_ = nullptr;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // It's called when the main thread is blocked, so lock isn't needed.
+ if (provider_) {
+ provider_->SetVideoFrameProviderClient(nullptr);
+ provider_ = nullptr;
+ }
+ if (rendering_)
+ StopRendering();
+ active_video_layer_ = nullptr;
+ stopped_ = true;
+}
+
+bool VideoFrameProviderClientImpl::Stopped() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return stopped_;
}
scoped_refptr<media::VideoFrame>
VideoFrameProviderClientImpl::AcquireLockAndCurrentFrame() {
+ DCHECK(thread_checker_.CalledOnValidThread());
provider_lock_.Acquire(); // Balanced by call to ReleaseLock().
if (!provider_)
return nullptr;
@@ -55,22 +87,55 @@ VideoFrameProviderClientImpl::AcquireLockAndCurrentFrame() {
return provider_->GetCurrentFrame();
}
-void VideoFrameProviderClientImpl::PutCurrentFrame(
- const scoped_refptr<media::VideoFrame>& frame) {
+void VideoFrameProviderClientImpl::PutCurrentFrame() {
+ DCHECK(thread_checker_.CalledOnValidThread());
provider_lock_.AssertAcquired();
- provider_->PutCurrentFrame(frame);
+ provider_->PutCurrentFrame();
+ needs_put_current_frame_ = false;
}
void VideoFrameProviderClientImpl::ReleaseLock() {
+ DCHECK(thread_checker_.CalledOnValidThread());
provider_lock_.AssertAcquired();
provider_lock_.Release();
}
+bool VideoFrameProviderClientImpl::HasCurrentFrame() {
+ base::AutoLock locker(provider_lock_);
+ return provider_ && provider_->HasCurrentFrame();
+}
+
+const gfx::Transform& VideoFrameProviderClientImpl::StreamTextureMatrix()
+ const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return stream_texture_matrix_;
+}
+
void VideoFrameProviderClientImpl::StopUsingProvider() {
// Block the provider from shutting down until this client is done
// using the frame.
base::AutoLock locker(provider_lock_);
provider_ = nullptr;
+ if (rendering_)
+ StopRendering();
+}
+
+void VideoFrameProviderClientImpl::StartRendering() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ TRACE_EVENT0("cc", "VideoFrameProviderClientImpl::StartRendering");
+ DCHECK(!rendering_);
+ DCHECK(!stopped_);
+ rendering_ = true;
+ client_->AddVideoFrameController(this);
+}
+
+void VideoFrameProviderClientImpl::StopRendering() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ TRACE_EVENT0("cc", "VideoFrameProviderClientImpl::StopRendering");
+ DCHECK(rendering_);
+ DCHECK(!stopped_);
+ client_->RemoveVideoFrameController(this);
+ rendering_ = false;
}
void VideoFrameProviderClientImpl::DidReceiveFrame() {
@@ -78,11 +143,14 @@ void VideoFrameProviderClientImpl::DidReceiveFrame() {
"VideoFrameProviderClientImpl::DidReceiveFrame",
"active_video_layer",
!!active_video_layer_);
+ DCHECK(thread_checker_.CalledOnValidThread());
+ needs_put_current_frame_ = true;
if (active_video_layer_)
active_video_layer_->SetNeedsRedraw();
}
void VideoFrameProviderClientImpl::DidUpdateMatrix(const float* matrix) {
+ DCHECK(thread_checker_.CalledOnValidThread());
stream_texture_matrix_ = gfx::Transform(
matrix[0], matrix[4], matrix[8], matrix[12],
matrix[1], matrix[5], matrix[9], matrix[13],
@@ -92,4 +160,33 @@ void VideoFrameProviderClientImpl::DidUpdateMatrix(const float* matrix) {
active_video_layer_->SetNeedsRedraw();
}
+void VideoFrameProviderClientImpl::OnBeginFrame(const BeginFrameArgs& args) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(rendering_);
+ DCHECK(!stopped_);
+
+ TRACE_EVENT0("cc", "VideoFrameProviderClientImpl::OnBeginFrame");
+ base::AutoLock locker(provider_lock_);
+
+ // We use frame_time + interval here because that is the estimated time at
+ // which a frame returned during this phase will end up being displayed.
+ if (!provider_ ||
+ !provider_->UpdateCurrentFrame(args.frame_time + args.interval,
+ args.frame_time + 2 * args.interval)) {
+ return;
+ }
+
+ DidReceiveFrame();
+}
+
+void VideoFrameProviderClientImpl::DidDrawFrame() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ {
+ base::AutoLock locker(provider_lock_);
+ if (provider_ && needs_put_current_frame_)
+ provider_->PutCurrentFrame();
+ }
+ needs_put_current_frame_ = false;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/video_frame_provider_client_impl.h b/chromium/cc/layers/video_frame_provider_client_impl.h
index b6eb86f0fef..5429228b49b 100644
--- a/chromium/cc/layers/video_frame_provider_client_impl.h
+++ b/chromium/cc/layers/video_frame_provider_client_impl.h
@@ -7,7 +7,10 @@
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "cc/base/cc_export.h"
#include "cc/layers/video_frame_provider.h"
+#include "cc/scheduler/video_frame_controller.h"
#include "ui/gfx/transform.h"
namespace media { class VideoFrame; }
@@ -15,44 +18,67 @@ namespace media { class VideoFrame; }
namespace cc {
class VideoLayerImpl;
-class VideoFrameProviderClientImpl
+// VideoFrameProviderClientImpl liasons with the VideoFrameProvider and the
+// VideoLayer. It receives updates from the provider and updates the layer as a
+// result. It also allows the layer to access the video frame that the provider
+// has.
+class CC_EXPORT VideoFrameProviderClientImpl
: public VideoFrameProvider::Client,
+ public VideoFrameController,
public base::RefCounted<VideoFrameProviderClientImpl> {
public:
+ // Must be created on the impl thread while the main thread is blocked.
static scoped_refptr<VideoFrameProviderClientImpl> Create(
- VideoFrameProvider* provider);
+ VideoFrameProvider* provider,
+ VideoFrameControllerClient* client);
- VideoLayerImpl* active_video_layer() { return active_video_layer_; }
- void set_active_video_layer(VideoLayerImpl* video_layer) {
- active_video_layer_ = video_layer;
- }
+ VideoLayerImpl* ActiveVideoLayer() const;
+ void SetActiveVideoLayer(VideoLayerImpl* video_layer);
+ bool Stopped() const;
+ // Must be called on the impl thread while the main thread is blocked.
void Stop();
- bool Stopped() const { return !provider_; }
scoped_refptr<media::VideoFrame> AcquireLockAndCurrentFrame();
- void PutCurrentFrame(const scoped_refptr<media::VideoFrame>& frame);
+ void PutCurrentFrame();
void ReleaseLock();
- const gfx::Transform& stream_texture_matrix() const {
- return stream_texture_matrix_;
- }
+ bool HasCurrentFrame();
- // VideoFrameProvider::Client implementation. These methods are all callable
- // on any thread.
+ const gfx::Transform& StreamTextureMatrix() const;
+
+ // VideoFrameController implementation.
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ void DidDrawFrame() override;
+
+ // VideoFrameProvider::Client implementation.
+ // Called on the main thread.
void StopUsingProvider() override;
+ // Called on the impl thread.
+ void StartRendering() override;
+ void StopRendering() override;
void DidReceiveFrame() override;
void DidUpdateMatrix(const float* matrix) override;
private:
- explicit VideoFrameProviderClientImpl(VideoFrameProvider* provider);
friend class base::RefCounted<VideoFrameProviderClientImpl>;
+
+ VideoFrameProviderClientImpl(VideoFrameProvider* provider,
+ VideoFrameControllerClient* client);
~VideoFrameProviderClientImpl() override;
+ VideoFrameProvider* provider_;
+ VideoFrameControllerClient* client_;
VideoLayerImpl* active_video_layer_;
-
- // Guards the destruction of provider_ and the frame that it provides
+ bool stopped_;
+ bool rendering_;
+ bool needs_put_current_frame_;
+
+ // Since the provider lives on another thread, it can be destroyed while the
+ // frame controller are accessing its frame. Before being destroyed the
+ // provider calls StopUsingProvider. provider_lock_ blocks StopUsingProvider
+ // from returning until the frame controller is done using the frame.
base::Lock provider_lock_;
- VideoFrameProvider* provider_;
+ base::ThreadChecker thread_checker_;
gfx::Transform stream_texture_matrix_;
diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc
index 8251a094877..d73786d9bf4 100644
--- a/chromium/cc/layers/video_layer_impl.cc
+++ b/chromium/cc/layers/video_layer_impl.cc
@@ -30,18 +30,24 @@ scoped_ptr<VideoLayerImpl> VideoLayerImpl::Create(
int id,
VideoFrameProvider* provider,
media::VideoRotation video_rotation) {
- scoped_ptr<VideoLayerImpl> layer(
- new VideoLayerImpl(tree_impl, id, video_rotation));
- layer->SetProviderClientImpl(VideoFrameProviderClientImpl::Create(provider));
- DCHECK(tree_impl->proxy()->IsImplThread());
DCHECK(tree_impl->proxy()->IsMainThreadBlocked());
- return layer.Pass();
+ DCHECK(tree_impl->proxy()->IsImplThread());
+
+ scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl =
+ VideoFrameProviderClientImpl::Create(
+ provider, tree_impl->GetVideoFrameControllerClient());
+
+ return make_scoped_ptr(
+ new VideoLayerImpl(tree_impl, id, provider_client_impl, video_rotation));
}
-VideoLayerImpl::VideoLayerImpl(LayerTreeImpl* tree_impl,
- int id,
- media::VideoRotation video_rotation)
+VideoLayerImpl::VideoLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ const scoped_refptr<VideoFrameProviderClientImpl>& provider_client_impl,
+ media::VideoRotation video_rotation)
: LayerImpl(tree_impl, id),
+ provider_client_impl_(provider_client_impl),
frame_(nullptr),
video_rotation_(video_rotation) {
}
@@ -61,18 +67,12 @@ VideoLayerImpl::~VideoLayerImpl() {
scoped_ptr<LayerImpl> VideoLayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return make_scoped_ptr(new VideoLayerImpl(tree_impl, id(), video_rotation_));
-}
-
-void VideoLayerImpl::PushPropertiesTo(LayerImpl* layer) {
- LayerImpl::PushPropertiesTo(layer);
-
- VideoLayerImpl* other = static_cast<VideoLayerImpl*>(layer);
- other->SetProviderClientImpl(provider_client_impl_);
+ return make_scoped_ptr(new VideoLayerImpl(
+ tree_impl, id(), provider_client_impl_, video_rotation_));
}
void VideoLayerImpl::DidBecomeActive() {
- provider_client_impl_->set_active_video_layer(this);
+ provider_client_impl_->SetActiveVideoLayer(this);
}
bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
@@ -132,7 +132,6 @@ bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
}
void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) {
DCHECK(frame_.get());
@@ -159,14 +158,9 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->SetAll(transform,
- rotated_size,
- visible_content_rect(),
- clip_rect(),
- is_clipped(),
- draw_opacity(),
- blend_mode(),
- sorting_context_id());
+ shared_quad_state->SetAll(transform, rotated_size, visible_content_rect(),
+ clip_rect(), is_clipped(), draw_opacity(),
+ draw_blend_mode(), sorting_context_id());
AppendDebugBorderQuad(
render_pass, rotated_size, shared_quad_state, append_quads_data);
@@ -177,7 +171,9 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
gfx::Size coded_size = frame_->coded_size();
Occlusion occlusion_in_video_space =
- occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(transform);
+ draw_properties()
+ .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
+ transform);
gfx::Rect visible_quad_rect =
occlusion_in_video_space.GetUnoccludedContentRect(quad_rect);
if (visible_quad_rect.IsEmpty())
@@ -188,10 +184,6 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
static_cast<float>(visible_rect.width()) / coded_size.width();
const float tex_height_scale =
static_cast<float>(visible_rect.height()) / coded_size.height();
- const float tex_x_offset =
- static_cast<float>(visible_rect.x()) / coded_size.width();
- const float tex_y_offset =
- static_cast<float>(visible_rect.y()) / coded_size.height();
switch (frame_resource_type_) {
// TODO(danakj): Remove this, hide it in the hardware path.
@@ -205,6 +197,7 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
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;
TextureDrawQuad* texture_quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
texture_quad->SetNew(shared_quad_state,
@@ -217,43 +210,79 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
uv_bottom_right,
SK_ColorTRANSPARENT,
opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(texture_quad);
break;
}
case VideoFrameExternalResources::YUV_RESOURCE: {
DCHECK_GE(frame_resources_.size(), 3u);
- if (frame_resources_.size() < 3u)
- break;
- YUVVideoDrawQuad::ColorSpace color_space =
- frame_->format() == media::VideoFrame::YV12J
- ? YUVVideoDrawQuad::REC_601_JPEG
- : YUVVideoDrawQuad::REC_601;
- gfx::RectF tex_coord_rect(
- tex_x_offset, tex_y_offset, tex_width_scale, tex_height_scale);
+
+ YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601;
+ if (frame_->format() == media::VideoFrame::YV12J) {
+ color_space = YUVVideoDrawQuad::JPEG;
+ } else if (frame_->format() == media::VideoFrame::YV12HD) {
+ color_space = YUVVideoDrawQuad::REC_709;
+ }
+
+ const gfx::Size ya_tex_size = coded_size;
+ gfx::Size uv_tex_size;
+
+ if (frame_->format() == media::VideoFrame::NATIVE_TEXTURE) {
+ DCHECK_EQ(media::VideoFrame::TEXTURE_YUV_420, frame_->texture_format());
+ DCHECK_EQ(3u, frame_resources_.size()); // Alpha is not supported yet.
+ DCHECK(visible_rect.origin().IsOrigin());
+ DCHECK(visible_rect.size() == coded_size);
+ uv_tex_size.SetSize((ya_tex_size.width() + 1) / 2,
+ (ya_tex_size.height() + 1) / 2);
+ } else {
+ uv_tex_size = media::VideoFrame::PlaneSize(
+ frame_->format(), media::VideoFrame::kUPlane, coded_size);
+ DCHECK(uv_tex_size ==
+ media::VideoFrame::PlaneSize(
+ frame_->format(), media::VideoFrame::kVPlane, coded_size));
+ DCHECK_IMPLIES(
+ frame_resources_.size() > 3,
+ ya_tex_size ==
+ media::VideoFrame::PlaneSize(
+ frame_->format(), media::VideoFrame::kAPlane, coded_size));
+ }
+
+ // Compute the UV sub-sampling factor based on the ratio between
+ // |ya_tex_size| and |uv_tex_size|.
+ float uv_subsampling_factor_x =
+ static_cast<float>(ya_tex_size.width()) / uv_tex_size.width();
+ float uv_subsampling_factor_y =
+ static_cast<float>(ya_tex_size.height()) / uv_tex_size.height();
+ gfx::RectF ya_tex_coord_rect(visible_rect);
+ gfx::RectF uv_tex_coord_rect(
+ visible_rect.x() / uv_subsampling_factor_x,
+ visible_rect.y() / uv_subsampling_factor_y,
+ visible_rect.width() / uv_subsampling_factor_x,
+ visible_rect.height() / uv_subsampling_factor_y);
+
YUVVideoDrawQuad* yuv_video_quad =
render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
yuv_video_quad->SetNew(
- shared_quad_state,
- quad_rect,
- opaque_rect,
- visible_quad_rect,
- tex_coord_rect,
- frame_resources_[0],
- frame_resources_[1],
- frame_resources_[2],
- frame_resources_.size() > 3 ? frame_resources_[3] : 0,
- color_space);
+ shared_quad_state, quad_rect, opaque_rect, visible_quad_rect,
+ ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size, uv_tex_size,
+ frame_resources_[0], frame_resources_[1], frame_resources_[2],
+ frame_resources_.size() > 3 ? frame_resources_[3] : 0, color_space);
+ ValidateQuadResources(yuv_video_quad);
break;
}
+ case VideoFrameExternalResources::RGBA_RESOURCE:
case VideoFrameExternalResources::RGB_RESOURCE: {
DCHECK_EQ(frame_resources_.size(), 1u);
if (frame_resources_.size() < 1u)
break;
- bool premultiplied_alpha = true;
+ bool premultiplied_alpha =
+ (frame_resource_type_ == VideoFrameExternalResources::RGBA_RESOURCE);
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;
TextureDrawQuad* texture_quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
texture_quad->SetNew(shared_quad_state,
@@ -266,7 +295,9 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
uv_bottom_right,
SK_ColorTRANSPARENT,
opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+ ValidateQuadResources(texture_quad);
break;
}
case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
@@ -278,12 +309,10 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
StreamVideoDrawQuad* stream_video_quad =
render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
stream_video_quad->SetNew(
- shared_quad_state,
- quad_rect,
- opaque_rect,
- visible_quad_rect,
+ shared_quad_state, quad_rect, opaque_rect, visible_quad_rect,
frame_resources_[0],
- scale * provider_client_impl_->stream_texture_matrix());
+ scale * provider_client_impl_->StreamTextureMatrix());
+ ValidateQuadResources(stream_video_quad);
break;
}
case VideoFrameExternalResources::IO_SURFACE: {
@@ -299,15 +328,16 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
visible_rect.size(),
frame_resources_[0],
IOSurfaceDrawQuad::UNFLIPPED);
+ ValidateQuadResources(io_surface_quad);
break;
}
#if defined(VIDEO_HOLE)
- // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not
+ // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
// maintained by the general compositor team. Please contact the following
// people instead:
//
// wonsik@chromium.org
- // ycheo@chromium.org
+ // lcwu@chromium.org
case VideoFrameExternalResources::HOLE: {
DCHECK_EQ(frame_resources_.size(), 0u);
SolidColorDrawQuad* solid_color_draw_quad =
@@ -352,12 +382,19 @@ void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) {
frame_resources_.clear();
}
- provider_client_impl_->PutCurrentFrame(frame_);
+ provider_client_impl_->PutCurrentFrame();
frame_ = nullptr;
provider_client_impl_->ReleaseLock();
}
+SimpleEnclosedRegion VideoLayerImpl::VisibleContentOpaqueRegion() const {
+ // If we don't have a frame yet, then we don't have an opaque region.
+ if (!provider_client_impl_->HasCurrentFrame())
+ return SimpleEnclosedRegion();
+ return LayerImpl::VisibleContentOpaqueRegion();
+}
+
void VideoLayerImpl::ReleaseResources() {
updater_ = nullptr;
}
@@ -367,11 +404,6 @@ void VideoLayerImpl::SetNeedsRedraw() {
layer_tree_impl()->SetNeedsRedraw();
}
-void VideoLayerImpl::SetProviderClientImpl(
- scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl) {
- provider_client_impl_ = provider_client_impl;
-}
-
const char* VideoLayerImpl::LayerTypeAsString() const {
return "cc::VideoLayerImpl";
}
diff --git a/chromium/cc/layers/video_layer_impl.h b/chromium/cc/layers/video_layer_impl.h
index 1843ec7a651..aea38b5cbbe 100644
--- a/chromium/cc/layers/video_layer_impl.h
+++ b/chromium/cc/layers/video_layer_impl.h
@@ -23,6 +23,8 @@ class VideoFrameProviderClientImpl;
class CC_EXPORT VideoLayerImpl : public LayerImpl {
public:
+ // Must be called on the impl thread while the main thread is blocked. This is
+ // so that |provider| stays alive while this is being created.
static scoped_ptr<VideoLayerImpl> Create(LayerTreeImpl* tree_impl,
int id,
VideoFrameProvider* provider,
@@ -31,27 +33,24 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl {
// LayerImpl implementation.
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
- void PushPropertiesTo(LayerImpl* layer) override;
bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) override;
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override;
void DidDraw(ResourceProvider* resource_provider) override;
+ SimpleEnclosedRegion VisibleContentOpaqueRegion() const override;
void DidBecomeActive() override;
void ReleaseResources() override;
void SetNeedsRedraw();
-
- void SetProviderClientImpl(
- scoped_refptr<VideoFrameProviderClientImpl> provider_client_impl);
-
media::VideoRotation video_rotation() const { return video_rotation_; }
private:
- VideoLayerImpl(LayerTreeImpl* tree_impl,
- int id,
- media::VideoRotation video_rotation);
+ VideoLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ const scoped_refptr<VideoFrameProviderClientImpl>& provider_client_impl,
+ media::VideoRotation video_rotation);
const char* LayerTypeAsString() const override;
diff --git a/chromium/cc/layers/video_layer_impl_unittest.cc b/chromium/cc/layers/video_layer_impl_unittest.cc
index 2fde4957c26..b0ecff95d39 100644
--- a/chromium/cc/layers/video_layer_impl_unittest.cc
+++ b/chromium/cc/layers/video_layer_impl_unittest.cc
@@ -8,6 +8,7 @@
#include "cc/output/context_provider.h"
#include "cc/output/output_surface.h"
#include "cc/quads/draw_quad.h"
+#include "cc/quads/yuv_video_draw_quad.h"
#include "cc/test/fake_video_frame_provider.h"
#include "cc/test/layer_test_common.h"
#include "cc/trees/single_thread_proxy.h"
@@ -17,12 +18,22 @@
namespace cc {
namespace {
+// NOTE: We cannot use DebugScopedSetImplThreadAndMainThreadBlocked in these
+// tests because it gets destroyed before the VideoLayerImpl is destroyed. This
+// causes a DCHECK in VideoLayerImpl's destructor to fail.
+static void DebugSetImplThreadAndMainThreadBlocked(Proxy* proxy) {
+#if DCHECK_IS_ON()
+ proxy->SetCurrentThreadIsImplThread(true);
+ proxy->SetMainThreadBlocked(true);
+#endif
+}
+
TEST(VideoLayerImplTest, Occlusion) {
gfx::Size layer_size(1000, 1000);
gfx::Size viewport_size(1000, 1000);
LayerTestCommon::LayerImplTest impl;
- DebugScopedSetImplThreadAndMainThreadBlocked thread(impl.proxy());
+ DebugSetImplThreadAndMainThreadBlocked(impl.proxy());
scoped_refptr<media::VideoFrame> video_frame =
media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
@@ -74,9 +85,53 @@ TEST(VideoLayerImplTest, Occlusion) {
}
}
+TEST(VideoLayerImplTest, OccludesOtherLayers) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Rect visible(layer_size);
+
+ LayerTestCommon::LayerImplTest impl;
+ impl.host_impl()->SetViewportSize(layer_size);
+ DebugSetImplThreadAndMainThreadBlocked(impl.proxy());
+ auto active_tree = impl.host_impl()->active_tree();
+
+ // Create a video layer with no frame on top of another layer.
+ scoped_ptr<LayerImpl> layer_impl = LayerImpl::Create(active_tree, 3);
+ layer_impl->SetHasRenderSurface(true);
+ layer_impl->SetBounds(layer_size);
+ layer_impl->SetContentBounds(layer_size);
+ layer_impl->SetDrawsContent(true);
+ const auto& draw_properties = layer_impl->draw_properties();
+
+ FakeVideoFrameProvider provider;
+ scoped_ptr<VideoLayerImpl> video_layer_impl = VideoLayerImpl::Create(
+ active_tree, 4, &provider, media::VIDEO_ROTATION_0);
+ video_layer_impl->SetBounds(layer_size);
+ video_layer_impl->SetContentBounds(layer_size);
+ video_layer_impl->SetDrawsContent(true);
+ video_layer_impl->SetContentsOpaque(true);
+
+ layer_impl->AddChild(video_layer_impl.Pass());
+ active_tree->SetRootLayer(layer_impl.Pass());
+
+ active_tree->UpdateDrawProperties(false);
+
+ // We don't have a frame yet, so the video doesn't occlude the layer below it.
+ EXPECT_FALSE(draw_properties.occlusion_in_content_space.IsOccluded(visible));
+
+ scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
+ media::VideoFrame::YV12, gfx::Size(10, 10), gfx::Rect(10, 10),
+ gfx::Size(10, 10), base::TimeDelta());
+ provider.set_frame(video_frame);
+ active_tree->set_needs_update_draw_properties();
+ active_tree->UpdateDrawProperties(false);
+
+ // We have a frame now, so the video occludes the layer below it.
+ EXPECT_TRUE(draw_properties.occlusion_in_content_space.IsOccluded(visible));
+}
+
TEST(VideoLayerImplTest, DidBecomeActiveShouldSetActiveVideoLayer) {
LayerTestCommon::LayerImplTest impl;
- DebugScopedSetImplThreadAndMainThreadBlocked thread(impl.proxy());
+ DebugSetImplThreadAndMainThreadBlocked(impl.proxy());
FakeVideoFrameProvider provider;
VideoLayerImpl* video_layer_impl =
@@ -85,10 +140,10 @@ TEST(VideoLayerImplTest, DidBecomeActiveShouldSetActiveVideoLayer) {
VideoFrameProviderClientImpl* client =
static_cast<VideoFrameProviderClientImpl*>(provider.client());
ASSERT_TRUE(client);
- EXPECT_FALSE(client->active_video_layer());
+ EXPECT_FALSE(client->ActiveVideoLayer());
video_layer_impl->DidBecomeActive();
- EXPECT_EQ(video_layer_impl, client->active_video_layer());
+ EXPECT_EQ(video_layer_impl, client->ActiveVideoLayer());
}
TEST(VideoLayerImplTest, Rotated0) {
@@ -96,7 +151,7 @@ TEST(VideoLayerImplTest, Rotated0) {
gfx::Size viewport_size(1000, 500);
LayerTestCommon::LayerImplTest impl;
- DebugScopedSetImplThreadAndMainThreadBlocked thread(impl.proxy());
+ DebugSetImplThreadAndMainThreadBlocked(impl.proxy());
scoped_refptr<media::VideoFrame> video_frame =
media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
@@ -132,7 +187,7 @@ TEST(VideoLayerImplTest, Rotated90) {
gfx::Size viewport_size(1000, 500);
LayerTestCommon::LayerImplTest impl;
- DebugScopedSetImplThreadAndMainThreadBlocked thread(impl.proxy());
+ DebugSetImplThreadAndMainThreadBlocked(impl.proxy());
scoped_refptr<media::VideoFrame> video_frame =
media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
@@ -168,7 +223,7 @@ TEST(VideoLayerImplTest, Rotated180) {
gfx::Size viewport_size(1000, 500);
LayerTestCommon::LayerImplTest impl;
- DebugScopedSetImplThreadAndMainThreadBlocked thread(impl.proxy());
+ DebugSetImplThreadAndMainThreadBlocked(impl.proxy());
scoped_refptr<media::VideoFrame> video_frame =
media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
@@ -204,7 +259,7 @@ TEST(VideoLayerImplTest, Rotated270) {
gfx::Size viewport_size(1000, 500);
LayerTestCommon::LayerImplTest impl;
- DebugScopedSetImplThreadAndMainThreadBlocked thread(impl.proxy());
+ DebugSetImplThreadAndMainThreadBlocked(impl.proxy());
scoped_refptr<media::VideoFrame> video_frame =
media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
@@ -235,5 +290,85 @@ TEST(VideoLayerImplTest, Rotated270) {
EXPECT_EQ(gfx::Point3F(0, 0, 0), p2);
}
+void EmptyCallback(unsigned sync_point) {
+}
+
+TEST(VideoLayerImplTest, SoftwareVideoFrameGeneratesYUVQuad) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+ DebugSetImplThreadAndMainThreadBlocked(impl.proxy());
+
+ gpu::MailboxHolder mailbox_holder;
+ mailbox_holder.mailbox.name[0] = 1;
+
+ scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
+ media::VideoFrame::YV12, gfx::Size(20, 10), gfx::Rect(20, 10),
+ gfx::Size(20, 10), base::TimeDelta());
+
+ FakeVideoFrameProvider provider;
+ provider.set_frame(video_frame);
+
+ VideoLayerImpl* video_layer_impl =
+ impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0);
+ video_layer_impl->SetBounds(layer_size);
+ video_layer_impl->SetContentBounds(layer_size);
+ video_layer_impl->SetDrawsContent(true);
+
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
+
+ EXPECT_EQ(1u, impl.quad_list().size());
+ const DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
+ ASSERT_EQ(DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material);
+
+ const YUVVideoDrawQuad* yuv_draw_quad =
+ static_cast<const YUVVideoDrawQuad*>(draw_quad);
+ EXPECT_EQ(yuv_draw_quad->uv_tex_size.height(),
+ (yuv_draw_quad->ya_tex_size.height() + 1) / 2);
+ EXPECT_EQ(yuv_draw_quad->uv_tex_size.width(),
+ (yuv_draw_quad->ya_tex_size.width() + 1) / 2);
+}
+
+TEST(VideoLayerImplTest, NativeYUVFrameGeneratesYUVQuad) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+ DebugSetImplThreadAndMainThreadBlocked(impl.proxy());
+
+ gpu::MailboxHolder mailbox_holder;
+ mailbox_holder.mailbox.name[0] = 1;
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::WrapYUV420NativeTextures(
+ mailbox_holder, mailbox_holder, mailbox_holder,
+ base::Bind(EmptyCallback), gfx::Size(10, 10), gfx::Rect(10, 10),
+ gfx::Size(10, 10), base::TimeDelta(), true);
+ FakeVideoFrameProvider provider;
+ provider.set_frame(video_frame);
+
+ VideoLayerImpl* video_layer_impl =
+ impl.AddChildToRoot<VideoLayerImpl>(&provider, media::VIDEO_ROTATION_0);
+ video_layer_impl->SetBounds(layer_size);
+ video_layer_impl->SetContentBounds(layer_size);
+ video_layer_impl->SetDrawsContent(true);
+
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
+
+ EXPECT_EQ(1u, impl.quad_list().size());
+ const DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
+ ASSERT_EQ(DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material);
+
+ const YUVVideoDrawQuad* yuv_draw_quad =
+ static_cast<const YUVVideoDrawQuad*>(draw_quad);
+ EXPECT_EQ(yuv_draw_quad->uv_tex_size.height(),
+ (yuv_draw_quad->ya_tex_size.height() + 1) / 2);
+ EXPECT_EQ(yuv_draw_quad->uv_tex_size.width(),
+ (yuv_draw_quad->ya_tex_size.width() + 1) / 2);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/viewport.cc b/chromium/cc/layers/viewport.cc
new file mode 100644
index 00000000000..944f1bbd3cf
--- /dev/null
+++ b/chromium/cc/layers/viewport.cc
@@ -0,0 +1,133 @@
+// 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.
+
+#include "cc/layers/viewport.h"
+
+#include "base/logging.h"
+#include "cc/input/top_controls_manager.h"
+#include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace cc {
+
+// static
+scoped_ptr<Viewport> Viewport::Create(
+ LayerTreeHostImpl* host_impl) {
+ return make_scoped_ptr(new Viewport(host_impl));
+}
+
+Viewport::Viewport(LayerTreeHostImpl* host_impl)
+ : host_impl_(host_impl) {
+ DCHECK(host_impl_);
+}
+
+Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta,
+ const gfx::Point& viewport_point,
+ bool is_wheel_scroll) {
+ gfx::Vector2dF content_delta = delta;
+ ScrollResult result;
+
+ if (ShouldTopControlsConsumeScroll(delta)) {
+ result.top_controls_applied_delta = ScrollTopControls(delta);
+ content_delta -= result.top_controls_applied_delta;
+ }
+
+ gfx::Vector2dF pending_content_delta = content_delta;
+
+ if (OuterScrollLayer()) {
+ pending_content_delta -= host_impl_->ScrollLayer(OuterScrollLayer(),
+ pending_content_delta,
+ viewport_point,
+ is_wheel_scroll);
+ }
+
+ // TODO(bokan): This shouldn't be needed but removing it causes subtle
+ // viewport movement during top controls manipulation.
+ if (!gfx::ToRoundedVector2d(pending_content_delta).IsZero()) {
+ pending_content_delta -= host_impl_->ScrollLayer(InnerScrollLayer(),
+ pending_content_delta,
+ viewport_point,
+ is_wheel_scroll);
+ result.unused_scroll_delta = AdjustOverscroll(pending_content_delta);
+ }
+
+
+ result.applied_delta = content_delta - pending_content_delta;
+ return result;
+}
+
+gfx::Vector2dF Viewport::ScrollTopControls(const gfx::Vector2dF& delta) {
+ gfx::Vector2dF excess_delta =
+ host_impl_->top_controls_manager()->ScrollBy(delta);
+
+ return delta - excess_delta;
+}
+
+bool Viewport::ShouldTopControlsConsumeScroll(
+ const gfx::Vector2dF& scroll_delta) const {
+ // Always consume if it's in the direction to show the top controls.
+ if (scroll_delta.y() < 0)
+ return true;
+
+ if (TotalScrollOffset().y() < MaxTotalScrollOffset().y())
+ return true;
+
+ return false;
+}
+
+gfx::Vector2dF Viewport::AdjustOverscroll(const gfx::Vector2dF& delta) const {
+ const float kEpsilon = 0.1f;
+ gfx::Vector2dF adjusted = delta;
+
+ if (std::abs(adjusted.x()) < kEpsilon)
+ adjusted.set_x(0.0f);
+ if (std::abs(adjusted.y()) < kEpsilon)
+ adjusted.set_y(0.0f);
+
+ // Disable overscroll on axes which are impossible to scroll.
+ if (host_impl_->settings().report_overscroll_only_for_scrollable_axes) {
+ if (std::abs(MaxTotalScrollOffset().x()) <= kEpsilon ||
+ !InnerScrollLayer()->user_scrollable_horizontal())
+ adjusted.set_x(0.0f);
+ if (std::abs(MaxTotalScrollOffset().y()) <= kEpsilon ||
+ !InnerScrollLayer()->user_scrollable_vertical())
+ adjusted.set_y(0.0f);
+ }
+
+ return adjusted;
+}
+
+gfx::ScrollOffset Viewport::MaxTotalScrollOffset() const {
+ gfx::ScrollOffset offset;
+
+ offset += InnerScrollLayer()->MaxScrollOffset();
+
+ if (OuterScrollLayer())
+ offset += OuterScrollLayer()->MaxScrollOffset();
+
+ return offset;
+}
+
+gfx::ScrollOffset Viewport::TotalScrollOffset() const {
+ gfx::ScrollOffset offset;
+
+ offset += InnerScrollLayer()->CurrentScrollOffset();
+
+ if (OuterScrollLayer())
+ offset += OuterScrollLayer()->CurrentScrollOffset();
+
+ return offset;
+}
+
+LayerImpl* Viewport::InnerScrollLayer() const {
+ return host_impl_->InnerViewportScrollLayer();
+}
+
+LayerImpl* Viewport::OuterScrollLayer() const {
+ return host_impl_->OuterViewportScrollLayer();
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/viewport.h b/chromium/cc/layers/viewport.h
new file mode 100644
index 00000000000..25528af02a4
--- /dev/null
+++ b/chromium/cc/layers/viewport.h
@@ -0,0 +1,59 @@
+// 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_LAYERS_VIEWPORT_H_
+#define CC_LAYERS_VIEWPORT_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/layers/layer_impl.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace cc {
+
+class LayerTreeHostImpl;
+
+// Encapsulates gesture handling logic on the viewport layers. The "viewport"
+// is made up of two scrolling layers, the inner viewport (visual) and the
+// outer viewport (layout) scroll layers. These layers have different scroll
+// bubbling behavior from the rest of the layer tree which is encoded in this
+// class.
+class CC_EXPORT Viewport {
+ public:
+ struct ScrollResult {
+ gfx::Vector2dF applied_delta;
+ gfx::Vector2dF unused_scroll_delta;
+ gfx::Vector2dF top_controls_applied_delta;
+ };
+
+ static scoped_ptr<Viewport> Create(LayerTreeHostImpl* host_impl);
+
+ // Scrolls the viewport, applying the unique bubbling between the inner and
+ // outer viewport. Scrolls can be consumed by top controls.
+ ScrollResult ScrollBy(const gfx::Vector2dF& delta,
+ const gfx::Point& viewport_point,
+ bool is_wheel_scroll);
+
+ private:
+ explicit Viewport(LayerTreeHostImpl* host_impl);
+
+ bool ShouldTopControlsConsumeScroll(const gfx::Vector2dF& scroll_delta) const;
+ gfx::Vector2dF AdjustOverscroll(const gfx::Vector2dF& delta) const;
+
+ // Sends the delta to the top controls, returns the amount applied.
+ gfx::Vector2dF ScrollTopControls(const gfx::Vector2dF& delta);
+
+ gfx::ScrollOffset MaxTotalScrollOffset() const;
+ gfx::ScrollOffset TotalScrollOffset() const;
+
+ LayerImpl* InnerScrollLayer() const;
+ LayerImpl* OuterScrollLayer() const;
+
+ LayerTreeHostImpl* host_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(Viewport);
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_VIEWPORT_H_
diff --git a/chromium/cc/output/begin_frame_args.cc b/chromium/cc/output/begin_frame_args.cc
index fc7098f4798..7a77be2bd52 100644
--- a/chromium/cc/output/begin_frame_args.cc
+++ b/chromium/cc/output/begin_frame_args.cc
@@ -4,11 +4,26 @@
#include "cc/output/begin_frame_args.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "ui/gfx/frame_time.h"
namespace cc {
+const char* BeginFrameArgs::TypeToString(BeginFrameArgsType type) {
+ switch (type) {
+ case BeginFrameArgs::INVALID:
+ return "INVALID";
+ case BeginFrameArgs::NORMAL:
+ return "NORMAL";
+ case BeginFrameArgs::MISSED:
+ return "MISSED";
+ case BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX:
+ return "BEGIN_FRAME_ARGS_TYPE_MAX";
+ }
+ NOTREACHED();
+ return "???";
+}
+
BeginFrameArgs::BeginFrameArgs()
: frame_time(base::TimeTicks()),
deadline(base::TimeTicks()),
@@ -26,58 +41,39 @@ BeginFrameArgs::BeginFrameArgs(base::TimeTicks frame_time,
type(type) {
}
-BeginFrameArgs BeginFrameArgs::CreateTyped(
- base::TimeTicks frame_time,
- base::TimeTicks deadline,
- base::TimeDelta interval,
- BeginFrameArgs::BeginFrameArgsType type) {
+BeginFrameArgs BeginFrameArgs::Create(BeginFrameArgs::CreationLocation location,
+ base::TimeTicks frame_time,
+ base::TimeTicks deadline,
+ base::TimeDelta interval,
+ BeginFrameArgs::BeginFrameArgsType type) {
DCHECK_NE(type, BeginFrameArgs::INVALID);
+ DCHECK_NE(type, BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX);
+#ifdef NDEBUG
return BeginFrameArgs(frame_time, deadline, interval, type);
+#else
+ BeginFrameArgs args = BeginFrameArgs(frame_time, deadline, interval, type);
+ args.created_from = location;
+ return args;
+#endif
}
-BeginFrameArgs BeginFrameArgs::Create(base::TimeTicks frame_time,
- base::TimeTicks deadline,
- base::TimeDelta interval) {
- return CreateTyped(frame_time, deadline, interval, BeginFrameArgs::NORMAL);
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat> BeginFrameArgs::AsValue()
- const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+BeginFrameArgs::AsValue() const {
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
AsValueInto(state.get());
return state;
}
-void BeginFrameArgs::AsValueInto(base::debug::TracedValue* state) const {
+void BeginFrameArgs::AsValueInto(base::trace_event::TracedValue* state) const {
state->SetString("type", "BeginFrameArgs");
- switch (type) {
- case BeginFrameArgs::INVALID:
- state->SetString("subtype", "INVALID");
- break;
- case BeginFrameArgs::NORMAL:
- state->SetString("subtype", "NORMAL");
- break;
- case BeginFrameArgs::SYNCHRONOUS:
- state->SetString("subtype", "SYNCHRONOUS");
- break;
- case BeginFrameArgs::MISSED:
- state->SetString("subtype", "MISSED");
- break;
- }
+ state->SetString("subtype", TypeToString(type));
state->SetDouble("frame_time_us", frame_time.ToInternalValue());
state->SetDouble("deadline_us", deadline.ToInternalValue());
state->SetDouble("interval_us", interval.InMicroseconds());
-}
-
-BeginFrameArgs BeginFrameArgs::CreateForSynchronousCompositor(
- base::TimeTicks now) {
- // For WebView/SynchronousCompositor, we always want to draw immediately,
- // so we set the deadline to 0 and guess that the interval is 16 milliseconds.
- if (now.is_null())
- now = gfx::FrameTime::Now();
- return CreateTyped(
- now, base::TimeTicks(), DefaultInterval(), BeginFrameArgs::SYNCHRONOUS);
+#ifndef NDEBUG
+ state->SetString("created_from", created_from.ToString());
+#endif
}
// This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
@@ -94,8 +90,4 @@ base::TimeDelta BeginFrameArgs::DefaultInterval() {
return base::TimeDelta::FromMicroseconds(16666);
}
-base::TimeDelta BeginFrameArgs::DefaultRetroactiveBeginFramePeriod() {
- return base::TimeDelta::FromMicroseconds(4444);
-}
-
} // namespace cc
diff --git a/chromium/cc/output/begin_frame_args.h b/chromium/cc/output/begin_frame_args.h
index c35a5005695..c22f7fdde97 100644
--- a/chromium/cc/output/begin_frame_args.h
+++ b/chromium/cc/output/begin_frame_args.h
@@ -5,42 +5,66 @@
#ifndef CC_OUTPUT_BEGIN_FRAME_ARGS_H_
#define CC_OUTPUT_BEGIN_FRAME_ARGS_H_
+#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "base/values.h"
#include "cc/base/cc_export.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
class TracedValue;
}
}
+/**
+ * In debug builds we trace the creation origin of BeginFrameArgs objects. We
+ * reuse the tracked_objects::Location system to do that.
+ *
+ * However, in release builds we don't want this as it doubles the size of the
+ * BeginFrameArgs object. As well it adds a number of largish strings to the
+ * binary. Despite the argument being unused, most compilers are unable to
+ * optimise it away even when unused. Instead we use the BEGINFRAME_FROM_HERE
+ * macro to prevent the data even getting referenced.
+ */
+#ifdef NDEBUG
+#define BEGINFRAME_FROM_HERE nullptr
+#else
+#define BEGINFRAME_FROM_HERE FROM_HERE
+#endif
+
namespace cc {
struct CC_EXPORT BeginFrameArgs {
enum BeginFrameArgsType {
INVALID,
NORMAL,
- SYNCHRONOUS,
MISSED,
+ // Not a real type, but used by the IPC system. Should always remain the
+ // *last* value in this enum.
+ BEGIN_FRAME_ARGS_TYPE_MAX,
};
+ static const char* TypeToString(BeginFrameArgsType type);
// Creates an invalid set of values.
BeginFrameArgs();
+#ifdef NDEBUG
+ typedef const void* CreationLocation;
+#else
+ typedef const tracked_objects::Location& CreationLocation;
+ tracked_objects::Location created_from;
+#endif
+
// You should be able to find all instances where a BeginFrame has been
// created by searching for "BeginFrameArgs::Create".
- static BeginFrameArgs Create(base::TimeTicks frame_time,
+ // The location argument should **always** be BEGINFRAME_FROM_HERE macro.
+ static BeginFrameArgs Create(CreationLocation location,
+ base::TimeTicks frame_time,
base::TimeTicks deadline,
- base::TimeDelta interval);
- static BeginFrameArgs CreateTyped(base::TimeTicks frame_time,
- base::TimeTicks deadline,
- base::TimeDelta interval,
- BeginFrameArgsType type);
- static BeginFrameArgs CreateForSynchronousCompositor(
- base::TimeTicks now = base::TimeTicks());
+ base::TimeDelta interval,
+ BeginFrameArgsType type);
// This is the default delta that will be used to adjust the deadline when
// proper draw-time estimations are not yet available.
@@ -50,16 +74,10 @@ struct CC_EXPORT BeginFrameArgs {
// magic numbers.
static base::TimeDelta DefaultInterval();
- // This is the default amount of time after the frame_time to retroactively
- // send a BeginFrame that had been skipped. This only has an effect if the
- // deadline has passed, since the deadline is also used to trigger BeginFrame
- // retroactively.
- static base::TimeDelta DefaultRetroactiveBeginFramePeriod();
-
bool IsValid() const { return interval >= base::TimeDelta(); }
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
- void AsValueInto(base::debug::TracedValue* dict) const;
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
base::TimeTicks frame_time;
base::TimeTicks deadline;
diff --git a/chromium/cc/output/begin_frame_args_unittest.cc b/chromium/cc/output/begin_frame_args_unittest.cc
index e0c8b3efd34..877a857c632 100644
--- a/chromium/cc/output/begin_frame_args_unittest.cc
+++ b/chromium/cc/output/begin_frame_args_unittest.cc
@@ -15,42 +15,62 @@ namespace {
TEST(BeginFrameArgsTest, Helpers) {
// Quick create methods work
- BeginFrameArgs args0 = CreateBeginFrameArgsForTesting();
+ BeginFrameArgs args0 = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
EXPECT_TRUE(args0.IsValid()) << args0;
- BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(0, 0, -1);
+ BeginFrameArgs args1 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 0, -1);
EXPECT_FALSE(args1.IsValid()) << args1;
- BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(1, 2, 3);
+ BeginFrameArgs args2 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 1, 2, 3);
EXPECT_TRUE(args2.IsValid()) << args2;
EXPECT_EQ(1, args2.frame_time.ToInternalValue());
EXPECT_EQ(2, args2.deadline.ToInternalValue());
EXPECT_EQ(3, args2.interval.ToInternalValue());
+ EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type);
- BeginFrameArgs args3 = CreateExpiredBeginFrameArgsForTesting();
+ BeginFrameArgs args3 =
+ CreateExpiredBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
EXPECT_TRUE(args3.IsValid()) << args3;
EXPECT_GT(gfx::FrameTime::Now(), args3.deadline);
+ EXPECT_EQ(BeginFrameArgs::NORMAL, args3.type);
+
+ BeginFrameArgs args4 = CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 1, 2, 3, BeginFrameArgs::MISSED);
+ EXPECT_TRUE(args4.IsValid()) << args4;
+ EXPECT_EQ(1, args4.frame_time.ToInternalValue());
+ EXPECT_EQ(2, args4.deadline.ToInternalValue());
+ EXPECT_EQ(3, args4.interval.ToInternalValue());
+ EXPECT_EQ(BeginFrameArgs::MISSED, args4.type);
// operator==
- EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6),
- CreateBeginFrameArgsForTesting(4, 5, 6));
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6));
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9,
+ BeginFrameArgs::MISSED),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9)),
+ "");
- EXPECT_NONFATAL_FAILURE(EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6),
- CreateBeginFrameArgsForTesting(7, 8, 9)),
- "");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9)),
+ "");
// operator<<
std::stringstream out1;
out1 << args1;
- EXPECT_EQ("BeginFrameArgs(0, 0, -1us)", out1.str());
+ EXPECT_EQ("BeginFrameArgs(NORMAL, 0, 0, -1us)", out1.str());
std::stringstream out2;
out2 << args2;
- EXPECT_EQ("BeginFrameArgs(1, 2, 3us)", out2.str());
+ EXPECT_EQ("BeginFrameArgs(NORMAL, 1, 2, 3us)", out2.str());
// PrintTo
- EXPECT_EQ(std::string("BeginFrameArgs(0, 0, -1us)"),
+ EXPECT_EQ(std::string("BeginFrameArgs(NORMAL, 0, 0, -1us)"),
::testing::PrintToString(args1));
- EXPECT_EQ(std::string("BeginFrameArgs(1, 2, 3us)"),
+ EXPECT_EQ(std::string("BeginFrameArgs(NORMAL, 1, 2, 3us)"),
::testing::PrintToString(args2));
}
@@ -59,19 +79,25 @@ TEST(BeginFrameArgsTest, Create) {
BeginFrameArgs args1;
EXPECT_FALSE(args1.IsValid()) << args1;
- BeginFrameArgs args2 =
- BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(1),
- base::TimeTicks::FromInternalValue(2),
- base::TimeDelta::FromInternalValue(3));
+ BeginFrameArgs args2 = BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, base::TimeTicks::FromInternalValue(1),
+ base::TimeTicks::FromInternalValue(2),
+ base::TimeDelta::FromInternalValue(3), BeginFrameArgs::NORMAL);
EXPECT_TRUE(args2.IsValid()) << args2;
EXPECT_EQ(1, args2.frame_time.ToInternalValue()) << args2;
EXPECT_EQ(2, args2.deadline.ToInternalValue()) << args2;
EXPECT_EQ(3, args2.interval.ToInternalValue()) << args2;
+ EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type) << args2;
+}
+
+#ifndef NDEBUG
+TEST(BeginFrameArgsTest, Location) {
+ tracked_objects::Location expected_location = BEGINFRAME_FROM_HERE;
- base::TimeTicks now = base::TimeTicks::FromInternalValue(1);
- EXPECT_EQ(CreateBeginFrameArgsForTesting(1, 0, 16666),
- BeginFrameArgs::CreateForSynchronousCompositor(now));
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting(expected_location);
+ EXPECT_EQ(expected_location.ToString(), args.created_from.ToString());
}
+#endif
} // namespace
} // namespace cc
diff --git a/chromium/cc/output/bsp_tree.cc b/chromium/cc/output/bsp_tree.cc
index e6596dab911..4eb87cb95d2 100644
--- a/chromium/cc/output/bsp_tree.cc
+++ b/chromium/cc/output/bsp_tree.cc
@@ -4,7 +4,6 @@
#include "cc/output/bsp_tree.h"
-#include <list>
#include <vector>
#include "base/memory/scoped_ptr.h"
@@ -63,10 +62,9 @@ void BspTree::BuildTree(BspNode* node,
scoped_ptr<DrawPolygon> polygon;
scoped_ptr<DrawPolygon> new_front;
scoped_ptr<DrawPolygon> new_back;
- bool split_result = false;
// Time to split this geometry, *it needs to be split by node_data.
polygon = polygon_list->take_front();
- split_result =
+ bool split_result =
polygon->Split(*(node->node_data), &new_front, &new_back);
DCHECK(split_result);
if (!split_result) {
diff --git a/chromium/cc/output/bsp_tree.h b/chromium/cc/output/bsp_tree.h
index 6e7f66ba9cd..29c8605b9b4 100644
--- a/chromium/cc/output/bsp_tree.h
+++ b/chromium/cc/output/bsp_tree.h
@@ -5,7 +5,6 @@
#ifndef CC_OUTPUT_BSP_TREE_H_
#define CC_OUTPUT_BSP_TREE_H_
-#include <list>
#include <vector>
#include "base/memory/scoped_ptr.h"
diff --git a/chromium/cc/output/bsp_walk_action.cc b/chromium/cc/output/bsp_walk_action.cc
index da5ada5a82a..9ffc2998d5e 100644
--- a/chromium/cc/output/bsp_walk_action.cc
+++ b/chromium/cc/output/bsp_walk_action.cc
@@ -9,15 +9,37 @@
#include "base/memory/scoped_ptr.h"
#include "cc/output/direct_renderer.h"
#include "cc/quads/draw_polygon.h"
+#include "cc/quads/draw_quad.h"
namespace cc {
-void BspWalkActionToVector::operator()(DrawPolygon* item) {
- list_->push_back(item);
+BspWalkActionDrawPolygon::BspWalkActionDrawPolygon(
+ DirectRenderer* renderer,
+ DirectRenderer::DrawingFrame* frame,
+ const gfx::Rect& render_pass_scissor,
+ bool using_scissor_as_optimization)
+ : renderer_(renderer),
+ frame_(frame),
+ render_pass_scissor_(render_pass_scissor),
+ using_scissor_as_optimization_(using_scissor_as_optimization) {
+}
+
+void BspWalkActionDrawPolygon::operator()(DrawPolygon* item) {
+ gfx::Transform inverse_transform;
+ bool invertible =
+ item->original_ref()->quadTransform().GetInverse(&inverse_transform);
+ DCHECK(invertible);
+ item->TransformToLayerSpace(inverse_transform);
+ renderer_->DoDrawPolygon(*item, frame_, render_pass_scissor_,
+ using_scissor_as_optimization_);
}
BspWalkActionToVector::BspWalkActionToVector(std::vector<DrawPolygon*>* in_list)
: list_(in_list) {
}
+void BspWalkActionToVector::operator()(DrawPolygon* item) {
+ list_->push_back(item);
+}
+
} // namespace cc
diff --git a/chromium/cc/output/bsp_walk_action.h b/chromium/cc/output/bsp_walk_action.h
index ac8fa417b7b..a89d8eab364 100644
--- a/chromium/cc/output/bsp_walk_action.h
+++ b/chromium/cc/output/bsp_walk_action.h
@@ -20,6 +20,22 @@ class CC_EXPORT BspWalkAction {
// The BspTree class takes ownership of all the DrawPolygons returned in list_
// so the BspTree must be preserved while elements in that vector are in use.
+class CC_EXPORT BspWalkActionDrawPolygon : public BspWalkAction {
+ public:
+ void operator()(DrawPolygon* item) override;
+
+ BspWalkActionDrawPolygon(DirectRenderer* renderer,
+ DirectRenderer::DrawingFrame* frame,
+ const gfx::Rect& render_pass_scissor,
+ bool using_scissor_as_optimization);
+
+ private:
+ DirectRenderer* renderer_;
+ DirectRenderer::DrawingFrame* frame_;
+ const gfx::Rect& render_pass_scissor_;
+ bool using_scissor_as_optimization_;
+};
+
class CC_EXPORT BspWalkActionToVector : public BspWalkAction {
public:
explicit BspWalkActionToVector(std::vector<DrawPolygon*>* in_list);
diff --git a/chromium/cc/output/compositor_frame_metadata.cc b/chromium/cc/output/compositor_frame_metadata.cc
index 039f69d31be..dad78a0c822 100644
--- a/chromium/cc/output/compositor_frame_metadata.cc
+++ b/chromium/cc/output/compositor_frame_metadata.cc
@@ -10,7 +10,9 @@ CompositorFrameMetadata::CompositorFrameMetadata()
: device_scale_factor(0.f),
page_scale_factor(0.f),
min_page_scale_factor(0.f),
- max_page_scale_factor(0.f) {
+ max_page_scale_factor(0.f),
+ root_overflow_x_hidden(false),
+ root_overflow_y_hidden(false) {
}
CompositorFrameMetadata::~CompositorFrameMetadata() {
diff --git a/chromium/cc/output/compositor_frame_metadata.h b/chromium/cc/output/compositor_frame_metadata.h
index a6fe2d4117a..999a6b4406a 100644
--- a/chromium/cc/output/compositor_frame_metadata.h
+++ b/chromium/cc/output/compositor_frame_metadata.h
@@ -34,6 +34,8 @@ class CC_EXPORT CompositorFrameMetadata {
gfx::SizeF root_layer_size;
float min_page_scale_factor;
float max_page_scale_factor;
+ bool root_overflow_x_hidden;
+ bool root_overflow_y_hidden;
// Used to position the Android location top bar and page content, whose
// precise position is computed by the renderer compositor.
@@ -42,8 +44,7 @@ class CC_EXPORT CompositorFrameMetadata {
// Provides selection region updates relative to the current viewport. If the
// selection is empty or otherwise unused, the bound types will indicate such.
- ViewportSelectionBound selection_start;
- ViewportSelectionBound selection_end;
+ ViewportSelection selection;
std::vector<ui::LatencyInfo> latency_info;
diff --git a/chromium/cc/output/context_provider.h b/chromium/cc/output/context_provider.h
index 7362e8b55aa..dfaab4a15b2 100644
--- a/chromium/cc/output/context_provider.h
+++ b/chromium/cc/output/context_provider.h
@@ -12,6 +12,10 @@
class GrContext;
+namespace base {
+class Lock;
+}
+
namespace gpu {
class ContextSupport;
namespace gles2 { class GLES2Interface; }
@@ -27,6 +31,7 @@ class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> {
// Once this function has been called, the class should only be accessed
// from the same thread.
virtual bool BindToCurrentThread() = 0;
+ virtual void DetachFromThread() {}
virtual gpu::gles2::GLES2Interface* ContextGL() = 0;
virtual gpu::ContextSupport* ContextSupport() = 0;
@@ -39,6 +44,17 @@ class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> {
CC_EXPORT Capabilities();
};
+ // Invalidates the cached OpenGL state in GrContext.
+ // See skia GrContext::resetContext for details.
+ virtual void InvalidateGrContext(uint32_t state) = 0;
+
+ // Sets up a lock so this context can be used from multiple threads.
+ virtual void SetupLock() = 0;
+
+ // Returns the lock that should be held if using this context from multiple
+ // threads.
+ virtual base::Lock* GetLock() = 0;
+
// Returns the capabilities of the currently bound 3d context.
virtual Capabilities ContextCapabilities() = 0;
diff --git a/chromium/cc/output/copy_output_request.cc b/chromium/cc/output/copy_output_request.cc
index 97b95e10e0f..d70bac1bfca 100644
--- a/chromium/cc/output/copy_output_request.cc
+++ b/chromium/cc/output/copy_output_request.cc
@@ -6,8 +6,8 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "cc/output/copy_output_result.h"
#include "cc/resources/texture_mailbox.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -32,7 +32,8 @@ CopyOutputRequest::CopyOutputRequest() {}
CopyOutputRequest::CopyOutputRequest(
bool force_bitmap_result,
const CopyOutputRequestCallback& result_callback)
- : force_bitmap_result_(force_bitmap_result),
+ : source_(nullptr),
+ force_bitmap_result_(force_bitmap_result),
has_area_(false),
has_texture_mailbox_(false),
result_callback_(result_callback) {
diff --git a/chromium/cc/output/copy_output_request.h b/chromium/cc/output/copy_output_request.h
index 58aa790d242..c634db44dda 100644
--- a/chromium/cc/output/copy_output_request.h
+++ b/chromium/cc/output/copy_output_request.h
@@ -41,6 +41,12 @@ class CC_EXPORT CopyOutputRequest {
bool IsEmpty() const { return result_callback_.is_null(); }
+ // Optionally specify the source of this copy request. If set when this copy
+ // request is submitted to a layer, a prior uncommitted copy request from the
+ // same |source| will be aborted.
+ void set_source(void* source) { source_ = source; }
+ void* source() const { return source_; }
+
bool force_bitmap_result() const { return force_bitmap_result_; }
// By default copy requests copy the entire layer's subtree output. If an
@@ -73,6 +79,7 @@ class CC_EXPORT CopyOutputRequest {
CopyOutputRequest(bool force_bitmap_result,
const CopyOutputRequestCallback& result_callback);
+ void* source_;
bool force_bitmap_result_;
bool has_area_;
bool has_texture_mailbox_;
diff --git a/chromium/cc/output/delegating_renderer.cc b/chromium/cc/output/delegating_renderer.cc
index dc951af194f..7906afa77e6 100644
--- a/chromium/cc/output/delegating_renderer.cc
+++ b/chromium/cc/output/delegating_renderer.cc
@@ -8,7 +8,7 @@
#include <string>
#include <vector>
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/output/compositor_frame_ack.h"
#include "cc/output/context_provider.h"
#include "cc/quads/draw_quad.h"
@@ -22,7 +22,7 @@ namespace cc {
scoped_ptr<DelegatingRenderer> DelegatingRenderer::Create(
RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider) {
return make_scoped_ptr(new DelegatingRenderer(
@@ -30,7 +30,7 @@ scoped_ptr<DelegatingRenderer> DelegatingRenderer::Create(
}
DelegatingRenderer::DelegatingRenderer(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider)
: Renderer(client, settings),
@@ -41,7 +41,8 @@ DelegatingRenderer::DelegatingRenderer(RendererClient* client,
capabilities_.using_partial_swap = false;
capabilities_.max_texture_size = resource_provider_->max_texture_size();
capabilities_.best_texture_format = resource_provider_->best_texture_format();
- capabilities_.allow_partial_texture_updates = false;
+ capabilities_.allow_partial_texture_updates =
+ output_surface->capabilities().can_force_reclaim_resources;
if (!output_surface_->context_provider()) {
capabilities_.using_shared_memory_resources = true;
@@ -55,6 +56,7 @@ DelegatingRenderer::DelegatingRenderer(RendererClient* client,
capabilities_.using_image = caps.gpu.image;
capabilities_.allow_rasterize_on_demand = false;
+ capabilities_.max_msaa_samples = caps.gpu.max_samples;
}
}
diff --git a/chromium/cc/output/delegating_renderer.h b/chromium/cc/output/delegating_renderer.h
index 89b47ad990e..b2bc01fd2ed 100644
--- a/chromium/cc/output/delegating_renderer.h
+++ b/chromium/cc/output/delegating_renderer.h
@@ -19,7 +19,7 @@ class CC_EXPORT DelegatingRenderer : public Renderer {
public:
static scoped_ptr<DelegatingRenderer> Create(
RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider);
~DelegatingRenderer() override;
@@ -39,7 +39,7 @@ class CC_EXPORT DelegatingRenderer : public Renderer {
private:
DelegatingRenderer(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider);
diff --git a/chromium/cc/output/delegating_renderer_unittest.cc b/chromium/cc/output/delegating_renderer_unittest.cc
index fffa0ac6a81..3238d2d9028 100644
--- a/chromium/cc/output/delegating_renderer_unittest.cc
+++ b/chromium/cc/output/delegating_renderer_unittest.cc
@@ -15,9 +15,9 @@ namespace cc {
class DelegatingRendererTest : public LayerTreeTest {
public:
DelegatingRendererTest() : LayerTreeTest(), output_surface_(NULL) {}
- virtual ~DelegatingRendererTest() {}
+ ~DelegatingRendererTest() override {}
- scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override {
+ scoped_ptr<OutputSurface> CreateOutputSurface() override {
scoped_ptr<FakeOutputSurface> output_surface =
FakeOutputSurface::CreateDelegating3d();
output_surface_ = output_surface.get();
diff --git a/chromium/cc/output/direct_renderer.cc b/chromium/cc/output/direct_renderer.cc
index 50d82d02cc8..10bba297434 100644
--- a/chromium/cc/output/direct_renderer.cc
+++ b/chromium/cc/output/direct_renderer.cc
@@ -9,9 +9,11 @@
#include "base/containers/hash_tables.h"
#include "base/containers/scoped_ptr_hash_map.h"
-#include "base/debug/trace_event.h"
#include "base/metrics/histogram.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
+#include "cc/output/bsp_tree.h"
+#include "cc/output/bsp_walk_action.h"
#include "cc/output/copy_output_request.h"
#include "cc/quads/draw_quad.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -106,11 +108,10 @@ void DirectRenderer::InitializeViewport(DrawingFrame* frame,
window_rect.y(),
window_rect.width(),
window_rect.height());
- SetDrawViewport(window_rect);
-
current_draw_rect_ = draw_rect;
current_viewport_rect_ = viewport_rect;
current_surface_size_ = surface_size;
+ current_window_space_viewport_ = window_rect;
}
gfx::Rect DirectRenderer::MoveFromDrawToWindowSpace(
@@ -125,7 +126,7 @@ gfx::Rect DirectRenderer::MoveFromDrawToWindowSpace(
}
DirectRenderer::DirectRenderer(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider)
: Renderer(client, settings),
@@ -145,9 +146,6 @@ void DirectRenderer::SetEnlargePassTextureAmountForTesting(
void DirectRenderer::DecideRenderPassAllocationsForFrame(
const RenderPassList& render_passes_in_draw_order) {
- if (!resource_provider_)
- return;
-
base::hash_map<RenderPassId, gfx::Size> render_passes_in_frame;
for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i)
render_passes_in_frame.insert(std::pair<RenderPassId, gfx::Size>(
@@ -155,11 +153,8 @@ void DirectRenderer::DecideRenderPassAllocationsForFrame(
RenderPassTextureSize(render_passes_in_draw_order[i])));
std::vector<RenderPassId> passes_to_delete;
- base::ScopedPtrHashMap<RenderPassId, ScopedResource>::const_iterator
- pass_iter;
- for (pass_iter = render_pass_textures_.begin();
- pass_iter != render_pass_textures_.end();
- ++pass_iter) {
+ for (auto pass_iter = render_pass_textures_.begin();
+ pass_iter != render_pass_textures_.end(); ++pass_iter) {
base::hash_map<RenderPassId, gfx::Size>::const_iterator it =
render_passes_in_frame.find(pass_iter->first);
if (it == render_passes_in_frame.end()) {
@@ -216,9 +211,6 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
frame.disable_picture_quad_image_filtering =
disable_picture_quad_image_filtering;
- overlay_processor_->ProcessForOverlays(render_passes_in_draw_order,
- &frame.overlay_list);
-
EnsureBackbuffer();
// Only reshape when we know we are going to draw. Otherwise, the reshape
@@ -227,6 +219,14 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
output_surface_->Reshape(device_viewport_rect.size(), device_scale_factor);
BeginDrawingFrame(&frame);
+
+ // If we have any copy requests, we can't remove any quads for overlays,
+ // otherwise the framebuffer will be missing the overlay contents.
+ if (root_render_pass->copy_requests.empty()) {
+ overlay_processor_->ProcessForOverlays(render_passes_in_draw_order,
+ &frame.overlay_list);
+ }
+
for (size_t i = 0; i < render_passes_in_draw_order->size(); ++i) {
RenderPass* pass = render_passes_in_draw_order->at(i);
DrawRenderPass(&frame, pass);
@@ -235,7 +235,7 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
pass->copy_requests.begin();
it != pass->copy_requests.end();
++it) {
- if (i > 0) {
+ if (it != pass->copy_requests.begin()) {
// Doing a readback is destructive of our state on Mac, so make sure
// we restore the state between readbacks. http://crbug.com/99393.
UseRenderPass(&frame, pass);
@@ -276,46 +276,65 @@ bool DirectRenderer::NeedDeviceClip(const DrawingFrame* frame) const {
return !frame->device_clip_rect.Contains(frame->device_viewport_rect);
}
-gfx::Rect DirectRenderer::DeviceClipRectInWindowSpace(const DrawingFrame* frame)
- const {
+gfx::Rect DirectRenderer::DeviceClipRectInDrawSpace(
+ const DrawingFrame* frame) const {
gfx::Rect device_clip_rect = frame->device_clip_rect;
- if (FlippedFramebuffer(frame))
- device_clip_rect.set_y(current_surface_size_.height() -
- device_clip_rect.bottom());
+ device_clip_rect -= current_viewport_rect_.OffsetFromOrigin();
+ device_clip_rect += current_draw_rect_.OffsetFromOrigin();
return device_clip_rect;
}
-void DirectRenderer::SetScissorStateForQuad(const DrawingFrame* frame,
- const DrawQuad& quad) {
- if (quad.isClipped()) {
- SetScissorTestRectInDrawSpace(frame, quad.clipRect());
- return;
+gfx::Rect DirectRenderer::DeviceViewportRectInDrawSpace(
+ const DrawingFrame* frame) const {
+ gfx::Rect device_viewport_rect = frame->device_viewport_rect;
+ device_viewport_rect -= current_viewport_rect_.OffsetFromOrigin();
+ device_viewport_rect += current_draw_rect_.OffsetFromOrigin();
+ return device_viewport_rect;
+}
+
+gfx::Rect DirectRenderer::OutputSurfaceRectInDrawSpace(
+ const DrawingFrame* frame) const {
+ if (frame->current_render_pass == frame->root_render_pass) {
+ gfx::Rect output_surface_rect(output_surface_->SurfaceSize());
+ output_surface_rect -= current_viewport_rect_.OffsetFromOrigin();
+ output_surface_rect += current_draw_rect_.OffsetFromOrigin();
+ return output_surface_rect;
+ } else {
+ return frame->current_render_pass->output_rect;
}
- if (NeedDeviceClip(frame)) {
- SetScissorTestRect(DeviceClipRectInWindowSpace(frame));
- return;
+}
+
+bool DirectRenderer::ShouldSkipQuad(const DrawQuad& quad,
+ const gfx::Rect& render_pass_scissor) {
+ if (render_pass_scissor.IsEmpty())
+ return true;
+
+ if (quad.isClipped()) {
+ gfx::Rect r = quad.clipRect();
+ r.Intersect(render_pass_scissor);
+ return r.IsEmpty();
}
- EnsureScissorTestDisabled();
+ return false;
}
-void DirectRenderer::SetScissorStateForQuadWithRenderPassScissor(
+void DirectRenderer::SetScissorStateForQuad(
const DrawingFrame* frame,
const DrawQuad& quad,
const gfx::Rect& render_pass_scissor,
- bool* should_skip_quad) {
- gfx::Rect quad_scissor_rect = render_pass_scissor;
-
- if (quad.isClipped())
- quad_scissor_rect.Intersect(quad.clipRect());
-
- if (quad_scissor_rect.IsEmpty()) {
- *should_skip_quad = true;
+ bool use_render_pass_scissor) {
+ if (use_render_pass_scissor) {
+ gfx::Rect quad_scissor_rect = render_pass_scissor;
+ if (quad.isClipped())
+ quad_scissor_rect.Intersect(quad.clipRect());
+ SetScissorTestRectInDrawSpace(frame, quad_scissor_rect);
+ return;
+ } else if (quad.isClipped()) {
+ SetScissorTestRectInDrawSpace(frame, quad.clipRect());
return;
}
- *should_skip_quad = false;
- SetScissorTestRectInDrawSpace(frame, quad_scissor_rect);
+ EnsureScissorTestDisabled();
}
void DirectRenderer::SetScissorTestRectInDrawSpace(
@@ -323,67 +342,140 @@ void DirectRenderer::SetScissorTestRectInDrawSpace(
const gfx::Rect& draw_space_rect) {
gfx::Rect window_space_rect =
MoveFromDrawToWindowSpace(frame, draw_space_rect);
- if (NeedDeviceClip(frame))
- window_space_rect.Intersect(DeviceClipRectInWindowSpace(frame));
SetScissorTestRect(window_space_rect);
}
void DirectRenderer::FinishDrawingQuadList() {}
+void DirectRenderer::DoDrawPolygon(const DrawPolygon& poly,
+ DrawingFrame* frame,
+ const gfx::Rect& render_pass_scissor,
+ bool use_render_pass_scissor) {
+ SetScissorStateForQuad(frame, *poly.original_ref(), render_pass_scissor,
+ use_render_pass_scissor);
+
+ // If the poly has not been split, then it is just a normal DrawQuad,
+ // and we should save any extra processing that would have to be done.
+ if (!poly.is_split()) {
+ DoDrawQuad(frame, poly.original_ref(), NULL);
+ return;
+ }
+
+ std::vector<gfx::QuadF> quads;
+ poly.ToQuads2D(&quads);
+ for (size_t i = 0; i < quads.size(); ++i) {
+ DoDrawQuad(frame, poly.original_ref(), &quads[i]);
+ }
+}
+
+void DirectRenderer::FlushPolygons(ScopedPtrDeque<DrawPolygon>* poly_list,
+ DrawingFrame* frame,
+ const gfx::Rect& render_pass_scissor,
+ bool use_render_pass_scissor) {
+ if (poly_list->empty()) {
+ return;
+ }
+
+ BspTree bsp_tree(poly_list);
+ BspWalkActionDrawPolygon action_handler(this, frame, render_pass_scissor,
+ use_render_pass_scissor);
+ bsp_tree.TraverseWithActionHandler(&action_handler);
+ DCHECK(poly_list->empty());
+}
+
void DirectRenderer::DrawRenderPass(DrawingFrame* frame,
const RenderPass* render_pass) {
TRACE_EVENT0("cc", "DirectRenderer::DrawRenderPass");
if (!UseRenderPass(frame, render_pass))
return;
- bool using_scissor_as_optimization = Capabilities().using_partial_swap;
- gfx::Rect render_pass_scissor;
- bool draw_rect_covers_full_surface = true;
- if (frame->current_render_pass == frame->root_render_pass &&
- !frame->device_viewport_rect.Contains(
- gfx::Rect(output_surface_->SurfaceSize())))
- draw_rect_covers_full_surface = false;
-
- if (using_scissor_as_optimization) {
- render_pass_scissor = ComputeScissorRectForRenderPass(frame);
- SetScissorTestRectInDrawSpace(frame, render_pass_scissor);
- if (!render_pass_scissor.Contains(frame->current_render_pass->output_rect))
- draw_rect_covers_full_surface = false;
+ const gfx::Rect surface_rect_in_draw_space =
+ OutputSurfaceRectInDrawSpace(frame);
+ gfx::Rect render_pass_scissor_in_draw_space = surface_rect_in_draw_space;
+
+ if (frame->current_render_pass == frame->root_render_pass) {
+ render_pass_scissor_in_draw_space.Intersect(
+ DeviceViewportRectInDrawSpace(frame));
}
- if (frame->current_render_pass != frame->root_render_pass ||
- settings_->should_clear_root_render_pass) {
- if (NeedDeviceClip(frame)) {
- SetScissorTestRect(DeviceClipRectInWindowSpace(frame));
- draw_rect_covers_full_surface = false;
- } else if (!using_scissor_as_optimization) {
- EnsureScissorTestDisabled();
- }
+ if (Capabilities().using_partial_swap) {
+ render_pass_scissor_in_draw_space.Intersect(
+ ComputeScissorRectForRenderPass(frame));
+ }
- bool has_external_stencil_test =
- output_surface_->HasExternalStencilTest() &&
- frame->current_render_pass == frame->root_render_pass;
+ if (NeedDeviceClip(frame)) {
+ render_pass_scissor_in_draw_space.Intersect(
+ DeviceClipRectInDrawSpace(frame));
+ }
- DiscardPixels(has_external_stencil_test, draw_rect_covers_full_surface);
- ClearFramebuffer(frame, has_external_stencil_test);
+ bool render_pass_is_clipped =
+ !render_pass_scissor_in_draw_space.Contains(surface_rect_in_draw_space);
+ bool is_root_render_pass =
+ frame->current_render_pass == frame->root_render_pass;
+ bool has_external_stencil_test =
+ is_root_render_pass && output_surface_->HasExternalStencilTest();
+ bool should_clear_surface =
+ !has_external_stencil_test &&
+ (!is_root_render_pass || settings_->should_clear_root_render_pass);
+
+ // If |has_external_stencil_test| we can't discard or clear. Make sure we
+ // don't need to.
+ DCHECK_IMPLIES(has_external_stencil_test,
+ !frame->current_render_pass->has_transparent_background);
+
+ SurfaceInitializationMode mode;
+ if (should_clear_surface && render_pass_is_clipped) {
+ mode = SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR;
+ } else if (should_clear_surface) {
+ mode = SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR;
+ } else {
+ mode = SURFACE_INITIALIZATION_MODE_PRESERVE;
}
+ PrepareSurfaceForPass(
+ frame, mode,
+ MoveFromDrawToWindowSpace(frame, render_pass_scissor_in_draw_space));
+
const QuadList& quad_list = render_pass->quad_list;
+ ScopedPtrDeque<DrawPolygon> poly_list;
+
+ int next_polygon_id = 0;
+ int last_sorting_context_id = 0;
for (auto it = quad_list.BackToFrontBegin(); it != quad_list.BackToFrontEnd();
++it) {
const DrawQuad& quad = **it;
- bool should_skip_quad = false;
+ gfx::QuadF send_quad(quad.visible_rect);
+
+ if (render_pass_is_clipped &&
+ ShouldSkipQuad(quad, render_pass_scissor_in_draw_space)) {
+ continue;
+ }
- if (using_scissor_as_optimization) {
- SetScissorStateForQuadWithRenderPassScissor(
- frame, quad, render_pass_scissor, &should_skip_quad);
- } else {
- SetScissorStateForQuad(frame, quad);
+ if (last_sorting_context_id != quad.shared_quad_state->sorting_context_id) {
+ last_sorting_context_id = quad.shared_quad_state->sorting_context_id;
+ FlushPolygons(&poly_list, frame, render_pass_scissor_in_draw_space,
+ render_pass_is_clipped);
+ }
+
+ // This layer is in a 3D sorting context so we add it to the list of
+ // polygons to go into the BSP tree.
+ if (quad.shared_quad_state->sorting_context_id != 0) {
+ scoped_ptr<DrawPolygon> new_polygon(new DrawPolygon(
+ *it, quad.visible_rect, quad.quadTransform(), next_polygon_id++));
+ if (new_polygon->points().size() > 2u) {
+ poly_list.push_back(new_polygon.Pass());
+ }
+ continue;
}
- if (!should_skip_quad)
- DoDrawQuad(frame, &quad);
+ // We are not in a 3d sorting context, so we should draw the quad normally.
+ SetScissorStateForQuad(frame, quad, render_pass_scissor_in_draw_space,
+ render_pass_is_clipped);
+
+ DoDrawQuad(frame, &quad, nullptr);
}
+ FlushPolygons(&poly_list, frame, render_pass_scissor_in_draw_space,
+ render_pass_is_clipped);
FinishDrawingQuadList();
}
@@ -391,7 +483,6 @@ bool DirectRenderer::UseRenderPass(DrawingFrame* frame,
const RenderPass* render_pass) {
frame->current_render_pass = render_pass;
frame->current_texture = NULL;
-
if (render_pass == frame->root_render_pass) {
BindFramebufferToOutputSurface(frame);
InitializeViewport(frame,
@@ -407,12 +498,20 @@ bool DirectRenderer::UseRenderPass(DrawingFrame* frame,
gfx::Size size = RenderPassTextureSize(render_pass);
size.Enlarge(enlarge_pass_texture_amount_.x(),
enlarge_pass_texture_amount_.y());
- if (!texture->id())
+ if (!texture->id()) {
texture->Allocate(
- size, ResourceProvider::TextureHintImmutableFramebuffer, RGBA_8888);
+ size, ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER, RGBA_8888);
+ }
DCHECK(texture->id());
- return BindFramebufferToTexture(frame, texture, render_pass->output_rect);
+ if (BindFramebufferToTexture(frame, texture, render_pass->output_rect)) {
+ InitializeViewport(frame, render_pass->output_rect,
+ gfx::Rect(render_pass->output_rect.size()),
+ render_pass->output_rect.size());
+ return true;
+ }
+
+ return false;
}
bool DirectRenderer::HasAllocatedResourcesForTesting(RenderPassId id) const {
diff --git a/chromium/cc/output/direct_renderer.h b/chromium/cc/output/direct_renderer.h
index 40fff835736..a4f184a30e6 100644
--- a/chromium/cc/output/direct_renderer.h
+++ b/chromium/cc/output/direct_renderer.h
@@ -9,13 +9,17 @@
#include "base/callback.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "cc/base/cc_export.h"
+#include "cc/base/scoped_ptr_deque.h"
#include "cc/output/overlay_processor.h"
#include "cc/output/renderer.h"
+#include "cc/raster/task_graph_runner.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/scoped_resource.h"
+#include "ui/gfx/geometry/quad_f.h"
namespace cc {
+class DrawPolygon;
class ResourceProvider;
// This is the base class for code shared between the GL and software
@@ -56,10 +60,20 @@ class CC_EXPORT DirectRenderer : public Renderer {
};
void SetEnlargePassTextureAmountForTesting(const gfx::Vector2d& amount);
+ void DoDrawPolygon(const DrawPolygon& poly,
+ DrawingFrame* frame,
+ const gfx::Rect& render_pass_scissor,
+ bool use_render_pass_scissor);
protected:
+ enum SurfaceInitializationMode {
+ SURFACE_INITIALIZATION_MODE_PRESERVE,
+ SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR,
+ SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR,
+ };
+
DirectRenderer(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider);
@@ -75,19 +89,25 @@ class CC_EXPORT DirectRenderer : public Renderer {
const gfx::Rect& draw_rect) const;
bool NeedDeviceClip(const DrawingFrame* frame) const;
- gfx::Rect DeviceClipRectInWindowSpace(const DrawingFrame* frame) const;
+ gfx::Rect DeviceClipRectInDrawSpace(const DrawingFrame* frame) const;
+ gfx::Rect DeviceViewportRectInDrawSpace(const DrawingFrame* frame) const;
+ gfx::Rect OutputSurfaceRectInDrawSpace(const DrawingFrame* frame) const;
static gfx::Rect ComputeScissorRectForRenderPass(const DrawingFrame* frame);
- void SetScissorStateForQuad(const DrawingFrame* frame, const DrawQuad& quad);
- void SetScissorStateForQuadWithRenderPassScissor(
- const DrawingFrame* frame,
- const DrawQuad& quad,
- const gfx::Rect& render_pass_scissor,
- bool* should_skip_quad);
+ void SetScissorStateForQuad(const DrawingFrame* frame,
+ const DrawQuad& quad,
+ const gfx::Rect& render_pass_scissor,
+ bool use_render_pass_scissor);
+ bool ShouldSkipQuad(const DrawQuad& quad,
+ const gfx::Rect& render_pass_scissor);
void SetScissorTestRectInDrawSpace(const DrawingFrame* frame,
const gfx::Rect& draw_space_rect);
static gfx::Size RenderPassTextureSize(const RenderPass* render_pass);
+ void FlushPolygons(ScopedPtrDeque<DrawPolygon>* poly_list,
+ DrawingFrame* frame,
+ const gfx::Rect& render_pass_scissor,
+ bool use_render_pass_scissor);
void DrawRenderPass(DrawingFrame* frame, const RenderPass* render_pass);
bool UseRenderPass(DrawingFrame* frame, const RenderPass* render_pass);
@@ -95,13 +115,17 @@ class CC_EXPORT DirectRenderer : public Renderer {
virtual bool BindFramebufferToTexture(DrawingFrame* frame,
const ScopedResource* resource,
const gfx::Rect& target_rect) = 0;
- virtual void SetDrawViewport(const gfx::Rect& window_space_viewport) = 0;
virtual void SetScissorTestRect(const gfx::Rect& scissor_rect) = 0;
- virtual void DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) = 0;
- virtual void ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) = 0;
- virtual void DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) = 0;
+ virtual void PrepareSurfaceForPass(
+ DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) = 0;
+ // clip_region is a (possibly null) pointer to a quad in the same
+ // space as the quad. When non-null only the area of the quad that overlaps
+ // with clip_region will be drawn.
+ virtual void DoDrawQuad(DrawingFrame* frame,
+ const DrawQuad* quad,
+ const gfx::QuadF* clip_region) = 0;
virtual void BeginDrawingFrame(DrawingFrame* frame) = 0;
virtual void FinishDrawingFrame(DrawingFrame* frame) = 0;
virtual void FinishDrawingQuadList();
@@ -115,19 +139,21 @@ class CC_EXPORT DirectRenderer : public Renderer {
DrawingFrame* frame,
scoped_ptr<CopyOutputRequest> request) = 0;
- base::ScopedPtrHashMap<RenderPassId, ScopedResource> render_pass_textures_;
+ base::ScopedPtrHashMap<RenderPassId, scoped_ptr<ScopedResource>>
+ render_pass_textures_;
OutputSurface* output_surface_;
ResourceProvider* resource_provider_;
scoped_ptr<OverlayProcessor> overlay_processor_;
// For use in coordinate conversion, this stores the output rect, viewport
- // rect (= unflipped version of glViewport rect), and the size of target
- // framebuffer. During a draw, this stores the values for the current render
- // pass; in between draws, they retain the values for the root render pass of
- // the last draw.
+ // rect (= unflipped version of glViewport rect), the size of target
+ // framebuffer, and the current window space viewport. During a draw, this
+ // stores the values for the current render pass; in between draws, they
+ // retain the values for the root render pass of the last draw.
gfx::Rect current_draw_rect_;
gfx::Rect current_viewport_rect_;
gfx::Size current_surface_size_;
+ gfx::Rect current_window_space_viewport_;
private:
gfx::Vector2d enlarge_pass_texture_amount_;
diff --git a/chromium/cc/output/dynamic_geometry_binding.cc b/chromium/cc/output/dynamic_geometry_binding.cc
new file mode 100644
index 00000000000..ecdf66e133e
--- /dev/null
+++ b/chromium/cc/output/dynamic_geometry_binding.cc
@@ -0,0 +1,66 @@
+// 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.
+
+#include "cc/output/dynamic_geometry_binding.h"
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace cc {
+
+DynamicGeometryBinding::DynamicGeometryBinding(gpu::gles2::GLES2Interface* gl)
+ : gl_(gl), quad_vertices_vbo_(0), quad_elements_vbo_(0) {
+ GeometryBindingQuad quads[1];
+ GeometryBindingQuadIndex quad_indices[1];
+
+ static_assert(sizeof(GeometryBindingQuad) == 24 * sizeof(float),
+ "struct Quad should be densely packed");
+ static_assert(sizeof(GeometryBindingQuadIndex) == 6 * sizeof(uint16_t),
+ "struct QuadIndex should be densely packed");
+
+ gl_->GenBuffers(1, &quad_vertices_vbo_);
+ gl_->GenBuffers(1, &quad_elements_vbo_);
+
+ gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_);
+ gl_->BufferData(GL_ARRAY_BUFFER, sizeof(GeometryBindingQuad) * 1, quads,
+ GL_DYNAMIC_DRAW);
+
+ gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_);
+ gl_->BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GeometryBindingQuadIndex) * 1,
+ &quad_indices, GL_DYNAMIC_DRAW);
+}
+
+void DynamicGeometryBinding::InitializeCustomQuad(const gfx::QuadF& quad) {
+ float uv[] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
+ InitializeCustomQuadWithUVs(quad, uv);
+}
+
+void DynamicGeometryBinding::InitializeCustomQuadWithUVs(const gfx::QuadF& quad,
+ const float uv[8]) {
+ GeometryBindingVertex v0 = {
+ {quad.p1().x(), quad.p1().y(), 0.0f}, {uv[0], uv[1]}, 0.0f};
+ GeometryBindingVertex v1 = {
+ {quad.p2().x(), quad.p2().y(), 0.0f}, {uv[2], uv[3]}, 1.0f};
+ GeometryBindingVertex v2 = {
+ {quad.p3().x(), quad.p3().y(), 0.0f}, {uv[4], uv[5]}, 2.0f};
+ GeometryBindingVertex v3 = {
+ {quad.p4().x(), quad.p4().y(), 0.0f}, {uv[6], uv[7]}, 3.0f};
+
+ GeometryBindingQuad local_quad = {v0, v1, v2, v3};
+ GeometryBindingQuadIndex quad_index(
+ static_cast<uint16>(0), static_cast<uint16>(1), static_cast<uint16>(2),
+ static_cast<uint16>(3), static_cast<uint16>(0), static_cast<uint16>(2));
+
+ gl_->BufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GeometryBindingQuad),
+ &local_quad);
+ gl_->BufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0,
+ sizeof(GeometryBindingQuadIndex), &quad_index);
+}
+
+void DynamicGeometryBinding::PrepareForDraw() {
+ SetupGLContext(gl_, quad_elements_vbo_, quad_vertices_vbo_);
+}
+
+} // namespace cc
diff --git a/chromium/cc/output/dynamic_geometry_binding.h b/chromium/cc/output/dynamic_geometry_binding.h
new file mode 100644
index 00000000000..4e4ea3d1fd1
--- /dev/null
+++ b/chromium/cc/output/dynamic_geometry_binding.h
@@ -0,0 +1,30 @@
+// 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_OUTPUT_DYNAMIC_GEOMETRY_BINDING_H_
+#define CC_OUTPUT_DYNAMIC_GEOMETRY_BINDING_H_
+
+#include "cc/output/geometry_binding.h"
+
+namespace cc {
+
+class DynamicGeometryBinding {
+ public:
+ explicit DynamicGeometryBinding(gpu::gles2::GLES2Interface* gl);
+ void PrepareForDraw();
+ void InitializeCustomQuad(const gfx::QuadF& quad);
+ void InitializeCustomQuadWithUVs(const gfx::QuadF& quad, const float uv[8]);
+
+ private:
+ gpu::gles2::GLES2Interface* gl_;
+
+ GLuint quad_vertices_vbo_;
+ GLuint quad_elements_vbo_;
+
+ DISALLOW_COPY_AND_ASSIGN(DynamicGeometryBinding);
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_DYNAMIC_GEOMETRY_BINDING_H_
diff --git a/chromium/cc/output/filter_operation.cc b/chromium/cc/output/filter_operation.cc
index 173985b384a..1579e554a04 100644
--- a/chromium/cc/output/filter_operation.cc
+++ b/chromium/cc/output/filter_operation.cc
@@ -4,7 +4,7 @@
#include <algorithm>
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
#include "cc/output/filter_operation.h"
@@ -255,7 +255,7 @@ FilterOperation FilterOperation::Blend(const FilterOperation* from,
return blended_filter;
}
-void FilterOperation::AsValueInto(base::debug::TracedValue* value) const {
+void FilterOperation::AsValueInto(base::trace_event::TracedValue* value) const {
value->SetInteger("type", type_);
switch (type_) {
case FilterOperation::GRAYSCALE:
@@ -272,9 +272,7 @@ void FilterOperation::AsValueInto(base::debug::TracedValue* value) const {
break;
case FilterOperation::DROP_SHADOW:
value->SetDouble("std_deviation", amount_);
- value->BeginArray("offset");
- MathUtil::AddToTracedValue(drop_shadow_offset_, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("offset", drop_shadow_offset_, value);
value->SetInteger("color", drop_shadow_color_);
break;
case FilterOperation::COLOR_MATRIX: {
diff --git a/chromium/cc/output/filter_operation.h b/chromium/cc/output/filter_operation.h
index fc14cb1017a..44590c233ba 100644
--- a/chromium/cc/output/filter_operation.h
+++ b/chromium/cc/output/filter_operation.h
@@ -16,7 +16,7 @@
#include "ui/gfx/geometry/point.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
class Value;
@@ -223,7 +223,7 @@ class CC_EXPORT FilterOperation {
const FilterOperation* to,
double progress);
- void AsValueInto(base::debug::TracedValue* value) const;
+ void AsValueInto(base::trace_event::TracedValue* value) const;
private:
FilterOperation(FilterType type, float amount);
diff --git a/chromium/cc/output/filter_operations.cc b/chromium/cc/output/filter_operations.cc
index dcdd4803fd6..92423de9b59 100644
--- a/chromium/cc/output/filter_operations.cc
+++ b/chromium/cc/output/filter_operations.cc
@@ -6,7 +6,7 @@
#include <cmath>
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/output/filter_operation.h"
@@ -197,7 +197,8 @@ FilterOperations FilterOperations::Blend(const FilterOperations& from,
return blended_filters;
}
-void FilterOperations::AsValueInto(base::debug::TracedValue* value) const {
+void FilterOperations::AsValueInto(
+ base::trace_event::TracedValue* value) const {
for (size_t i = 0; i < operations_.size(); ++i) {
value->BeginDictionary();
operations_[i].AsValueInto(value);
diff --git a/chromium/cc/output/filter_operations.h b/chromium/cc/output/filter_operations.h
index a8c206eacd1..7018b82af18 100644
--- a/chromium/cc/output/filter_operations.h
+++ b/chromium/cc/output/filter_operations.h
@@ -12,7 +12,7 @@
#include "cc/output/filter_operation.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
class Value;
@@ -70,7 +70,7 @@ class CC_EXPORT FilterOperations {
// a copy of this.
FilterOperations Blend(const FilterOperations& from, double progress) const;
- void AsValueInto(base::debug::TracedValue* value) const;
+ void AsValueInto(base::trace_event::TracedValue* value) const;
private:
std::vector<FilterOperation> operations_;
diff --git a/chromium/cc/output/geometry_binding.cc b/chromium/cc/output/geometry_binding.cc
index b8c97596185..9a87c7f149e 100644
--- a/chromium/cc/output/geometry_binding.cc
+++ b/chromium/cc/output/geometry_binding.cc
@@ -4,111 +4,70 @@
#include "cc/output/geometry_binding.h"
-#include "cc/output/gl_renderer.h" // For the GLC() macro.
#include "gpu/command_buffer/client/gles2_interface.h"
#include "ui/gfx/geometry/rect_f.h"
namespace cc {
-GeometryBinding::GeometryBinding(gpu::gles2::GLES2Interface* gl,
- const gfx::RectF& quad_vertex_rect)
- : gl_(gl), quad_vertices_vbo_(0), quad_elements_vbo_(0) {
- struct Vertex {
- float a_position[3];
- float a_texCoord[2];
- // Index of the vertex, divide by 4 to have the matrix for this quad.
- float a_index;
- };
- struct Quad {
- Vertex v0, v1, v2, v3;
- };
- struct QuadIndex {
- uint16 data[6];
- };
-
- COMPILE_ASSERT(sizeof(Quad) == 24 * sizeof(float), // NOLINT(runtime/sizeof)
- struct_is_densely_packed);
- COMPILE_ASSERT(
- sizeof(QuadIndex) == 6 * sizeof(uint16_t), // NOLINT(runtime/sizeof)
- struct_is_densely_packed);
+void SetupGLContext(gpu::gles2::GLES2Interface* gl,
+ GLuint quad_elements_vbo,
+ GLuint quad_vertices_vbo) {
+ gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo);
- Quad quad_list[8];
- QuadIndex quad_index_list[8];
- for (int i = 0; i < 8; i++) {
- Vertex v0 = {{quad_vertex_rect.x(), quad_vertex_rect.bottom(), 0.0f, },
- {0.0f, 1.0f, }, i * 4.0f + 0.0f};
- Vertex v1 = {{quad_vertex_rect.x(), quad_vertex_rect.y(), 0.0f, },
- {0.0f, 0.0f, }, i * 4.0f + 1.0f};
- Vertex v2 = {{quad_vertex_rect.right(), quad_vertex_rect.y(), 0.0f, },
- {1.0f, .0f, }, i * 4.0f + 2.0f};
- Vertex v3 = {{quad_vertex_rect.right(), quad_vertex_rect.bottom(), 0.0f, },
- {1.0f, 1.0f, }, i * 4.0f + 3.0f};
- Quad x = {v0, v1, v2, v3};
- quad_list[i] = x;
- QuadIndex y = {
- {static_cast<uint16>(0 + 4 * i), static_cast<uint16>(1 + 4 * i),
- static_cast<uint16>(2 + 4 * i), static_cast<uint16>(3 + 4 * i),
- static_cast<uint16>(0 + 4 * i), static_cast<uint16>(2 + 4 * i)}};
- quad_index_list[i] = y;
- }
+ gl->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo);
+ // OpenGL defines the last parameter to VertexAttribPointer as type
+ // "const GLvoid*" even though it is actually an offset into the buffer
+ // object's data store and not a pointer to the client's address space.
+ const void* offsets[3] = {
+ 0,
+ reinterpret_cast<const void*>(3 * sizeof(float)),
+ reinterpret_cast<const void*>(5 * sizeof(float)),
+ };
- gl_->GenBuffers(1, &quad_vertices_vbo_);
- gl_->GenBuffers(1, &quad_elements_vbo_);
- GLC(gl_, gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_));
- GLC(gl_,
- gl_->BufferData(
- GL_ARRAY_BUFFER, sizeof(quad_list), quad_list, GL_STATIC_DRAW));
- GLC(gl_, gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_));
- GLC(gl_,
- gl_->BufferData(GL_ELEMENT_ARRAY_BUFFER,
- sizeof(quad_index_list),
- quad_index_list,
- GL_STATIC_DRAW));
+ gl->VertexAttribPointer(GeometryBinding::PositionAttribLocation(), 3,
+ GL_FLOAT, false, 6 * sizeof(float), offsets[0]);
+ gl->VertexAttribPointer(GeometryBinding::TexCoordAttribLocation(), 2,
+ GL_FLOAT, false, 6 * sizeof(float), offsets[1]);
+ gl->VertexAttribPointer(GeometryBinding::TriangleIndexAttribLocation(), 1,
+ GL_FLOAT, false, 6 * sizeof(float), offsets[2]);
+ gl->EnableVertexAttribArray(GeometryBinding::PositionAttribLocation());
+ gl->EnableVertexAttribArray(GeometryBinding::TexCoordAttribLocation());
+ gl->EnableVertexAttribArray(GeometryBinding::TriangleIndexAttribLocation());
}
-GeometryBinding::~GeometryBinding() {
- gl_->DeleteBuffers(1, &quad_vertices_vbo_);
- gl_->DeleteBuffers(1, &quad_elements_vbo_);
+GeometryBindingQuad::GeometryBindingQuad() {
+ v0 = {{0, 0, 0}, {0, 0}, 0};
+ v1 = {{0, 0, 0}, {0, 0}, 0};
+ v2 = {{0, 0, 0}, {0, 0}, 0};
+ v3 = {{0, 0, 0}, {0, 0}, 0};
}
-void GeometryBinding::PrepareForDraw() {
- GLC(gl_, gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_));
+GeometryBindingQuad::GeometryBindingQuad(const GeometryBindingVertex& vert0,
+ const GeometryBindingVertex& vert1,
+ const GeometryBindingVertex& vert2,
+ const GeometryBindingVertex& vert3) {
+ v0 = vert0;
+ v1 = vert1;
+ v2 = vert2;
+ v3 = vert3;
+}
- GLC(gl_, gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_));
- // OpenGL defines the last parameter to VertexAttribPointer as type
- // "const GLvoid*" even though it is actually an offset into the buffer
- // object's data store and not a pointer to the client's address space.
- const void* offsets[3] = {
- 0, reinterpret_cast<const void*>(
- 3 * sizeof(float)), // NOLINT(runtime/sizeof)
- reinterpret_cast<const void*>(5 *
- sizeof(float)), // NOLINT(runtime/sizeof)
- };
+GeometryBindingQuadIndex::GeometryBindingQuadIndex() {
+ memset(data, 0x0, sizeof(data));
+}
- GLC(gl_,
- gl_->VertexAttribPointer(PositionAttribLocation(),
- 3,
- GL_FLOAT,
- false,
- 6 * sizeof(float), // NOLINT(runtime/sizeof)
- offsets[0]));
- GLC(gl_,
- gl_->VertexAttribPointer(TexCoordAttribLocation(),
- 2,
- GL_FLOAT,
- false,
- 6 * sizeof(float), // NOLINT(runtime/sizeof)
- offsets[1]));
- GLC(gl_,
- gl_->VertexAttribPointer(TriangleIndexAttribLocation(),
- 1,
- GL_FLOAT,
- false,
- 6 * sizeof(float), // NOLINT(runtime/sizeof)
- offsets[2]));
- GLC(gl_, gl_->EnableVertexAttribArray(PositionAttribLocation()));
- GLC(gl_, gl_->EnableVertexAttribArray(TexCoordAttribLocation()));
- GLC(gl_, gl_->EnableVertexAttribArray(TriangleIndexAttribLocation()));
+GeometryBindingQuadIndex::GeometryBindingQuadIndex(uint16 index0,
+ uint16 index1,
+ uint16 index2,
+ uint16 index3,
+ uint16 index4,
+ uint16 index5) {
+ data[0] = index0;
+ data[1] = index1;
+ data[2] = index2;
+ data[3] = index3;
+ data[4] = index4;
+ data[5] = index5;
}
} // namespace cc
diff --git a/chromium/cc/output/geometry_binding.h b/chromium/cc/output/geometry_binding.h
index cfa21efd1fc..de7cfc90b62 100644
--- a/chromium/cc/output/geometry_binding.h
+++ b/chromium/cc/output/geometry_binding.h
@@ -6,43 +6,64 @@
#define CC_OUTPUT_GEOMETRY_BINDING_H_
#include "base/basictypes.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "ui/gfx/geometry/rect_f.h"
namespace gfx {
-class RectF;
-}
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
+class QuadF;
+class Quad;
+class QuadIndex;
+class PointF;
}
namespace cc {
-class GeometryBinding {
- public:
- GeometryBinding(gpu::gles2::GLES2Interface* gl,
- const gfx::RectF& quad_vertex_rect);
- ~GeometryBinding();
+struct GeometryBindingVertex {
+ float a_position[3];
+ float a_texCoord[2];
+ // Index of the vertex, divide by 4 to have the matrix for this quad.
+ float a_index;
+};
+
+struct GeometryBindingQuad {
+ GeometryBindingQuad();
+ GeometryBindingQuad(const GeometryBindingVertex& vert0,
+ const GeometryBindingVertex& vert1,
+ const GeometryBindingVertex& vert2,
+ const GeometryBindingVertex& vert3);
+ GeometryBindingVertex v0, v1, v2, v3;
+};
+
+struct GeometryBindingQuadIndex {
+ GeometryBindingQuadIndex();
+ GeometryBindingQuadIndex(uint16 index0,
+ uint16 index1,
+ uint16 index2,
+ uint16 index3,
+ uint16 index4,
+ uint16 index5);
- void PrepareForDraw();
+ uint16 data[6];
+};
+
+class DrawQuad;
+class DrawPolygon;
+struct GeometryBinding {
// All layer shaders share the same attribute locations for the vertex
// positions and texture coordinates. This allows switching shaders without
// rebinding attribute arrays.
static int PositionAttribLocation() { return 0; }
static int TexCoordAttribLocation() { return 1; }
static int TriangleIndexAttribLocation() { return 2; }
-
- private:
- gpu::gles2::GLES2Interface* gl_;
-
- GLuint quad_vertices_vbo_;
- GLuint quad_elements_vbo_;
-
- DISALLOW_COPY_AND_ASSIGN(GeometryBinding);
};
+void SetupGLContext(gpu::gles2::GLES2Interface* gl,
+ GLuint quad_elements_vbo,
+ GLuint quad_vertices_vbo);
+
} // namespace cc
#endif // CC_OUTPUT_GEOMETRY_BINDING_H_
diff --git a/chromium/cc/output/gl_renderer.cc b/chromium/cc/output/gl_renderer.cc
index a472475d236..69da9a74754 100644
--- a/chromium/cc/output/gl_renderer.cc
+++ b/chromium/cc/output/gl_renderer.cc
@@ -10,25 +10,32 @@
#include <string>
#include <vector>
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
-#include "cc/layers/video_layer_impl.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_metadata.h"
#include "cc/output/context_provider.h"
#include "cc/output/copy_output_request.h"
-#include "cc/output/geometry_binding.h"
+#include "cc/output/dynamic_geometry_binding.h"
#include "cc/output/gl_frame_data.h"
+#include "cc/output/layer_quad.h"
#include "cc/output/output_surface.h"
#include "cc/output/render_surface_filters.h"
+#include "cc/output/static_geometry_binding.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/quads/draw_polygon.h"
#include "cc/quads/picture_draw_quad.h"
#include "cc/quads/render_pass.h"
#include "cc/quads/stream_video_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
-#include "cc/resources/layer_quad.h"
+#include "cc/raster/scoped_gpu_raster.h"
#include "cc/resources/scoped_resource.h"
-#include "cc/resources/texture_mailbox_deleter.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -40,6 +47,7 @@
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/GrTexture.h"
+#include "third_party/skia/include/gpu/GrTextureProvider.h"
#include "third_party/skia/include/gpu/SkGrTexturePixelRef.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
#include "ui/gfx/geometry/quad_f.h"
@@ -64,7 +72,7 @@ Float4 UVTransform(const TextureDrawQuad* quad) {
gfx::PointF uv0 = quad->uv_top_left;
gfx::PointF uv1 = quad->uv_bottom_right;
Float4 xform = {{uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y()}};
- if (quad->flipped) {
+ if (quad->y_flipped) {
xform.data[1] = 1.0f - xform.data[1];
xform.data[3] = -xform.data[3];
}
@@ -84,52 +92,54 @@ Float4 PremultipliedColor(SkColor color) {
SamplerType SamplerTypeFromTextureTarget(GLenum target) {
switch (target) {
case GL_TEXTURE_2D:
- return SamplerType2D;
+ return SAMPLER_TYPE_2D;
case GL_TEXTURE_RECTANGLE_ARB:
- return SamplerType2DRect;
+ return SAMPLER_TYPE_2D_RECT;
case GL_TEXTURE_EXTERNAL_OES:
- return SamplerTypeExternalOES;
+ return SAMPLER_TYPE_EXTERNAL_OES;
default:
NOTREACHED();
- return SamplerType2D;
+ return SAMPLER_TYPE_2D;
}
}
BlendMode BlendModeFromSkXfermode(SkXfermode::Mode mode) {
switch (mode) {
case SkXfermode::kSrcOver_Mode:
- return BlendModeNormal;
+ return BLEND_MODE_NORMAL;
+ case SkXfermode::kScreen_Mode:
+ return BLEND_MODE_SCREEN;
case SkXfermode::kOverlay_Mode:
- return BlendModeOverlay;
+ return BLEND_MODE_OVERLAY;
case SkXfermode::kDarken_Mode:
- return BlendModeDarken;
+ return BLEND_MODE_DARKEN;
case SkXfermode::kLighten_Mode:
- return BlendModeLighten;
+ return BLEND_MODE_LIGHTEN;
case SkXfermode::kColorDodge_Mode:
- return BlendModeColorDodge;
+ return BLEND_MODE_COLOR_DODGE;
case SkXfermode::kColorBurn_Mode:
- return BlendModeColorBurn;
+ return BLEND_MODE_COLOR_BURN;
case SkXfermode::kHardLight_Mode:
- return BlendModeHardLight;
+ return BLEND_MODE_HARD_LIGHT;
case SkXfermode::kSoftLight_Mode:
- return BlendModeSoftLight;
+ return BLEND_MODE_SOFT_LIGHT;
case SkXfermode::kDifference_Mode:
- return BlendModeDifference;
+ return BLEND_MODE_DIFFERENCE;
case SkXfermode::kExclusion_Mode:
- return BlendModeExclusion;
+ return BLEND_MODE_EXCLUSION;
case SkXfermode::kMultiply_Mode:
- return BlendModeMultiply;
+ return BLEND_MODE_MULTIPLY;
case SkXfermode::kHue_Mode:
- return BlendModeHue;
+ return BLEND_MODE_HUE;
case SkXfermode::kSaturation_Mode:
- return BlendModeSaturation;
+ return BLEND_MODE_SATURATION;
case SkXfermode::kColor_Mode:
- return BlendModeColor;
+ return BLEND_MODE_COLOR;
case SkXfermode::kLuminosity_Mode:
- return BlendModeLuminosity;
+ return BLEND_MODE_LUMINOSITY;
default:
NOTREACHED();
- return BlendModeNormal;
+ return BLEND_MODE_NONE;
}
}
@@ -153,12 +163,21 @@ class GLRenderer::ScopedUseGrContext {
public:
static scoped_ptr<ScopedUseGrContext> Create(GLRenderer* renderer,
DrawingFrame* frame) {
- if (!renderer->output_surface_->context_provider()->GrContext())
- return nullptr;
- return make_scoped_ptr(new ScopedUseGrContext(renderer, frame));
+ // GrContext for filters is created lazily, and may fail if the context
+ // is lost.
+ // TODO(vmiura,bsalomon): crbug.com/487850 Ensure that
+ // ContextProvider::GrContext() does not return NULL.
+ if (renderer->output_surface_->context_provider()->GrContext())
+ return make_scoped_ptr(new ScopedUseGrContext(renderer, frame));
+ return nullptr;
}
- ~ScopedUseGrContext() { PassControlToGLRenderer(); }
+ ~ScopedUseGrContext() {
+ // Pass context control back to GLrenderer.
+ scoped_gpu_raster_ = nullptr;
+ renderer_->RestoreGLState();
+ renderer_->RestoreFramebuffer(frame_);
+ }
GrContext* context() const {
return renderer_->output_surface_->context_provider()->GrContext();
@@ -166,17 +185,14 @@ class GLRenderer::ScopedUseGrContext {
private:
ScopedUseGrContext(GLRenderer* renderer, DrawingFrame* frame)
- : renderer_(renderer), frame_(frame) {
- PassControlToSkia();
- }
-
- void PassControlToSkia() { context()->resetContext(); }
-
- void PassControlToGLRenderer() {
- renderer_->RestoreGLState();
- renderer_->RestoreFramebuffer(frame_);
+ : scoped_gpu_raster_(
+ new ScopedGpuRaster(renderer->output_surface_->context_provider())),
+ renderer_(renderer),
+ frame_(frame) {
+ // scoped_gpu_raster_ passes context control to Skia.
}
+ scoped_ptr<ScopedGpuRaster> scoped_gpu_raster_;
GLRenderer* renderer_;
DrawingFrame* frame_;
@@ -288,7 +304,7 @@ class GLRenderer::SyncQuery {
scoped_ptr<GLRenderer> GLRenderer::Create(
RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider,
TextureMailboxDeleter* texture_mailbox_deleter,
@@ -302,7 +318,7 @@ scoped_ptr<GLRenderer> GLRenderer::Create(
}
GLRenderer::GLRenderer(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider,
TextureMailboxDeleter* texture_mailbox_deleter,
@@ -321,7 +337,8 @@ GLRenderer::GLRenderer(RendererClient* client,
highp_threshold_min_(highp_threshold_min),
highp_threshold_cache_(0),
use_sync_query_(false),
- on_demand_tile_raster_resource_id_(0) {
+ on_demand_tile_raster_resource_id_(0),
+ bound_geometry_(NO_BINDING) {
DCHECK(gl_);
DCHECK(context_support_);
@@ -347,6 +364,7 @@ GLRenderer::GLRenderer(RendererClient* client,
context_caps.gpu.discard_framebuffer;
capabilities_.allow_rasterize_on_demand = true;
+ capabilities_.max_msaa_samples = context_caps.gpu.max_samples;
use_sync_query_ = context_caps.gpu.sync_query;
use_blend_equation_advanced_ = context_caps.gpu.blend_equation_advanced;
@@ -372,17 +390,6 @@ const RendererCapabilitiesImpl& GLRenderer::Capabilities() const {
return capabilities_;
}
-void GLRenderer::DebugGLCall(GLES2Interface* gl,
- const char* command,
- const char* file,
- int line) {
- GLuint error = gl->GetError();
- if (error != GL_NO_ERROR)
- LOG(ERROR) << "GL command failed: File: " << file << "\n\tLine " << line
- << "\n\tcommand: " << command << ", error "
- << static_cast<int>(error) << "\n";
-}
-
void GLRenderer::DidChangeVisibility() {
EnforceMemoryPolicy();
@@ -391,10 +398,8 @@ void GLRenderer::DidChangeVisibility() {
void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); }
-void GLRenderer::DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) {
- if (has_external_stencil_test || !draw_rect_covers_full_surface ||
- !capabilities_.using_discard_framebuffer)
+void GLRenderer::DiscardPixels() {
+ if (!capabilities_.using_discard_framebuffer)
return;
bool using_default_framebuffer =
!current_framebuffer_lock_ &&
@@ -405,21 +410,35 @@ void GLRenderer::DiscardPixels(bool has_external_stencil_test,
GL_FRAMEBUFFER, arraysize(attachments), attachments);
}
-void GLRenderer::ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) {
- // It's unsafe to clear when we have a stencil test because glClear ignores
- // stencil.
- if (has_external_stencil_test) {
- DCHECK(!frame->current_render_pass->has_transparent_background);
- return;
+void GLRenderer::PrepareSurfaceForPass(
+ DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) {
+ SetViewport();
+
+ switch (initialization_mode) {
+ case SURFACE_INITIALIZATION_MODE_PRESERVE:
+ EnsureScissorTestDisabled();
+ return;
+ case SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR:
+ EnsureScissorTestDisabled();
+ DiscardPixels();
+ ClearFramebuffer(frame);
+ break;
+ case SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR:
+ SetScissorTestRect(render_pass_scissor);
+ ClearFramebuffer(frame);
+ break;
}
+}
+void GLRenderer::ClearFramebuffer(DrawingFrame* frame) {
// On DEBUG builds, opaque render passes are cleared to blue to easily see
// regions that were not drawn on the screen.
if (frame->current_render_pass->has_transparent_background)
- GLC(gl_, gl_->ClearColor(0, 0, 0, 0));
+ gl_->ClearColor(0, 0, 0, 0);
else
- GLC(gl_, gl_->ClearColor(0, 0, 1, 1));
+ gl_->ClearColor(0, 0, 1, 1);
bool always_clear = false;
#ifndef NDEBUG
@@ -487,14 +506,16 @@ void GLRenderer::BeginDrawingFrame(DrawingFrame* frame) {
}
void GLRenderer::DoNoOp() {
- GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, 0));
- GLC(gl_, gl_->Flush());
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
+ gl_->Flush();
}
-void GLRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
+void GLRenderer::DoDrawQuad(DrawingFrame* frame,
+ const DrawQuad* quad,
+ const gfx::QuadF* clip_region) {
DCHECK(quad->rect.Contains(quad->visible_rect));
if (quad->material != DrawQuad::TEXTURE_CONTENT) {
- FlushTextureQuadCache();
+ FlushTextureQuadCache(SHARED_BINDING);
}
switch (quad->material) {
@@ -502,25 +523,31 @@ void GLRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
NOTREACHED();
break;
case DrawQuad::CHECKERBOARD:
- DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad));
+ DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad),
+ clip_region);
break;
case DrawQuad::DEBUG_BORDER:
DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad));
break;
case DrawQuad::IO_SURFACE_CONTENT:
- DrawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad));
+ DrawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad),
+ clip_region);
break;
case DrawQuad::PICTURE_CONTENT:
- DrawPictureQuad(frame, PictureDrawQuad::MaterialCast(quad));
+ // PictureDrawQuad should only be used for resourceless software draws.
+ NOTREACHED();
break;
case DrawQuad::RENDER_PASS:
- DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad));
+ DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad),
+ clip_region);
break;
case DrawQuad::SOLID_COLOR:
- DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad));
+ DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad),
+ clip_region);
break;
case DrawQuad::STREAM_VIDEO_CONTENT:
- DrawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad));
+ DrawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad),
+ clip_region);
break;
case DrawQuad::SURFACE_CONTENT:
// Surface content should be fully resolved to other quad types before
@@ -528,19 +555,28 @@ void GLRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
NOTREACHED();
break;
case DrawQuad::TEXTURE_CONTENT:
- EnqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad));
+ EnqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad),
+ clip_region);
break;
case DrawQuad::TILED_CONTENT:
- DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad));
+ DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad), clip_region);
break;
case DrawQuad::YUV_VIDEO_CONTENT:
- DrawYUVVideoQuad(frame, YUVVideoDrawQuad::MaterialCast(quad));
+ DrawYUVVideoQuad(frame, YUVVideoDrawQuad::MaterialCast(quad),
+ clip_region);
break;
}
}
void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame,
- const CheckerboardDrawQuad* quad) {
+ const CheckerboardDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ // TODO(enne) For now since checkerboards shouldn't be part of a 3D
+ // context, clipping regions aren't supported so we skip drawing them
+ // if this becomes the case.
+ if (clip_region) {
+ return;
+ }
SetBlendEnabled(quad->ShouldDrawWithBlending());
const TileCheckerboardProgram* program = GetTileCheckerboardProgram();
@@ -548,31 +584,25 @@ void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame,
SetUseProgram(program->program());
SkColor color = quad->color;
- GLC(gl_,
- gl_->Uniform4f(program->fragment_shader().color_location(),
- SkColorGetR(color) * (1.0f / 255.0f),
- SkColorGetG(color) * (1.0f / 255.0f),
- SkColorGetB(color) * (1.0f / 255.0f),
- 1));
+ gl_->Uniform4f(program->fragment_shader().color_location(),
+ SkColorGetR(color) * (1.0f / 255.0f),
+ SkColorGetG(color) * (1.0f / 255.0f),
+ SkColorGetB(color) * (1.0f / 255.0f), 1);
- const int checkerboard_width = 16;
- float frequency = 1.0f / checkerboard_width;
+ const int kCheckerboardWidth = 16;
+ float frequency = 1.0f / kCheckerboardWidth;
gfx::Rect tile_rect = quad->rect;
- float tex_offset_x = tile_rect.x() % checkerboard_width;
- float tex_offset_y = tile_rect.y() % checkerboard_width;
- float tex_scale_x = tile_rect.width();
- float tex_scale_y = tile_rect.height();
- GLC(gl_,
- gl_->Uniform4f(program->fragment_shader().tex_transform_location(),
- tex_offset_x,
- tex_offset_y,
- tex_scale_x,
- tex_scale_y));
-
- GLC(gl_,
- gl_->Uniform1f(program->fragment_shader().frequency_location(),
- frequency));
+ float tex_offset_x =
+ static_cast<int>(tile_rect.x() / quad->scale) % kCheckerboardWidth;
+ float tex_offset_y =
+ static_cast<int>(tile_rect.y() / quad->scale) % kCheckerboardWidth;
+ float tex_scale_x = tile_rect.width() / quad->scale;
+ float tex_scale_y = tile_rect.height() / quad->scale;
+ gl_->Uniform4f(program->fragment_shader().tex_transform_location(),
+ tex_offset_x, tex_offset_y, tex_scale_x, tex_scale_y);
+
+ gl_->Uniform1f(program->fragment_shader().frequency_location(), frequency);
SetShaderOpacity(quad->opacity(),
program->fragment_shader().alpha_location());
@@ -582,6 +612,9 @@ void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame,
program->vertex_shader().matrix_location());
}
+// This function does not handle 3D sorting right now, since the debug border
+// quads are just drawn as their original quads and not in split pieces. This
+// results in some debug border quads drawing over foreground quads.
void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,
const DebugBorderDrawQuad* quad) {
SetBlendEnabled(quad->ShouldDrawWithBlending());
@@ -598,31 +631,28 @@ void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,
QuadRectTransform(&render_matrix, quad->quadTransform(), layer_rect);
GLRenderer::ToGLMatrix(&gl_matrix[0],
frame->projection_matrix * render_matrix);
- GLC(gl_,
- gl_->UniformMatrix4fv(
- program->vertex_shader().matrix_location(), 1, false, &gl_matrix[0]));
+ gl_->UniformMatrix4fv(program->vertex_shader().matrix_location(), 1, false,
+ &gl_matrix[0]);
SkColor color = quad->color;
float alpha = SkColorGetA(color) * (1.0f / 255.0f);
- GLC(gl_,
- gl_->Uniform4f(program->fragment_shader().color_location(),
- (SkColorGetR(color) * (1.0f / 255.0f)) * alpha,
- (SkColorGetG(color) * (1.0f / 255.0f)) * alpha,
- (SkColorGetB(color) * (1.0f / 255.0f)) * alpha,
- alpha));
+ gl_->Uniform4f(program->fragment_shader().color_location(),
+ (SkColorGetR(color) * (1.0f / 255.0f)) * alpha,
+ (SkColorGetG(color) * (1.0f / 255.0f)) * alpha,
+ (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, alpha);
- GLC(gl_, gl_->LineWidth(quad->width));
+ gl_->LineWidth(quad->width);
// The indices for the line are stored in the same array as the triangle
// indices.
- GLC(gl_, gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0));
+ gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0);
}
static skia::RefPtr<SkImage> ApplyImageFilter(
scoped_ptr<GLRenderer::ScopedUseGrContext> use_gr_context,
ResourceProvider* resource_provider,
- const gfx::Point& origin,
+ const gfx::Rect& rect,
const gfx::Vector2dF& scale,
SkImageFilter* filter,
ScopedResource* source_texture_resource) {
@@ -643,8 +673,8 @@ static skia::RefPtr<SkImage> ApplyImageFilter(
backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
backend_texture_description.fTextureHandle = lock.texture_id();
backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
- skia::RefPtr<GrTexture> texture =
- skia::AdoptRef(use_gr_context->context()->wrapBackendTexture(
+ skia::RefPtr<GrTexture> texture = skia::AdoptRef(
+ use_gr_context->context()->textureProvider()->wrapBackendTexture(
backend_texture_description));
if (!texture) {
TRACE_EVENT_INSTANT0("cc",
@@ -653,37 +683,26 @@ static skia::RefPtr<SkImage> ApplyImageFilter(
return skia::RefPtr<SkImage>();
}
- SkImageInfo info =
+ SkImageInfo src_info =
SkImageInfo::MakeN32Premul(source_texture_resource->size().width(),
source_texture_resource->size().height());
// Place the platform texture inside an SkBitmap.
SkBitmap source;
- source.setInfo(info);
+ source.setInfo(src_info);
skia::RefPtr<SkGrPixelRef> pixel_ref =
- skia::AdoptRef(new SkGrPixelRef(info, texture.get()));
+ skia::AdoptRef(new SkGrPixelRef(src_info, texture.get()));
source.setPixelRef(pixel_ref.get());
- // Create a scratch texture for backing store.
- GrTextureDesc desc;
- desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
- desc.fSampleCnt = 0;
- desc.fWidth = source.width();
- desc.fHeight = source.height();
- desc.fConfig = kSkia8888_GrPixelConfig;
- desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
- skia::RefPtr<GrTexture> backing_store =
- skia::AdoptRef(use_gr_context->context()->refScratchTexture(
- desc, GrContext::kExact_ScratchTexMatch));
- if (!backing_store) {
- TRACE_EVENT_INSTANT0("cc",
- "ApplyImageFilter scratch texture allocation failed",
+ // Create surface to draw into.
+ SkImageInfo dst_info =
+ SkImageInfo::MakeN32Premul(source.width(), source.height());
+ skia::RefPtr<SkSurface> surface = skia::AdoptRef(SkSurface::NewRenderTarget(
+ use_gr_context->context(), SkSurface::kYes_Budgeted, dst_info, 0));
+ if (!surface) {
+ TRACE_EVENT_INSTANT0("cc", "ApplyImageFilter surface allocation failed",
TRACE_EVENT_SCOPE_THREAD);
return skia::RefPtr<SkImage>();
}
-
- // Create surface to draw into.
- skia::RefPtr<SkSurface> surface = skia::AdoptRef(
- SkSurface::NewRenderTargetDirect(backing_store->asRenderTarget()));
skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas());
// Draw the source bitmap through the filter to the canvas.
@@ -691,7 +710,12 @@ static skia::RefPtr<SkImage> ApplyImageFilter(
paint.setImageFilter(filter);
canvas->clear(SK_ColorTRANSPARENT);
- canvas->translate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
+ // The origin of the filter is top-left and the origin of the source is
+ // bottom-left, but the orientation is the same, so we must translate the
+ // filter so that it renders at the bottom of the texture to avoid
+ // misregistration.
+ int y_translate = source.height() - rect.height() - rect.origin().y();
+ canvas->translate(-rect.origin().x(), y_translate);
canvas->scale(scale.x(), scale.y());
canvas->drawSprite(source, 0, 0, &paint);
@@ -771,10 +795,10 @@ void GLRenderer::ApplyBlendModeUsingBlendFunc(SkXfermode::Mode blend_mode) {
return;
}
- GLC(gl_, gl_->BlendEquation(equation));
+ gl_->BlendEquation(equation);
} else {
if (blend_mode == SkXfermode::kScreen_Mode) {
- GLC(gl_, gl_->BlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE));
+ gl_->BlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE);
}
}
}
@@ -784,9 +808,9 @@ void GLRenderer::RestoreBlendFuncToDefault(SkXfermode::Mode blend_mode) {
return;
if (use_blend_equation_advanced_) {
- GLC(gl_, gl_->BlendEquation(GL_FUNC_ADD));
+ gl_->BlendEquation(GL_FUNC_ADD);
} else {
- GLC(gl_, gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
+ gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
}
@@ -808,13 +832,56 @@ bool GLRenderer::ShouldApplyBackgroundFilters(DrawingFrame* frame,
return true;
}
+// This takes a gfx::Rect and a clip region quad in the same space,
+// and returns a quad with the same proportions in the space -0.5->0.5.
+bool GetScaledRegion(const gfx::Rect& rect,
+ const gfx::QuadF* clip,
+ gfx::QuadF* scaled_region) {
+ if (!clip)
+ return false;
+
+ gfx::PointF p1(((clip->p1().x() - rect.x()) / rect.width()) - 0.5f,
+ ((clip->p1().y() - rect.y()) / rect.height()) - 0.5f);
+ gfx::PointF p2(((clip->p2().x() - rect.x()) / rect.width()) - 0.5f,
+ ((clip->p2().y() - rect.y()) / rect.height()) - 0.5f);
+ gfx::PointF p3(((clip->p3().x() - rect.x()) / rect.width()) - 0.5f,
+ ((clip->p3().y() - rect.y()) / rect.height()) - 0.5f);
+ gfx::PointF p4(((clip->p4().x() - rect.x()) / rect.width()) - 0.5f,
+ ((clip->p4().y() - rect.y()) / rect.height()) - 0.5f);
+ *scaled_region = gfx::QuadF(p1, p2, p3, p4);
+ return true;
+}
+
+// This takes a gfx::Rect and a clip region quad in the same space,
+// and returns the proportional uv's in the space 0->1.
+bool GetScaledUVs(const gfx::Rect& rect, const gfx::QuadF* clip, float uvs[8]) {
+ if (!clip)
+ return false;
+
+ uvs[0] = ((clip->p1().x() - rect.x()) / rect.width());
+ uvs[1] = ((clip->p1().y() - rect.y()) / rect.height());
+ uvs[2] = ((clip->p2().x() - rect.x()) / rect.width());
+ uvs[3] = ((clip->p2().y() - rect.y()) / rect.height());
+ uvs[4] = ((clip->p3().x() - rect.x()) / rect.width());
+ uvs[5] = ((clip->p3().y() - rect.y()) / rect.height());
+ uvs[6] = ((clip->p4().x() - rect.x()) / rect.width());
+ uvs[7] = ((clip->p4().y() - rect.y()) / rect.height());
+ return true;
+}
+
gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad(
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform,
+ const gfx::QuadF* clip_region,
bool use_aa) {
+ gfx::QuadF scaled_region;
+ if (!GetScaledRegion(quad->rect, clip_region, &scaled_region)) {
+ scaled_region = SharedGeometryQuad().BoundingBox();
+ }
+
gfx::Rect backdrop_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
- contents_device_transform, SharedGeometryQuad().BoundingBox()));
+ contents_device_transform, scaled_region.BoundingBox()));
if (ShouldApplyBackgroundFilters(frame, quad)) {
int top, right, bottom, left;
@@ -838,7 +905,7 @@ scoped_ptr<ScopedResource> GLRenderer::GetBackdropTexture(
ScopedResource::Create(resource_provider_);
// CopyTexImage2D fails when called on a texture having immutable storage.
device_background_texture->Allocate(
- bounding_rect.size(), ResourceProvider::TextureHintDefault, RGBA_8888);
+ bounding_rect.size(), ResourceProvider::TEXTURE_HINT_DEFAULT, RGBA_8888);
{
ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
device_background_texture->id());
@@ -856,113 +923,19 @@ skia::RefPtr<SkImage> GLRenderer::ApplyBackgroundFilters(
skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
quad->background_filters, background_texture->size());
- skia::RefPtr<SkImage> background_with_filters =
- ApplyImageFilter(ScopedUseGrContext::Create(this, frame),
- resource_provider_,
- quad->rect.origin(),
- quad->filters_scale,
- filter.get(),
- background_texture);
+ skia::RefPtr<SkImage> background_with_filters = ApplyImageFilter(
+ ScopedUseGrContext::Create(this, frame), resource_provider_, quad->rect,
+ quad->filters_scale, filter.get(), background_texture);
return background_with_filters;
}
-scoped_ptr<ScopedResource>
-GLRenderer::ApplyInverseTransformForBackgroundFilters(
- DrawingFrame* frame,
- const RenderPassDrawQuad* quad,
- const gfx::Transform& contents_device_transform,
- skia::RefPtr<SkImage> filtered_device_background,
- const gfx::Rect& backdrop_bounding_rect) {
- // This method draws a background filter, which applies a filter to any pixels
- // behind the quad and seen through its background. The algorithm works as
- // follows:
- // 1. Read the pixels in the bounding box into a buffer.
- // Moved to GLRenderer::GetBackdropBoundingBoxForRenderPassQuad().
- // 2. Read the pixels in the bounding box into a buffer R.
- // Moved to GLRenderer::GetBackdropTexture().
- // 3. Apply the background filter to R, so that it is applied in the pixels'
- // coordinate space. Moved to GLRenderer::ApplyBackgroundFilters().
- // 4. Apply the quad's inverse transform to map the pixels in R into the
- // quad's content space. This implicitly clips R by the content bounds of the
- // quad since the destination texture has bounds matching the quad's content.
- // 5. Draw the background texture for the contents using the same transform as
- // used to draw the contents itself. This is done without blending to replace
- // the current background pixels with the new filtered background.
- // 6. Draw the contents of the quad over drop of the new background with
- // blending, as per usual. The filtered background pixels will show through
- // any non-opaque pixels in this draws.
- //
- // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
-
- // TODO(danakj): When this algorithm changes, update
- // LayerTreeHost::PrioritizeTextures() accordingly.
-
- DCHECK(filtered_device_background);
-
- GrTexture* texture = filtered_device_background->getTexture();
-
- scoped_ptr<ScopedResource> background_texture =
- ScopedResource::Create(resource_provider_);
- background_texture->Allocate(
- quad->rect.size(),
- ResourceProvider::TextureHintImmutableFramebuffer,
- RGBA_8888);
-
- const RenderPass* target_render_pass = frame->current_render_pass;
- bool using_background_texture =
- UseScopedTexture(frame, background_texture.get(), quad->rect);
-
- if (using_background_texture) {
- // Copy the readback pixels from device to the background texture for the
- // surface.
-
- gfx::Transform contents_device_transform_inverse(
- gfx::Transform::kSkipInitialization);
- bool did_invert = contents_device_transform.GetInverse(
- &contents_device_transform_inverse);
- DCHECK(did_invert);
- gfx::Transform device_to_framebuffer_transform;
- QuadRectTransform(
- &device_to_framebuffer_transform, gfx::Transform(), quad->rect);
- device_to_framebuffer_transform.PreconcatTransform(
- contents_device_transform_inverse);
-
-#ifndef NDEBUG
- GLC(gl_, gl_->ClearColor(0, 0, 1, 1));
- gl_->Clear(GL_COLOR_BUFFER_BIT);
-#endif
-
- // The background_texture is oriented the same as the frame buffer.
- // The transform we are copying with has a vertical flip, as well as
- // the |device_to_framebuffer_transform|, which cancel each other out. So do
- // not flip the contents in the shader to maintain orientation.
- bool flip_vertically = false;
-
- CopyTextureToFramebuffer(frame,
- texture->getTextureHandle(),
- backdrop_bounding_rect,
- device_to_framebuffer_transform,
- flip_vertically);
- }
-
- UseRenderPass(frame, target_render_pass);
-
- if (!using_background_texture)
- return nullptr;
- return background_texture.Pass();
-}
-
void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
- const RenderPassDrawQuad* quad) {
- SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode;
- SetBlendEnabled(
- CanApplyBlendModeUsingBlendFunc(blend_mode) &&
- (quad->ShouldDrawWithBlending() || !IsDefaultBlendMode(blend_mode)));
-
+ const RenderPassDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
ScopedResource* contents_texture =
render_pass_textures_.get(quad->render_pass_id);
- if (!contents_texture || !contents_texture->id())
- return;
+ DCHECK(contents_texture);
+ DCHECK(contents_texture->id());
gfx::Transform quad_rect_matrix;
QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
@@ -980,65 +953,66 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
ShouldAntialiasQuad(contents_device_transform, quad,
settings_->force_antialiasing);
- if (use_aa)
- SetupQuadForAntialiasing(contents_device_transform, quad,
- &surface_quad, edge);
-
- bool need_background_texture = !CanApplyBlendModeUsingBlendFunc(blend_mode) ||
- ShouldApplyBackgroundFilters(frame, quad);
+ SetupQuadForClippingAndAntialiasing(contents_device_transform, quad, use_aa,
+ clip_region, &surface_quad, edge);
+ SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode;
+ bool use_shaders_for_blending =
+ !CanApplyBlendModeUsingBlendFunc(blend_mode) ||
+ ShouldApplyBackgroundFilters(frame, quad) ||
+ settings_->force_blending_with_shaders;
scoped_ptr<ScopedResource> background_texture;
skia::RefPtr<SkImage> background_image;
gfx::Rect background_rect;
- if (need_background_texture) {
+ if (use_shaders_for_blending) {
// Compute a bounding box around the pixels that will be visible through
// the quad.
background_rect = GetBackdropBoundingBoxForRenderPassQuad(
- frame, quad, contents_device_transform, use_aa);
- }
-
- if (!background_rect.IsEmpty()) {
- // The pixels from the filtered background should completely replace the
- // current pixel values.
- bool disable_blending = blend_enabled();
- if (disable_blending)
- SetBlendEnabled(false);
-
- // Read the pixels in the bounding box into a buffer R.
- scoped_ptr<ScopedResource> scoped_background_texture =
- GetBackdropTexture(background_rect);
-
- skia::RefPtr<SkImage> background_with_filters;
- if (ShouldApplyBackgroundFilters(frame, quad) &&
- scoped_background_texture) {
- // Apply the background filters to R, so that it is applied in the pixels'
- // coordinate space.
- background_with_filters =
- ApplyBackgroundFilters(frame, quad, scoped_background_texture.get());
- }
-
- if (CanApplyBlendModeUsingBlendFunc(blend_mode) &&
- background_with_filters) {
- // The background with filters will be copied to the frame buffer.
- // Apply the quad's inverse transform to map the pixels in R into the
- // quad's content space. This implicitly clips R by the content bounds of
- // the quad since the destination texture has bounds matching the quad's
- // content.
- background_texture = ApplyInverseTransformForBackgroundFilters(
- frame, quad, contents_device_transform, background_with_filters,
- background_rect);
- } else if (!CanApplyBlendModeUsingBlendFunc(blend_mode)) {
- if (background_with_filters) {
- // The background with filters will be used as backdrop for blending.
- background_image = background_with_filters;
- } else {
- background_texture = scoped_background_texture.Pass();
+ frame, quad, contents_device_transform, clip_region, use_aa);
+
+ if (!background_rect.IsEmpty()) {
+ // The pixels from the filtered background should completely replace the
+ // current pixel values.
+ if (blend_enabled())
+ SetBlendEnabled(false);
+
+ // Read the pixels in the bounding box into a buffer R.
+ // This function allocates a texture, which should contribute to the
+ // amount of memory used by render surfaces:
+ // LayerTreeHost::CalculateMemoryForRenderSurfaces.
+ background_texture = GetBackdropTexture(background_rect);
+
+ if (ShouldApplyBackgroundFilters(frame, quad) && background_texture) {
+ // Apply the background filters to R, so that it is applied in the
+ // pixels' coordinate space.
+ background_image =
+ ApplyBackgroundFilters(frame, quad, background_texture.get());
}
}
- if (disable_blending)
- SetBlendEnabled(true);
+ if (!background_texture) {
+ // Something went wrong with reading the backdrop.
+ DCHECK(!background_image);
+ use_shaders_for_blending = false;
+ } else if (background_image) {
+ // Reset original background texture if there is not any mask
+ if (!quad->mask_resource_id)
+ background_texture.reset();
+ } else if (CanApplyBlendModeUsingBlendFunc(blend_mode) &&
+ ShouldApplyBackgroundFilters(frame, quad)) {
+ // Something went wrong with applying background filters to the backdrop.
+ use_shaders_for_blending = false;
+ background_texture.reset();
+ }
}
+ // Need original background texture for mask?
+ bool mask_for_background =
+ background_texture && // Have original background texture
+ background_image && // Have filtered background texture
+ quad->mask_resource_id; // Have mask texture
+ SetBlendEnabled(
+ !use_shaders_for_blending &&
+ (quad->ShouldDrawWithBlending() || !IsDefaultBlendMode(blend_mode)));
// TODO(senorblanco): Cache this value so that we don't have to do it for both
// the surface and its replica. Apply filters to the contents texture.
@@ -1062,38 +1036,16 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
// in the compositor.
use_color_matrix = true;
} else {
- filter_image = ApplyImageFilter(ScopedUseGrContext::Create(this, frame),
- resource_provider_,
- quad->rect.origin(),
- quad->filters_scale,
- filter.get(),
- contents_texture);
+ filter_image = ApplyImageFilter(
+ ScopedUseGrContext::Create(this, frame), resource_provider_,
+ quad->rect, quad->filters_scale, filter.get(), contents_texture);
}
}
}
- if (background_texture && ShouldApplyBackgroundFilters(frame, quad)) {
- // Draw the background texture if it has some filters applied.
- DCHECK(CanApplyBlendModeUsingBlendFunc(blend_mode));
- DCHECK(background_texture->size() == quad->rect.size());
- ResourceProvider::ScopedReadLockGL lock(resource_provider_,
- background_texture->id());
-
- // The background_texture is oriented the same as the frame buffer. The
- // transform we are copying with has a vertical flip, so flip the contents
- // in the shader to maintain orientation
- bool flip_vertically = true;
-
- CopyTextureToFramebuffer(frame,
- lock.texture_id(),
- quad->rect,
- quad->quadTransform(),
- flip_vertically);
- }
-
scoped_ptr<ResourceProvider::ScopedSamplerGL> mask_resource_lock;
unsigned mask_texture_id = 0;
- SamplerType mask_sampler = SamplerTypeNA;
+ SamplerType mask_sampler = SAMPLER_TYPE_NA;
if (quad->mask_resource_id) {
mask_resource_lock.reset(new ResourceProvider::ScopedSamplerGL(
resource_provider_, quad->mask_resource_id, GL_TEXTURE1, GL_LINEAR));
@@ -1101,9 +1053,6 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
mask_sampler = SamplerTypeFromTextureTarget(mask_resource_lock->target());
}
- // TODO(danakj): use the background_texture and blend the background in with
- // this draw instead of having a separate copy of the background texture.
-
scoped_ptr<ResourceProvider::ScopedSamplerGL> contents_resource_lock;
if (filter_image) {
GrTexture* texture = filter_image->getTexture();
@@ -1117,9 +1066,9 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
contents_resource_lock->target());
}
- if (CanApplyBlendModeUsingBlendFunc(blend_mode)) {
+ if (!use_shaders_for_blending) {
if (!use_blend_equation_advanced_coherent_ && use_blend_equation_advanced_)
- GLC(gl_, gl_->BlendBarrierKHR());
+ gl_->BlendBarrierKHR();
ApplyBlendModeUsingBlendFunc(blend_mode);
}
@@ -1130,184 +1079,76 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
highp_threshold_min_,
quad->shared_quad_state->visible_content_rect.bottom_right());
- int shader_quad_location = -1;
- int shader_edge_location = -1;
- int shader_viewport_location = -1;
- int shader_mask_sampler_location = -1;
- int shader_mask_tex_coord_scale_location = -1;
- int shader_mask_tex_coord_offset_location = -1;
- int shader_matrix_location = -1;
- int shader_alpha_location = -1;
- int shader_color_matrix_location = -1;
- int shader_color_offset_location = -1;
- int shader_tex_transform_location = -1;
- int shader_backdrop_location = -1;
- int shader_backdrop_rect_location = -1;
-
- BlendMode shader_blend_mode = ((background_texture || background_image) &&
- !CanApplyBlendModeUsingBlendFunc(blend_mode))
+ ShaderLocations locations;
+
+ DCHECK_EQ(background_texture || background_image, use_shaders_for_blending);
+ BlendMode shader_blend_mode = use_shaders_for_blending
? BlendModeFromSkXfermode(blend_mode)
- : BlendModeNormal;
+ : BLEND_MODE_NONE;
if (use_aa && mask_texture_id && !use_color_matrix) {
const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA(
- tex_coord_precision, mask_sampler, shader_blend_mode);
+ tex_coord_precision, mask_sampler,
+ shader_blend_mode, mask_for_background);
SetUseProgram(program->program());
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
- shader_quad_location = program->vertex_shader().quad_location();
- shader_edge_location = program->vertex_shader().edge_location();
- shader_viewport_location = program->vertex_shader().viewport_location();
- shader_mask_sampler_location =
- program->fragment_shader().mask_sampler_location();
- shader_mask_tex_coord_scale_location =
- program->fragment_shader().mask_tex_coord_scale_location();
- shader_mask_tex_coord_offset_location =
- program->fragment_shader().mask_tex_coord_offset_location();
- shader_matrix_location = program->vertex_shader().matrix_location();
- shader_alpha_location = program->fragment_shader().alpha_location();
- shader_tex_transform_location =
- program->vertex_shader().tex_transform_location();
- shader_backdrop_location = program->fragment_shader().backdrop_location();
- shader_backdrop_rect_location =
- program->fragment_shader().backdrop_rect_location();
+ program->vertex_shader().FillLocations(&locations);
+ program->fragment_shader().FillLocations(&locations);
+ gl_->Uniform1i(locations.sampler, 0);
} else if (!use_aa && mask_texture_id && !use_color_matrix) {
const RenderPassMaskProgram* program = GetRenderPassMaskProgram(
- tex_coord_precision, mask_sampler, shader_blend_mode);
+ tex_coord_precision, mask_sampler,
+ shader_blend_mode, mask_for_background);
SetUseProgram(program->program());
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
- shader_mask_sampler_location =
- program->fragment_shader().mask_sampler_location();
- shader_mask_tex_coord_scale_location =
- program->fragment_shader().mask_tex_coord_scale_location();
- shader_mask_tex_coord_offset_location =
- program->fragment_shader().mask_tex_coord_offset_location();
- shader_matrix_location = program->vertex_shader().matrix_location();
- shader_alpha_location = program->fragment_shader().alpha_location();
- shader_tex_transform_location =
- program->vertex_shader().tex_transform_location();
- shader_backdrop_location = program->fragment_shader().backdrop_location();
- shader_backdrop_rect_location =
- program->fragment_shader().backdrop_rect_location();
+ program->vertex_shader().FillLocations(&locations);
+ program->fragment_shader().FillLocations(&locations);
+ gl_->Uniform1i(locations.sampler, 0);
} else if (use_aa && !mask_texture_id && !use_color_matrix) {
const RenderPassProgramAA* program =
GetRenderPassProgramAA(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
- shader_quad_location = program->vertex_shader().quad_location();
- shader_edge_location = program->vertex_shader().edge_location();
- shader_viewport_location = program->vertex_shader().viewport_location();
- shader_matrix_location = program->vertex_shader().matrix_location();
- shader_alpha_location = program->fragment_shader().alpha_location();
- shader_tex_transform_location =
- program->vertex_shader().tex_transform_location();
- shader_backdrop_location = program->fragment_shader().backdrop_location();
- shader_backdrop_rect_location =
- program->fragment_shader().backdrop_rect_location();
+ program->vertex_shader().FillLocations(&locations);
+ program->fragment_shader().FillLocations(&locations);
+ gl_->Uniform1i(locations.sampler, 0);
} else if (use_aa && mask_texture_id && use_color_matrix) {
const RenderPassMaskColorMatrixProgramAA* program =
GetRenderPassMaskColorMatrixProgramAA(
- tex_coord_precision, mask_sampler, shader_blend_mode);
+ tex_coord_precision, mask_sampler,
+ shader_blend_mode, mask_for_background);
SetUseProgram(program->program());
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
- shader_matrix_location = program->vertex_shader().matrix_location();
- shader_quad_location = program->vertex_shader().quad_location();
- shader_tex_transform_location =
- program->vertex_shader().tex_transform_location();
- shader_edge_location = program->vertex_shader().edge_location();
- shader_viewport_location = program->vertex_shader().viewport_location();
- shader_alpha_location = program->fragment_shader().alpha_location();
- shader_mask_sampler_location =
- program->fragment_shader().mask_sampler_location();
- shader_mask_tex_coord_scale_location =
- program->fragment_shader().mask_tex_coord_scale_location();
- shader_mask_tex_coord_offset_location =
- program->fragment_shader().mask_tex_coord_offset_location();
- shader_color_matrix_location =
- program->fragment_shader().color_matrix_location();
- shader_color_offset_location =
- program->fragment_shader().color_offset_location();
- shader_backdrop_location = program->fragment_shader().backdrop_location();
- shader_backdrop_rect_location =
- program->fragment_shader().backdrop_rect_location();
+ program->vertex_shader().FillLocations(&locations);
+ program->fragment_shader().FillLocations(&locations);
+ gl_->Uniform1i(locations.sampler, 0);
} else if (use_aa && !mask_texture_id && use_color_matrix) {
const RenderPassColorMatrixProgramAA* program =
GetRenderPassColorMatrixProgramAA(tex_coord_precision,
shader_blend_mode);
SetUseProgram(program->program());
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
- shader_matrix_location = program->vertex_shader().matrix_location();
- shader_quad_location = program->vertex_shader().quad_location();
- shader_tex_transform_location =
- program->vertex_shader().tex_transform_location();
- shader_edge_location = program->vertex_shader().edge_location();
- shader_viewport_location = program->vertex_shader().viewport_location();
- shader_alpha_location = program->fragment_shader().alpha_location();
- shader_color_matrix_location =
- program->fragment_shader().color_matrix_location();
- shader_color_offset_location =
- program->fragment_shader().color_offset_location();
- shader_backdrop_location = program->fragment_shader().backdrop_location();
- shader_backdrop_rect_location =
- program->fragment_shader().backdrop_rect_location();
+ program->vertex_shader().FillLocations(&locations);
+ program->fragment_shader().FillLocations(&locations);
+ gl_->Uniform1i(locations.sampler, 0);
} else if (!use_aa && mask_texture_id && use_color_matrix) {
const RenderPassMaskColorMatrixProgram* program =
GetRenderPassMaskColorMatrixProgram(
- tex_coord_precision, mask_sampler, shader_blend_mode);
+ tex_coord_precision, mask_sampler,
+ shader_blend_mode, mask_for_background);
SetUseProgram(program->program());
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
- shader_matrix_location = program->vertex_shader().matrix_location();
- shader_tex_transform_location =
- program->vertex_shader().tex_transform_location();
- shader_mask_sampler_location =
- program->fragment_shader().mask_sampler_location();
- shader_mask_tex_coord_scale_location =
- program->fragment_shader().mask_tex_coord_scale_location();
- shader_mask_tex_coord_offset_location =
- program->fragment_shader().mask_tex_coord_offset_location();
- shader_alpha_location = program->fragment_shader().alpha_location();
- shader_color_matrix_location =
- program->fragment_shader().color_matrix_location();
- shader_color_offset_location =
- program->fragment_shader().color_offset_location();
- shader_backdrop_location = program->fragment_shader().backdrop_location();
- shader_backdrop_rect_location =
- program->fragment_shader().backdrop_rect_location();
+ program->vertex_shader().FillLocations(&locations);
+ program->fragment_shader().FillLocations(&locations);
+ gl_->Uniform1i(locations.sampler, 0);
} else if (!use_aa && !mask_texture_id && use_color_matrix) {
const RenderPassColorMatrixProgram* program =
GetRenderPassColorMatrixProgram(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
- shader_matrix_location = program->vertex_shader().matrix_location();
- shader_tex_transform_location =
- program->vertex_shader().tex_transform_location();
- shader_alpha_location = program->fragment_shader().alpha_location();
- shader_color_matrix_location =
- program->fragment_shader().color_matrix_location();
- shader_color_offset_location =
- program->fragment_shader().color_offset_location();
- shader_backdrop_location = program->fragment_shader().backdrop_location();
- shader_backdrop_rect_location =
- program->fragment_shader().backdrop_rect_location();
+ program->vertex_shader().FillLocations(&locations);
+ program->fragment_shader().FillLocations(&locations);
+ gl_->Uniform1i(locations.sampler, 0);
} else {
const RenderPassProgram* program =
GetRenderPassProgram(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
- shader_matrix_location = program->vertex_shader().matrix_location();
- shader_alpha_location = program->fragment_shader().alpha_location();
- shader_tex_transform_location =
- program->vertex_shader().tex_transform_location();
- shader_backdrop_location = program->fragment_shader().backdrop_location();
- shader_backdrop_rect_location =
- program->fragment_shader().backdrop_rect_location();
+ program->vertex_shader().FillLocations(&locations);
+ program->fragment_shader().FillLocations(&locations);
+ gl_->Uniform1i(locations.sampler, 0);
}
float tex_scale_x =
quad->rect.width() / static_cast<float>(contents_texture->size().width());
@@ -1316,25 +1157,21 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
DCHECK_LE(tex_scale_x, 1.0f);
DCHECK_LE(tex_scale_y, 1.0f);
- DCHECK(shader_tex_transform_location != -1 || IsContextLost());
+ DCHECK(locations.tex_transform != -1 || IsContextLost());
// Flip the content vertically in the shader, as the RenderPass input
// texture is already oriented the same way as the framebuffer, but the
// projection transform does a flip.
- GLC(gl_,
- gl_->Uniform4f(shader_tex_transform_location,
- 0.0f,
- tex_scale_y,
- tex_scale_x,
- -tex_scale_y));
+ gl_->Uniform4f(locations.tex_transform, 0.0f, tex_scale_y, tex_scale_x,
+ -tex_scale_y);
GLint last_texture_unit = 0;
- if (shader_mask_sampler_location != -1) {
- DCHECK_NE(shader_mask_tex_coord_scale_location, 1);
- DCHECK_NE(shader_mask_tex_coord_offset_location, 1);
- GLC(gl_, gl_->Uniform1i(shader_mask_sampler_location, 1));
+ if (locations.mask_sampler != -1) {
+ DCHECK_NE(locations.mask_tex_coord_scale, 1);
+ DCHECK_NE(locations.mask_tex_coord_offset, 1);
+ gl_->Uniform1i(locations.mask_sampler, 1);
gfx::RectF mask_uv_rect = quad->MaskUVRect();
- if (mask_sampler != SamplerType2D) {
+ if (mask_sampler != SAMPLER_TYPE_2D) {
mask_uv_rect.Scale(quad->mask_texture_size.width(),
quad->mask_texture_size.height());
}
@@ -1342,68 +1179,66 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
// Mask textures are oriented vertically flipped relative to the framebuffer
// and the RenderPass contents texture, so we flip the tex coords from the
// RenderPass texture to find the mask texture coords.
- GLC(gl_,
- gl_->Uniform2f(shader_mask_tex_coord_offset_location,
- mask_uv_rect.x(),
- mask_uv_rect.bottom()));
- GLC(gl_,
- gl_->Uniform2f(shader_mask_tex_coord_scale_location,
- mask_uv_rect.width() / tex_scale_x,
- -mask_uv_rect.height() / tex_scale_y));
+ gl_->Uniform2f(locations.mask_tex_coord_offset, mask_uv_rect.x(),
+ mask_uv_rect.bottom());
+ gl_->Uniform2f(locations.mask_tex_coord_scale,
+ mask_uv_rect.width() / tex_scale_x,
+ -mask_uv_rect.height() / tex_scale_y);
last_texture_unit = 1;
}
- if (shader_edge_location != -1)
- GLC(gl_, gl_->Uniform3fv(shader_edge_location, 8, edge));
+ if (locations.edge != -1)
+ gl_->Uniform3fv(locations.edge, 8, edge);
- if (shader_viewport_location != -1) {
- float viewport[4] = {static_cast<float>(viewport_.x()),
- static_cast<float>(viewport_.y()),
- static_cast<float>(viewport_.width()),
- static_cast<float>(viewport_.height()), };
- GLC(gl_, gl_->Uniform4fv(shader_viewport_location, 1, viewport));
+ if (locations.viewport != -1) {
+ float viewport[4] = {
+ static_cast<float>(current_window_space_viewport_.x()),
+ static_cast<float>(current_window_space_viewport_.y()),
+ static_cast<float>(current_window_space_viewport_.width()),
+ static_cast<float>(current_window_space_viewport_.height()),
+ };
+ gl_->Uniform4fv(locations.viewport, 1, viewport);
}
- if (shader_color_matrix_location != -1) {
+ if (locations.color_matrix != -1) {
float matrix[16];
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j)
matrix[i * 4 + j] = SkScalarToFloat(color_matrix[j * 5 + i]);
}
- GLC(gl_,
- gl_->UniformMatrix4fv(shader_color_matrix_location, 1, false, matrix));
+ gl_->UniformMatrix4fv(locations.color_matrix, 1, false, matrix);
}
static const float kScale = 1.0f / 255.0f;
- if (shader_color_offset_location != -1) {
+ if (locations.color_offset != -1) {
float offset[4];
for (int i = 0; i < 4; ++i)
offset[i] = SkScalarToFloat(color_matrix[i * 5 + 4]) * kScale;
- GLC(gl_, gl_->Uniform4fv(shader_color_offset_location, 1, offset));
+ gl_->Uniform4fv(locations.color_offset, 1, offset);
}
scoped_ptr<ResourceProvider::ScopedSamplerGL> shader_background_sampler_lock;
- if (shader_backdrop_location != -1) {
+ if (locations.backdrop != -1) {
DCHECK(background_texture || background_image);
- DCHECK_NE(shader_backdrop_location, 0);
- DCHECK_NE(shader_backdrop_rect_location, 0);
+ DCHECK_NE(locations.backdrop, 0);
+ DCHECK_NE(locations.backdrop_rect, 0);
- GLC(gl_, gl_->Uniform1i(shader_backdrop_location, ++last_texture_unit));
+ gl_->Uniform1i(locations.backdrop, ++last_texture_unit);
- GLC(gl_,
- gl_->Uniform4f(shader_backdrop_rect_location,
- background_rect.x(),
- background_rect.y(),
- background_rect.width(),
- background_rect.height()));
+ gl_->Uniform4f(locations.backdrop_rect, background_rect.x(),
+ background_rect.y(), background_rect.width(),
+ background_rect.height());
if (background_image) {
GrTexture* texture = background_image->getTexture();
- GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0 + last_texture_unit));
+ gl_->ActiveTexture(GL_TEXTURE0 + last_texture_unit);
gl_->BindTexture(GL_TEXTURE_2D, texture->getTextureHandle());
- GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0));
- } else {
+ gl_->ActiveTexture(GL_TEXTURE0);
+ if (mask_for_background)
+ gl_->Uniform1i(locations.original_backdrop, ++last_texture_unit);
+ }
+ if (background_texture) {
shader_background_sampler_lock = make_scoped_ptr(
new ResourceProvider::ScopedSamplerGL(resource_provider_,
background_texture->id(),
@@ -1414,17 +1249,17 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
}
}
- SetShaderOpacity(quad->opacity(), shader_alpha_location);
- SetShaderQuadF(surface_quad, shader_quad_location);
+ SetShaderOpacity(quad->opacity(), locations.alpha);
+ SetShaderQuadF(surface_quad, locations.quad);
DrawQuadGeometry(
- frame, quad->quadTransform(), quad->rect, shader_matrix_location);
+ frame, quad->quadTransform(), quad->rect, locations.matrix);
// Flush the compositor context before the filter bitmap goes out of
// scope, so the draw gets processed before the filter texture gets deleted.
if (filter_image)
- GLC(gl_, gl_->Flush());
+ gl_->Flush();
- if (CanApplyBlendModeUsingBlendFunc(blend_mode))
+ if (!use_shaders_for_blending)
RestoreBlendFuncToDefault(blend_mode);
}
@@ -1448,15 +1283,78 @@ static void SolidColorUniformLocation(T program,
uniforms->color_location = program->fragment_shader().color_location();
}
+namespace {
+// These functions determine if a quad, clipped by a clip_region contains
+// the entire {top|bottom|left|right} edge.
+bool is_top(const gfx::QuadF* clip_region, const DrawQuad* quad) {
+ if (!quad->IsTopEdge())
+ return false;
+ if (!clip_region)
+ return true;
+
+ return std::abs(clip_region->p1().y()) < kAntiAliasingEpsilon &&
+ std::abs(clip_region->p2().y()) < kAntiAliasingEpsilon;
+}
+
+bool is_bottom(const gfx::QuadF* clip_region, const DrawQuad* quad) {
+ if (!quad->IsBottomEdge())
+ return false;
+ if (!clip_region)
+ return true;
+
+ return std::abs(clip_region->p3().y() -
+ quad->shared_quad_state->content_bounds.height()) <
+ kAntiAliasingEpsilon &&
+ std::abs(clip_region->p4().y() -
+ quad->shared_quad_state->content_bounds.height()) <
+ kAntiAliasingEpsilon;
+}
+
+bool is_left(const gfx::QuadF* clip_region, const DrawQuad* quad) {
+ if (!quad->IsLeftEdge())
+ return false;
+ if (!clip_region)
+ return true;
+
+ return std::abs(clip_region->p1().x()) < kAntiAliasingEpsilon &&
+ std::abs(clip_region->p4().x()) < kAntiAliasingEpsilon;
+}
+
+bool is_right(const gfx::QuadF* clip_region, const DrawQuad* quad) {
+ if (!quad->IsRightEdge())
+ return false;
+ if (!clip_region)
+ return true;
+
+ return std::abs(clip_region->p2().x() -
+ quad->shared_quad_state->content_bounds.width()) <
+ kAntiAliasingEpsilon &&
+ std::abs(clip_region->p3().x() -
+ quad->shared_quad_state->content_bounds.width()) <
+ kAntiAliasingEpsilon;
+}
+} // anonymous namespace
+
static gfx::QuadF GetDeviceQuadWithAntialiasingOnExteriorEdges(
const LayerQuad& device_layer_edges,
const gfx::Transform& device_transform,
+ const gfx::QuadF* clip_region,
const DrawQuad* quad) {
- gfx::Rect tile_rect = quad->visible_rect;
- gfx::PointF bottom_right = tile_rect.bottom_right();
- gfx::PointF bottom_left = tile_rect.bottom_left();
- gfx::PointF top_left = tile_rect.origin();
- gfx::PointF top_right = tile_rect.top_right();
+ gfx::RectF tile_rect = quad->visible_rect;
+ gfx::QuadF tile_quad(tile_rect);
+
+ if (clip_region) {
+ if (quad->material != DrawQuad::RENDER_PASS) {
+ tile_quad = *clip_region;
+ } else {
+ GetScaledRegion(quad->rect, clip_region, &tile_quad);
+ }
+ }
+
+ gfx::PointF bottom_right = tile_quad.p3();
+ gfx::PointF bottom_left = tile_quad.p4();
+ gfx::PointF top_left = tile_quad.p1();
+ gfx::PointF top_right = tile_quad.p2();
bool clipped = false;
// Map points to device space. We ignore |clipped|, since the result of
@@ -1473,16 +1371,26 @@ static gfx::QuadF GetDeviceQuadWithAntialiasingOnExteriorEdges(
LayerQuad::Edge right_edge(top_right, bottom_right);
// Only apply anti-aliasing to edges not clipped by culling or scissoring.
- if (quad->IsTopEdge() && tile_rect.y() == quad->rect.y())
+ // If an edge is degenerate we do not want to replace it with a "proper" edge
+ // as that will cause the quad to possibly expand is strange ways.
+ if (!top_edge.degenerate() && is_top(clip_region, quad) &&
+ tile_rect.y() == quad->rect.y()) {
top_edge = device_layer_edges.top();
- if (quad->IsLeftEdge() && tile_rect.x() == quad->rect.x())
+ }
+ if (!left_edge.degenerate() && is_left(clip_region, quad) &&
+ tile_rect.x() == quad->rect.x()) {
left_edge = device_layer_edges.left();
- if (quad->IsRightEdge() && tile_rect.right() == quad->rect.right())
+ }
+ if (!right_edge.degenerate() && is_right(clip_region, quad) &&
+ tile_rect.right() == quad->rect.right()) {
right_edge = device_layer_edges.right();
- if (quad->IsBottomEdge() && tile_rect.bottom() == quad->rect.bottom())
+ }
+ if (!bottom_edge.degenerate() && is_bottom(clip_region, quad) &&
+ tile_rect.bottom() == quad->rect.bottom()) {
bottom_edge = device_layer_edges.bottom();
+ }
- float sign = gfx::QuadF(tile_rect).IsCounterClockwise() ? -1 : 1;
+ float sign = tile_quad.IsCounterClockwise() ? -1 : 1;
bottom_edge.scale(sign);
left_edge.scale(sign);
top_edge.scale(sign);
@@ -1492,6 +1400,32 @@ static gfx::QuadF GetDeviceQuadWithAntialiasingOnExteriorEdges(
return LayerQuad(left_edge, top_edge, right_edge, bottom_edge).ToQuadF();
}
+float GetTotalQuadError(const gfx::QuadF* clipped_quad,
+ const gfx::QuadF* ideal_rect) {
+ return (clipped_quad->p1() - ideal_rect->p1()).LengthSquared() +
+ (clipped_quad->p2() - ideal_rect->p2()).LengthSquared() +
+ (clipped_quad->p3() - ideal_rect->p3()).LengthSquared() +
+ (clipped_quad->p4() - ideal_rect->p4()).LengthSquared();
+}
+
+// Attempt to rotate the clipped quad until it lines up the most
+// correctly. This is necessary because we check the edges of this
+// quad against the expected left/right/top/bottom for anti-aliasing.
+void AlignQuadToBoundingBox(gfx::QuadF* clipped_quad) {
+ gfx::QuadF bounding_quad = gfx::QuadF(clipped_quad->BoundingBox());
+ gfx::QuadF best_rotation = *clipped_quad;
+ float least_error_amount = GetTotalQuadError(clipped_quad, &bounding_quad);
+ for (size_t i = 1; i < 4; ++i) {
+ clipped_quad->Realign(1);
+ float new_error = GetTotalQuadError(clipped_quad, &bounding_quad);
+ if (new_error < least_error_amount) {
+ least_error_amount = new_error;
+ best_rotation = *clipped_quad;
+ }
+ }
+ *clipped_quad = best_rotation;
+}
+
// static
bool GLRenderer::ShouldAntialiasQuad(const gfx::Transform& device_transform,
const DrawQuad* quad,
@@ -1523,18 +1457,39 @@ bool GLRenderer::ShouldAntialiasQuad(const gfx::Transform& device_transform,
}
// static
-void GLRenderer::SetupQuadForAntialiasing(
+void GLRenderer::SetupQuadForClippingAndAntialiasing(
const gfx::Transform& device_transform,
const DrawQuad* quad,
+ bool use_aa,
+ const gfx::QuadF* clip_region,
gfx::QuadF* local_quad,
float edge[24]) {
bool is_render_pass_quad = (quad->material == DrawQuad::RENDER_PASS);
- gfx::RectF content_rect =
- is_render_pass_quad ? QuadVertexRect() : quad->visibleContentRect();
-
+ gfx::QuadF rotated_clip;
+ const gfx::QuadF* local_clip_region = clip_region;
+ if (local_clip_region) {
+ rotated_clip = *clip_region;
+ AlignQuadToBoundingBox(&rotated_clip);
+ local_clip_region = &rotated_clip;
+ }
+
+ gfx::QuadF content_rect = is_render_pass_quad
+ ? gfx::QuadF(QuadVertexRect())
+ : gfx::QuadF(quad->visibleContentRect());
+ if (!use_aa) {
+ if (local_clip_region) {
+ if (!is_render_pass_quad) {
+ content_rect = *local_clip_region;
+ } else {
+ GetScaledRegion(quad->rect, local_clip_region, &content_rect);
+ }
+ *local_quad = content_rect;
+ }
+ return;
+ }
bool clipped = false;
gfx::QuadF device_layer_quad =
- MathUtil::MapQuad(device_transform, gfx::QuadF(content_rect), &clipped);
+ MathUtil::MapQuad(device_transform, content_rect, &clipped);
LayerQuad device_layer_bounds(gfx::QuadF(device_layer_quad.BoundingBox()));
device_layer_bounds.InflateAntiAliasingDistance();
@@ -1545,16 +1500,25 @@ void GLRenderer::SetupQuadForAntialiasing(
device_layer_edges.ToFloatArray(edge);
device_layer_bounds.ToFloatArray(&edge[12]);
+ // If we have a clip region then we are split, and therefore
+ // by necessity, at least one of our edges is not an external
+ // one.
+ bool is_full_rect = quad->visible_rect == quad->rect;
+
+ bool region_contains_all_outside_edges =
+ is_full_rect &&
+ (is_top(local_clip_region, quad) && is_left(local_clip_region, quad) &&
+ is_bottom(local_clip_region, quad) && is_right(local_clip_region, quad));
+
bool use_aa_on_all_four_edges =
- is_render_pass_quad ||
- (quad->IsTopEdge() && quad->IsLeftEdge() && quad->IsBottomEdge() &&
- quad->IsRightEdge() && quad->visible_rect == quad->rect);
+ !local_clip_region &&
+ (is_render_pass_quad || region_contains_all_outside_edges);
gfx::QuadF device_quad =
use_aa_on_all_four_edges
? device_layer_edges.ToQuadF()
: GetDeviceQuadWithAntialiasingOnExteriorEdges(
- device_layer_edges, device_transform, quad);
+ device_layer_edges, device_transform, local_clip_region, quad);
// 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
@@ -1570,7 +1534,8 @@ void GLRenderer::SetupQuadForAntialiasing(
}
void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame,
- const SolidColorDrawQuad* quad) {
+ const SolidColorDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
gfx::Rect tile_rect = quad->visible_rect;
SkColor color = quad->color;
@@ -1594,29 +1559,30 @@ void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame,
bool use_aa = settings_->allow_antialiasing &&
!quad->force_anti_aliasing_off &&
ShouldAntialiasQuad(device_transform, quad, force_aa);
+ SetupQuadForClippingAndAntialiasing(device_transform, quad, use_aa,
+ clip_region, &local_quad, edge);
SolidColorProgramUniforms uniforms;
if (use_aa) {
- SetupQuadForAntialiasing(device_transform, quad, &local_quad, edge);
SolidColorUniformLocation(GetSolidColorProgramAA(), &uniforms);
} else {
SolidColorUniformLocation(GetSolidColorProgram(), &uniforms);
}
SetUseProgram(uniforms.program);
- GLC(gl_,
- gl_->Uniform4f(uniforms.color_location,
- (SkColorGetR(color) * (1.0f / 255.0f)) * alpha,
- (SkColorGetG(color) * (1.0f / 255.0f)) * alpha,
- (SkColorGetB(color) * (1.0f / 255.0f)) * alpha,
- alpha));
+ gl_->Uniform4f(uniforms.color_location,
+ (SkColorGetR(color) * (1.0f / 255.0f)) * alpha,
+ (SkColorGetG(color) * (1.0f / 255.0f)) * alpha,
+ (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, alpha);
if (use_aa) {
- float viewport[4] = {static_cast<float>(viewport_.x()),
- static_cast<float>(viewport_.y()),
- static_cast<float>(viewport_.width()),
- static_cast<float>(viewport_.height()), };
- GLC(gl_, gl_->Uniform4fv(uniforms.viewport_location, 1, viewport));
- GLC(gl_, gl_->Uniform3fv(uniforms.edge_location, 8, edge));
+ float viewport[4] = {
+ static_cast<float>(current_window_space_viewport_.x()),
+ static_cast<float>(current_window_space_viewport_.y()),
+ static_cast<float>(current_window_space_viewport_.width()),
+ static_cast<float>(current_window_space_viewport_.height()),
+ };
+ gl_->Uniform4fv(uniforms.viewport_location, 1, viewport);
+ gl_->Uniform3fv(uniforms.edge_location, 8, edge);
}
// Enable blending when the quad properties require it or if we decided
@@ -1668,13 +1634,15 @@ static void TileUniformLocation(T program, TileProgramUniforms* uniforms) {
}
void GLRenderer::DrawTileQuad(const DrawingFrame* frame,
- const TileDrawQuad* quad) {
- DrawContentQuad(frame, quad, quad->resource_id);
+ const TileDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ DrawContentQuad(frame, quad, quad->resource_id, clip_region);
}
void GLRenderer::DrawContentQuad(const DrawingFrame* frame,
const ContentDrawQuadBase* quad,
- ResourceProvider::ResourceId resource_id) {
+ ResourceProvider::ResourceId resource_id,
+ const gfx::QuadF* clip_region) {
gfx::Transform device_transform =
frame->window_matrix * frame->projection_matrix * quad->quadTransform();
device_transform.FlattenTo2d();
@@ -1686,15 +1654,16 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame,
// similar to the way DrawContentQuadNoAA works and then consider
// combining DrawContentQuadAA and DrawContentQuadNoAA into one method.
if (use_aa)
- DrawContentQuadAA(frame, quad, resource_id, device_transform);
+ DrawContentQuadAA(frame, quad, resource_id, device_transform, clip_region);
else
- DrawContentQuadNoAA(frame, quad, resource_id);
+ DrawContentQuadNoAA(frame, quad, resource_id, clip_region);
}
void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame,
const ContentDrawQuadBase* quad,
ResourceProvider::ResourceId resource_id,
- const gfx::Transform& device_transform) {
+ const gfx::Transform& device_transform,
+ const gfx::QuadF* clip_region) {
if (!device_transform.IsInvertible())
return;
@@ -1739,10 +1708,11 @@ void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame,
gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect));
float edge[24];
- SetupQuadForAntialiasing(device_transform, quad, &local_quad, edge);
-
+ SetupQuadForClippingAndAntialiasing(device_transform, quad, true, clip_region,
+ &local_quad, edge);
ResourceProvider::ScopedSamplerGL quad_resource_lock(
- resource_provider_, resource_id, GL_LINEAR);
+ resource_provider_, resource_id,
+ quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR);
SamplerType sampler =
SamplerTypeFromTextureTarget(quad_resource_lock.target());
@@ -1752,7 +1722,7 @@ void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame,
float fragment_tex_scale_y = clamp_tex_rect.height();
// Map to normalized texture coordinates.
- if (sampler != SamplerType2DRect) {
+ if (sampler != SAMPLER_TYPE_2D_RECT) {
gfx::Size texture_size = quad->texture_size;
DCHECK(!texture_size.IsEmpty());
fragment_tex_translate_x /= texture_size.width();
@@ -1771,29 +1741,23 @@ void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame,
}
SetUseProgram(uniforms.program);
- GLC(gl_, gl_->Uniform1i(uniforms.sampler_location, 0));
+ gl_->Uniform1i(uniforms.sampler_location, 0);
float viewport[4] = {
- static_cast<float>(viewport_.x()),
- static_cast<float>(viewport_.y()),
- static_cast<float>(viewport_.width()),
- static_cast<float>(viewport_.height()),
+ static_cast<float>(current_window_space_viewport_.x()),
+ static_cast<float>(current_window_space_viewport_.y()),
+ static_cast<float>(current_window_space_viewport_.width()),
+ static_cast<float>(current_window_space_viewport_.height()),
};
- GLC(gl_, gl_->Uniform4fv(uniforms.viewport_location, 1, viewport));
- GLC(gl_, gl_->Uniform3fv(uniforms.edge_location, 8, edge));
-
- GLC(gl_,
- gl_->Uniform4f(uniforms.vertex_tex_transform_location,
- vertex_tex_translate_x,
- vertex_tex_translate_y,
- vertex_tex_scale_x,
- vertex_tex_scale_y));
- GLC(gl_,
- gl_->Uniform4f(uniforms.fragment_tex_transform_location,
- fragment_tex_translate_x,
- fragment_tex_translate_y,
- fragment_tex_scale_x,
- fragment_tex_scale_y));
+ gl_->Uniform4fv(uniforms.viewport_location, 1, viewport);
+ gl_->Uniform3fv(uniforms.edge_location, 8, edge);
+
+ gl_->Uniform4f(uniforms.vertex_tex_transform_location, vertex_tex_translate_x,
+ vertex_tex_translate_y, vertex_tex_scale_x,
+ vertex_tex_scale_y);
+ gl_->Uniform4f(uniforms.fragment_tex_transform_location,
+ fragment_tex_translate_x, fragment_tex_translate_y,
+ fragment_tex_scale_x, fragment_tex_scale_y);
// Blending is required for antialiasing.
SetBlendEnabled(true);
@@ -1817,7 +1781,8 @@ void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame,
void GLRenderer::DrawContentQuadNoAA(const DrawingFrame* frame,
const ContentDrawQuadBase* quad,
- ResourceProvider::ResourceId resource_id) {
+ ResourceProvider::ResourceId resource_id,
+ const gfx::QuadF* clip_region) {
gfx::RectF tex_coord_rect = MathUtil::ScaleRectProportional(
quad->tex_coord_rect, quad->rect, quad->visible_rect);
float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width();
@@ -1826,7 +1791,8 @@ void GLRenderer::DrawContentQuadNoAA(const DrawingFrame* frame,
bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f);
GLenum filter =
- (scaled || !quad->quadTransform().IsIdentityOrIntegerTranslation())
+ (scaled || !quad->quadTransform().IsIdentityOrIntegerTranslation()) &&
+ !quad->nearest_neighbor
? GL_LINEAR
: GL_NEAREST;
@@ -1841,7 +1807,7 @@ void GLRenderer::DrawContentQuadNoAA(const DrawingFrame* frame,
float vertex_tex_scale_y = tex_coord_rect.height();
// Map to normalized texture coordinates.
- if (sampler != SamplerType2DRect) {
+ if (sampler != SAMPLER_TYPE_2D_RECT) {
gfx::Size texture_size = quad->texture_size;
DCHECK(!texture_size.IsEmpty());
vertex_tex_translate_x /= texture_size.width();
@@ -1873,14 +1839,11 @@ void GLRenderer::DrawContentQuadNoAA(const DrawingFrame* frame,
}
SetUseProgram(uniforms.program);
- GLC(gl_, gl_->Uniform1i(uniforms.sampler_location, 0));
+ gl_->Uniform1i(uniforms.sampler_location, 0);
- GLC(gl_,
- gl_->Uniform4f(uniforms.vertex_tex_transform_location,
- vertex_tex_translate_x,
- vertex_tex_translate_y,
- vertex_tex_scale_x,
- vertex_tex_scale_y));
+ gl_->Uniform4f(uniforms.vertex_tex_transform_location, vertex_tex_translate_x,
+ vertex_tex_translate_y, vertex_tex_scale_x,
+ vertex_tex_scale_y);
SetBlendEnabled(quad->ShouldDrawWithBlending());
@@ -1890,30 +1853,50 @@ void GLRenderer::DrawContentQuadNoAA(const DrawingFrame* frame,
// does, then vertices will match the texture mapping in the vertex buffer.
// The method SetShaderQuadF() changes the order of vertices and so it's
// not used here.
-
- gfx::RectF tile_rect = quad->visible_rect;
+ gfx::QuadF tile_rect(quad->visible_rect);
+ float width = quad->visible_rect.width();
+ float height = quad->visible_rect.height();
+ gfx::PointF top_left = quad->visible_rect.origin();
+ if (clip_region) {
+ tile_rect = *clip_region;
+ float gl_uv[8] = {
+ (tile_rect.p4().x() - top_left.x()) / width,
+ (tile_rect.p4().y() - top_left.y()) / height,
+ (tile_rect.p1().x() - top_left.x()) / width,
+ (tile_rect.p1().y() - top_left.y()) / height,
+ (tile_rect.p2().x() - top_left.x()) / width,
+ (tile_rect.p2().y() - top_left.y()) / height,
+ (tile_rect.p3().x() - top_left.x()) / width,
+ (tile_rect.p3().y() - top_left.y()) / height,
+ };
+ PrepareGeometry(CLIPPED_BINDING);
+ clipped_geometry_->InitializeCustomQuadWithUVs(
+ gfx::QuadF(quad->visible_rect), gl_uv);
+ } else {
+ PrepareGeometry(SHARED_BINDING);
+ }
float gl_quad[8] = {
- tile_rect.x(),
- tile_rect.bottom(),
- tile_rect.x(),
- tile_rect.y(),
- tile_rect.right(),
- tile_rect.y(),
- tile_rect.right(),
- tile_rect.bottom(),
+ tile_rect.p4().x(),
+ tile_rect.p4().y(),
+ tile_rect.p1().x(),
+ tile_rect.p1().y(),
+ tile_rect.p2().x(),
+ tile_rect.p2().y(),
+ tile_rect.p3().x(),
+ tile_rect.p3().y(),
};
- GLC(gl_, gl_->Uniform2fv(uniforms.quad_location, 4, gl_quad));
+ gl_->Uniform2fv(uniforms.quad_location, 4, gl_quad);
static float gl_matrix[16];
ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad->quadTransform());
- GLC(gl_,
- gl_->UniformMatrix4fv(uniforms.matrix_location, 1, false, &gl_matrix[0]));
+ gl_->UniformMatrix4fv(uniforms.matrix_location, 1, false, &gl_matrix[0]);
- GLC(gl_, gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0));
+ gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
}
void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
- const YUVVideoDrawQuad* quad) {
+ const YUVVideoDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
SetBlendEnabled(quad->ShouldDrawWithBlending());
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
@@ -1926,23 +1909,29 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
ResourceProvider::ScopedSamplerGL y_plane_lock(
resource_provider_, quad->y_plane_resource_id, GL_TEXTURE1, GL_LINEAR);
- DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), y_plane_lock.target());
ResourceProvider::ScopedSamplerGL u_plane_lock(
resource_provider_, quad->u_plane_resource_id, GL_TEXTURE2, GL_LINEAR);
- DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), u_plane_lock.target());
+ DCHECK_EQ(y_plane_lock.target(), u_plane_lock.target());
ResourceProvider::ScopedSamplerGL v_plane_lock(
resource_provider_, quad->v_plane_resource_id, GL_TEXTURE3, GL_LINEAR);
- DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), v_plane_lock.target());
+ DCHECK_EQ(y_plane_lock.target(), v_plane_lock.target());
scoped_ptr<ResourceProvider::ScopedSamplerGL> a_plane_lock;
if (use_alpha_plane) {
a_plane_lock.reset(new ResourceProvider::ScopedSamplerGL(
resource_provider_, quad->a_plane_resource_id, GL_TEXTURE4, GL_LINEAR));
- DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), a_plane_lock->target());
+ DCHECK_EQ(y_plane_lock.target(), a_plane_lock->target());
}
+ // All planes must have the same sampler type.
+ SamplerType sampler = SamplerTypeFromTextureTarget(y_plane_lock.target());
+
int matrix_location = -1;
- int tex_scale_location = -1;
- int tex_offset_location = -1;
+ int ya_tex_scale_location = -1;
+ int ya_tex_offset_location = -1;
+ int uv_tex_scale_location = -1;
+ int uv_tex_offset_location = -1;
+ int ya_clamp_rect_location = -1;
+ int uv_clamp_rect_location = -1;
int y_texture_location = -1;
int u_texture_location = -1;
int v_texture_location = -1;
@@ -1951,47 +1940,104 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
int yuv_adj_location = -1;
int alpha_location = -1;
if (use_alpha_plane) {
- const VideoYUVAProgram* program = GetVideoYUVAProgram(tex_coord_precision);
+ const VideoYUVAProgram* program =
+ GetVideoYUVAProgram(tex_coord_precision, sampler);
DCHECK(program && (program->initialized() || IsContextLost()));
SetUseProgram(program->program());
matrix_location = program->vertex_shader().matrix_location();
- tex_scale_location = program->vertex_shader().tex_scale_location();
- tex_offset_location = program->vertex_shader().tex_offset_location();
+ ya_tex_scale_location = program->vertex_shader().ya_tex_scale_location();
+ ya_tex_offset_location = program->vertex_shader().ya_tex_offset_location();
+ uv_tex_scale_location = program->vertex_shader().uv_tex_scale_location();
+ uv_tex_offset_location = program->vertex_shader().uv_tex_offset_location();
y_texture_location = program->fragment_shader().y_texture_location();
u_texture_location = program->fragment_shader().u_texture_location();
v_texture_location = program->fragment_shader().v_texture_location();
a_texture_location = program->fragment_shader().a_texture_location();
yuv_matrix_location = program->fragment_shader().yuv_matrix_location();
yuv_adj_location = program->fragment_shader().yuv_adj_location();
+ ya_clamp_rect_location =
+ program->fragment_shader().ya_clamp_rect_location();
+ uv_clamp_rect_location =
+ program->fragment_shader().uv_clamp_rect_location();
alpha_location = program->fragment_shader().alpha_location();
} else {
- const VideoYUVProgram* program = GetVideoYUVProgram(tex_coord_precision);
+ const VideoYUVProgram* program =
+ GetVideoYUVProgram(tex_coord_precision, sampler);
DCHECK(program && (program->initialized() || IsContextLost()));
SetUseProgram(program->program());
matrix_location = program->vertex_shader().matrix_location();
- tex_scale_location = program->vertex_shader().tex_scale_location();
- tex_offset_location = program->vertex_shader().tex_offset_location();
+ ya_tex_scale_location = program->vertex_shader().ya_tex_scale_location();
+ ya_tex_offset_location = program->vertex_shader().ya_tex_offset_location();
+ uv_tex_scale_location = program->vertex_shader().uv_tex_scale_location();
+ uv_tex_offset_location = program->vertex_shader().uv_tex_offset_location();
y_texture_location = program->fragment_shader().y_texture_location();
u_texture_location = program->fragment_shader().u_texture_location();
v_texture_location = program->fragment_shader().v_texture_location();
yuv_matrix_location = program->fragment_shader().yuv_matrix_location();
yuv_adj_location = program->fragment_shader().yuv_adj_location();
+ ya_clamp_rect_location =
+ program->fragment_shader().ya_clamp_rect_location();
+ uv_clamp_rect_location =
+ program->fragment_shader().uv_clamp_rect_location();
alpha_location = program->fragment_shader().alpha_location();
}
- GLC(gl_,
- gl_->Uniform2f(tex_scale_location,
- quad->tex_coord_rect.width(),
- quad->tex_coord_rect.height()));
- GLC(gl_,
- gl_->Uniform2f(tex_offset_location,
- quad->tex_coord_rect.x(),
- quad->tex_coord_rect.y()));
- GLC(gl_, gl_->Uniform1i(y_texture_location, 1));
- GLC(gl_, gl_->Uniform1i(u_texture_location, 2));
- GLC(gl_, gl_->Uniform1i(v_texture_location, 3));
+ gfx::SizeF ya_tex_scale(1.0f, 1.0f);
+ gfx::SizeF uv_tex_scale(1.0f, 1.0f);
+ if (sampler != SAMPLER_TYPE_2D_RECT) {
+ DCHECK(!quad->ya_tex_size.IsEmpty());
+ DCHECK(!quad->uv_tex_size.IsEmpty());
+ ya_tex_scale = gfx::SizeF(1.0f / quad->ya_tex_size.width(),
+ 1.0f / quad->ya_tex_size.height());
+ uv_tex_scale = gfx::SizeF(1.0f / quad->uv_tex_size.width(),
+ 1.0f / quad->uv_tex_size.height());
+ }
+
+ float ya_vertex_tex_translate_x =
+ quad->ya_tex_coord_rect.x() * ya_tex_scale.width();
+ float ya_vertex_tex_translate_y =
+ quad->ya_tex_coord_rect.y() * ya_tex_scale.height();
+ float ya_vertex_tex_scale_x =
+ quad->ya_tex_coord_rect.width() * ya_tex_scale.width();
+ float ya_vertex_tex_scale_y =
+ quad->ya_tex_coord_rect.height() * ya_tex_scale.height();
+
+ float uv_vertex_tex_translate_x =
+ quad->uv_tex_coord_rect.x() * uv_tex_scale.width();
+ float uv_vertex_tex_translate_y =
+ quad->uv_tex_coord_rect.y() * uv_tex_scale.height();
+ float uv_vertex_tex_scale_x =
+ quad->uv_tex_coord_rect.width() * uv_tex_scale.width();
+ float uv_vertex_tex_scale_y =
+ quad->uv_tex_coord_rect.height() * uv_tex_scale.height();
+
+ gl_->Uniform2f(ya_tex_scale_location, ya_vertex_tex_scale_x,
+ ya_vertex_tex_scale_y);
+ gl_->Uniform2f(ya_tex_offset_location, ya_vertex_tex_translate_x,
+ ya_vertex_tex_translate_y);
+ gl_->Uniform2f(uv_tex_scale_location, uv_vertex_tex_scale_x,
+ uv_vertex_tex_scale_y);
+ gl_->Uniform2f(uv_tex_offset_location, uv_vertex_tex_translate_x,
+ uv_vertex_tex_translate_y);
+
+ gfx::RectF ya_clamp_rect(ya_vertex_tex_translate_x, ya_vertex_tex_translate_y,
+ ya_vertex_tex_scale_x, ya_vertex_tex_scale_y);
+ ya_clamp_rect.Inset(0.5f * ya_tex_scale.width(),
+ 0.5f * ya_tex_scale.height());
+ gfx::RectF uv_clamp_rect(uv_vertex_tex_translate_x, uv_vertex_tex_translate_y,
+ uv_vertex_tex_scale_x, uv_vertex_tex_scale_y);
+ uv_clamp_rect.Inset(0.5f * uv_tex_scale.width(),
+ 0.5f * uv_tex_scale.height());
+ gl_->Uniform4f(ya_clamp_rect_location, ya_clamp_rect.x(), ya_clamp_rect.y(),
+ ya_clamp_rect.right(), ya_clamp_rect.bottom());
+ gl_->Uniform4f(uv_clamp_rect_location, uv_clamp_rect.x(), uv_clamp_rect.y(),
+ uv_clamp_rect.right(), uv_clamp_rect.bottom());
+
+ gl_->Uniform1i(y_texture_location, 1);
+ gl_->Uniform1i(u_texture_location, 2);
+ gl_->Uniform1i(v_texture_location, 3);
if (use_alpha_plane)
- GLC(gl_, gl_->Uniform1i(a_texture_location, 4));
+ gl_->Uniform1i(a_texture_location, 4);
// These values are magic numbers that are used in the transformation from YUV
// to RGB color values. They are taken from the following webpage:
@@ -1999,9 +2045,12 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
float yuv_to_rgb_rec601[9] = {
1.164f, 1.164f, 1.164f, 0.0f, -.391f, 2.018f, 1.596f, -.813f, 0.0f,
};
- float yuv_to_rgb_rec601_jpeg[9] = {
+ float yuv_to_rgb_jpeg[9] = {
1.f, 1.f, 1.f, 0.0f, -.34414f, 1.772f, 1.402f, -.71414f, 0.0f,
};
+ float yuv_to_rgb_rec709[9] = {
+ 1.164f, 1.164f, 1.164f, 0.0f, -0.213f, 2.112f, 1.793f, -0.533f, 0.0f,
+ };
// These values map to 16, 128, and 128 respectively, and are computed
// as a fraction over 256 (e.g. 16 / 256 = 0.0625).
@@ -2009,12 +2058,12 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
// Y - 16 : Gives 16 values of head and footroom for overshooting
// U - 128 : Turns unsigned U into signed U [-128,127]
// V - 128 : Turns unsigned V into signed V [-128,127]
- float yuv_adjust_rec601[3] = {
+ float yuv_adjust_constrained[3] = {
-0.0625f, -0.5f, -0.5f,
};
// Same as above, but without the head and footroom.
- float yuv_adjust_rec601_jpeg[3] = {
+ float yuv_adjust_full[3] = {
0.0f, -0.5f, -0.5f,
};
@@ -2024,23 +2073,43 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
switch (quad->color_space) {
case YUVVideoDrawQuad::REC_601:
yuv_to_rgb = yuv_to_rgb_rec601;
- yuv_adjust = yuv_adjust_rec601;
+ yuv_adjust = yuv_adjust_constrained;
break;
- case YUVVideoDrawQuad::REC_601_JPEG:
- yuv_to_rgb = yuv_to_rgb_rec601_jpeg;
- yuv_adjust = yuv_adjust_rec601_jpeg;
+ case YUVVideoDrawQuad::REC_709:
+ yuv_to_rgb = yuv_to_rgb_rec709;
+ yuv_adjust = yuv_adjust_constrained;
+ break;
+ case YUVVideoDrawQuad::JPEG:
+ yuv_to_rgb = yuv_to_rgb_jpeg;
+ yuv_adjust = yuv_adjust_full;
break;
}
- GLC(gl_, gl_->UniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb));
- GLC(gl_, gl_->Uniform3fv(yuv_adj_location, 1, yuv_adjust));
+ // The transform and vertex data are used to figure out the extents that the
+ // un-antialiased quad should have and which vertex this is and the float
+ // quad passed in via uniform is the actual geometry that gets used to draw
+ // it. This is why this centered rect is used and not the original quad_rect.
+ gfx::RectF tile_rect = quad->rect;
+ gl_->UniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb);
+ gl_->Uniform3fv(yuv_adj_location, 1, yuv_adjust);
SetShaderOpacity(quad->opacity(), alpha_location);
- DrawQuadGeometry(frame, quad->quadTransform(), quad->rect, matrix_location);
+ if (!clip_region) {
+ DrawQuadGeometry(frame, quad->quadTransform(), tile_rect, matrix_location);
+ } else {
+ float uvs[8] = {0};
+ GetScaledUVs(quad->visible_rect, clip_region, uvs);
+ gfx::QuadF region_quad = *clip_region;
+ region_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
+ region_quad -= gfx::Vector2dF(0.5f, 0.5f);
+ DrawQuadGeometryClippedByQuadF(frame, quad->quadTransform(), tile_rect,
+ region_quad, matrix_location, uvs);
+ }
}
void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame,
- const StreamVideoDrawQuad* quad) {
+ const StreamVideoDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
SetBlendEnabled(quad->ShouldDrawWithBlending());
static float gl_matrix[16];
@@ -2058,71 +2127,31 @@ void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame,
SetUseProgram(program->program());
ToGLMatrix(&gl_matrix[0], quad->matrix);
- GLC(gl_,
- gl_->UniformMatrix4fv(
- program->vertex_shader().tex_matrix_location(), 1, false, gl_matrix));
+ gl_->UniformMatrix4fv(program->vertex_shader().tex_matrix_location(), 1,
+ false, gl_matrix);
ResourceProvider::ScopedReadLockGL lock(resource_provider_,
quad->resource_id);
DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id()));
+ gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id());
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
+ gl_->Uniform1i(program->fragment_shader().sampler_location(), 0);
SetShaderOpacity(quad->opacity(),
program->fragment_shader().alpha_location());
- DrawQuadGeometry(frame,
- quad->quadTransform(),
- quad->rect,
- program->vertex_shader().matrix_location());
-}
-
-void GLRenderer::DrawPictureQuad(const DrawingFrame* frame,
- const PictureDrawQuad* quad) {
- if (on_demand_tile_raster_bitmap_.width() != quad->texture_size.width() ||
- on_demand_tile_raster_bitmap_.height() != quad->texture_size.height()) {
- on_demand_tile_raster_bitmap_.allocN32Pixels(quad->texture_size.width(),
- quad->texture_size.height());
-
- if (on_demand_tile_raster_resource_id_)
- resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
-
- on_demand_tile_raster_resource_id_ = resource_provider_->CreateGLTexture(
- quad->texture_size,
- GL_TEXTURE_2D,
- GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- quad->texture_format);
- }
-
- SkCanvas canvas(on_demand_tile_raster_bitmap_);
- quad->picture_pile->PlaybackToCanvas(&canvas, quad->content_rect,
- quad->contents_scale);
-
- uint8_t* bitmap_pixels = NULL;
- SkBitmap on_demand_tile_raster_bitmap_dest;
- SkColorType colorType = ResourceFormatToSkColorType(quad->texture_format);
- if (on_demand_tile_raster_bitmap_.colorType() != colorType) {
- on_demand_tile_raster_bitmap_.copyTo(&on_demand_tile_raster_bitmap_dest,
- colorType);
- // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
- // bitmap data. This check will be removed once crbug.com/293728 is fixed.
- CHECK_EQ(0u, on_demand_tile_raster_bitmap_dest.rowBytes() % 4);
- bitmap_pixels = reinterpret_cast<uint8_t*>(
- on_demand_tile_raster_bitmap_dest.getPixels());
+ if (!clip_region) {
+ DrawQuadGeometry(frame, quad->quadTransform(), quad->rect,
+ program->vertex_shader().matrix_location());
} else {
- bitmap_pixels =
- reinterpret_cast<uint8_t*>(on_demand_tile_raster_bitmap_.getPixels());
+ gfx::QuadF region_quad(*clip_region);
+ region_quad.Scale(1.0f / quad->rect.width(), 1.0f / quad->rect.height());
+ region_quad -= gfx::Vector2dF(0.5f, 0.5f);
+ float uvs[8] = {0};
+ GetScaledUVs(quad->visible_rect, clip_region, uvs);
+ DrawQuadGeometryClippedByQuadF(
+ frame, quad->quadTransform(), quad->rect, region_quad,
+ program->vertex_shader().matrix_location(), uvs);
}
-
- resource_provider_->SetPixels(on_demand_tile_raster_resource_id_,
- bitmap_pixels,
- gfx::Rect(quad->texture_size),
- gfx::Rect(quad->texture_size),
- gfx::Vector2d());
-
- DrawContentQuad(frame, quad, on_demand_tile_raster_resource_id_);
}
struct TextureProgramBinding {
@@ -2138,6 +2167,7 @@ struct TextureProgramBinding {
int program_id;
int sampler_location;
int matrix_location;
+ int transform_location;
int background_color_location;
};
@@ -2153,11 +2183,13 @@ struct TexTransformTextureProgramBinding : TextureProgramBinding {
int vertex_opacity_location;
};
-void GLRenderer::FlushTextureQuadCache() {
+void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) {
// Check to see if we have anything to draw.
if (draw_cache_.program_id == -1)
return;
+ PrepareGeometry(flush_binding);
+
// Set the correct blending mode.
SetBlendEnabled(draw_cache_.needs_blending);
@@ -2165,80 +2197,94 @@ void GLRenderer::FlushTextureQuadCache() {
SetUseProgram(draw_cache_.program_id);
// Bind the correct texture sampler location.
- GLC(gl_, gl_->Uniform1i(draw_cache_.sampler_location, 0));
+ gl_->Uniform1i(draw_cache_.sampler_location, 0);
// Assume the current active textures is 0.
- ResourceProvider::ScopedReadLockGL locked_quad(resource_provider_,
- draw_cache_.resource_id);
+ ResourceProvider::ScopedSamplerGL locked_quad(
+ resource_provider_,
+ draw_cache_.resource_id,
+ draw_cache_.nearest_neighbor ? GL_NEAREST : GL_LINEAR);
DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, locked_quad.texture_id()));
+ gl_->BindTexture(locked_quad.target(), locked_quad.texture_id());
- COMPILE_ASSERT(sizeof(Float4) == 4 * sizeof(float), struct_is_densely_packed);
- COMPILE_ASSERT(sizeof(Float16) == 16 * sizeof(float),
- struct_is_densely_packed);
+ static_assert(sizeof(Float4) == 4 * sizeof(float),
+ "Float4 struct should be densely packed");
+ static_assert(sizeof(Float16) == 16 * sizeof(float),
+ "Float16 struct should be densely packed");
// Upload the tranforms for both points and uvs.
- GLC(gl_,
- gl_->UniformMatrix4fv(
- static_cast<int>(draw_cache_.matrix_location),
- static_cast<int>(draw_cache_.matrix_data.size()),
- false,
- reinterpret_cast<float*>(&draw_cache_.matrix_data.front())));
- GLC(gl_,
- gl_->Uniform4fv(
- static_cast<int>(draw_cache_.uv_xform_location),
- static_cast<int>(draw_cache_.uv_xform_data.size()),
- reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front())));
+ gl_->UniformMatrix4fv(
+ static_cast<int>(draw_cache_.matrix_location),
+ static_cast<int>(draw_cache_.matrix_data.size()), false,
+ reinterpret_cast<float*>(&draw_cache_.matrix_data.front()));
+ gl_->Uniform4fv(static_cast<int>(draw_cache_.uv_xform_location),
+ static_cast<int>(draw_cache_.uv_xform_data.size()),
+ reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front()));
if (draw_cache_.background_color != SK_ColorTRANSPARENT) {
Float4 background_color = PremultipliedColor(draw_cache_.background_color);
- GLC(gl_,
- gl_->Uniform4fv(
- draw_cache_.background_color_location, 1, background_color.data));
+ gl_->Uniform4fv(draw_cache_.background_color_location, 1,
+ background_color.data);
}
- GLC(gl_,
- gl_->Uniform1fv(
- static_cast<int>(draw_cache_.vertex_opacity_location),
- static_cast<int>(draw_cache_.vertex_opacity_data.size()),
- static_cast<float*>(&draw_cache_.vertex_opacity_data.front())));
+ gl_->Uniform1fv(
+ static_cast<int>(draw_cache_.vertex_opacity_location),
+ static_cast<int>(draw_cache_.vertex_opacity_data.size()),
+ static_cast<float*>(&draw_cache_.vertex_opacity_data.front()));
// Draw the quads!
- GLC(gl_,
- gl_->DrawElements(GL_TRIANGLES,
- 6 * draw_cache_.matrix_data.size(),
- GL_UNSIGNED_SHORT,
- 0));
+ gl_->DrawElements(GL_TRIANGLES, 6 * draw_cache_.matrix_data.size(),
+ GL_UNSIGNED_SHORT, 0);
// Clear the cache.
draw_cache_.program_id = -1;
draw_cache_.uv_xform_data.resize(0);
draw_cache_.vertex_opacity_data.resize(0);
draw_cache_.matrix_data.resize(0);
+
+ // If we had a clipped binding, prepare the shared binding for the
+ // next inserts.
+ if (flush_binding == CLIPPED_BINDING) {
+ PrepareGeometry(SHARED_BINDING);
+ }
}
void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame,
- const TextureDrawQuad* quad) {
+ const TextureDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
+ // If we have a clip_region then we have to render the next quad
+ // with dynamic geometry, therefore we must flush all pending
+ // texture quads.
+ if (clip_region) {
+ // We send in false here because we want to flush what's currently in the
+ // queue using the shared_geometry and not clipped_geometry
+ FlushTextureQuadCache(SHARED_BINDING);
+ }
+
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
gl_,
&highp_threshold_cache_,
highp_threshold_min_,
quad->shared_quad_state->visible_content_rect.bottom_right());
+ ResourceProvider::ScopedReadLockGL lock(resource_provider_,
+ quad->resource_id);
+ const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target());
// Choose the correct texture program binding
TexTransformTextureProgramBinding binding;
if (quad->premultiplied_alpha) {
if (quad->background_color == SK_ColorTRANSPARENT) {
- binding.Set(GetTextureProgram(tex_coord_precision));
+ binding.Set(GetTextureProgram(tex_coord_precision, sampler));
} else {
- binding.Set(GetTextureBackgroundProgram(tex_coord_precision));
+ binding.Set(GetTextureBackgroundProgram(tex_coord_precision, sampler));
}
} else {
if (quad->background_color == SK_ColorTRANSPARENT) {
- binding.Set(GetNonPremultipliedTextureProgram(tex_coord_precision));
- } else {
binding.Set(
- GetNonPremultipliedTextureBackgroundProgram(tex_coord_precision));
+ GetNonPremultipliedTextureProgram(tex_coord_precision, sampler));
+ } else {
+ binding.Set(GetNonPremultipliedTextureBackgroundProgram(
+ tex_coord_precision, sampler));
}
}
@@ -2247,12 +2293,14 @@ void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame,
if (draw_cache_.program_id != binding.program_id ||
draw_cache_.resource_id != resource_id ||
draw_cache_.needs_blending != quad->ShouldDrawWithBlending() ||
+ draw_cache_.nearest_neighbor != quad->nearest_neighbor ||
draw_cache_.background_color != quad->background_color ||
draw_cache_.matrix_data.size() >= 8) {
- FlushTextureQuadCache();
+ FlushTextureQuadCache(SHARED_BINDING);
draw_cache_.program_id = binding.program_id;
draw_cache_.resource_id = resource_id;
draw_cache_.needs_blending = quad->ShouldDrawWithBlending();
+ draw_cache_.nearest_neighbor = quad->nearest_neighbor;
draw_cache_.background_color = quad->background_color;
draw_cache_.uv_xform_location = binding.tex_transform_location;
@@ -2263,7 +2311,12 @@ void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame,
}
// Generate the uv-transform
- draw_cache_.uv_xform_data.push_back(UVTransform(quad));
+ if (!clip_region) {
+ draw_cache_.uv_xform_data.push_back(UVTransform(quad));
+ } else {
+ Float4 uv_transform = {{0.0f, 0.0f, 1.0f, 1.0f}};
+ draw_cache_.uv_xform_data.push_back(uv_transform);
+ }
// Generate the vertex opacity
const float opacity = quad->opacity();
@@ -2280,10 +2333,32 @@ void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame,
Float16 m;
quad_rect_matrix.matrix().asColMajorf(m.data);
draw_cache_.matrix_data.push_back(m);
+
+ if (clip_region) {
+ gfx::QuadF scaled_region;
+ if (!GetScaledRegion(quad->rect, clip_region, &scaled_region)) {
+ scaled_region = SharedGeometryQuad().BoundingBox();
+ }
+ // Both the scaled region and the SharedGeomtryQuad are in the space
+ // -0.5->0.5. We need to move that to the space 0->1.
+ float uv[8];
+ uv[0] = scaled_region.p1().x() + 0.5f;
+ uv[1] = scaled_region.p1().y() + 0.5f;
+ uv[2] = scaled_region.p2().x() + 0.5f;
+ uv[3] = scaled_region.p2().y() + 0.5f;
+ uv[4] = scaled_region.p3().x() + 0.5f;
+ uv[5] = scaled_region.p3().y() + 0.5f;
+ uv[6] = scaled_region.p4().x() + 0.5f;
+ uv[7] = scaled_region.p4().y() + 0.5f;
+ PrepareGeometry(CLIPPED_BINDING);
+ clipped_geometry_->InitializeCustomQuadWithUVs(scaled_region, uv);
+ FlushTextureQuadCache(CLIPPED_BINDING);
+ }
}
void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame,
- const IOSurfaceDrawQuad* quad) {
+ const IOSurfaceDrawQuad* quad,
+ const gfx::QuadF* clip_region) {
SetBlendEnabled(quad->ShouldDrawWithBlending());
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
@@ -2296,36 +2371,37 @@ void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame,
binding.Set(GetTextureIOSurfaceProgram(tex_coord_precision));
SetUseProgram(binding.program_id);
- GLC(gl_, gl_->Uniform1i(binding.sampler_location, 0));
+ gl_->Uniform1i(binding.sampler_location, 0);
if (quad->orientation == IOSurfaceDrawQuad::FLIPPED) {
- GLC(gl_,
- gl_->Uniform4f(binding.tex_transform_location,
- 0,
- quad->io_surface_size.height(),
- quad->io_surface_size.width(),
- quad->io_surface_size.height() * -1.0f));
+ gl_->Uniform4f(
+ binding.tex_transform_location, 0, quad->io_surface_size.height(),
+ quad->io_surface_size.width(), quad->io_surface_size.height() * -1.0f);
} else {
- GLC(gl_,
- gl_->Uniform4f(binding.tex_transform_location,
- 0,
- 0,
- quad->io_surface_size.width(),
- quad->io_surface_size.height()));
+ gl_->Uniform4f(binding.tex_transform_location, 0, 0,
+ quad->io_surface_size.width(),
+ quad->io_surface_size.height());
}
const float vertex_opacity[] = {quad->opacity(), quad->opacity(),
quad->opacity(), quad->opacity()};
- GLC(gl_, gl_->Uniform1fv(binding.vertex_opacity_location, 4, vertex_opacity));
+ gl_->Uniform1fv(binding.vertex_opacity_location, 4, vertex_opacity);
ResourceProvider::ScopedReadLockGL lock(resource_provider_,
quad->io_surface_resource_id);
DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, lock.texture_id()));
+ gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, lock.texture_id());
- DrawQuadGeometry(
- frame, quad->quadTransform(), quad->rect, binding.matrix_location);
+ if (!clip_region) {
+ DrawQuadGeometry(frame, quad->quadTransform(), quad->rect,
+ binding.matrix_location);
+ } else {
+ float uvs[8] = {0};
+ GetScaledUVs(quad->visible_rect, clip_region, uvs);
+ DrawQuadGeometryClippedByQuadF(frame, quad->quadTransform(), quad->rect,
+ *clip_region, binding.matrix_location, uvs);
+ }
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, 0));
+ gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}
void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) {
@@ -2338,13 +2414,15 @@ void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) {
current_framebuffer_lock_ = nullptr;
swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame->root_damage_rect));
- GLC(gl_, gl_->Disable(GL_BLEND));
+ gl_->Disable(GL_BLEND);
blend_shadow_ = false;
ScheduleOverlays(frame);
}
-void GLRenderer::FinishDrawingQuadList() { FlushTextureQuadCache(); }
+void GLRenderer::FinishDrawingQuadList() {
+ FlushTextureQuadCache(SHARED_BINDING);
+}
bool GLRenderer::FlippedFramebuffer(const DrawingFrame* frame) const {
if (frame->current_render_pass != frame->root_render_pass)
@@ -2361,8 +2439,8 @@ void GLRenderer::EnsureScissorTestEnabled() {
if (is_scissor_enabled_)
return;
- FlushTextureQuadCache();
- GLC(gl_, gl_->Enable(GL_SCISSOR_TEST));
+ FlushTextureQuadCache(SHARED_BINDING);
+ gl_->Enable(GL_SCISSOR_TEST);
is_scissor_enabled_ = true;
}
@@ -2370,8 +2448,8 @@ void GLRenderer::EnsureScissorTestDisabled() {
if (!is_scissor_enabled_)
return;
- FlushTextureQuadCache();
- GLC(gl_, gl_->Disable(GL_SCISSOR_TEST));
+ FlushTextureQuadCache(SHARED_BINDING);
+ gl_->Disable(GL_SCISSOR_TEST);
is_scissor_enabled_ = false;
}
@@ -2402,12 +2480,12 @@ void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad, int quad_location) {
gl_quad[5] = quad.p3().y();
gl_quad[6] = quad.p4().x();
gl_quad[7] = quad.p4().y();
- GLC(gl_, gl_->Uniform2fv(quad_location, 4, gl_quad));
+ gl_->Uniform2fv(quad_location, 4, gl_quad);
}
void GLRenderer::SetShaderOpacity(float opacity, int alpha_location) {
if (alpha_location != -1)
- GLC(gl_, gl_->Uniform1f(alpha_location, opacity));
+ gl_->Uniform1f(alpha_location, opacity);
}
void GLRenderer::SetStencilEnabled(bool enabled) {
@@ -2415,9 +2493,9 @@ void GLRenderer::SetStencilEnabled(bool enabled) {
return;
if (enabled)
- GLC(gl_, gl_->Enable(GL_STENCIL_TEST));
+ gl_->Enable(GL_STENCIL_TEST);
else
- GLC(gl_, gl_->Disable(GL_STENCIL_TEST));
+ gl_->Disable(GL_STENCIL_TEST);
stencil_shadow_ = enabled;
}
@@ -2426,9 +2504,9 @@ void GLRenderer::SetBlendEnabled(bool enabled) {
return;
if (enabled)
- GLC(gl_, gl_->Enable(GL_BLEND));
+ gl_->Enable(GL_BLEND);
else
- GLC(gl_, gl_->Disable(GL_BLEND));
+ gl_->Disable(GL_BLEND);
blend_shadow_ = enabled;
}
@@ -2439,59 +2517,46 @@ void GLRenderer::SetUseProgram(unsigned program) {
program_shadow_ = program;
}
+void GLRenderer::DrawQuadGeometryClippedByQuadF(
+ const DrawingFrame* frame,
+ const gfx::Transform& draw_transform,
+ const gfx::RectF& quad_rect,
+ const gfx::QuadF& clipping_region_quad,
+ int matrix_location,
+ const float* uvs) {
+ PrepareGeometry(CLIPPED_BINDING);
+ if (uvs) {
+ clipped_geometry_->InitializeCustomQuadWithUVs(clipping_region_quad, uvs);
+ } else {
+ clipped_geometry_->InitializeCustomQuad(clipping_region_quad);
+ }
+ gfx::Transform quad_rect_matrix;
+ QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect);
+ static float gl_matrix[16];
+ ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad_rect_matrix);
+ gl_->UniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0]);
+
+ gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT,
+ reinterpret_cast<const void*>(0));
+}
+
void GLRenderer::DrawQuadGeometry(const DrawingFrame* frame,
const gfx::Transform& draw_transform,
const gfx::RectF& quad_rect,
int matrix_location) {
+ PrepareGeometry(SHARED_BINDING);
gfx::Transform quad_rect_matrix;
QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect);
static float gl_matrix[16];
ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad_rect_matrix);
- GLC(gl_, gl_->UniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0]));
-
- GLC(gl_, gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0));
-}
-
-void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame,
- int texture_id,
- const gfx::Rect& rect,
- const gfx::Transform& draw_matrix,
- bool flip_vertically) {
- TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, highp_threshold_min_, rect.bottom_right());
-
- const RenderPassProgram* program =
- GetRenderPassProgram(tex_coord_precision, BlendModeNormal);
- SetUseProgram(program->program());
-
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
+ gl_->UniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0]);
- if (flip_vertically) {
- GLC(gl_,
- gl_->Uniform4f(program->vertex_shader().tex_transform_location(),
- 0.f,
- 1.f,
- 1.f,
- -1.f));
- } else {
- GLC(gl_,
- gl_->Uniform4f(program->vertex_shader().tex_transform_location(),
- 0.f,
- 0.f,
- 1.f,
- 1.f));
- }
-
- SetShaderOpacity(1.f, program->fragment_shader().alpha_location());
- DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id));
- DrawQuadGeometry(
- frame, draw_matrix, rect, program->vertex_shader().matrix_location());
+ gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
}
void GLRenderer::Finish() {
TRACE_EVENT0("cc", "GLRenderer::Finish");
- GLC(gl_, gl_->Finish());
+ gl_->Finish();
}
void GLRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) {
@@ -2540,8 +2605,9 @@ void GLRenderer::EnforceMemoryPolicy() {
DiscardBackbuffer();
resource_provider_->ReleaseCachedData();
output_surface_->context_provider()->DeleteCachedResources();
- GLC(gl_, gl_->Flush());
+ gl_->Flush();
}
+ PrepareGeometry(NO_BINDING);
}
void GLRenderer::DiscardBackbuffer() {
@@ -2586,21 +2652,15 @@ void GLRenderer::GetFramebufferPixelsAsync(
GLuint texture_id = 0;
gpu::Mailbox mailbox;
if (own_mailbox) {
- GLC(gl_, gl_->GenMailboxCHROMIUM(mailbox.name));
+ gl_->GenMailboxCHROMIUM(mailbox.name);
gl_->GenTextures(1, &texture_id);
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id));
-
- GLC(gl_,
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
- GLC(gl_,
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
- GLC(gl_,
- gl_->TexParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- GLC(gl_,
- gl_->TexParameteri(
- GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- GLC(gl_, gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name));
+ gl_->BindTexture(GL_TEXTURE_2D, texture_id);
+
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
} else {
mailbox = request->texture_mailbox().mailbox();
DCHECK_EQ(static_cast<unsigned>(GL_TEXTURE_2D),
@@ -2608,11 +2668,10 @@ void GLRenderer::GetFramebufferPixelsAsync(
DCHECK(!mailbox.IsZero());
unsigned incoming_sync_point = request->texture_mailbox().sync_point();
if (incoming_sync_point)
- GLC(gl_, gl_->WaitSyncPointCHROMIUM(incoming_sync_point));
+ gl_->WaitSyncPointCHROMIUM(incoming_sync_point);
- texture_id = GLC(
- gl_,
- gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name));
+ texture_id =
+ gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
}
GetFramebufferTexture(texture_id, RGBA_8888, window_rect);
@@ -2621,7 +2680,7 @@ void GLRenderer::GetFramebufferPixelsAsync(
scoped_ptr<SingleReleaseCallback> release_callback;
if (own_mailbox) {
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, 0));
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
release_callback = texture_mailbox_deleter_->GetReleaseCallback(
output_surface_->context_provider(), texture_id);
} else {
@@ -2653,28 +2712,20 @@ void GLRenderer::GetFramebufferPixelsAsync(
// http://crbug.com/99393. <rdar://problem/10949687>
gl_->GenTextures(1, &temporary_texture);
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, temporary_texture));
- GLC(gl_,
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
- GLC(gl_,
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
- GLC(gl_,
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- GLC(gl_,
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+ gl_->BindTexture(GL_TEXTURE_2D, temporary_texture);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Copy the contents of the current (IOSurface-backed) framebuffer into a
// temporary texture.
GetFramebufferTexture(
temporary_texture, RGBA_8888, gfx::Rect(current_surface_size_));
gl_->GenFramebuffers(1, &temporary_fbo);
// Attach this texture to an FBO, and perform the readback from that FBO.
- GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, temporary_fbo));
- GLC(gl_,
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- temporary_texture,
- 0));
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, temporary_fbo);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, temporary_texture, 0);
DCHECK_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE),
gl_->CheckFramebufferStatus(GL_FRAMEBUFFER));
@@ -2682,34 +2733,25 @@ void GLRenderer::GetFramebufferPixelsAsync(
GLuint buffer = 0;
gl_->GenBuffers(1, &buffer);
- GLC(gl_, gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, buffer));
- GLC(gl_,
- gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- 4 * window_rect.size().GetArea(),
- NULL,
- GL_STREAM_READ));
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, buffer);
+ gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ 4 * window_rect.size().GetArea(), NULL, GL_STREAM_READ);
GLuint query = 0;
gl_->GenQueriesEXT(1, &query);
- GLC(gl_, gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, query));
+ gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, query);
- GLC(gl_,
- gl_->ReadPixels(window_rect.x(),
- window_rect.y(),
- window_rect.width(),
- window_rect.height(),
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- NULL));
+ gl_->ReadPixels(window_rect.x(), window_rect.y(), window_rect.width(),
+ window_rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- GLC(gl_, gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0));
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
if (do_workaround) {
// Clean up.
- GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, 0));
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, 0));
- GLC(gl_, gl_->DeleteFramebuffers(1, &temporary_fbo));
- GLC(gl_, gl_->DeleteTextures(1, &temporary_texture));
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
+ gl_->DeleteFramebuffers(1, &temporary_fbo);
+ gl_->DeleteTextures(1, &temporary_texture);
}
base::Closure finished_callback = base::Bind(&GLRenderer::FinishedReadback,
@@ -2727,7 +2769,7 @@ void GLRenderer::GetFramebufferPixelsAsync(
// Save the buffer to verify the callbacks happen in the expected order.
pending_async_read_pixels_.front()->buffer = buffer;
- GLC(gl_, gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM));
+ gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
context_support_->SignalQuery(query, cancelable_callback);
EnforceMemoryPolicy();
@@ -2739,7 +2781,7 @@ void GLRenderer::FinishedReadback(unsigned source_buffer,
DCHECK(!pending_async_read_pixels_.empty());
if (query != 0) {
- GLC(gl_, gl_->DeleteQueriesEXT(1, &query));
+ gl_->DeleteQueriesEXT(1, &query);
}
PendingAsyncReadPixels* current_read = pending_async_read_pixels_.back();
@@ -2750,8 +2792,7 @@ void GLRenderer::FinishedReadback(unsigned source_buffer,
scoped_ptr<SkBitmap> bitmap;
if (source_buffer != 0) {
- GLC(gl_,
- gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, source_buffer));
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, source_buffer);
src_pixels = static_cast<uint8*>(gl_->MapBufferCHROMIUM(
GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
@@ -2780,11 +2821,10 @@ void GLRenderer::FinishedReadback(unsigned source_buffer,
}
}
- GLC(gl_,
- gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM));
+ gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
}
- GLC(gl_, gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0));
- GLC(gl_, gl_->DeleteBuffers(1, &source_buffer));
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ gl_->DeleteBuffers(1, &source_buffer);
}
if (bitmap)
@@ -2801,17 +2841,11 @@ void GLRenderer::GetFramebufferTexture(unsigned texture_id,
DCHECK_LE(window_rect.right(), current_surface_size_.width());
DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id));
- GLC(gl_,
- gl_->CopyTexImage2D(GL_TEXTURE_2D,
- 0,
- GLDataFormat(texture_format),
- window_rect.x(),
- window_rect.y(),
- window_rect.width(),
- window_rect.height(),
- 0));
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, 0));
+ gl_->BindTexture(GL_TEXTURE_2D, texture_id);
+ gl_->CopyTexImage2D(GL_TEXTURE_2D, 0, GLDataFormat(texture_format),
+ window_rect.x(), window_rect.y(), window_rect.width(),
+ window_rect.height(), 0);
+ gl_->BindTexture(GL_TEXTURE_2D, 0);
}
bool GLRenderer::UseScopedTexture(DrawingFrame* frame,
@@ -2830,7 +2864,7 @@ void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
if (output_surface_->HasExternalStencilTest()) {
SetStencilEnabled(true);
- GLC(gl_, gl_->StencilFunc(GL_EQUAL, 1, 1));
+ gl_->StencilFunc(GL_EQUAL, 1, 1);
} else {
SetStencilEnabled(false);
}
@@ -2841,24 +2875,22 @@ bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
const gfx::Rect& target_rect) {
DCHECK(texture->id());
+ // Explicitly release lock, otherwise we can crash when try to lock
+ // same texture again.
current_framebuffer_lock_ = nullptr;
SetStencilEnabled(false);
- GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_));
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_);
current_framebuffer_lock_ =
make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL(
resource_provider_, texture->id()));
unsigned texture_id = current_framebuffer_lock_->texture_id();
- GLC(gl_,
- gl_->FramebufferTexture2D(
- GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0));
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ texture_id, 0);
DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) ==
GL_FRAMEBUFFER_COMPLETE ||
IsContextLost());
-
- InitializeViewport(
- frame, target_rect, gfx::Rect(target_rect.size()), target_rect.size());
return true;
}
@@ -2871,33 +2903,47 @@ void GLRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
return;
scissor_rect_ = scissor_rect;
- FlushTextureQuadCache();
- GLC(gl_,
- gl_->Scissor(scissor_rect.x(),
- scissor_rect.y(),
- scissor_rect.width(),
- scissor_rect.height()));
+ FlushTextureQuadCache(SHARED_BINDING);
+ gl_->Scissor(scissor_rect.x(), scissor_rect.y(), scissor_rect.width(),
+ scissor_rect.height());
scissor_rect_needs_reset_ = false;
}
-void GLRenderer::SetDrawViewport(const gfx::Rect& window_space_viewport) {
- viewport_ = window_space_viewport;
- GLC(gl_,
- gl_->Viewport(window_space_viewport.x(),
- window_space_viewport.y(),
- window_space_viewport.width(),
- window_space_viewport.height()));
+void GLRenderer::SetViewport() {
+ gl_->Viewport(current_window_space_viewport_.x(),
+ current_window_space_viewport_.y(),
+ current_window_space_viewport_.width(),
+ current_window_space_viewport_.height());
}
void GLRenderer::InitializeSharedObjects() {
TRACE_EVENT0("cc", "GLRenderer::InitializeSharedObjects");
// Create an FBO for doing offscreen rendering.
- GLC(gl_, gl_->GenFramebuffers(1, &offscreen_framebuffer_id_));
+ gl_->GenFramebuffers(1, &offscreen_framebuffer_id_);
+
+ shared_geometry_ =
+ make_scoped_ptr(new StaticGeometryBinding(gl_, QuadVertexRect()));
+ clipped_geometry_ = make_scoped_ptr(new DynamicGeometryBinding(gl_));
+}
- shared_geometry_ = make_scoped_ptr(
- new GeometryBinding(gl_, QuadVertexRect()));
+void GLRenderer::PrepareGeometry(BoundGeometry binding) {
+ if (binding == bound_geometry_) {
+ return;
+ }
+
+ switch (binding) {
+ case SHARED_BINDING:
+ shared_geometry_->PrepareForDraw();
+ break;
+ case CLIPPED_BINDING:
+ clipped_geometry_->PrepareForDraw();
+ break;
+ case NO_BINDING:
+ break;
+ }
+ bound_geometry_ = binding;
}
const GLRenderer::TileCheckerboardProgram*
@@ -2905,8 +2951,8 @@ GLRenderer::GetTileCheckerboardProgram() {
if (!tile_checkerboard_program_.initialized()) {
TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize");
tile_checkerboard_program_.Initialize(output_surface_->context_provider(),
- TexCoordPrecisionNA,
- SamplerTypeNA);
+ TEX_COORD_PRECISION_NA,
+ SAMPLER_TYPE_NA);
}
return &tile_checkerboard_program_;
}
@@ -2915,8 +2961,7 @@ const GLRenderer::DebugBorderProgram* GLRenderer::GetDebugBorderProgram() {
if (!debug_border_program_.initialized()) {
TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize");
debug_border_program_.Initialize(output_surface_->context_provider(),
- TexCoordPrecisionNA,
- SamplerTypeNA);
+ TEX_COORD_PRECISION_NA, SAMPLER_TYPE_NA);
}
return &debug_border_program_;
}
@@ -2925,8 +2970,7 @@ const GLRenderer::SolidColorProgram* GLRenderer::GetSolidColorProgram() {
if (!solid_color_program_.initialized()) {
TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize");
solid_color_program_.Initialize(output_surface_->context_provider(),
- TexCoordPrecisionNA,
- SamplerTypeNA);
+ TEX_COORD_PRECISION_NA, SAMPLER_TYPE_NA);
}
return &solid_color_program_;
}
@@ -2935,8 +2979,7 @@ const GLRenderer::SolidColorProgramAA* GLRenderer::GetSolidColorProgramAA() {
if (!solid_color_program_aa_.initialized()) {
TRACE_EVENT0("cc", "GLRenderer::solidColorProgramAA::initialize");
solid_color_program_aa_.Initialize(output_surface_->context_provider(),
- TexCoordPrecisionNA,
- SamplerTypeNA);
+ TEX_COORD_PRECISION_NA, SAMPLER_TYPE_NA);
}
return &solid_color_program_aa_;
}
@@ -2945,16 +2988,14 @@ const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram(
TexCoordPrecision precision,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassProgram* program = &render_pass_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize");
- program->Initialize(output_surface_->context_provider(),
- precision,
- SamplerType2D,
- blend_mode);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D, blend_mode);
}
return program;
}
@@ -2963,17 +3004,15 @@ const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA(
TexCoordPrecision precision,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassProgramAA* program =
&render_pass_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize");
- program->Initialize(output_surface_->context_provider(),
- precision,
- SamplerType2D,
- blend_mode);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D, blend_mode);
}
return program;
}
@@ -2981,19 +3020,22 @@ const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA(
const GLRenderer::RenderPassMaskProgram* GLRenderer::GetRenderPassMaskProgram(
TexCoordPrecision precision,
SamplerType sampler,
- BlendMode blend_mode) {
+ BlendMode blend_mode,
+ bool mask_for_background) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassMaskProgram* program =
- &render_pass_mask_program_[precision][sampler][blend_mode];
+ &render_pass_mask_program_[precision][sampler][blend_mode]
+ [mask_for_background ? HAS_MASK : NO_MASK];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize");
program->Initialize(
- output_surface_->context_provider(), precision, sampler, blend_mode);
+ output_surface_->context_provider(), precision,
+ sampler, blend_mode, mask_for_background);
}
return program;
}
@@ -3001,19 +3043,22 @@ const GLRenderer::RenderPassMaskProgram* GLRenderer::GetRenderPassMaskProgram(
const GLRenderer::RenderPassMaskProgramAA*
GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision,
SamplerType sampler,
- BlendMode blend_mode) {
+ BlendMode blend_mode,
+ bool mask_for_background) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassMaskProgramAA* program =
- &render_pass_mask_program_aa_[precision][sampler][blend_mode];
+ &render_pass_mask_program_aa_[precision][sampler][blend_mode]
+ [mask_for_background ? HAS_MASK : NO_MASK];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize");
program->Initialize(
- output_surface_->context_provider(), precision, sampler, blend_mode);
+ output_surface_->context_provider(), precision,
+ sampler, blend_mode, mask_for_background);
}
return program;
}
@@ -3022,17 +3067,15 @@ const GLRenderer::RenderPassColorMatrixProgram*
GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassColorMatrixProgram* program =
&render_pass_color_matrix_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgram::initialize");
- program->Initialize(output_surface_->context_provider(),
- precision,
- SamplerType2D,
- blend_mode);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D, blend_mode);
}
return program;
}
@@ -3041,61 +3084,66 @@ const GLRenderer::RenderPassColorMatrixProgramAA*
GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassColorMatrixProgramAA* program =
&render_pass_color_matrix_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::renderPassColorMatrixProgramAA::initialize");
- program->Initialize(output_surface_->context_provider(),
- precision,
- SamplerType2D,
- blend_mode);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D, blend_mode);
}
return program;
}
const GLRenderer::RenderPassMaskColorMatrixProgram*
-GLRenderer::GetRenderPassMaskColorMatrixProgram(TexCoordPrecision precision,
- SamplerType sampler,
- BlendMode blend_mode) {
+GLRenderer::GetRenderPassMaskColorMatrixProgram(
+ TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode,
+ bool mask_for_background) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassMaskColorMatrixProgram* program =
- &render_pass_mask_color_matrix_program_[precision][sampler][blend_mode];
+ &render_pass_mask_color_matrix_program_[precision][sampler][blend_mode]
+ [mask_for_background ? HAS_MASK : NO_MASK];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::renderPassMaskColorMatrixProgram::initialize");
program->Initialize(
- output_surface_->context_provider(), precision, sampler, blend_mode);
+ output_surface_->context_provider(), precision,
+ sampler, blend_mode, mask_for_background);
}
return program;
}
const GLRenderer::RenderPassMaskColorMatrixProgramAA*
-GLRenderer::GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
- SamplerType sampler,
- BlendMode blend_mode) {
+GLRenderer::GetRenderPassMaskColorMatrixProgramAA(
+ TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode,
+ bool mask_for_background) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassMaskColorMatrixProgramAA* program =
- &render_pass_mask_color_matrix_program_aa_[precision][sampler]
- [blend_mode];
+ &render_pass_mask_color_matrix_program_aa_[precision][sampler][blend_mode]
+ [mask_for_background ? HAS_MASK : NO_MASK];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::renderPassMaskColorMatrixProgramAA::initialize");
program->Initialize(
- output_surface_->context_provider(), precision, sampler, blend_mode);
+ output_surface_->context_provider(), precision,
+ sampler, blend_mode, mask_for_background);
}
return program;
}
@@ -3104,9 +3152,9 @@ const GLRenderer::TileProgram* GLRenderer::GetTileProgram(
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgram* program = &tile_program_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize");
@@ -3120,9 +3168,9 @@ const GLRenderer::TileProgramOpaque* GLRenderer::GetTileProgramOpaque(
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramOpaque* program = &tile_program_opaque_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize");
@@ -3136,9 +3184,9 @@ const GLRenderer::TileProgramAA* GLRenderer::GetTileProgramAA(
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramAA* program = &tile_program_aa_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize");
@@ -3152,9 +3200,9 @@ const GLRenderer::TileProgramSwizzle* GLRenderer::GetTileProgramSwizzle(
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramSwizzle* program = &tile_program_swizzle_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize");
@@ -3168,9 +3216,9 @@ const GLRenderer::TileProgramSwizzleOpaque*
GLRenderer::GetTileProgramSwizzleOpaque(TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramSwizzleOpaque* program =
&tile_program_swizzle_opaque_[precision][sampler];
if (!program->initialized()) {
@@ -3185,9 +3233,9 @@ const GLRenderer::TileProgramSwizzleAA* GLRenderer::GetTileProgramSwizzleAA(
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramSwizzleAA* program = &tile_program_swizzle_aa_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize");
@@ -3198,58 +3246,71 @@ const GLRenderer::TileProgramSwizzleAA* GLRenderer::GetTileProgramSwizzleAA(
}
const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
- TextureProgram* program = &texture_program_[precision];
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
+ DCHECK_GE(sampler, 0);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
+ TextureProgram* program = &texture_program_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ sampler);
}
return program;
}
const GLRenderer::NonPremultipliedTextureProgram*
-GLRenderer::GetNonPremultipliedTextureProgram(TexCoordPrecision precision) {
+GLRenderer::GetNonPremultipliedTextureProgram(TexCoordPrecision precision,
+ SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
+ DCHECK_GE(sampler, 0);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
NonPremultipliedTextureProgram* program =
- &nonpremultiplied_texture_program_[precision];
+ &nonpremultiplied_texture_program_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::NonPremultipliedTextureProgram::Initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ sampler);
}
return program;
}
const GLRenderer::TextureBackgroundProgram*
-GLRenderer::GetTextureBackgroundProgram(TexCoordPrecision precision) {
+GLRenderer::GetTextureBackgroundProgram(TexCoordPrecision precision,
+ SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
- TextureBackgroundProgram* program = &texture_background_program_[precision];
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
+ DCHECK_GE(sampler, 0);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
+ TextureBackgroundProgram* program =
+ &texture_background_program_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ sampler);
}
return program;
}
const GLRenderer::NonPremultipliedTextureBackgroundProgram*
GLRenderer::GetNonPremultipliedTextureBackgroundProgram(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
+ DCHECK_GE(sampler, 0);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
NonPremultipliedTextureBackgroundProgram* program =
- &nonpremultiplied_texture_background_program_[precision];
+ &nonpremultiplied_texture_background_program_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::NonPremultipliedTextureProgram::Initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ sampler);
}
return program;
}
@@ -3257,38 +3318,44 @@ GLRenderer::GetNonPremultipliedTextureBackgroundProgram(
const GLRenderer::TextureProgram* GLRenderer::GetTextureIOSurfaceProgram(
TexCoordPrecision precision) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
TextureProgram* program = &texture_io_surface_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2DRect);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D_RECT);
}
return program;
}
const GLRenderer::VideoYUVProgram* GLRenderer::GetVideoYUVProgram(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
- VideoYUVProgram* program = &video_yuv_program_[precision];
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
+ DCHECK_GE(sampler, 0);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
+ VideoYUVProgram* program = &video_yuv_program_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ sampler);
}
return program;
}
const GLRenderer::VideoYUVAProgram* GLRenderer::GetVideoYUVAProgram(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
- VideoYUVAProgram* program = &video_yuva_program_[precision];
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
+ DCHECK_GE(sampler, 0);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
+ VideoYUVAProgram* program = &video_yuva_program_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::videoYUVAProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ sampler);
}
return program;
}
@@ -3298,13 +3365,13 @@ GLRenderer::GetVideoStreamTextureProgram(TexCoordPrecision precision) {
if (!Capabilities().using_egl_image)
return NULL;
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
VideoStreamTextureProgram* program =
&video_stream_texture_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerTypeExternalOES);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_EXTERNAL_OES);
}
return program;
}
@@ -3312,8 +3379,8 @@ GLRenderer::GetVideoStreamTextureProgram(TexCoordPrecision precision) {
void GLRenderer::CleanupSharedObjects() {
shared_geometry_ = nullptr;
- for (int i = 0; i < NumTexCoordPrecisions; ++i) {
- for (int j = 0; j < NumSamplerTypes; ++j) {
+ for (int i = 0; i <= LAST_TEX_COORD_PRECISION; ++i) {
+ for (int j = 0; j <= LAST_SAMPLER_TYPE; ++j) {
tile_program_[i][j].Cleanup(gl_);
tile_program_opaque_[i][j].Cleanup(gl_);
tile_program_swizzle_[i][j].Cleanup(gl_);
@@ -3321,28 +3388,33 @@ void GLRenderer::CleanupSharedObjects() {
tile_program_aa_[i][j].Cleanup(gl_);
tile_program_swizzle_aa_[i][j].Cleanup(gl_);
- for (int k = 0; k < NumBlendModes; k++) {
- render_pass_mask_program_[i][j][k].Cleanup(gl_);
- render_pass_mask_program_aa_[i][j][k].Cleanup(gl_);
- render_pass_mask_color_matrix_program_aa_[i][j][k].Cleanup(gl_);
- render_pass_mask_color_matrix_program_[i][j][k].Cleanup(gl_);
+ for (int k = 0; k <= LAST_BLEND_MODE; k++) {
+ for (int l = 0; l <= LAST_MASK_VALUE; ++l) {
+ render_pass_mask_program_[i][j][k][l].Cleanup(gl_);
+ render_pass_mask_program_aa_[i][j][k][l].Cleanup(gl_);
+ render_pass_mask_color_matrix_program_aa_[i][j][k][l].Cleanup(gl_);
+ render_pass_mask_color_matrix_program_[i][j][k][l].Cleanup(gl_);
+ }
}
+
+ video_yuv_program_[i][j].Cleanup(gl_);
+ video_yuva_program_[i][j].Cleanup(gl_);
}
- for (int j = 0; j < NumBlendModes; j++) {
+ for (int j = 0; j <= LAST_BLEND_MODE; j++) {
render_pass_program_[i][j].Cleanup(gl_);
render_pass_program_aa_[i][j].Cleanup(gl_);
render_pass_color_matrix_program_[i][j].Cleanup(gl_);
render_pass_color_matrix_program_aa_[i][j].Cleanup(gl_);
}
- texture_program_[i].Cleanup(gl_);
- nonpremultiplied_texture_program_[i].Cleanup(gl_);
- texture_background_program_[i].Cleanup(gl_);
- nonpremultiplied_texture_background_program_[i].Cleanup(gl_);
+ for (int j = 0; j <= LAST_SAMPLER_TYPE; ++j) {
+ texture_program_[i][j].Cleanup(gl_);
+ nonpremultiplied_texture_program_[i][j].Cleanup(gl_);
+ texture_background_program_[i][j].Cleanup(gl_);
+ nonpremultiplied_texture_background_program_[i][j].Cleanup(gl_);
+ }
texture_io_surface_program_[i].Cleanup(gl_);
- video_yuv_program_[i].Cleanup(gl_);
- video_yuva_program_[i].Cleanup(gl_);
video_stream_texture_program_[i].Cleanup(gl_);
}
@@ -3353,7 +3425,7 @@ void GLRenderer::CleanupSharedObjects() {
solid_color_program_aa_.Cleanup(gl_);
if (offscreen_framebuffer_id_)
- GLC(gl_, gl_->DeleteFramebuffers(1, &offscreen_framebuffer_id_));
+ gl_->DeleteFramebuffers(1, &offscreen_framebuffer_id_);
if (on_demand_tile_raster_resource_id_)
resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
@@ -3373,42 +3445,44 @@ void GLRenderer::ReinitializeGLState() {
void GLRenderer::RestoreGLState() {
// This restores the current GLRenderer state to the GL context.
+ bound_geometry_ = NO_BINDING;
+ PrepareGeometry(SHARED_BINDING);
- shared_geometry_->PrepareForDraw();
-
- GLC(gl_, gl_->Disable(GL_DEPTH_TEST));
- GLC(gl_, gl_->Disable(GL_CULL_FACE));
- GLC(gl_, gl_->ColorMask(true, true, true, true));
- GLC(gl_, gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
- GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0));
+ gl_->Disable(GL_DEPTH_TEST);
+ gl_->Disable(GL_CULL_FACE);
+ gl_->ColorMask(true, true, true, true);
+ gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ gl_->ActiveTexture(GL_TEXTURE0);
if (program_shadow_)
gl_->UseProgram(program_shadow_);
if (stencil_shadow_)
- GLC(gl_, gl_->Enable(GL_STENCIL_TEST));
+ gl_->Enable(GL_STENCIL_TEST);
else
- GLC(gl_, gl_->Disable(GL_STENCIL_TEST));
+ gl_->Disable(GL_STENCIL_TEST);
if (blend_shadow_)
- GLC(gl_, gl_->Enable(GL_BLEND));
+ gl_->Enable(GL_BLEND);
else
- GLC(gl_, gl_->Disable(GL_BLEND));
+ gl_->Disable(GL_BLEND);
if (is_scissor_enabled_) {
- GLC(gl_, gl_->Enable(GL_SCISSOR_TEST));
- GLC(gl_,
- gl_->Scissor(scissor_rect_.x(),
- scissor_rect_.y(),
- scissor_rect_.width(),
- scissor_rect_.height()));
+ gl_->Enable(GL_SCISSOR_TEST);
+ gl_->Scissor(scissor_rect_.x(), scissor_rect_.y(), scissor_rect_.width(),
+ scissor_rect_.height());
} else {
- GLC(gl_, gl_->Disable(GL_SCISSOR_TEST));
+ gl_->Disable(GL_SCISSOR_TEST);
}
}
void GLRenderer::RestoreFramebuffer(DrawingFrame* frame) {
UseRenderPass(frame, frame->current_render_pass);
+
+ // Call SetViewport directly, rather than through PrepareSurfaceForPass.
+ // PrepareSurfaceForPass also clears the surface, which is not desired when
+ // restoring.
+ SetViewport();
}
bool GLRenderer::IsContextLost() {
@@ -3421,9 +3495,7 @@ void GLRenderer::ScheduleOverlays(DrawingFrame* frame) {
ResourceProvider::ResourceIdArray resources;
OverlayCandidateList& overlays = frame->overlay_list;
- OverlayCandidateList::iterator it;
- for (it = overlays.begin(); it != overlays.end(); ++it) {
- const OverlayCandidate& overlay = *it;
+ for (const OverlayCandidate& overlay : overlays) {
// Skip primary plane.
if (overlay.plane_z_order == 0)
continue;
@@ -3436,7 +3508,7 @@ void GLRenderer::ScheduleOverlays(DrawingFrame* frame) {
overlay.plane_z_order,
overlay.transform,
pending_overlay_resources_.back()->texture_id(),
- overlay.display_rect,
+ ToNearestRect(overlay.display_rect),
overlay.uv_rect);
}
}
diff --git a/chromium/cc/output/gl_renderer.h b/chromium/cc/output/gl_renderer.h
index 4930204eb4c..324a7bd16e4 100644
--- a/chromium/cc/output/gl_renderer.h
+++ b/chromium/cc/output/gl_renderer.h
@@ -39,7 +39,8 @@ class ScopedResource;
class StreamVideoDrawQuad;
class TextureDrawQuad;
class TextureMailboxDeleter;
-class GeometryBinding;
+class StaticGeometryBinding;
+class DynamicGeometryBinding;
class ScopedEnsureFramebufferAllocation;
// Class that handles drawing of composited render layers using GL.
@@ -49,7 +50,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
static scoped_ptr<GLRenderer> Create(
RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider,
TextureMailboxDeleter* texture_mailbox_deleter,
@@ -67,14 +68,9 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
virtual bool IsContextLost();
- static void DebugGLCall(gpu::gles2::GLES2Interface* gl,
- const char* command,
- const char* file,
- int line);
-
protected:
GLRenderer(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider,
TextureMailboxDeleter* texture_mailbox_deleter,
@@ -85,7 +81,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
bool IsBackbufferDiscarded() const { return is_backbuffer_discarded_; }
const gfx::QuadF& SharedGeometryQuad() const { return shared_geometry_quad_; }
- const GeometryBinding* SharedGeometry() const {
+ const StaticGeometryBinding* SharedGeometry() const {
return shared_geometry_.get();
}
@@ -96,7 +92,8 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
ResourceFormat texture_format,
const gfx::Rect& device_rect);
void ReleaseRenderPassTextures();
-
+ enum BoundGeometry { NO_BINDING, SHARED_BINDING, CLIPPED_BINDING };
+ void PrepareGeometry(BoundGeometry geometry_to_bind);
void SetStencilEnabled(bool enabled);
bool stencil_enabled() const { return stencil_shadow_; }
void SetBlendEnabled(bool enabled);
@@ -106,13 +103,13 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
bool BindFramebufferToTexture(DrawingFrame* frame,
const ScopedResource* resource,
const gfx::Rect& target_rect) override;
- void SetDrawViewport(const gfx::Rect& window_space_viewport) override;
void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
- void DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) override;
- void ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) override;
- void DoDrawQuad(DrawingFrame* frame, const class DrawQuad*) override;
+ void PrepareSurfaceForPass(DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) override;
+ void DoDrawQuad(DrawingFrame* frame,
+ const class DrawQuad*,
+ const gfx::QuadF* draw_region) override;
void BeginDrawingFrame(DrawingFrame* frame) override;
void FinishDrawingFrame(DrawingFrame* frame) override;
bool FlippedFramebuffer(const DrawingFrame* frame) const override;
@@ -132,10 +129,13 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
// Inflate the quad and fill edge array for fragment shader.
// |local_quad| is set to inflated quad. |edge| array is filled with
// inflated quad's edge data.
- static void SetupQuadForAntialiasing(const gfx::Transform& device_transform,
- const DrawQuad* quad,
- gfx::QuadF* local_quad,
- float edge[24]);
+ static void SetupQuadForClippingAndAntialiasing(
+ const gfx::Transform& device_transform,
+ const DrawQuad* quad,
+ bool use_aa,
+ const gfx::QuadF* clip_region,
+ gfx::QuadF* local_quad,
+ float edge[24]);
private:
friend class GLRendererShaderPixelTest;
@@ -143,8 +143,13 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
static void ToGLMatrix(float* gl_matrix, const gfx::Transform& transform);
+ void DiscardPixels();
+ void ClearFramebuffer(DrawingFrame* frame);
+ void SetViewport();
+
void DrawCheckerboardQuad(const DrawingFrame* frame,
- const CheckerboardDrawQuad* quad);
+ const CheckerboardDrawQuad* quad,
+ const gfx::QuadF* clip_region);
void DrawDebugBorderQuad(const DrawingFrame* frame,
const DebugBorderDrawQuad* quad);
static bool IsDefaultBlendMode(SkXfermode::Mode blend_mode) {
@@ -158,6 +163,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform,
+ const gfx::QuadF* clip_region,
bool use_aa);
scoped_ptr<ScopedResource> GetBackdropTexture(const gfx::Rect& bounding_rect);
@@ -167,53 +173,63 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
ScopedResource* background_texture);
- scoped_ptr<ScopedResource> ApplyInverseTransformForBackgroundFilters(
- DrawingFrame* frame,
- const RenderPassDrawQuad* quad,
- const gfx::Transform& contents_device_transform,
- skia::RefPtr<SkImage> backdrop_bitmap,
- const gfx::Rect& backdrop_bounding_rect);
- void DrawRenderPassQuad(DrawingFrame* frame, const RenderPassDrawQuad* quad);
+ void DrawRenderPassQuad(DrawingFrame* frame,
+ const RenderPassDrawQuad* quadi,
+ const gfx::QuadF* clip_region);
void DrawSolidColorQuad(const DrawingFrame* frame,
- const SolidColorDrawQuad* quad);
+ const SolidColorDrawQuad* quad,
+ const gfx::QuadF* clip_region);
void DrawStreamVideoQuad(const DrawingFrame* frame,
- const StreamVideoDrawQuad* quad);
+ const StreamVideoDrawQuad* quad,
+ const gfx::QuadF* clip_region);
+ void DrawTextureQuad(const DrawingFrame* frame,
+ const TextureDrawQuad* quad,
+ const gfx::QuadF* clip_region);
void EnqueueTextureQuad(const DrawingFrame* frame,
- const TextureDrawQuad* quad);
- void FlushTextureQuadCache();
+ const TextureDrawQuad* quad,
+ const gfx::QuadF* clip_region);
+ void FlushTextureQuadCache(BoundGeometry flush_binding);
void DrawIOSurfaceQuad(const DrawingFrame* frame,
- const IOSurfaceDrawQuad* quad);
- void DrawTileQuad(const DrawingFrame* frame, const TileDrawQuad* quad);
+ const IOSurfaceDrawQuad* quad,
+ const gfx::QuadF* clip_region);
+ void DrawTileQuad(const DrawingFrame* frame,
+ const TileDrawQuad* quad,
+ const gfx::QuadF* clip_region);
void DrawContentQuad(const DrawingFrame* frame,
const ContentDrawQuadBase* quad,
- ResourceProvider::ResourceId resource_id);
+ ResourceProvider::ResourceId resource_id,
+ const gfx::QuadF* clip_region);
void DrawContentQuadAA(const DrawingFrame* frame,
const ContentDrawQuadBase* quad,
ResourceProvider::ResourceId resource_id,
- const gfx::Transform& device_transform);
+ const gfx::Transform& device_transform,
+ const gfx::QuadF* clip_region);
void DrawContentQuadNoAA(const DrawingFrame* frame,
const ContentDrawQuadBase* quad,
- ResourceProvider::ResourceId resource_id);
+ ResourceProvider::ResourceId resource_id,
+ const gfx::QuadF* clip_region);
void DrawYUVVideoQuad(const DrawingFrame* frame,
- const YUVVideoDrawQuad* quad);
+ const YUVVideoDrawQuad* quad,
+ const gfx::QuadF* clip_region);
void DrawPictureQuad(const DrawingFrame* frame,
- const PictureDrawQuad* quad);
+ const PictureDrawQuad* quad,
+ const gfx::QuadF* clip_region);
void SetShaderOpacity(float opacity, int alpha_location);
void SetShaderQuadF(const gfx::QuadF& quad, int quad_location);
+ void DrawQuadGeometryClippedByQuadF(const DrawingFrame* frame,
+ const gfx::Transform& draw_transform,
+ const gfx::RectF& quad_rect,
+ const gfx::QuadF& clipping_region_quad,
+ int matrix_location,
+ const float uv[8]);
void DrawQuadGeometry(const DrawingFrame* frame,
const gfx::Transform& draw_transform,
const gfx::RectF& quad_rect,
int matrix_location);
void SetUseProgram(unsigned program);
- void CopyTextureToFramebuffer(const DrawingFrame* frame,
- int texture_id,
- const gfx::Rect& rect,
- const gfx::Transform& draw_matrix,
- bool flip_vertically);
-
bool UseScopedTexture(DrawingFrame* frame,
const ScopedResource* resource,
const gfx::Rect& viewport_rect);
@@ -249,7 +265,8 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
unsigned offscreen_framebuffer_id_;
- scoped_ptr<GeometryBinding> shared_geometry_;
+ scoped_ptr<StaticGeometryBinding> shared_geometry_;
+ scoped_ptr<DynamicGeometryBinding> clipped_geometry_;
gfx::QuadF shared_geometry_quad_;
// This block of bindings defines all of the programs used by the compositor
@@ -346,11 +363,13 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
const RenderPassMaskProgram* GetRenderPassMaskProgram(
TexCoordPrecision precision,
SamplerType sampler,
- BlendMode blend_mode);
+ BlendMode blend_mode,
+ bool mask_for_background);
const RenderPassMaskProgramAA* GetRenderPassMaskProgramAA(
TexCoordPrecision precision,
SamplerType sampler,
- BlendMode blend_mode);
+ BlendMode blend_mode,
+ bool mask_for_background);
const RenderPassColorMatrixProgram* GetRenderPassColorMatrixProgram(
TexCoordPrecision precision,
BlendMode blend_mode);
@@ -360,27 +379,32 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
const RenderPassMaskColorMatrixProgram* GetRenderPassMaskColorMatrixProgram(
TexCoordPrecision precision,
SamplerType sampler,
- BlendMode blend_mode);
+ BlendMode blend_mode,
+ bool mask_for_background);
const RenderPassMaskColorMatrixProgramAA*
GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
SamplerType sampler,
- BlendMode blend_mode);
+ BlendMode blend_mode,
+ bool mask_for_background);
- const TextureProgram* GetTextureProgram(
- TexCoordPrecision precision);
+ const TextureProgram* GetTextureProgram(TexCoordPrecision precision,
+ SamplerType sampler);
const NonPremultipliedTextureProgram* GetNonPremultipliedTextureProgram(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ SamplerType sampler);
const TextureBackgroundProgram* GetTextureBackgroundProgram(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ SamplerType sampler);
const NonPremultipliedTextureBackgroundProgram*
- GetNonPremultipliedTextureBackgroundProgram(TexCoordPrecision precision);
+ GetNonPremultipliedTextureBackgroundProgram(TexCoordPrecision precision,
+ SamplerType sampler);
const TextureProgram* GetTextureIOSurfaceProgram(
TexCoordPrecision precision);
- const VideoYUVProgram* GetVideoYUVProgram(
- TexCoordPrecision precision);
- const VideoYUVAProgram* GetVideoYUVAProgram(
- TexCoordPrecision precision);
+ const VideoYUVProgram* GetVideoYUVProgram(TexCoordPrecision precision,
+ SamplerType sampler);
+ const VideoYUVAProgram* GetVideoYUVAProgram(TexCoordPrecision precision,
+ SamplerType sampler);
const VideoStreamTextureProgram* GetVideoStreamTextureProgram(
TexCoordPrecision precision);
@@ -388,47 +412,72 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
const SolidColorProgram* GetSolidColorProgram();
const SolidColorProgramAA* GetSolidColorProgramAA();
- TileProgram tile_program_[NumTexCoordPrecisions][NumSamplerTypes];
+ TileProgram
+ tile_program_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1];
TileProgramOpaque
- tile_program_opaque_[NumTexCoordPrecisions][NumSamplerTypes];
- TileProgramAA tile_program_aa_[NumTexCoordPrecisions][NumSamplerTypes];
- TileProgramSwizzle
- tile_program_swizzle_[NumTexCoordPrecisions][NumSamplerTypes];
+ tile_program_opaque_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1];
+ TileProgramAA
+ tile_program_aa_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1];
+ TileProgramSwizzle tile_program_swizzle_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1];
TileProgramSwizzleOpaque
- tile_program_swizzle_opaque_[NumTexCoordPrecisions][NumSamplerTypes];
- TileProgramSwizzleAA
- tile_program_swizzle_aa_[NumTexCoordPrecisions][NumSamplerTypes];
+ tile_program_swizzle_opaque_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1];
+ TileProgramSwizzleAA tile_program_swizzle_aa_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1];
TileCheckerboardProgram tile_checkerboard_program_;
- TextureProgram texture_program_[NumTexCoordPrecisions];
+ TextureProgram
+ texture_program_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1];
NonPremultipliedTextureProgram
- nonpremultiplied_texture_program_[NumTexCoordPrecisions];
- TextureBackgroundProgram texture_background_program_[NumTexCoordPrecisions];
+ nonpremultiplied_texture_program_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1];
+ TextureBackgroundProgram
+ texture_background_program_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1];
NonPremultipliedTextureBackgroundProgram
- nonpremultiplied_texture_background_program_[NumTexCoordPrecisions];
- TextureProgram texture_io_surface_program_[NumTexCoordPrecisions];
-
- RenderPassProgram render_pass_program_[NumTexCoordPrecisions][NumBlendModes];
- RenderPassProgramAA
- render_pass_program_aa_[NumTexCoordPrecisions][NumBlendModes];
- RenderPassMaskProgram render_pass_mask_program_
- [NumTexCoordPrecisions][NumSamplerTypes][NumBlendModes];
- RenderPassMaskProgramAA render_pass_mask_program_aa_
- [NumTexCoordPrecisions][NumSamplerTypes][NumBlendModes];
+ nonpremultiplied_texture_background_program_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1];
+ TextureProgram texture_io_surface_program_[LAST_TEX_COORD_PRECISION + 1];
+
+ RenderPassProgram
+ render_pass_program_[LAST_TEX_COORD_PRECISION + 1][LAST_BLEND_MODE + 1];
+ RenderPassProgramAA render_pass_program_aa_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_BLEND_MODE + 1];
+ RenderPassMaskProgram
+ render_pass_mask_program_[LAST_TEX_COORD_PRECISION + 1]
+ [LAST_SAMPLER_TYPE + 1]
+ [LAST_BLEND_MODE + 1]
+ [LAST_MASK_VALUE + 1];
+ RenderPassMaskProgramAA
+ render_pass_mask_program_aa_[LAST_TEX_COORD_PRECISION + 1]
+ [LAST_SAMPLER_TYPE + 1]
+ [LAST_BLEND_MODE + 1]
+ [LAST_MASK_VALUE + 1];
RenderPassColorMatrixProgram
- render_pass_color_matrix_program_[NumTexCoordPrecisions][NumBlendModes];
- RenderPassColorMatrixProgramAA render_pass_color_matrix_program_aa_
- [NumTexCoordPrecisions][NumBlendModes];
- RenderPassMaskColorMatrixProgram render_pass_mask_color_matrix_program_
- [NumTexCoordPrecisions][NumSamplerTypes][NumBlendModes];
- RenderPassMaskColorMatrixProgramAA render_pass_mask_color_matrix_program_aa_
- [NumTexCoordPrecisions][NumSamplerTypes][NumBlendModes];
-
- VideoYUVProgram video_yuv_program_[NumTexCoordPrecisions];
- VideoYUVAProgram video_yuva_program_[NumTexCoordPrecisions];
+ render_pass_color_matrix_program_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_BLEND_MODE + 1];
+ RenderPassColorMatrixProgramAA
+ render_pass_color_matrix_program_aa_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_BLEND_MODE + 1];
+ RenderPassMaskColorMatrixProgram
+ render_pass_mask_color_matrix_program_[LAST_TEX_COORD_PRECISION + 1]
+ [LAST_SAMPLER_TYPE + 1]
+ [LAST_BLEND_MODE + 1]
+ [LAST_MASK_VALUE + 1];
+ RenderPassMaskColorMatrixProgramAA
+ render_pass_mask_color_matrix_program_aa_[LAST_TEX_COORD_PRECISION + 1]
+ [LAST_SAMPLER_TYPE + 1]
+ [LAST_BLEND_MODE + 1]
+ [LAST_MASK_VALUE + 1];
+
+ VideoYUVProgram
+ video_yuv_program_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1];
+ VideoYUVAProgram
+ video_yuva_program_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1];
VideoStreamTextureProgram
- video_stream_texture_program_[NumTexCoordPrecisions];
+ video_stream_texture_program_[LAST_TEX_COORD_PRECISION + 1];
DebugBorderProgram debug_border_program_;
SolidColorProgram solid_color_program_;
@@ -441,7 +490,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
gfx::Rect swap_buffer_rect_;
gfx::Rect scissor_rect_;
- gfx::Rect viewport_;
bool is_backbuffer_discarded_;
bool is_using_bind_uniform_;
bool is_scissor_enabled_;
@@ -468,22 +516,10 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
SkBitmap on_demand_tile_raster_bitmap_;
ResourceProvider::ResourceId on_demand_tile_raster_resource_id_;
-
+ BoundGeometry bound_geometry_;
DISALLOW_COPY_AND_ASSIGN(GLRenderer);
};
-// Setting DEBUG_GL_CALLS to 1 will call glGetError() after almost every GL
-// call made by the compositor. Useful for debugging rendering issues but
-// will significantly degrade performance.
-#define DEBUG_GL_CALLS 0
-
-#if DEBUG_GL_CALLS && !defined(NDEBUG)
-#define GLC(context, x) \
- (x, GLRenderer::DebugGLCall(&* context, #x, __FILE__, __LINE__))
-#else
-#define GLC(context, x) (x)
-#endif
-
} // namespace cc
#endif // CC_OUTPUT_GL_RENDERER_H_
diff --git a/chromium/cc/output/gl_renderer_draw_cache.cc b/chromium/cc/output/gl_renderer_draw_cache.cc
index a0004f2a064..91581f481be 100644
--- a/chromium/cc/output/gl_renderer_draw_cache.cc
+++ b/chromium/cc/output/gl_renderer_draw_cache.cc
@@ -10,6 +10,7 @@ TexturedQuadDrawCache::TexturedQuadDrawCache()
: program_id(-1),
resource_id(-1),
needs_blending(false),
+ nearest_neighbor(false),
background_color(0),
uv_xform_location(-1),
background_color_location(-1),
diff --git a/chromium/cc/output/gl_renderer_draw_cache.h b/chromium/cc/output/gl_renderer_draw_cache.h
index f8284184f0c..a16c8a5bde8 100644
--- a/chromium/cc/output/gl_renderer_draw_cache.h
+++ b/chromium/cc/output/gl_renderer_draw_cache.h
@@ -33,6 +33,7 @@ struct TexturedQuadDrawCache {
int program_id;
int resource_id;
bool needs_blending;
+ bool nearest_neighbor;
SkColor background_color;
// Information about the program binding that is required to draw.
diff --git a/chromium/cc/output/gl_renderer_unittest.cc b/chromium/cc/output/gl_renderer_unittest.cc
index dc686757cf8..09407f55ed7 100644
--- a/chromium/cc/output/gl_renderer_unittest.cc
+++ b/chromium/cc/output/gl_renderer_unittest.cc
@@ -6,8 +6,16 @@
#include <set>
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/base/math_util.h"
#include "cc/output/compositor_frame_metadata.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
+#include "cc/output/overlay_strategy_single_on_top.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/quads/texture_draw_quad.h"
#include "cc/resources/resource_provider.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
@@ -57,38 +65,39 @@ class GLRendererTest : public testing::Test {
static inline SkXfermode::Mode BlendModeToSkXfermode(BlendMode blend_mode) {
switch (blend_mode) {
- case BlendModeNormal:
+ case BLEND_MODE_NONE:
+ case BLEND_MODE_NORMAL:
return SkXfermode::kSrcOver_Mode;
- case BlendModeOverlay:
+ case BLEND_MODE_SCREEN:
+ return SkXfermode::kScreen_Mode;
+ case BLEND_MODE_OVERLAY:
return SkXfermode::kOverlay_Mode;
- case BlendModeDarken:
+ case BLEND_MODE_DARKEN:
return SkXfermode::kDarken_Mode;
- case BlendModeLighten:
+ case BLEND_MODE_LIGHTEN:
return SkXfermode::kLighten_Mode;
- case BlendModeColorDodge:
+ case BLEND_MODE_COLOR_DODGE:
return SkXfermode::kColorDodge_Mode;
- case BlendModeColorBurn:
+ case BLEND_MODE_COLOR_BURN:
return SkXfermode::kColorBurn_Mode;
- case BlendModeHardLight:
+ case BLEND_MODE_HARD_LIGHT:
return SkXfermode::kHardLight_Mode;
- case BlendModeSoftLight:
+ case BLEND_MODE_SOFT_LIGHT:
return SkXfermode::kSoftLight_Mode;
- case BlendModeDifference:
+ case BLEND_MODE_DIFFERENCE:
return SkXfermode::kDifference_Mode;
- case BlendModeExclusion:
+ case BLEND_MODE_EXCLUSION:
return SkXfermode::kExclusion_Mode;
- case BlendModeMultiply:
+ case BLEND_MODE_MULTIPLY:
return SkXfermode::kMultiply_Mode;
- case BlendModeHue:
+ case BLEND_MODE_HUE:
return SkXfermode::kHue_Mode;
- case BlendModeSaturation:
+ case BLEND_MODE_SATURATION:
return SkXfermode::kSaturation_Mode;
- case BlendModeColor:
+ case BLEND_MODE_COLOR:
return SkXfermode::kColor_Mode;
- case BlendModeLuminosity:
+ case BLEND_MODE_LUMINOSITY:
return SkXfermode::kLuminosity_Mode;
- case NumBlendModes:
- NOTREACHED();
}
return SkXfermode::kSrcOver_Mode;
}
@@ -96,48 +105,56 @@ static inline SkXfermode::Mode BlendModeToSkXfermode(BlendMode blend_mode) {
// Explicitly named to be a friend in GLRenderer for shader access.
class GLRendererShaderPixelTest : public GLRendererPixelTest {
public:
- void TestShaders() {
+ void SetUp() override {
+ GLRendererPixelTest::SetUp();
ASSERT_FALSE(renderer()->IsContextLost());
+ }
+
+ void TearDown() override {
+ GLRendererPixelTest::TearDown();
+ ASSERT_FALSE(renderer()->IsContextLost());
+ }
+
+ void TestBasicShaders() {
EXPECT_PROGRAM_VALID(renderer()->GetTileCheckerboardProgram());
EXPECT_PROGRAM_VALID(renderer()->GetDebugBorderProgram());
EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgram());
EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgramAA());
- TestShadersWithTexCoordPrecision(TexCoordPrecisionMedium);
- TestShadersWithTexCoordPrecision(TexCoordPrecisionHigh);
- ASSERT_FALSE(renderer()->IsContextLost());
}
- void TestShadersWithTexCoordPrecision(TexCoordPrecision precision) {
- for (int i = 0; i < NumBlendModes; ++i) {
- BlendMode blend_mode = static_cast<BlendMode>(i);
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassProgram(precision, blend_mode));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassProgramAA(precision, blend_mode));
- }
- EXPECT_PROGRAM_VALID(renderer()->GetTextureProgram(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetNonPremultipliedTextureProgram(precision));
- EXPECT_PROGRAM_VALID(renderer()->GetTextureBackgroundProgram(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetNonPremultipliedTextureBackgroundProgram(precision));
+ void TestShadersWithPrecision(TexCoordPrecision precision) {
EXPECT_PROGRAM_VALID(renderer()->GetTextureIOSurfaceProgram(precision));
- EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVProgram(precision));
- EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVAProgram(precision));
- // This is unlikely to be ever true in tests due to usage of osmesa.
if (renderer()->Capabilities().using_egl_image)
EXPECT_PROGRAM_VALID(renderer()->GetVideoStreamTextureProgram(precision));
else
EXPECT_FALSE(renderer()->GetVideoStreamTextureProgram(precision));
- TestShadersWithSamplerType(precision, SamplerType2D);
- TestShadersWithSamplerType(precision, SamplerType2DRect);
- // This is unlikely to be ever true in tests due to usage of osmesa.
- if (renderer()->Capabilities().using_egl_image)
- TestShadersWithSamplerType(precision, SamplerTypeExternalOES);
}
- void TestShadersWithSamplerType(TexCoordPrecision precision,
- SamplerType sampler) {
+ void TestShadersWithPrecisionAndBlend(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgram(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgramAA(precision, blend_mode));
+ }
+
+ void TestShadersWithPrecisionAndSampler(TexCoordPrecision precision,
+ SamplerType sampler) {
+ if (!renderer()->Capabilities().using_egl_image &&
+ sampler == SAMPLER_TYPE_EXTERNAL_OES) {
+ // This will likely be hit in tests due to usage of osmesa.
+ return;
+ }
+
+ EXPECT_PROGRAM_VALID(renderer()->GetTextureProgram(precision, sampler));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetNonPremultipliedTextureProgram(precision, sampler));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetTextureBackgroundProgram(precision, sampler));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetNonPremultipliedTextureBackgroundProgram(precision,
+ sampler));
+
EXPECT_PROGRAM_VALID(renderer()->GetTileProgram(precision, sampler));
EXPECT_PROGRAM_VALID(renderer()->GetTileProgramOpaque(precision, sampler));
EXPECT_PROGRAM_VALID(renderer()->GetTileProgramAA(precision, sampler));
@@ -146,30 +163,134 @@ class GLRendererShaderPixelTest : public GLRendererPixelTest {
renderer()->GetTileProgramSwizzleOpaque(precision, sampler));
EXPECT_PROGRAM_VALID(
renderer()->GetTileProgramSwizzleAA(precision, sampler));
- for (int i = 0; i < NumBlendModes; ++i) {
- BlendMode blend_mode = static_cast<BlendMode>(i);
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassMaskProgram(precision, sampler, blend_mode));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgramAA(
- precision, sampler, blend_mode));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgramAA(
- precision, sampler, blend_mode));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgram(
- precision, sampler, blend_mode));
+ EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVProgram(precision, sampler));
+ EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVAProgram(precision, sampler));
+ }
+
+ void TestShadersWithMasks(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode,
+ bool mask_for_background) {
+ if (!renderer()->Capabilities().using_egl_image &&
+ sampler == SAMPLER_TYPE_EXTERNAL_OES) {
+ // This will likely be hit in tests due to usage of osmesa.
+ return;
}
+
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgram(
+ precision, sampler, blend_mode, mask_for_background));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgramAA(
+ precision, sampler, blend_mode, mask_for_background));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgramAA(
+ precision, sampler, blend_mode, mask_for_background));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgram(
+ precision, sampler, blend_mode, mask_for_background));
}
};
namespace {
-#if !defined(OS_ANDROID)
-TEST_F(GLRendererShaderPixelTest, AllShadersCompile) { TestShaders(); }
+#if !defined(OS_ANDROID) && !defined(OS_WIN)
+static const TexCoordPrecision kPrecisionList[] = {TEX_COORD_PRECISION_MEDIUM,
+ TEX_COORD_PRECISION_HIGH};
+
+static const BlendMode kBlendModeList[LAST_BLEND_MODE + 1] = {
+ BLEND_MODE_NONE,
+ BLEND_MODE_NORMAL,
+ BLEND_MODE_SCREEN,
+ BLEND_MODE_OVERLAY,
+ BLEND_MODE_DARKEN,
+ BLEND_MODE_LIGHTEN,
+ BLEND_MODE_COLOR_DODGE,
+ BLEND_MODE_COLOR_BURN,
+ BLEND_MODE_HARD_LIGHT,
+ BLEND_MODE_SOFT_LIGHT,
+ BLEND_MODE_DIFFERENCE,
+ BLEND_MODE_EXCLUSION,
+ BLEND_MODE_MULTIPLY,
+ BLEND_MODE_HUE,
+ BLEND_MODE_SATURATION,
+ BLEND_MODE_COLOR,
+ BLEND_MODE_LUMINOSITY,
+};
+
+static const SamplerType kSamplerList[] = {
+ SAMPLER_TYPE_2D,
+ SAMPLER_TYPE_2D_RECT,
+ SAMPLER_TYPE_EXTERNAL_OES,
+};
+
+TEST_F(GLRendererShaderPixelTest, BasicShadersCompile) {
+ TestBasicShaders();
+}
+
+class PrecisionShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<TexCoordPrecision> {};
+
+TEST_P(PrecisionShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecision(GetParam());
+}
+
+INSTANTIATE_TEST_CASE_P(PrecisionShadersCompile,
+ PrecisionShaderPixelTest,
+ ::testing::ValuesIn(kPrecisionList));
+
+class PrecisionBlendShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, BlendMode>> {};
+
+TEST_P(PrecisionBlendShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecisionAndBlend(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PrecisionBlendShadersCompile,
+ PrecisionBlendShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kBlendModeList)));
+
+class PrecisionSamplerShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, SamplerType>> {};
+
+TEST_P(PrecisionSamplerShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecisionAndSampler(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(PrecisionSamplerShadersCompile,
+ PrecisionSamplerShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kSamplerList)));
+
+class MaskShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, SamplerType, BlendMode, bool>> {};
+
+TEST_P(MaskShaderPixelTest, ShadersCompile) {
+ TestShadersWithMasks(
+ std::tr1::get<0>(GetParam()), std::tr1::get<1>(GetParam()),
+ std::tr1::get<2>(GetParam()), std::tr1::get<3>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(MaskShadersCompile,
+ MaskShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kSamplerList),
+ ::testing::ValuesIn(kBlendModeList),
+ ::testing::Bool()));
+
#endif
class FakeRendererGL : public GLRenderer {
public:
FakeRendererGL(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider)
: GLRenderer(client,
@@ -179,6 +300,22 @@ class FakeRendererGL : public GLRenderer {
NULL,
0) {}
+ FakeRendererGL(RendererClient* client,
+ const RendererSettings* settings,
+ OutputSurface* output_surface,
+ ResourceProvider* resource_provider,
+ TextureMailboxDeleter* texture_mailbox_deleter)
+ : GLRenderer(client,
+ settings,
+ output_surface,
+ resource_provider,
+ texture_mailbox_deleter,
+ 0) {}
+
+ void SetOverlayProcessor(OverlayProcessor* processor) {
+ overlay_processor_.reset(processor);
+ }
+
// GLRenderer methods.
// Changing visibility to public.
@@ -212,7 +349,7 @@ class GLRendererWithDefaultHarnessTest : public GLRendererTest {
void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); }
- LayerTreeSettings settings_;
+ RendererSettings settings_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
FakeRendererClient renderer_client_;
@@ -268,10 +405,15 @@ class GLRendererShaderTest : public GLRendererTest {
SamplerType sampler,
BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
- &renderer_->render_pass_mask_program_[precision][sampler][blend_mode]);
+ &renderer_->render_pass_mask_program_[precision]
+ [sampler]
+ [blend_mode]
+ [NO_MASK]);
EXPECT_EQ(
- renderer_->render_pass_mask_program_[precision][sampler][blend_mode]
- .program(),
+ renderer_->render_pass_mask_program_[precision]
+ [sampler]
+ [blend_mode]
+ [NO_MASK].program(),
renderer_->program_shadow_);
}
@@ -279,9 +421,9 @@ class GLRendererShaderTest : public GLRendererTest {
SamplerType sampler,
BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_color_matrix_program_
- [precision][sampler][blend_mode]);
+ [precision][sampler][blend_mode][NO_MASK]);
EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_
- [precision][sampler][blend_mode].program(),
+ [precision][sampler][blend_mode][NO_MASK].program(),
renderer_->program_shadow_);
}
@@ -310,10 +452,11 @@ class GLRendererShaderTest : public GLRendererTest {
BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
&renderer_
- ->render_pass_mask_program_aa_[precision][sampler][blend_mode]);
+ ->render_pass_mask_program_aa_
+ [precision][sampler][blend_mode][NO_MASK]);
EXPECT_EQ(
renderer_->render_pass_mask_program_aa_[precision][sampler][blend_mode]
- .program(),
+ [NO_MASK].program(),
renderer_->program_shadow_);
}
@@ -321,9 +464,9 @@ class GLRendererShaderTest : public GLRendererTest {
SamplerType sampler,
BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_color_matrix_program_aa_
- [precision][sampler][blend_mode]);
+ [precision][sampler][blend_mode][NO_MASK]);
EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_aa_
- [precision][sampler][blend_mode].program(),
+ [precision][sampler][blend_mode][NO_MASK].program(),
renderer_->program_shadow_);
}
@@ -333,7 +476,7 @@ class GLRendererShaderTest : public GLRendererTest {
renderer_->program_shadow_);
}
- LayerTreeSettings settings_;
+ RendererSettings settings_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
FakeRendererClient renderer_client_;
@@ -540,7 +683,7 @@ TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
&settings,
@@ -580,7 +723,7 @@ TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
&settings,
@@ -619,7 +762,7 @@ TEST_F(GLRendererTest, OpaqueBackground) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
&settings,
@@ -671,7 +814,7 @@ TEST_F(GLRendererTest, TransparentBackground) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
&settings,
@@ -716,7 +859,7 @@ TEST_F(GLRendererTest, OffscreenOutputSurface) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
&settings,
@@ -801,7 +944,7 @@ TEST_F(GLRendererTest, VisibilityChangeIsLastCall) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
&settings,
@@ -872,7 +1015,7 @@ TEST_F(GLRendererTest, ActiveTextureState) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
&settings,
@@ -882,11 +1025,11 @@ TEST_F(GLRendererTest, ActiveTextureState) {
// During initialization we are allowed to set any texture parameters.
EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber());
- RenderPassId id(1, 1);
- TestRenderPass* root_pass = AddRenderPass(
- &render_passes_in_draw_order_, id, gfx::Rect(100, 100), gfx::Transform());
+ TestRenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, RenderPassId(1, 1),
+ gfx::Rect(100, 100), gfx::Transform());
root_pass->AppendOneOfEveryQuadType(resource_provider.get(),
- RenderPassId(2, 1));
+ RenderPassId(0, 0));
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
@@ -963,7 +1106,7 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
settings.should_clear_root_render_pass = false;
FakeRendererClient renderer_client;
@@ -974,6 +1117,12 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
gfx::Rect viewport_rect(10, 10);
+ RenderPassId child_pass_id(2, 0);
+ TestRenderPass* child_pass =
+ AddRenderPass(&render_passes_in_draw_order_, child_pass_id, viewport_rect,
+ gfx::Transform());
+ AddQuad(child_pass, viewport_rect, SK_ColorBLUE);
+
RenderPassId root_pass_id(1, 0);
TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
root_pass_id,
@@ -981,12 +1130,6 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
gfx::Transform());
AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
- RenderPassId child_pass_id(2, 0);
- TestRenderPass* child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- viewport_rect,
- gfx::Transform());
- AddQuad(child_pass, viewport_rect, SK_ColorBLUE);
AddRenderPassQuad(root_pass, child_pass);
@@ -1061,7 +1204,7 @@ TEST_F(GLRendererTest, ScissorTestWhenClearing) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
&settings,
@@ -1159,7 +1302,7 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
settings.partial_swap_enabled = true;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
@@ -1296,32 +1439,8 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
class FlippedScissorAndViewportContext : public TestWebGraphicsContext3D {
public:
- FlippedScissorAndViewportContext()
- : did_call_viewport_(false), did_call_scissor_(false) {}
- ~FlippedScissorAndViewportContext() override {
- EXPECT_TRUE(did_call_viewport_);
- EXPECT_TRUE(did_call_scissor_);
- }
-
- void viewport(GLint x, GLint y, GLsizei width, GLsizei height) override {
- EXPECT_EQ(10, x);
- EXPECT_EQ(390, y);
- EXPECT_EQ(100, width);
- EXPECT_EQ(100, height);
- did_call_viewport_ = true;
- }
-
- void scissor(GLint x, GLint y, GLsizei width, GLsizei height) override {
- EXPECT_EQ(30, x);
- EXPECT_EQ(450, y);
- EXPECT_EQ(20, width);
- EXPECT_EQ(20, height);
- did_call_scissor_ = true;
- }
-
- private:
- bool did_call_viewport_;
- bool did_call_scissor_;
+ MOCK_METHOD4(viewport, void(GLint x, GLint y, GLsizei width, GLsizei height));
+ MOCK_METHOD4(scissor, void(GLint x, GLint y, GLsizei width, GLsizei height));
};
TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) {
@@ -1332,6 +1451,12 @@ TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) {
scoped_ptr<FlippedScissorAndViewportContext> context_owned(
new FlippedScissorAndViewportContext);
+ // We expect exactly one call to viewport on this context and exactly two
+ // to scissor (one to scissor the clear, one to scissor the quad draw).
+ EXPECT_CALL(*context_owned, viewport(10, 390, 100, 100));
+ EXPECT_CALL(*context_owned, scissor(10, 390, 100, 100));
+ EXPECT_CALL(*context_owned, scissor(30, 450, 20, 20));
+
FakeOutputSurfaceClient output_surface_client;
scoped_ptr<OutputSurface> output_surface(
new NonReshapableOutputSurface(context_owned.Pass()));
@@ -1348,7 +1473,7 @@ TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) {
false,
1));
- LayerTreeSettings settings;
+ RendererSettings settings;
FakeRendererClient renderer_client;
FakeRendererGL renderer(&renderer_client,
&settings,
@@ -1375,6 +1500,54 @@ TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) {
false);
}
+TEST_F(GLRendererTest, DrawFramePreservesFramebuffer) {
+ // When using render-to-FBO to display the surface, all rendering is done
+ // to a non-zero FBO. Make sure that the framebuffer is always restored to
+ // the correct framebuffer during rendering, if changed.
+ // Note: there is one path that will set it to 0, but that is after the render
+ // has finished.
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<FakeOutputSurface> output_surface(
+ FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create().Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), NULL, NULL, 0, false,
+ 1));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client, &settings, output_surface.get(),
+ resource_provider.get());
+ EXPECT_FALSE(renderer.Capabilities().using_partial_swap);
+
+ gfx::Rect device_viewport_rect(0, 0, 100, 100);
+ gfx::Rect viewport_rect(device_viewport_rect.size());
+ gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20);
+
+ RenderPassId root_pass_id(1, 0);
+ TestRenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, root_pass_id, viewport_rect,
+ gfx::Transform());
+ AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN);
+
+ unsigned fbo;
+ gpu::gles2::GLES2Interface* gl =
+ output_surface->context_provider()->ContextGL();
+ gl->GenFramebuffers(1, &fbo);
+ output_surface->set_framebuffer(fbo);
+
+ renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+ renderer.DrawFrame(&render_passes_in_draw_order_, 1.f, device_viewport_rect,
+ device_viewport_rect, false);
+
+ int bound_fbo;
+ gl->GetIntegerv(GL_FRAMEBUFFER_BINDING, &bound_fbo);
+ EXPECT_EQ(static_cast<int>(fbo), bound_fbo);
+}
+
TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
gfx::Rect viewport_rect(1, 1);
@@ -1386,9 +1559,8 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
TestRenderPass* root_pass;
ResourceProvider::ResourceId mask = resource_provider_->CreateResource(
- gfx::Size(20, 12),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ gfx::Size(20, 12), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider_->best_texture_format());
resource_provider_->AllocateForTesting(mask);
@@ -1418,9 +1590,10 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
gfx::Transform transform_causing_aa;
transform_causing_aa.Rotate(20.0);
- for (int i = 0; i < NumBlendModes; ++i) {
+ for (int i = 0; i <= LAST_BLEND_MODE; ++i) {
BlendMode blend_mode = static_cast<BlendMode>(i);
SkXfermode::Mode xfer_mode = BlendModeToSkXfermode(blend_mode);
+ settings_.force_blending_with_shaders = (blend_mode != BLEND_MODE_NONE);
// RenderPassProgram
render_passes_in_draw_order_.clear();
child_pass = AddRenderPass(&render_passes_in_draw_order_,
@@ -1447,7 +1620,7 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
viewport_rect,
viewport_rect,
false);
- TestRenderPassProgram(TexCoordPrecisionMedium, blend_mode);
+ TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
// RenderPassColorMatrixProgram
render_passes_in_draw_order_.clear();
@@ -1472,7 +1645,7 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
viewport_rect,
viewport_rect,
false);
- TestRenderPassColorMatrixProgram(TexCoordPrecisionMedium, blend_mode);
+ TestRenderPassColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
// RenderPassMaskProgram
render_passes_in_draw_order_.clear();
@@ -1501,8 +1674,8 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
viewport_rect,
viewport_rect,
false);
- TestRenderPassMaskProgram(
- TexCoordPrecisionMedium, SamplerType2D, blend_mode);
+ TestRenderPassMaskProgram(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
+ blend_mode);
// RenderPassMaskColorMatrixProgram
render_passes_in_draw_order_.clear();
@@ -1527,8 +1700,8 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
viewport_rect,
viewport_rect,
false);
- TestRenderPassMaskColorMatrixProgram(
- TexCoordPrecisionMedium, SamplerType2D, blend_mode);
+ TestRenderPassMaskColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM,
+ SAMPLER_TYPE_2D, blend_mode);
// RenderPassProgramAA
render_passes_in_draw_order_.clear();
@@ -1557,7 +1730,7 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
viewport_rect,
viewport_rect,
false);
- TestRenderPassProgramAA(TexCoordPrecisionMedium, blend_mode);
+ TestRenderPassProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
// RenderPassColorMatrixProgramAA
render_passes_in_draw_order_.clear();
@@ -1582,7 +1755,7 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
viewport_rect,
viewport_rect,
false);
- TestRenderPassColorMatrixProgramAA(TexCoordPrecisionMedium, blend_mode);
+ TestRenderPassColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
// RenderPassMaskProgramAA
render_passes_in_draw_order_.clear();
@@ -1611,8 +1784,8 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
viewport_rect,
viewport_rect,
false);
- TestRenderPassMaskProgramAA(
- TexCoordPrecisionMedium, SamplerType2D, blend_mode);
+ TestRenderPassMaskProgramAA(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
+ blend_mode);
// RenderPassMaskColorMatrixProgramAA
render_passes_in_draw_order_.clear();
@@ -1637,8 +1810,8 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
viewport_rect,
viewport_rect,
false);
- TestRenderPassMaskColorMatrixProgramAA(
- TexCoordPrecisionMedium, SamplerType2D, blend_mode);
+ TestRenderPassMaskColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM,
+ SAMPLER_TYPE_2D, blend_mode);
}
}
@@ -1690,7 +1863,7 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) {
// If use_aa incorrectly ignores clipping, it will use the
// RenderPassProgramAA shader instead of the RenderPassProgram.
- TestRenderPassProgram(TexCoordPrecisionMedium, BlendModeNormal);
+ TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, BLEND_MODE_NONE);
}
TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
@@ -1810,7 +1983,7 @@ class MockOutputSurfaceTest : public GLRendererTest {
->TestContext3d());
}
- LayerTreeSettings settings_;
+ RendererSettings settings_;
FakeOutputSurfaceClient output_surface_client_;
StrictMock<MockOutputSurface> output_surface_;
scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
@@ -1886,7 +2059,7 @@ TEST_F(GLRendererTestSyncPoint, SignalSyncPointOnLostContext) {
// Make the sync point happen.
gl->Finish();
// Post a task after the sync point.
- base::MessageLoop::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&OtherCallback, &other_callback_count));
base::MessageLoop::current()->Run();
@@ -1915,7 +2088,7 @@ TEST_F(GLRendererTestSyncPoint, SignalSyncPoint) {
// Make the sync point happen.
gl->Finish();
// Post a task after the sync point.
- base::MessageLoop::current()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&OtherCallback, &other_callback_count));
base::MessageLoop::current()->Run();
@@ -1926,5 +2099,235 @@ TEST_F(GLRendererTestSyncPoint, SignalSyncPoint) {
}
#endif // OS_ANDROID
+class TestOverlayProcessor : public OverlayProcessor {
+ public:
+ class Strategy : public OverlayProcessor::Strategy {
+ public:
+ Strategy() {}
+ ~Strategy() override {}
+ MOCK_METHOD2(Attempt,
+ bool(RenderPassList* render_passes_in_draw_order,
+ OverlayCandidateList* candidates));
+ };
+
+ TestOverlayProcessor(OutputSurface* surface,
+ ResourceProvider* resource_provider)
+ : OverlayProcessor(surface, resource_provider) {}
+ ~TestOverlayProcessor() override {}
+ void Initialize() override {
+ strategy_ = new Strategy();
+ strategies_.push_back(scoped_ptr<OverlayProcessor::Strategy>(strategy_));
+ }
+
+ Strategy* strategy_;
+};
+
+void MailboxReleased(unsigned sync_point,
+ bool lost_resource,
+ BlockingTaskRunner* main_thread_task_runner) {
+}
+
+void IgnoreCopyResult(scoped_ptr<CopyOutputResult> result) {
+}
+
+TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
+ scoped_ptr<DiscardCheckingContext> context_owned(new DiscardCheckingContext);
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(context_owned.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), NULL, NULL, 0, false,
+ 1));
+ scoped_ptr<TextureMailboxDeleter> mailbox_deleter(
+ new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get()));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client, &settings, output_surface.get(),
+ resource_provider.get(), mailbox_deleter.get());
+
+ TestOverlayProcessor* processor =
+ new TestOverlayProcessor(output_surface.get(), resource_provider.get());
+ processor->Initialize();
+ renderer.SetOverlayProcessor(processor);
+
+ gfx::Rect viewport_rect(1, 1);
+ TestRenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, RenderPassId(1, 0),
+ viewport_rect, gfx::Transform());
+ root_pass->has_transparent_background = false;
+ root_pass->copy_requests.push_back(
+ CopyOutputRequest::CreateRequest(base::Bind(&IgnoreCopyResult)));
+
+ unsigned sync_point = 0;
+ TextureMailbox mailbox =
+ TextureMailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point);
+ mailbox.set_allow_overlay(true);
+ scoped_ptr<SingleReleaseCallbackImpl> release_callback =
+ SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));
+ ResourceProvider::ResourceId resource_id =
+ resource_provider->CreateResourceFromTextureMailbox(
+ mailbox, release_callback.Pass());
+ bool premultiplied_alpha = false;
+ bool flipped = false;
+ bool nearest_neighbor = false;
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ TextureDrawQuad* overlay_quad =
+ root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
+ overlay_quad->SetNew(root_pass->CreateAndAppendSharedQuadState(),
+ viewport_rect, viewport_rect, viewport_rect, resource_id,
+ premultiplied_alpha, gfx::PointF(0, 0),
+ gfx::PointF(1, 1), SK_ColorTRANSPARENT, vertex_opacity,
+ flipped, nearest_neighbor);
+
+ // DirectRenderer::DrawFrame calls into OverlayProcessor::ProcessForOverlays.
+ // Attempt will be called for each strategy in OverlayProcessor. We have
+ // added a fake strategy, so checking for Attempt calls checks if there was
+ // any attempt to overlay, which there shouldn't be. We can't use the quad
+ // list because the render pass is cleaned up by DrawFrame.
+ EXPECT_CALL(*processor->strategy_, Attempt(_, _)).Times(0);
+ renderer.DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_rect,
+ viewport_rect, false);
+ Mock::VerifyAndClearExpectations(processor->strategy_);
+
+ // Without a copy request Attempt() should be called once.
+ root_pass = AddRenderPass(&render_passes_in_draw_order_, RenderPassId(1, 0),
+ viewport_rect, gfx::Transform());
+ root_pass->has_transparent_background = false;
+
+ overlay_quad = root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
+ overlay_quad->SetNew(root_pass->CreateAndAppendSharedQuadState(),
+ viewport_rect, viewport_rect, viewport_rect, resource_id,
+ premultiplied_alpha, gfx::PointF(0, 0),
+ gfx::PointF(1, 1), SK_ColorTRANSPARENT, vertex_opacity,
+ flipped, nearest_neighbor);
+
+ EXPECT_CALL(*processor->strategy_, Attempt(_, _)).Times(1);
+ renderer.DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_rect,
+ viewport_rect, false);
+}
+
+class SingleOverlayOnTopProcessor : public OverlayProcessor {
+ public:
+ class SingleOverlayValidator : public OverlayCandidateValidator {
+ public:
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override {
+ ASSERT_EQ(2U, surfaces->size());
+ OverlayCandidate& candidate = surfaces->back();
+ candidate.overlay_handled = true;
+ }
+ };
+
+ SingleOverlayOnTopProcessor(OutputSurface* surface,
+ ResourceProvider* resource_provider)
+ : OverlayProcessor(surface, resource_provider) {}
+
+ void Initialize() override {
+ strategies_.push_back(scoped_ptr<Strategy>(
+ new OverlayStrategySingleOnTop(&validator_, resource_provider_)));
+ }
+
+ SingleOverlayValidator validator_;
+};
+
+class WaitSyncPointCountingContext : public TestWebGraphicsContext3D {
+ public:
+ MOCK_METHOD1(waitSyncPoint, void(unsigned sync_point));
+};
+
+class MockOverlayScheduler {
+ public:
+ MOCK_METHOD5(Schedule,
+ void(int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ unsigned overlay_texture_id,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& uv_rect));
+};
+
+TEST_F(GLRendererTest, OverlaySyncPointsAreProcessed) {
+ scoped_ptr<WaitSyncPointCountingContext> context_owned(
+ new WaitSyncPointCountingContext);
+ WaitSyncPointCountingContext* context = context_owned.get();
+
+ MockOverlayScheduler overlay_scheduler;
+ scoped_refptr<TestContextProvider> context_provider =
+ TestContextProvider::Create(context_owned.Pass());
+ context_provider->support()->SetScheduleOverlayPlaneCallback(base::Bind(
+ &MockOverlayScheduler::Schedule, base::Unretained(&overlay_scheduler)));
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(context_provider));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), NULL, NULL, 0, false,
+ 1));
+ scoped_ptr<TextureMailboxDeleter> mailbox_deleter(
+ new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get()));
+
+ RendererSettings settings;
+ FakeRendererClient renderer_client;
+ FakeRendererGL renderer(&renderer_client, &settings, output_surface.get(),
+ resource_provider.get(), mailbox_deleter.get());
+
+ SingleOverlayOnTopProcessor* processor = new SingleOverlayOnTopProcessor(
+ output_surface.get(), resource_provider.get());
+ processor->Initialize();
+ renderer.SetOverlayProcessor(processor);
+
+ gfx::Rect viewport_rect(1, 1);
+ TestRenderPass* root_pass =
+ AddRenderPass(&render_passes_in_draw_order_, RenderPassId(1, 0),
+ viewport_rect, gfx::Transform());
+ root_pass->has_transparent_background = false;
+
+ unsigned sync_point = TestRenderPass::kSyncPointForMailboxTextureQuad;
+ TextureMailbox mailbox =
+ TextureMailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point);
+ mailbox.set_allow_overlay(true);
+ scoped_ptr<SingleReleaseCallbackImpl> release_callback =
+ SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));
+ ResourceProvider::ResourceId resource_id =
+ resource_provider->CreateResourceFromTextureMailbox(
+ mailbox, release_callback.Pass());
+ bool premultiplied_alpha = false;
+ bool flipped = false;
+ bool nearest_neighbor = false;
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ gfx::PointF uv_top_left(0, 0);
+ gfx::PointF uv_bottom_right(1, 1);
+
+ TextureDrawQuad* overlay_quad =
+ root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
+ SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
+ shared_state->SetAll(gfx::Transform(), viewport_rect.size(), viewport_rect,
+ viewport_rect, false, 1, SkXfermode::kSrcOver_Mode, 0);
+ overlay_quad->SetNew(shared_state, viewport_rect, viewport_rect,
+ viewport_rect, resource_id, premultiplied_alpha,
+ uv_top_left, uv_bottom_right, SK_ColorTRANSPARENT,
+ vertex_opacity, flipped, nearest_neighbor);
+
+ // Verify that overlay_quad actually gets turned into an overlay, and even
+ // though it's not drawn, that its sync point is waited on.
+ EXPECT_CALL(*context,
+ waitSyncPoint(TestRenderPass::kSyncPointForMailboxTextureQuad))
+ .Times(1);
+ EXPECT_CALL(overlay_scheduler,
+ Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, viewport_rect,
+ BoundingRect(uv_top_left, uv_bottom_right))).Times(1);
+
+ renderer.DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_rect,
+ viewport_rect, false);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/base/latency_info_swap_promise.cc b/chromium/cc/output/latency_info_swap_promise.cc
index 8c6ee0ec131..afc0f2d8502 100644
--- a/chromium/cc/base/latency_info_swap_promise.cc
+++ b/chromium/cc/output/latency_info_swap_promise.cc
@@ -2,25 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/base/latency_info_swap_promise.h"
+#include "cc/output/latency_info_swap_promise.h"
#include "base/logging.h"
namespace {
- ui::LatencyComponentType DidNotSwapReasonToLatencyComponentType(
- cc::SwapPromise::DidNotSwapReason reason) {
- switch (reason) {
- case cc::SwapPromise::DID_NOT_SWAP_UNKNOWN:
- case cc::SwapPromise::SWAP_FAILS:
- return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT;
- case cc::SwapPromise::COMMIT_FAILS:
- return ui::INPUT_EVENT_LATENCY_TERMINATED_COMMIT_FAILED_COMPONENT;
- case cc::SwapPromise::COMMIT_NO_UPDATE:
- return ui::INPUT_EVENT_LATENCY_TERMINATED_COMMIT_NO_UPDATE_COMPONENT;
- }
- NOTREACHED() << "Unhandled DidNotSwapReason.";
- return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT;
+ui::LatencyComponentType DidNotSwapReasonToLatencyComponentType(
+ cc::SwapPromise::DidNotSwapReason reason) {
+ switch (reason) {
+ case cc::SwapPromise::ACTIVATION_FAILS:
+ case cc::SwapPromise::SWAP_FAILS:
+ return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT;
+ case cc::SwapPromise::COMMIT_FAILS:
+ return ui::INPUT_EVENT_LATENCY_TERMINATED_COMMIT_FAILED_COMPONENT;
+ case cc::SwapPromise::COMMIT_NO_UPDATE:
+ return ui::INPUT_EVENT_LATENCY_TERMINATED_COMMIT_NO_UPDATE_COMPONENT;
}
+ NOTREACHED() << "Unhandled DidNotSwapReason.";
+ return ui::INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT;
+}
} // namespace
namespace cc {
@@ -38,8 +38,8 @@ void LatencyInfoSwapPromise::DidSwap(CompositorFrameMetadata* metadata) {
}
void LatencyInfoSwapPromise::DidNotSwap(DidNotSwapReason reason) {
- latency_.AddLatencyNumber(DidNotSwapReasonToLatencyComponentType(reason),
- 0, 0);
+ latency_.AddLatencyNumber(DidNotSwapReasonToLatencyComponentType(reason), 0,
+ 0);
// TODO(miletus): Turn this back on once per-event LatencyInfo tracking
// is enabled in GPU side.
// DCHECK(latency_.terminated);
diff --git a/chromium/cc/base/latency_info_swap_promise.h b/chromium/cc/output/latency_info_swap_promise.h
index a7941f1ae5c..74810b8d1a2 100644
--- a/chromium/cc/base/latency_info_swap_promise.h
+++ b/chromium/cc/output/latency_info_swap_promise.h
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_BASE_LATENCY_INFO_SWAP_PROMISE_H_
-#define CC_BASE_LATENCY_INFO_SWAP_PROMISE_H_
+#ifndef CC_OUTPUT_LATENCY_INFO_SWAP_PROMISE_H_
+#define CC_OUTPUT_LATENCY_INFO_SWAP_PROMISE_H_
#include "base/compiler_specific.h"
-#include "cc/base/swap_promise.h"
+#include "cc/output/swap_promise.h"
#include "ui/events/latency_info.h"
namespace cc {
@@ -16,6 +16,7 @@ class CC_EXPORT LatencyInfoSwapPromise : public SwapPromise {
explicit LatencyInfoSwapPromise(const ui::LatencyInfo& latency_info);
~LatencyInfoSwapPromise() override;
+ void DidActivate() override {}
void DidSwap(CompositorFrameMetadata* metadata) override;
void DidNotSwap(DidNotSwapReason reason) override;
@@ -27,4 +28,4 @@ class CC_EXPORT LatencyInfoSwapPromise : public SwapPromise {
} // namespace cc
-#endif // CC_BASE_LATENCY_INFO_SWAP_PROMISE_H_
+#endif // CC_OUTPUT_LATENCY_INFO_SWAP_PROMISE_H_
diff --git a/chromium/cc/output/layer_quad.cc b/chromium/cc/output/layer_quad.cc
new file mode 100644
index 00000000000..537c87bd61d
--- /dev/null
+++ b/chromium/cc/output/layer_quad.cc
@@ -0,0 +1,124 @@
+// Copyright 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/output/layer_quad.h"
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/quad_f.h"
+
+namespace cc {
+
+LayerQuad::Edge::Edge(const gfx::PointF& p, const gfx::PointF& q) {
+ if (p == q) {
+ degenerate_ = true;
+ return;
+ }
+ degenerate_ = false;
+ gfx::Vector2dF tangent(p.y() - q.y(), q.x() - p.x());
+ float cross2 = p.x() * q.y() - q.x() * p.y();
+
+ set(tangent.x(), tangent.y(), cross2);
+ scale(1.0f / tangent.Length());
+}
+
+gfx::PointF LayerQuad::Edge::Intersect(const LayerQuad::Edge& e) const {
+ DCHECK(!degenerate());
+ DCHECK(!e.degenerate());
+
+ return gfx::PointF((y() * e.z() - e.y() * z()) / (x() * e.y() - e.x() * y()),
+ (x() * e.z() - e.x() * z()) / (e.x() * y() - x() * e.y()));
+}
+
+LayerQuad::LayerQuad(const gfx::QuadF& quad) {
+ // Create edges.
+ left_ = Edge(quad.p4(), quad.p1());
+ right_ = Edge(quad.p2(), quad.p3());
+ top_ = Edge(quad.p1(), quad.p2());
+ bottom_ = Edge(quad.p3(), quad.p4());
+
+ float sign = quad.IsCounterClockwise() ? -1 : 1;
+ left_.scale(sign);
+ right_.scale(sign);
+ top_.scale(sign);
+ bottom_.scale(sign);
+}
+
+LayerQuad::LayerQuad(const Edge& left,
+ const Edge& top,
+ const Edge& right,
+ const Edge& bottom)
+ : left_(left),
+ top_(top),
+ right_(right),
+ bottom_(bottom) {}
+
+gfx::QuadF LayerQuad::ToQuadF() const {
+ size_t num_degenerate_edges = left_.degenerate() + right_.degenerate() +
+ top_.degenerate() + bottom_.degenerate();
+ if (num_degenerate_edges > 1) {
+ return gfx::QuadF();
+ }
+
+ if (left_.degenerate()) {
+ return gfx::QuadF(top_.Intersect(bottom_), top_.Intersect(right_),
+ right_.Intersect(bottom_), bottom_.Intersect(top_));
+ }
+ if (right_.degenerate()) {
+ return gfx::QuadF(left_.Intersect(top_), top_.Intersect(bottom_),
+ bottom_.Intersect(top_), bottom_.Intersect(left_));
+ }
+ if (top_.degenerate()) {
+ return gfx::QuadF(left_.Intersect(right_), right_.Intersect(left_),
+ right_.Intersect(bottom_), bottom_.Intersect(left_));
+ }
+ if (bottom_.degenerate()) {
+ return gfx::QuadF(left_.Intersect(top_), top_.Intersect(right_),
+ right_.Intersect(left_), left_.Intersect(right_));
+ }
+ return gfx::QuadF(left_.Intersect(top_),
+ top_.Intersect(right_),
+ right_.Intersect(bottom_),
+ bottom_.Intersect(left_));
+}
+
+void LayerQuad::ToFloatArray(float flattened[12]) const {
+ if (left_.degenerate()) {
+ flattened[0] = bottom_.x();
+ flattened[1] = bottom_.y();
+ flattened[2] = bottom_.z();
+ } else {
+ flattened[0] = left_.x();
+ flattened[1] = left_.y();
+ flattened[2] = left_.z();
+ }
+ if (top_.degenerate()) {
+ flattened[3] = left_.x();
+ flattened[4] = left_.y();
+ flattened[5] = left_.z();
+ } else {
+ flattened[3] = top_.x();
+ flattened[4] = top_.y();
+ flattened[5] = top_.z();
+ }
+ if (right_.degenerate()) {
+ flattened[6] = top_.x();
+ flattened[7] = top_.y();
+ flattened[8] = top_.z();
+ } else {
+ flattened[6] = right_.x();
+ flattened[7] = right_.y();
+ flattened[8] = right_.z();
+ }
+ if (bottom_.degenerate()) {
+ flattened[9] = right_.x();
+ flattened[10] = right_.y();
+ flattened[11] = right_.z();
+ } else {
+ flattened[9] = bottom_.x();
+ flattened[10] = bottom_.y();
+ flattened[11] = bottom_.z();
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/layer_quad.h b/chromium/cc/output/layer_quad.h
index ed1db101a97..9ed3ff567bc 100644
--- a/chromium/cc/resources/layer_quad.h
+++ b/chromium/cc/output/layer_quad.h
@@ -3,8 +3,8 @@
// found in the LICENSE file.
-#ifndef CC_RESOURCES_LAYER_QUAD_H_
-#define CC_RESOURCES_LAYER_QUAD_H_
+#ifndef CC_OUTPUT_LAYER_QUAD_H_
+#define CC_OUTPUT_LAYER_QUAD_H_
#include "base/basictypes.h"
#include "cc/base/cc_export.h"
@@ -20,9 +20,9 @@ namespace cc {
class CC_EXPORT LayerQuad {
public:
- class Edge {
+ class CC_EXPORT Edge {
public:
- Edge() : x_(0), y_(0), z_(0) {}
+ Edge() : x_(0), y_(0), z_(0), degenerate_(false) {}
Edge(const gfx::PointF& p, const gfx::PointF& q);
float x() const { return x_; }
@@ -57,16 +57,15 @@ class CC_EXPORT LayerQuad {
}
void scale(float s) { scale(s, s, s); }
- gfx::PointF Intersect(const Edge& e) const {
- return gfx::PointF(
- (y() * e.z() - e.y() * z()) / (x() * e.y() - e.x() * y()),
- (x() * e.z() - e.x() * z()) / (e.x() * y() - x() * e.y()));
- }
+ bool degenerate() const { return degenerate_; }
+
+ gfx::PointF Intersect(const Edge& e) const;
private:
float x_;
float y_;
float z_;
+ bool degenerate_;
};
LayerQuad(const Edge& left,
@@ -111,4 +110,4 @@ class CC_EXPORT LayerQuad {
} // namespace cc
-#endif // CC_RESOURCES_LAYER_QUAD_H_
+#endif // CC_OUTPUT_LAYER_QUAD_H_
diff --git a/chromium/cc/resources/layer_quad_unittest.cc b/chromium/cc/output/layer_quad_unittest.cc
index 3560b8d379e..e910705a0f6 100644
--- a/chromium/cc/resources/layer_quad_unittest.cc
+++ b/chromium/cc/output/layer_quad_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/layer_quad.h"
+#include "cc/output/layer_quad.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/quad_f.h"
@@ -38,5 +38,32 @@ TEST(LayerQuadTest, Inflate) {
EXPECT_EQ(layer_quad.ToQuadF(), quad);
}
+TEST(LayerQuadTest, Degenerate) {
+ gfx::QuadF quad;
+ gfx::PointF p1(1.0f, 1.0f);
+ gfx::PointF p2(0.0f, 1.0f);
+ gfx::PointF p3(1.0f, 0.0f);
+ gfx::QuadF triangle(p1, p2, p3, p1);
+
+ LayerQuad::Edge e1d(p1, p1);
+ LayerQuad::Edge e2d(p2, p2);
+ LayerQuad::Edge e2(p1, p2);
+ LayerQuad::Edge e3(p2, p3);
+ LayerQuad::Edge e4(p3, p1);
+ EXPECT_TRUE(e1d.degenerate());
+ EXPECT_TRUE(e2d.degenerate());
+ EXPECT_FALSE(e2.degenerate());
+ EXPECT_FALSE(e3.degenerate());
+ EXPECT_FALSE(e4.degenerate());
+
+ LayerQuad degenerate_quad(e1d, e2d, e2, e3);
+ // With more than one degenerate edge, we expect the quad to be zero.
+ EXPECT_EQ(quad, degenerate_quad.ToQuadF());
+
+ LayerQuad triangle_quad(e1d, e2, e3, e4);
+ // With only one degenerate edge, we expect the quad to be a triangle.
+ EXPECT_EQ(triangle, triangle_quad.ToQuadF());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/output/managed_memory_policy.h b/chromium/cc/output/managed_memory_policy.h
index ad0224b6c42..a7273822a78 100644
--- a/chromium/cc/output/managed_memory_policy.h
+++ b/chromium/cc/output/managed_memory_policy.h
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "cc/base/cc_export.h"
-#include "cc/resources/tile_priority.h"
+#include "cc/tiles/tile_priority.h"
#include "gpu/command_buffer/common/gpu_memory_allocation.h"
namespace cc {
diff --git a/chromium/cc/output/output_surface.cc b/chromium/cc/output/output_surface.cc
index 3502927f84b..670578ad6b0 100644
--- a/chromium/cc/output/output_surface.cc
+++ b/chromium/cc/output/output_surface.cc
@@ -5,8 +5,10 @@
#include "cc/output/output_surface.h"
#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
#include "cc/output/managed_memory_policy.h"
#include "cc/output/output_surface_client.h"
#include "gpu/GLES2/gl2extchromium.h"
@@ -18,31 +20,37 @@
namespace cc {
OutputSurface::OutputSurface(
- const scoped_refptr<ContextProvider>& context_provider)
+ const scoped_refptr<ContextProvider>& context_provider,
+ const scoped_refptr<ContextProvider>& worker_context_provider,
+ scoped_ptr<SoftwareOutputDevice> software_device)
: client_(NULL),
context_provider_(context_provider),
+ worker_context_provider_(worker_context_provider),
+ software_device_(software_device.Pass()),
device_scale_factor_(-1),
external_stencil_test_enabled_(false),
weak_ptr_factory_(this) {
}
+OutputSurface::OutputSurface(
+ const scoped_refptr<ContextProvider>& context_provider)
+ : OutputSurface(context_provider, nullptr, nullptr) {
+}
+
+OutputSurface::OutputSurface(
+ const scoped_refptr<ContextProvider>& context_provider,
+ const scoped_refptr<ContextProvider>& worker_context_provider)
+ : OutputSurface(context_provider, worker_context_provider, nullptr) {
+}
+
OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
- : client_(NULL),
- software_device_(software_device.Pass()),
- device_scale_factor_(-1),
- external_stencil_test_enabled_(false),
- weak_ptr_factory_(this) {
+ : OutputSurface(nullptr, nullptr, software_device.Pass()) {
}
OutputSurface::OutputSurface(
const scoped_refptr<ContextProvider>& context_provider,
scoped_ptr<SoftwareOutputDevice> software_device)
- : client_(NULL),
- context_provider_(context_provider),
- software_device_(software_device.Pass()),
- device_scale_factor_(-1),
- external_stencil_test_enabled_(false),
- weak_ptr_factory_(this) {
+ : OutputSurface(context_provider, nullptr, software_device.Pass()) {
}
void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase,
@@ -91,7 +99,16 @@ void OutputSurface::SetExternalDrawConstraints(
}
OutputSurface::~OutputSurface() {
- ResetContext3d();
+ if (context_provider_.get()) {
+ context_provider_->SetLostContextCallback(
+ ContextProvider::LostContextCallback());
+ context_provider_->SetMemoryPolicyChangedCallback(
+ ContextProvider::MemoryPolicyChangedCallback());
+ }
+ if (worker_context_provider_.get()) {
+ worker_context_provider_->SetLostContextCallback(
+ ContextProvider::LostContextCallback());
+ }
}
bool OutputSurface::HasExternalStencilTest() const {
@@ -105,71 +122,32 @@ bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
if (context_provider_.get()) {
success = context_provider_->BindToCurrentThread();
- if (success)
- SetUpContext3d();
+ if (success) {
+ context_provider_->SetLostContextCallback(base::Bind(
+ &OutputSurface::DidLoseOutputSurface, base::Unretained(this)));
+ context_provider_->SetMemoryPolicyChangedCallback(
+ base::Bind(&OutputSurface::SetMemoryPolicy, base::Unretained(this)));
+ }
}
- if (!success)
- client_ = NULL;
-
- return success;
-}
-
-bool OutputSurface::InitializeAndSetContext3d(
- scoped_refptr<ContextProvider> context_provider) {
- DCHECK(!context_provider_.get());
- DCHECK(context_provider.get());
- DCHECK(client_);
-
- bool success = false;
- if (context_provider->BindToCurrentThread()) {
- context_provider_ = context_provider;
- SetUpContext3d();
- client_->DeferredInitialize();
- success = true;
+ if (success && worker_context_provider_.get()) {
+ success = worker_context_provider_->BindToCurrentThread();
+ if (success) {
+ worker_context_provider_->SetupLock();
+ // The destructor resets the context lost callback, so base::Unretained
+ // is safe, as long as the worker threads stop using the context before
+ // the output surface is destroyed.
+ worker_context_provider_->SetLostContextCallback(base::Bind(
+ &OutputSurface::DidLoseOutputSurface, base::Unretained(this)));
+ }
}
if (!success)
- ResetContext3d();
+ client_ = NULL;
return success;
}
-void OutputSurface::ReleaseGL() {
- DCHECK(client_);
- DCHECK(context_provider_.get());
- client_->ReleaseGL();
- DCHECK(!context_provider_.get());
-}
-
-void OutputSurface::SetUpContext3d() {
- DCHECK(context_provider_.get());
- DCHECK(client_);
-
- context_provider_->SetLostContextCallback(
- base::Bind(&OutputSurface::DidLoseOutputSurface,
- base::Unretained(this)));
- context_provider_->SetMemoryPolicyChangedCallback(
- base::Bind(&OutputSurface::SetMemoryPolicy,
- base::Unretained(this)));
-}
-
-void OutputSurface::ReleaseContextProvider() {
- DCHECK(client_);
- DCHECK(context_provider_.get());
- ResetContext3d();
-}
-
-void OutputSurface::ResetContext3d() {
- if (context_provider_.get()) {
- context_provider_->SetLostContextCallback(
- ContextProvider::LostContextCallback());
- context_provider_->SetMemoryPolicyChangedCallback(
- ContextProvider::MemoryPolicyChangedCallback());
- }
- context_provider_ = NULL;
-}
-
void OutputSurface::EnsureBackbuffer() {
if (software_device_)
software_device_->EnsureBackbuffer();
@@ -206,10 +184,9 @@ void OutputSurface::BindFramebuffer() {
}
void OutputSurface::PostSwapBuffersComplete() {
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&OutputSurface::OnSwapBuffersComplete,
- weak_ptr_factory_.GetWeakPtr()));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&OutputSurface::OnSwapBuffersComplete,
+ weak_ptr_factory_.GetWeakPtr()));
}
// We don't post tasks bound to the client directly since they might run
@@ -228,4 +205,8 @@ void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
client_->SetMemoryPolicy(policy);
}
+OverlayCandidateValidator* OutputSurface::GetOverlayCandidateValidator() const {
+ return nullptr;
+}
+
} // namespace cc
diff --git a/chromium/cc/output/output_surface.h b/chromium/cc/output/output_surface.h
index 0a0d456e78e..deaf97b4825 100644
--- a/chromium/cc/output/output_surface.h
+++ b/chromium/cc/output/output_surface.h
@@ -46,6 +46,11 @@ class CC_EXPORT OutputSurface {
DEFAULT_MAX_FRAMES_PENDING = 2
};
+ OutputSurface(const scoped_refptr<ContextProvider>& context_provider,
+ const scoped_refptr<ContextProvider>& worker_context_provider,
+ scoped_ptr<SoftwareOutputDevice> software_device);
+ OutputSurface(const scoped_refptr<ContextProvider>& context_provider,
+ const scoped_refptr<ContextProvider>& worker_context_provider);
explicit OutputSurface(
const scoped_refptr<ContextProvider>& context_provider);
@@ -60,14 +65,14 @@ class CC_EXPORT OutputSurface {
Capabilities()
: delegated_rendering(false),
max_frames_pending(0),
- deferred_gl_initialization(false),
draw_and_swap_full_viewport_every_frame(false),
adjust_deadline_for_parent(true),
uses_default_gl_framebuffer(true),
- flipped_output_surface(false) {}
+ flipped_output_surface(false),
+ can_force_reclaim_resources(false),
+ delegated_sync_points_required(true) {}
bool delegated_rendering;
int max_frames_pending;
- bool deferred_gl_initialization;
bool draw_and_swap_full_viewport_every_frame;
// This doesn't handle the <webview> case, but once BeginFrame is
// supported natively, we shouldn't need adjust_deadline_for_parent.
@@ -77,6 +82,12 @@ class CC_EXPORT OutputSurface {
bool uses_default_gl_framebuffer;
// Whether this OutputSurface is flipped or not.
bool flipped_output_surface;
+ // Whether ForceReclaimResources can be called to reclaim all resources
+ // from the OutputSurface.
+ bool can_force_reclaim_resources;
+ // True if sync points for resources are needed when swapping delegated
+ // frames.
+ bool delegated_sync_points_required;
};
const Capabilities& capabilities() const {
@@ -90,6 +101,9 @@ class CC_EXPORT OutputSurface {
// In the event of a lost context, the entire output surface should be
// recreated.
ContextProvider* context_provider() const { return context_provider_.get(); }
+ ContextProvider* worker_context_provider() const {
+ return worker_context_provider_.get();
+ }
SoftwareOutputDevice* software_device() const {
return software_device_.get();
}
@@ -100,17 +114,16 @@ class CC_EXPORT OutputSurface {
// thread.
virtual bool BindToClient(OutputSurfaceClient* client);
- // This is called by the compositor on the compositor thread inside ReleaseGL
- // in order to release the ContextProvider. Only used with
- // deferred_gl_initialization capability.
- void ReleaseContextProvider();
-
virtual void EnsureBackbuffer();
virtual void DiscardBackbuffer();
virtual void Reshape(const gfx::Size& size, float scale_factor);
virtual gfx::Size SurfaceSize() const;
+ // If supported, this causes a ReclaimResources for all resources that are
+ // currently in use.
+ virtual void ForceReclaimResources() {}
+
virtual void BindFramebuffer();
// The implementation may destroy or steal the contents of the CompositorFrame
@@ -125,36 +138,29 @@ class CC_EXPORT OutputSurface {
// processing should be stopped, or lowered in priority.
virtual void UpdateSmoothnessTakesPriority(bool prefer_smoothness) {}
- // Requests a BeginFrame notification from the output surface. The
- // notification will be delivered by calling
- // OutputSurfaceClient::BeginFrame until the callback is disabled.
- virtual void SetNeedsBeginFrame(bool enable) {}
-
bool HasClient() { return !!client_; }
// Get the class capable of informing cc of hardware overlay capability.
- OverlayCandidateValidator* overlay_candidate_validator() const {
- return overlay_candidate_validator_.get();
- }
+ virtual OverlayCandidateValidator* GetOverlayCandidateValidator() const;
void DidLoseOutputSurface();
void SetMemoryPolicy(const ManagedMemoryPolicy& policy);
+ // Support for a pull-model where draws are requested by the output surface.
+ //
+ // OutputSurface::Invalidate is called by the compositor to notify that
+ // there's new content.
+ virtual void Invalidate() {}
+
protected:
OutputSurfaceClient* client_;
- // Synchronously initialize context3d and enter hardware mode.
- // This can only supported in threaded compositing mode.
- bool InitializeAndSetContext3d(
- scoped_refptr<ContextProvider> context_provider);
- void ReleaseGL();
-
void PostSwapBuffersComplete();
struct OutputSurface::Capabilities capabilities_;
scoped_refptr<ContextProvider> context_provider_;
+ scoped_refptr<ContextProvider> worker_context_provider_;
scoped_ptr<SoftwareOutputDevice> software_device_;
- scoped_ptr<OverlayCandidateValidator> overlay_candidate_validator_;
gfx::Size surface_size_;
float device_scale_factor_;
@@ -173,9 +179,6 @@ class CC_EXPORT OutputSurface {
bool resourceless_software_draw);
private:
- void SetUpContext3d();
- void ResetContext3d();
-
bool external_stencil_test_enabled_;
base::WeakPtrFactory<OutputSurface> weak_ptr_factory_;
diff --git a/chromium/cc/output/output_surface_client.h b/chromium/cc/output/output_surface_client.h
index 99b174b2529..98010dc4337 100644
--- a/chromium/cc/output/output_surface_client.h
+++ b/chromium/cc/output/output_surface_client.h
@@ -9,7 +9,6 @@
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "cc/base/cc_export.h"
-#include "cc/output/begin_frame_args.h"
#include "cc/output/context_provider.h"
#include "ui/gfx/geometry/rect.h"
@@ -24,16 +23,9 @@ struct ManagedMemoryPolicy;
class CC_EXPORT OutputSurfaceClient {
public:
- // Called to synchronously re-initialize using the Context3D. Upon returning
- // the compositor should be able to draw using GL what was previously
- // committed.
- virtual void DeferredInitialize() = 0;
- // Must call OutputSurface::ReleaseContextProvider inside this call.
- virtual void ReleaseGL() = 0;
virtual void CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) = 0;
virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) = 0;
- virtual void BeginFrame(const BeginFrameArgs& args) = 0;
virtual void DidSwapBuffers() = 0;
virtual void DidSwapBuffersComplete() = 0;
virtual void ReclaimResources(const CompositorFrameAck* ack) = 0;
@@ -51,6 +43,8 @@ class CC_EXPORT OutputSurfaceClient {
// valid for the lifetime of the OutputSurfaceClient or until unregisted --
// use SetTreeActivationCallback(base::Closure()) to unregister it.
virtual void SetTreeActivationCallback(const base::Closure& callback) = 0;
+ // This allows the output surface to ask it's client for a draw.
+ virtual void OnDraw() = 0;
protected:
virtual ~OutputSurfaceClient() {}
diff --git a/chromium/cc/output/output_surface_unittest.cc b/chromium/cc/output/output_surface_unittest.cc
index b1f4149196d..3b027027729 100644
--- a/chromium/cc/output/output_surface_unittest.cc
+++ b/chromium/cc/output/output_surface_unittest.cc
@@ -25,6 +25,10 @@ class TestOutputSurface : public OutputSurface {
explicit TestOutputSurface(scoped_refptr<ContextProvider> context_provider)
: OutputSurface(context_provider) {}
+ TestOutputSurface(scoped_refptr<ContextProvider> context_provider,
+ scoped_refptr<ContextProvider> worker_context_provider)
+ : OutputSurface(worker_context_provider) {}
+
explicit TestOutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
: OutputSurface(software_device.Pass()) {}
@@ -37,22 +41,11 @@ class TestOutputSurface : public OutputSurface {
client_->DidSwapBuffersComplete();
}
- bool InitializeNewContext3d(
- scoped_refptr<ContextProvider> new_context_provider) {
- return InitializeAndSetContext3d(new_context_provider);
- }
-
- using OutputSurface::ReleaseGL;
-
void CommitVSyncParametersForTesting(base::TimeTicks timebase,
base::TimeDelta interval) {
CommitVSyncParameters(timebase, interval);
}
- void BeginFrameForTesting() {
- client_->BeginFrame(CreateExpiredBeginFrameArgsForTesting());
- }
-
void DidSwapBuffersForTesting() { client_->DidSwapBuffers(); }
void OnSwapBuffersCompleteForTesting() { client_->DidSwapBuffersComplete(); }
@@ -100,7 +93,25 @@ TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) {
FakeOutputSurfaceClient client;
EXPECT_TRUE(output_surface.BindToClient(&client));
EXPECT_TRUE(output_surface.HasClient());
- EXPECT_FALSE(client.deferred_initialize_called());
+
+ // Verify DidLoseOutputSurface callback is hooked up correctly.
+ EXPECT_FALSE(client.did_lose_output_surface_called());
+ output_surface.context_provider()->ContextGL()->LoseContextCHROMIUM(
+ GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
+ output_surface.context_provider()->ContextGL()->Flush();
+ EXPECT_TRUE(client.did_lose_output_surface_called());
+}
+
+TEST(OutputSurfaceTest, ClientPointerIndicatesWorkerBindToClientSuccess) {
+ scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
+ scoped_refptr<TestContextProvider> worker_provider =
+ TestContextProvider::Create();
+ TestOutputSurface output_surface(provider, worker_provider);
+ EXPECT_FALSE(output_surface.HasClient());
+
+ FakeOutputSurfaceClient client;
+ EXPECT_TRUE(output_surface.BindToClient(&client));
+ EXPECT_TRUE(output_surface.HasClient());
// Verify DidLoseOutputSurface callback is hooked up correctly.
EXPECT_FALSE(client.did_lose_output_surface_called());
@@ -125,56 +136,21 @@ TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) {
EXPECT_FALSE(output_surface.HasClient());
}
-class OutputSurfaceTestInitializeNewContext3d : public ::testing::Test {
- public:
- OutputSurfaceTestInitializeNewContext3d()
- : context_provider_(TestContextProvider::Create()),
- output_surface_(
- scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)),
- client_(&output_surface_) {}
-
- protected:
- void BindOutputSurface() {
- EXPECT_TRUE(output_surface_.BindToClient(&client_));
- EXPECT_TRUE(output_surface_.HasClient());
- }
-
- void InitializeNewContextExpectFail() {
- EXPECT_FALSE(output_surface_.InitializeNewContext3d(context_provider_));
- EXPECT_TRUE(output_surface_.HasClient());
-
- EXPECT_FALSE(output_surface_.context_provider());
- EXPECT_TRUE(output_surface_.software_device());
- }
-
- scoped_refptr<TestContextProvider> context_provider_;
- TestOutputSurface output_surface_;
- FakeOutputSurfaceClient client_;
-};
-
-TEST_F(OutputSurfaceTestInitializeNewContext3d, Success) {
- BindOutputSurface();
- EXPECT_FALSE(client_.deferred_initialize_called());
-
- EXPECT_TRUE(output_surface_.InitializeNewContext3d(context_provider_));
- EXPECT_TRUE(client_.deferred_initialize_called());
- EXPECT_EQ(context_provider_.get(), output_surface_.context_provider());
-
- EXPECT_FALSE(client_.did_lose_output_surface_called());
- context_provider_->ContextGL()->LoseContextCHROMIUM(
- GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
- context_provider_->ContextGL()->Flush();
- EXPECT_TRUE(client_.did_lose_output_surface_called());
+TEST(OutputSurfaceTest, ClientPointerIndicatesWorkerBindToClientFailure) {
+ scoped_refptr<TestContextProvider> context_provider =
+ TestContextProvider::Create();
+ scoped_refptr<TestContextProvider> worker_context_provider =
+ TestContextProvider::Create();
- output_surface_.ReleaseGL();
- EXPECT_FALSE(output_surface_.context_provider());
-}
+ // Lose the context so BindToClient fails.
+ worker_context_provider->UnboundTestContext3d()->set_context_lost(true);
-TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) {
- BindOutputSurface();
+ TestOutputSurface output_surface(context_provider, worker_context_provider);
+ EXPECT_FALSE(output_surface.HasClient());
- context_provider_->UnboundTestContext3d()->set_context_lost(true);
- InitializeNewContextExpectFail();
+ FakeOutputSurfaceClient client;
+ EXPECT_FALSE(output_surface.BindToClient(&client));
+ EXPECT_FALSE(output_surface.HasClient());
}
TEST(OutputSurfaceTest, MemoryAllocation) {
diff --git a/chromium/cc/output/overlay_candidate.cc b/chromium/cc/output/overlay_candidate.cc
index 41682539a58..7a825707d1d 100644
--- a/chromium/cc/output/overlay_candidate.cc
+++ b/chromium/cc/output/overlay_candidate.cc
@@ -5,11 +5,35 @@
#include "cc/output/overlay_candidate.h"
#include <algorithm>
+#include <limits>
#include "base/logging.h"
+#include "cc/base/math_util.h"
#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/vector3d_f.h"
namespace cc {
+namespace {
+// Tolerance for considering axis vector elements to be zero.
+const SkMScalar kEpsilon = std::numeric_limits<float>::epsilon();
+
+enum Axis { NONE, AXIS_POS_X, AXIS_NEG_X, AXIS_POS_Y, AXIS_NEG_Y };
+
+Axis VectorToAxis(const gfx::Vector3dF& vec) {
+ if (std::abs(vec.z()) > kEpsilon)
+ return NONE;
+ const bool x_zero = (std::abs(vec.x()) <= kEpsilon);
+ const bool y_zero = (std::abs(vec.y()) <= kEpsilon);
+ if (x_zero && !y_zero)
+ return (vec.y() > 0) ? AXIS_POS_Y : AXIS_NEG_Y;
+ else if (y_zero && !x_zero)
+ return (vec.x() > 0) ? AXIS_POS_X : AXIS_NEG_X;
+ else
+ return NONE;
+}
+
+} // namespace
+
OverlayCandidate::OverlayCandidate()
: transform(gfx::OVERLAY_TRANSFORM_NONE),
format(RGBA_8888),
@@ -23,22 +47,141 @@ OverlayCandidate::~OverlayCandidate() {}
// static
gfx::OverlayTransform OverlayCandidate::GetOverlayTransform(
const gfx::Transform& quad_transform,
- bool flipped) {
- if (!quad_transform.IsIdentityOrTranslation())
+ bool y_flipped) {
+ if (!quad_transform.Preserves2dAxisAlignment()) {
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+
+ gfx::Vector3dF x_axis = MathUtil::GetXAxis(quad_transform);
+ gfx::Vector3dF y_axis = MathUtil::GetYAxis(quad_transform);
+ if (y_flipped) {
+ y_axis.Scale(-1);
+ }
+
+ Axis x_to = VectorToAxis(x_axis);
+ Axis y_to = VectorToAxis(y_axis);
+
+ if (x_to == AXIS_POS_X && y_to == AXIS_POS_Y)
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ else if (x_to == AXIS_NEG_X && y_to == AXIS_POS_Y)
+ return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
+ else if (x_to == AXIS_POS_X && y_to == AXIS_NEG_Y)
+ return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
+ else if (x_to == AXIS_NEG_Y && y_to == AXIS_POS_X)
+ return gfx::OVERLAY_TRANSFORM_ROTATE_270;
+ else if (x_to == AXIS_NEG_X && y_to == AXIS_NEG_Y)
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ else if (x_to == AXIS_POS_Y && y_to == AXIS_NEG_X)
+ return gfx::OVERLAY_TRANSFORM_ROTATE_90;
+ else
return gfx::OVERLAY_TRANSFORM_INVALID;
+}
- return flipped ? gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL
- : gfx::OVERLAY_TRANSFORM_NONE;
+// static
+gfx::OverlayTransform OverlayCandidate::ModifyTransform(
+ gfx::OverlayTransform in,
+ gfx::OverlayTransform delta) {
+ // There are 8 different possible transforms. We can characterize these
+ // by looking at where the origin moves and the direction the horizontal goes.
+ // (TL=top-left, BR=bottom-right, H=horizontal, V=vertical).
+ // NONE: TL, H
+ // FLIP_VERTICAL: BL, H
+ // FLIP_HORIZONTAL: TR, H
+ // ROTATE_90: TR, V
+ // ROTATE_180: BR, H
+ // ROTATE_270: BL, V
+ // Missing transforms: TL, V & BR, V
+ // Basic combinations:
+ // Flip X & Y -> Rotate 180 (TL,H -> TR,H -> BR,H or TL,H -> BL,H -> BR,H)
+ // Flip X or Y + Rotate 180 -> other flip (eg, TL,H -> TR,H -> BL,H)
+ // Rotate + Rotate simply adds values.
+ // Rotate 90/270 + flip is invalid because we can only have verticals with
+ // the origin in TR or BL.
+ if (delta == gfx::OVERLAY_TRANSFORM_NONE)
+ return in;
+ switch (in) {
+ case gfx::OVERLAY_TRANSFORM_NONE:
+ return delta;
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_270;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_270;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_90;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_90;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
}
// static
-gfx::Rect OverlayCandidate::GetOverlayRect(const gfx::Transform& quad_transform,
- const gfx::Rect& rect) {
- DCHECK(quad_transform.IsIdentityOrTranslation());
+gfx::RectF OverlayCandidate::GetOverlayRect(
+ const gfx::Transform& quad_transform,
+ const gfx::Rect& rect) {
+ DCHECK(quad_transform.Preserves2dAxisAlignment());
gfx::RectF float_rect(rect);
quad_transform.TransformRect(&float_rect);
- return gfx::ToNearestRect(float_rect);
+ return float_rect;
}
} // namespace cc
diff --git a/chromium/cc/output/overlay_candidate.h b/chromium/cc/output/overlay_candidate.h
index 9a1e534e5f2..36396358e65 100644
--- a/chromium/cc/output/overlay_candidate.h
+++ b/chromium/cc/output/overlay_candidate.h
@@ -19,9 +19,13 @@ class CC_EXPORT OverlayCandidate {
public:
static gfx::OverlayTransform GetOverlayTransform(
const gfx::Transform& quad_transform,
- bool flipped);
- static gfx::Rect GetOverlayRect(const gfx::Transform& quad_transform,
- const gfx::Rect& rect);
+ bool y_flipped);
+ // Apply transform |delta| to |in| and return the resulting transform,
+ // or OVERLAY_TRANSFORM_INVALID.
+ static gfx::OverlayTransform ModifyTransform(gfx::OverlayTransform in,
+ gfx::OverlayTransform delta);
+ static gfx::RectF GetOverlayRect(const gfx::Transform& quad_transform,
+ const gfx::Rect& rect);
OverlayCandidate();
~OverlayCandidate();
@@ -30,8 +34,9 @@ class CC_EXPORT OverlayCandidate {
gfx::OverlayTransform transform;
// Format of the buffer to composite.
ResourceFormat format;
- // Rect on the display to position the overlay to.
- gfx::Rect display_rect;
+ // Rect on the display to position the overlay to. Implementer must convert
+ // to integer coordinates if setting |overlay_handled| to true.
+ gfx::RectF display_rect;
// Crop within the buffer to be placed inside |display_rect|.
gfx::RectF uv_rect;
// Texture resource to present in an overlay.
diff --git a/chromium/cc/output/overlay_candidate_validator.h b/chromium/cc/output/overlay_candidate_validator.h
index 036eafc4d1f..60647316f8b 100644
--- a/chromium/cc/output/overlay_candidate_validator.h
+++ b/chromium/cc/output/overlay_candidate_validator.h
@@ -19,7 +19,9 @@ class CC_EXPORT OverlayCandidateValidator {
// A list of possible overlay candidates is presented to this function.
// The expected result is that those candidates that can be in a separate
// plane are marked with |overlay_handled| set to true, otherwise they are
- // to be traditionally composited.
+ // to be traditionally composited. Candidates with |overlay_handled| set to
+ // true must also have their |display_rect| converted to integer
+ // coordinates if necessary.
virtual void CheckOverlaySupport(OverlayCandidateList* surfaces) = 0;
virtual ~OverlayCandidateValidator() {}
diff --git a/chromium/cc/output/overlay_processor.cc b/chromium/cc/output/overlay_processor.cc
index 61c4ebbef91..0f5ec560dd6 100644
--- a/chromium/cc/output/overlay_processor.cc
+++ b/chromium/cc/output/overlay_processor.cc
@@ -6,6 +6,7 @@
#include "cc/output/output_surface.h"
#include "cc/output/overlay_strategy_single_on_top.h"
+#include "cc/output/overlay_strategy_underlay.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/transform.h"
@@ -21,10 +22,12 @@ void OverlayProcessor::Initialize() {
return;
OverlayCandidateValidator* candidates =
- surface_->overlay_candidate_validator();
+ surface_->GetOverlayCandidateValidator();
if (candidates) {
strategies_.push_back(scoped_ptr<Strategy>(
new OverlayStrategySingleOnTop(candidates, resource_provider_)));
+ strategies_.push_back(scoped_ptr<Strategy>(
+ new OverlayStrategyUnderlay(candidates, resource_provider_)));
}
}
diff --git a/chromium/cc/output/overlay_strategy_common.cc b/chromium/cc/output/overlay_strategy_common.cc
new file mode 100644
index 00000000000..be352a5130a
--- /dev/null
+++ b/chromium/cc/output/overlay_strategy_common.cc
@@ -0,0 +1,136 @@
+// 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.
+
+#include "cc/output/overlay_strategy_common.h"
+
+#include <limits>
+
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/stream_video_draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "ui/gfx/geometry/point3_f.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+
+OverlayStrategyCommon::OverlayStrategyCommon(
+ OverlayCandidateValidator* capability_checker,
+ ResourceProvider* resource_provider)
+ : capability_checker_(capability_checker),
+ resource_provider_(resource_provider) {
+}
+
+OverlayStrategyCommon::~OverlayStrategyCommon() {
+}
+
+bool OverlayStrategyCommon::IsOverlayQuad(const DrawQuad* draw_quad) {
+ unsigned int resource_id;
+ switch (draw_quad->material) {
+ case DrawQuad::TEXTURE_CONTENT:
+ resource_id = TextureDrawQuad::MaterialCast(draw_quad)->resource_id;
+ break;
+ case DrawQuad::STREAM_VIDEO_CONTENT:
+ resource_id = StreamVideoDrawQuad::MaterialCast(draw_quad)->resource_id;
+ break;
+ default:
+ return false;
+ }
+ return resource_provider_->AllowOverlay(resource_id);
+}
+
+bool OverlayStrategyCommon::IsInvisibleQuad(const DrawQuad* draw_quad) {
+ if (draw_quad->material == DrawQuad::SOLID_COLOR) {
+ const SolidColorDrawQuad* solid_quad =
+ SolidColorDrawQuad::MaterialCast(draw_quad);
+ SkColor color = solid_quad->color;
+ float opacity = solid_quad->opacity();
+ float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
+ return solid_quad->ShouldDrawWithBlending() &&
+ alpha < std::numeric_limits<float>::epsilon();
+ }
+ return false;
+}
+
+bool OverlayStrategyCommon::GetTextureQuadInfo(const TextureDrawQuad& quad,
+ OverlayCandidate* quad_info) {
+ gfx::OverlayTransform overlay_transform =
+ OverlayCandidate::GetOverlayTransform(quad.quadTransform(),
+ quad.y_flipped);
+ if (quad.background_color != SK_ColorTRANSPARENT ||
+ quad.premultiplied_alpha ||
+ overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
+ return false;
+ quad_info->resource_id = quad.resource_id;
+ quad_info->transform = overlay_transform;
+ quad_info->uv_rect = BoundingRect(quad.uv_top_left, quad.uv_bottom_right);
+ return true;
+}
+
+bool OverlayStrategyCommon::GetVideoQuadInfo(const StreamVideoDrawQuad& quad,
+ OverlayCandidate* quad_info) {
+ gfx::OverlayTransform overlay_transform =
+ OverlayCandidate::GetOverlayTransform(quad.quadTransform(), false);
+ if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
+ return false;
+ if (!quad.matrix.IsScaleOrTranslation()) {
+ // We cannot handle anything other than scaling & translation for texture
+ // coordinates yet.
+ return false;
+ }
+ quad_info->resource_id = quad.resource_id;
+ quad_info->transform = overlay_transform;
+
+ gfx::Point3F uv0 = gfx::Point3F(0, 0, 0);
+ gfx::Point3F uv1 = gfx::Point3F(1, 1, 0);
+ quad.matrix.TransformPoint(&uv0);
+ quad.matrix.TransformPoint(&uv1);
+ gfx::Vector3dF delta = uv1 - uv0;
+ if (delta.x() < 0) {
+ quad_info->transform = OverlayCandidate::ModifyTransform(
+ quad_info->transform, gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL);
+ float x0 = uv0.x();
+ uv0.set_x(uv1.x());
+ uv1.set_x(x0);
+ delta.set_x(-delta.x());
+ }
+
+ if (delta.y() < 0) {
+ // In this situation, uv0y < uv1y. Since we overlay inverted, a request
+ // to invert the source texture means we can just output the texture
+ // normally and it will be correct.
+ quad_info->uv_rect = gfx::RectF(uv0.x(), uv1.y(), delta.x(), -delta.y());
+ } else {
+ quad_info->transform = OverlayCandidate::ModifyTransform(
+ quad_info->transform, gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL);
+ quad_info->uv_rect = gfx::RectF(uv0.x(), uv0.y(), delta.x(), delta.y());
+ }
+ return true;
+}
+
+bool OverlayStrategyCommon::GetCandidateQuadInfo(const DrawQuad& draw_quad,
+ OverlayCandidate* quad_info) {
+ // All quad checks.
+ if (draw_quad.needs_blending || draw_quad.shared_quad_state->opacity != 1.f ||
+ draw_quad.shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode)
+ return false;
+
+ if (draw_quad.material == DrawQuad::TEXTURE_CONTENT) {
+ const TextureDrawQuad& quad = *TextureDrawQuad::MaterialCast(&draw_quad);
+ if (!GetTextureQuadInfo(quad, quad_info))
+ return false;
+ } else if (draw_quad.material == DrawQuad::STREAM_VIDEO_CONTENT) {
+ const StreamVideoDrawQuad& quad =
+ *StreamVideoDrawQuad::MaterialCast(&draw_quad);
+ if (!GetVideoQuadInfo(quad, quad_info))
+ return false;
+ }
+
+ quad_info->format = RGBA_8888;
+ quad_info->display_rect = OverlayCandidate::GetOverlayRect(
+ draw_quad.quadTransform(), draw_quad.rect);
+ return true;
+}
+
+} // namespace cc
diff --git a/chromium/cc/output/overlay_strategy_common.h b/chromium/cc/output/overlay_strategy_common.h
new file mode 100644
index 00000000000..515a106e782
--- /dev/null
+++ b/chromium/cc/output/overlay_strategy_common.h
@@ -0,0 +1,49 @@
+// 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_OUTPUT_OVERLAY_STRATEGY_COMMON_H_
+#define CC_OUTPUT_OVERLAY_STRATEGY_COMMON_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/output/overlay_candidate.h"
+#include "cc/output/overlay_processor.h"
+
+namespace cc {
+class OverlayCandidateValidator;
+class StreamVideoDrawQuad;
+class TextureDrawQuad;
+class OverlayCandidate;
+
+class CC_EXPORT OverlayStrategyCommon : public OverlayProcessor::Strategy {
+ public:
+ OverlayStrategyCommon(OverlayCandidateValidator* capability_checker,
+ ResourceProvider* resource_provider);
+ ~OverlayStrategyCommon() override;
+
+ protected:
+ bool GetCandidateQuadInfo(const DrawQuad& draw_quad,
+ OverlayCandidate* quad_info);
+
+ // Returns true if |draw_quad| will not block quads underneath from becoming
+ // an overlay.
+ bool IsInvisibleQuad(const DrawQuad* draw_quad);
+
+ // Returns true if |draw_quad| is of a known quad type and contains an
+ // overlayable resource.
+ bool IsOverlayQuad(const DrawQuad* draw_quad);
+
+ bool GetTextureQuadInfo(const TextureDrawQuad& quad,
+ OverlayCandidate* quad_info);
+ bool GetVideoQuadInfo(const StreamVideoDrawQuad& quad,
+ OverlayCandidate* quad_info);
+
+ OverlayCandidateValidator* capability_checker_;
+ ResourceProvider* resource_provider_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OverlayStrategyCommon);
+};
+} // namespace cc
+
+#endif // CC_OUTPUT_OVERLAY_STRATEGY_COMMON_H_
diff --git a/chromium/cc/output/overlay_strategy_single_on_top.cc b/chromium/cc/output/overlay_strategy_single_on_top.cc
index 98d77ad4ca1..65b039e6052 100644
--- a/chromium/cc/output/overlay_strategy_single_on_top.cc
+++ b/chromium/cc/output/overlay_strategy_single_on_top.cc
@@ -4,18 +4,17 @@
#include "cc/output/overlay_strategy_single_on_top.h"
+#include <limits>
+
#include "cc/quads/draw_quad.h"
-#include "cc/quads/texture_draw_quad.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/transform.h"
namespace cc {
OverlayStrategySingleOnTop::OverlayStrategySingleOnTop(
OverlayCandidateValidator* capability_checker,
ResourceProvider* resource_provider)
- : capability_checker_(capability_checker),
- resource_provider_(resource_provider) {}
+ : OverlayStrategyCommon(capability_checker, resource_provider) {
+}
bool OverlayStrategySingleOnTop::Attempt(
RenderPassList* render_passes_in_draw_order,
@@ -27,15 +26,12 @@ bool OverlayStrategySingleOnTop::Attempt(
RenderPass* root_render_pass = render_passes_in_draw_order->back();
DCHECK(root_render_pass);
+ OverlayCandidate candidate;
QuadList& quad_list = root_render_pass->quad_list;
auto candidate_iterator = quad_list.end();
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
const DrawQuad* draw_quad = *it;
- if (draw_quad->material == DrawQuad::TEXTURE_CONTENT) {
- const TextureDrawQuad& quad = *TextureDrawQuad::MaterialCast(draw_quad);
- if (!resource_provider_->AllowOverlay(quad.resource_id)) {
- continue;
- }
+ if (IsOverlayQuad(draw_quad)) {
// Check that no prior quads overlap it.
bool intersects = false;
gfx::RectF rect = draw_quad->rect;
@@ -44,12 +40,12 @@ bool OverlayStrategySingleOnTop::Attempt(
++overlap_iter) {
gfx::RectF overlap_rect = overlap_iter->rect;
overlap_iter->quadTransform().TransformRect(&overlap_rect);
- if (rect.Intersects(overlap_rect)) {
+ if (rect.Intersects(overlap_rect) && !IsInvisibleQuad(*overlap_iter)) {
intersects = true;
break;
}
}
- if (intersects)
+ if (intersects || !GetCandidateQuadInfo(*draw_quad, &candidate))
continue;
candidate_iterator = it;
break;
@@ -57,34 +53,14 @@ bool OverlayStrategySingleOnTop::Attempt(
}
if (candidate_iterator == quad_list.end())
return false;
- const TextureDrawQuad& quad =
- *TextureDrawQuad::MaterialCast(*candidate_iterator);
-
- // Simple quads only.
- gfx::OverlayTransform overlay_transform =
- OverlayCandidate::GetOverlayTransform(quad.quadTransform(), quad.flipped);
- if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID ||
- !quad.quadTransform().IsIdentityOrTranslation() || quad.needs_blending ||
- quad.shared_quad_state->opacity != 1.f ||
- quad.shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode ||
- quad.premultiplied_alpha || quad.background_color != SK_ColorTRANSPARENT)
- return false;
// Add our primary surface.
OverlayCandidateList candidates;
OverlayCandidate main_image;
main_image.display_rect = root_render_pass->output_rect;
- main_image.format = RGBA_8888;
candidates.push_back(main_image);
// Add the overlay.
- OverlayCandidate candidate;
- candidate.transform = overlay_transform;
- candidate.display_rect =
- OverlayCandidate::GetOverlayRect(quad.quadTransform(), quad.rect);
- candidate.uv_rect = BoundingRect(quad.uv_top_left, quad.uv_bottom_right);
- candidate.format = RGBA_8888;
- candidate.resource_id = quad.resource_id;
candidate.plane_z_order = 1;
candidates.push_back(candidate);
diff --git a/chromium/cc/output/overlay_strategy_single_on_top.h b/chromium/cc/output/overlay_strategy_single_on_top.h
index e5518cc5c9b..eeecd32fa4c 100644
--- a/chromium/cc/output/overlay_strategy_single_on_top.h
+++ b/chromium/cc/output/overlay_strategy_single_on_top.h
@@ -10,12 +10,14 @@
#include "cc/base/cc_export.h"
#include "cc/output/overlay_candidate.h"
#include "cc/output/overlay_processor.h"
+#include "cc/output/overlay_strategy_common.h"
#include "cc/quads/render_pass.h"
namespace cc {
-class OverlayCandidateValidator;
+class StreamVideoDrawQuad;
+class TextureDrawQuad;
-class CC_EXPORT OverlayStrategySingleOnTop : public OverlayProcessor::Strategy {
+class CC_EXPORT OverlayStrategySingleOnTop : public OverlayStrategyCommon {
public:
OverlayStrategySingleOnTop(OverlayCandidateValidator* capability_checker,
ResourceProvider* resource_provider);
@@ -23,8 +25,6 @@ class CC_EXPORT OverlayStrategySingleOnTop : public OverlayProcessor::Strategy {
OverlayCandidateList* candidate_list) override;
private:
- OverlayCandidateValidator* capability_checker_;
- ResourceProvider* resource_provider_;
DISALLOW_COPY_AND_ASSIGN(OverlayStrategySingleOnTop);
};
diff --git a/chromium/cc/output/overlay_strategy_underlay.cc b/chromium/cc/output/overlay_strategy_underlay.cc
new file mode 100644
index 00000000000..631ce03d95a
--- /dev/null
+++ b/chromium/cc/output/overlay_strategy_underlay.cc
@@ -0,0 +1,69 @@
+// Copyright 2014 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/output/overlay_strategy_underlay.h"
+
+#include "cc/quads/draw_quad.h"
+#include "cc/quads/solid_color_draw_quad.h"
+
+namespace cc {
+
+OverlayStrategyUnderlay::OverlayStrategyUnderlay(
+ OverlayCandidateValidator* capability_checker,
+ ResourceProvider* resource_provider)
+ : OverlayStrategyCommon(capability_checker, resource_provider) {
+}
+
+bool OverlayStrategyUnderlay::Attempt(
+ RenderPassList* render_passes_in_draw_order,
+ OverlayCandidateList* candidate_list) {
+ if (!capability_checker_)
+ return false;
+
+ RenderPass* root_render_pass = render_passes_in_draw_order->back();
+ DCHECK(root_render_pass);
+
+ OverlayCandidate candidate;
+ QuadList& quad_list = root_render_pass->quad_list;
+ auto candidate_iterator = quad_list.end();
+ for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
+ if (IsOverlayQuad(*it) && GetCandidateQuadInfo(**it, &candidate)) {
+ candidate_iterator = it;
+ break;
+ }
+ }
+ if (candidate_iterator == quad_list.end())
+ return false;
+
+ // Add our primary surface.
+ OverlayCandidateList candidates;
+ OverlayCandidate main_image;
+ main_image.display_rect = root_render_pass->output_rect;
+ candidates.push_back(main_image);
+
+ // Add the overlay.
+ candidate.plane_z_order = -1;
+ candidates.push_back(candidate);
+
+ // Check for support.
+ capability_checker_->CheckOverlaySupport(&candidates);
+
+ // If the candidate can be handled by an overlay, create a pass for it. We
+ // need to switch out the video quad with a black transparent one.
+ if (candidates[1].overlay_handled) {
+ const SharedQuadState* shared_quad_state =
+ candidate_iterator->shared_quad_state;
+ gfx::Rect rect = candidate_iterator->visible_rect;
+ SolidColorDrawQuad* replacement =
+ quad_list.ReplaceExistingElement<SolidColorDrawQuad>(
+ candidate_iterator);
+ replacement->SetAll(shared_quad_state, rect, rect, rect, false,
+ SK_ColorTRANSPARENT, true);
+ candidate_list->swap(candidates);
+ return true;
+ }
+ return false;
+}
+
+} // namespace cc
diff --git a/chromium/cc/output/overlay_strategy_underlay.h b/chromium/cc/output/overlay_strategy_underlay.h
new file mode 100644
index 00000000000..881e170535f
--- /dev/null
+++ b/chromium/cc/output/overlay_strategy_underlay.h
@@ -0,0 +1,32 @@
+// Copyright 2014 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_OUTPUT_OVERLAY_STRATEGY_UNDERLAY_H_
+#define CC_OUTPUT_OVERLAY_STRATEGY_UNDERLAY_H_
+
+#include "cc/output/overlay_strategy_common.h"
+
+namespace cc {
+class StreamVideoDrawQuad;
+class TextureDrawQuad;
+
+// The underlay strategy looks for a video quad without regard to quads above
+// it. The video is "underlaid" through a black transparent quad substituted
+// for the video quad. The overlay content can then be blended in by the
+// hardware under the the scene. This is only valid for overlay contents that
+// are fully opaque.
+class CC_EXPORT OverlayStrategyUnderlay : public OverlayStrategyCommon {
+ public:
+ OverlayStrategyUnderlay(OverlayCandidateValidator* capability_checker,
+ ResourceProvider* resource_provider);
+ bool Attempt(RenderPassList* render_passes_in_draw_order,
+ OverlayCandidateList* candidate_list) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OverlayStrategyUnderlay);
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_OVERLAY_STRATEGY_UNDERLAY_H_
diff --git a/chromium/cc/output/overlay_unittest.cc b/chromium/cc/output/overlay_unittest.cc
index 99192c8ec43..c9a2ae0c19a 100644
--- a/chromium/cc/output/overlay_unittest.cc
+++ b/chromium/cc/output/overlay_unittest.cc
@@ -3,14 +3,17 @@
// found in the LICENSE file.
#include "cc/base/scoped_ptr_vector.h"
+#include "cc/output/compositor_frame_metadata.h"
#include "cc/output/gl_renderer.h"
#include "cc/output/output_surface.h"
#include "cc/output/output_surface_client.h"
#include "cc/output/overlay_candidate_validator.h"
#include "cc/output/overlay_processor.h"
#include "cc/output/overlay_strategy_single_on_top.h"
+#include "cc/output/overlay_strategy_underlay.h"
#include "cc/quads/checkerboard_draw_quad.h"
#include "cc/quads/render_pass.h"
+#include "cc/quads/stream_video_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/texture_mailbox.h"
@@ -32,6 +35,16 @@ const gfx::Rect kOverlayTopLeftRect(0, 0, 64, 64);
const gfx::Rect kOverlayBottomRightRect(64, 64, 64, 64);
const gfx::PointF kUVTopLeft(0.1f, 0.2f);
const gfx::PointF kUVBottomRight(1.0f, 1.0f);
+const gfx::Transform kNormalTransform =
+ gfx::Transform(0.9f, 0, 0, 0.8f, 0.1f, 0.2f); // x,y -> x,y.
+const gfx::Transform kXMirrorTransform =
+ gfx::Transform(-0.9f, 0, 0, 0.8f, 1.0f, 0.2f); // x,y -> 1-x,y.
+const gfx::Transform kYMirrorTransform =
+ gfx::Transform(0.9f, 0, 0, -0.8f, 0.1f, 1.0f); // x,y -> x,1-y.
+const gfx::Transform kBothMirrorTransform =
+ gfx::Transform(-0.9f, 0, 0, -0.8f, 1.0f, 1.0f); // x,y -> 1-x,1-y.
+const gfx::Transform kSwapTransform =
+ gfx::Transform(0, 1, 1, 0, 0, 0); // x,y -> y,x.
void MailboxReleased(unsigned sync_point,
bool lost_resource,
@@ -48,39 +61,39 @@ void SingleOverlayValidator::CheckOverlaySupport(
ASSERT_EQ(2U, surfaces->size());
OverlayCandidate& candidate = surfaces->back();
- if (candidate.display_rect.width() == 64)
+ if (candidate.display_rect.width() == 64) {
EXPECT_EQ(kOverlayBottomRightRect, candidate.display_rect);
- else
- EXPECT_EQ(kOverlayRect, candidate.display_rect);
+ } else {
+ EXPECT_NEAR(kOverlayRect.x(), candidate.display_rect.x(), 0.01f);
+ EXPECT_NEAR(kOverlayRect.y(), candidate.display_rect.y(), 0.01f);
+ EXPECT_NEAR(kOverlayRect.width(), candidate.display_rect.width(), 0.01f);
+ EXPECT_NEAR(kOverlayRect.height(), candidate.display_rect.height(), 0.01f);
+ }
EXPECT_EQ(BoundingRect(kUVTopLeft, kUVBottomRight).ToString(),
candidate.uv_rect.ToString());
candidate.overlay_handled = true;
}
+template <typename OverlayStrategyType>
class SingleOverlayProcessor : public OverlayProcessor {
public:
SingleOverlayProcessor(OutputSurface* surface,
- ResourceProvider* resource_provider);
+ ResourceProvider* resource_provider)
+ : OverlayProcessor(surface, resource_provider) {
+ EXPECT_EQ(surface, surface_);
+ EXPECT_EQ(resource_provider, resource_provider_);
+ }
+
// Virtual to allow testing different strategies.
- void Initialize() override;
+ void Initialize() override {
+ OverlayCandidateValidator* candidates =
+ surface_->GetOverlayCandidateValidator();
+ ASSERT_TRUE(candidates != NULL);
+ strategies_.push_back(scoped_ptr<Strategy>(
+ new OverlayStrategyType(candidates, resource_provider_)));
+ }
};
-SingleOverlayProcessor::SingleOverlayProcessor(
- OutputSurface* surface,
- ResourceProvider* resource_provider)
- : OverlayProcessor(surface, resource_provider) {
- EXPECT_EQ(surface, surface_);
- EXPECT_EQ(resource_provider, resource_provider_);
-}
-
-void SingleOverlayProcessor::Initialize() {
- OverlayCandidateValidator* candidates =
- surface_->overlay_candidate_validator();
- ASSERT_TRUE(candidates != NULL);
- strategies_.push_back(scoped_ptr<Strategy>(
- new OverlayStrategySingleOnTop(candidates, resource_provider_)));
-}
-
class DefaultOverlayProcessor : public OverlayProcessor {
public:
DefaultOverlayProcessor(OutputSurface* surface,
@@ -108,6 +121,13 @@ class OverlayOutputSurface : public OutputSurface {
void InitWithSingleOverlayValidator() {
overlay_candidate_validator_.reset(new SingleOverlayValidator);
}
+
+ OverlayCandidateValidator* GetOverlayCandidateValidator() const override {
+ return overlay_candidate_validator_.get();
+ }
+
+ private:
+ scoped_ptr<OverlayCandidateValidator> overlay_candidate_validator_;
};
void OverlayOutputSurface::SwapBuffers(CompositorFrame* frame) {
@@ -145,6 +165,17 @@ ResourceProvider::ResourceId CreateResource(
mailbox, release_callback.Pass());
}
+SolidColorDrawQuad* CreateSolidColorQuadAt(
+ const SharedQuadState* shared_quad_state,
+ SkColor color,
+ RenderPass* render_pass,
+ const gfx::Rect& rect) {
+ SolidColorDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ quad->SetNew(shared_quad_state, rect, rect, color, false);
+ return quad;
+}
+
TextureDrawQuad* CreateCandidateQuadAt(ResourceProvider* resource_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
@@ -152,6 +183,7 @@ TextureDrawQuad* CreateCandidateQuadAt(ResourceProvider* resource_provider,
ResourceProvider::ResourceId resource_id = CreateResource(resource_provider);
bool premultiplied_alpha = false;
bool flipped = false;
+ bool nearest_neighbor = false;
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
TextureDrawQuad* overlay_quad =
@@ -166,7 +198,24 @@ TextureDrawQuad* CreateCandidateQuadAt(ResourceProvider* resource_provider,
kUVBottomRight,
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
+
+ return overlay_quad;
+}
+
+StreamVideoDrawQuad* CreateCandidateVideoQuadAt(
+ ResourceProvider* resource_provider,
+ const SharedQuadState* shared_quad_state,
+ RenderPass* render_pass,
+ const gfx::Rect& rect,
+ const gfx::Transform& transform) {
+ ResourceProvider::ResourceId resource_id = CreateResource(resource_provider);
+
+ StreamVideoDrawQuad* overlay_quad =
+ render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
+ overlay_quad->SetNew(shared_quad_state, rect, rect, rect, resource_id,
+ transform);
return overlay_quad;
}
@@ -179,13 +228,22 @@ TextureDrawQuad* CreateFullscreenCandidateQuad(
resource_provider, shared_quad_state, render_pass, kOverlayRect);
}
+StreamVideoDrawQuad* CreateFullscreenCandidateVideoQuad(
+ ResourceProvider* resource_provider,
+ const SharedQuadState* shared_quad_state,
+ RenderPass* render_pass,
+ const gfx::Transform& transform) {
+ return CreateCandidateVideoQuadAt(resource_provider, shared_quad_state,
+ render_pass, kOverlayRect, transform);
+}
+
void CreateCheckeredQuadAt(ResourceProvider* resource_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect) {
CheckerboardDrawQuad* checkerboard_quad =
render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
- checkerboard_quad->SetNew(shared_quad_state, rect, rect, SkColor());
+ checkerboard_quad->SetNew(shared_quad_state, rect, rect, SkColor(), 1.f);
}
void CreateFullscreenCheckeredQuad(ResourceProvider* resource_provider,
@@ -203,10 +261,10 @@ static void CompareRenderPassLists(const RenderPassList& expected_list,
RenderPass* actual = actual_list[i];
EXPECT_EQ(expected->id, actual->id);
- EXPECT_RECT_EQ(expected->output_rect, actual->output_rect);
+ EXPECT_EQ(expected->output_rect, actual->output_rect);
EXPECT_EQ(expected->transform_to_root_target,
actual->transform_to_root_target);
- EXPECT_RECT_EQ(expected->damage_rect, actual->damage_rect);
+ EXPECT_EQ(expected->damage_rect, actual->damage_rect);
EXPECT_EQ(expected->has_transparent_background,
actual->has_transparent_background);
@@ -228,10 +286,10 @@ static void CompareRenderPassLists(const RenderPassList& expected_list,
TEST(OverlayTest, NoOverlaysByDefault) {
scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
OverlayOutputSurface output_surface(provider);
- EXPECT_EQ(NULL, output_surface.overlay_candidate_validator());
+ EXPECT_EQ(NULL, output_surface.GetOverlayCandidateValidator());
output_surface.InitWithSingleOverlayValidator();
- EXPECT_TRUE(output_surface.overlay_candidate_validator() != NULL);
+ EXPECT_TRUE(output_surface.GetOverlayCandidateValidator() != NULL);
}
TEST(OverlayTest, OverlaysProcessorHasStrategy) {
@@ -240,7 +298,7 @@ TEST(OverlayTest, OverlaysProcessorHasStrategy) {
FakeOutputSurfaceClient client;
EXPECT_TRUE(output_surface.BindToClient(&client));
output_surface.InitWithSingleOverlayValidator();
- EXPECT_TRUE(output_surface.overlay_candidate_validator() != NULL);
+ EXPECT_TRUE(output_surface.GetOverlayCandidateValidator() != NULL);
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
@@ -250,17 +308,18 @@ TEST(OverlayTest, OverlaysProcessorHasStrategy) {
scoped_ptr<DefaultOverlayProcessor> overlay_processor(
new DefaultOverlayProcessor(&output_surface, resource_provider.get()));
overlay_processor->Initialize();
- EXPECT_GE(1U, overlay_processor->GetStrategyCount());
+ EXPECT_GE(2U, overlay_processor->GetStrategyCount());
}
-class SingleOverlayOnTopTest : public testing::Test {
+template <typename OverlayStrategyType>
+class OverlayTest : public testing::Test {
protected:
- virtual void SetUp() {
+ void SetUp() override {
provider_ = TestContextProvider::Create();
output_surface_.reset(new OverlayOutputSurface(provider_));
EXPECT_TRUE(output_surface_->BindToClient(&client_));
output_surface_->InitWithSingleOverlayValidator();
- EXPECT_TRUE(output_surface_->overlay_candidate_validator() != NULL);
+ EXPECT_TRUE(output_surface_->GetOverlayCandidateValidator() != NULL);
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
resource_provider_ = ResourceProvider::Create(output_surface_.get(),
@@ -271,7 +330,7 @@ class SingleOverlayOnTopTest : public testing::Test {
false,
1);
- overlay_processor_.reset(new SingleOverlayProcessor(
+ overlay_processor_.reset(new SingleOverlayProcessor<OverlayStrategyType>(
output_surface_.get(), resource_provider_.get()));
overlay_processor_->Initialize();
}
@@ -281,9 +340,12 @@ class SingleOverlayOnTopTest : public testing::Test {
FakeOutputSurfaceClient client_;
scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
- scoped_ptr<SingleOverlayProcessor> overlay_processor_;
+ scoped_ptr<SingleOverlayProcessor<OverlayStrategyType>> overlay_processor_;
};
+typedef OverlayTest<OverlayStrategySingleOnTop> SingleOverlayOnTopTest;
+typedef OverlayTest<OverlayStrategyUnderlay> UnderlayTest;
+
TEST_F(SingleOverlayOnTopTest, SuccessfullOverlay) {
scoped_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* original_quad =
@@ -482,13 +544,13 @@ TEST_F(SingleOverlayOnTopTest, RejectOpacity) {
EXPECT_EQ(0U, candidate_list.size());
}
-TEST_F(SingleOverlayOnTopTest, RejectTransform) {
+TEST_F(SingleOverlayOnTopTest, RejectNonAxisAlignedTransform) {
scoped_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(),
pass.get());
- pass->shared_quad_state_list.back()->content_to_target_transform.Scale(2.f,
- 2.f);
+ pass->shared_quad_state_list.back()
+ ->content_to_target_transform.RotateAboutXAxis(45.f);
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -498,6 +560,117 @@ TEST_F(SingleOverlayOnTopTest, RejectTransform) {
EXPECT_EQ(0U, candidate_list.size());
}
+TEST_F(SingleOverlayOnTopTest, AllowVerticalFlip) {
+ gfx::Rect rect = kOverlayRect;
+ rect.set_width(rect.width() / 2);
+ rect.Offset(0, -rect.height());
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(), rect);
+ pass->shared_quad_state_list.back()->content_to_target_transform.Scale(2.0f,
+ -1.0f);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ ASSERT_EQ(2U, candidate_list.size());
+ EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL,
+ candidate_list.back().transform);
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowHorizontalFlip) {
+ gfx::Rect rect = kOverlayRect;
+ rect.set_height(rect.height() / 2);
+ rect.Offset(-rect.width(), 0);
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(), rect);
+ pass->shared_quad_state_list.back()->content_to_target_transform.Scale(-1.0f,
+ 2.0f);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ ASSERT_EQ(2U, candidate_list.size());
+ EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL,
+ candidate_list.back().transform);
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) {
+ gfx::Rect rect = kOverlayRect;
+ rect.set_width(rect.width() / 2);
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(), rect);
+ pass->shared_quad_state_list.back()->content_to_target_transform.Scale(2.0f,
+ 1.0f);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, Allow90DegreeRotation) {
+ gfx::Rect rect = kOverlayRect;
+ rect.Offset(0, -rect.height());
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(), rect);
+ pass->shared_quad_state_list.back()
+ ->content_to_target_transform.RotateAboutZAxis(90.f);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ ASSERT_EQ(2U, candidate_list.size());
+ EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_90, candidate_list.back().transform);
+}
+
+TEST_F(SingleOverlayOnTopTest, Allow180DegreeRotation) {
+ gfx::Rect rect = kOverlayRect;
+ rect.Offset(-rect.width(), -rect.height());
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(), rect);
+ pass->shared_quad_state_list.back()
+ ->content_to_target_transform.RotateAboutZAxis(180.f);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ ASSERT_EQ(2U, candidate_list.size());
+ EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_180, candidate_list.back().transform);
+}
+
+TEST_F(SingleOverlayOnTopTest, Allow270DegreeRotation) {
+ gfx::Rect rect = kOverlayRect;
+ rect.Offset(-rect.width(), 0);
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(), rect);
+ pass->shared_quad_state_list.back()
+ ->content_to_target_transform.RotateAboutZAxis(270.f);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ ASSERT_EQ(2U, candidate_list.size());
+ EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_270, candidate_list.back().transform);
+}
+
TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) {
scoped_ptr<RenderPass> pass = CreateRenderPass();
CreateCheckeredQuadAt(resource_provider_.get(),
@@ -521,10 +694,214 @@ TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) {
EXPECT_EQ(2U, candidate_list.size());
}
+TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+ shared_state->opacity = 0.f;
+ CreateSolidColorQuadAt(shared_state, SK_ColorBLACK, pass.get(),
+ kOverlayBottomRightRect);
+ shared_state = pass->CreateAndAppendSharedQuadState();
+ shared_state->opacity = 1.f;
+ CreateCandidateQuadAt(resource_provider_.get(), shared_state, pass.get(),
+ kOverlayBottomRightRect);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ RenderPassList original_pass_list;
+ RenderPass::CopyAll(pass_list, &original_pass_list);
+
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(1U, pass_list.size());
+ EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateSolidColorQuadAt(pass->shared_quad_state_list.back(),
+ SK_ColorTRANSPARENT, pass.get(),
+ kOverlayBottomRightRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayBottomRightRect);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ RenderPassList original_pass_list;
+ RenderPass::CopyAll(pass_list, &original_pass_list);
+
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(1U, pass_list.size());
+ EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectOpaqueColorOnTop) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+ shared_state->opacity = 0.5f;
+ CreateSolidColorQuadAt(shared_state, SK_ColorBLACK, pass.get(),
+ kOverlayBottomRightRect);
+ shared_state = pass->CreateAndAppendSharedQuadState();
+ shared_state->opacity = 1.f;
+ CreateCandidateQuadAt(resource_provider_.get(), shared_state, pass.get(),
+ kOverlayBottomRightRect);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ RenderPassList original_pass_list;
+ RenderPass::CopyAll(pass_list, &original_pass_list);
+
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(1U, pass_list.size());
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectTransparentColorOnTopWithoutBlending) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+ CreateSolidColorQuadAt(shared_state, SK_ColorTRANSPARENT, pass.get(),
+ kOverlayBottomRightRect)->opaque_rect =
+ kOverlayBottomRightRect;
+ CreateCandidateQuadAt(resource_provider_.get(), shared_state, pass.get(),
+ kOverlayBottomRightRect);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ RenderPassList original_pass_list;
+ RenderPass::CopyAll(pass_list, &original_pass_list);
+
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(1U, pass_list.size());
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectVideoSwapTransform) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get(), kSwapTransform);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowVideoXMirrorTransform) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get(), kXMirrorTransform);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowVideoBothMirrorTransform) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get(), kBothMirrorTransform);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowVideoNormalTransform) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get(), kNormalTransform);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowVideoYMirrorTransform) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get(), kYMirrorTransform);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCheckeredQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get());
+ CreateCandidateQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayBottomRightRect);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(1U, pass_list.size());
+ ASSERT_EQ(2U, candidate_list.size());
+ EXPECT_EQ(0, candidate_list[0].plane_z_order);
+ EXPECT_EQ(-1, candidate_list[1].plane_z_order);
+ EXPECT_EQ(2U, pass_list[0]->quad_list.size());
+ // The overlay quad should have changed to a SOLID_COLOR quad.
+ EXPECT_EQ(pass_list[0]->quad_list.back()->material, DrawQuad::SOLID_COLOR);
+}
+
+TEST_F(UnderlayTest, AllowOnTop) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get());
+ pass->CreateAndAppendSharedQuadState()->opacity = 0.5f;
+ CreateFullscreenCheckeredQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get());
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(1U, pass_list.size());
+ ASSERT_EQ(2U, candidate_list.size());
+ EXPECT_EQ(0, candidate_list[0].plane_z_order);
+ EXPECT_EQ(-1, candidate_list[1].plane_z_order);
+ // The overlay quad should have changed to a SOLID_COLOR quad.
+ EXPECT_EQ(pass_list[0]->quad_list.front()->material, DrawQuad::SOLID_COLOR);
+}
+
class OverlayInfoRendererGL : public GLRenderer {
public:
OverlayInfoRendererGL(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider)
: GLRenderer(client,
@@ -535,11 +912,14 @@ class OverlayInfoRendererGL : public GLRenderer {
0),
expect_overlays_(false) {}
- MOCK_METHOD2(DoDrawQuad, void(DrawingFrame* frame, const DrawQuad* quad));
+ MOCK_METHOD3(DoDrawQuad,
+ void(DrawingFrame* frame,
+ const DrawQuad* quad,
+ const gfx::QuadF* draw_region));
using GLRenderer::BeginDrawingFrame;
- virtual void FinishDrawingFrame(DrawingFrame* frame) override {
+ void FinishDrawingFrame(DrawingFrame* frame) override {
GLRenderer::FinishDrawingFrame(frame);
if (!expect_overlays_) {
@@ -601,7 +981,7 @@ class GLRendererWithOverlaysTest : public testing::Test {
void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); }
- LayerTreeSettings settings_;
+ RendererSettings settings_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<OverlayOutputSurface> output_surface_;
FakeRendererClient renderer_client_;
@@ -635,7 +1015,7 @@ TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) {
// Candidate pass was taken out and extra skipped pass added,
// so only draw 2 quads.
- EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(2);
+ EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(2);
EXPECT_CALL(scheduler_,
Schedule(1,
gfx::OVERLAY_TRANSFORM_NONE,
@@ -650,10 +1030,10 @@ TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) {
Mock::VerifyAndClearExpectations(&scheduler_);
}
-TEST_F(GLRendererWithOverlaysTest, OccludedQuadDrawn) {
+TEST_F(GLRendererWithOverlaysTest, OccludedQuadInUnderlay) {
bool use_validator = true;
Init(use_validator);
- renderer_->set_expect_overlays(false);
+ renderer_->set_expect_overlays(true);
gfx::Rect viewport_rect(16, 16);
scoped_ptr<RenderPass> pass = CreateRenderPass();
@@ -672,9 +1052,12 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadDrawn) {
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
- // 3 quads in the pass, all should draw.
- EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3);
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0);
+ // Candidate quad should fail to be overlaid on top because of occlusion.
+ // Expect to be replaced with transparent hole quad and placed in underlay.
+ EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(3);
+ EXPECT_CALL(scheduler_,
+ Schedule(-1, gfx::OVERLAY_TRANSFORM_NONE, _, kOverlayRect,
+ BoundingRect(kUVTopLeft, kUVBottomRight))).Times(1);
renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false);
SwapBuffers();
@@ -706,7 +1089,7 @@ TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) {
pass_list.push_back(pass.Pass());
// Should see no overlays.
- EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3);
+ EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(3);
EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0);
renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false);
diff --git a/chromium/cc/output/program_binding.cc b/chromium/cc/output/program_binding.cc
index 9a5bc81ab46..7809e1085c7 100644
--- a/chromium/cc/output/program_binding.cc
+++ b/chromium/cc/output/program_binding.cc
@@ -4,7 +4,7 @@
#include "cc/output/program_binding.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/output/geometry_binding.h"
#include "gpu/command_buffer/client/gles2_interface.h"
diff --git a/chromium/cc/output/program_binding.h b/chromium/cc/output/program_binding.h
index 722c782de9d..1d5132bdaea 100644
--- a/chromium/cc/output/program_binding.h
+++ b/chromium/cc/output/program_binding.h
@@ -58,8 +58,24 @@ class ProgramBinding : public ProgramBindingBase {
void Initialize(ContextProvider* context_provider,
TexCoordPrecision precision,
+ SamplerType sampler) {
+ return Initialize(
+ context_provider, precision, sampler, BLEND_MODE_NONE, false);
+ }
+
+ void Initialize(ContextProvider* context_provider,
+ TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode) {
+ return Initialize(
+ context_provider, precision, sampler, blend_mode, false);
+ }
+
+ void Initialize(ContextProvider* context_provider,
+ TexCoordPrecision precision,
SamplerType sampler,
- BlendMode blend_mode = BlendModeNormal) {
+ BlendMode blend_mode,
+ bool mask_for_background) {
DCHECK(context_provider);
DCHECK(!initialized_);
@@ -67,6 +83,7 @@ class ProgramBinding : public ProgramBindingBase {
return;
fragment_shader_.set_blend_mode(blend_mode);
+ fragment_shader_.set_mask_for_background(mask_for_background);
if (!ProgramBindingBase::Init(
context_provider->ContextGL(),
diff --git a/chromium/cc/output/render_surface_filters.cc b/chromium/cc/output/render_surface_filters.cc
index fc2e88a8486..7cccb2417d1 100644
--- a/chromium/cc/output/render_surface_filters.cc
+++ b/chromium/cc/output/render_surface_filters.cc
@@ -206,6 +206,7 @@ skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter(
SkIntToScalar(op.amount()),
SkIntToScalar(op.amount()),
op.drop_shadow_color(),
+ SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
image_filter.get()));
break;
case FilterOperation::COLOR_MATRIX:
diff --git a/chromium/cc/output/renderer.cc b/chromium/cc/output/renderer.cc
index 7be8075a8e1..7fe0ffb9aaa 100644
--- a/chromium/cc/output/renderer.cc
+++ b/chromium/cc/output/renderer.cc
@@ -29,7 +29,8 @@ RendererCapabilitiesImpl::RendererCapabilitiesImpl()
using_egl_image(false),
using_image(false),
using_discard_framebuffer(false),
- allow_rasterize_on_demand(false) {
+ allow_rasterize_on_demand(false),
+ max_msaa_samples(0) {
}
RendererCapabilitiesImpl::~RendererCapabilitiesImpl() {}
diff --git a/chromium/cc/output/renderer.h b/chromium/cc/output/renderer.h
index 19533104b2b..8143e2a0410 100644
--- a/chromium/cc/output/renderer.h
+++ b/chromium/cc/output/renderer.h
@@ -8,7 +8,9 @@
#include "base/basictypes.h"
#include "cc/base/cc_export.h"
#include "cc/base/scoped_ptr_vector.h"
-#include "cc/trees/layer_tree_host.h"
+#include "cc/output/renderer_capabilities.h"
+#include "cc/output/renderer_settings.h"
+#include "ui/gfx/geometry/rect.h"
namespace cc {
@@ -37,6 +39,7 @@ struct RendererCapabilitiesImpl {
bool using_image;
bool using_discard_framebuffer;
bool allow_rasterize_on_demand;
+ int max_msaa_samples;
RendererCapabilities MainThreadCapabilities() const;
};
@@ -80,13 +83,13 @@ class CC_EXPORT Renderer {
void SetVisible(bool visible);
protected:
- explicit Renderer(RendererClient* client, const LayerTreeSettings* settings)
+ Renderer(RendererClient* client, const RendererSettings* settings)
: client_(client), settings_(settings), visible_(true) {}
virtual void DidChangeVisibility() = 0;
RendererClient* client_;
- const LayerTreeSettings* settings_;
+ const RendererSettings* settings_;
bool visible_;
private:
diff --git a/chromium/cc/output/renderer_capabilities.cc b/chromium/cc/output/renderer_capabilities.cc
new file mode 100644
index 00000000000..36e012bf672
--- /dev/null
+++ b/chromium/cc/output/renderer_capabilities.cc
@@ -0,0 +1,29 @@
+// 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.
+
+#include "cc/output/renderer_capabilities.h"
+
+namespace cc {
+
+RendererCapabilities::RendererCapabilities(ResourceFormat best_texture_format,
+ bool allow_partial_texture_updates,
+ int max_texture_size,
+ bool using_shared_memory_resources)
+ : best_texture_format(best_texture_format),
+ allow_partial_texture_updates(allow_partial_texture_updates),
+ max_texture_size(max_texture_size),
+ using_shared_memory_resources(using_shared_memory_resources) {
+}
+
+RendererCapabilities::RendererCapabilities()
+ : best_texture_format(RGBA_8888),
+ allow_partial_texture_updates(false),
+ max_texture_size(0),
+ using_shared_memory_resources(false) {
+}
+
+RendererCapabilities::~RendererCapabilities() {
+}
+
+} // namespace cc
diff --git a/chromium/cc/output/renderer_capabilities.h b/chromium/cc/output/renderer_capabilities.h
new file mode 100644
index 00000000000..f03d51cf0dc
--- /dev/null
+++ b/chromium/cc/output/renderer_capabilities.h
@@ -0,0 +1,32 @@
+// 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_OUTPUT_RENDERER_CAPABILITIES_H_
+#define CC_OUTPUT_RENDERER_CAPABILITIES_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/resources/resource_format.h"
+
+namespace cc {
+
+// Represents the set of capabilities that a particular Renderer has.
+struct CC_EXPORT RendererCapabilities {
+ RendererCapabilities(ResourceFormat best_texture_format,
+ bool allow_partial_texture_updates,
+ int max_texture_size,
+ bool using_shared_memory_resources);
+
+ RendererCapabilities();
+ ~RendererCapabilities();
+
+ // Duplicate any modification to this list to RendererCapabilitiesImpl.
+ ResourceFormat best_texture_format;
+ bool allow_partial_texture_updates;
+ int max_texture_size;
+ bool using_shared_memory_resources;
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_RENDERER_CAPABILITIES_H_
diff --git a/chromium/cc/output/renderer_pixeltest.cc b/chromium/cc/output/renderer_pixeltest.cc
index bdb030f0631..330c8bfd983 100644
--- a/chromium/cc/output/renderer_pixeltest.cc
+++ b/chromium/cc/output/renderer_pixeltest.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "base/message_loop/message_loop.h"
-#include "cc/layers/append_quads_data.h"
#include "cc/output/gl_renderer.h"
#include "cc/quads/draw_quad.h"
#include "cc/quads/picture_draw_quad.h"
@@ -111,6 +110,52 @@ void CreateTestRenderPassDrawQuad(const SharedQuadState* shared_state,
FilterOperations()); // background filters
}
+void CreateTestTwoColoredTextureDrawQuad(const gfx::Rect& rect,
+ SkColor texel_color,
+ SkColor texel_stripe_color,
+ SkColor background_color,
+ bool premultiplied_alpha,
+ const SharedQuadState* shared_state,
+ ResourceProvider* resource_provider,
+ RenderPass* render_pass) {
+ SkPMColor pixel_color = premultiplied_alpha
+ ? SkPreMultiplyColor(texel_color)
+ : SkPackARGB32NoCheck(SkColorGetA(texel_color),
+ SkColorGetR(texel_color),
+ SkColorGetG(texel_color),
+ SkColorGetB(texel_color));
+ SkPMColor pixel_stripe_color =
+ premultiplied_alpha
+ ? SkPreMultiplyColor(texel_stripe_color)
+ : SkPackARGB32NoCheck(SkColorGetA(texel_stripe_color),
+ SkColorGetR(texel_stripe_color),
+ SkColorGetG(texel_stripe_color),
+ SkColorGetB(texel_stripe_color));
+ std::vector<uint32_t> pixels(rect.size().GetArea(), pixel_color);
+ for (int i = rect.height() / 4; i < (rect.height() * 3 / 4); ++i) {
+ for (int k = rect.width() / 4; k < (rect.width() * 3 / 4); ++k) {
+ pixels[i * rect.width() + k] = pixel_stripe_color;
+ }
+ }
+ ResourceProvider::ResourceId resource = resource_provider->CreateResource(
+ rect.size(), GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
+ resource_provider->SetPixels(resource,
+ reinterpret_cast<uint8_t*>(&pixels.front()),
+ rect, rect, gfx::Vector2d());
+
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const gfx::PointF uv_top_left(0.0f, 0.0f);
+ const gfx::PointF uv_bottom_right(1.0f, 1.0f);
+ const bool flipped = false;
+ const bool nearest_neighbor = false;
+ TextureDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
+ quad->SetNew(shared_state, rect, gfx::Rect(), rect, resource,
+ premultiplied_alpha, uv_top_left, uv_bottom_right,
+ background_color, vertex_opacity, flipped, nearest_neighbor);
+}
+
void CreateTestTextureDrawQuad(const gfx::Rect& rect,
SkColor texel_color,
SkColor background_color,
@@ -124,35 +169,254 @@ void CreateTestTextureDrawQuad(const gfx::Rect& rect,
SkColorGetR(texel_color),
SkColorGetG(texel_color),
SkColorGetB(texel_color));
- std::vector<uint32_t> pixels(rect.size().GetArea(), pixel_color);
+ size_t num_pixels = static_cast<size_t>(rect.width()) * rect.height();
+ std::vector<uint32_t> pixels(num_pixels, pixel_color);
- ResourceProvider::ResourceId resource =
- resource_provider->CreateResource(rect.size(),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
- resource_provider->SetPixels(
- resource,
- reinterpret_cast<uint8_t*>(&pixels.front()),
- rect,
- rect,
- gfx::Vector2d());
+ ResourceProvider::ResourceId resource = resource_provider->CreateResource(
+ rect.size(), GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
+ resource_provider->CopyToResource(
+ resource, reinterpret_cast<uint8_t*>(&pixels.front()), rect.size());
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const gfx::PointF uv_top_left(0.0f, 0.0f);
+ const gfx::PointF uv_bottom_right(1.0f, 1.0f);
+ const bool flipped = false;
+ const bool nearest_neighbor = false;
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- quad->SetNew(shared_state,
- rect,
- gfx::Rect(),
- rect,
- resource,
- premultiplied_alpha,
- gfx::PointF(0.0f, 0.0f), // uv_top_left
- gfx::PointF(1.0f, 1.0f), // uv_bottom_right
- background_color,
- vertex_opacity,
- false); // flipped
+ quad->SetNew(shared_state, rect, gfx::Rect(), rect, resource,
+ premultiplied_alpha, uv_top_left, uv_bottom_right,
+ background_color, vertex_opacity, flipped, nearest_neighbor);
+}
+
+void CreateTestYUVVideoDrawQuad_FromVideoFrame(
+ const SharedQuadState* shared_state,
+ scoped_refptr<media::VideoFrame> video_frame,
+ uint8 alpha_value,
+ const gfx::RectF& tex_coord_rect,
+ RenderPass* render_pass,
+ VideoResourceUpdater* video_resource_updater,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
+ ResourceProvider* resource_provider) {
+ const bool with_alpha = (video_frame->format() == media::VideoFrame::YV12A);
+ const YUVVideoDrawQuad::ColorSpace color_space =
+ (video_frame->format() == media::VideoFrame::YV12J
+ ? YUVVideoDrawQuad::JPEG
+ : YUVVideoDrawQuad::REC_601);
+ const gfx::Rect opaque_rect(0, 0, 0, 0);
+
+ if (with_alpha) {
+ memset(video_frame->data(media::VideoFrame::kAPlane), alpha_value,
+ video_frame->stride(media::VideoFrame::kAPlane) *
+ video_frame->rows(media::VideoFrame::kAPlane));
+ }
+
+ VideoFrameExternalResources resources =
+ video_resource_updater->CreateExternalResourcesFromVideoFrame(
+ video_frame);
+
+ EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
+ resources.mailboxes.size());
+ EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
+ resources.release_callbacks.size());
+
+ ResourceProvider::ResourceId y_resource =
+ resource_provider->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kYPlane],
+ SingleReleaseCallbackImpl::Create(
+ resources.release_callbacks[media::VideoFrame::kYPlane]));
+ ResourceProvider::ResourceId u_resource =
+ resource_provider->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kUPlane],
+ SingleReleaseCallbackImpl::Create(
+ resources.release_callbacks[media::VideoFrame::kUPlane]));
+ ResourceProvider::ResourceId v_resource =
+ resource_provider->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kVPlane],
+ SingleReleaseCallbackImpl::Create(
+ resources.release_callbacks[media::VideoFrame::kVPlane]));
+ ResourceProvider::ResourceId a_resource = 0;
+ if (with_alpha) {
+ a_resource = resource_provider->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kAPlane],
+ SingleReleaseCallbackImpl::Create(
+ resources.release_callbacks[media::VideoFrame::kAPlane]));
+ }
+
+ const gfx::Size ya_tex_size = video_frame->coded_size();
+ const gfx::Size uv_tex_size = media::VideoFrame::PlaneSize(
+ video_frame->format(), media::VideoFrame::kUPlane,
+ video_frame->coded_size());
+ DCHECK(uv_tex_size == media::VideoFrame::PlaneSize(
+ video_frame->format(), media::VideoFrame::kVPlane,
+ video_frame->coded_size()));
+ if (with_alpha) {
+ DCHECK(ya_tex_size == media::VideoFrame::PlaneSize(
+ video_frame->format(), media::VideoFrame::kAPlane,
+ video_frame->coded_size()));
+ }
+
+ gfx::RectF ya_tex_coord_rect(tex_coord_rect.x() * ya_tex_size.width(),
+ tex_coord_rect.y() * ya_tex_size.height(),
+ tex_coord_rect.width() * ya_tex_size.width(),
+ tex_coord_rect.height() * ya_tex_size.height());
+ gfx::RectF uv_tex_coord_rect(tex_coord_rect.x() * uv_tex_size.width(),
+ tex_coord_rect.y() * uv_tex_size.height(),
+ tex_coord_rect.width() * uv_tex_size.width(),
+ tex_coord_rect.height() * uv_tex_size.height());
+
+ YUVVideoDrawQuad* yuv_quad =
+ render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
+ yuv_quad->SetNew(shared_state, rect, opaque_rect, visible_rect,
+ ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size,
+ uv_tex_size, y_resource, u_resource, v_resource, a_resource,
+ color_space);
+}
+
+void CreateTestYUVVideoDrawQuad_Striped(
+ const SharedQuadState* shared_state,
+ media::VideoFrame::Format format,
+ bool is_transparent,
+ const gfx::RectF& tex_coord_rect,
+ RenderPass* render_pass,
+ VideoResourceUpdater* video_resource_updater,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
+ ResourceProvider* resource_provider) {
+ scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
+ format, rect.size(), rect, rect.size(), base::TimeDelta());
+
+ // YUV values representing a striped pattern, for validating texture
+ // coordinates for sampling.
+ uint8_t y_value = 0;
+ uint8_t u_value = 0;
+ uint8_t v_value = 0;
+ for (int i = 0; i < video_frame->rows(media::VideoFrame::kYPlane); ++i) {
+ uint8_t* y_row = video_frame->data(media::VideoFrame::kYPlane) +
+ video_frame->stride(media::VideoFrame::kYPlane) * i;
+ for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kYPlane);
+ ++j) {
+ y_row[j] = (y_value += 1);
+ }
+ }
+ for (int i = 0; i < video_frame->rows(media::VideoFrame::kUPlane); ++i) {
+ uint8_t* u_row = video_frame->data(media::VideoFrame::kUPlane) +
+ video_frame->stride(media::VideoFrame::kUPlane) * i;
+ uint8_t* v_row = video_frame->data(media::VideoFrame::kVPlane) +
+ video_frame->stride(media::VideoFrame::kVPlane) * i;
+ for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kUPlane);
+ ++j) {
+ u_row[j] = (u_value += 3);
+ v_row[j] = (v_value += 5);
+ }
+ }
+ uint8 alpha_value = is_transparent ? 0 : 128;
+ CreateTestYUVVideoDrawQuad_FromVideoFrame(
+ shared_state, video_frame, alpha_value, tex_coord_rect, render_pass,
+ video_resource_updater, rect, visible_rect, resource_provider);
+}
+
+// Creates a video frame of size background_size filled with yuv_background,
+// and then draws a foreground rectangle in a different color on top of
+// that. The foreground rectangle must have coordinates that are divisible
+// by 2 because YUV is a block format.
+void CreateTestYUVVideoDrawQuad_TwoColor(
+ const SharedQuadState* shared_state,
+ media::VideoFrame::Format format,
+ bool is_transparent,
+ const gfx::RectF& tex_coord_rect,
+ const gfx::Size& background_size,
+ const gfx::Rect& visible_rect,
+ uint8 y_background,
+ uint8 u_background,
+ uint8 v_background,
+ const gfx::Rect& foreground_rect,
+ uint8 y_foreground,
+ uint8 u_foreground,
+ uint8 v_foreground,
+ RenderPass* render_pass,
+ VideoResourceUpdater* video_resource_updater,
+ ResourceProvider* resource_provider) {
+ const gfx::Rect rect(background_size);
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateFrame(format, background_size, foreground_rect,
+ foreground_rect.size(), base::TimeDelta());
+
+ int planes[] = {media::VideoFrame::kYPlane,
+ media::VideoFrame::kUPlane,
+ media::VideoFrame::kVPlane};
+ uint8 yuv_background[] = {y_background, u_background, v_background};
+ uint8 yuv_foreground[] = {y_foreground, u_foreground, v_foreground};
+ int sample_size[] = {1, 2, 2};
+
+ for (int i = 0; i < 3; ++i) {
+ memset(video_frame->data(planes[i]), yuv_background[i],
+ video_frame->stride(planes[i]) * video_frame->rows(planes[i]));
+ }
+
+ for (int i = 0; i < 3; ++i) {
+ // Since yuv encoding uses block encoding, widths have to be divisible
+ // by the sample size in order for this function to behave properly.
+ DCHECK_EQ(foreground_rect.x() % sample_size[i], 0);
+ DCHECK_EQ(foreground_rect.y() % sample_size[i], 0);
+ DCHECK_EQ(foreground_rect.width() % sample_size[i], 0);
+ DCHECK_EQ(foreground_rect.height() % sample_size[i], 0);
+
+ gfx::Rect sample_rect(foreground_rect.x() / sample_size[i],
+ foreground_rect.y() / sample_size[i],
+ foreground_rect.width() / sample_size[i],
+ foreground_rect.height() / sample_size[i]);
+ for (int y = sample_rect.y(); y < sample_rect.bottom(); ++y) {
+ for (int x = sample_rect.x(); x < sample_rect.right(); ++x) {
+ size_t offset = y * video_frame->stride(planes[i]) + x;
+ video_frame->data(planes[i])[offset] = yuv_foreground[i];
+ }
+ }
+ }
+
+ uint8 alpha_value = 255;
+ CreateTestYUVVideoDrawQuad_FromVideoFrame(
+ shared_state, video_frame, alpha_value, tex_coord_rect, render_pass,
+ video_resource_updater, rect, visible_rect, resource_provider);
+}
+
+void CreateTestYUVVideoDrawQuad_Solid(
+ const SharedQuadState* shared_state,
+ media::VideoFrame::Format format,
+ bool is_transparent,
+ const gfx::RectF& tex_coord_rect,
+ uint8 y,
+ uint8 u,
+ uint8 v,
+ RenderPass* render_pass,
+ VideoResourceUpdater* video_resource_updater,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
+ ResourceProvider* resource_provider) {
+ scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
+ format, rect.size(), rect, rect.size(), base::TimeDelta());
+
+ // YUV values of a solid, constant, color. Useful for testing that color
+ // space/color range are being handled properly.
+ memset(video_frame->data(media::VideoFrame::kYPlane), y,
+ video_frame->stride(media::VideoFrame::kYPlane) *
+ video_frame->rows(media::VideoFrame::kYPlane));
+ memset(video_frame->data(media::VideoFrame::kUPlane), u,
+ video_frame->stride(media::VideoFrame::kUPlane) *
+ video_frame->rows(media::VideoFrame::kUPlane));
+ memset(video_frame->data(media::VideoFrame::kVPlane), v,
+ video_frame->stride(media::VideoFrame::kVPlane) *
+ video_frame->rows(media::VideoFrame::kVPlane));
+
+ uint8 alpha_value = is_transparent ? 0 : 128;
+ CreateTestYUVVideoDrawQuad_FromVideoFrame(
+ shared_state, video_frame, alpha_value, tex_coord_rect, render_pass,
+ video_resource_updater, rect, visible_rect, resource_provider);
}
typedef ::testing::Types<GLRenderer,
@@ -162,13 +426,20 @@ typedef ::testing::Types<GLRenderer,
TYPED_TEST_CASE(RendererPixelTest, RendererTypes);
template <typename RendererType>
+class SoftwareRendererPixelTest : public RendererPixelTest<RendererType> {};
+
+typedef ::testing::Types<SoftwareRenderer, SoftwareRendererWithExpandedViewport>
+ SoftwareRendererTypes;
+TYPED_TEST_CASE(SoftwareRendererPixelTest, SoftwareRendererTypes);
+
+template <typename RendererType>
class FuzzyForSoftwareOnlyPixelComparator : public PixelComparator {
public:
explicit FuzzyForSoftwareOnlyPixelComparator(bool discard_alpha)
: fuzzy_(discard_alpha), exact_(discard_alpha) {}
- virtual bool Compare(const SkBitmap& actual_bmp,
- const SkBitmap& expected_bmp) const;
+ bool Compare(const SkBitmap& actual_bmp,
+ const SkBitmap& expected_bmp) const override;
private:
FuzzyPixelOffByOneComparator fuzzy_;
@@ -320,6 +591,280 @@ TYPED_TEST(RendererPixelTest, PremultipliedTextureWithBackground) {
FuzzyPixelOffByOneComparator(true)));
}
+template <typename QuadType>
+static const base::FilePath::CharType* IntersectingQuadImage() {
+ return FILE_PATH_LITERAL("intersecting_blue_green_squares.png");
+}
+template <>
+const base::FilePath::CharType* IntersectingQuadImage<SolidColorDrawQuad>() {
+ return FILE_PATH_LITERAL("intersecting_blue_green.png");
+}
+template <>
+const base::FilePath::CharType* IntersectingQuadImage<YUVVideoDrawQuad>() {
+ return FILE_PATH_LITERAL("intersecting_blue_green_squares_video.png");
+}
+
+template <typename TypeParam>
+class IntersectingQuadPixelTest : public RendererPixelTest<TypeParam> {
+ protected:
+ void SetupQuadStateAndRenderPass() {
+ // This sets up a pair of draw quads. They are both rotated
+ // relative to the root plane, they are also rotated relative to each other.
+ // The intersect in the middle at a non-perpendicular angle so that any
+ // errors are hopefully magnified.
+ // The quads should intersect correctly, as in the front quad should only
+ // be partially in front of the back quad, and partially behind.
+
+ viewport_rect_ = gfx::Rect(this->device_viewport_size_);
+ quad_rect_ = gfx::Rect(0, 0, this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2.0);
+
+ RenderPassId id(1, 1);
+ render_pass_ = CreateTestRootRenderPass(id, viewport_rect_);
+
+ // Create the front quad rotated on the Z and Y axis.
+ gfx::Transform trans;
+ trans.Translate3d(0, 0, 0.707 * this->device_viewport_size_.width() / 2.0);
+ trans.RotateAboutZAxis(45.0);
+ trans.RotateAboutYAxis(45.0);
+ front_quad_state_ =
+ CreateTestSharedQuadState(trans, viewport_rect_, render_pass_.get());
+ front_quad_state_->clip_rect = quad_rect_;
+ // Make sure they end up in a 3d sorting context.
+ front_quad_state_->sorting_context_id = 1;
+
+ // Create the back quad, and rotate on just the y axis. This will intersect
+ // the first quad partially.
+ trans = gfx::Transform();
+ trans.Translate3d(0, 0, -0.707 * this->device_viewport_size_.width() / 2.0);
+ trans.RotateAboutYAxis(-45.0);
+ back_quad_state_ =
+ CreateTestSharedQuadState(trans, viewport_rect_, render_pass_.get());
+ back_quad_state_->sorting_context_id = 1;
+ back_quad_state_->clip_rect = quad_rect_;
+ }
+ template <typename T>
+ void AppendBackgroundAndRunTest(const PixelComparator& comparator) {
+ SharedQuadState* background_quad_state = CreateTestSharedQuadState(
+ gfx::Transform(), viewport_rect_, render_pass_.get());
+ SolidColorDrawQuad* background_quad =
+ render_pass_->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ background_quad->SetNew(background_quad_state, viewport_rect_,
+ viewport_rect_, SK_ColorWHITE, false);
+ pass_list_.push_back(render_pass_.Pass());
+ const base::FilePath::CharType* fileName = IntersectingQuadImage<T>();
+ EXPECT_TRUE(
+ this->RunPixelTest(&pass_list_, base::FilePath(fileName), comparator));
+ }
+ template <typename T>
+ T* CreateAndAppendDrawQuad() {
+ return render_pass_->CreateAndAppendDrawQuad<T>();
+ }
+
+ scoped_ptr<RenderPass> render_pass_;
+ gfx::Rect viewport_rect_;
+ SharedQuadState* front_quad_state_;
+ SharedQuadState* back_quad_state_;
+ gfx::Rect quad_rect_;
+ RenderPassList pass_list_;
+};
+
+template <typename TypeParam>
+class IntersectingQuadGLPixelTest
+ : public IntersectingQuadPixelTest<TypeParam> {
+ public:
+ void SetUp() override {
+ IntersectingQuadPixelTest<TypeParam>::SetUp();
+ video_resource_updater_.reset(
+ new VideoResourceUpdater(this->output_surface_->context_provider(),
+ this->resource_provider_.get()));
+ video_resource_updater2_.reset(
+ new VideoResourceUpdater(this->output_surface_->context_provider(),
+ this->resource_provider_.get()));
+ }
+
+ protected:
+ scoped_ptr<VideoResourceUpdater> video_resource_updater_;
+ scoped_ptr<VideoResourceUpdater> video_resource_updater2_;
+};
+
+template <typename TypeParam>
+class IntersectingQuadSoftwareTest
+ : public IntersectingQuadPixelTest<TypeParam> {};
+
+typedef ::testing::Types<SoftwareRenderer, SoftwareRendererWithExpandedViewport>
+ SoftwareRendererTypes;
+typedef ::testing::Types<GLRenderer, GLRendererWithExpandedViewport>
+ GLRendererTypes;
+
+TYPED_TEST_CASE(IntersectingQuadPixelTest, RendererTypes);
+TYPED_TEST_CASE(IntersectingQuadGLPixelTest, GLRendererTypes);
+TYPED_TEST_CASE(IntersectingQuadSoftwareTest, SoftwareRendererTypes);
+
+TYPED_TEST(IntersectingQuadPixelTest, SolidColorQuads) {
+ this->SetupQuadStateAndRenderPass();
+
+ SolidColorDrawQuad* quad =
+ this->template CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ SolidColorDrawQuad* quad2 =
+ this->template CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+
+ quad->SetNew(this->front_quad_state_, this->quad_rect_, this->quad_rect_,
+ SK_ColorBLUE, false);
+ quad2->SetNew(this->back_quad_state_, this->quad_rect_, this->quad_rect_,
+ SK_ColorGREEN, false);
+ SCOPED_TRACE("IntersectingSolidColorQuads");
+ this->template AppendBackgroundAndRunTest<SolidColorDrawQuad>(
+ FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f));
+}
+
+template <typename TypeParam>
+SkColor GetColor(const SkColor& color) {
+ return color;
+}
+
+template <>
+SkColor GetColor<GLRenderer>(const SkColor& color) {
+ return SkColorSetARGB(SkColorGetA(color), SkColorGetB(color),
+ SkColorGetG(color), SkColorGetR(color));
+}
+template <>
+SkColor GetColor<GLRendererWithExpandedViewport>(const SkColor& color) {
+ return GetColor<GLRenderer>(color);
+}
+
+TYPED_TEST(IntersectingQuadPixelTest, TexturedQuads) {
+ this->SetupQuadStateAndRenderPass();
+ CreateTestTwoColoredTextureDrawQuad(
+ this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)),
+ GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT,
+ true, this->front_quad_state_, this->resource_provider_.get(),
+ this->render_pass_.get());
+ CreateTestTwoColoredTextureDrawQuad(
+ this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)),
+ GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT,
+ true, this->back_quad_state_, this->resource_provider_.get(),
+ this->render_pass_.get());
+
+ SCOPED_TRACE("IntersectingTexturedQuads");
+ this->template AppendBackgroundAndRunTest<TextureDrawQuad>(
+ FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f));
+}
+
+TYPED_TEST(IntersectingQuadSoftwareTest, PictureQuads) {
+ this->SetupQuadStateAndRenderPass();
+ gfx::RectF outer_rect(this->quad_rect_);
+ gfx::RectF inner_rect(this->quad_rect_.x() + (this->quad_rect_.width() / 4),
+ this->quad_rect_.y() + (this->quad_rect_.height() / 4),
+ this->quad_rect_.width() / 2,
+ this->quad_rect_.height() / 2);
+
+ SkPaint black_paint;
+ black_paint.setColor(SK_ColorBLACK);
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ SkPaint green_paint;
+ green_paint.setColor(SK_ColorGREEN);
+
+ scoped_ptr<FakePicturePile> blue_recording =
+ FakePicturePile::CreateFilledPile(gfx::Size(1000, 1000),
+ this->quad_rect_.size());
+ blue_recording->add_draw_rect_with_paint(outer_rect, black_paint);
+ blue_recording->add_draw_rect_with_paint(inner_rect, blue_paint);
+ blue_recording->Rerecord();
+ scoped_refptr<FakePicturePileImpl> blue_pile =
+ FakePicturePileImpl::CreateFromPile(blue_recording.get(), nullptr);
+
+ PictureDrawQuad* blue_quad =
+ this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>();
+
+ blue_quad->SetNew(this->front_quad_state_, this->quad_rect_, gfx::Rect(),
+ this->quad_rect_, this->quad_rect_, this->quad_rect_.size(),
+ false, RGBA_8888, this->quad_rect_, 1.f, blue_pile);
+
+ scoped_ptr<FakePicturePile> green_recording =
+ FakePicturePile::CreateFilledPile(this->quad_rect_.size(),
+ this->quad_rect_.size());
+ green_recording->add_draw_rect_with_paint(outer_rect, green_paint);
+ green_recording->add_draw_rect_with_paint(inner_rect, black_paint);
+ green_recording->Rerecord();
+ scoped_refptr<FakePicturePileImpl> green_pile =
+ FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr);
+
+ PictureDrawQuad* green_quad =
+ this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>();
+ green_quad->SetNew(this->back_quad_state_, this->quad_rect_, gfx::Rect(),
+ this->quad_rect_, this->quad_rect_,
+ this->quad_rect_.size(), false, RGBA_8888,
+ this->quad_rect_, 1.f, green_pile);
+ SCOPED_TRACE("IntersectingPictureQuadsPass");
+ this->template AppendBackgroundAndRunTest<PictureDrawQuad>(
+ FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f));
+}
+
+TYPED_TEST(IntersectingQuadPixelTest, RenderPassQuads) {
+ this->SetupQuadStateAndRenderPass();
+ RenderPassId child_pass_id1(2, 2);
+ RenderPassId child_pass_id2(2, 3);
+ scoped_ptr<RenderPass> child_pass1 =
+ CreateTestRenderPass(child_pass_id1, this->quad_rect_, gfx::Transform());
+ SharedQuadState* child1_quad_state = CreateTestSharedQuadState(
+ gfx::Transform(), this->quad_rect_, child_pass1.get());
+ scoped_ptr<RenderPass> child_pass2 =
+ CreateTestRenderPass(child_pass_id2, this->quad_rect_, gfx::Transform());
+ SharedQuadState* child2_quad_state = CreateTestSharedQuadState(
+ gfx::Transform(), this->quad_rect_, child_pass2.get());
+
+ CreateTestTwoColoredTextureDrawQuad(
+ this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)),
+ GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT,
+ true, child1_quad_state, this->resource_provider_.get(),
+ child_pass1.get());
+ CreateTestTwoColoredTextureDrawQuad(
+ this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)),
+ GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT,
+ true, child2_quad_state, this->resource_provider_.get(),
+ child_pass2.get());
+
+ CreateTestRenderPassDrawQuad(this->front_quad_state_, this->quad_rect_,
+ child_pass_id1, this->render_pass_.get());
+ CreateTestRenderPassDrawQuad(this->back_quad_state_, this->quad_rect_,
+ child_pass_id2, this->render_pass_.get());
+
+ this->pass_list_.push_back(child_pass1.Pass());
+ this->pass_list_.push_back(child_pass2.Pass());
+ SCOPED_TRACE("IntersectingRenderQuadsPass");
+ this->template AppendBackgroundAndRunTest<RenderPassDrawQuad>(
+ FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f));
+}
+
+TYPED_TEST(IntersectingQuadGLPixelTest, YUVVideoQuads) {
+ this->SetupQuadStateAndRenderPass();
+ gfx::Rect inner_rect(
+ ((this->quad_rect_.x() + (this->quad_rect_.width() / 4)) & ~0xF),
+ ((this->quad_rect_.y() + (this->quad_rect_.height() / 4)) & ~0xF),
+ (this->quad_rect_.width() / 2) & ~0xF,
+ (this->quad_rect_.height() / 2) & ~0xF);
+
+ CreateTestYUVVideoDrawQuad_TwoColor(
+ this->front_quad_state_, media::VideoFrame::YV12J, false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(),
+ this->quad_rect_, 0, 128, 128, inner_rect, 29, 255, 107,
+ this->render_pass_.get(), this->video_resource_updater_.get(),
+ this->resource_provider_.get());
+
+ CreateTestYUVVideoDrawQuad_TwoColor(
+ this->back_quad_state_, media::VideoFrame::YV12J, false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(),
+ this->quad_rect_, 149, 43, 21, inner_rect, 0, 128, 128,
+ this->render_pass_.get(), this->video_resource_updater2_.get(),
+ this->resource_provider_.get());
+
+ SCOPED_TRACE("IntersectingVideoQuads");
+ this->template AppendBackgroundAndRunTest<YUVVideoDrawQuad>(
+ FuzzyPixelOffByOneComparator(false));
+}
+
// TODO(skaslev): The software renderer does not support non-premultplied alpha.
TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithoutBackground) {
gfx::Rect rect(this->device_viewport_size_);
@@ -387,152 +932,47 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) {
class VideoGLRendererPixelTest : public GLRendererPixelTest {
protected:
- void CreateTestYUVVideoDrawQuad_Striped(const SharedQuadState* shared_state,
- media::VideoFrame::Format format,
- bool is_transparent,
- const gfx::RectF& tex_coord_rect,
- RenderPass* render_pass) {
- const gfx::Rect rect(this->device_viewport_size_);
-
- scoped_refptr<media::VideoFrame> video_frame =
- media::VideoFrame::CreateFrame(
- format, rect.size(), rect, rect.size(), base::TimeDelta());
-
- // YUV values representing a striped pattern, for validating texture
- // coordinates for sampling.
- uint8_t y_value = 0;
- uint8_t u_value = 0;
- uint8_t v_value = 0;
- for (int i = 0; i < video_frame->rows(media::VideoFrame::kYPlane); ++i) {
- uint8_t* y_row = video_frame->data(media::VideoFrame::kYPlane) +
- video_frame->stride(media::VideoFrame::kYPlane) * i;
- for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kYPlane);
- ++j) {
- y_row[j] = (y_value += 1);
- }
- }
- for (int i = 0; i < video_frame->rows(media::VideoFrame::kUPlane); ++i) {
- uint8_t* u_row = video_frame->data(media::VideoFrame::kUPlane) +
- video_frame->stride(media::VideoFrame::kUPlane) * i;
- uint8_t* v_row = video_frame->data(media::VideoFrame::kVPlane) +
- video_frame->stride(media::VideoFrame::kVPlane) * i;
- for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kUPlane);
- ++j) {
- u_row[j] = (u_value += 3);
- v_row[j] = (v_value += 5);
- }
- }
- CreateTestYUVVideoDrawQuad_FromVideoFrame(
- shared_state, video_frame, is_transparent, tex_coord_rect, render_pass);
- }
-
- void CreateTestYUVVideoDrawQuad_Solid(const SharedQuadState* shared_state,
- media::VideoFrame::Format format,
- bool is_transparent,
- const gfx::RectF& tex_coord_rect,
- uint8 y,
- uint8 u,
- uint8 v,
- RenderPass* render_pass) {
- const gfx::Rect rect(this->device_viewport_size_);
-
- scoped_refptr<media::VideoFrame> video_frame =
- media::VideoFrame::CreateFrame(
- format, rect.size(), rect, rect.size(), base::TimeDelta());
-
- // YUV values of a solid, constant, color. Useful for testing that color
- // space/color range are being handled properly.
- memset(video_frame->data(media::VideoFrame::kYPlane),
- y,
- video_frame->stride(media::VideoFrame::kYPlane) *
- video_frame->rows(media::VideoFrame::kYPlane));
- memset(video_frame->data(media::VideoFrame::kUPlane),
- u,
- video_frame->stride(media::VideoFrame::kUPlane) *
- video_frame->rows(media::VideoFrame::kUPlane));
- memset(video_frame->data(media::VideoFrame::kVPlane),
- v,
- video_frame->stride(media::VideoFrame::kVPlane) *
- video_frame->rows(media::VideoFrame::kVPlane));
-
- CreateTestYUVVideoDrawQuad_FromVideoFrame(
- shared_state, video_frame, is_transparent, tex_coord_rect, render_pass);
- }
-
- void CreateTestYUVVideoDrawQuad_FromVideoFrame(
- const SharedQuadState* shared_state,
- scoped_refptr<media::VideoFrame> video_frame,
- bool is_transparent,
- const gfx::RectF& tex_coord_rect,
- RenderPass* render_pass) {
- const bool with_alpha = (video_frame->format() == media::VideoFrame::YV12A);
- const YUVVideoDrawQuad::ColorSpace color_space =
- (video_frame->format() == media::VideoFrame::YV12J
- ? YUVVideoDrawQuad::REC_601_JPEG
- : YUVVideoDrawQuad::REC_601);
- const gfx::Rect rect(this->device_viewport_size_);
- const gfx::Rect opaque_rect(0, 0, 0, 0);
-
- if (with_alpha)
- memset(video_frame->data(media::VideoFrame::kAPlane),
- is_transparent ? 0 : 128,
- video_frame->stride(media::VideoFrame::kAPlane) *
- video_frame->rows(media::VideoFrame::kAPlane));
-
- VideoFrameExternalResources resources =
- video_resource_updater_->CreateExternalResourcesFromVideoFrame(
- video_frame);
-
- EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
- EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
- resources.mailboxes.size());
- EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
- resources.release_callbacks.size());
-
- ResourceProvider::ResourceId y_resource =
- resource_provider_->CreateResourceFromTextureMailbox(
- resources.mailboxes[media::VideoFrame::kYPlane],
- SingleReleaseCallbackImpl::Create(
- resources.release_callbacks[media::VideoFrame::kYPlane]));
- ResourceProvider::ResourceId u_resource =
- resource_provider_->CreateResourceFromTextureMailbox(
- resources.mailboxes[media::VideoFrame::kUPlane],
- SingleReleaseCallbackImpl::Create(
- resources.release_callbacks[media::VideoFrame::kUPlane]));
- ResourceProvider::ResourceId v_resource =
- resource_provider_->CreateResourceFromTextureMailbox(
- resources.mailboxes[media::VideoFrame::kVPlane],
- SingleReleaseCallbackImpl::Create(
- resources.release_callbacks[media::VideoFrame::kVPlane]));
- ResourceProvider::ResourceId a_resource = 0;
- if (with_alpha) {
- a_resource = resource_provider_->CreateResourceFromTextureMailbox(
- resources.mailboxes[media::VideoFrame::kAPlane],
- SingleReleaseCallbackImpl::Create(
- resources.release_callbacks[media::VideoFrame::kAPlane]));
- }
-
- YUVVideoDrawQuad* yuv_quad =
- render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
- yuv_quad->SetNew(shared_state,
- rect,
- opaque_rect,
- rect,
- tex_coord_rect,
- y_resource,
- u_resource,
- v_resource,
- a_resource,
- color_space);
+ void CreateEdgeBleedPass(media::VideoFrame::Format format,
+ RenderPassList* pass_list) {
+ gfx::Rect rect(200, 200);
+
+ RenderPassId id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+
+ // Scale the video up so that bilinear filtering kicks in to sample more
+ // than just nearest neighbor would.
+ gfx::Transform scale_by_2;
+ scale_by_2.Scale(2.f, 2.f);
+ gfx::Rect half_rect(100, 100);
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(scale_by_2, half_rect, pass.get());
+
+ gfx::Size background_size(200, 200);
+ gfx::Rect green_rect(16, 20, 100, 100);
+ gfx::RectF tex_coord_rect(
+ static_cast<float>(green_rect.x()) / background_size.width(),
+ static_cast<float>(green_rect.y()) / background_size.height(),
+ static_cast<float>(green_rect.width()) / background_size.width(),
+ static_cast<float>(green_rect.height()) / background_size.height());
+
+ // YUV of (149,43,21) should be green (0,255,0) in RGB.
+ // Create a video frame that has a non-green background rect, with a
+ // green sub-rectangle that should be the only thing displayed in
+ // the final image. Bleeding will appear on all four sides of the video
+ // if the tex coords are not clamped.
+ CreateTestYUVVideoDrawQuad_TwoColor(
+ shared_state, format, false, tex_coord_rect, background_size,
+ gfx::Rect(background_size), 128, 128, 128, green_rect, 149, 43, 21,
+ pass.get(), video_resource_updater_.get(), resource_provider_.get());
+ pass_list->push_back(pass.Pass());
}
- virtual void SetUp() override {
+ void SetUp() override {
GLRendererPixelTest::SetUp();
video_resource_updater_.reset(new VideoResourceUpdater(
output_surface_->context_provider(), resource_provider_.get()));
}
- private:
scoped_ptr<VideoResourceUpdater> video_resource_updater_;
};
@@ -545,11 +985,10 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) {
SharedQuadState* shared_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
- CreateTestYUVVideoDrawQuad_Striped(shared_state,
- media::VideoFrame::YV12,
- false,
- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
- pass.get());
+ CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12,
+ false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
+ pass.get(), video_resource_updater_.get(),
+ rect, rect, resource_provider_.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -560,6 +999,30 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) {
FuzzyPixelOffByOneComparator(true)));
}
+TEST_F(VideoGLRendererPixelTest, ClippedYUVRect) {
+ gfx::Rect viewport(this->device_viewport_size_);
+ gfx::Rect draw_rect(this->device_viewport_size_.width() * 1.5,
+ this->device_viewport_size_.height() * 1.5);
+
+ RenderPassId id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, viewport);
+
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(gfx::Transform(), viewport, pass.get());
+
+ CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12,
+ false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
+ pass.get(), video_resource_updater_.get(),
+ draw_rect, viewport,
+ resource_provider_.get());
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list, base::FilePath(FILE_PATH_LITERAL("yuv_stripes_clipped.png")),
+ FuzzyPixelOffByOneComparator(true)));
+}
+
TEST_F(VideoGLRendererPixelTest, OffsetYUVRect) {
gfx::Rect rect(this->device_viewport_size_);
@@ -570,11 +1033,10 @@ TEST_F(VideoGLRendererPixelTest, OffsetYUVRect) {
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
// Intentionally sets frame format to I420 for testing coverage.
- CreateTestYUVVideoDrawQuad_Striped(shared_state,
- media::VideoFrame::I420,
- false,
- gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f),
- pass.get());
+ CreateTestYUVVideoDrawQuad_Striped(
+ shared_state, media::VideoFrame::I420, false,
+ gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f), pass.get(),
+ video_resource_updater_.get(), rect, rect, resource_provider_.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -595,14 +1057,10 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVRectBlack) {
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
// In MPEG color range YUV values of (15,128,128) should produce black.
- CreateTestYUVVideoDrawQuad_Solid(shared_state,
- media::VideoFrame::YV12,
- false,
- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
- 15,
- 128,
- 128,
- pass.get());
+ CreateTestYUVVideoDrawQuad_Solid(
+ shared_state, media::VideoFrame::YV12, false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
+ video_resource_updater_.get(), rect, rect, resource_provider_.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -624,14 +1082,10 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) {
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
// YUV of (149,43,21) should be green (0,255,0) in RGB.
- CreateTestYUVVideoDrawQuad_Solid(shared_state,
- media::VideoFrame::YV12J,
- false,
- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
- 149,
- 43,
- 21,
- pass.get());
+ CreateTestYUVVideoDrawQuad_Solid(
+ shared_state, media::VideoFrame::YV12J, false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(),
+ video_resource_updater_.get(), rect, rect, resource_provider_.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -641,6 +1095,24 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) {
FuzzyPixelOffByOneComparator(true)));
}
+// Test that a YUV video doesn't bleed outside of its tex coords when the
+// tex coord rect is only a partial subrectangle of the coded contents.
+TEST_F(VideoGLRendererPixelTest, YUVEdgeBleed) {
+ RenderPassList pass_list;
+ CreateEdgeBleedPass(media::VideoFrame::YV12J, &pass_list);
+ EXPECT_TRUE(this->RunPixelTest(&pass_list,
+ base::FilePath(FILE_PATH_LITERAL("green.png")),
+ FuzzyPixelOffByOneComparator(true)));
+}
+
+TEST_F(VideoGLRendererPixelTest, YUVAEdgeBleed) {
+ RenderPassList pass_list;
+ CreateEdgeBleedPass(media::VideoFrame::YV12A, &pass_list);
+ EXPECT_TRUE(this->RunPixelTest(&pass_list,
+ base::FilePath(FILE_PATH_LITERAL("green.png")),
+ FuzzyPixelOffByOneComparator(true)));
+}
+
TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) {
gfx::Rect rect(this->device_viewport_size_);
@@ -651,14 +1123,10 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) {
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
// Dark grey in JPEG color range (in MPEG, this is black).
- CreateTestYUVVideoDrawQuad_Solid(shared_state,
- media::VideoFrame::YV12J,
- false,
- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
- 15,
- 128,
- 128,
- pass.get());
+ CreateTestYUVVideoDrawQuad_Solid(
+ shared_state, media::VideoFrame::YV12J, false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
+ video_resource_updater_.get(), rect, rect, resource_provider_.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -678,11 +1146,10 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVARect) {
SharedQuadState* shared_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
- CreateTestYUVVideoDrawQuad_Striped(shared_state,
- media::VideoFrame::YV12A,
- false,
- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
- pass.get());
+ CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12A,
+ false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
+ pass.get(), video_resource_updater_.get(),
+ rect, rect, resource_provider_.get());
SolidColorDrawQuad* color_quad =
pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -706,11 +1173,10 @@ TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) {
SharedQuadState* shared_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
- CreateTestYUVVideoDrawQuad_Striped(shared_state,
- media::VideoFrame::YV12A,
- true,
- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
- pass.get());
+ CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12A,
+ true, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
+ pass.get(), video_resource_updater_.get(),
+ rect, rect, resource_provider_.get());
SolidColorDrawQuad* color_quad =
pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -881,10 +1347,11 @@ TYPED_TEST(RendererPixelTest, FastPassSaturateFilter) {
pass_list.push_back(child_pass.Pass());
pass_list.push_back(root_pass.Pass());
+ // This test blends slightly differently with the software renderer vs. the gl
+ // renderer so use a fuzzy comparator.
EXPECT_TRUE(this->RunPixelTest(
- &pass_list,
- base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")),
- ExactPixelComparator(true)));
+ &pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")),
+ FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
}
TYPED_TEST(RendererPixelTest, FastPassFilterChain) {
@@ -952,10 +1419,12 @@ TYPED_TEST(RendererPixelTest, FastPassFilterChain) {
pass_list.push_back(child_pass.Pass());
pass_list.push_back(root_pass.Pass());
+ // This test blends slightly differently with the software renderer vs. the gl
+ // renderer so use a fuzzy comparator.
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_filter_chain.png")),
- ExactPixelComparator(true)));
+ FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
}
TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) {
@@ -1212,18 +1681,13 @@ TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) {
ResourceProvider::ResourceId mask_resource_id =
this->resource_provider_->CreateResource(
- mask_rect.size(),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
+ mask_rect.size(), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
{
SkAutoLockPixels lock(bitmap);
- this->resource_provider_->SetPixels(
- mask_resource_id,
- reinterpret_cast<uint8_t*>(bitmap.getPixels()),
- mask_rect,
- mask_rect,
- gfx::Vector2d());
+ this->resource_provider_->CopyToResource(
+ mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
+ mask_rect.size());
}
// This RenderPassDrawQuad does not include the full |viewport_rect| which is
@@ -1719,11 +2183,12 @@ TEST_F(GLRendererPixelTest, AntiAliasingPerspective) {
FuzzyPixelOffByOneComparator(true)));
}
-TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) {
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadIdentityScale) {
gfx::Size pile_tile_size(1000, 1000);
gfx::Rect viewport(this->device_viewport_size_);
// TODO(enne): the renderer should figure this out on its own.
ResourceFormat texture_format = RGBA_8888;
+ bool nearest_neighbor = false;
RenderPassId id(1, 1);
gfx::Transform transform_to_root;
@@ -1734,15 +2199,19 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) {
// is red, which should not appear.
gfx::Rect blue_rect(gfx::Size(100, 100));
gfx::Rect blue_clip_rect(gfx::Point(50, 50), gfx::Size(50, 50));
- scoped_refptr<FakePicturePileImpl> blue_pile =
- FakePicturePileImpl::CreateFilledPile(pile_tile_size, blue_rect.size());
+
+ scoped_ptr<FakePicturePile> blue_recording =
+ FakePicturePile::CreateFilledPile(pile_tile_size, blue_rect.size());
SkPaint red_paint;
red_paint.setColor(SK_ColorRED);
- blue_pile->add_draw_rect_with_paint(blue_rect, red_paint);
+ blue_recording->add_draw_rect_with_paint(blue_rect, red_paint);
SkPaint blue_paint;
blue_paint.setColor(SK_ColorBLUE);
- blue_pile->add_draw_rect_with_paint(blue_clip_rect, blue_paint);
- blue_pile->RerecordPile();
+ blue_recording->add_draw_rect_with_paint(blue_clip_rect, blue_paint);
+ blue_recording->Rerecord();
+
+ scoped_refptr<FakePicturePileImpl> blue_pile =
+ FakePicturePileImpl::CreateFromPile(blue_recording.get(), nullptr);
gfx::Transform blue_content_to_target_transform;
gfx::Vector2d offset(viewport.bottom_right() - blue_rect.bottom_right());
@@ -1760,16 +2229,18 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) {
blue_quad->SetNew(blue_shared_state,
viewport, // Intentionally bigger than clip.
gfx::Rect(), viewport, gfx::RectF(viewport),
- viewport.size(), texture_format, viewport, 1.f,
- blue_pile.get());
+ viewport.size(), nearest_neighbor, texture_format, viewport,
+ 1.f, blue_pile.get());
// One viewport-filling green quad.
- scoped_refptr<FakePicturePileImpl> green_pile =
- FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+ scoped_ptr<FakePicturePile> green_recording =
+ FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
SkPaint green_paint;
green_paint.setColor(SK_ColorGREEN);
- green_pile->add_draw_rect_with_paint(viewport, green_paint);
- green_pile->RerecordPile();
+ green_recording->add_draw_rect_with_paint(viewport, green_paint);
+ green_recording->Rerecord();
+ scoped_refptr<FakePicturePileImpl> green_pile =
+ FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr);
gfx::Transform green_content_to_target_transform;
SharedQuadState* green_shared_state = CreateTestSharedQuadState(
@@ -1779,7 +2250,8 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) {
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport,
gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(),
- texture_format, viewport, 1.f, green_pile.get());
+ nearest_neighbor, texture_format, viewport, 1.f,
+ green_pile.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -1791,10 +2263,11 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) {
}
// Not WithSkiaGPUBackend since that path currently requires tiles for opacity.
-TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) {
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadOpacity) {
gfx::Size pile_tile_size(1000, 1000);
gfx::Rect viewport(this->device_viewport_size_);
ResourceFormat texture_format = RGBA_8888;
+ bool nearest_neighbor = false;
RenderPassId id(1, 1);
gfx::Transform transform_to_root;
@@ -1802,12 +2275,14 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) {
CreateTestRenderPass(id, viewport, transform_to_root);
// One viewport-filling 0.5-opacity green quad.
- scoped_refptr<FakePicturePileImpl> green_pile =
- FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+ scoped_ptr<FakePicturePile> green_recording =
+ FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
SkPaint green_paint;
green_paint.setColor(SK_ColorGREEN);
- green_pile->add_draw_rect_with_paint(viewport, green_paint);
- green_pile->RerecordPile();
+ green_recording->add_draw_rect_with_paint(viewport, green_paint);
+ green_recording->Rerecord();
+ scoped_refptr<FakePicturePileImpl> green_pile =
+ FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr);
gfx::Transform green_content_to_target_transform;
SharedQuadState* green_shared_state = CreateTestSharedQuadState(
@@ -1817,16 +2292,18 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) {
PictureDrawQuad* green_quad =
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport,
- gfx::RectF(0, 0, 1, 1), viewport.size(), texture_format,
- viewport, 1.f, green_pile.get());
+ gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor,
+ texture_format, viewport, 1.f, green_pile.get());
// One viewport-filling white quad.
- scoped_refptr<FakePicturePileImpl> white_pile =
- FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+ scoped_ptr<FakePicturePile> white_recording =
+ FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
SkPaint white_paint;
white_paint.setColor(SK_ColorWHITE);
- white_pile->add_draw_rect_with_paint(viewport, white_paint);
- white_pile->RerecordPile();
+ white_recording->add_draw_rect_with_paint(viewport, white_paint);
+ white_recording->Rerecord();
+ scoped_refptr<FakePicturePileImpl> white_pile =
+ FakePicturePileImpl::CreateFromPile(white_recording.get(), nullptr);
gfx::Transform white_content_to_target_transform;
SharedQuadState* white_shared_state = CreateTestSharedQuadState(
@@ -1835,8 +2312,8 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) {
PictureDrawQuad* white_quad =
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
white_quad->SetNew(white_shared_state, viewport, gfx::Rect(), viewport,
- gfx::RectF(0, 0, 1, 1), viewport.size(), texture_format,
- viewport, 1.f, white_pile.get());
+ gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor,
+ texture_format, viewport, 1.f, white_pile.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -1863,7 +2340,7 @@ bool IsSoftwareRenderer<SoftwareRendererWithExpandedViewport>() {
// If we disable image filtering, then a 2x2 bitmap should appear as four
// huge sharp squares.
-TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) {
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadDisableImageFiltering) {
// We only care about this in software mode since bilinear filtering is
// cheap in hardware.
if (!IsSoftwareRenderer<TypeParam>())
@@ -1872,6 +2349,7 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) {
gfx::Size pile_tile_size(1000, 1000);
gfx::Rect viewport(this->device_viewport_size_);
ResourceFormat texture_format = RGBA_8888;
+ bool nearest_neighbor = false;
RenderPassId id(1, 1);
gfx::Transform transform_to_root;
@@ -1889,12 +2367,14 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) {
canvas.drawPoint(1, 1, SK_ColorGREEN);
}
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+ scoped_ptr<FakePicturePile> recording =
+ FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
SkPaint paint;
- paint.setFilterLevel(SkPaint::kLow_FilterLevel);
- pile->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint);
- pile->RerecordPile();
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ recording->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint);
+ recording->Rerecord();
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording.get(), nullptr);
gfx::Transform content_to_target_transform;
SharedQuadState* shared_state = CreateTestSharedQuadState(
@@ -1902,8 +2382,8 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) {
PictureDrawQuad* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
quad->SetNew(shared_state, viewport, gfx::Rect(), viewport,
- gfx::RectF(0, 0, 2, 2), viewport.size(), texture_format,
- viewport, 1.f, pile.get());
+ gfx::RectF(0, 0, 2, 2), viewport.size(), nearest_neighbor,
+ texture_format, viewport, 1.f, pile.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -1916,11 +2396,222 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) {
ExactPixelComparator(true)));
}
-TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
+// This disables filtering by setting |nearest_neighbor| on the PictureDrawQuad.
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNearestNeighbor) {
+ gfx::Size pile_tile_size(1000, 1000);
+ gfx::Rect viewport(this->device_viewport_size_);
+ ResourceFormat texture_format = RGBA_8888;
+ bool nearest_neighbor = true;
+
+ RenderPassId id(1, 1);
+ gfx::Transform transform_to_root;
+ scoped_ptr<RenderPass> pass =
+ CreateTestRenderPass(id, viewport, transform_to_root);
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(2, 2);
+ {
+ SkAutoLockPixels lock(bitmap);
+ SkCanvas canvas(bitmap);
+ canvas.drawPoint(0, 0, SK_ColorGREEN);
+ canvas.drawPoint(0, 1, SK_ColorBLUE);
+ canvas.drawPoint(1, 0, SK_ColorBLUE);
+ canvas.drawPoint(1, 1, SK_ColorGREEN);
+ }
+
+ scoped_ptr<FakePicturePile> recording =
+ FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
+ SkPaint paint;
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ recording->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint);
+ recording->Rerecord();
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording.get(), nullptr);
+
+ gfx::Transform content_to_target_transform;
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ content_to_target_transform, viewport, pass.get());
+
+ PictureDrawQuad* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
+ quad->SetNew(shared_state, viewport, gfx::Rect(), viewport,
+ gfx::RectF(0, 0, 2, 2), viewport.size(), nearest_neighbor,
+ texture_format, viewport, 1.f, pile.get());
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
+ ExactPixelComparator(true)));
+}
+
+// This disables filtering by setting |nearest_neighbor| on the TileDrawQuad.
+TYPED_TEST(RendererPixelTest, TileDrawQuadNearestNeighbor) {
+ gfx::Rect viewport(this->device_viewport_size_);
+ bool swizzle_contents = true;
+ bool nearest_neighbor = true;
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(2, 2);
+ {
+ SkAutoLockPixels lock(bitmap);
+ SkCanvas canvas(bitmap);
+ canvas.drawPoint(0, 0, SK_ColorGREEN);
+ canvas.drawPoint(0, 1, SK_ColorBLUE);
+ canvas.drawPoint(1, 0, SK_ColorBLUE);
+ canvas.drawPoint(1, 1, SK_ColorGREEN);
+ }
+
+ gfx::Size tile_size(2, 2);
+ ResourceProvider::ResourceId resource =
+ this->resource_provider_->CreateResource(
+ tile_size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
+
+ {
+ SkAutoLockPixels lock(bitmap);
+ this->resource_provider_->CopyToResource(
+ resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
+ }
+
+ RenderPassId id(1, 1);
+ gfx::Transform transform_to_root;
+ scoped_ptr<RenderPass> pass =
+ CreateTestRenderPass(id, viewport, transform_to_root);
+
+ gfx::Transform content_to_target_transform;
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ content_to_target_transform, viewport, pass.get());
+
+ TileDrawQuad* quad = pass->CreateAndAppendDrawQuad<TileDrawQuad>();
+ quad->SetNew(shared_state, viewport, gfx::Rect(), viewport, resource,
+ gfx::Rect(tile_size), tile_size, swizzle_contents,
+ nearest_neighbor);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
+ ExactPixelComparator(true)));
+}
+
+// This disables filtering by setting |nearest_neighbor| to true on the
+// TextureDrawQuad.
+TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadNearestNeighbor) {
+ gfx::Rect viewport(this->device_viewport_size_);
+ bool nearest_neighbor = true;
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(2, 2);
+ {
+ SkAutoLockPixels lock(bitmap);
+ SkCanvas canvas(bitmap);
+ canvas.drawPoint(0, 0, SK_ColorGREEN);
+ canvas.drawPoint(0, 1, SK_ColorBLUE);
+ canvas.drawPoint(1, 0, SK_ColorBLUE);
+ canvas.drawPoint(1, 1, SK_ColorGREEN);
+ }
+
+ gfx::Size tile_size(2, 2);
+ ResourceProvider::ResourceId resource =
+ this->resource_provider_->CreateResource(
+ tile_size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
+
+ {
+ SkAutoLockPixels lock(bitmap);
+ this->resource_provider_->CopyToResource(
+ resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
+ }
+
+ RenderPassId id(1, 1);
+ gfx::Transform transform_to_root;
+ scoped_ptr<RenderPass> pass =
+ CreateTestRenderPass(id, viewport, transform_to_root);
+
+ gfx::Transform content_to_target_transform;
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ content_to_target_transform, viewport, pass.get());
+
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ TextureDrawQuad* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
+ quad->SetNew(shared_state, viewport, gfx::Rect(), viewport, resource, false,
+ gfx::PointF(0, 0), gfx::PointF(1, 1), SK_ColorBLACK,
+ vertex_opacity, false, nearest_neighbor);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
+ FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f)));
+}
+
+// This ensures filtering is enabled by setting |nearest_neighbor| to false on
+// the TextureDrawQuad.
+TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadLinear) {
+ gfx::Rect viewport(this->device_viewport_size_);
+ bool nearest_neighbor = false;
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(2, 2);
+ {
+ SkAutoLockPixels lock(bitmap);
+ SkCanvas canvas(bitmap);
+ canvas.drawPoint(0, 0, SK_ColorGREEN);
+ canvas.drawPoint(0, 1, SK_ColorBLUE);
+ canvas.drawPoint(1, 0, SK_ColorBLUE);
+ canvas.drawPoint(1, 1, SK_ColorGREEN);
+ }
+
+ gfx::Size tile_size(2, 2);
+ ResourceProvider::ResourceId resource =
+ this->resource_provider_->CreateResource(
+ tile_size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
+
+ {
+ SkAutoLockPixels lock(bitmap);
+ this->resource_provider_->CopyToResource(
+ resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
+ }
+
+ RenderPassId id(1, 1);
+ gfx::Transform transform_to_root;
+ scoped_ptr<RenderPass> pass =
+ CreateTestRenderPass(id, viewport, transform_to_root);
+
+ gfx::Transform content_to_target_transform;
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ content_to_target_transform, viewport, pass.get());
+
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ TextureDrawQuad* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
+ quad->SetNew(shared_state, viewport, gfx::Rect(), viewport, resource, false,
+ gfx::PointF(0, 0), gfx::PointF(1, 1), SK_ColorBLACK,
+ vertex_opacity, false, nearest_neighbor);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ // Allow for a small amount of error as the blending alogrithm used by Skia is
+ // affected by the offset in the expanded rect.
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers_linear.png")),
+ FuzzyPixelComparator(false, 100.f, 0.f, 16.f, 16.f, 0.f)));
+}
+
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) {
gfx::Size pile_tile_size(1000, 1000);
gfx::Rect viewport(this->device_viewport_size_);
// TODO(enne): the renderer should figure this out on its own.
ResourceFormat texture_format = RGBA_8888;
+ bool nearest_neighbor = false;
RenderPassId id(1, 1);
gfx::Transform transform_to_root;
@@ -1934,16 +2625,20 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
gfx::Transform green_content_to_target_transform;
gfx::Rect green_rect1(gfx::Point(80, 0), gfx::Size(20, 100));
gfx::Rect green_rect2(gfx::Point(0, 80), gfx::Size(100, 20));
- scoped_refptr<FakePicturePileImpl> green_pile =
- FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+
+ scoped_ptr<FakePicturePile> green_recording =
+ FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
+
SkPaint red_paint;
red_paint.setColor(SK_ColorRED);
- green_pile->add_draw_rect_with_paint(viewport, red_paint);
+ green_recording->add_draw_rect_with_paint(viewport, red_paint);
SkPaint green_paint;
green_paint.setColor(SK_ColorGREEN);
- green_pile->add_draw_rect_with_paint(green_rect1, green_paint);
- green_pile->add_draw_rect_with_paint(green_rect2, green_paint);
- green_pile->RerecordPile();
+ green_recording->add_draw_rect_with_paint(green_rect1, green_paint);
+ green_recording->add_draw_rect_with_paint(green_rect2, green_paint);
+ green_recording->Rerecord();
+ scoped_refptr<FakePicturePileImpl> green_pile =
+ FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr);
SharedQuadState* top_right_green_shared_quad_state =
CreateTestSharedQuadState(
@@ -1953,15 +2648,15 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
green_quad1->SetNew(top_right_green_shared_quad_state, green_rect1,
gfx::Rect(), green_rect1, gfx::RectF(green_rect1.size()),
- green_rect1.size(), texture_format, green_rect1, 1.f,
- green_pile.get());
+ green_rect1.size(), nearest_neighbor, texture_format,
+ green_rect1, 1.f, green_pile.get());
PictureDrawQuad* green_quad2 =
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
green_quad2->SetNew(top_right_green_shared_quad_state, green_rect2,
gfx::Rect(), green_rect2, gfx::RectF(green_rect2.size()),
- green_rect2.size(), texture_format, green_rect2, 1.f,
- green_pile.get());
+ green_rect2.size(), nearest_neighbor, texture_format,
+ green_rect2, 1.f, green_pile.get());
// Add a green clipped checkerboard in the bottom right to help test
// interleaving picture quad content and solid color content.
@@ -1998,20 +2693,22 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
blue_layer_rect1.Inset(inset, inset, inset, inset);
blue_layer_rect2.Inset(inset, inset, inset, inset);
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(pile_tile_size, layer_rect.size());
+ scoped_ptr<FakePicturePile> recording =
+ FakePicturePile::CreateFilledPile(pile_tile_size, layer_rect.size());
Region outside(layer_rect);
outside.Subtract(gfx::ToEnclosingRect(union_layer_rect));
for (Region::Iterator iter(outside); iter.has_rect(); iter.next()) {
- pile->add_draw_rect_with_paint(iter.rect(), red_paint);
+ recording->add_draw_rect_with_paint(iter.rect(), red_paint);
}
SkPaint blue_paint;
blue_paint.setColor(SK_ColorBLUE);
- pile->add_draw_rect_with_paint(blue_layer_rect1, blue_paint);
- pile->add_draw_rect_with_paint(blue_layer_rect2, blue_paint);
- pile->RerecordPile();
+ recording->add_draw_rect_with_paint(blue_layer_rect1, blue_paint);
+ recording->add_draw_rect_with_paint(blue_layer_rect2, blue_paint);
+ recording->Rerecord();
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording.get(), nullptr);
gfx::Rect content_rect(
gfx::ScaleToEnclosingRect(layer_rect, contents_scale));
@@ -2029,7 +2726,7 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
blue_quad->SetNew(blue_shared_state, quad_content_rect, gfx::Rect(),
quad_content_rect, gfx::RectF(quad_content_rect),
- content_union_rect.size(), texture_format,
+ content_union_rect.size(), nearest_neighbor, texture_format,
content_union_rect, contents_scale, pile.get());
// Fill left half of viewport with green.
@@ -2210,41 +2907,6 @@ TEST_F(GLRendererPixelTest, CheckReadbackSubset) {
&capture_rect));
}
-TEST_F(GLRendererPixelTest, PictureDrawQuadTexture4444) {
- gfx::Size pile_tile_size(1000, 1000);
- gfx::Rect viewport(this->device_viewport_size_);
- ResourceFormat texture_format = RGBA_4444;
-
- RenderPassId id(1, 1);
- gfx::Transform transform_to_root;
- scoped_ptr<RenderPass> pass =
- CreateTestRenderPass(id, viewport, transform_to_root);
-
- // One viewport-filling blue quad
- scoped_refptr<FakePicturePileImpl> blue_pile =
- FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
- SkPaint blue_paint;
- blue_paint.setColor(SK_ColorBLUE);
- blue_pile->add_draw_rect_with_paint(viewport, blue_paint);
- blue_pile->RerecordPile();
-
- gfx::Transform blue_content_to_target_transform;
- SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
- blue_content_to_target_transform, viewport, pass.get());
-
- PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- blue_quad->SetNew(blue_shared_state, viewport, gfx::Rect(), viewport,
- gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(),
- texture_format, viewport, 1.f, blue_pile.get());
-
- RenderPassList pass_list;
- pass_list.push_back(pass.Pass());
-
- EXPECT_TRUE(this->RunPixelTest(&pass_list,
- base::FilePath(FILE_PATH_LITERAL("blue.png")),
- ExactPixelComparator(true)));
-}
-
TYPED_TEST(RendererPixelTest, WrapModeRepeat) {
gfx::Rect rect(this->device_viewport_size_);
@@ -2254,7 +2916,7 @@ TYPED_TEST(RendererPixelTest, WrapModeRepeat) {
SharedQuadState* shared_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
- gfx::Rect texture_rect(4, 4);
+ gfx::Size texture_size(4, 4);
SkPMColor colors[4] = {
SkPreMultiplyColor(SkColorSetARGB(255, 0, 255, 0)),
SkPreMultiplyColor(SkColorSetARGB(255, 0, 128, 0)),
@@ -2269,34 +2931,25 @@ TYPED_TEST(RendererPixelTest, WrapModeRepeat) {
};
ResourceProvider::ResourceId resource =
this->resource_provider_->CreateResource(
- texture_rect.size(),
- GL_REPEAT,
- ResourceProvider::TextureHintImmutable,
+ texture_size, GL_REPEAT, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
RGBA_8888);
- this->resource_provider_->SetPixels(
- resource,
- reinterpret_cast<uint8_t*>(pixels),
- texture_rect,
- texture_rect,
- gfx::Vector2d());
+ this->resource_provider_->CopyToResource(
+ resource, reinterpret_cast<uint8_t*>(pixels), texture_size);
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
TextureDrawQuad* texture_quad =
pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
texture_quad->SetNew(
- shared_state,
- gfx::Rect(this->device_viewport_size_),
- gfx::Rect(),
- gfx::Rect(this->device_viewport_size_),
- resource,
+ shared_state, gfx::Rect(this->device_viewport_size_), gfx::Rect(),
+ gfx::Rect(this->device_viewport_size_), resource,
true, // premultiplied_alpha
gfx::PointF(0.0f, 0.0f), // uv_top_left
gfx::PointF( // uv_bottom_right
- this->device_viewport_size_.width() / texture_rect.width(),
- this->device_viewport_size_.height() / texture_rect.height()),
- SK_ColorWHITE,
- vertex_opacity,
- false); // flipped
+ this->device_viewport_size_.width() / texture_size.width(),
+ this->device_viewport_size_.height() / texture_size.height()),
+ SK_ColorWHITE, vertex_opacity,
+ false, // flipped
+ false); // nearest_neighbor
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -2307,6 +2960,109 @@ TYPED_TEST(RendererPixelTest, WrapModeRepeat) {
FuzzyPixelOffByOneComparator(true)));
}
+TYPED_TEST(RendererPixelTest, Checkerboards) {
+ gfx::Rect rect(this->device_viewport_size_);
+
+ RenderPassId id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+
+ // The color's alpha value is not used.
+ SkColor color1 = SK_ColorGREEN;
+ color1 = SkColorSetA(color1, 0);
+ SkColor color2 = SK_ColorBLUE;
+ color2 = SkColorSetA(color2, 0);
+
+ gfx::Rect content_rect(rect);
+
+ gfx::Rect top_left(content_rect);
+ gfx::Rect top_right(content_rect);
+ gfx::Rect bottom_left(content_rect);
+ gfx::Rect bottom_right(content_rect);
+ // The format is Inset(left, top, right, bottom).
+ top_left.Inset(0, 0, content_rect.width() / 2, content_rect.height() / 2);
+ top_right.Inset(content_rect.width() / 2, 0, 0, content_rect.height() / 2);
+ bottom_left.Inset(0, content_rect.height() / 2, content_rect.width() / 2, 0);
+ bottom_right.Inset(content_rect.width() / 2, content_rect.height() / 2, 0, 0);
+
+ // Appends checkerboard quads with a scale of 1.
+ CheckerboardDrawQuad* quad =
+ pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
+ quad->SetNew(shared_state, top_left, top_left, color1, 1.f);
+ quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
+ quad->SetNew(shared_state, top_right, top_right, color2, 1.f);
+ quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
+ quad->SetNew(shared_state, bottom_left, bottom_left, color2, 1.f);
+ quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
+ quad->SetNew(shared_state, bottom_right, bottom_right, color1, 1.f);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ base::FilePath::StringType path =
+ IsSoftwareRenderer<TypeParam>()
+ ? FILE_PATH_LITERAL("four_blue_green_checkers.png")
+ : FILE_PATH_LITERAL("checkers.png");
+ EXPECT_TRUE(this->RunPixelTest(&pass_list, base::FilePath(path),
+ ExactPixelComparator(true)));
+}
+
+TYPED_TEST(RendererPixelTest, CheckerboardsScaled) {
+ gfx::Rect rect(this->device_viewport_size_);
+
+ RenderPassId id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+
+ gfx::Transform scale;
+ scale.Scale(2.f, 2.f);
+
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(scale, rect, pass.get());
+
+ // The color's alpha value is not used.
+ SkColor color1 = SK_ColorGREEN;
+ color1 = SkColorSetA(color1, 0);
+ SkColor color2 = SK_ColorBLUE;
+ color2 = SkColorSetA(color2, 0);
+
+ gfx::Rect content_rect(rect);
+ content_rect.Inset(0, 0, rect.width() / 2, rect.height() / 2);
+
+ gfx::Rect top_left(content_rect);
+ gfx::Rect top_right(content_rect);
+ gfx::Rect bottom_left(content_rect);
+ gfx::Rect bottom_right(content_rect);
+ // The format is Inset(left, top, right, bottom).
+ top_left.Inset(0, 0, content_rect.width() / 2, content_rect.height() / 2);
+ top_right.Inset(content_rect.width() / 2, 0, 0, content_rect.height() / 2);
+ bottom_left.Inset(0, content_rect.height() / 2, content_rect.width() / 2, 0);
+ bottom_right.Inset(content_rect.width() / 2, content_rect.height() / 2, 0, 0);
+
+ // Appends checkerboard quads with a scale of 2, and a shared quad state
+ // with a scale of 2. The checkers should be scaled by 2 * 2 = 4.
+ CheckerboardDrawQuad* quad =
+ pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
+ quad->SetNew(shared_state, top_left, top_left, color1, 2.f);
+ quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
+ quad->SetNew(shared_state, top_right, top_right, color2, 2.f);
+ quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
+ quad->SetNew(shared_state, bottom_left, bottom_left, color2, 2.f);
+ quad = pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
+ quad->SetNew(shared_state, bottom_right, bottom_right, color1, 2.f);
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ base::FilePath::StringType path =
+ IsSoftwareRenderer<TypeParam>()
+ ? FILE_PATH_LITERAL("four_blue_green_checkers.png")
+ : FILE_PATH_LITERAL("checkers_big.png");
+ EXPECT_TRUE(this->RunPixelTest(&pass_list, base::FilePath(path),
+ ExactPixelComparator(true)));
+}
+
#endif // !defined(OS_ANDROID)
} // namespace
diff --git a/chromium/cc/output/renderer_settings.cc b/chromium/cc/output/renderer_settings.cc
new file mode 100644
index 00000000000..2277af3ed3c
--- /dev/null
+++ b/chromium/cc/output/renderer_settings.cc
@@ -0,0 +1,29 @@
+// Copyright 2014 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/output/renderer_settings.h"
+
+#include <limits>
+
+#include "base/logging.h"
+
+namespace cc {
+
+RendererSettings::RendererSettings()
+ : allow_antialiasing(true),
+ force_antialiasing(false),
+ force_blending_with_shaders(false),
+ partial_swap_enabled(false),
+ finish_rendering_on_resize(false),
+ should_clear_root_render_pass(true),
+ refresh_rate(60.0),
+ highp_threshold_min(0),
+ use_rgba_4444_textures(false),
+ texture_id_allocation_chunk_size(64) {
+}
+
+RendererSettings::~RendererSettings() {
+}
+
+} // namespace cc
diff --git a/chromium/cc/output/renderer_settings.h b/chromium/cc/output/renderer_settings.h
new file mode 100644
index 00000000000..6da02383826
--- /dev/null
+++ b/chromium/cc/output/renderer_settings.h
@@ -0,0 +1,32 @@
+// Copyright 2014 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_OUTPUT_RENDERER_SETTINGS_H_
+#define CC_OUTPUT_RENDERER_SETTINGS_H_
+
+#include "base/basictypes.h"
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+class CC_EXPORT RendererSettings {
+ public:
+ RendererSettings();
+ ~RendererSettings();
+
+ bool allow_antialiasing;
+ bool force_antialiasing;
+ bool force_blending_with_shaders;
+ bool partial_swap_enabled;
+ bool finish_rendering_on_resize;
+ bool should_clear_root_render_pass;
+ double refresh_rate;
+ int highp_threshold_min;
+ bool use_rgba_4444_textures;
+ size_t texture_id_allocation_chunk_size;
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_RENDERER_SETTINGS_H_
diff --git a/chromium/cc/output/renderer_unittest.cc b/chromium/cc/output/renderer_unittest.cc
index 6e43cc0e0a0..a8f09ff9474 100644
--- a/chromium/cc/output/renderer_unittest.cc
+++ b/chromium/cc/output/renderer_unittest.cc
@@ -50,14 +50,14 @@ class MockContextProvider : public TestContextProvider {
template <class T>
scoped_ptr<Renderer> CreateRenderer(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider);
template <>
scoped_ptr<Renderer> CreateRenderer<DelegatingRenderer>(
RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider) {
return DelegatingRenderer::Create(
@@ -67,7 +67,7 @@ scoped_ptr<Renderer> CreateRenderer<DelegatingRenderer>(
template <>
scoped_ptr<Renderer> CreateRenderer<GLRenderer>(
RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider) {
return GLRenderer::Create(
@@ -91,7 +91,7 @@ class RendererTest : public ::testing::Test {
}
FakeRendererClient renderer_client_;
- LayerTreeSettings tree_settings_;
+ RendererSettings tree_settings_;
FakeOutputSurfaceClient output_surface_client_;
scoped_refptr<MockContextProvider> context_provider_;
scoped_ptr<OutputSurface> output_surface_;
diff --git a/chromium/cc/output/shader.cc b/chromium/cc/output/shader.cc
index b962d4ace91..15ad7e05fa7 100644
--- a/chromium/cc/output/shader.cc
+++ b/chromium/cc/output/shader.cc
@@ -8,15 +8,28 @@
#include "base/basictypes.h"
#include "base/logging.h"
-#include "cc/output/gl_renderer.h" // For the GLC() macro.
#include "gpu/command_buffer/client/gles2_interface.h"
-
-#define SHADER0(Src) #Src
-#define VERTEX_SHADER(Src) SetVertexTexCoordPrecision(SHADER0(Src))
-#define FRAGMENT_SHADER(Src) \
- SetFragmentTexCoordPrecision( \
- precision, \
- SetFragmentSamplerType(sampler, SetBlendModeFunctions(SHADER0(Src))))
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+
+template <size_t size>
+std::string StripLambda(const char(&shader)[size]) {
+ // Must contain at least "[]() {}" and trailing null (included in size).
+ static_assert(size >= 8,
+ "String passed to StripLambda must be at least 8 characters");
+ DCHECK_EQ(strncmp("[]() {", shader, 6), 0);
+ DCHECK_EQ(shader[size - 2], '}');
+ return std::string(shader + 6, shader + size - 2);
+}
+
+// Shaders are passed in with lambda syntax, which tricks clang-format into
+// handling them correctly. StipLambda removes this.
+#define SHADER0(Src) StripLambda(#Src)
+#define VERTEX_SHADER(Head, Body) SetVertexTexCoordPrecision(Head + Body)
+#define FRAGMENT_SHADER(Head, Body) \
+ SetFragmentTexCoordPrecision( \
+ precision, \
+ SetFragmentSamplerType(sampler, SetBlendModeFunctions(Head + Body)))
using gpu::gles2::GLES2Interface;
@@ -40,7 +53,7 @@ static std::string SetFragmentTexCoordPrecision(
TexCoordPrecision requested_precision,
std::string shader_string) {
switch (requested_precision) {
- case TexCoordPrecisionHigh:
+ case TEX_COORD_PRECISION_HIGH:
DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos);
return "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
" #define TexCoordPrecision highp\n"
@@ -48,10 +61,10 @@ static std::string SetFragmentTexCoordPrecision(
" #define TexCoordPrecision mediump\n"
"#endif\n" +
shader_string;
- case TexCoordPrecisionMedium:
+ case TEX_COORD_PRECISION_MEDIUM:
DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos);
return "#define TexCoordPrecision mediump\n" + shader_string;
- case TexCoordPrecisionNA:
+ case TEX_COORD_PRECISION_NA:
DCHECK_EQ(shader_string.find("TexCoordPrecision"), std::string::npos);
DCHECK_EQ(shader_string.find("texture2D"), std::string::npos);
DCHECK_EQ(shader_string.find("texture2DRect"), std::string::npos);
@@ -63,12 +76,13 @@ static std::string SetFragmentTexCoordPrecision(
return shader_string;
}
-static std::string SetVertexTexCoordPrecision(const char* shader_string) {
+static std::string SetVertexTexCoordPrecision(
+ const std::string& shader_string) {
// We unconditionally use highp in the vertex shader since
// we are unlikely to be vertex shader bound when drawing large quads.
// Also, some vertex shaders mutate the texture coordinate in such a
// way that the effective precision might be lower than expected.
- return "#define TexCoordPrecision highp\n" + std::string(shader_string);
+ return "#define TexCoordPrecision highp\n" + shader_string;
}
TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
@@ -83,42 +97,41 @@ TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
// everywhere.
GLint range[2] = {14, 14};
GLint precision = 10;
- GLC(context,
- context->GetShaderPrecisionFormat(
- GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, range, &precision));
+ context->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
+ range, &precision);
*highp_threshold_cache = 1 << precision;
}
int highp_threshold = std::max(*highp_threshold_cache, highp_threshold_min);
if (x > highp_threshold || y > highp_threshold)
- return TexCoordPrecisionHigh;
- return TexCoordPrecisionMedium;
+ return TEX_COORD_PRECISION_HIGH;
+ return TEX_COORD_PRECISION_MEDIUM;
}
static std::string SetFragmentSamplerType(SamplerType requested_type,
std::string shader_string) {
switch (requested_type) {
- case SamplerType2D:
+ case SAMPLER_TYPE_2D:
DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
return "#define SamplerType sampler2D\n"
"#define TextureLookup texture2D\n" +
shader_string;
- case SamplerType2DRect:
+ case SAMPLER_TYPE_2D_RECT:
DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
return "#extension GL_ARB_texture_rectangle : require\n"
"#define SamplerType sampler2DRect\n"
"#define TextureLookup texture2DRect\n" +
shader_string;
- case SamplerTypeExternalOES:
+ case SAMPLER_TYPE_EXTERNAL_OES:
DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
return "#extension GL_OES_EGL_image_external : require\n"
"#define SamplerType samplerExternalOES\n"
"#define TextureLookup texture2D\n" +
shader_string;
- case SamplerTypeNA:
+ case SAMPLER_TYPE_NA:
DCHECK_EQ(shader_string.find("SamplerType"), std::string::npos);
DCHECK_EQ(shader_string.find("TextureLookup"), std::string::npos);
return shader_string;
@@ -131,6 +144,9 @@ static std::string SetFragmentSamplerType(SamplerType requested_type,
} // namespace
+ShaderLocations::ShaderLocations() {
+}
+
TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
int* highp_threshold_cache,
int highp_threshold_min,
@@ -174,31 +190,40 @@ void VertexShaderPosTex::Init(GLES2Interface* context,
}
std::string VertexShaderPosTex::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute vec4 a_position;
- attribute TexCoordPrecision vec2 a_texCoord;
- uniform mat4 matrix;
- varying TexCoordPrecision vec2 v_texCoord;
- void main() {
- gl_Position = matrix * a_position;
- v_texCoord = a_texCoord;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPosTex::GetShaderHead() {
+ return SHADER0([]() {
+ attribute vec4 a_position;
+ attribute TexCoordPrecision vec2 a_texCoord;
+ uniform mat4 matrix;
+ varying TexCoordPrecision vec2 v_texCoord;
+ });
+}
+
+std::string VertexShaderPosTex::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ gl_Position = matrix * a_position;
+ v_texCoord = a_texCoord;
+ }
+ });
}
VertexShaderPosTexYUVStretchOffset::VertexShaderPosTexYUVStretchOffset()
- : matrix_location_(-1), tex_scale_location_(-1), tex_offset_location_(-1) {
+ : matrix_location_(-1),
+ ya_tex_scale_location_(-1),
+ ya_tex_offset_location_(-1),
+ uv_tex_scale_location_(-1),
+ uv_tex_offset_location_(-1) {
}
void VertexShaderPosTexYUVStretchOffset::Init(GLES2Interface* context,
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "matrix", "texScale", "texOffset",
+ "matrix", "yaTexScale", "yaTexOffset", "uvTexScale", "uvTexOffset",
};
int locations[arraysize(uniforms)];
@@ -209,28 +234,39 @@ void VertexShaderPosTexYUVStretchOffset::Init(GLES2Interface* context,
locations,
base_uniform_index);
matrix_location_ = locations[0];
- tex_scale_location_ = locations[1];
- tex_offset_location_ = locations[2];
+ ya_tex_scale_location_ = locations[1];
+ ya_tex_offset_location_ = locations[2];
+ uv_tex_scale_location_ = locations[3];
+ uv_tex_offset_location_ = locations[4];
}
std::string VertexShaderPosTexYUVStretchOffset::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- precision mediump float;
- attribute vec4 a_position;
- attribute TexCoordPrecision vec2 a_texCoord;
- uniform mat4 matrix;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform TexCoordPrecision vec2 texScale;
- uniform TexCoordPrecision vec2 texOffset;
- void main() {
- gl_Position = matrix * a_position;
- v_texCoord = a_texCoord * texScale + texOffset;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPosTexYUVStretchOffset::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ attribute vec4 a_position;
+ attribute TexCoordPrecision vec2 a_texCoord;
+ uniform mat4 matrix;
+ varying TexCoordPrecision vec2 v_yaTexCoord;
+ varying TexCoordPrecision vec2 v_uvTexCoord;
+ uniform TexCoordPrecision vec2 yaTexScale;
+ uniform TexCoordPrecision vec2 yaTexOffset;
+ uniform TexCoordPrecision vec2 uvTexScale;
+ uniform TexCoordPrecision vec2 uvTexOffset;
+ });
+}
+
+std::string VertexShaderPosTexYUVStretchOffset::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ gl_Position = matrix * a_position;
+ v_yaTexCoord = a_texCoord * yaTexScale + yaTexOffset;
+ v_uvTexCoord = a_texCoord * uvTexScale + uvTexOffset;
+ }
+ });
}
VertexShaderPos::VertexShaderPos() : matrix_location_(-1) {
@@ -254,15 +290,20 @@ void VertexShaderPos::Init(GLES2Interface* context,
}
std::string VertexShaderPos::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute vec4 a_position;
- uniform mat4 matrix;
- void main() { gl_Position = matrix * a_position; }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPos::GetShaderHead() {
+ return SHADER0([]() {
+ attribute vec4 a_position;
+ uniform mat4 matrix;
+ });
+}
+
+std::string VertexShaderPos::GetShaderBody() {
+ return SHADER0([]() {
+ void main() { gl_Position = matrix * a_position; }
+ });
}
VertexShaderPosTexTransform::VertexShaderPosTexTransform()
@@ -291,42 +332,58 @@ void VertexShaderPosTexTransform::Init(GLES2Interface* context,
}
std::string VertexShaderPosTexTransform::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute vec4 a_position;
- attribute TexCoordPrecision vec2 a_texCoord;
- attribute float a_index;
- uniform mat4 matrix[8];
- uniform TexCoordPrecision vec4 texTransform[8];
- uniform float opacity[32];
- varying TexCoordPrecision vec2 v_texCoord;
- varying float v_alpha;
- void main() {
- int quad_index = int(a_index * 0.25); // NOLINT
- gl_Position = matrix[quad_index] * a_position;
- TexCoordPrecision vec4 texTrans = texTransform[quad_index];
- v_texCoord = a_texCoord * texTrans.zw + texTrans.xy;
- v_alpha = opacity[int(a_index)]; // NOLINT
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPosTexTransform::GetShaderHead() {
+ return SHADER0([]() {
+ attribute vec4 a_position;
+ attribute TexCoordPrecision vec2 a_texCoord;
+ attribute float a_index;
+ uniform mat4 matrix[8];
+ uniform TexCoordPrecision vec4 texTransform[8];
+ uniform float opacity[32];
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying float v_alpha;
+ });
+}
+
+std::string VertexShaderPosTexTransform::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ int quad_index = int(a_index * 0.25); // NOLINT
+ gl_Position = matrix[quad_index] * a_position;
+ TexCoordPrecision vec4 texTrans = texTransform[quad_index];
+ v_texCoord = a_texCoord * texTrans.zw + texTrans.xy;
+ v_alpha = opacity[int(a_index)]; // NOLINT
+ }
+ });
+}
+
+void VertexShaderPosTexTransform::FillLocations(
+ ShaderLocations* locations) const {
+ locations->matrix = matrix_location();
+ locations->tex_transform = tex_transform_location();
}
std::string VertexShaderPosTexIdentity::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute vec4 a_position;
- varying TexCoordPrecision vec2 v_texCoord;
- void main() {
- gl_Position = a_position;
- v_texCoord = (a_position.xy + vec2(1.0)) * 0.5;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPosTexIdentity::GetShaderHead() {
+ return SHADER0([]() {
+ attribute vec4 a_position;
+ varying TexCoordPrecision vec2 v_texCoord;
+ });
+}
+
+std::string VertexShaderPosTexIdentity::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ gl_Position = a_position;
+ v_texCoord = (a_position.xy + vec2(1.0)) * 0.5;
+ }
+ });
}
VertexShaderQuad::VertexShaderQuad()
@@ -352,42 +409,48 @@ void VertexShaderQuad::Init(GLES2Interface* context,
}
std::string VertexShaderQuad::GetShaderString() const {
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderQuad::GetShaderHead() {
#if defined(OS_ANDROID)
// TODO(epenner): Find the cause of this 'quad' uniform
// being missing if we don't add dummy variables.
// http://crbug.com/240602
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute TexCoordPrecision vec4 a_position;
- attribute float a_index;
- uniform mat4 matrix;
- uniform TexCoordPrecision vec2 quad[4];
- uniform TexCoordPrecision vec2 dummy_uniform;
- varying TexCoordPrecision vec2 dummy_varying;
- void main() {
- vec2 pos = quad[int(a_index)]; // NOLINT
- gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
- dummy_varying = dummy_uniform;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
-// clang-format on
+ return SHADER0([]() {
+ attribute TexCoordPrecision vec4 a_position;
+ attribute float a_index;
+ uniform mat4 matrix;
+ uniform TexCoordPrecision vec2 quad[4];
+ uniform TexCoordPrecision vec2 dummy_uniform;
+ varying TexCoordPrecision vec2 dummy_varying;
+ });
#else
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute TexCoordPrecision vec4 a_position;
- attribute float a_index;
- uniform mat4 matrix;
- uniform TexCoordPrecision vec2 quad[4];
- void main() {
- vec2 pos = quad[int(a_index)]; // NOLINT
- gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
-// clang-format on
+ return SHADER0([]() {
+ attribute TexCoordPrecision vec4 a_position;
+ attribute float a_index;
+ uniform mat4 matrix;
+ uniform TexCoordPrecision vec2 quad[4];
+ });
+#endif
+}
+
+std::string VertexShaderQuad::GetShaderBody() {
+#if defined(OS_ANDROID)
+ return SHADER0([]() {
+ void main() {
+ vec2 pos = quad[int(a_index)]; // NOLINT
+ gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+ dummy_varying = dummy_uniform;
+ }
+ });
+#else
+ return SHADER0([]() {
+ void main() {
+ vec2 pos = quad[int(a_index)]; // NOLINT
+ gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+ }
+ });
#endif
}
@@ -419,36 +482,36 @@ void VertexShaderQuadAA::Init(GLES2Interface* context,
}
std::string VertexShaderQuadAA::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute TexCoordPrecision vec4 a_position;
- attribute float a_index;
- uniform mat4 matrix;
- uniform vec4 viewport;
- uniform TexCoordPrecision vec2 quad[4];
- uniform TexCoordPrecision vec3 edge[8];
- varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- vec2 pos = quad[int(a_index)]; // NOLINT
- gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
- vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
- vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
- edge_dist[0] = vec4(dot(edge[0], screen_pos),
- dot(edge[1], screen_pos),
- dot(edge[2], screen_pos),
- dot(edge[3], screen_pos)) *
- gl_Position.w;
- edge_dist[1] = vec4(dot(edge[4], screen_pos),
- dot(edge[5], screen_pos),
- dot(edge[6], screen_pos),
- dot(edge[7], screen_pos)) *
- gl_Position.w;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderQuadAA::GetShaderHead() {
+ return SHADER0([]() {
+ attribute TexCoordPrecision vec4 a_position;
+ attribute float a_index;
+ uniform mat4 matrix;
+ uniform vec4 viewport;
+ uniform TexCoordPrecision vec2 quad[4];
+ uniform TexCoordPrecision vec3 edge[8];
+ varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string VertexShaderQuadAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec2 pos = quad[int(a_index)]; // NOLINT
+ gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+ vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
+ vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
+ edge_dist[0] = vec4(dot(edge[0], screen_pos), dot(edge[1], screen_pos),
+ dot(edge[2], screen_pos), dot(edge[3], screen_pos)) *
+ gl_Position.w;
+ edge_dist[1] = vec4(dot(edge[4], screen_pos), dot(edge[5], screen_pos),
+ dot(edge[6], screen_pos), dot(edge[7], screen_pos)) *
+ gl_Position.w;
+ }
+ });
}
VertexShaderQuadTexTransformAA::VertexShaderQuadTexTransformAA()
@@ -481,41 +544,51 @@ void VertexShaderQuadTexTransformAA::Init(GLES2Interface* context,
}
std::string VertexShaderQuadTexTransformAA::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute TexCoordPrecision vec4 a_position;
- attribute float a_index;
- uniform mat4 matrix;
- uniform vec4 viewport;
- uniform TexCoordPrecision vec2 quad[4];
- uniform TexCoordPrecision vec3 edge[8];
- uniform TexCoordPrecision vec4 texTrans;
- varying TexCoordPrecision vec2 v_texCoord;
- varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- vec2 pos = quad[int(a_index)]; // NOLINT
- gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
- vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
- vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
- edge_dist[0] = vec4(dot(edge[0], screen_pos),
- dot(edge[1], screen_pos),
- dot(edge[2], screen_pos),
- dot(edge[3], screen_pos)) *
- gl_Position.w;
- edge_dist[1] = vec4(dot(edge[4], screen_pos),
- dot(edge[5], screen_pos),
- dot(edge[6], screen_pos),
- dot(edge[7], screen_pos)) *
- gl_Position.w;
- v_texCoord = (pos.xy + vec2(0.5)) * texTrans.zw + texTrans.xy;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderQuadTexTransformAA::GetShaderHead() {
+ return SHADER0([]() {
+ attribute TexCoordPrecision vec4 a_position;
+ attribute float a_index;
+ uniform mat4 matrix;
+ uniform vec4 viewport;
+ uniform TexCoordPrecision vec2 quad[4];
+ uniform TexCoordPrecision vec3 edge[8];
+ uniform TexCoordPrecision vec4 texTrans;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string VertexShaderQuadTexTransformAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec2 pos = quad[int(a_index)]; // NOLINT
+ gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+ vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
+ vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
+ edge_dist[0] = vec4(dot(edge[0], screen_pos), dot(edge[1], screen_pos),
+ dot(edge[2], screen_pos), dot(edge[3], screen_pos)) *
+ gl_Position.w;
+ edge_dist[1] = vec4(dot(edge[4], screen_pos), dot(edge[5], screen_pos),
+ dot(edge[6], screen_pos), dot(edge[7], screen_pos)) *
+ gl_Position.w;
+ v_texCoord = (pos.xy + vec2(0.5)) * texTrans.zw + texTrans.xy;
+ }
+ });
+}
+
+void VertexShaderQuadTexTransformAA::FillLocations(
+ ShaderLocations* locations) const {
+ locations->quad = quad_location();
+ locations->edge = edge_location();
+ locations->viewport = viewport_location();
+ locations->matrix = matrix_location();
+ locations->tex_transform = tex_transform_location();
}
+
VertexShaderTile::VertexShaderTile()
: matrix_location_(-1),
quad_location_(-1),
@@ -542,24 +615,29 @@ void VertexShaderTile::Init(GLES2Interface* context,
}
std::string VertexShaderTile::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute TexCoordPrecision vec4 a_position;
- attribute TexCoordPrecision vec2 a_texCoord;
- attribute float a_index;
- uniform mat4 matrix;
- uniform TexCoordPrecision vec2 quad[4];
- uniform TexCoordPrecision vec4 vertexTexTransform;
- varying TexCoordPrecision vec2 v_texCoord;
- void main() {
- vec2 pos = quad[int(a_index)]; // NOLINT
- gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
- v_texCoord = a_texCoord * vertexTexTransform.zw + vertexTexTransform.xy;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderTile::GetShaderHead() {
+ return SHADER0([]() {
+ attribute TexCoordPrecision vec4 a_position;
+ attribute TexCoordPrecision vec2 a_texCoord;
+ attribute float a_index;
+ uniform mat4 matrix;
+ uniform TexCoordPrecision vec2 quad[4];
+ uniform TexCoordPrecision vec4 vertexTexTransform;
+ varying TexCoordPrecision vec2 v_texCoord;
+ });
+}
+
+std::string VertexShaderTile::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec2 pos = quad[int(a_index)]; // NOLINT
+ gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+ v_texCoord = a_texCoord * vertexTexTransform.zw + vertexTexTransform.xy;
+ }
+ });
}
VertexShaderTileAA::VertexShaderTileAA()
@@ -592,39 +670,39 @@ void VertexShaderTileAA::Init(GLES2Interface* context,
}
std::string VertexShaderTileAA::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute TexCoordPrecision vec4 a_position;
- attribute float a_index;
- uniform mat4 matrix;
- uniform vec4 viewport;
- uniform TexCoordPrecision vec2 quad[4];
- uniform TexCoordPrecision vec3 edge[8];
- uniform TexCoordPrecision vec4 vertexTexTransform;
- varying TexCoordPrecision vec2 v_texCoord;
- varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- vec2 pos = quad[int(a_index)]; // NOLINT
- gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
- vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
- vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
- edge_dist[0] = vec4(dot(edge[0], screen_pos),
- dot(edge[1], screen_pos),
- dot(edge[2], screen_pos),
- dot(edge[3], screen_pos)) *
- gl_Position.w;
- edge_dist[1] = vec4(dot(edge[4], screen_pos),
- dot(edge[5], screen_pos),
- dot(edge[6], screen_pos),
- dot(edge[7], screen_pos)) *
- gl_Position.w;
- v_texCoord = pos.xy * vertexTexTransform.zw + vertexTexTransform.xy;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderTileAA::GetShaderHead() {
+ return SHADER0([]() {
+ attribute TexCoordPrecision vec4 a_position;
+ attribute float a_index;
+ uniform mat4 matrix;
+ uniform vec4 viewport;
+ uniform TexCoordPrecision vec2 quad[4];
+ uniform TexCoordPrecision vec3 edge[8];
+ uniform TexCoordPrecision vec4 vertexTexTransform;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string VertexShaderTileAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec2 pos = quad[int(a_index)]; // NOLINT
+ gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+ vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
+ vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
+ edge_dist[0] = vec4(dot(edge[0], screen_pos), dot(edge[1], screen_pos),
+ dot(edge[2], screen_pos), dot(edge[3], screen_pos)) *
+ gl_Position.w;
+ edge_dist[1] = vec4(dot(edge[4], screen_pos), dot(edge[5], screen_pos),
+ dot(edge[6], screen_pos), dot(edge[7], screen_pos)) *
+ gl_Position.w;
+ v_texCoord = pos.xy * vertexTexTransform.zw + vertexTexTransform.xy;
+ }
+ });
}
VertexShaderVideoTransform::VertexShaderVideoTransform()
@@ -650,37 +728,47 @@ void VertexShaderVideoTransform::Init(GLES2Interface* context,
}
std::string VertexShaderVideoTransform::GetShaderString() const {
- // clang-format off
- return VERTEX_SHADER(
- // clang-format on
- attribute vec4 a_position;
- attribute TexCoordPrecision vec2 a_texCoord;
- uniform mat4 matrix;
- uniform TexCoordPrecision mat4 texMatrix;
- varying TexCoordPrecision vec2 v_texCoord;
- void main() {
- gl_Position = matrix * a_position;
- v_texCoord =
- vec2(texMatrix * vec4(a_texCoord.x, 1.0 - a_texCoord.y, 0.0, 1.0));
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderVideoTransform::GetShaderHead() {
+ return SHADER0([]() {
+ attribute vec4 a_position;
+ attribute TexCoordPrecision vec2 a_texCoord;
+ uniform mat4 matrix;
+ uniform TexCoordPrecision mat4 texMatrix;
+ varying TexCoordPrecision vec2 v_texCoord;
+ });
+}
+
+std::string VertexShaderVideoTransform::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ gl_Position = matrix * a_position;
+ v_texCoord =
+ vec2(texMatrix * vec4(a_texCoord.x, 1.0 - a_texCoord.y, 0.0, 1.0));
+ }
+ });
}
-#define BLEND_MODE_UNIFORMS "s_backdropTexture", "backdropRect"
-#define UNUSED_BLEND_MODE_UNIFORMS (is_default_blend_mode() ? 2 : 0)
+#define BLEND_MODE_UNIFORMS "s_backdropTexture", \
+ "s_originalBackdropTexture", \
+ "backdropRect"
+#define UNUSED_BLEND_MODE_UNIFORMS (!has_blend_mode() ? 3 : 0)
#define BLEND_MODE_SET_LOCATIONS(X, POS) \
- if (!is_default_blend_mode()) { \
- DCHECK_LT(static_cast<size_t>(POS) + 1, arraysize(X)); \
+ if (has_blend_mode()) { \
+ DCHECK_LT(static_cast<size_t>(POS) + 2, arraysize(X)); \
backdrop_location_ = locations[POS]; \
- backdrop_rect_location_ = locations[POS + 1]; \
+ original_backdrop_location_ = locations[POS + 1]; \
+ backdrop_rect_location_ = locations[POS + 2]; \
}
FragmentTexBlendMode::FragmentTexBlendMode()
: backdrop_location_(-1),
+ original_backdrop_location_(-1),
backdrop_rect_location_(-1),
- blend_mode_(BlendModeNormal) {
+ blend_mode_(BLEND_MODE_NONE),
+ mask_for_background_(false) {
}
std::string FragmentTexBlendMode::SetBlendModeFunctions(
@@ -688,203 +776,208 @@ std::string FragmentTexBlendMode::SetBlendModeFunctions(
if (shader_string.find("ApplyBlendMode") == std::string::npos)
return shader_string;
- if (is_default_blend_mode()) {
- return "#define ApplyBlendMode(X) (X)\n" + shader_string;
+ if (!has_blend_mode()) {
+ return "#define ApplyBlendMode(X, Y) (X)\n" + shader_string;
}
- // clang-format off
- static const std::string kFunctionApplyBlendMode = SHADER0(
- // clang-format on
- uniform SamplerType s_backdropTexture;
- uniform TexCoordPrecision vec4 backdropRect;
-
- vec4 GetBackdropColor() {
- TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
- bgTexCoord.x /= backdropRect.z;
- bgTexCoord.y /= backdropRect.w;
- return TextureLookup(s_backdropTexture, bgTexCoord);
+ static const std::string kUniforms = SHADER0([]() {
+ uniform sampler2D s_backdropTexture;
+ uniform sampler2D s_originalBackdropTexture;
+ uniform TexCoordPrecision vec4 backdropRect;
+ });
+
+ std::string mixFunction;
+ if (mask_for_background()) {
+ mixFunction = SHADER0([]() {
+ vec4 MixBackdrop(TexCoordPrecision vec2 bgTexCoord, float mask) {
+ vec4 backdrop = texture2D(s_backdropTexture, bgTexCoord);
+ vec4 original_backdrop =
+ texture2D(s_originalBackdropTexture, bgTexCoord);
+ return mix(original_backdrop, backdrop, mask);
}
-
- vec4 ApplyBlendMode(vec4 src) {
- vec4 dst = GetBackdropColor();
- return Blend(src, dst);
+ });
+ } else {
+ mixFunction = SHADER0([]() {
+ vec4 MixBackdrop(TexCoordPrecision vec2 bgTexCoord, float mask) {
+ return texture2D(s_backdropTexture, bgTexCoord);
}
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ });
+ }
+
+ static const std::string kFunctionApplyBlendMode = SHADER0([]() {
+ vec4 GetBackdropColor(float mask) {
+ TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
+ bgTexCoord.x /= backdropRect.z;
+ bgTexCoord.y /= backdropRect.w;
+ return MixBackdrop(bgTexCoord, mask);
+ }
+
+ vec4 ApplyBlendMode(vec4 src, float mask) {
+ vec4 dst = GetBackdropColor(mask);
+ return Blend(src, dst);
+ }
+ });
return "precision mediump float;" + GetHelperFunctions() +
- GetBlendFunction() + kFunctionApplyBlendMode + shader_string;
+ GetBlendFunction() + kUniforms + mixFunction +
+ kFunctionApplyBlendMode + shader_string;
}
std::string FragmentTexBlendMode::GetHelperFunctions() const {
- // clang-format off
- static const std::string kFunctionHardLight = SHADER0(
- // clang-format on
- vec3 hardLight(vec4 src, vec4 dst) {
- vec3 result;
- result.r =
- (2.0 * src.r <= src.a)
- ? (2.0 * src.r * dst.r)
- : (src.a * dst.a - 2.0 * (dst.a - dst.r) * (src.a - src.r));
- result.g =
- (2.0 * src.g <= src.a)
- ? (2.0 * src.g * dst.g)
- : (src.a * dst.a - 2.0 * (dst.a - dst.g) * (src.a - src.g));
- result.b =
- (2.0 * src.b <= src.a)
- ? (2.0 * src.b * dst.b)
- : (src.a * dst.a - 2.0 * (dst.a - dst.b) * (src.a - src.b));
- result.rgb += src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
- return result;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
-
- static const std::string kFunctionColorDodgeComponent = SHADER0(
- // clang-format on
- float getColorDodgeComponent(
- float srcc, float srca, float dstc, float dsta) {
- if (0.0 == dstc)
- return srcc * (1.0 - dsta);
- float d = srca - srcc;
- if (0.0 == d)
- return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
- d = min(dsta, dstc * srca / d);
- return d * srca + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
-
- static const std::string kFunctionColorBurnComponent = SHADER0(
- // clang-format on
- float getColorBurnComponent(
- float srcc, float srca, float dstc, float dsta) {
- if (dsta == dstc)
- return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
- if (0.0 == srcc)
- return dstc * (1.0 - srca);
- float d = max(0.0, dsta - (dsta - dstc) * srca / srcc);
- return srca * d + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
-
- static const std::string kFunctionSoftLightComponentPosDstAlpha = SHADER0(
- // clang-format on
- float getSoftLightComponent(
- float srcc, float srca, float dstc, float dsta) {
- if (2.0 * srcc <= srca) {
- return (dstc * dstc * (srca - 2.0 * srcc)) / dsta +
- (1.0 - dsta) * srcc + dstc * (-srca + 2.0 * srcc + 1.0);
- } else if (4.0 * dstc <= dsta) {
- float DSqd = dstc * dstc;
- float DCub = DSqd * dstc;
- float DaSqd = dsta * dsta;
- float DaCub = DaSqd * dsta;
- return (-DaCub * srcc +
- DaSqd * (srcc - dstc * (3.0 * srca - 6.0 * srcc - 1.0)) +
- 12.0 * dsta * DSqd * (srca - 2.0 * srcc) -
- 16.0 * DCub * (srca - 2.0 * srcc)) /
- DaSqd;
- } else {
- return -sqrt(dsta * dstc) * (srca - 2.0 * srcc) - dsta * srcc +
- dstc * (srca - 2.0 * srcc + 1.0) + srcc;
- }
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
-
- static const std::string kFunctionLum = SHADER0(
- // clang-format on
- float luminance(vec3 color) { return dot(vec3(0.3, 0.59, 0.11), color); }
-
- vec3 set_luminance(vec3 hueSat, float alpha, vec3 lumColor) {
- float diff = luminance(lumColor - hueSat);
- vec3 outColor = hueSat + diff;
- float outLum = luminance(outColor);
- float minComp = min(min(outColor.r, outColor.g), outColor.b);
- float maxComp = max(max(outColor.r, outColor.g), outColor.b);
- if (minComp < 0.0 && outLum != minComp) {
- outColor = outLum +
- ((outColor - vec3(outLum, outLum, outLum)) * outLum) /
- (outLum - minComp);
- }
- if (maxComp > alpha && maxComp != outLum) {
- outColor =
- outLum +
- ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /
- (maxComp - outLum);
+ static const std::string kFunctionHardLight = SHADER0([]() {
+ vec3 hardLight(vec4 src, vec4 dst) {
+ vec3 result;
+ result.r =
+ (2.0 * src.r <= src.a)
+ ? (2.0 * src.r * dst.r)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.r) * (src.a - src.r));
+ result.g =
+ (2.0 * src.g <= src.a)
+ ? (2.0 * src.g * dst.g)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.g) * (src.a - src.g));
+ result.b =
+ (2.0 * src.b <= src.a)
+ ? (2.0 * src.b * dst.b)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.b) * (src.a - src.b));
+ result.rgb += src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
+ return result;
+ }
+ });
+
+ static const std::string kFunctionColorDodgeComponent = SHADER0([]() {
+ float getColorDodgeComponent(float srcc, float srca, float dstc,
+ float dsta) {
+ if (0.0 == dstc)
+ return srcc * (1.0 - dsta);
+ float d = srca - srcc;
+ if (0.0 == d)
+ return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ d = min(dsta, dstc * srca / d);
+ return d * srca + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ }
+ });
+
+ static const std::string kFunctionColorBurnComponent = SHADER0([]() {
+ float getColorBurnComponent(float srcc, float srca, float dstc,
+ float dsta) {
+ if (dsta == dstc)
+ return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ if (0.0 == srcc)
+ return dstc * (1.0 - srca);
+ float d = max(0.0, dsta - (dsta - dstc) * srca / srcc);
+ return srca * d + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ }
+ });
+
+ static const std::string kFunctionSoftLightComponentPosDstAlpha =
+ SHADER0([]() {
+ float getSoftLightComponent(float srcc, float srca, float dstc,
+ float dsta) {
+ if (2.0 * srcc <= srca) {
+ return (dstc * dstc * (srca - 2.0 * srcc)) / dsta +
+ (1.0 - dsta) * srcc + dstc * (-srca + 2.0 * srcc + 1.0);
+ } else if (4.0 * dstc <= dsta) {
+ float DSqd = dstc * dstc;
+ float DCub = DSqd * dstc;
+ float DaSqd = dsta * dsta;
+ float DaCub = DaSqd * dsta;
+ return (-DaCub * srcc +
+ DaSqd * (srcc - dstc * (3.0 * srca - 6.0 * srcc - 1.0)) +
+ 12.0 * dsta * DSqd * (srca - 2.0 * srcc) -
+ 16.0 * DCub * (srca - 2.0 * srcc)) /
+ DaSqd;
+ } else {
+ return -sqrt(dsta * dstc) * (srca - 2.0 * srcc) - dsta * srcc +
+ dstc * (srca - 2.0 * srcc + 1.0) + srcc;
+ }
}
- return outColor;
+ });
+
+ static const std::string kFunctionLum = SHADER0([]() {
+ float luminance(vec3 color) { return dot(vec3(0.3, 0.59, 0.11), color); }
+
+ vec3 set_luminance(vec3 hueSat, float alpha, vec3 lumColor) {
+ float diff = luminance(lumColor - hueSat);
+ vec3 outColor = hueSat + diff;
+ float outLum = luminance(outColor);
+ float minComp = min(min(outColor.r, outColor.g), outColor.b);
+ float maxComp = max(max(outColor.r, outColor.g), outColor.b);
+ if (minComp < 0.0 && outLum != minComp) {
+ outColor = outLum +
+ ((outColor - vec3(outLum, outLum, outLum)) * outLum) /
+ (outLum - minComp);
}
- // clang-format off
- ); // NOLINT(whitespace/parens)
-
- static const std::string kFunctionSat = SHADER0(
- // clang-format on
- float saturation(vec3 color) {
- return max(max(color.r, color.g), color.b) -
- min(min(color.r, color.g), color.b);
+ if (maxComp > alpha && maxComp != outLum) {
+ outColor =
+ outLum +
+ ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /
+ (maxComp - outLum);
}
-
- vec3 set_saturation_helper(
- float minComp, float midComp, float maxComp, float sat) {
- if (minComp < maxComp) {
- vec3 result;
- result.r = 0.0;
- result.g = sat * (midComp - minComp) / (maxComp - minComp);
- result.b = sat;
- return result;
- } else {
- return vec3(0, 0, 0);
- }
+ return outColor;
+ }
+ });
+
+ static const std::string kFunctionSat = SHADER0([]() {
+ float saturation(vec3 color) {
+ return max(max(color.r, color.g), color.b) -
+ min(min(color.r, color.g), color.b);
+ }
+
+ vec3 set_saturation_helper(float minComp, float midComp, float maxComp,
+ float sat) {
+ if (minComp < maxComp) {
+ vec3 result;
+ result.r = 0.0;
+ result.g = sat * (midComp - minComp) / (maxComp - minComp);
+ result.b = sat;
+ return result;
+ } else {
+ return vec3(0, 0, 0);
}
-
- vec3 set_saturation(vec3 hueLumColor, vec3 satColor) {
- float sat = saturation(satColor);
- if (hueLumColor.r <= hueLumColor.g) {
- if (hueLumColor.g <= hueLumColor.b) {
- hueLumColor.rgb = set_saturation_helper(
- hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);
- } else if (hueLumColor.r <= hueLumColor.b) {
- hueLumColor.rbg = set_saturation_helper(
- hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);
- } else {
- hueLumColor.brg = set_saturation_helper(
- hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);
- }
+ }
+
+ vec3 set_saturation(vec3 hueLumColor, vec3 satColor) {
+ float sat = saturation(satColor);
+ if (hueLumColor.r <= hueLumColor.g) {
+ if (hueLumColor.g <= hueLumColor.b) {
+ hueLumColor.rgb = set_saturation_helper(hueLumColor.r, hueLumColor.g,
+ hueLumColor.b, sat);
} else if (hueLumColor.r <= hueLumColor.b) {
- hueLumColor.grb = set_saturation_helper(
- hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);
- } else if (hueLumColor.g <= hueLumColor.b) {
- hueLumColor.gbr = set_saturation_helper(
- hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);
+ hueLumColor.rbg = set_saturation_helper(hueLumColor.r, hueLumColor.b,
+ hueLumColor.g, sat);
} else {
- hueLumColor.bgr = set_saturation_helper(
- hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);
+ hueLumColor.brg = set_saturation_helper(hueLumColor.b, hueLumColor.r,
+ hueLumColor.g, sat);
}
- return hueLumColor;
+ } else if (hueLumColor.r <= hueLumColor.b) {
+ hueLumColor.grb = set_saturation_helper(hueLumColor.g, hueLumColor.r,
+ hueLumColor.b, sat);
+ } else if (hueLumColor.g <= hueLumColor.b) {
+ hueLumColor.gbr = set_saturation_helper(hueLumColor.g, hueLumColor.b,
+ hueLumColor.r, sat);
+ } else {
+ hueLumColor.bgr = set_saturation_helper(hueLumColor.b, hueLumColor.g,
+ hueLumColor.r, sat);
}
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return hueLumColor;
+ }
+ });
switch (blend_mode_) {
- case BlendModeOverlay:
- case BlendModeHardLight:
+ case BLEND_MODE_OVERLAY:
+ case BLEND_MODE_HARD_LIGHT:
return kFunctionHardLight;
- case BlendModeColorDodge:
+ case BLEND_MODE_COLOR_DODGE:
return kFunctionColorDodgeComponent;
- case BlendModeColorBurn:
+ case BLEND_MODE_COLOR_BURN:
return kFunctionColorBurnComponent;
- case BlendModeSoftLight:
+ case BLEND_MODE_SOFT_LIGHT:
return kFunctionSoftLightComponentPosDstAlpha;
- case BlendModeHue:
- case BlendModeSaturation:
+ case BLEND_MODE_HUE:
+ case BLEND_MODE_SATURATION:
return kFunctionLum + kFunctionSat;
- case BlendModeColor:
- case BlendModeLuminosity:
+ case BLEND_MODE_COLOR:
+ case BLEND_MODE_LUMINOSITY:
return kFunctionLum;
default:
return std::string();
@@ -902,25 +995,29 @@ std::string FragmentTexBlendMode::GetBlendFunction() const {
std::string FragmentTexBlendMode::GetBlendFunctionBodyForRGB() const {
switch (blend_mode_) {
- case BlendModeLighten:
+ case BLEND_MODE_NORMAL:
+ return "result.rgb = src.rgb + dst.rgb * (1.0 - src.a);";
+ case BLEND_MODE_SCREEN:
+ return "result.rgb = src.rgb + (1.0 - src.rgb) * dst.rgb;";
+ case BLEND_MODE_LIGHTEN:
return "result.rgb = max((1.0 - src.a) * dst.rgb + src.rgb,"
" (1.0 - dst.a) * src.rgb + dst.rgb);";
- case BlendModeOverlay:
+ case BLEND_MODE_OVERLAY:
return "result.rgb = hardLight(dst, src);";
- case BlendModeDarken:
+ case BLEND_MODE_DARKEN:
return "result.rgb = min((1.0 - src.a) * dst.rgb + src.rgb,"
" (1.0 - dst.a) * src.rgb + dst.rgb);";
- case BlendModeColorDodge:
+ case BLEND_MODE_COLOR_DODGE:
return "result.r = getColorDodgeComponent(src.r, src.a, dst.r, dst.a);"
"result.g = getColorDodgeComponent(src.g, src.a, dst.g, dst.a);"
"result.b = getColorDodgeComponent(src.b, src.a, dst.b, dst.a);";
- case BlendModeColorBurn:
+ case BLEND_MODE_COLOR_BURN:
return "result.r = getColorBurnComponent(src.r, src.a, dst.r, dst.a);"
"result.g = getColorBurnComponent(src.g, src.a, dst.g, dst.a);"
"result.b = getColorBurnComponent(src.b, src.a, dst.b, dst.a);";
- case BlendModeHardLight:
+ case BLEND_MODE_HARD_LIGHT:
return "result.rgb = hardLight(src, dst);";
- case BlendModeSoftLight:
+ case BLEND_MODE_SOFT_LIGHT:
return "if (0.0 == dst.a) {"
" result.rgb = src.rgb;"
"} else {"
@@ -928,15 +1025,15 @@ std::string FragmentTexBlendMode::GetBlendFunctionBodyForRGB() const {
" result.g = getSoftLightComponent(src.g, src.a, dst.g, dst.a);"
" result.b = getSoftLightComponent(src.b, src.a, dst.b, dst.a);"
"}";
- case BlendModeDifference:
+ case BLEND_MODE_DIFFERENCE:
return "result.rgb = src.rgb + dst.rgb -"
" 2.0 * min(src.rgb * dst.a, dst.rgb * src.a);";
- case BlendModeExclusion:
+ case BLEND_MODE_EXCLUSION:
return "result.rgb = dst.rgb + src.rgb - 2.0 * dst.rgb * src.rgb;";
- case BlendModeMultiply:
+ case BLEND_MODE_MULTIPLY:
return "result.rgb = (1.0 - src.a) * dst.rgb +"
" (1.0 - dst.a) * src.rgb + src.rgb * dst.rgb;";
- case BlendModeHue:
+ case BLEND_MODE_HUE:
return "vec4 dstSrcAlpha = dst * src.a;"
"result.rgb ="
" set_luminance(set_saturation(src.rgb * dst.a,"
@@ -944,30 +1041,29 @@ std::string FragmentTexBlendMode::GetBlendFunctionBodyForRGB() const {
" dstSrcAlpha.a,"
" dstSrcAlpha.rgb);"
"result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- case BlendModeSaturation:
+ case BLEND_MODE_SATURATION:
return "vec4 dstSrcAlpha = dst * src.a;"
"result.rgb = set_luminance(set_saturation(dstSrcAlpha.rgb,"
" src.rgb * dst.a),"
" dstSrcAlpha.a,"
" dstSrcAlpha.rgb);"
"result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- case BlendModeColor:
+ case BLEND_MODE_COLOR:
return "vec4 srcDstAlpha = src * dst.a;"
"result.rgb = set_luminance(srcDstAlpha.rgb,"
" srcDstAlpha.a,"
" dst.rgb * src.a);"
"result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- case BlendModeLuminosity:
+ case BLEND_MODE_LUMINOSITY:
return "vec4 srcDstAlpha = src * dst.a;"
"result.rgb = set_luminance(dst.rgb * src.a,"
" srcDstAlpha.a,"
" srcDstAlpha.rgb);"
"result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- default:
+ case BLEND_MODE_NONE:
NOTREACHED();
- // simple alpha compositing
- return "result.rgb = src.rgb * src.a + dst.rgb * dst.a * (1 - src.a)";
}
+ return "result = vec4(1.0, 0.0, 0.0, 1.0);";
}
FragmentTexAlphaBinding::FragmentTexAlphaBinding()
@@ -1044,85 +1140,123 @@ void FragmentTexOpaqueBinding::Init(GLES2Interface* context,
std::string FragmentShaderRGBATexAlpha::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform SamplerType s_texture;
- uniform float alpha;
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- gl_FragColor = ApplyBlendMode(texColor * alpha);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlpha::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ uniform SamplerType s_texture;
+ uniform float alpha;
+ });
+}
+
+std::string FragmentShaderRGBATexAlpha::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ gl_FragColor = ApplyBlendMode(texColor * alpha, 0.0);
+ }
+ });
+}
+
+void FragmentShaderRGBATexAlpha::FillLocations(
+ ShaderLocations* locations) const {
+ locations->sampler = sampler_location();
+ locations->alpha = alpha_location();
+ locations->backdrop = backdrop_location();
+ locations->backdrop_rect = backdrop_rect_location();
}
std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform SamplerType s_texture;
- uniform float alpha;
- uniform mat4 colorMatrix;
- uniform vec4 colorOffset;
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- float nonZeroAlpha = max(texColor.a, 0.00001);
- texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
- texColor = colorMatrix * texColor + colorOffset;
- texColor.rgb *= texColor.a;
- texColor = clamp(texColor, 0.0, 1.0);
- gl_FragColor = ApplyBlendMode(texColor * alpha);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ uniform SamplerType s_texture;
+ uniform float alpha;
+ uniform mat4 colorMatrix;
+ uniform vec4 colorOffset;
+ });
+}
+
+std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ float nonZeroAlpha = max(texColor.a, 0.00001);
+ texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
+ texColor = colorMatrix * texColor + colorOffset;
+ texColor.rgb *= texColor.a;
+ texColor = clamp(texColor, 0.0, 1.0);
+ gl_FragColor = ApplyBlendMode(texColor * alpha, 0.0);
+ }
+ });
+}
+
+void FragmentShaderRGBATexColorMatrixAlpha::FillLocations(
+ ShaderLocations* locations) const {
+ locations->sampler = sampler_location();
+ locations->alpha = alpha_location();
+ locations->color_matrix = color_matrix_location();
+ locations->color_offset = color_offset_location();
+ locations->backdrop = backdrop_location();
+ locations->backdrop_rect = backdrop_rect_location();
}
std::string FragmentShaderRGBATexVaryingAlpha::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- varying float v_alpha;
- uniform SamplerType s_texture;
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- gl_FragColor = texColor * v_alpha;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexVaryingAlpha::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying float v_alpha;
+ uniform SamplerType s_texture;
+ });
+}
+
+std::string FragmentShaderRGBATexVaryingAlpha::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ gl_FragColor = texColor * v_alpha;
+ }
+ });
}
std::string FragmentShaderRGBATexPremultiplyAlpha::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- varying float v_alpha;
- uniform SamplerType s_texture;
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- texColor.rgb *= texColor.a;
- gl_FragColor = texColor * v_alpha;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexPremultiplyAlpha::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying float v_alpha;
+ uniform SamplerType s_texture;
+ });
+}
+
+std::string FragmentShaderRGBATexPremultiplyAlpha::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ texColor.rgb *= texColor.a;
+ gl_FragColor = texColor * v_alpha;
+ }
+ });
}
FragmentTexBackgroundBinding::FragmentTexBackgroundBinding()
@@ -1154,114 +1288,144 @@ void FragmentTexBackgroundBinding::Init(GLES2Interface* context,
std::string FragmentShaderTexBackgroundVaryingAlpha::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- varying float v_alpha;
- uniform vec4 background_color;
- uniform SamplerType s_texture;
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- texColor += background_color * (1.0 - texColor.a);
- gl_FragColor = texColor * v_alpha;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderTexBackgroundVaryingAlpha::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying float v_alpha;
+ uniform vec4 background_color;
+ uniform SamplerType s_texture;
+ });
+}
+
+std::string FragmentShaderTexBackgroundVaryingAlpha::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ texColor += background_color * (1.0 - texColor.a);
+ gl_FragColor = texColor * v_alpha;
+ }
+ });
}
std::string FragmentShaderTexBackgroundPremultiplyAlpha::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- varying float v_alpha;
- uniform vec4 background_color;
- uniform SamplerType s_texture;
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- texColor.rgb *= texColor.a;
- texColor += background_color * (1.0 - texColor.a);
- gl_FragColor = texColor * v_alpha;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderTexBackgroundPremultiplyAlpha::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying float v_alpha;
+ uniform vec4 background_color;
+ uniform SamplerType s_texture;
+ });
+}
+
+std::string FragmentShaderTexBackgroundPremultiplyAlpha::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ texColor.rgb *= texColor.a;
+ texColor += background_color * (1.0 - texColor.a);
+ gl_FragColor = texColor * v_alpha;
+ }
+ });
}
std::string FragmentShaderRGBATexOpaque::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform SamplerType s_texture;
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- gl_FragColor = vec4(texColor.rgb, 1.0);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexOpaque::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ uniform SamplerType s_texture;
+ });
+}
+
+std::string FragmentShaderRGBATexOpaque::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ gl_FragColor = vec4(texColor.rgb, 1.0);
+ }
+ });
}
std::string FragmentShaderRGBATex::GetShaderString(TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform SamplerType s_texture;
- void main() { gl_FragColor = TextureLookup(s_texture, v_texCoord); }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATex::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ uniform SamplerType s_texture;
+ });
+}
+
+std::string FragmentShaderRGBATex::GetShaderBody() {
+ return SHADER0([]() {
+ void main() { gl_FragColor = TextureLookup(s_texture, v_texCoord); }
+ });
}
std::string FragmentShaderRGBATexSwizzleAlpha::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform SamplerType s_texture;
- uniform float alpha;
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- gl_FragColor =
- vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexSwizzleAlpha::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ uniform SamplerType s_texture;
+ uniform float alpha;
+ });
+}
+
+std::string FragmentShaderRGBATexSwizzleAlpha::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ gl_FragColor =
+ vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha;
+ }
+ });
}
std::string FragmentShaderRGBATexSwizzleOpaque::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform SamplerType s_texture;
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, 1.0);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexSwizzleOpaque::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ uniform SamplerType s_texture;
+ });
+}
+
+std::string FragmentShaderRGBATexSwizzleOpaque::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, 1.0);
+ }
+ });
}
FragmentShaderRGBATexAlphaAA::FragmentShaderRGBATexAlphaAA()
@@ -1290,25 +1454,37 @@ void FragmentShaderRGBATexAlphaAA::Init(GLES2Interface* context,
std::string FragmentShaderRGBATexAlphaAA::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- uniform SamplerType s_texture;
- uniform float alpha;
- varying TexCoordPrecision vec2 v_texCoord;
- varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- vec4 d4 = min(edge_dist[0], edge_dist[1]);
- vec2 d2 = min(d4.xz, d4.yw);
- float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlphaAA::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ uniform SamplerType s_texture;
+ uniform float alpha;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string FragmentShaderRGBATexAlphaAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ vec4 d4 = min(edge_dist[0], edge_dist[1]);
+ vec2 d2 = min(d4.xz, d4.yw);
+ float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+ gl_FragColor = ApplyBlendMode(texColor * alpha * aa, 0.0);
+ }
+ });
+}
+
+void FragmentShaderRGBATexAlphaAA::FillLocations(
+ ShaderLocations* locations) const {
+ locations->sampler = sampler_location();
+ locations->alpha = alpha_location();
+ locations->backdrop = backdrop_location();
+ locations->backdrop_rect = backdrop_rect_location();
}
FragmentTexClampAlphaAABinding::FragmentTexClampAlphaAABinding()
@@ -1339,58 +1515,66 @@ void FragmentTexClampAlphaAABinding::Init(GLES2Interface* context,
std::string FragmentShaderRGBATexClampAlphaAA::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- uniform SamplerType s_texture;
- uniform float alpha;
- uniform TexCoordPrecision vec4 fragmentTexTransform;
- varying TexCoordPrecision vec2 v_texCoord;
- varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- TexCoordPrecision vec2 texCoord =
- clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
- fragmentTexTransform.xy;
- vec4 texColor = TextureLookup(s_texture, texCoord);
- vec4 d4 = min(edge_dist[0], edge_dist[1]);
- vec2 d2 = min(d4.xz, d4.yw);
- float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = texColor * alpha * aa;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexClampAlphaAA::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ uniform SamplerType s_texture;
+ uniform float alpha;
+ uniform TexCoordPrecision vec4 fragmentTexTransform;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string FragmentShaderRGBATexClampAlphaAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ TexCoordPrecision vec2 texCoord =
+ clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
+ fragmentTexTransform.xy;
+ vec4 texColor = TextureLookup(s_texture, texCoord);
+ vec4 d4 = min(edge_dist[0], edge_dist[1]);
+ vec2 d2 = min(d4.xz, d4.yw);
+ float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+ gl_FragColor = texColor * alpha * aa;
+ }
+ });
}
std::string FragmentShaderRGBATexClampSwizzleAlphaAA::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- uniform SamplerType s_texture;
- uniform float alpha;
- uniform TexCoordPrecision vec4 fragmentTexTransform;
- varying TexCoordPrecision vec2 v_texCoord;
- varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- TexCoordPrecision vec2 texCoord =
- clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
- fragmentTexTransform.xy;
- vec4 texColor = TextureLookup(s_texture, texCoord);
- vec4 d4 = min(edge_dist[0], edge_dist[1]);
- vec2 d2 = min(d4.xz, d4.yw);
- float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor =
- vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha * aa;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexClampSwizzleAlphaAA::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ uniform SamplerType s_texture;
+ uniform float alpha;
+ uniform TexCoordPrecision vec4 fragmentTexTransform;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string FragmentShaderRGBATexClampSwizzleAlphaAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ TexCoordPrecision vec2 texCoord =
+ clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
+ fragmentTexTransform.xy;
+ vec4 texColor = TextureLookup(s_texture, texCoord);
+ vec4 d4 = min(edge_dist[0], edge_dist[1]);
+ vec2 d2 = min(d4.xz, d4.yw);
+ float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+ gl_FragColor =
+ vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha * aa;
+ }
+ });
}
FragmentShaderRGBATexAlphaMask::FragmentShaderRGBATexAlphaMask()
@@ -1430,27 +1614,46 @@ void FragmentShaderRGBATexAlphaMask::Init(GLES2Interface* context,
std::string FragmentShaderRGBATexAlphaMask::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform sampler2D s_texture;
- uniform SamplerType s_mask;
- uniform TexCoordPrecision vec2 maskTexCoordScale;
- uniform TexCoordPrecision vec2 maskTexCoordOffset;
- uniform float alpha;
- void main() {
- vec4 texColor = texture2D(s_texture, v_texCoord);
- TexCoordPrecision vec2 maskTexCoord =
- vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
- maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
- vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
- gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlphaMask::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ uniform sampler2D s_texture;
+ uniform SamplerType s_mask;
+ uniform TexCoordPrecision vec2 maskTexCoordScale;
+ uniform TexCoordPrecision vec2 maskTexCoordOffset;
+ uniform float alpha;
+ });
+}
+
+std::string FragmentShaderRGBATexAlphaMask::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = texture2D(s_texture, v_texCoord);
+ TexCoordPrecision vec2 maskTexCoord =
+ vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
+ maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
+ vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
+ gl_FragColor = ApplyBlendMode(
+ texColor * alpha * maskColor.w, maskColor.w);
+ }
+ });
+}
+
+void FragmentShaderRGBATexAlphaMask::FillLocations(
+ ShaderLocations* locations) const {
+ locations->sampler = sampler_location();
+ locations->mask_sampler = mask_sampler_location();
+ locations->mask_tex_coord_scale = mask_tex_coord_scale_location();
+ locations->mask_tex_coord_offset = mask_tex_coord_offset_location();
+ locations->alpha = alpha_location();
+ locations->backdrop = backdrop_location();
+ locations->backdrop_rect = backdrop_rect_location();
+ if (mask_for_background())
+ locations->original_backdrop = original_backdrop_location();
}
FragmentShaderRGBATexAlphaMaskAA::FragmentShaderRGBATexAlphaMaskAA()
@@ -1491,32 +1694,50 @@ void FragmentShaderRGBATexAlphaMaskAA::Init(GLES2Interface* context,
std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- uniform sampler2D s_texture;
- uniform SamplerType s_mask;
- uniform TexCoordPrecision vec2 maskTexCoordScale;
- uniform TexCoordPrecision vec2 maskTexCoordOffset;
- uniform float alpha;
- varying TexCoordPrecision vec2 v_texCoord;
- varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- vec4 texColor = texture2D(s_texture, v_texCoord);
- TexCoordPrecision vec2 maskTexCoord =
- vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
- maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
- vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
- vec4 d4 = min(edge_dist[0], edge_dist[1]);
- vec2 d2 = min(d4.xz, d4.yw);
- float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ uniform sampler2D s_texture;
+ uniform SamplerType s_mask;
+ uniform TexCoordPrecision vec2 maskTexCoordScale;
+ uniform TexCoordPrecision vec2 maskTexCoordOffset;
+ uniform float alpha;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = texture2D(s_texture, v_texCoord);
+ TexCoordPrecision vec2 maskTexCoord =
+ vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
+ maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
+ vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
+ vec4 d4 = min(edge_dist[0], edge_dist[1]);
+ vec2 d2 = min(d4.xz, d4.yw);
+ float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+ gl_FragColor = ApplyBlendMode(
+ texColor * alpha * maskColor.w * aa, maskColor.w);
+ }
+ });
+}
+
+void FragmentShaderRGBATexAlphaMaskAA::FillLocations(
+ ShaderLocations* locations) const {
+ locations->sampler = sampler_location();
+ locations->mask_sampler = mask_sampler_location();
+ locations->mask_tex_coord_scale = mask_tex_coord_scale_location();
+ locations->mask_tex_coord_offset = mask_tex_coord_offset_location();
+ locations->alpha = alpha_location();
+ locations->backdrop = backdrop_location();
+ locations->backdrop_rect = backdrop_rect_location();
+ if (mask_for_background())
+ locations->original_backdrop = original_backdrop_location();
}
FragmentShaderRGBATexAlphaMaskColorMatrixAA::
@@ -1564,39 +1785,59 @@ void FragmentShaderRGBATexAlphaMaskColorMatrixAA::Init(
std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- uniform sampler2D s_texture;
- uniform SamplerType s_mask;
- uniform vec2 maskTexCoordScale;
- uniform vec2 maskTexCoordOffset;
- uniform mat4 colorMatrix;
- uniform vec4 colorOffset;
- uniform float alpha;
- varying TexCoordPrecision vec2 v_texCoord;
- varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- vec4 texColor = texture2D(s_texture, v_texCoord);
- float nonZeroAlpha = max(texColor.a, 0.00001);
- texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
- texColor = colorMatrix * texColor + colorOffset;
- texColor.rgb *= texColor.a;
- texColor = clamp(texColor, 0.0, 1.0);
- TexCoordPrecision vec2 maskTexCoord =
- vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
- maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
- vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
- vec4 d4 = min(edge_dist[0], edge_dist[1]);
- vec2 d2 = min(d4.xz, d4.yw);
- float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ uniform sampler2D s_texture;
+ uniform SamplerType s_mask;
+ uniform vec2 maskTexCoordScale;
+ uniform vec2 maskTexCoordOffset;
+ uniform mat4 colorMatrix;
+ uniform vec4 colorOffset;
+ uniform float alpha;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = texture2D(s_texture, v_texCoord);
+ float nonZeroAlpha = max(texColor.a, 0.00001);
+ texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
+ texColor = colorMatrix * texColor + colorOffset;
+ texColor.rgb *= texColor.a;
+ texColor = clamp(texColor, 0.0, 1.0);
+ TexCoordPrecision vec2 maskTexCoord =
+ vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
+ maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
+ vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
+ vec4 d4 = min(edge_dist[0], edge_dist[1]);
+ vec2 d2 = min(d4.xz, d4.yw);
+ float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+ gl_FragColor = ApplyBlendMode(
+ texColor * alpha * maskColor.w * aa, maskColor.w);
+ }
+ });
+}
+
+void FragmentShaderRGBATexAlphaMaskColorMatrixAA::FillLocations(
+ ShaderLocations* locations) const {
+ locations->sampler = sampler_location();
+ locations->alpha = alpha_location();
+ locations->mask_sampler = mask_sampler_location();
+ locations->mask_tex_coord_scale = mask_tex_coord_scale_location();
+ locations->mask_tex_coord_offset = mask_tex_coord_offset_location();
+ locations->color_matrix = color_matrix_location();
+ locations->color_offset = color_offset_location();
+ locations->backdrop = backdrop_location();
+ locations->backdrop_rect = backdrop_rect_location();
+ if (mask_for_background())
+ locations->original_backdrop = original_backdrop_location();
}
FragmentShaderRGBATexAlphaColorMatrixAA::
@@ -1631,32 +1872,46 @@ void FragmentShaderRGBATexAlphaColorMatrixAA::Init(GLES2Interface* context,
std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- uniform SamplerType s_texture;
- uniform float alpha;
- uniform mat4 colorMatrix;
- uniform vec4 colorOffset;
- varying TexCoordPrecision vec2 v_texCoord;
- varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- vec4 texColor = TextureLookup(s_texture, v_texCoord);
- float nonZeroAlpha = max(texColor.a, 0.00001);
- texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
- texColor = colorMatrix * texColor + colorOffset;
- texColor.rgb *= texColor.a;
- texColor = clamp(texColor, 0.0, 1.0);
- vec4 d4 = min(edge_dist[0], edge_dist[1]);
- vec2 d2 = min(d4.xz, d4.yw);
- float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ uniform SamplerType s_texture;
+ uniform float alpha;
+ uniform mat4 colorMatrix;
+ uniform vec4 colorOffset;
+ varying TexCoordPrecision vec2 v_texCoord;
+ varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = TextureLookup(s_texture, v_texCoord);
+ float nonZeroAlpha = max(texColor.a, 0.00001);
+ texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
+ texColor = colorMatrix * texColor + colorOffset;
+ texColor.rgb *= texColor.a;
+ texColor = clamp(texColor, 0.0, 1.0);
+ vec4 d4 = min(edge_dist[0], edge_dist[1]);
+ vec2 d2 = min(d4.xz, d4.yw);
+ float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+ gl_FragColor = ApplyBlendMode(texColor * alpha * aa, 0.0);
+ }
+ });
+}
+
+void FragmentShaderRGBATexAlphaColorMatrixAA::FillLocations(
+ ShaderLocations* locations) const {
+ locations->sampler = sampler_location();
+ locations->alpha = alpha_location();
+ locations->color_matrix = color_matrix_location();
+ locations->color_offset = color_offset_location();
+ locations->backdrop = backdrop_location();
+ locations->backdrop_rect = backdrop_rect_location();
}
FragmentShaderRGBATexAlphaMaskColorMatrix::
@@ -1701,34 +1956,55 @@ void FragmentShaderRGBATexAlphaMaskColorMatrix::Init(GLES2Interface* context,
std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform sampler2D s_texture;
- uniform SamplerType s_mask;
- uniform vec2 maskTexCoordScale;
- uniform vec2 maskTexCoordOffset;
- uniform mat4 colorMatrix;
- uniform vec4 colorOffset;
- uniform float alpha;
- void main() {
- vec4 texColor = texture2D(s_texture, v_texCoord);
- float nonZeroAlpha = max(texColor.a, 0.00001);
- texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
- texColor = colorMatrix * texColor + colorOffset;
- texColor.rgb *= texColor.a;
- texColor = clamp(texColor, 0.0, 1.0);
- TexCoordPrecision vec2 maskTexCoord =
- vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
- maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
- vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
- gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ varying TexCoordPrecision vec2 v_texCoord;
+ uniform sampler2D s_texture;
+ uniform SamplerType s_mask;
+ uniform vec2 maskTexCoordScale;
+ uniform vec2 maskTexCoordOffset;
+ uniform mat4 colorMatrix;
+ uniform vec4 colorOffset;
+ uniform float alpha;
+ });
+}
+
+std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 texColor = texture2D(s_texture, v_texCoord);
+ float nonZeroAlpha = max(texColor.a, 0.00001);
+ texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
+ texColor = colorMatrix * texColor + colorOffset;
+ texColor.rgb *= texColor.a;
+ texColor = clamp(texColor, 0.0, 1.0);
+ TexCoordPrecision vec2 maskTexCoord =
+ vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
+ maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
+ vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
+ gl_FragColor = ApplyBlendMode(
+ texColor * alpha * maskColor.w, maskColor.w);
+ }
+ });
+}
+
+void FragmentShaderRGBATexAlphaMaskColorMatrix::FillLocations(
+ ShaderLocations* locations) const {
+ locations->sampler = sampler_location();
+ locations->mask_sampler = mask_sampler_location();
+ locations->mask_tex_coord_scale = mask_tex_coord_scale_location();
+ locations->mask_tex_coord_offset = mask_tex_coord_offset_location();
+ locations->alpha = alpha_location();
+ locations->color_matrix = color_matrix_location();
+ locations->color_offset = color_offset_location();
+ locations->backdrop = backdrop_location();
+ locations->backdrop_rect = backdrop_rect_location();
+ if (mask_for_background())
+ locations->original_backdrop = original_backdrop_location();
}
FragmentShaderYUVVideo::FragmentShaderYUVVideo()
@@ -1737,15 +2013,22 @@ FragmentShaderYUVVideo::FragmentShaderYUVVideo()
v_texture_location_(-1),
alpha_location_(-1),
yuv_matrix_location_(-1),
- yuv_adj_location_(-1) {
+ yuv_adj_location_(-1),
+ ya_clamp_rect_location_(-1),
+ uv_clamp_rect_location_(-1) {
}
void FragmentShaderYUVVideo::Init(GLES2Interface* context,
unsigned program,
int* base_uniform_index) {
- static const char* uniforms[] = {
- "y_texture", "u_texture", "v_texture", "alpha", "yuv_matrix", "yuv_adj",
- };
+ static const char* uniforms[] = {"y_texture",
+ "u_texture",
+ "v_texture",
+ "alpha",
+ "yuv_matrix",
+ "yuv_adj",
+ "ya_clamp_rect",
+ "uv_clamp_rect"};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
@@ -1760,33 +2043,47 @@ void FragmentShaderYUVVideo::Init(GLES2Interface* context,
alpha_location_ = locations[3];
yuv_matrix_location_ = locations[4];
yuv_adj_location_ = locations[5];
+ ya_clamp_rect_location_ = locations[6];
+ uv_clamp_rect_location_ = locations[7];
}
std::string FragmentShaderYUVVideo::GetShaderString(TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- precision mediump int;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform SamplerType y_texture;
- uniform SamplerType u_texture;
- uniform SamplerType v_texture;
- uniform float alpha;
- uniform vec3 yuv_adj;
- uniform mat3 yuv_matrix;
- void main() {
- float y_raw = TextureLookup(y_texture, v_texCoord).x;
- float u_unsigned = TextureLookup(u_texture, v_texCoord).x;
- float v_unsigned = TextureLookup(v_texture, v_texCoord).x;
- vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
- vec3 rgb = yuv_matrix * yuv;
- gl_FragColor = vec4(rgb, 1.0) * alpha;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderYUVVideo::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ precision mediump int;
+ varying TexCoordPrecision vec2 v_yaTexCoord;
+ varying TexCoordPrecision vec2 v_uvTexCoord;
+ uniform SamplerType y_texture;
+ uniform SamplerType u_texture;
+ uniform SamplerType v_texture;
+ uniform float alpha;
+ uniform vec3 yuv_adj;
+ uniform mat3 yuv_matrix;
+ uniform vec4 ya_clamp_rect;
+ uniform vec4 uv_clamp_rect;
+ });
+}
+
+std::string FragmentShaderYUVVideo::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec2 ya_clamped =
+ max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));
+ float y_raw = TextureLookup(y_texture, ya_clamped).x;
+ vec2 uv_clamped =
+ max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));
+ float u_unsigned = TextureLookup(u_texture, uv_clamped).x;
+ float v_unsigned = TextureLookup(v_texture, uv_clamped).x;
+ vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
+ vec3 rgb = yuv_matrix * yuv;
+ gl_FragColor = vec4(rgb, 1.0) * alpha;
+ }
+ });
}
FragmentShaderYUVAVideo::FragmentShaderYUVAVideo()
@@ -1810,6 +2107,8 @@ void FragmentShaderYUVAVideo::Init(GLES2Interface* context,
"alpha",
"cc_matrix",
"yuv_adj",
+ "ya_clamp_rect",
+ "uv_clamp_rect",
};
int locations[arraysize(uniforms)];
@@ -1826,36 +2125,50 @@ void FragmentShaderYUVAVideo::Init(GLES2Interface* context,
alpha_location_ = locations[4];
yuv_matrix_location_ = locations[5];
yuv_adj_location_ = locations[6];
+ ya_clamp_rect_location_ = locations[7];
+ uv_clamp_rect_location_ = locations[8];
}
std::string FragmentShaderYUVAVideo::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- precision mediump int;
- varying TexCoordPrecision vec2 v_texCoord;
- uniform SamplerType y_texture;
- uniform SamplerType u_texture;
- uniform SamplerType v_texture;
- uniform SamplerType a_texture;
- uniform float alpha;
- uniform vec3 yuv_adj;
- uniform mat3 yuv_matrix;
- void main() {
- float y_raw = TextureLookup(y_texture, v_texCoord).x;
- float u_unsigned = TextureLookup(u_texture, v_texCoord).x;
- float v_unsigned = TextureLookup(v_texture, v_texCoord).x;
- float a_raw = TextureLookup(a_texture, v_texCoord).x;
- vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
- vec3 rgb = yuv_matrix * yuv;
- gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderYUVAVideo::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ precision mediump int;
+ varying TexCoordPrecision vec2 v_yaTexCoord;
+ varying TexCoordPrecision vec2 v_uvTexCoord;
+ uniform SamplerType y_texture;
+ uniform SamplerType u_texture;
+ uniform SamplerType v_texture;
+ uniform SamplerType a_texture;
+ uniform float alpha;
+ uniform vec3 yuv_adj;
+ uniform mat3 yuv_matrix;
+ uniform vec4 ya_clamp_rect;
+ uniform vec4 uv_clamp_rect;
+ });
+}
+
+std::string FragmentShaderYUVAVideo::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec2 ya_clamped =
+ max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));
+ float y_raw = TextureLookup(y_texture, ya_clamped).x;
+ vec2 uv_clamped =
+ max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));
+ float u_unsigned = TextureLookup(u_texture, uv_clamped).x;
+ float v_unsigned = TextureLookup(v_texture, uv_clamped).x;
+ float a_raw = TextureLookup(a_texture, ya_clamped).x;
+ vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
+ vec3 rgb = yuv_matrix * yuv;
+ gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);
+ }
+ });
}
FragmentShaderColor::FragmentShaderColor() : color_location_(-1) {
@@ -1880,15 +2193,20 @@ void FragmentShaderColor::Init(GLES2Interface* context,
std::string FragmentShaderColor::GetShaderString(TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- uniform vec4 color;
- void main() { gl_FragColor = color; }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderColor::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ uniform vec4 color;
+ });
+}
+
+std::string FragmentShaderColor::GetShaderBody() {
+ return SHADER0([]() {
+ void main() { gl_FragColor = color; }
+ });
}
FragmentShaderColorAA::FragmentShaderColorAA() : color_location_(-1) {
@@ -1913,22 +2231,26 @@ void FragmentShaderColorAA::Init(GLES2Interface* context,
std::string FragmentShaderColorAA::GetShaderString(TexCoordPrecision precision,
SamplerType sampler) const {
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- uniform vec4 color;
- varying vec4 edge_dist[2]; // 8 edge distances.
-
- void main() {
- vec4 d4 = min(edge_dist[0], edge_dist[1]);
- vec2 d2 = min(d4.xz, d4.yw);
- float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = color * aa;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderColorAA::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ uniform vec4 color;
+ varying vec4 edge_dist[2]; // 8 edge distances.
+ });
+}
+
+std::string FragmentShaderColorAA::GetShaderBody() {
+ return SHADER0([]() {
+ void main() {
+ vec4 d4 = min(edge_dist[0], edge_dist[1]);
+ vec2 d2 = min(d4.xz, d4.yw);
+ float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+ gl_FragColor = color * aa;
+ }
+ });
}
FragmentShaderCheckerboard::FragmentShaderCheckerboard()
@@ -1960,30 +2282,35 @@ void FragmentShaderCheckerboard::Init(GLES2Interface* context,
std::string FragmentShaderCheckerboard::GetShaderString(
TexCoordPrecision precision,
SamplerType sampler) const {
+ return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderCheckerboard::GetShaderHead() {
+ return SHADER0([]() {
+ precision mediump float;
+ precision mediump int;
+ varying vec2 v_texCoord;
+ uniform float alpha;
+ uniform float frequency;
+ uniform vec4 texTransform;
+ uniform vec4 color;
+ });
+}
+
+std::string FragmentShaderCheckerboard::GetShaderBody() {
// Shader based on Example 13-17 of "OpenGL ES 2.0 Programming Guide"
// by Munshi, Ginsburg, Shreiner.
- // clang-format off
- return FRAGMENT_SHADER(
- // clang-format on
- precision mediump float;
- precision mediump int;
- varying vec2 v_texCoord;
- uniform float alpha;
- uniform float frequency;
- uniform vec4 texTransform;
- uniform vec4 color;
- void main() {
- vec4 color1 = vec4(1.0, 1.0, 1.0, 1.0);
- vec4 color2 = color;
- vec2 texCoord =
- clamp(v_texCoord, 0.0, 1.0) * texTransform.zw + texTransform.xy;
- vec2 coord = mod(floor(texCoord * frequency * 2.0), 2.0);
- float picker = abs(coord.x - coord.y); // NOLINT
- gl_FragColor = mix(color1, color2, picker) * alpha;
- }
- // clang-format off
- ); // NOLINT(whitespace/parens)
- // clang-format on
+ return SHADER0([]() {
+ void main() {
+ vec4 color1 = vec4(1.0, 1.0, 1.0, 1.0);
+ vec4 color2 = color;
+ vec2 texCoord =
+ clamp(v_texCoord, 0.0, 1.0) * texTransform.zw + texTransform.xy;
+ vec2 coord = mod(floor(texCoord * frequency * 2.0), 2.0);
+ float picker = abs(coord.x - coord.y); // NOLINT
+ gl_FragColor = mix(color1, color2, picker) * alpha;
+ }
+ });
}
} // namespace cc
diff --git a/chromium/cc/output/shader.h b/chromium/cc/output/shader.h
index 0384366feb0..d692a123cd7 100644
--- a/chromium/cc/output/shader.h
+++ b/chromium/cc/output/shader.h
@@ -24,37 +24,65 @@ class GLES2Interface;
namespace cc {
enum TexCoordPrecision {
- TexCoordPrecisionNA = 0,
- TexCoordPrecisionMedium = 1,
- TexCoordPrecisionHigh = 2,
- NumTexCoordPrecisions = 3
+ TEX_COORD_PRECISION_NA = 0,
+ TEX_COORD_PRECISION_MEDIUM = 1,
+ TEX_COORD_PRECISION_HIGH = 2,
+ LAST_TEX_COORD_PRECISION = 2
};
enum SamplerType {
- SamplerTypeNA = 0,
- SamplerType2D = 1,
- SamplerType2DRect = 2,
- SamplerTypeExternalOES = 3,
- NumSamplerTypes = 4
+ SAMPLER_TYPE_NA = 0,
+ SAMPLER_TYPE_2D = 1,
+ SAMPLER_TYPE_2D_RECT = 2,
+ SAMPLER_TYPE_EXTERNAL_OES = 3,
+ LAST_SAMPLER_TYPE = 3
};
enum BlendMode {
- BlendModeNormal,
- BlendModeOverlay,
- BlendModeDarken,
- BlendModeLighten,
- BlendModeColorDodge,
- BlendModeColorBurn,
- BlendModeHardLight,
- BlendModeSoftLight,
- BlendModeDifference,
- BlendModeExclusion,
- BlendModeMultiply,
- BlendModeHue,
- BlendModeSaturation,
- BlendModeColor,
- BlendModeLuminosity,
- NumBlendModes
+ BLEND_MODE_NONE,
+ BLEND_MODE_NORMAL,
+ BLEND_MODE_SCREEN,
+ BLEND_MODE_OVERLAY,
+ BLEND_MODE_DARKEN,
+ BLEND_MODE_LIGHTEN,
+ BLEND_MODE_COLOR_DODGE,
+ BLEND_MODE_COLOR_BURN,
+ BLEND_MODE_HARD_LIGHT,
+ BLEND_MODE_SOFT_LIGHT,
+ BLEND_MODE_DIFFERENCE,
+ BLEND_MODE_EXCLUSION,
+ BLEND_MODE_MULTIPLY,
+ BLEND_MODE_HUE,
+ BLEND_MODE_SATURATION,
+ BLEND_MODE_COLOR,
+ BLEND_MODE_LUMINOSITY,
+ LAST_BLEND_MODE = BLEND_MODE_LUMINOSITY
+};
+
+enum MaskMode {
+ NO_MASK = 0,
+ HAS_MASK = 1,
+ LAST_MASK_VALUE = HAS_MASK
+};
+
+struct ShaderLocations {
+ ShaderLocations();
+
+ int sampler = -1;
+ int quad = -1;
+ int edge = -1;
+ int viewport = -1;
+ int mask_sampler = -1;
+ int mask_tex_coord_scale = -1;
+ int mask_tex_coord_offset = -1;
+ int matrix = -1;
+ int alpha = -1;
+ int color_matrix = -1;
+ int color_offset = -1;
+ int tex_transform = -1;
+ int backdrop = -1;
+ int backdrop_rect = -1;
+ int original_backdrop = -1;
};
// Note: The highp_threshold_cache must be provided by the caller to make
@@ -81,6 +109,8 @@ class VertexShaderPosTex {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
int matrix_location() const { return matrix_location_; }
@@ -98,15 +128,21 @@ class VertexShaderPosTexYUVStretchOffset {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
int matrix_location() const { return matrix_location_; }
- int tex_scale_location() const { return tex_scale_location_; }
- int tex_offset_location() const { return tex_offset_location_; }
+ int ya_tex_scale_location() const { return ya_tex_scale_location_; }
+ int ya_tex_offset_location() const { return ya_tex_offset_location_; }
+ int uv_tex_scale_location() const { return uv_tex_scale_location_; }
+ int uv_tex_offset_location() const { return uv_tex_offset_location_; }
private:
int matrix_location_;
- int tex_scale_location_;
- int tex_offset_location_;
+ int ya_tex_scale_location_;
+ int ya_tex_offset_location_;
+ int uv_tex_scale_location_;
+ int uv_tex_offset_location_;
DISALLOW_COPY_AND_ASSIGN(VertexShaderPosTexYUVStretchOffset);
};
@@ -119,6 +155,8 @@ class VertexShaderPos {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
int matrix_location() const { return matrix_location_; }
@@ -134,6 +172,8 @@ class VertexShaderPosTexIdentity {
unsigned program,
int* base_uniform_index) {}
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
class VertexShaderPosTexTransform {
@@ -144,6 +184,9 @@ class VertexShaderPosTexTransform {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
int matrix_location() const { return matrix_location_; }
int tex_transform_location() const { return tex_transform_location_; }
@@ -165,6 +208,8 @@ class VertexShaderQuad {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
int matrix_location() const { return matrix_location_; }
int viewport_location() const { return -1; }
@@ -186,6 +231,8 @@ class VertexShaderQuadAA {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
int matrix_location() const { return matrix_location_; }
int viewport_location() const { return viewport_location_; }
@@ -210,6 +257,9 @@ class VertexShaderQuadTexTransformAA {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
int matrix_location() const { return matrix_location_; }
int viewport_location() const { return viewport_location_; }
@@ -235,6 +285,8 @@ class VertexShaderTile {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
int matrix_location() const { return matrix_location_; }
int viewport_location() const { return -1; }
@@ -260,6 +312,8 @@ class VertexShaderTileAA {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
int matrix_location() const { return matrix_location_; }
int viewport_location() const { return viewport_location_; }
@@ -287,6 +341,8 @@ class VertexShaderVideoTransform {
unsigned program,
int* base_uniform_index);
std::string GetShaderString() const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
int matrix_location() const { return matrix_location_; }
int tex_matrix_location() const { return tex_matrix_location_; }
@@ -301,11 +357,16 @@ class VertexShaderVideoTransform {
class FragmentTexBlendMode {
public:
int backdrop_location() const { return backdrop_location_; }
+ int original_backdrop_location() const { return original_backdrop_location_; }
int backdrop_rect_location() const { return backdrop_rect_location_; }
BlendMode blend_mode() const { return blend_mode_; }
void set_blend_mode(BlendMode blend_mode) { blend_mode_ = blend_mode; }
- bool is_default_blend_mode() const { return blend_mode_ == BlendModeNormal; }
+ bool has_blend_mode() const { return blend_mode_ != BLEND_MODE_NONE; }
+ void set_mask_for_background(bool mask_for_background) {
+ mask_for_background_ = mask_for_background;
+ }
+ bool mask_for_background() const { return mask_for_background_; }
protected:
FragmentTexBlendMode();
@@ -313,10 +374,12 @@ class FragmentTexBlendMode {
std::string SetBlendModeFunctions(std::string shader_string) const;
int backdrop_location_;
+ int original_backdrop_location_;
int backdrop_rect_location_;
private:
BlendMode blend_mode_;
+ bool mask_for_background_;
std::string GetHelperFunctions() const;
std::string GetBlendFunction() const;
@@ -400,12 +463,16 @@ class FragmentShaderRGBATexVaryingAlpha : public FragmentTexOpaqueBinding {
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
class FragmentShaderRGBATexPremultiplyAlpha : public FragmentTexOpaqueBinding {
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
class FragmentShaderTexBackgroundVaryingAlpha
@@ -413,6 +480,8 @@ class FragmentShaderTexBackgroundVaryingAlpha
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
class FragmentShaderTexBackgroundPremultiplyAlpha
@@ -420,31 +489,43 @@ class FragmentShaderTexBackgroundPremultiplyAlpha
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
class FragmentShaderRGBATexAlpha : public FragmentTexAlphaBinding {
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
};
class FragmentShaderRGBATexColorMatrixAlpha
: public FragmentTexColorMatrixAlphaBinding {
public:
- std::string GetShaderString(
- TexCoordPrecision precision, SamplerType sampler) const;
+ std::string GetShaderString(TexCoordPrecision precision,
+ SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
};
class FragmentShaderRGBATexOpaque : public FragmentTexOpaqueBinding {
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
class FragmentShaderRGBATex : public FragmentTexOpaqueBinding {
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
// Swizzles the red and blue component of sampled texel with alpha.
@@ -452,6 +533,8 @@ class FragmentShaderRGBATexSwizzleAlpha : public FragmentTexAlphaBinding {
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
// Swizzles the red and blue component of sampled texel without alpha.
@@ -459,6 +542,8 @@ class FragmentShaderRGBATexSwizzleOpaque : public FragmentTexOpaqueBinding {
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
class FragmentShaderRGBATexAlphaAA : public FragmentTexBlendMode {
@@ -470,6 +555,9 @@ class FragmentShaderRGBATexAlphaAA : public FragmentTexBlendMode {
int* base_uniform_index);
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
int alpha_location() const { return alpha_location_; }
int sampler_location() const { return sampler_location_; }
@@ -507,6 +595,8 @@ class FragmentShaderRGBATexClampAlphaAA
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
// Swizzles the red and blue component of sampled texel.
@@ -515,6 +605,8 @@ class FragmentShaderRGBATexClampSwizzleAlphaAA
public:
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
};
class FragmentShaderRGBATexAlphaMask : public FragmentTexBlendMode {
@@ -522,7 +614,9 @@ class FragmentShaderRGBATexAlphaMask : public FragmentTexBlendMode {
FragmentShaderRGBATexAlphaMask();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
-
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
int* base_uniform_index);
@@ -551,7 +645,9 @@ class FragmentShaderRGBATexAlphaMaskAA : public FragmentTexBlendMode {
FragmentShaderRGBATexAlphaMaskAA();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
-
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
int* base_uniform_index);
@@ -581,7 +677,9 @@ class FragmentShaderRGBATexAlphaMaskColorMatrixAA
FragmentShaderRGBATexAlphaMaskColorMatrixAA();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
-
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
int* base_uniform_index);
@@ -612,7 +710,9 @@ class FragmentShaderRGBATexAlphaColorMatrixAA : public FragmentTexBlendMode {
FragmentShaderRGBATexAlphaColorMatrixAA();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
-
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
int* base_uniform_index);
@@ -633,7 +733,9 @@ class FragmentShaderRGBATexAlphaMaskColorMatrix : public FragmentTexBlendMode {
FragmentShaderRGBATexAlphaMaskColorMatrix();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
-
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
+ void FillLocations(ShaderLocations* locations) const;
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
int* base_uniform_index);
@@ -664,6 +766,8 @@ class FragmentShaderYUVVideo : public FragmentTexBlendMode {
FragmentShaderYUVVideo();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
@@ -674,6 +778,8 @@ class FragmentShaderYUVVideo : public FragmentTexBlendMode {
int alpha_location() const { return alpha_location_; }
int yuv_matrix_location() const { return yuv_matrix_location_; }
int yuv_adj_location() const { return yuv_adj_location_; }
+ int ya_clamp_rect_location() const { return ya_clamp_rect_location_; }
+ int uv_clamp_rect_location() const { return uv_clamp_rect_location_; }
private:
int y_texture_location_;
@@ -682,6 +788,8 @@ class FragmentShaderYUVVideo : public FragmentTexBlendMode {
int alpha_location_;
int yuv_matrix_location_;
int yuv_adj_location_;
+ int ya_clamp_rect_location_;
+ int uv_clamp_rect_location_;
DISALLOW_COPY_AND_ASSIGN(FragmentShaderYUVVideo);
};
@@ -691,6 +799,8 @@ class FragmentShaderYUVAVideo : public FragmentTexBlendMode {
FragmentShaderYUVAVideo();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
@@ -703,6 +813,8 @@ class FragmentShaderYUVAVideo : public FragmentTexBlendMode {
int alpha_location() const { return alpha_location_; }
int yuv_matrix_location() const { return yuv_matrix_location_; }
int yuv_adj_location() const { return yuv_adj_location_; }
+ int ya_clamp_rect_location() const { return ya_clamp_rect_location_; }
+ int uv_clamp_rect_location() const { return uv_clamp_rect_location_; }
private:
int y_texture_location_;
@@ -712,6 +824,8 @@ class FragmentShaderYUVAVideo : public FragmentTexBlendMode {
int alpha_location_;
int yuv_matrix_location_;
int yuv_adj_location_;
+ int ya_clamp_rect_location_;
+ int uv_clamp_rect_location_;
DISALLOW_COPY_AND_ASSIGN(FragmentShaderYUVAVideo);
};
@@ -721,6 +835,8 @@ class FragmentShaderColor : public FragmentTexBlendMode {
FragmentShaderColor();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
@@ -738,6 +854,8 @@ class FragmentShaderColorAA : public FragmentTexBlendMode {
FragmentShaderColorAA();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
@@ -755,6 +873,8 @@ class FragmentShaderCheckerboard : public FragmentTexBlendMode {
FragmentShaderCheckerboard();
std::string GetShaderString(
TexCoordPrecision precision, SamplerType sampler) const;
+ static std::string GetShaderHead();
+ static std::string GetShaderBody();
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
diff --git a/chromium/cc/output/shader_unittest.cc b/chromium/cc/output/shader_unittest.cc
index 4fd696f55c4..675e47fb26b 100644
--- a/chromium/cc/output/shader_unittest.cc
+++ b/chromium/cc/output/shader_unittest.cc
@@ -27,24 +27,32 @@ TEST(ShaderTest, HighpThresholds) {
gfx::Size bigSize(2560, 2560);
threshold_min = 0;
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, closePoint));
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, smallSize));
- EXPECT_EQ(TexCoordPrecisionHigh, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, farPoint));
- EXPECT_EQ(TexCoordPrecisionHigh, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, bigSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ closePoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ smallSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ farPoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ bigSize));
threshold_min = 3000;
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, closePoint));
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, smallSize));
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, farPoint));
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, bigSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ closePoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ smallSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ farPoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ bigSize));
}
} // namespace cc
diff --git a/chromium/cc/output/software_output_device.cc b/chromium/cc/output/software_output_device.cc
index 0c374c9afb4..3692224679d 100644
--- a/chromium/cc/output/software_output_device.cc
+++ b/chromium/cc/output/software_output_device.cc
@@ -27,13 +27,13 @@ void SoftwareOutputDevice::Resize(const gfx::Size& viewport_pixel_size,
viewport_pixel_size.height(),
kOpaque_SkAlphaType);
viewport_pixel_size_ = viewport_pixel_size;
- canvas_ = skia::AdoptRef(SkCanvas::NewRaster(info));
+ surface_ = skia::AdoptRef(SkSurface::NewRaster(info));
}
SkCanvas* SoftwareOutputDevice::BeginPaint(const gfx::Rect& damage_rect) {
- DCHECK(canvas_);
+ DCHECK(surface_);
damage_rect_ = damage_rect;
- return canvas_.get();
+ return surface_->getCanvas();
}
void SoftwareOutputDevice::EndPaint(SoftwareFrameData* frame_data) {
@@ -43,17 +43,6 @@ void SoftwareOutputDevice::EndPaint(SoftwareFrameData* frame_data) {
frame_data->damage_rect = damage_rect_;
}
-void SoftwareOutputDevice::CopyToPixels(const gfx::Rect& rect, void* pixels) {
- DCHECK(canvas_);
- SkImageInfo info = SkImageInfo::MakeN32Premul(rect.width(), rect.height());
- canvas_->readPixels(info, pixels, info.minRowBytes(), rect.x(), rect.y());
-}
-
-void SoftwareOutputDevice::Scroll(const gfx::Vector2d& delta,
- const gfx::Rect& clip_rect) {
- NOTIMPLEMENTED();
-}
-
void SoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) {
NOTIMPLEMENTED();
}
diff --git a/chromium/cc/output/software_output_device.h b/chromium/cc/output/software_output_device.h
index d183fdcb434..45ce83117c7 100644
--- a/chromium/cc/output/software_output_device.h
+++ b/chromium/cc/output/software_output_device.h
@@ -9,6 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/vector2d.h"
@@ -47,14 +48,6 @@ class CC_EXPORT SoftwareOutputDevice {
// that it holds to it.
virtual void EndPaint(SoftwareFrameData* frame_data);
- // Copies pixels inside |rect| from the current software framebuffer to
- // |pixels|. Fails if there is no current softwareframebuffer.
- virtual void CopyToPixels(const gfx::Rect& rect, void* pixels);
-
- // Blit the pixel content of the SoftwareOutputDevice by |delta| with the
- // write clipped to |clip_rect|.
- virtual void Scroll(const gfx::Vector2d& delta, const gfx::Rect& clip_rect);
-
// Discard the backing buffer in the surface provided by this instance.
virtual void DiscardBackbuffer() {}
@@ -75,7 +68,7 @@ class CC_EXPORT SoftwareOutputDevice {
gfx::Size viewport_pixel_size_;
float scale_factor_;
gfx::Rect damage_rect_;
- skia::RefPtr<SkCanvas> canvas_;
+ skia::RefPtr<SkSurface> surface_;
scoped_ptr<gfx::VSyncProvider> vsync_provider_;
private:
diff --git a/chromium/cc/output/software_renderer.cc b/chromium/cc/output/software_renderer.cc
index 06f18518762..80a5f0e53ca 100644
--- a/chromium/cc/output/software_renderer.cc
+++ b/chromium/cc/output/software_renderer.cc
@@ -4,7 +4,7 @@
#include "cc/output/software_renderer.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_ack.h"
@@ -25,6 +25,7 @@
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/include/effects/SkLayerRasterizer.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -63,7 +64,7 @@ static SkShader::TileMode WrapModeToTileMode(GLint wrap_mode) {
scoped_ptr<SoftwareRenderer> SoftwareRenderer::Create(
RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider) {
return make_scoped_ptr(new SoftwareRenderer(
@@ -71,7 +72,7 @@ scoped_ptr<SoftwareRenderer> SoftwareRenderer::Create(
}
SoftwareRenderer::SoftwareRenderer(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider)
: DirectRenderer(client, settings, output_surface, resource_provider),
@@ -108,6 +109,7 @@ void SoftwareRenderer::BeginDrawingFrame(DrawingFrame* frame) {
void SoftwareRenderer::FinishDrawingFrame(DrawingFrame* frame) {
TRACE_EVENT0("cc", "SoftwareRenderer::FinishDrawingFrame");
current_framebuffer_lock_ = nullptr;
+ current_framebuffer_canvas_.clear();
current_canvas_ = NULL;
root_canvas_ = NULL;
@@ -151,6 +153,7 @@ void SoftwareRenderer::Finish() {}
void SoftwareRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
DCHECK(!output_surface_->HasExternalStencilTest());
current_framebuffer_lock_ = nullptr;
+ current_framebuffer_canvas_.clear();
current_canvas_ = root_canvas_;
}
@@ -158,14 +161,17 @@ bool SoftwareRenderer::BindFramebufferToTexture(
DrawingFrame* frame,
const ScopedResource* texture,
const gfx::Rect& target_rect) {
+ DCHECK(texture->id());
+
+ // Explicitly release lock, otherwise we can crash when try to lock
+ // same texture again.
+ current_framebuffer_lock_ = nullptr;
current_framebuffer_lock_ = make_scoped_ptr(
new ResourceProvider::ScopedWriteLockSoftware(
resource_provider_, texture->id()));
- current_canvas_ = current_framebuffer_lock_->sk_canvas();
- InitializeViewport(frame,
- target_rect,
- gfx::Rect(target_rect.size()),
- target_rect.size());
+ current_framebuffer_canvas_ =
+ skia::AdoptRef(new SkCanvas(current_framebuffer_lock_->sk_bitmap()));
+ current_canvas_ = current_framebuffer_canvas_.get();
return true;
}
@@ -192,11 +198,7 @@ void SoftwareRenderer::ClearCanvas(SkColor color) {
current_canvas_->clear(color);
}
-void SoftwareRenderer::DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) {}
-
-void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) {
+void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame) {
if (frame->current_render_pass->has_transparent_background) {
ClearCanvas(SkColorSetARGB(0, 0, 0, 0));
} else {
@@ -208,25 +210,45 @@ void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame,
}
}
-void SoftwareRenderer::SetDrawViewport(
- const gfx::Rect& window_space_viewport) {}
+void SoftwareRenderer::PrepareSurfaceForPass(
+ DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) {
+ switch (initialization_mode) {
+ case SURFACE_INITIALIZATION_MODE_PRESERVE:
+ EnsureScissorTestDisabled();
+ return;
+ case SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR:
+ EnsureScissorTestDisabled();
+ ClearFramebuffer(frame);
+ break;
+ case SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR:
+ SetScissorTestRect(render_pass_scissor);
+ ClearFramebuffer(frame);
+ break;
+ }
+}
bool SoftwareRenderer::IsSoftwareResource(
ResourceProvider::ResourceId resource_id) const {
switch (resource_provider_->GetResourceType(resource_id)) {
- case ResourceProvider::GLTexture:
+ case ResourceProvider::RESOURCE_TYPE_GL_TEXTURE:
return false;
- case ResourceProvider::Bitmap:
+ case ResourceProvider::RESOURCE_TYPE_BITMAP:
return true;
- case ResourceProvider::InvalidType:
- break;
}
LOG(FATAL) << "Invalid resource type.";
return false;
}
-void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
+void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame,
+ const DrawQuad* quad,
+ const gfx::QuadF* draw_region) {
+ if (draw_region) {
+ current_canvas_->save();
+ }
+
TRACE_EVENT0("cc", "SoftwareRenderer::DoDrawQuad");
gfx::Transform quad_rect_matrix;
QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
@@ -250,7 +272,7 @@ void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
if (settings_->allow_antialiasing &&
(settings_->force_antialiasing || all_four_edges_are_exterior))
current_paint_.setAntiAlias(true);
- current_paint_.setFilterLevel(SkPaint::kLow_FilterLevel);
+ current_paint_.setFilterQuality(kLow_SkFilterQuality);
}
if (quad->ShouldDrawWithBlending() ||
@@ -261,9 +283,31 @@ void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
current_paint_.setXfermodeMode(SkXfermode::kSrc_Mode);
}
+ if (draw_region) {
+ gfx::QuadF local_draw_region(*draw_region);
+ SkPath draw_region_clip_path;
+ local_draw_region -=
+ gfx::Vector2dF(quad->visible_rect.x(), quad->visible_rect.y());
+ local_draw_region.Scale(1.0f / quad->visible_rect.width(),
+ 1.0f / quad->visible_rect.height());
+ local_draw_region -= gfx::Vector2dF(0.5f, 0.5f);
+
+ SkPoint clip_points[4];
+ QuadFToSkPoints(local_draw_region, clip_points);
+ draw_region_clip_path.addPoly(clip_points, 4, true);
+
+ current_canvas_->clipPath(draw_region_clip_path, SkRegion::kIntersect_Op,
+ false);
+ }
+
switch (quad->material) {
case DrawQuad::CHECKERBOARD:
- DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad));
+ // TODO(enne) For now since checkerboards shouldn't be part of a 3D
+ // context, clipping regions aren't supported so we skip drawing them
+ // if this becomes the case.
+ if (!draw_region) {
+ DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad));
+ }
break;
case DrawQuad::DEBUG_BORDER:
DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad));
@@ -298,6 +342,9 @@ void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
}
current_canvas_->resetMatrix();
+ if (draw_region) {
+ current_canvas_->restore();
+ }
}
void SoftwareRenderer::DrawCheckerboardQuad(const DrawingFrame* frame,
@@ -305,7 +352,7 @@ void SoftwareRenderer::DrawCheckerboardQuad(const DrawingFrame* frame,
gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional(
QuadVertexRect(), quad->rect, quad->visible_rect);
current_paint_.setColor(quad->color);
- current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color));
+ current_paint_.setAlpha(quad->opacity());
current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect),
current_paint_);
}
@@ -343,15 +390,16 @@ void SoftwareRenderer::DrawPictureQuad(const DrawingFrame* frame,
// (http://crbug.com/280374).
skia::RefPtr<SkDrawFilter> opacity_filter =
skia::AdoptRef(new skia::OpacityDrawFilter(
- quad->opacity(), frame->disable_picture_quad_image_filtering));
+ quad->opacity(), frame->disable_picture_quad_image_filtering ||
+ quad->nearest_neighbor));
DCHECK(!current_canvas_->getDrawFilter());
current_canvas_->setDrawFilter(opacity_filter.get());
TRACE_EVENT0("cc",
"SoftwareRenderer::DrawPictureQuad");
- quad->picture_pile->RasterDirect(current_canvas_, quad->content_rect,
- quad->contents_scale);
+ quad->raster_source->PlaybackToSharedCanvas(
+ current_canvas_, quad->content_rect, quad->contents_scale);
current_canvas_->setDrawFilter(NULL);
}
@@ -390,7 +438,7 @@ void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame,
QuadVertexRect(), quad->rect, quad->visible_rect);
SkRect quad_rect = gfx::RectFToSkRect(visible_quad_vertex_rect);
- if (quad->flipped)
+ if (quad->y_flipped)
current_canvas_->scale(1, -1);
bool blend_background = quad->background_color != SK_ColorTRANSPARENT &&
@@ -405,6 +453,8 @@ void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame,
background_paint.setColor(quad->background_color);
current_canvas_->drawRect(quad_rect, background_paint);
}
+ current_paint_.setFilterQuality(
+ quad->nearest_neighbor ? kNone_SkFilterQuality : kLow_SkFilterQuality);
SkShader::TileMode tile_mode = WrapModeToTileMode(lock.wrap_mode());
if (tile_mode != SkShader::kClamp_TileMode) {
SkMatrix matrix;
@@ -445,7 +495,8 @@ void SoftwareRenderer::DrawTileQuad(const DrawingFrame* frame,
QuadVertexRect(), quad->rect, quad->visible_rect);
SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect);
- current_paint_.setFilterLevel(SkPaint::kLow_FilterLevel);
+ current_paint_.setFilterQuality(
+ quad->nearest_neighbor ? kNone_SkFilterQuality : kLow_SkFilterQuality);
current_canvas_->drawBitmapRectToRect(
*lock.sk_bitmap(),
&uv_rect,
@@ -457,10 +508,10 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame,
const RenderPassDrawQuad* quad) {
ScopedResource* content_texture =
render_pass_textures_.get(quad->render_pass_id);
- if (!content_texture || !content_texture->id())
- return;
-
+ DCHECK(content_texture);
+ DCHECK(content_texture->id());
DCHECK(IsSoftwareResource(content_texture->id()));
+
ResourceProvider::ScopedReadLockSoftware lock(resource_provider_,
content_texture->id());
if (!lock.valid())
diff --git a/chromium/cc/output/software_renderer.h b/chromium/cc/output/software_renderer.h
index 2a672d5c172..74f328edc01 100644
--- a/chromium/cc/output/software_renderer.h
+++ b/chromium/cc/output/software_renderer.h
@@ -29,7 +29,7 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer {
public:
static scoped_ptr<SoftwareRenderer> Create(
RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider);
@@ -46,13 +46,14 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer {
bool BindFramebufferToTexture(DrawingFrame* frame,
const ScopedResource* texture,
const gfx::Rect& target_rect) override;
- void SetDrawViewport(const gfx::Rect& window_space_viewport) override;
void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
- void DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) override;
- void ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) override;
- void DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) override;
+ void PrepareSurfaceForPass(DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) override;
+
+ void DoDrawQuad(DrawingFrame* frame,
+ const DrawQuad* quad,
+ const gfx::QuadF* draw_region) override;
void BeginDrawingFrame(DrawingFrame* frame) override;
void FinishDrawingFrame(DrawingFrame* frame) override;
bool FlippedFramebuffer(const DrawingFrame* frame) const override;
@@ -63,7 +64,7 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer {
scoped_ptr<CopyOutputRequest> request) override;
SoftwareRenderer(RendererClient* client,
- const LayerTreeSettings* settings,
+ const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider);
@@ -71,6 +72,7 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer {
private:
void ClearCanvas(SkColor color);
+ void ClearFramebuffer(DrawingFrame* frame);
void SetClipRect(const gfx::Rect& rect);
bool IsSoftwareResource(ResourceProvider::ResourceId resource_id) const;
@@ -102,6 +104,7 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer {
SkPaint current_paint_;
scoped_ptr<ResourceProvider::ScopedWriteLockSoftware>
current_framebuffer_lock_;
+ skia::RefPtr<SkCanvas> current_framebuffer_canvas_;
scoped_ptr<SoftwareFrameData> current_frame_data_;
DISALLOW_COPY_AND_ASSIGN(SoftwareRenderer);
diff --git a/chromium/cc/output/software_renderer_unittest.cc b/chromium/cc/output/software_renderer_unittest.cc
index 60f75d9081b..3b2c4bc2317 100644
--- a/chromium/cc/output/software_renderer_unittest.cc
+++ b/chromium/cc/output/software_renderer_unittest.cc
@@ -86,7 +86,7 @@ class SoftwareRendererTest : public testing::Test, public RendererClient {
}
protected:
- LayerTreeSettings settings_;
+ RendererSettings settings_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
@@ -135,7 +135,7 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) {
scoped_ptr<SkBitmap> output =
DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
EXPECT_EQ(outer_rect.width(), output->info().fWidth);
- EXPECT_EQ(outer_rect.width(), output->info().fHeight);
+ EXPECT_EQ(outer_rect.height(), output->info().fHeight);
EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0));
EXPECT_EQ(SK_ColorYELLOW,
@@ -155,16 +155,12 @@ TEST_F(SoftwareRendererTest, TileQuad) {
ResourceProvider::ResourceId resource_yellow =
resource_provider()->CreateResource(
- outer_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
+ outer_size, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
ResourceProvider::ResourceId resource_cyan =
resource_provider()->CreateResource(
- inner_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
+ inner_size, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
SkBitmap yellow_tile;
yellow_tile.allocN32Pixels(outer_size.width(), outer_size.height());
@@ -174,17 +170,11 @@ TEST_F(SoftwareRendererTest, TileQuad) {
cyan_tile.allocN32Pixels(inner_size.width(), inner_size.height());
cyan_tile.eraseColor(SK_ColorCYAN);
- resource_provider()->SetPixels(
- resource_yellow,
- static_cast<uint8_t*>(yellow_tile.getPixels()),
- gfx::Rect(outer_size),
- gfx::Rect(outer_size),
- gfx::Vector2d());
- resource_provider()->SetPixels(resource_cyan,
- static_cast<uint8_t*>(cyan_tile.getPixels()),
- gfx::Rect(inner_size),
- gfx::Rect(inner_size),
- gfx::Vector2d());
+ resource_provider()->CopyToResource(
+ resource_yellow, static_cast<uint8_t*>(yellow_tile.getPixels()),
+ outer_size);
+ resource_provider()->CopyToResource(
+ resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), inner_size);
gfx::Rect root_rect = outer_rect;
@@ -211,6 +201,7 @@ TEST_F(SoftwareRendererTest, TileQuad) {
resource_cyan,
gfx::RectF(inner_size),
inner_size,
+ false,
false);
TileDrawQuad* outer_quad =
root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
@@ -221,6 +212,7 @@ TEST_F(SoftwareRendererTest, TileQuad) {
resource_yellow,
gfx::RectF(outer_size),
outer_size,
+ false,
false);
RenderPassList list;
@@ -231,7 +223,7 @@ TEST_F(SoftwareRendererTest, TileQuad) {
scoped_ptr<SkBitmap> output =
DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
EXPECT_EQ(outer_rect.width(), output->info().fWidth);
- EXPECT_EQ(outer_rect.width(), output->info().fHeight);
+ EXPECT_EQ(outer_rect.height(), output->info().fHeight);
EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0));
EXPECT_EQ(SK_ColorYELLOW,
@@ -250,9 +242,7 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
ResourceProvider::ResourceId resource_cyan =
resource_provider()->CreateResource(
- tile_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ tile_size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
RGBA_8888);
SkBitmap cyan_tile; // The lowest five rows are yellow.
@@ -263,11 +253,8 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
0, visible_rect.bottom() - 1, tile_rect.width(), tile_rect.bottom()),
SK_ColorYELLOW);
- resource_provider()->SetPixels(resource_cyan,
- static_cast<uint8_t*>(cyan_tile.getPixels()),
- gfx::Rect(tile_size),
- gfx::Rect(tile_size),
- gfx::Vector2d());
+ resource_provider()->CopyToResource(
+ resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), tile_size);
gfx::Rect root_rect(tile_size);
@@ -294,6 +281,7 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
resource_cyan,
gfx::RectF(tile_size),
tile_size,
+ false,
false);
quad->visible_rect = visible_rect;
@@ -305,7 +293,7 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
scoped_ptr<SkBitmap> output =
DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
EXPECT_EQ(tile_rect.width(), output->info().fWidth);
- EXPECT_EQ(tile_rect.width(), output->info().fHeight);
+ EXPECT_EQ(tile_rect.height(), output->info().fHeight);
// Check portion of tile not in visible rect isn't drawn.
const unsigned int kTransparent = SK_ColorTRANSPARENT;
@@ -347,7 +335,7 @@ TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) {
scoped_ptr<SkBitmap> output =
DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
- EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
+ EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight);
EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
EXPECT_EQ(SK_ColorGREEN,
@@ -369,7 +357,7 @@ TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) {
output = DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
- EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
+ EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight);
// If we didn't clear, the borders should still be green.
EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
@@ -414,7 +402,7 @@ TEST_F(SoftwareRendererTest, RenderPassVisibleRect) {
scoped_ptr<SkBitmap> output =
DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
- EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
+ EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight);
EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
EXPECT_EQ(SK_ColorGREEN,
diff --git a/chromium/cc/output/static_geometry_binding.cc b/chromium/cc/output/static_geometry_binding.cc
new file mode 100644
index 00000000000..e4af11d9491
--- /dev/null
+++ b/chromium/cc/output/static_geometry_binding.cc
@@ -0,0 +1,70 @@
+// 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.
+
+#include "cc/output/static_geometry_binding.h"
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace cc {
+
+StaticGeometryBinding::StaticGeometryBinding(gpu::gles2::GLES2Interface* gl,
+ const gfx::RectF& quad_vertex_rect)
+ : gl_(gl), quad_vertices_vbo_(0), quad_elements_vbo_(0) {
+ GeometryBindingQuad quads[8];
+ GeometryBindingQuadIndex quad_indices[8];
+
+ static_assert(sizeof(GeometryBindingQuad) == 24 * sizeof(float),
+ "struct Quad should be densely packed");
+ static_assert(sizeof(GeometryBindingQuadIndex) == 6 * sizeof(uint16_t),
+ "struct QuadIndex should be densely packed");
+
+ for (size_t i = 0; i < 8; i++) {
+ GeometryBindingVertex v0 = {
+ {quad_vertex_rect.x(), quad_vertex_rect.bottom(), 0.0f},
+ {0.0f, 1.0f},
+ i * 4.0f + 0.0f};
+ GeometryBindingVertex v1 = {
+ {quad_vertex_rect.x(), quad_vertex_rect.y(), 0.0f},
+ {0.0f, 0.0f},
+ i * 4.0f + 1.0f};
+ GeometryBindingVertex v2 = {
+ {quad_vertex_rect.right(), quad_vertex_rect.y(), 0.0f},
+ {1.0f, 0.0f},
+ i * 4.0f + 2.0f};
+ GeometryBindingVertex v3 = {
+ {quad_vertex_rect.right(), quad_vertex_rect.bottom(), 0.0f},
+ {1.0f, 1.0f},
+ i * 4.0f + 3.0f};
+ GeometryBindingQuad x(v0, v1, v2, v3);
+ quads[i] = x;
+ GeometryBindingQuadIndex y(
+ static_cast<uint16>(0 + 4 * i), static_cast<uint16>(1 + 4 * i),
+ static_cast<uint16>(2 + 4 * i), static_cast<uint16>(3 + 4 * i),
+ static_cast<uint16>(0 + 4 * i), static_cast<uint16>(2 + 4 * i));
+ quad_indices[i] = y;
+ }
+
+ gl_->GenBuffers(1, &quad_vertices_vbo_);
+ gl_->GenBuffers(1, &quad_elements_vbo_);
+
+ gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_);
+ gl_->BufferData(GL_ARRAY_BUFFER, sizeof(GeometryBindingQuad) * 8, quads,
+ GL_STATIC_DRAW);
+
+ gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_);
+ gl_->BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GeometryBindingQuadIndex) * 8,
+ &quad_indices, GL_STATIC_DRAW);
+}
+
+StaticGeometryBinding::~StaticGeometryBinding() {
+ gl_->DeleteBuffers(1, &quad_vertices_vbo_);
+ gl_->DeleteBuffers(1, &quad_elements_vbo_);
+}
+
+void StaticGeometryBinding::PrepareForDraw() {
+ SetupGLContext(gl_, quad_elements_vbo_, quad_vertices_vbo_);
+}
+
+} // namespace cc
diff --git a/chromium/cc/output/static_geometry_binding.h b/chromium/cc/output/static_geometry_binding.h
new file mode 100644
index 00000000000..bd6bfccc021
--- /dev/null
+++ b/chromium/cc/output/static_geometry_binding.h
@@ -0,0 +1,33 @@
+// 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_OUTPUT_STATIC_GEOMETRY_BINDING_H_
+#define CC_OUTPUT_STATIC_GEOMETRY_BINDING_H_
+
+#include "cc/output/geometry_binding.h"
+
+using gpu::gles2::GLES2Interface;
+
+namespace cc {
+
+class StaticGeometryBinding {
+ public:
+ StaticGeometryBinding(gpu::gles2::GLES2Interface* gl,
+ const gfx::RectF& quad_vertex_rect);
+ ~StaticGeometryBinding();
+
+ void PrepareForDraw();
+
+ private:
+ gpu::gles2::GLES2Interface* gl_;
+
+ GLuint quad_vertices_vbo_;
+ GLuint quad_elements_vbo_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticGeometryBinding);
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_STATIC_GEOMETRY_BINDING_H_
diff --git a/chromium/cc/output/swap_promise.h b/chromium/cc/output/swap_promise.h
new file mode 100644
index 00000000000..45deee83401
--- /dev/null
+++ b/chromium/cc/output/swap_promise.h
@@ -0,0 +1,66 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_OUTPUT_SWAP_PROMISE_H_
+#define CC_OUTPUT_SWAP_PROMISE_H_
+
+#include "cc/output/compositor_frame_metadata.h"
+
+namespace cc {
+
+// 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
+// completed in the compositor, i.e. the compositor knows it has been sent
+// to its output or not.
+//
+// If the commit results in a successful activation of the pending layer tree,
+// SwapPromise::DidActivate() will be called.
+//
+// If the new compositor state is sent to the output, SwapPromise::DidSwap()
+// will be called.
+//
+// If the scheduler fails to activate the pending tree, or the compositor
+// fails to send its new state to the output, SwapPromise::DidNotSwap() will
+// be called. Note that it is possible to activate, and subsequently not swap.
+//
+// Promises complete afer either DidSwap() or DidNotSwap() is called, thus
+// there are three possible call sequences:
+// DidNotSwap()
+// DidActivate() ; DidSwap()
+// DidActivate() ; DidNotSwap()
+//
+// Clients that wish to use SwapPromise should have a subclass that defines
+// the behavior of DidActivate(), DidSwap() and DidNotSwap(). Notice that the
+// promise can be broken at either main or impl thread, e.g. commit fails on
+// main thread, new frame data has no actual damage so
+// LayerTreeHostImpl::SwapBuffers() bails out early on impl thread, so don't
+// assume that Did*() methods are called at a particular thread. It is better
+// to let the subclass carry thread-safe member data and operate on that
+// member data in Did*().
+class CC_EXPORT SwapPromise {
+ public:
+ enum DidNotSwapReason {
+ SWAP_FAILS,
+ COMMIT_FAILS,
+ COMMIT_NO_UPDATE,
+ ACTIVATION_FAILS,
+ };
+
+ SwapPromise() {}
+ virtual ~SwapPromise() {}
+
+ virtual void DidActivate() = 0;
+ virtual void DidSwap(CompositorFrameMetadata* metadata) = 0;
+ virtual void DidNotSwap(DidNotSwapReason reason) = 0;
+
+ // A non-zero trace id identifies a trace flow object that is embedded in the
+ // swap promise. This can be used for registering additional flow steps to
+ // visualize the object's path through the system.
+ virtual int64 TraceId() const = 0;
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_SWAP_PROMISE_H_
diff --git a/chromium/cc/resources/texture_mailbox_deleter.cc b/chromium/cc/output/texture_mailbox_deleter.cc
index ab863684e81..aaf2a0ef223 100644
--- a/chromium/cc/resources/texture_mailbox_deleter.cc
+++ b/chromium/cc/output/texture_mailbox_deleter.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/texture_mailbox_deleter.h"
+#include "cc/output/texture_mailbox_deleter.h"
#include "base/bind.h"
#include "base/location.h"
diff --git a/chromium/cc/resources/texture_mailbox_deleter.h b/chromium/cc/output/texture_mailbox_deleter.h
index ca0bc0032ca..286512626d4 100644
--- a/chromium/cc/resources/texture_mailbox_deleter.h
+++ b/chromium/cc/output/texture_mailbox_deleter.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_TEXTURE_MAILBOX_DELETER_H_
-#define CC_RESOURCES_TEXTURE_MAILBOX_DELETER_H_
+#ifndef CC_OUTPUT_TEXTURE_MAILBOX_DELETER_H_
+#define CC_OUTPUT_TEXTURE_MAILBOX_DELETER_H_
#include "base/memory/weak_ptr.h"
#include "cc/base/cc_export.h"
@@ -48,4 +48,4 @@ class CC_EXPORT TextureMailboxDeleter {
} // namespace cc
-#endif // CC_RESOURCES_TEXTURE_MAILBOX_DELETER_H_
+#endif // CC_OUTPUT_TEXTURE_MAILBOX_DELETER_H_
diff --git a/chromium/cc/resources/texture_mailbox_deleter_unittest.cc b/chromium/cc/output/texture_mailbox_deleter_unittest.cc
index 05e33a313aa..34d8595aa20 100644
--- a/chromium/cc/resources/texture_mailbox_deleter_unittest.cc
+++ b/chromium/cc/output/texture_mailbox_deleter_unittest.cc
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/texture_mailbox_deleter.h"
+#include "cc/output/texture_mailbox_deleter.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/resources/single_release_callback.h"
#include "cc/test/test_context_provider.h"
#include "cc/test/test_web_graphics_context_3d.h"
@@ -15,7 +16,7 @@ namespace {
TEST(TextureMailboxDeleterTest, Destroy) {
scoped_ptr<TextureMailboxDeleter> deleter(
- new TextureMailboxDeleter(base::MessageLoopProxy::current()));
+ new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get()));
scoped_refptr<TestContextProvider> context_provider =
TestContextProvider::Create();
diff --git a/chromium/cc/output/viewport_selection_bound.h b/chromium/cc/output/viewport_selection_bound.h
index 77298e71f83..2e4fe3c9e3d 100644
--- a/chromium/cc/output/viewport_selection_bound.h
+++ b/chromium/cc/output/viewport_selection_bound.h
@@ -6,12 +6,14 @@
#define CC_OUTPUT_VIEWPORT_SELECTION_BOUND_H_
#include "cc/base/cc_export.h"
+#include "cc/input/selection.h"
#include "cc/input/selection_bound_type.h"
#include "ui/gfx/geometry/point_f.h"
namespace cc {
// Marker for a selection end-point in (DIP) viewport coordinates.
+// TODO(jdduke): Move this to ui/gfx and merge with ui::SelectionBound.
struct CC_EXPORT ViewportSelectionBound {
ViewportSelectionBound();
~ViewportSelectionBound();
@@ -27,6 +29,8 @@ CC_EXPORT bool operator==(const ViewportSelectionBound& lhs,
CC_EXPORT bool operator!=(const ViewportSelectionBound& lhs,
const ViewportSelectionBound& rhs);
+typedef Selection<ViewportSelectionBound> ViewportSelection;
+
} // namespace cc
#endif // CC_OUTPUT_VIEWPORT_SELECTION_BOUND_H_
diff --git a/chromium/cc/playback/clip_display_item.cc b/chromium/cc/playback/clip_display_item.cc
new file mode 100644
index 00000000000..a29787409c3
--- /dev/null
+++ b/chromium/cc/playback/clip_display_item.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 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/playback/clip_display_item.h"
+
+#include <string>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+ClipDisplayItem::ClipDisplayItem() {
+}
+
+ClipDisplayItem::~ClipDisplayItem() {
+}
+
+void ClipDisplayItem::SetNew(gfx::Rect clip_rect,
+ const std::vector<SkRRect>& rounded_clip_rects) {
+ clip_rect_ = clip_rect;
+ rounded_clip_rects_ = rounded_clip_rects;
+
+ size_t memory_usage = sizeof(gfx::Rect);
+ for (size_t i = 0; i < rounded_clip_rects_.size(); ++i) {
+ memory_usage += sizeof(rounded_clip_rects_[i]);
+ }
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 1 /* op_count */,
+ memory_usage);
+}
+
+void ClipDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->save();
+ canvas->clipRect(SkRect::MakeXYWH(clip_rect_.x(), clip_rect_.y(),
+ clip_rect_.width(), clip_rect_.height()));
+ for (size_t i = 0; i < rounded_clip_rects_.size(); ++i) {
+ if (rounded_clip_rects_[i].isRect()) {
+ canvas->clipRect(rounded_clip_rects_[i].rect());
+ } else {
+ bool antialiased = true;
+ canvas->clipRRect(rounded_clip_rects_[i], SkRegion::kIntersect_Op,
+ antialiased);
+ }
+ }
+}
+
+void ClipDisplayItem::AsValueInto(base::trace_event::TracedValue* array) const {
+ std::string value = base::StringPrintf("ClipDisplayItem rect: [%s]",
+ clip_rect_.ToString().c_str());
+ for (const SkRRect& rounded_rect : rounded_clip_rects_) {
+ base::StringAppendF(
+ &value, " rounded_rect: [rect: [%s]",
+ gfx::SkRectToRectF(rounded_rect.rect()).ToString().c_str());
+ base::StringAppendF(&value, " radii: [");
+ SkVector upper_left_radius = rounded_rect.radii(SkRRect::kUpperLeft_Corner);
+ base::StringAppendF(&value, "[%f,%f],", upper_left_radius.x(),
+ upper_left_radius.y());
+ SkVector upper_right_radius =
+ rounded_rect.radii(SkRRect::kUpperRight_Corner);
+ base::StringAppendF(&value, " [%f,%f],", upper_right_radius.x(),
+ upper_right_radius.y());
+ SkVector lower_right_radius =
+ rounded_rect.radii(SkRRect::kLowerRight_Corner);
+ base::StringAppendF(&value, " [%f,%f],", lower_right_radius.x(),
+ lower_right_radius.y());
+ SkVector lower_left_radius = rounded_rect.radii(SkRRect::kLowerLeft_Corner);
+ base::StringAppendF(&value, " [%f,%f]]", lower_left_radius.x(),
+ lower_left_radius.y());
+ }
+ array->AppendString(value);
+}
+
+EndClipDisplayItem::EndClipDisplayItem() {
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 0 /* op_count */,
+ 0 /* memory_usage */);
+}
+
+EndClipDisplayItem::~EndClipDisplayItem() {
+}
+
+void EndClipDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+}
+
+void EndClipDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString("EndClipDisplayItem");
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/clip_display_item.h b/chromium/cc/playback/clip_display_item.h
new file mode 100644
index 00000000000..a4acc9f9893
--- /dev/null
+++ b/chromium/cc/playback/clip_display_item.h
@@ -0,0 +1,48 @@
+// Copyright 2014 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_PLAYBACK_CLIP_DISPLAY_ITEM_H_
+#define CC_PLAYBACK_CLIP_DISPLAY_ITEM_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/playback/display_item.h"
+#include "third_party/skia/include/core/SkRRect.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT ClipDisplayItem : public DisplayItem {
+ public:
+ ClipDisplayItem();
+ ~ClipDisplayItem() override;
+
+ void SetNew(gfx::Rect clip_rect,
+ const std::vector<SkRRect>& rounded_clip_rects);
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+
+ private:
+ gfx::Rect clip_rect_;
+ std::vector<SkRRect> rounded_clip_rects_;
+};
+
+class CC_EXPORT EndClipDisplayItem : public DisplayItem {
+ public:
+ EndClipDisplayItem();
+ ~EndClipDisplayItem() override;
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_CLIP_DISPLAY_ITEM_H_
diff --git a/chromium/cc/playback/clip_path_display_item.cc b/chromium/cc/playback/clip_path_display_item.cc
new file mode 100644
index 00000000000..7be8922fca7
--- /dev/null
+++ b/chromium/cc/playback/clip_path_display_item.cc
@@ -0,0 +1,61 @@
+// 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.
+
+#include "cc/playback/clip_path_display_item.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace cc {
+
+ClipPathDisplayItem::ClipPathDisplayItem() {
+}
+
+ClipPathDisplayItem::~ClipPathDisplayItem() {
+}
+
+void ClipPathDisplayItem::SetNew(const SkPath& clip_path,
+ SkRegion::Op clip_op,
+ bool antialias) {
+ clip_path_ = clip_path;
+ clip_op_ = clip_op;
+ antialias_ = antialias;
+
+ size_t memory_usage = sizeof(SkPath) + sizeof(SkRegion::Op) + sizeof(bool);
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 1 /* op_count */,
+ memory_usage);
+}
+
+void ClipPathDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->save();
+ canvas->clipPath(clip_path_, clip_op_, antialias_);
+}
+
+void ClipPathDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString(base::StringPrintf("ClipPathDisplayItem length: %d",
+ clip_path_.countPoints()));
+}
+
+EndClipPathDisplayItem::EndClipPathDisplayItem() {
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 0 /* op_count */,
+ 0 /* memory_usage */);
+}
+
+EndClipPathDisplayItem::~EndClipPathDisplayItem() {
+}
+
+void EndClipPathDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+}
+
+void EndClipPathDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString("EndClipPathDisplayItem");
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/clip_path_display_item.h b/chromium/cc/playback/clip_path_display_item.h
new file mode 100644
index 00000000000..19d4a7ced39
--- /dev/null
+++ b/chromium/cc/playback/clip_path_display_item.h
@@ -0,0 +1,50 @@
+// 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_PLAYBACK_CLIP_PATH_DISPLAY_ITEM_H_
+#define CC_PLAYBACK_CLIP_PATH_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/playback/display_item.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRegion.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT ClipPathDisplayItem : public DisplayItem {
+ public:
+ ClipPathDisplayItem();
+ ~ClipPathDisplayItem() override;
+
+ void SetNew(const SkPath& path, SkRegion::Op clip_op, bool antialias);
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+
+ private:
+ SkPath clip_path_;
+ SkRegion::Op clip_op_;
+ bool antialias_;
+};
+
+class CC_EXPORT EndClipPathDisplayItem : public DisplayItem {
+ public:
+ EndClipPathDisplayItem();
+ ~EndClipPathDisplayItem() override;
+
+ static scoped_ptr<EndClipPathDisplayItem> Create() {
+ return make_scoped_ptr(new EndClipPathDisplayItem());
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_CLIP_PATH_DISPLAY_ITEM_H_
diff --git a/chromium/cc/playback/compositing_display_item.cc b/chromium/cc/playback/compositing_display_item.cc
new file mode 100644
index 00000000000..bee1fb15dcb
--- /dev/null
+++ b/chromium/cc/playback/compositing_display_item.cc
@@ -0,0 +1,78 @@
+// 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.
+
+#include "cc/playback/compositing_display_item.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+CompositingDisplayItem::CompositingDisplayItem() {
+}
+
+CompositingDisplayItem::~CompositingDisplayItem() {
+}
+
+void CompositingDisplayItem::SetNew(uint8_t alpha,
+ SkXfermode::Mode xfermode,
+ SkRect* bounds,
+ skia::RefPtr<SkColorFilter> cf) {
+ alpha_ = alpha;
+ xfermode_ = xfermode;
+ has_bounds_ = !!bounds;
+ if (bounds)
+ bounds_ = SkRect(*bounds);
+ color_filter_ = cf;
+
+ // TODO(pdr): Include color_filter's memory here.
+ size_t memory_usage =
+ sizeof(float) + sizeof(bool) + sizeof(SkRect) + sizeof(SkXfermode::Mode);
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 1 /* op_count */,
+ memory_usage);
+}
+
+void CompositingDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ SkPaint paint;
+ paint.setXfermodeMode(xfermode_);
+ paint.setAlpha(alpha_);
+ paint.setColorFilter(color_filter_.get());
+ canvas->saveLayer(has_bounds_ ? &bounds_ : nullptr, &paint);
+}
+
+void CompositingDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString(base::StringPrintf(
+ "CompositingDisplayItem alpha: %d, xfermode: %d", alpha_, xfermode_));
+ if (has_bounds_)
+ array->AppendString(base::StringPrintf(
+ ", bounds: [%f, %f, %f, %f]", static_cast<float>(bounds_.x()),
+ static_cast<float>(bounds_.y()), static_cast<float>(bounds_.width()),
+ static_cast<float>(bounds_.height())));
+}
+
+EndCompositingDisplayItem::EndCompositingDisplayItem() {
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 0 /* op_count */,
+ 0 /* memory_usage */);
+}
+
+EndCompositingDisplayItem::~EndCompositingDisplayItem() {
+}
+
+void EndCompositingDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+}
+
+void EndCompositingDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString("EndCompositingDisplayItem");
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/compositing_display_item.h b/chromium/cc/playback/compositing_display_item.h
new file mode 100644
index 00000000000..d2af8d5ceb7
--- /dev/null
+++ b/chromium/cc/playback/compositing_display_item.h
@@ -0,0 +1,58 @@
+// 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_PLAYBACK_COMPOSITING_DISPLAY_ITEM_H_
+#define CC_PLAYBACK_COMPOSITING_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/playback/display_item.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT CompositingDisplayItem : public DisplayItem {
+ public:
+ CompositingDisplayItem();
+ ~CompositingDisplayItem() override;
+
+ void SetNew(uint8_t alpha,
+ SkXfermode::Mode xfermode,
+ SkRect* bounds,
+ skia::RefPtr<SkColorFilter> color_filter);
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+
+ private:
+ uint8_t alpha_;
+ SkXfermode::Mode xfermode_;
+ bool has_bounds_;
+ SkRect bounds_;
+ skia::RefPtr<SkColorFilter> color_filter_;
+};
+
+class CC_EXPORT EndCompositingDisplayItem : public DisplayItem {
+ public:
+ EndCompositingDisplayItem();
+ ~EndCompositingDisplayItem() override;
+
+ static scoped_ptr<EndCompositingDisplayItem> Create() {
+ return make_scoped_ptr(new EndCompositingDisplayItem());
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_COMPOSITING_DISPLAY_ITEM_H_
diff --git a/chromium/cc/playback/display_item.cc b/chromium/cc/playback/display_item.cc
new file mode 100644
index 00000000000..cbfee030477
--- /dev/null
+++ b/chromium/cc/playback/display_item.cc
@@ -0,0 +1,12 @@
+// Copyright 2014 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/playback/display_item.h"
+
+namespace cc {
+
+DisplayItem::DisplayItem() {
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/display_item.h b/chromium/cc/playback/display_item.h
new file mode 100644
index 00000000000..2eedb91b5f3
--- /dev/null
+++ b/chromium/cc/playback/display_item.h
@@ -0,0 +1,51 @@
+// Copyright 2014 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_PLAYBACK_DISPLAY_ITEM_H_
+#define CC_PLAYBACK_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/debug/traced_value.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT DisplayItem {
+ public:
+ virtual ~DisplayItem() {}
+
+ void SetNew(bool is_suitable_for_gpu_rasterization,
+ int approximate_op_count,
+ size_t picture_memory_usage) {
+ is_suitable_for_gpu_rasterization_ = is_suitable_for_gpu_rasterization;
+ approximate_op_count_ = approximate_op_count;
+ picture_memory_usage_ =
+ picture_memory_usage + sizeof(bool) + sizeof(int) + sizeof(size_t);
+ }
+
+ virtual void Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const = 0;
+ virtual void AsValueInto(base::trace_event::TracedValue* array) const = 0;
+
+ bool is_suitable_for_gpu_rasterization() const {
+ return is_suitable_for_gpu_rasterization_;
+ }
+ int approximate_op_count() const { return approximate_op_count_; }
+ size_t picture_memory_usage() const { return picture_memory_usage_; }
+
+ protected:
+ DisplayItem();
+
+ bool is_suitable_for_gpu_rasterization_;
+ int approximate_op_count_;
+ size_t picture_memory_usage_;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_DISPLAY_ITEM_H_
diff --git a/chromium/cc/playback/display_item_list.cc b/chromium/cc/playback/display_item_list.cc
new file mode 100644
index 00000000000..656ade1deff
--- /dev/null
+++ b/chromium/cc/playback/display_item_list.cc
@@ -0,0 +1,229 @@
+// Copyright 2014 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/playback/display_item_list.h"
+
+#include <string>
+
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/base/math_util.h"
+#include "cc/debug/picture_debug_util.h"
+#include "cc/debug/traced_picture.h"
+#include "cc/debug/traced_value.h"
+#include "cc/playback/largest_display_item.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkDrawPictureCallback.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+namespace {
+
+bool PictureTracingEnabled() {
+ bool tracing_enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") ","
+ TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"),
+ &tracing_enabled);
+ return tracing_enabled;
+}
+
+const int kDefaultNumDisplayItemsToReserve = 100;
+
+} // namespace
+
+DisplayItemList::DisplayItemList(gfx::Rect layer_rect,
+ bool use_cached_picture,
+ bool retain_individual_display_items)
+ : items_(LargestDisplayItemSize(), kDefaultNumDisplayItemsToReserve),
+ use_cached_picture_(use_cached_picture),
+ retain_individual_display_items_(retain_individual_display_items),
+ layer_rect_(layer_rect),
+ is_suitable_for_gpu_rasterization_(true),
+ approximate_op_count_(0),
+ picture_memory_usage_(0) {
+#if DCHECK_IS_ON()
+ needs_process_ = false;
+#endif
+ if (use_cached_picture_) {
+ SkRTreeFactory factory;
+ recorder_.reset(new SkPictureRecorder());
+ canvas_ = skia::SharePtr(recorder_->beginRecording(
+ layer_rect_.width(), layer_rect_.height(), &factory));
+ canvas_->translate(-layer_rect_.x(), -layer_rect_.y());
+ canvas_->clipRect(gfx::RectToSkRect(layer_rect_));
+ }
+}
+
+DisplayItemList::DisplayItemList(gfx::Rect layer_rect, bool use_cached_picture)
+ : DisplayItemList(layer_rect,
+ use_cached_picture,
+ !use_cached_picture || PictureTracingEnabled()) {
+}
+
+scoped_refptr<DisplayItemList> DisplayItemList::Create(
+ gfx::Rect layer_rect,
+ bool use_cached_picture) {
+ return make_scoped_refptr(
+ new DisplayItemList(layer_rect, use_cached_picture));
+}
+
+DisplayItemList::~DisplayItemList() {
+}
+
+void DisplayItemList::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ float contents_scale) const {
+ DCHECK(ProcessAppendedItemsCalled());
+ if (!use_cached_picture_) {
+ canvas->save();
+ canvas->scale(contents_scale, contents_scale);
+ for (auto* item : items_)
+ item->Raster(canvas, callback);
+ canvas->restore();
+ } else {
+ DCHECK(picture_);
+
+ canvas->save();
+ canvas->scale(contents_scale, contents_scale);
+ canvas->translate(layer_rect_.x(), layer_rect_.y());
+ if (callback) {
+ // If we have a callback, we need to call |draw()|, |drawPicture()|
+ // doesn't take a callback. This is used by |AnalysisCanvas| to early
+ // out.
+ picture_->playback(canvas, callback);
+ } else {
+ // Prefer to call |drawPicture()| on the canvas since it could place the
+ // entire picture on the canvas instead of parsing the skia operations.
+ canvas->drawPicture(picture_.get());
+ }
+ canvas->restore();
+ }
+}
+
+void DisplayItemList::ProcessAppendedItemsOnTheFly() {
+ if (retain_individual_display_items_)
+ return;
+ if (items_.size() >= kDefaultNumDisplayItemsToReserve) {
+ ProcessAppendedItems();
+ // This function exists to keep the |items_| from growing indefinitely if
+ // we're not going to store them anyway. So the items better be deleted
+ // after |items_| grows too large and we process it.
+ DCHECK(items_.empty());
+ }
+}
+
+void DisplayItemList::ProcessAppendedItems() {
+#if DCHECK_IS_ON()
+ needs_process_ = false;
+#endif
+ for (DisplayItem* item : items_) {
+ is_suitable_for_gpu_rasterization_ &=
+ item->is_suitable_for_gpu_rasterization();
+ approximate_op_count_ += item->approximate_op_count();
+
+ if (use_cached_picture_) {
+ DCHECK(canvas_);
+ item->Raster(canvas_.get(), NULL);
+ }
+
+ if (retain_individual_display_items_) {
+ // Warning: this double-counts SkPicture data if use_cached_picture_ is
+ // also true.
+ picture_memory_usage_ += item->picture_memory_usage();
+ }
+ }
+
+ if (!retain_individual_display_items_)
+ items_.clear();
+}
+
+void DisplayItemList::CreateAndCacheSkPicture() {
+ DCHECK(ProcessAppendedItemsCalled());
+ // Convert to an SkPicture for faster rasterization.
+ DCHECK(use_cached_picture_);
+ DCHECK(!picture_);
+ picture_ = skia::AdoptRef(recorder_->endRecordingAsPicture());
+ DCHECK(picture_);
+ picture_memory_usage_ += SkPictureUtils::ApproximateBytesUsed(picture_.get());
+ recorder_.reset();
+ canvas_.clear();
+}
+
+bool DisplayItemList::IsSuitableForGpuRasterization() const {
+ DCHECK(ProcessAppendedItemsCalled());
+ // This is more permissive than Picture's implementation, since none of the
+ // items might individually trigger a veto even though they collectively have
+ // enough "bad" operations that a corresponding Picture would get vetoed.
+ return is_suitable_for_gpu_rasterization_;
+}
+
+int DisplayItemList::ApproximateOpCount() const {
+ DCHECK(ProcessAppendedItemsCalled());
+ return approximate_op_count_;
+}
+
+size_t DisplayItemList::PictureMemoryUsage() const {
+ DCHECK(ProcessAppendedItemsCalled());
+ // We double-count in this case. Produce zero to avoid being misleading.
+ if (use_cached_picture_ && retain_individual_display_items_)
+ return 0;
+
+ DCHECK_IMPLIES(use_cached_picture_, picture_);
+ return picture_memory_usage_;
+}
+
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+DisplayItemList::AsValue() const {
+ DCHECK(ProcessAppendedItemsCalled());
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
+
+ state->SetInteger("length", items_.size());
+ state->BeginArray("params.items");
+ for (const DisplayItem* item : items_) {
+ item->AsValueInto(state.get());
+ }
+ state->EndArray();
+ state->SetValue("params.layer_rect", MathUtil::AsValue(layer_rect_));
+
+ SkPictureRecorder recorder;
+ SkCanvas* canvas =
+ recorder.beginRecording(layer_rect_.width(), layer_rect_.height());
+ canvas->translate(-layer_rect_.x(), -layer_rect_.y());
+ canvas->clipRect(gfx::RectToSkRect(layer_rect_));
+ Raster(canvas, NULL, 1.f);
+ skia::RefPtr<SkPicture> picture =
+ skia::AdoptRef(recorder.endRecordingAsPicture());
+
+ std::string b64_picture;
+ PictureDebugUtil::SerializeAsBase64(picture.get(), &b64_picture);
+ state->SetString("skp64", b64_picture);
+
+ return state;
+}
+
+void DisplayItemList::EmitTraceSnapshot() const {
+ DCHECK(ProcessAppendedItemsCalled());
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") ","
+ TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"),
+ "cc::DisplayItemList", this, AsValue());
+}
+
+void DisplayItemList::GatherPixelRefs(const gfx::Size& grid_cell_size) {
+ DCHECK(ProcessAppendedItemsCalled());
+ // This should be only called once, and only after CreateAndCacheSkPicture.
+ DCHECK(picture_);
+ DCHECK(!pixel_refs_);
+ pixel_refs_ = make_scoped_ptr(new PixelRefMap(grid_cell_size));
+ if (!picture_->willPlayBackBitmaps())
+ return;
+
+ pixel_refs_->GatherPixelRefsFromPicture(picture_.get());
+}
+} // namespace cc
diff --git a/chromium/cc/playback/display_item_list.h b/chromium/cc/playback/display_item_list.h
new file mode 100644
index 00000000000..84b41683720
--- /dev/null
+++ b/chromium/cc/playback/display_item_list.h
@@ -0,0 +1,100 @@
+// Copyright 2014 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_PLAYBACK_DISPLAY_ITEM_LIST_H_
+#define CC_PLAYBACK_DISPLAY_ITEM_LIST_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/base/cc_export.h"
+#include "cc/base/scoped_ptr_vector.h"
+#include "cc/playback/display_item.h"
+#include "cc/playback/pixel_ref_map.h"
+// TODO(danakj): Move ListContainer out of cc/quads/
+#include "cc/quads/list_container.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+class SkPictureRecorder;
+
+namespace cc {
+
+class CC_EXPORT DisplayItemList
+ : public base::RefCountedThreadSafe<DisplayItemList> {
+ public:
+ static scoped_refptr<DisplayItemList> Create(gfx::Rect layer_rect,
+ bool use_cached_picture);
+
+ void Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ float contents_scale) const;
+
+ template <typename DisplayItemType>
+ DisplayItemType* CreateAndAppendItem() {
+#if DCHECK_IS_ON()
+ needs_process_ = true;
+#endif
+ ProcessAppendedItemsOnTheFly();
+ return items_.AllocateAndConstruct<DisplayItemType>();
+ }
+
+ void ProcessAppendedItems();
+ void CreateAndCacheSkPicture();
+
+ bool IsSuitableForGpuRasterization() const;
+ int ApproximateOpCount() const;
+ size_t PictureMemoryUsage() const;
+
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+
+ void EmitTraceSnapshot() const;
+
+ void GatherPixelRefs(const gfx::Size& grid_cell_size);
+
+ private:
+ DisplayItemList(gfx::Rect layer_rect,
+ bool use_cached_picture,
+ bool retain_individual_display_items);
+ DisplayItemList(gfx::Rect layer_rect, bool use_cached_picture);
+ ~DisplayItemList();
+
+ // While appending new items, if they are not being retained, this can process
+ // periodically to avoid retaining all the items and processing at the end.
+ void ProcessAppendedItemsOnTheFly();
+#if DCHECK_IS_ON()
+ bool ProcessAppendedItemsCalled() const { return !needs_process_; }
+ bool needs_process_;
+#else
+ bool ProcessAppendedItemsCalled() const { return true; }
+#endif
+
+ ListContainer<DisplayItem> items_;
+ skia::RefPtr<SkPicture> picture_;
+
+ scoped_ptr<SkPictureRecorder> recorder_;
+ skia::RefPtr<SkCanvas> canvas_;
+ bool use_cached_picture_;
+ bool retain_individual_display_items_;
+
+ gfx::Rect layer_rect_;
+ bool is_suitable_for_gpu_rasterization_;
+ int approximate_op_count_;
+ size_t picture_memory_usage_;
+
+ scoped_ptr<PixelRefMap> pixel_refs_;
+
+ friend class base::RefCountedThreadSafe<DisplayItemList>;
+ friend class PixelRefMap::Iterator;
+ FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, PictureMemoryUsage);
+ DISALLOW_COPY_AND_ASSIGN(DisplayItemList);
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_DISPLAY_ITEM_LIST_H_
diff --git a/chromium/cc/playback/display_item_list_unittest.cc b/chromium/cc/playback/display_item_list_unittest.cc
new file mode 100644
index 00000000000..6a5bbf61ae8
--- /dev/null
+++ b/chromium/cc/playback/display_item_list_unittest.cc
@@ -0,0 +1,340 @@
+// Copyright 2014 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/playback/display_item_list.h"
+
+#include <vector>
+
+#include "cc/output/filter_operation.h"
+#include "cc/output/filter_operations.h"
+#include "cc/playback/clip_display_item.h"
+#include "cc/playback/drawing_display_item.h"
+#include "cc/playback/filter_display_item.h"
+#include "cc/playback/transform_display_item.h"
+#include "cc/test/skia_common.h"
+#include "skia/ext/refptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "third_party/skia/include/effects/SkBitmapSource.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+TEST(DisplayItemListTest, SingleDrawingItem) {
+ gfx::Rect layer_rect(100, 100);
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas;
+ skia::RefPtr<SkPicture> picture;
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ SkPaint red_paint;
+ red_paint.setColor(SK_ColorRED);
+ unsigned char pixels[4 * 100 * 100] = {0};
+ const bool use_cached_picture = true;
+ scoped_refptr<DisplayItemList> list =
+ DisplayItemList::Create(layer_rect, use_cached_picture);
+
+ gfx::PointF offset(8.f, 9.f);
+ gfx::RectF recording_rect(offset, layer_rect.size());
+ canvas = skia::SharePtr(
+ recorder.beginRecording(gfx::RectFToSkRect(recording_rect)));
+ canvas->translate(offset.x(), offset.y());
+ canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+ canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+ picture = skia::AdoptRef(recorder.endRecordingAsPicture());
+ auto* item = list->CreateAndAppendItem<DrawingDisplayItem>();
+ item->SetNew(picture);
+ list->ProcessAppendedItems();
+ list->CreateAndCacheSkPicture();
+ DrawDisplayList(pixels, layer_rect, list);
+
+ SkBitmap expected_bitmap;
+ unsigned char expected_pixels[4 * 100 * 100] = {0};
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+ SkCanvas expected_canvas(expected_bitmap);
+ expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
+ expected_canvas.drawRectCoords(0.f + offset.x(), 0.f + offset.y(),
+ 60.f + offset.x(), 60.f + offset.y(),
+ red_paint);
+ expected_canvas.drawRectCoords(50.f + offset.x(), 50.f + offset.y(),
+ 75.f + offset.x(), 75.f + offset.y(),
+ blue_paint);
+
+ EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+TEST(DisplayItemListTest, ClipItem) {
+ gfx::Rect layer_rect(100, 100);
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas;
+ skia::RefPtr<SkPicture> picture;
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ SkPaint red_paint;
+ red_paint.setColor(SK_ColorRED);
+ unsigned char pixels[4 * 100 * 100] = {0};
+ const bool use_cached_picture = true;
+ scoped_refptr<DisplayItemList> list =
+ DisplayItemList::Create(layer_rect, use_cached_picture);
+
+ gfx::PointF first_offset(8.f, 9.f);
+ gfx::RectF first_recording_rect(first_offset, layer_rect.size());
+ canvas = skia::SharePtr(
+ recorder.beginRecording(gfx::RectFToSkRect(first_recording_rect)));
+ canvas->translate(first_offset.x(), first_offset.y());
+ canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+ picture = skia::AdoptRef(recorder.endRecordingAsPicture());
+ auto* item1 = list->CreateAndAppendItem<DrawingDisplayItem>();
+ item1->SetNew(picture.Pass());
+
+ gfx::Rect clip_rect(60, 60, 10, 10);
+ auto* item2 = list->CreateAndAppendItem<ClipDisplayItem>();
+ item2->SetNew(clip_rect, std::vector<SkRRect>());
+
+ gfx::PointF second_offset(2.f, 3.f);
+ gfx::RectF second_recording_rect(second_offset, layer_rect.size());
+ canvas = skia::SharePtr(
+ recorder.beginRecording(gfx::RectFToSkRect(second_recording_rect)));
+ canvas->translate(second_offset.x(), second_offset.y());
+ canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+ picture = skia::AdoptRef(recorder.endRecordingAsPicture());
+ auto* item3 = list->CreateAndAppendItem<DrawingDisplayItem>();
+ item3->SetNew(picture.Pass());
+
+ list->CreateAndAppendItem<EndClipDisplayItem>();
+ list->ProcessAppendedItems();
+ list->CreateAndCacheSkPicture();
+
+ DrawDisplayList(pixels, layer_rect, list);
+
+ SkBitmap expected_bitmap;
+ unsigned char expected_pixels[4 * 100 * 100] = {0};
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+ SkCanvas expected_canvas(expected_bitmap);
+ expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
+ expected_canvas.drawRectCoords(0.f + first_offset.x(), 0.f + first_offset.y(),
+ 60.f + first_offset.x(),
+ 60.f + first_offset.y(), red_paint);
+ expected_canvas.clipRect(gfx::RectToSkRect(clip_rect));
+ expected_canvas.drawRectCoords(
+ 50.f + second_offset.x(), 50.f + second_offset.y(),
+ 75.f + second_offset.x(), 75.f + second_offset.y(), blue_paint);
+
+ EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+TEST(DisplayItemListTest, TransformItem) {
+ gfx::Rect layer_rect(100, 100);
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas;
+ skia::RefPtr<SkPicture> picture;
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ SkPaint red_paint;
+ red_paint.setColor(SK_ColorRED);
+ unsigned char pixels[4 * 100 * 100] = {0};
+ const bool use_cached_picture = true;
+ scoped_refptr<DisplayItemList> list =
+ DisplayItemList::Create(layer_rect, use_cached_picture);
+
+ gfx::PointF first_offset(8.f, 9.f);
+ gfx::RectF first_recording_rect(first_offset, layer_rect.size());
+ canvas = skia::SharePtr(
+ recorder.beginRecording(gfx::RectFToSkRect(first_recording_rect)));
+ canvas->translate(first_offset.x(), first_offset.y());
+ canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+ picture = skia::AdoptRef(recorder.endRecordingAsPicture());
+ auto* item1 = list->CreateAndAppendItem<DrawingDisplayItem>();
+ item1->SetNew(picture);
+
+ gfx::Transform transform;
+ transform.Rotate(45.0);
+ auto* item2 = list->CreateAndAppendItem<TransformDisplayItem>();
+ item2->SetNew(transform);
+
+ gfx::PointF second_offset(2.f, 3.f);
+ gfx::RectF second_recording_rect(second_offset, layer_rect.size());
+ canvas = skia::SharePtr(
+ recorder.beginRecording(gfx::RectFToSkRect(second_recording_rect)));
+ canvas->translate(second_offset.x(), second_offset.y());
+ canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+ picture = skia::AdoptRef(recorder.endRecordingAsPicture());
+ auto* item3 = list->CreateAndAppendItem<DrawingDisplayItem>();
+ item3->SetNew(picture);
+
+ list->CreateAndAppendItem<EndTransformDisplayItem>();
+ list->ProcessAppendedItems();
+ list->CreateAndCacheSkPicture();
+
+ DrawDisplayList(pixels, layer_rect, list);
+
+ SkBitmap expected_bitmap;
+ unsigned char expected_pixels[4 * 100 * 100] = {0};
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+ SkCanvas expected_canvas(expected_bitmap);
+ expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
+ expected_canvas.drawRectCoords(0.f + first_offset.x(), 0.f + first_offset.y(),
+ 60.f + first_offset.x(),
+ 60.f + first_offset.y(), red_paint);
+ expected_canvas.setMatrix(transform.matrix());
+ expected_canvas.drawRectCoords(
+ 50.f + second_offset.x(), 50.f + second_offset.y(),
+ 75.f + second_offset.x(), 75.f + second_offset.y(), blue_paint);
+
+ EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+TEST(DisplayItemListTest, FilterItem) {
+ gfx::Rect layer_rect(100, 100);
+ FilterOperations filters;
+ unsigned char pixels[4 * 100 * 100] = {0};
+ const bool use_cached_picture = true;
+ scoped_refptr<DisplayItemList> list =
+ DisplayItemList::Create(layer_rect, use_cached_picture);
+
+ SkBitmap source_bitmap;
+ source_bitmap.allocN32Pixels(50, 50);
+ SkCanvas source_canvas(source_bitmap);
+ source_canvas.clear(SkColorSetRGB(128, 128, 128));
+
+ // For most SkImageFilters, the |dst| bounds computed by computeFastBounds are
+ // dependent on the provided |src| bounds. This means, for example, that
+ // translating |src| results in a corresponding translation of |dst|. But this
+ // is not the case for all SkImageFilters; for some of them (e.g.
+ // SkBitmapSource), the computation of |dst| in computeFastBounds doesn't
+ // involve |src| at all. Incorrectly assuming such a relationship (e.g. by
+ // translating |dst| after it is computed by computeFastBounds, rather than
+ // translating |src| before it provided to computedFastBounds) can cause
+ // incorrect clipping of filter output. To test for this, we include an
+ // SkBitmapSource filter in |filters|. Here, |src| is |filter_bounds|, defined
+ // below.
+ skia::RefPtr<SkImageFilter> image_filter =
+ skia::AdoptRef(SkBitmapSource::Create(source_bitmap));
+ filters.Append(FilterOperation::CreateReferenceFilter(image_filter));
+ filters.Append(FilterOperation::CreateBrightnessFilter(0.5f));
+ gfx::RectF filter_bounds(10.f, 10.f, 50.f, 50.f);
+ auto* item = list->CreateAndAppendItem<FilterDisplayItem>();
+ item->SetNew(filters, filter_bounds);
+ list->CreateAndAppendItem<EndFilterDisplayItem>();
+ list->ProcessAppendedItems();
+ list->CreateAndCacheSkPicture();
+
+ DrawDisplayList(pixels, layer_rect, list);
+
+ SkBitmap expected_bitmap;
+ unsigned char expected_pixels[4 * 100 * 100] = {0};
+ SkPaint paint;
+ paint.setColor(SkColorSetRGB(64, 64, 64));
+ SkImageInfo info =
+ SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+ expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+ SkCanvas expected_canvas(expected_bitmap);
+ expected_canvas.drawRect(RectFToSkRect(filter_bounds), paint);
+
+ EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+TEST(DisplayItemListTest, CompactingItems) {
+ gfx::Rect layer_rect(100, 100);
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas;
+ skia::RefPtr<SkPicture> picture;
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ SkPaint red_paint;
+ red_paint.setColor(SK_ColorRED);
+ unsigned char pixels[4 * 100 * 100] = {0};
+
+ gfx::PointF offset(8.f, 9.f);
+ gfx::RectF recording_rect(offset, layer_rect.size());
+
+ bool use_cached_picture = false;
+ scoped_refptr<DisplayItemList> list_without_caching =
+ DisplayItemList::Create(layer_rect, use_cached_picture);
+
+ canvas = skia::SharePtr(
+ recorder.beginRecording(gfx::RectFToSkRect(recording_rect)));
+ canvas->translate(offset.x(), offset.y());
+ canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+ canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+ picture = skia::AdoptRef(recorder.endRecordingAsPicture());
+ auto* item1 = list_without_caching->CreateAndAppendItem<DrawingDisplayItem>();
+ item1->SetNew(picture);
+ list_without_caching->ProcessAppendedItems();
+ DrawDisplayList(pixels, layer_rect, list_without_caching);
+
+ unsigned char expected_pixels[4 * 100 * 100] = {0};
+ use_cached_picture = true;
+ scoped_refptr<DisplayItemList> list_with_caching =
+ DisplayItemList::Create(layer_rect, use_cached_picture);
+ auto* item2 = list_with_caching->CreateAndAppendItem<DrawingDisplayItem>();
+ item2->SetNew(picture);
+ list_with_caching->ProcessAppendedItems();
+ list_with_caching->CreateAndCacheSkPicture();
+ DrawDisplayList(expected_pixels, layer_rect, list_with_caching);
+
+ EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+TEST(DisplayItemListTest, PictureMemoryUsage) {
+ scoped_refptr<DisplayItemList> list;
+ size_t memory_usage;
+
+ // Make an SkPicture whose size is known.
+ gfx::Rect layer_rect(100, 100);
+ SkPictureRecorder recorder;
+ SkPaint blue_paint;
+ blue_paint.setColor(SK_ColorBLUE);
+ SkCanvas* canvas = recorder.beginRecording(gfx::RectFToSkRect(layer_rect));
+ for (int i = 0; i < 100; i++)
+ canvas->drawPaint(blue_paint);
+ skia::RefPtr<SkPicture> picture =
+ skia::AdoptRef(recorder.endRecordingAsPicture());
+ size_t picture_size = SkPictureUtils::ApproximateBytesUsed(picture.get());
+ ASSERT_GE(picture_size, 100 * sizeof(SkPaint));
+ ASSERT_LE(picture_size, 200 * sizeof(SkPaint));
+
+ // Using a cached picture, we should get about the right size.
+ list = DisplayItemList::Create(layer_rect, true);
+ auto* item = list->CreateAndAppendItem<DrawingDisplayItem>();
+ item->SetNew(picture);
+ list->ProcessAppendedItems();
+ list->CreateAndCacheSkPicture();
+ memory_usage = list->PictureMemoryUsage();
+ EXPECT_GE(memory_usage, picture_size);
+ EXPECT_LE(memory_usage, 2 * picture_size);
+
+ // Using no cached picture, we should still get the right size.
+ list = DisplayItemList::Create(layer_rect, false);
+ item = list->CreateAndAppendItem<DrawingDisplayItem>();
+ item->SetNew(picture);
+ list->ProcessAppendedItems();
+ memory_usage = list->PictureMemoryUsage();
+ EXPECT_GE(memory_usage, picture_size);
+ EXPECT_LE(memory_usage, 2 * picture_size);
+
+ // To avoid double counting, we expect zero size to be computed if both the
+ // picture and items are retained (currently this only happens due to certain
+ // categories being traced).
+ list = new DisplayItemList(layer_rect, true, true);
+ item = list->CreateAndAppendItem<DrawingDisplayItem>();
+ item->SetNew(picture);
+ list->ProcessAppendedItems();
+ list->CreateAndCacheSkPicture();
+ memory_usage = list->PictureMemoryUsage();
+ EXPECT_EQ(static_cast<size_t>(0), memory_usage);
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/display_list_raster_source.cc b/chromium/cc/playback/display_list_raster_source.cc
new file mode 100644
index 00000000000..0dcd025f3c9
--- /dev/null
+++ b/chromium/cc/playback/display_list_raster_source.cc
@@ -0,0 +1,235 @@
+// Copyright 2014 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/playback/display_list_raster_source.h"
+
+#include "base/trace_event/trace_event.h"
+#include "cc/base/region.h"
+#include "cc/debug/debug_colors.h"
+#include "cc/playback/display_item_list.h"
+#include "cc/playback/raster_source_helper.h"
+#include "skia/ext/analysis_canvas.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+
+namespace {
+
+#ifdef NDEBUG
+const bool kDefaultClearCanvasSetting = false;
+#else
+const bool kDefaultClearCanvasSetting = true;
+#endif
+
+} // namespace
+
+namespace cc {
+
+scoped_refptr<DisplayListRasterSource>
+DisplayListRasterSource::CreateFromDisplayListRecordingSource(
+ const DisplayListRecordingSource* other,
+ bool can_use_lcd_text) {
+ return make_scoped_refptr(
+ new DisplayListRasterSource(other, can_use_lcd_text));
+}
+
+DisplayListRasterSource::DisplayListRasterSource()
+ : background_color_(SK_ColorTRANSPARENT),
+ requires_clear_(true),
+ can_use_lcd_text_(true),
+ is_solid_color_(false),
+ solid_color_(SK_ColorTRANSPARENT),
+ clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+ slow_down_raster_scale_factor_for_debug_(0),
+ should_attempt_to_use_distance_field_text_(false) {
+}
+
+DisplayListRasterSource::DisplayListRasterSource(
+ const DisplayListRecordingSource* other,
+ bool can_use_lcd_text)
+ : display_list_(other->display_list_),
+ background_color_(other->background_color_),
+ requires_clear_(other->requires_clear_),
+ can_use_lcd_text_(can_use_lcd_text),
+ is_solid_color_(other->is_solid_color_),
+ solid_color_(other->solid_color_),
+ recorded_viewport_(other->recorded_viewport_),
+ size_(other->size_),
+ clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+ slow_down_raster_scale_factor_for_debug_(
+ other->slow_down_raster_scale_factor_for_debug_),
+ should_attempt_to_use_distance_field_text_(false) {
+}
+
+DisplayListRasterSource::DisplayListRasterSource(
+ const DisplayListRasterSource* other,
+ bool can_use_lcd_text)
+ : display_list_(other->display_list_),
+ background_color_(other->background_color_),
+ requires_clear_(other->requires_clear_),
+ can_use_lcd_text_(can_use_lcd_text),
+ is_solid_color_(other->is_solid_color_),
+ solid_color_(other->solid_color_),
+ recorded_viewport_(other->recorded_viewport_),
+ size_(other->size_),
+ clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+ slow_down_raster_scale_factor_for_debug_(
+ other->slow_down_raster_scale_factor_for_debug_),
+ should_attempt_to_use_distance_field_text_(
+ other->should_attempt_to_use_distance_field_text_) {
+}
+
+DisplayListRasterSource::~DisplayListRasterSource() {
+}
+
+void DisplayListRasterSource::PlaybackToSharedCanvas(
+ SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale);
+}
+
+void DisplayListRasterSource::RasterForAnalysis(skia::AnalysisCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
+ RasterCommon(canvas, canvas, canvas_rect, contents_scale);
+}
+
+void DisplayListRasterSource::PlaybackToCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
+ RasterSourceHelper::PrepareForPlaybackToCanvas(
+ canvas, canvas_rect, gfx::Rect(size_), contents_scale, background_color_,
+ clear_canvas_with_debug_color_, requires_clear_);
+
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale);
+}
+
+void DisplayListRasterSource::RasterCommon(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
+ canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+ gfx::Rect content_rect =
+ gfx::ToEnclosingRect(gfx::ScaleRect(gfx::Rect(size_), contents_scale));
+ content_rect.Intersect(canvas_rect);
+
+ canvas->clipRect(gfx::RectToSkRect(content_rect), SkRegion::kIntersect_Op);
+
+ DCHECK(display_list_.get());
+ display_list_->Raster(canvas, callback, contents_scale);
+}
+
+skia::RefPtr<SkPicture> DisplayListRasterSource::GetFlattenedPicture() {
+ TRACE_EVENT0("cc", "DisplayListRasterSource::GetFlattenedPicture");
+
+ gfx::Rect display_list_rect(size_);
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(display_list_rect.width(),
+ display_list_rect.height());
+ if (!display_list_rect.IsEmpty())
+ PlaybackToCanvas(canvas, display_list_rect, 1.0);
+ skia::RefPtr<SkPicture> picture =
+ skia::AdoptRef(recorder.endRecordingAsPicture());
+
+ return picture;
+}
+
+size_t DisplayListRasterSource::GetPictureMemoryUsage() const {
+ if (!display_list_)
+ return 0;
+ return display_list_->PictureMemoryUsage();
+}
+
+void DisplayListRasterSource::PerformSolidColorAnalysis(
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ RasterSource::SolidColorAnalysis* analysis) const {
+ DCHECK(analysis);
+ TRACE_EVENT0("cc", "DisplayListRasterSource::PerformSolidColorAnalysis");
+
+ gfx::Rect layer_rect =
+ gfx::ScaleToEnclosingRect(content_rect, 1.0f / contents_scale);
+
+ layer_rect.Intersect(gfx::Rect(size_));
+ skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height());
+ RasterForAnalysis(&canvas, layer_rect, 1.0f);
+ analysis->is_solid_color = canvas.GetColorIfSolid(&analysis->solid_color);
+}
+
+void DisplayListRasterSource::GatherPixelRefs(
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ std::vector<SkPixelRef*>* pixel_refs) const {
+ DCHECK_EQ(0u, pixel_refs->size());
+
+ gfx::Rect layer_rect =
+ gfx::ScaleToEnclosingRect(content_rect, 1.0f / contents_scale);
+
+ PixelRefMap::Iterator iterator(layer_rect, display_list_.get());
+ while (iterator) {
+ pixel_refs->push_back(*iterator);
+ ++iterator;
+ }
+}
+
+bool DisplayListRasterSource::CoversRect(const gfx::Rect& content_rect,
+ float contents_scale) const {
+ if (size_.IsEmpty())
+ return false;
+ gfx::Rect layer_rect =
+ gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale);
+ layer_rect.Intersect(gfx::Rect(size_));
+
+ return recorded_viewport_.Contains(layer_rect);
+}
+
+gfx::Size DisplayListRasterSource::GetSize() const {
+ return size_;
+}
+
+bool DisplayListRasterSource::IsSolidColor() const {
+ return is_solid_color_;
+}
+
+SkColor DisplayListRasterSource::GetSolidColor() const {
+ DCHECK(IsSolidColor());
+ return solid_color_;
+}
+
+bool DisplayListRasterSource::HasRecordings() const {
+ return !!display_list_.get();
+}
+
+void DisplayListRasterSource::SetShouldAttemptToUseDistanceFieldText() {
+ should_attempt_to_use_distance_field_text_ = true;
+}
+
+bool DisplayListRasterSource::ShouldAttemptToUseDistanceFieldText() const {
+ return should_attempt_to_use_distance_field_text_;
+}
+
+void DisplayListRasterSource::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ if (display_list_.get())
+ TracedValue::AppendIDRef(display_list_.get(), array);
+}
+
+void DisplayListRasterSource::DidBeginTracing() {
+ if (display_list_.get())
+ display_list_->EmitTraceSnapshot();
+}
+
+bool DisplayListRasterSource::CanUseLCDText() const {
+ return can_use_lcd_text_;
+}
+
+scoped_refptr<RasterSource> DisplayListRasterSource::CreateCloneWithoutLCDText()
+ const {
+ bool can_use_lcd_text = false;
+ return scoped_refptr<RasterSource>(
+ new DisplayListRasterSource(this, can_use_lcd_text));
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/display_list_raster_source.h b/chromium/cc/playback/display_list_raster_source.h
new file mode 100644
index 00000000000..e9010e59261
--- /dev/null
+++ b/chromium/cc/playback/display_list_raster_source.h
@@ -0,0 +1,98 @@
+// Copyright 2014 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_PLAYBACK_DISPLAY_LIST_RASTER_SOURCE_H_
+#define CC_PLAYBACK_DISPLAY_LIST_RASTER_SOURCE_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/debug/rendering_stats_instrumentation.h"
+#include "cc/playback/display_list_recording_source.h"
+#include "cc/playback/raster_source.h"
+#include "skia/ext/analysis_canvas.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkPicture.h"
+
+namespace cc {
+class DisplayItemList;
+
+class CC_EXPORT DisplayListRasterSource : public RasterSource {
+ public:
+ static scoped_refptr<DisplayListRasterSource>
+ CreateFromDisplayListRecordingSource(const DisplayListRecordingSource* other,
+ bool can_use_lcd_text);
+
+ // RasterSource overrides.
+ void PlaybackToCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const override;
+ void PlaybackToSharedCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const override;
+ void PerformSolidColorAnalysis(
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ RasterSource::SolidColorAnalysis* analysis) const override;
+ bool IsSolidColor() const override;
+ SkColor GetSolidColor() const override;
+ gfx::Size GetSize() const override;
+ void GatherPixelRefs(const gfx::Rect& content_rect,
+ float contents_scale,
+ std::vector<SkPixelRef*>* pixel_refs) const override;
+ bool CoversRect(const gfx::Rect& content_rect,
+ float contents_scale) const override;
+ bool HasRecordings() const override;
+ void SetShouldAttemptToUseDistanceFieldText() override;
+ bool ShouldAttemptToUseDistanceFieldText() const override;
+ void DidBeginTracing() override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+ skia::RefPtr<SkPicture> GetFlattenedPicture() override;
+ size_t GetPictureMemoryUsage() const override;
+ bool CanUseLCDText() const override;
+ scoped_refptr<RasterSource> CreateCloneWithoutLCDText() const override;
+
+ protected:
+ DisplayListRasterSource();
+ DisplayListRasterSource(const DisplayListRecordingSource* other,
+ bool can_use_lcd_text);
+ DisplayListRasterSource(const DisplayListRasterSource* other,
+ bool can_use_lcd_text);
+ ~DisplayListRasterSource() override;
+
+ // These members are const as this raster source may be in use on another
+ // thread and so should not be touched after construction.
+ const scoped_refptr<DisplayItemList> display_list_;
+ const SkColor background_color_;
+ const bool requires_clear_;
+ const bool can_use_lcd_text_;
+ const bool is_solid_color_;
+ const SkColor solid_color_;
+ const gfx::Rect recorded_viewport_;
+ const gfx::Size size_;
+ const bool clear_canvas_with_debug_color_;
+ const int slow_down_raster_scale_factor_for_debug_;
+ // TODO(enne/vmiura): this has a read/write race between raster and compositor
+ // threads with multi-threaded Ganesh. Make this const or remove it.
+ bool should_attempt_to_use_distance_field_text_;
+
+ private:
+ // Called when analyzing a tile. We can use AnalysisCanvas as
+ // SkDrawPictureCallback, which allows us to early out from analysis.
+ void RasterForAnalysis(skia::AnalysisCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const;
+
+ void RasterCommon(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayListRasterSource);
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_DISPLAY_LIST_RASTER_SOURCE_H_
diff --git a/chromium/cc/playback/display_list_recording_source.cc b/chromium/cc/playback/display_list_recording_source.cc
new file mode 100644
index 00000000000..9d6e31f26c7
--- /dev/null
+++ b/chromium/cc/playback/display_list_recording_source.cc
@@ -0,0 +1,192 @@
+// Copyright 2014 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/playback/display_list_recording_source.h"
+
+#include <algorithm>
+
+#include "cc/base/region.h"
+#include "cc/layers/content_layer_client.h"
+#include "cc/playback/display_item_list.h"
+#include "cc/playback/display_list_raster_source.h"
+#include "skia/ext/analysis_canvas.h"
+
+namespace {
+
+// Layout pixel buffer around the visible layer rect to record. Any base
+// picture that intersects the visible layer rect expanded by this distance
+// will be recorded.
+const int kPixelDistanceToRecord = 8000;
+// We don't perform solid color analysis on images that have more than 10 skia
+// operations.
+const int kOpCountThatIsOkToAnalyze = 10;
+
+} // namespace
+
+namespace cc {
+
+DisplayListRecordingSource::DisplayListRecordingSource(
+ const gfx::Size& grid_cell_size,
+ bool use_cached_picture)
+ : use_cached_picture_(use_cached_picture),
+ slow_down_raster_scale_factor_for_debug_(0),
+ gather_pixel_refs_(false),
+ requires_clear_(false),
+ is_solid_color_(false),
+ solid_color_(SK_ColorTRANSPARENT),
+ background_color_(SK_ColorTRANSPARENT),
+ pixel_record_distance_(kPixelDistanceToRecord),
+ grid_cell_size_(grid_cell_size),
+ is_suitable_for_gpu_rasterization_(true) {
+}
+
+DisplayListRecordingSource::~DisplayListRecordingSource() {
+}
+
+bool DisplayListRecordingSource::UpdateAndExpandInvalidation(
+ ContentLayerClient* painter,
+ Region* invalidation,
+ const gfx::Size& layer_size,
+ const gfx::Rect& visible_layer_rect,
+ int frame_number,
+ RecordingMode recording_mode) {
+ bool updated = false;
+
+ if (size_ != layer_size) {
+ size_ = layer_size;
+ updated = true;
+ }
+
+ gfx::Rect old_recorded_viewport = recorded_viewport_;
+ recorded_viewport_ = visible_layer_rect;
+ recorded_viewport_.Inset(-pixel_record_distance_, -pixel_record_distance_);
+ recorded_viewport_.Intersect(gfx::Rect(GetSize()));
+
+ if (recorded_viewport_ != old_recorded_viewport) {
+ // Invalidate newly-exposed and no-longer-exposed areas.
+ Region newly_exposed_region(recorded_viewport_);
+ newly_exposed_region.Subtract(old_recorded_viewport);
+ invalidation->Union(newly_exposed_region);
+
+ Region no_longer_exposed_region(old_recorded_viewport);
+ no_longer_exposed_region.Subtract(recorded_viewport_);
+ invalidation->Union(no_longer_exposed_region);
+
+ updated = true;
+ }
+
+ if (!updated && !invalidation->Intersects(recorded_viewport_))
+ return false;
+
+ ContentLayerClient::PaintingControlSetting painting_control =
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL;
+
+ switch (recording_mode) {
+ case RECORD_NORMALLY:
+ // Already setup for normal recording.
+ break;
+ case RECORD_WITH_PAINTING_DISABLED:
+ painting_control = ContentLayerClient::DISPLAY_LIST_PAINTING_DISABLED;
+ break;
+ case RECORD_WITH_CACHING_DISABLED:
+ painting_control = ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED;
+ break;
+ case RECORD_WITH_CONSTRUCTION_DISABLED:
+ painting_control = ContentLayerClient::DISPLAY_LIST_CONSTRUCTION_DISABLED;
+ break;
+ default:
+ // case RecordingSource::RECORD_WITH_SK_NULL_CANVAS should not be reached
+ NOTREACHED();
+ }
+
+ int repeat_count = 1;
+ if (slow_down_raster_scale_factor_for_debug_ > 1) {
+ repeat_count = slow_down_raster_scale_factor_for_debug_;
+ painting_control = ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED;
+ }
+ for (int i = 0; i < repeat_count; ++i) {
+ display_list_ =
+ DisplayItemList::Create(recorded_viewport_, use_cached_picture_);
+ painter->PaintContentsToDisplayList(display_list_.get(), recorded_viewport_,
+ painting_control);
+ }
+ display_list_->ProcessAppendedItems();
+ if (use_cached_picture_)
+ display_list_->CreateAndCacheSkPicture();
+
+ is_suitable_for_gpu_rasterization_ =
+ display_list_->IsSuitableForGpuRasterization();
+ DetermineIfSolidColor();
+ display_list_->EmitTraceSnapshot();
+ if (gather_pixel_refs_)
+ display_list_->GatherPixelRefs(grid_cell_size_);
+
+ return true;
+}
+
+gfx::Size DisplayListRecordingSource::GetSize() const {
+ return size_;
+}
+
+void DisplayListRecordingSource::SetEmptyBounds() {
+ size_ = gfx::Size();
+ Clear();
+}
+
+void DisplayListRecordingSource::SetSlowdownRasterScaleFactor(int factor) {
+ slow_down_raster_scale_factor_for_debug_ = factor;
+}
+
+void DisplayListRecordingSource::SetGatherPixelRefs(bool gather_pixel_refs) {
+ gather_pixel_refs_ = gather_pixel_refs;
+}
+
+void DisplayListRecordingSource::SetBackgroundColor(SkColor background_color) {
+ background_color_ = background_color;
+}
+
+void DisplayListRecordingSource::SetRequiresClear(bool requires_clear) {
+ requires_clear_ = requires_clear;
+}
+
+void DisplayListRecordingSource::SetUnsuitableForGpuRasterizationForTesting() {
+ is_suitable_for_gpu_rasterization_ = false;
+}
+
+bool DisplayListRecordingSource::IsSuitableForGpuRasterization() const {
+ return is_suitable_for_gpu_rasterization_;
+}
+
+scoped_refptr<RasterSource> DisplayListRecordingSource::CreateRasterSource(
+ bool can_use_lcd_text) const {
+ return scoped_refptr<RasterSource>(
+ DisplayListRasterSource::CreateFromDisplayListRecordingSource(
+ this, can_use_lcd_text));
+}
+
+gfx::Size DisplayListRecordingSource::GetTileGridSizeForTesting() const {
+ return gfx::Size();
+}
+
+void DisplayListRecordingSource::DetermineIfSolidColor() {
+ DCHECK(display_list_.get());
+ is_solid_color_ = false;
+ solid_color_ = SK_ColorTRANSPARENT;
+
+ if (display_list_->ApproximateOpCount() > kOpCountThatIsOkToAnalyze)
+ return;
+
+ gfx::Size layer_size = GetSize();
+ skia::AnalysisCanvas canvas(layer_size.width(), layer_size.height());
+ display_list_->Raster(&canvas, nullptr, 1.f);
+ is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
+}
+
+void DisplayListRecordingSource::Clear() {
+ recorded_viewport_ = gfx::Rect();
+ display_list_ = NULL;
+ is_solid_color_ = false;
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/display_list_recording_source.h b/chromium/cc/playback/display_list_recording_source.h
new file mode 100644
index 00000000000..8d652fa67de
--- /dev/null
+++ b/chromium/cc/playback/display_list_recording_source.h
@@ -0,0 +1,70 @@
+// Copyright 2014 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_PLAYBACK_DISPLAY_LIST_RECORDING_SOURCE_H_
+#define CC_PLAYBACK_DISPLAY_LIST_RECORDING_SOURCE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/playback/recording_source.h"
+
+namespace cc {
+class DisplayItemList;
+class DisplayListRasterSource;
+
+class CC_EXPORT DisplayListRecordingSource : public RecordingSource {
+ public:
+ DisplayListRecordingSource(const gfx::Size& grid_cell_size,
+ bool use_cached_picture);
+ ~DisplayListRecordingSource() override;
+
+ // RecordingSource overrides.
+ bool UpdateAndExpandInvalidation(ContentLayerClient* painter,
+ Region* invalidation,
+ const gfx::Size& layer_size,
+ const gfx::Rect& visible_layer_rect,
+ int frame_number,
+ RecordingMode recording_mode) override;
+ scoped_refptr<RasterSource> CreateRasterSource(
+ bool can_use_lcd_text) const override;
+ gfx::Size GetSize() const final;
+ void SetEmptyBounds() override;
+ void SetSlowdownRasterScaleFactor(int factor) override;
+ void SetGatherPixelRefs(bool gather_pixel_refs) override;
+ void SetBackgroundColor(SkColor background_color) override;
+ void SetRequiresClear(bool requires_clear) override;
+ bool IsSuitableForGpuRasterization() const override;
+ void SetUnsuitableForGpuRasterizationForTesting() override;
+ gfx::Size GetTileGridSizeForTesting() const override;
+
+ protected:
+ void Clear();
+
+ const bool use_cached_picture_;
+
+ gfx::Rect recorded_viewport_;
+ gfx::Size size_;
+ int slow_down_raster_scale_factor_for_debug_;
+ bool gather_pixel_refs_;
+ bool requires_clear_;
+ bool is_solid_color_;
+ SkColor solid_color_;
+ SkColor background_color_;
+ int pixel_record_distance_;
+ gfx::Size grid_cell_size_;
+
+ scoped_refptr<DisplayItemList> display_list_;
+
+ private:
+ friend class DisplayListRasterSource;
+
+ void DetermineIfSolidColor();
+
+ bool is_suitable_for_gpu_rasterization_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayListRecordingSource);
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_DISPLAY_LIST_RECORDING_SOURCE_H_
diff --git a/chromium/cc/playback/display_list_recording_source_unittest.cc b/chromium/cc/playback/display_list_recording_source_unittest.cc
new file mode 100644
index 00000000000..0d7ec7c74f1
--- /dev/null
+++ b/chromium/cc/playback/display_list_recording_source_unittest.cc
@@ -0,0 +1,165 @@
+// 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.
+
+#include <vector>
+
+#include "cc/playback/display_list_raster_source.h"
+#include "cc/test/fake_display_list_recording_source.h"
+#include "cc/test/skia_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+TEST(DisplayListRecordingSourceTest, DiscardablePixelRefsWithTransform) {
+ gfx::Size grid_cell_size(128, 128);
+ gfx::Rect recorded_viewport(0, 0, 256, 256);
+
+ scoped_ptr<FakeDisplayListRecordingSource> recording_source =
+ FakeDisplayListRecordingSource::CreateRecordingSource(recorded_viewport);
+ recording_source->SetGridCellSize(grid_cell_size);
+ SkBitmap discardable_bitmap[2][2];
+ gfx::Transform identity_transform;
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][0]);
+ // Translate transform is equivalent to moving using point.
+ gfx::Transform translate_transform;
+ translate_transform.Translate(0, 130);
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][0]);
+ // This moves the bitmap to center of viewport and rotate, this would make
+ // this bitmap in all four tile grids.
+ gfx::Transform rotate_transform;
+ rotate_transform.Translate(112, 112);
+ rotate_transform.Rotate(45);
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][1]);
+
+ recording_source->add_draw_bitmap_with_transform(discardable_bitmap[0][0],
+ identity_transform);
+ recording_source->add_draw_bitmap_with_transform(discardable_bitmap[1][0],
+ translate_transform);
+ recording_source->add_draw_bitmap_with_transform(discardable_bitmap[1][1],
+ rotate_transform);
+ recording_source->SetGatherPixelRefs(true);
+ recording_source->Rerecord();
+
+ bool can_use_lcd_text = true;
+ scoped_refptr<DisplayListRasterSource> raster_source =
+ DisplayListRasterSource::CreateFromDisplayListRecordingSource(
+ recording_source.get(), can_use_lcd_text);
+
+ // Tile sized iterators. These should find only one pixel ref.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 1.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(2u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 2.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(2u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 64, 64), 0.5, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(2u, pixel_refs.size());
+ }
+
+ // Shifted tile sized iterators. These should find only one pixel ref.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(140, 140, 128, 128), 1.0,
+ &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(280, 280, 256, 256), 2.0,
+ &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(70, 70, 64, 64), 0.5, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+
+ // The rotated bitmap would still be in the top right tile.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(140, 0, 128, 128), 1.0,
+ &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+
+ // Layer sized iterators. These should find all 6 pixel refs, including 1
+ // pixel ref bitmap[0][0], 1 pixel ref for bitmap[1][0], and 4 pixel refs for
+ // bitmap[1][1].
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 1.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ // Top left tile with bitmap[0][0] and bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[1][1].pixelRef());
+ // Top right tile with bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[2] == discardable_bitmap[1][1].pixelRef());
+ // Bottom left tile with bitmap[1][0] and bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[3] == discardable_bitmap[1][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[4] == discardable_bitmap[1][1].pixelRef());
+ // Bottom right tile with bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[5] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(6u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 512, 512), 2.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ // Top left tile with bitmap[0][0] and bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[1][1].pixelRef());
+ // Top right tile with bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[2] == discardable_bitmap[1][1].pixelRef());
+ // Bottom left tile with bitmap[1][0] and bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[3] == discardable_bitmap[1][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[4] == discardable_bitmap[1][1].pixelRef());
+ // Bottom right tile with bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[5] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(6u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 0.5, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ // Top left tile with bitmap[0][0] and bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[1][1].pixelRef());
+ // Top right tile with bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[2] == discardable_bitmap[1][1].pixelRef());
+ // Bottom left tile with bitmap[1][0] and bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[3] == discardable_bitmap[1][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[4] == discardable_bitmap[1][1].pixelRef());
+ // Bottom right tile with bitmap[1][1].
+ EXPECT_TRUE(pixel_refs[5] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(6u, pixel_refs.size());
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/playback/drawing_display_item.cc b/chromium/cc/playback/drawing_display_item.cc
new file mode 100644
index 00000000000..51cd42edf41
--- /dev/null
+++ b/chromium/cc/playback/drawing_display_item.cc
@@ -0,0 +1,62 @@
+// Copyright 2014 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/playback/drawing_display_item.h"
+
+#include <string>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/debug/picture_debug_util.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkDrawPictureCallback.h"
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
+
+namespace cc {
+
+DrawingDisplayItem::DrawingDisplayItem() {
+}
+
+DrawingDisplayItem::~DrawingDisplayItem() {
+}
+
+void DrawingDisplayItem::SetNew(skia::RefPtr<SkPicture> picture) {
+ picture_ = picture.Pass();
+ DisplayItem::SetNew(picture_->suitableForGpuRasterization(NULL),
+ picture_->approximateOpCount(),
+ SkPictureUtils::ApproximateBytesUsed(picture_.get()));
+}
+
+void DrawingDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ // SkPicture always does a wrapping save/restore on the canvas, so it is not
+ // necessary here.
+ if (callback)
+ picture_->playback(canvas, callback);
+ else
+ canvas->drawPicture(picture_.get());
+}
+
+void DrawingDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->BeginDictionary();
+ array->SetString("name", "DrawingDisplayItem");
+ array->SetString(
+ "cullRect",
+ base::StringPrintf("[%f,%f,%f,%f]", picture_->cullRect().x(),
+ picture_->cullRect().y(), picture_->cullRect().width(),
+ picture_->cullRect().height()));
+ std::string b64_picture;
+ PictureDebugUtil::SerializeAsBase64(picture_.get(), &b64_picture);
+ array->SetString("skp64", b64_picture);
+ array->EndDictionary();
+}
+
+void DrawingDisplayItem::CloneTo(DrawingDisplayItem* item) const {
+ item->SetNew(picture_);
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/drawing_display_item.h b/chromium/cc/playback/drawing_display_item.h
new file mode 100644
index 00000000000..81ddbce4f11
--- /dev/null
+++ b/chromium/cc/playback/drawing_display_item.h
@@ -0,0 +1,38 @@
+// Copyright 2014 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_PLAYBACK_DRAWING_DISPLAY_ITEM_H_
+#define CC_PLAYBACK_DRAWING_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/playback/display_item.h"
+#include "skia/ext/refptr.h"
+#include "ui/gfx/geometry/point_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+class SkPicture;
+
+namespace cc {
+
+class CC_EXPORT DrawingDisplayItem : public DisplayItem {
+ public:
+ DrawingDisplayItem();
+ ~DrawingDisplayItem() override;
+
+ void SetNew(skia::RefPtr<SkPicture> picture);
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+
+ void CloneTo(DrawingDisplayItem* item) const;
+
+ private:
+ skia::RefPtr<SkPicture> picture_;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_DRAWING_DISPLAY_ITEM_H_
diff --git a/chromium/cc/playback/filter_display_item.cc b/chromium/cc/playback/filter_display_item.cc
new file mode 100644
index 00000000000..8e849cf6009
--- /dev/null
+++ b/chromium/cc/playback/filter_display_item.cc
@@ -0,0 +1,81 @@
+// Copyright 2014 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/playback/filter_display_item.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/output/render_surface_filters.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+FilterDisplayItem::FilterDisplayItem() {
+}
+
+FilterDisplayItem::~FilterDisplayItem() {
+}
+
+void FilterDisplayItem::SetNew(const FilterOperations& filters,
+ const gfx::RectF& bounds) {
+ filters_ = filters;
+ bounds_ = bounds;
+
+ size_t memory_usage =
+ sizeof(skia::RefPtr<SkImageFilter>) + sizeof(gfx::RectF);
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 1 /* op_count */,
+ memory_usage);
+}
+
+void FilterDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->save();
+ canvas->translate(bounds_.x(), bounds_.y());
+
+ skia::RefPtr<SkImageFilter> image_filter =
+ RenderSurfaceFilters::BuildImageFilter(
+ filters_, gfx::SizeF(bounds_.width(), bounds_.height()));
+ SkRect boundaries;
+ image_filter->computeFastBounds(
+ SkRect::MakeWH(bounds_.width(), bounds_.height()), &boundaries);
+
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+ paint.setImageFilter(image_filter.get());
+ canvas->saveLayer(&boundaries, &paint);
+
+ canvas->translate(-bounds_.x(), -bounds_.y());
+}
+
+void FilterDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString(base::StringPrintf("FilterDisplayItem bounds: [%s]",
+ bounds_.ToString().c_str()));
+}
+
+EndFilterDisplayItem::EndFilterDisplayItem() {
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 0 /* op_count */,
+ 0 /* memory_usage */);
+}
+
+EndFilterDisplayItem::~EndFilterDisplayItem() {
+}
+
+void EndFilterDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+ canvas->restore();
+}
+
+void EndFilterDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString("EndFilterDisplayItem");
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/filter_display_item.h b/chromium/cc/playback/filter_display_item.h
new file mode 100644
index 00000000000..a999b3883bf
--- /dev/null
+++ b/chromium/cc/playback/filter_display_item.h
@@ -0,0 +1,49 @@
+// Copyright 2014 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_PLAYBACK_FILTER_DISPLAY_ITEM_H_
+#define CC_PLAYBACK_FILTER_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/output/filter_operations.h"
+#include "cc/playback/display_item.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT FilterDisplayItem : public DisplayItem {
+ public:
+ FilterDisplayItem();
+ ~FilterDisplayItem() override;
+
+ void SetNew(const FilterOperations& filters, const gfx::RectF& bounds);
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+
+ private:
+ FilterOperations filters_;
+ gfx::RectF bounds_;
+};
+
+class CC_EXPORT EndFilterDisplayItem : public DisplayItem {
+ public:
+ EndFilterDisplayItem();
+ ~EndFilterDisplayItem() override;
+
+ static scoped_ptr<EndFilterDisplayItem> Create() {
+ return make_scoped_ptr(new EndFilterDisplayItem());
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_FILTER_DISPLAY_ITEM_H_
diff --git a/chromium/cc/playback/float_clip_display_item.cc b/chromium/cc/playback/float_clip_display_item.cc
new file mode 100644
index 00000000000..0f368a65770
--- /dev/null
+++ b/chromium/cc/playback/float_clip_display_item.cc
@@ -0,0 +1,58 @@
+// 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.
+
+#include "cc/playback/float_clip_display_item.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+FloatClipDisplayItem::FloatClipDisplayItem() {
+}
+
+FloatClipDisplayItem::~FloatClipDisplayItem() {
+}
+
+void FloatClipDisplayItem::SetNew(const gfx::RectF& clip_rect) {
+ clip_rect_ = clip_rect;
+
+ size_t memory_usage = sizeof(gfx::RectF);
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 1 /* op_count */,
+ memory_usage);
+}
+
+void FloatClipDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->save();
+ canvas->clipRect(gfx::RectFToSkRect(clip_rect_));
+}
+
+void FloatClipDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString(base::StringPrintf("FloatClipDisplayItem rect: [%s]",
+ clip_rect_.ToString().c_str()));
+}
+
+EndFloatClipDisplayItem::EndFloatClipDisplayItem() {
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 0 /* op_count */,
+ 0 /* memory_usage */);
+}
+
+EndFloatClipDisplayItem::~EndFloatClipDisplayItem() {
+}
+
+void EndFloatClipDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+}
+
+void EndFloatClipDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString("EndFloatClipDisplayItem");
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/float_clip_display_item.h b/chromium/cc/playback/float_clip_display_item.h
new file mode 100644
index 00000000000..2812189ff61
--- /dev/null
+++ b/chromium/cc/playback/float_clip_display_item.h
@@ -0,0 +1,49 @@
+// 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_PLAYBACK_FLOAT_CLIP_DISPLAY_ITEM_H_
+#define CC_PLAYBACK_FLOAT_CLIP_DISPLAY_ITEM_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/playback/display_item.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT FloatClipDisplayItem : public DisplayItem {
+ public:
+ FloatClipDisplayItem();
+ ~FloatClipDisplayItem() override;
+
+ void SetNew(const gfx::RectF& clip_rect);
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+
+ private:
+ gfx::RectF clip_rect_;
+};
+
+class CC_EXPORT EndFloatClipDisplayItem : public DisplayItem {
+ public:
+ EndFloatClipDisplayItem();
+ ~EndFloatClipDisplayItem() override;
+
+ static scoped_ptr<EndFloatClipDisplayItem> Create() {
+ return make_scoped_ptr(new EndFloatClipDisplayItem());
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_FLOAT_CLIP_DISPLAY_ITEM_H_
diff --git a/chromium/cc/playback/largest_display_item.cc b/chromium/cc/playback/largest_display_item.cc
new file mode 100644
index 00000000000..0ecd3d0547a
--- /dev/null
+++ b/chromium/cc/playback/largest_display_item.cc
@@ -0,0 +1,71 @@
+// 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.
+
+#include "cc/playback/largest_display_item.h"
+
+#include <algorithm>
+
+#include "cc/playback/clip_display_item.h"
+#include "cc/playback/clip_path_display_item.h"
+#include "cc/playback/compositing_display_item.h"
+#include "cc/playback/drawing_display_item.h"
+#include "cc/playback/filter_display_item.h"
+#include "cc/playback/float_clip_display_item.h"
+#include "cc/playback/transform_display_item.h"
+
+#include "third_party/skia/include/core/SkPicture.h"
+
+namespace {
+const size_t kLargestDisplayItemSize = sizeof(cc::TransformDisplayItem);
+} // namespace
+
+namespace cc {
+
+size_t LargestDisplayItemSize() {
+ // Use compile assert to make sure largest is actually larger than all other
+ // type of display_items.
+ static_assert(sizeof(ClipDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. ClipDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(EndClipDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. EndClipDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(ClipPathDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. ClipPathDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(EndClipPathDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. EndClipPathDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(CompositingDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. CompositingDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(EndCompositingDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. EndCompositingDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(DrawingDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. DrawingDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(FilterDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. FilterDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(EndFilterDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. EndFilterDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(FloatClipDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. FloatClipDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(EndFloatClipDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. EndFloatClipDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(TransformDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. TransformDisplayItem"
+ " is currently largest.");
+ static_assert(sizeof(EndTransformDisplayItem) <= kLargestDisplayItemSize,
+ "Largest Draw Quad size needs update. EndTransformDisplayItem"
+ " is currently largest.");
+
+ return kLargestDisplayItemSize;
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/largest_display_item.h b/chromium/cc/playback/largest_display_item.h
new file mode 100644
index 00000000000..cce56719e4c
--- /dev/null
+++ b/chromium/cc/playback/largest_display_item.h
@@ -0,0 +1,17 @@
+// 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_PLAYBACK_LARGEST_DISPLAY_ITEM_H_
+#define CC_PLAYBACK_LARGEST_DISPLAY_ITEM_H_
+
+#include "base/basictypes.h"
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+CC_EXPORT size_t LargestDisplayItemSize();
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_LARGEST_DISPLAY_ITEM_H_
diff --git a/chromium/cc/playback/picture.cc b/chromium/cc/playback/picture.cc
new file mode 100644
index 00000000000..4537bf72107
--- /dev/null
+++ b/chromium/cc/playback/picture.cc
@@ -0,0 +1,340 @@
+// Copyright 2012 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/playback/picture.h"
+
+#include <set>
+#include <string>
+
+#include "base/base64.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+#include "cc/base/math_util.h"
+#include "cc/base/util.h"
+#include "cc/debug/picture_debug_util.h"
+#include "cc/debug/traced_picture.h"
+#include "cc/debug/traced_value.h"
+#include "cc/layers/content_layer_client.h"
+#include "skia/ext/pixel_ref_utils.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkDrawPictureCallback.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/utils/SkNullCanvas.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+namespace {
+
+bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
+ const unsigned char* data = static_cast<const unsigned char *>(buffer);
+
+ // Try PNG first.
+ if (gfx::PNGCodec::Decode(data, size, bm))
+ return true;
+
+ // Try JPEG.
+ scoped_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodec::Decode(data, size));
+ if (decoded_jpeg) {
+ *bm = *decoded_jpeg;
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+scoped_refptr<Picture> Picture::Create(
+ const gfx::Rect& layer_rect,
+ ContentLayerClient* client,
+ const gfx::Size& tile_grid_size,
+ bool gather_pixel_refs,
+ RecordingSource::RecordingMode recording_mode) {
+ scoped_refptr<Picture> picture =
+ make_scoped_refptr(new Picture(layer_rect, tile_grid_size));
+
+ picture->Record(client, recording_mode);
+ if (gather_pixel_refs)
+ picture->GatherPixelRefs();
+
+ return picture;
+}
+
+Picture::Picture(const gfx::Rect& layer_rect, const gfx::Size& tile_grid_size)
+ : layer_rect_(layer_rect), pixel_refs_(tile_grid_size) {
+ // Instead of recording a trace event for object creation here, we wait for
+ // the picture to be recorded in Picture::Record.
+}
+
+scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) {
+ // Decode the picture from base64.
+ std::string encoded;
+ if (!value->GetAsString(&encoded))
+ return NULL;
+
+ std::string decoded;
+ base::Base64Decode(encoded, &decoded);
+ SkMemoryStream stream(decoded.data(), decoded.size());
+
+ // Read the picture. This creates an empty picture on failure.
+ SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
+ if (skpicture == NULL)
+ return NULL;
+
+ gfx::Rect layer_rect(gfx::SkIRectToRect(skpicture->cullRect().roundOut()));
+ return make_scoped_refptr(new Picture(skpicture, layer_rect));
+}
+
+scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
+ const base::DictionaryValue* value = NULL;
+ if (!raw_value->GetAsDictionary(&value))
+ return NULL;
+
+ // Decode the picture from base64.
+ std::string encoded;
+ if (!value->GetString("skp64", &encoded))
+ return NULL;
+
+ std::string decoded;
+ base::Base64Decode(encoded, &decoded);
+ SkMemoryStream stream(decoded.data(), decoded.size());
+
+ const base::Value* layer_rect_value = NULL;
+ if (!value->Get("params.layer_rect", &layer_rect_value))
+ return NULL;
+
+ gfx::Rect layer_rect;
+ if (!MathUtil::FromValue(layer_rect_value, &layer_rect))
+ return NULL;
+
+ // Read the picture. This creates an empty picture on failure.
+ SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
+ if (skpicture == NULL)
+ return NULL;
+
+ return make_scoped_refptr(new Picture(skpicture, layer_rect));
+}
+
+Picture::Picture(SkPicture* picture, const gfx::Rect& layer_rect)
+ : layer_rect_(layer_rect),
+ picture_(skia::AdoptRef(picture)),
+ pixel_refs_(layer_rect.size()) {
+}
+
+Picture::Picture(const skia::RefPtr<SkPicture>& picture,
+ const gfx::Rect& layer_rect,
+ const PixelRefMap& pixel_refs)
+ : layer_rect_(layer_rect), picture_(picture), pixel_refs_(pixel_refs) {
+}
+
+Picture::~Picture() {
+ TRACE_EVENT_OBJECT_DELETED_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.picture"), "cc::Picture", this);
+}
+
+bool Picture::IsSuitableForGpuRasterization(const char** reason) const {
+ DCHECK(picture_);
+
+ // TODO(hendrikw): SkPicture::suitableForGpuRasterization takes a GrContext.
+ // Currently the GrContext isn't used, and should probably be removed from
+ // skia.
+ return picture_->suitableForGpuRasterization(nullptr, reason);
+}
+
+int Picture::ApproximateOpCount() const {
+ DCHECK(picture_);
+ return picture_->approximateOpCount();
+}
+
+size_t Picture::ApproximateMemoryUsage() const {
+ DCHECK(picture_);
+ return SkPictureUtils::ApproximateBytesUsed(picture_.get());
+}
+
+bool Picture::HasText() const {
+ DCHECK(picture_);
+ return picture_->hasText();
+}
+
+void Picture::Record(ContentLayerClient* painter,
+ RecordingSource::RecordingMode recording_mode) {
+ TRACE_EVENT2("cc",
+ "Picture::Record",
+ "data",
+ AsTraceableRecordData(),
+ "recording_mode",
+ recording_mode);
+
+ DCHECK(!picture_);
+
+ SkRTreeFactory factory;
+ SkPictureRecorder recorder;
+
+ skia::RefPtr<SkCanvas> canvas;
+ canvas = skia::SharePtr(recorder.beginRecording(
+ layer_rect_.width(), layer_rect_.height(), &factory,
+ SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag));
+
+ ContentLayerClient::PaintingControlSetting painting_control =
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL;
+
+ switch (recording_mode) {
+ case RecordingSource::RECORD_NORMALLY:
+ // Already setup for normal recording.
+ break;
+ case RecordingSource::RECORD_WITH_SK_NULL_CANVAS:
+ canvas = skia::AdoptRef(SkCreateNullCanvas());
+ break;
+ case RecordingSource::RECORD_WITH_PAINTING_DISABLED:
+ // We pass a disable flag through the paint calls when perfromance
+ // testing (the only time this case should ever arise) when we want to
+ // prevent the Blink GraphicsContext object from consuming any compute
+ // time.
+ canvas = skia::AdoptRef(SkCreateNullCanvas());
+ painting_control = ContentLayerClient::DISPLAY_LIST_PAINTING_DISABLED;
+ break;
+ case RecordingSource::RECORD_WITH_CACHING_DISABLED:
+ // This mode should give the same results as RECORD_NORMALLY.
+ painting_control = ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED;
+ break;
+ default:
+ // case RecordingSource::RECORD_WITH_CONSTRUCTION_DISABLED should
+ // not be reached
+ NOTREACHED();
+ }
+
+ canvas->save();
+ canvas->translate(SkFloatToScalar(-layer_rect_.x()),
+ SkFloatToScalar(-layer_rect_.y()));
+
+ canvas->clipRect(gfx::RectToSkRect(layer_rect_));
+
+ painter->PaintContents(canvas.get(), layer_rect_, painting_control);
+
+ canvas->restore();
+ picture_ = skia::AdoptRef(recorder.endRecordingAsPicture());
+ DCHECK(picture_);
+
+ EmitTraceSnapshot();
+}
+
+void Picture::GatherPixelRefs() {
+ TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
+ "width", layer_rect_.width(),
+ "height", layer_rect_.height());
+
+ DCHECK(picture_);
+ DCHECK(pixel_refs_.empty());
+ if (!WillPlayBackBitmaps())
+ return;
+
+ pixel_refs_.GatherPixelRefsFromPicture(picture_.get());
+}
+
+int Picture::Raster(SkCanvas* canvas,
+ SkPicture::AbortCallback* callback,
+ const Region& negated_content_region,
+ float contents_scale) const {
+ TRACE_EVENT_BEGIN1(
+ "cc",
+ "Picture::Raster",
+ "data",
+ AsTraceableRasterData(contents_scale));
+
+ DCHECK(picture_);
+
+ canvas->save();
+
+ for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
+ canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
+
+ canvas->scale(contents_scale, contents_scale);
+ canvas->translate(layer_rect_.x(), layer_rect_.y());
+ if (callback) {
+ // If we have a callback, we need to call |draw()|, |drawPicture()| doesn't
+ // take a callback. This is used by |AnalysisCanvas| to early out.
+ picture_->playback(canvas, callback);
+ } else {
+ // Prefer to call |drawPicture()| on the canvas since it could place the
+ // entire picture on the canvas instead of parsing the skia operations.
+ canvas->drawPicture(picture_.get());
+ }
+ SkIRect bounds;
+ canvas->getClipDeviceBounds(&bounds);
+ canvas->restore();
+ TRACE_EVENT_END1(
+ "cc", "Picture::Raster",
+ "num_pixels_rasterized", bounds.width() * bounds.height());
+ return bounds.width() * bounds.height();
+}
+
+void Picture::Replay(SkCanvas* canvas, SkPicture::AbortCallback* callback) {
+ TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
+ DCHECK(picture_);
+ picture_->playback(canvas, callback);
+ SkIRect bounds;
+ canvas->getClipDeviceBounds(&bounds);
+ TRACE_EVENT_END1("cc", "Picture::Replay",
+ "num_pixels_replayed", bounds.width() * bounds.height());
+}
+
+scoped_ptr<base::Value> Picture::AsValue() const {
+ // Encode the picture as base64.
+ scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
+ res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
+ std::string b64_picture;
+ PictureDebugUtil::SerializeAsBase64(picture_.get(), &b64_picture);
+ res->SetString("skp64", b64_picture);
+ return res.Pass();
+}
+
+void Picture::EmitTraceSnapshot() const {
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") ","
+ TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"),
+ "cc::Picture",
+ this,
+ TracedPicture::AsTraceablePicture(this));
+}
+
+void Picture::EmitTraceSnapshotAlias(Picture* original) const {
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") ","
+ TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"),
+ "cc::Picture",
+ this,
+ TracedPicture::AsTraceablePictureAlias(original));
+}
+
+PixelRefMap::Iterator Picture::GetPixelRefMapIterator(
+ const gfx::Rect& layer_rect) const {
+ return PixelRefMap::Iterator(layer_rect, this);
+}
+
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ Picture::AsTraceableRasterData(float scale) const {
+ scoped_refptr<base::trace_event::TracedValue> raster_data =
+ new base::trace_event::TracedValue();
+ TracedValue::SetIDRef(this, raster_data.get(), "picture_id");
+ raster_data->SetDouble("scale", scale);
+ return raster_data;
+}
+
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ Picture::AsTraceableRecordData() const {
+ scoped_refptr<base::trace_event::TracedValue> record_data =
+ new base::trace_event::TracedValue();
+ TracedValue::SetIDRef(this, record_data.get(), "picture_id");
+ MathUtil::AddToTracedValue("layer_rect", layer_rect_, record_data.get());
+ return record_data;
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/picture.h b/chromium/cc/playback/picture.h
index 1677309a6e2..b19504b4270 100644
--- a/chromium/cc/resources/picture.h
+++ b/chromium/cc/playback/picture.h
@@ -2,24 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_PICTURE_H_
-#define CC_RESOURCES_PICTURE_H_
-
-#include <string>
-#include <utility>
-#include <vector>
+#ifndef CC_PLAYBACK_PICTURE_H_
+#define CC_PLAYBACK_PICTURE_H_
#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
-#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/cc_export.h"
#include "cc/base/region.h"
+#include "cc/playback/pixel_ref_map.h"
+#include "cc/playback/recording_source.h"
#include "skia/ext/refptr.h"
-#include "third_party/skia/include/core/SkBBHFactory.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "ui/gfx/geometry/rect.h"
@@ -40,23 +37,12 @@ class ContentLayerClient;
class CC_EXPORT Picture
: public base::RefCountedThreadSafe<Picture> {
public:
- typedef std::pair<int, int> PixelRefMapKey;
- typedef std::vector<SkPixelRef*> PixelRefs;
- typedef base::hash_map<PixelRefMapKey, PixelRefs> PixelRefMap;
-
- enum RecordingMode {
- RECORD_NORMALLY,
- RECORD_WITH_SK_NULL_CANVAS,
- RECORD_WITH_PAINTING_DISABLED,
- RECORDING_MODE_COUNT, // Must be the last entry.
- };
-
static scoped_refptr<Picture> Create(
const gfx::Rect& layer_rect,
ContentLayerClient* client,
- const SkTileGridFactory::TileGridInfo& tile_grid_info,
+ const gfx::Size& tile_grid_size,
bool gather_pixels_refs,
- RecordingMode recording_mode);
+ RecordingSource::RecordingMode recording_mode);
static scoped_refptr<Picture> CreateFromValue(const base::Value* value);
static scoped_refptr<Picture> CreateFromSkpValue(const base::Value* value);
@@ -65,8 +51,9 @@ class CC_EXPORT Picture
// Has Record() been called yet?
bool HasRecording() const { return picture_.get() != NULL; }
- bool IsSuitableForGpuRasterization() const;
+ bool IsSuitableForGpuRasterization(const char** reason) const;
int ApproximateOpCount() const;
+ size_t ApproximateMemoryUsage() const;
bool HasText() const;
@@ -75,59 +62,26 @@ class CC_EXPORT Picture
// raster operation, i.e., the parts of the canvas which will not get drawn
// to.
int Raster(SkCanvas* canvas,
- SkDrawPictureCallback* callback,
+ SkPicture::AbortCallback* callback,
const Region& negated_content_region,
float contents_scale) const;
// Draw the picture directly into the given canvas, without applying any
// clip/scale/layer transformations.
- void Replay(SkCanvas* canvas);
+ void Replay(SkCanvas* canvas, SkPicture::AbortCallback* callback = NULL);
scoped_ptr<base::Value> AsValue() const;
- // This iterator imprecisely returns the set of pixel refs that are needed to
- // raster this layer rect from this picture. Internally, pixel refs are
- // clumped into tile grid buckets, so there may be false positives.
- class CC_EXPORT PixelRefIterator {
- public:
- PixelRefIterator();
- PixelRefIterator(const gfx::Rect& layer_rect, const Picture* picture);
- ~PixelRefIterator();
-
- SkPixelRef* operator->() const {
- DCHECK_LT(current_index_, current_pixel_refs_->size());
- return (*current_pixel_refs_)[current_index_];
- }
-
- SkPixelRef* operator*() const {
- DCHECK_LT(current_index_, current_pixel_refs_->size());
- return (*current_pixel_refs_)[current_index_];
- }
-
- PixelRefIterator& operator++();
- operator bool() const {
- return current_index_ < current_pixel_refs_->size();
- }
-
- private:
- static base::LazyInstance<PixelRefs> empty_pixel_refs_;
- const Picture* picture_;
- const PixelRefs* current_pixel_refs_;
- unsigned current_index_;
-
- gfx::Point min_point_;
- gfx::Point max_point_;
- int current_x_;
- int current_y_;
- };
-
void EmitTraceSnapshot() const;
void EmitTraceSnapshotAlias(Picture* original) const;
bool WillPlayBackBitmaps() const { return picture_->willPlayBackBitmaps(); }
+ PixelRefMap::Iterator GetPixelRefMapIterator(
+ const gfx::Rect& layer_rect) const;
+
private:
- explicit Picture(const gfx::Rect& layer_rect);
+ Picture(const gfx::Rect& layer_rect, const gfx::Size& tile_grid_size);
// This constructor assumes SkPicture is already ref'd and transfers
// ownership to this picture.
Picture(const skia::RefPtr<SkPicture>&,
@@ -140,30 +94,26 @@ class CC_EXPORT Picture
// Record a paint operation. To be able to safely use this SkPicture for
// playback on a different thread this can only be called once.
void Record(ContentLayerClient* client,
- const SkTileGridFactory::TileGridInfo& tile_grid_info,
- RecordingMode recording_mode);
+ RecordingSource::RecordingMode recording_mode);
// Gather pixel refs from recording.
- void GatherPixelRefs(const SkTileGridFactory::TileGridInfo& tile_grid_info);
+ void GatherPixelRefs();
gfx::Rect layer_rect_;
skia::RefPtr<SkPicture> picture_;
PixelRefMap pixel_refs_;
- gfx::Point min_pixel_cell_;
- gfx::Point max_pixel_cell_;
- gfx::Size cell_size_;
- scoped_refptr<base::debug::ConvertableToTraceFormat>
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>
AsTraceableRasterData(float scale) const;
- scoped_refptr<base::debug::ConvertableToTraceFormat>
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>
AsTraceableRecordData() const;
friend class base::RefCountedThreadSafe<Picture>;
- friend class PixelRefIterator;
+ friend class PixelRefMap::Iterator;
DISALLOW_COPY_AND_ASSIGN(Picture);
};
} // namespace cc
-#endif // CC_RESOURCES_PICTURE_H_
+#endif // CC_PLAYBACK_PICTURE_H_
diff --git a/chromium/cc/resources/picture_pile.cc b/chromium/cc/playback/picture_pile.cc
index ec843a57d1b..b7b2822195b 100644
--- a/chromium/cc/resources/picture_pile.cc
+++ b/chromium/cc/playback/picture_pile.cc
@@ -2,15 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/picture_pile.h"
+#include "cc/playback/picture_pile.h"
#include <algorithm>
#include <limits>
#include <vector>
#include "cc/base/region.h"
-#include "cc/debug/rendering_stats_instrumentation.h"
-#include "cc/resources/raster_worker_pool.h"
+#include "cc/playback/picture_pile_impl.h"
#include "skia/ext/analysis_canvas.h"
namespace {
@@ -22,6 +21,10 @@ const int kPixelDistanceToRecord = 8000;
// operations.
const int kOpCountThatIsOkToAnalyze = 10;
+// Dimensions of the tiles in this picture pile as well as the dimensions of
+// the base picture in each tile.
+const int kBasePictureSize = 512;
+
// TODO(humper): The density threshold here is somewhat arbitrary; need a
// way to set // this from the command line so we can write a benchmark
// script and find a sweet spot.
@@ -93,18 +96,17 @@ float PerformClustering(const std::vector<gfx::Rect>& tiles,
static_cast<float>(total_record_area);
}
-float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles,
- std::vector<gfx::Rect>* record_rects) {
+void ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles,
+ std::vector<gfx::Rect>* record_rects) {
TRACE_EVENT1("cc", "ClusterTiles",
"count",
invalid_tiles.size());
-
if (invalid_tiles.size() <= 1) {
// Quickly handle the special case for common
// single-invalidation update, and also the less common
// case of no tiles passed in.
*record_rects = invalid_tiles;
- return 1;
+ return;
}
// Sort the invalid tiles by y coordinate.
@@ -113,15 +115,14 @@ float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles,
invalid_tiles_vertical.end(),
rect_sort_y);
- float vertical_density;
std::vector<gfx::Rect> vertical_clustering;
- vertical_density = PerformClustering(invalid_tiles_vertical,
- &vertical_clustering);
+ float vertical_density =
+ PerformClustering(invalid_tiles_vertical, &vertical_clustering);
// If vertical density is optimal, then we can return early.
if (vertical_density == 1.f) {
*record_rects = vertical_clustering;
- return vertical_density;
+ return;
}
// Now try again with a horizontal sort, see which one is best
@@ -130,27 +131,44 @@ float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles,
invalid_tiles_horizontal.end(),
rect_sort_x);
- float horizontal_density;
std::vector<gfx::Rect> horizontal_clustering;
- horizontal_density = PerformClustering(invalid_tiles_horizontal,
- &horizontal_clustering);
+ float horizontal_density =
+ PerformClustering(invalid_tiles_horizontal, &horizontal_clustering);
if (vertical_density < horizontal_density) {
*record_rects = horizontal_clustering;
- return horizontal_density;
+ return;
}
*record_rects = vertical_clustering;
- return vertical_density;
}
+#ifdef NDEBUG
+const bool kDefaultClearCanvasSetting = false;
+#else
+const bool kDefaultClearCanvasSetting = true;
+#endif
+
} // namespace
namespace cc {
-PicturePile::PicturePile()
- : is_suitable_for_gpu_rasterization_(true),
- pixel_record_distance_(kPixelDistanceToRecord) {
+PicturePile::PicturePile(float min_contents_scale,
+ const gfx::Size& tile_grid_size)
+ : min_contents_scale_(0),
+ slow_down_raster_scale_factor_for_debug_(0),
+ gather_pixel_refs_(false),
+ has_any_recordings_(false),
+ clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+ requires_clear_(true),
+ is_solid_color_(false),
+ solid_color_(SK_ColorTRANSPARENT),
+ background_color_(SK_ColorTRANSPARENT),
+ pixel_record_distance_(kPixelDistanceToRecord),
+ is_suitable_for_gpu_rasterization_(true) {
+ tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
+ SetMinContentsScale(min_contents_scale);
+ SetTileGridSize(tile_grid_size);
}
PicturePile::~PicturePile() {
@@ -159,43 +177,58 @@ PicturePile::~PicturePile() {
bool PicturePile::UpdateAndExpandInvalidation(
ContentLayerClient* painter,
Region* invalidation,
- SkColor background_color,
- bool contents_opaque,
- bool contents_fill_bounds_completely,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
- Picture::RecordingMode recording_mode,
- RenderingStatsInstrumentation* stats_instrumentation) {
- background_color_ = background_color;
- contents_opaque_ = contents_opaque;
- contents_fill_bounds_completely_ = contents_fill_bounds_completely;
+ RecordingSource::RecordingMode recording_mode) {
+ gfx::Rect interest_rect = visible_layer_rect;
+ interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_);
+ recorded_viewport_ = interest_rect;
+ recorded_viewport_.Intersect(gfx::Rect(layer_size));
+
+ bool updated = ApplyInvalidationAndResize(interest_rect, invalidation,
+ layer_size, frame_number);
+ std::vector<gfx::Rect> invalid_tiles;
+ GetInvalidTileRects(interest_rect, &invalid_tiles);
+ std::vector<gfx::Rect> record_rects;
+ ClusterTiles(invalid_tiles, &record_rects);
+
+ if (record_rects.empty())
+ return updated;
+
+ CreatePictures(painter, recording_mode, record_rects);
+
+ DetermineIfSolidColor();
+
+ has_any_recordings_ = true;
+ DCHECK(CanRasterSlowTileCheck(recorded_viewport_));
+ return true;
+}
+bool PicturePile::ApplyInvalidationAndResize(const gfx::Rect& interest_rect,
+ Region* invalidation,
+ const gfx::Size& layer_size,
+ int frame_number) {
bool updated = false;
- Region resize_invalidation;
- gfx::Size old_tiling_size = tiling_size();
+ Region synthetic_invalidation;
+ gfx::Size old_tiling_size = GetSize();
if (old_tiling_size != layer_size) {
tiling_.SetTilingSize(layer_size);
updated = true;
}
- gfx::Rect interest_rect = visible_layer_rect;
- interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_);
- recorded_viewport_ = interest_rect;
- recorded_viewport_.Intersect(gfx::Rect(tiling_size()));
-
gfx::Rect interest_rect_over_tiles =
tiling_.ExpandRectToTileBounds(interest_rect);
- gfx::Size min_tiling_size(
- std::min(tiling_size().width(), old_tiling_size.width()),
- std::min(tiling_size().height(), old_tiling_size.height()));
- gfx::Size max_tiling_size(
- std::max(tiling_size().width(), old_tiling_size.width()),
- std::max(tiling_size().height(), old_tiling_size.height()));
-
if (old_tiling_size != layer_size) {
+ gfx::Size min_tiling_size(
+ std::min(GetSize().width(), old_tiling_size.width()),
+ std::min(GetSize().height(), old_tiling_size.height()));
+ gfx::Size max_tiling_size(
+ std::max(GetSize().width(), old_tiling_size.width()),
+ std::max(GetSize().height(), old_tiling_size.height()));
+
has_any_recordings_ = false;
// Drop recordings that are outside the new or old layer bounds or that
@@ -213,12 +246,10 @@ bool PicturePile::UpdateAndExpandInvalidation(
min_toss_y =
tiling_.FirstBorderTileYIndexFromSrcCoord(min_tiling_size.height());
}
- for (PictureMap::const_iterator it = picture_map_.begin();
- it != picture_map_.end();
- ++it) {
- const PictureMapKey& key = it->first;
+ for (const auto& key_picture_pair : picture_map_) {
+ const PictureMapKey& key = key_picture_pair.first;
if (key.first < min_toss_x && key.second < min_toss_y) {
- has_any_recordings_ |= !!it->second.GetPicture();
+ has_any_recordings_ = true;
continue;
}
to_erase.push_back(key);
@@ -342,11 +373,11 @@ bool PicturePile::UpdateAndExpandInvalidation(
exposed_top,
exposed_left_until - exposed_left,
exposed_bottom - exposed_top);
- resize_invalidation.Union(left_rect);
- resize_invalidation.Union(right_rect);
- resize_invalidation.Union(top_rect);
- resize_invalidation.Union(bottom_rect);
- resize_invalidation.Union(exposed_rect);
+ synthetic_invalidation.Union(left_rect);
+ synthetic_invalidation.Union(right_rect);
+ synthetic_invalidation.Union(top_rect);
+ synthetic_invalidation.Union(bottom_rect);
+ synthetic_invalidation.Union(exposed_rect);
}
if (min_toss_y < tiling_.num_tiles_y()) {
// The same thing occurs here as in the case above, but the invalidation
@@ -378,20 +409,20 @@ bool PicturePile::UpdateAndExpandInvalidation(
exposed_top,
exposed_right - exposed_left,
exposed_top_until - exposed_top);
- resize_invalidation.Union(left_rect);
- resize_invalidation.Union(right_rect);
- resize_invalidation.Union(top_rect);
- resize_invalidation.Union(bottom_rect);
- resize_invalidation.Union(exposed_rect);
+ synthetic_invalidation.Union(left_rect);
+ synthetic_invalidation.Union(right_rect);
+ synthetic_invalidation.Union(top_rect);
+ synthetic_invalidation.Union(bottom_rect);
+ synthetic_invalidation.Union(exposed_rect);
}
}
// Detect cases where the full pile is invalidated, in this situation we
// can just drop/invalidate everything.
if (invalidation->Contains(gfx::Rect(old_tiling_size)) ||
- invalidation->Contains(gfx::Rect(tiling_size()))) {
- for (auto& it : picture_map_)
- updated = it.second.Invalidate(frame_number) || updated;
+ invalidation->Contains(gfx::Rect(GetSize()))) {
+ updated = !picture_map_.empty();
+ picture_map_.clear();
} else {
// Expand invalidation that is on tiles that aren't in the interest rect and
// will not be re-recorded below. These tiles are no longer valid and should
@@ -431,8 +462,9 @@ bool PicturePile::UpdateAndExpandInvalidation(
if (picture_it == picture_map_.end())
continue;
- // Inform the grid cell that it has been invalidated in this frame.
- updated = picture_it->second.Invalidate(frame_number) || updated;
+ updated = true;
+ picture_map_.erase(key);
+
// Invalidate drops the picture so the whole tile better be invalidated
// if it won't be re-recorded below.
DCHECK_IMPLIES(!tiling_.TileBounds(key.first, key.second)
@@ -444,107 +476,77 @@ bool PicturePile::UpdateAndExpandInvalidation(
invalidation->Union(invalidation_expanded_to_full_tiles);
}
- invalidation->Union(resize_invalidation);
+ invalidation->Union(synthetic_invalidation);
+ return updated;
+}
+void PicturePile::GetInvalidTileRects(const gfx::Rect& interest_rect,
+ std::vector<gfx::Rect>* invalid_tiles) {
// Make a list of all invalid tiles; we will attempt to
// cluster these into multiple invalidation regions.
- std::vector<gfx::Rect> invalid_tiles;
bool include_borders = true;
for (TilingData::Iterator it(&tiling_, interest_rect, include_borders); it;
++it) {
const PictureMapKey& key = it.index();
- PictureInfo& info = picture_map_[key];
-
- gfx::Rect rect = PaddedRect(key);
- int distance_to_visible =
- rect.ManhattanInternalDistance(visible_layer_rect);
-
- if (info.NeedsRecording(frame_number, distance_to_visible)) {
- gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
- invalid_tiles.push_back(tile);
- } else if (!info.GetPicture()) {
- if (recorded_viewport_.Intersects(rect)) {
- // Recorded viewport is just an optimization for a fully recorded
- // interest rect. In this case, a tile in that rect has declined
- // to be recorded (probably due to frequent invalidations).
- // TODO(enne): Shrink the recorded_viewport_ rather than clearing.
- recorded_viewport_ = gfx::Rect();
- }
-
- // If a tile in the interest rect is not recorded, the entire tile needs
- // to be considered invalid, so that we know not to keep around raster
- // tiles that intersect this recording tile.
- invalidation->Union(tiling_.TileBounds(it.index_x(), it.index_y()));
- }
+ if (picture_map_.find(key) == picture_map_.end())
+ invalid_tiles->push_back(tiling_.TileBounds(key.first, key.second));
}
+}
- std::vector<gfx::Rect> record_rects;
- ClusterTiles(invalid_tiles, &record_rects);
-
- if (record_rects.empty())
- return updated;
-
- for (std::vector<gfx::Rect>::iterator it = record_rects.begin();
- it != record_rects.end();
- it++) {
- gfx::Rect record_rect = *it;
- record_rect = PadRect(record_rect);
+void PicturePile::CreatePictures(ContentLayerClient* painter,
+ RecordingSource::RecordingMode recording_mode,
+ const std::vector<gfx::Rect>& record_rects) {
+ for (const auto& record_rect : record_rects) {
+ gfx::Rect padded_record_rect = PadRect(record_rect);
int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
scoped_refptr<Picture> picture;
- // Note: Currently, gathering of pixel refs when using a single
- // raster thread doesn't provide any benefit. This might change
- // in the future but we avoid it for now to reduce the cost of
- // Picture::Create.
- bool gather_pixel_refs = RasterWorkerPool::GetNumRasterThreads() > 1;
-
- {
- base::TimeDelta best_duration = base::TimeDelta::Max();
- for (int i = 0; i < repeat_count; i++) {
- base::TimeTicks start_time = stats_instrumentation->StartRecording();
- picture = Picture::Create(record_rect,
- painter,
- tile_grid_info_,
- gather_pixel_refs,
- recording_mode);
- // Note the '&&' with previous is-suitable state.
- // This means that once a picture-pile becomes unsuitable for gpu
- // rasterization due to some content, it will continue to be unsuitable
- // even if that content is replaced by gpu-friendly content.
- // This is an optimization to avoid iterating though all pictures in
- // the pile after each invalidation.
+ for (int i = 0; i < repeat_count; i++) {
+ picture = Picture::Create(padded_record_rect, painter, tile_grid_size_,
+ gather_pixel_refs_, recording_mode);
+ // Note the '&&' with previous is-suitable state.
+ // This means that once a picture-pile becomes unsuitable for gpu
+ // rasterization due to some content, it will continue to be unsuitable
+ // even if that content is replaced by gpu-friendly content.
+ // This is an optimization to avoid iterating though all pictures in
+ // the pile after each invalidation.
+ if (is_suitable_for_gpu_rasterization_) {
+ const char* reason = nullptr;
is_suitable_for_gpu_rasterization_ &=
- picture->IsSuitableForGpuRasterization();
- base::TimeDelta duration =
- stats_instrumentation->EndRecording(start_time);
- best_duration = std::min(duration, best_duration);
+ picture->IsSuitableForGpuRasterization(&reason);
+
+ if (!is_suitable_for_gpu_rasterization_) {
+ TRACE_EVENT_INSTANT1("cc", "GPU Rasterization Veto",
+ TRACE_EVENT_SCOPE_THREAD, "reason", reason);
+ }
}
- int recorded_pixel_count =
- picture->LayerRect().width() * picture->LayerRect().height();
- stats_instrumentation->AddRecord(best_duration, recorded_pixel_count);
}
bool found_tile_for_recorded_picture = false;
bool include_borders = true;
- for (TilingData::Iterator it(&tiling_, record_rect, include_borders); it;
- ++it) {
+ for (TilingData::Iterator it(&tiling_, padded_record_rect, include_borders);
+ it; ++it) {
const PictureMapKey& key = it.index();
gfx::Rect tile = PaddedRect(key);
- if (record_rect.Contains(tile)) {
- PictureInfo& info = picture_map_[key];
- info.SetPicture(picture);
+ if (padded_record_rect.Contains(tile)) {
+ picture_map_[key] = picture;
found_tile_for_recorded_picture = true;
}
}
- DetermineIfSolidColor();
DCHECK(found_tile_for_recorded_picture);
}
+}
- has_any_recordings_ = true;
- DCHECK(CanRasterSlowTileCheck(recorded_viewport_));
- return true;
+scoped_refptr<RasterSource> PicturePile::CreateRasterSource(
+ bool can_use_lcd_text) const {
+ return scoped_refptr<RasterSource>(
+ PicturePileImpl::CreateFromPicturePile(this, can_use_lcd_text));
+}
+
+gfx::Size PicturePile::GetSize() const {
+ return tiling_.tiling_size();
}
void PicturePile::SetEmptyBounds() {
@@ -552,6 +554,62 @@ void PicturePile::SetEmptyBounds() {
Clear();
}
+void PicturePile::SetMinContentsScale(float min_contents_scale) {
+ DCHECK(min_contents_scale);
+ if (min_contents_scale_ == min_contents_scale)
+ return;
+
+ // Picture contents are played back scaled. When the final contents scale is
+ // less than 1 (i.e. low res), then multiple recorded pixels will be used
+ // to raster one final pixel. To avoid splitting a final pixel across
+ // pictures (which would result in incorrect rasterization due to blending), a
+ // buffer margin is added so that any picture can be snapped to integral
+ // final pixels.
+ //
+ // For example, if a 1/4 contents scale is used, then that would be 3 buffer
+ // pixels, since that's the minimum number of pixels to add so that resulting
+ // content can be snapped to a four pixel aligned grid.
+ int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
+ buffer_pixels = std::max(0, buffer_pixels);
+ SetBufferPixels(buffer_pixels);
+ min_contents_scale_ = min_contents_scale;
+}
+
+void PicturePile::SetSlowdownRasterScaleFactor(int factor) {
+ slow_down_raster_scale_factor_for_debug_ = factor;
+}
+
+void PicturePile::SetGatherPixelRefs(bool gather_pixel_refs) {
+ gather_pixel_refs_ = gather_pixel_refs;
+}
+
+void PicturePile::SetBackgroundColor(SkColor background_color) {
+ background_color_ = background_color;
+}
+
+void PicturePile::SetRequiresClear(bool requires_clear) {
+ requires_clear_ = requires_clear;
+}
+
+bool PicturePile::IsSuitableForGpuRasterization() const {
+ return is_suitable_for_gpu_rasterization_;
+}
+
+void PicturePile::SetTileGridSize(const gfx::Size& tile_grid_size) {
+ DCHECK_GT(tile_grid_size.width(), 0);
+ DCHECK_GT(tile_grid_size.height(), 0);
+
+ tile_grid_size_ = tile_grid_size;
+}
+
+void PicturePile::SetUnsuitableForGpuRasterizationForTesting() {
+ is_suitable_for_gpu_rasterization_ = false;
+}
+
+gfx::Size PicturePile::GetTileGridSizeForTesting() const {
+ return tile_grid_size_;
+}
+
bool PicturePile::CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const {
bool include_borders = false;
for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
@@ -559,8 +617,6 @@ bool PicturePile::CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const {
PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
if (map_iter == picture_map_.end())
return false;
- if (!map_iter->second.GetPicture())
- return false;
}
return true;
}
@@ -574,7 +630,7 @@ void PicturePile::DetermineIfSolidColor() {
}
PictureMap::const_iterator it = picture_map_.begin();
- const Picture* picture = it->second.GetPicture();
+ const Picture* picture = it->second.get();
// Missing recordings due to frequent invalidations or being too far away
// from the interest rect will cause the a null picture to exist.
@@ -587,14 +643,42 @@ void PicturePile::DetermineIfSolidColor() {
// Make sure all of the mapped images point to the same picture.
for (++it; it != picture_map_.end(); ++it) {
- if (it->second.GetPicture() != picture)
+ if (it->second.get() != picture)
return;
}
- skia::AnalysisCanvas canvas(recorded_viewport_.width(),
- recorded_viewport_.height());
- canvas.translate(-recorded_viewport_.x(), -recorded_viewport_.y());
+
+ gfx::Size layer_size = GetSize();
+ skia::AnalysisCanvas canvas(layer_size.width(), layer_size.height());
+
picture->Raster(&canvas, nullptr, Region(), 1.0f);
is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
}
+gfx::Rect PicturePile::PaddedRect(const PictureMapKey& key) const {
+ gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
+ return PadRect(tile);
+}
+
+gfx::Rect PicturePile::PadRect(const gfx::Rect& rect) const {
+ gfx::Rect padded_rect = rect;
+ padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(),
+ -buffer_pixels());
+ return padded_rect;
+}
+
+void PicturePile::Clear() {
+ picture_map_.clear();
+ recorded_viewport_ = gfx::Rect();
+ has_any_recordings_ = false;
+ is_solid_color_ = false;
+}
+
+void PicturePile::SetBufferPixels(int new_buffer_pixels) {
+ if (new_buffer_pixels == buffer_pixels())
+ return;
+
+ Clear();
+ tiling_.SetBorderTexels(new_buffer_pixels);
+}
+
} // namespace cc
diff --git a/chromium/cc/playback/picture_pile.h b/chromium/cc/playback/picture_pile.h
new file mode 100644
index 00000000000..889e9f5d981
--- /dev/null
+++ b/chromium/cc/playback/picture_pile.h
@@ -0,0 +1,107 @@
+// Copyright 2012 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_PLAYBACK_PICTURE_PILE_H_
+#define CC_PLAYBACK_PICTURE_PILE_H_
+
+#include <bitset>
+#include <utility>
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "cc/base/tiling_data.h"
+#include "cc/playback/picture.h"
+
+namespace cc {
+class PicturePileImpl;
+
+class CC_EXPORT PicturePile : public RecordingSource {
+ public:
+ PicturePile(float min_contents_scale, const gfx::Size& tile_grid_size);
+ ~PicturePile() override;
+
+ // RecordingSource overrides.
+ bool UpdateAndExpandInvalidation(ContentLayerClient* painter,
+ Region* invalidation,
+ const gfx::Size& layer_size,
+ const gfx::Rect& visible_layer_rect,
+ int frame_number,
+ RecordingMode recording_mode) override;
+ scoped_refptr<RasterSource> CreateRasterSource(
+ bool can_use_lcd_text) const override;
+ gfx::Size GetSize() const final;
+ void SetEmptyBounds() override;
+ void SetSlowdownRasterScaleFactor(int factor) override;
+ void SetGatherPixelRefs(bool gather_pixel_refs) override;
+ void SetBackgroundColor(SkColor background_color) override;
+ void SetRequiresClear(bool requires_clear) override;
+ bool IsSuitableForGpuRasterization() const override;
+ void SetUnsuitableForGpuRasterizationForTesting() override;
+ gfx::Size GetTileGridSizeForTesting() const override;
+
+ typedef std::pair<int, int> PictureMapKey;
+ typedef base::hash_map<PictureMapKey, scoped_refptr<const Picture>>
+ PictureMap;
+
+ // An internal CanRaster check that goes to the picture_map rather than
+ // using the recorded_viewport hint.
+ bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const;
+
+ void Clear();
+
+ void SetMinContentsScale(float min_contents_scale);
+ void SetTileGridSize(const gfx::Size& tile_grid_size);
+
+ gfx::Rect PaddedRect(const PictureMapKey& key) const;
+ gfx::Rect PadRect(const gfx::Rect& rect) const;
+
+ int buffer_pixels() const { return tiling_.border_texels(); }
+
+ // A picture pile is a tiled set of pictures. The picture map is a map of tile
+ // indices to picture infos.
+ PictureMap picture_map_;
+ TilingData tiling_;
+
+ // If non-empty, all pictures tiles inside this rect are recorded. There may
+ // be recordings outside this rect, but everything inside the rect is
+ // recorded.
+ gfx::Rect recorded_viewport_;
+ float min_contents_scale_;
+ gfx::Size tile_grid_size_;
+ int slow_down_raster_scale_factor_for_debug_;
+ bool gather_pixel_refs_;
+ // A hint about whether there are any recordings. This may be a false
+ // positive.
+ bool has_any_recordings_;
+ bool clear_canvas_with_debug_color_;
+ bool requires_clear_;
+ bool is_solid_color_;
+ SkColor solid_color_;
+ SkColor background_color_;
+ int pixel_record_distance_;
+
+ private:
+ friend class PicturePileImpl;
+
+ void CreatePictures(ContentLayerClient* painter,
+ RecordingMode recording_mode,
+ const std::vector<gfx::Rect>& record_rects);
+ void GetInvalidTileRects(const gfx::Rect& interest_rect,
+ std::vector<gfx::Rect>* invalid_tiles);
+ bool ApplyInvalidationAndResize(const gfx::Rect& interest_rect,
+ Region* invalidation,
+ const gfx::Size& layer_size,
+ int frame_number);
+ void DetermineIfSolidColor();
+ void SetBufferPixels(int buffer_pixels);
+
+ bool is_suitable_for_gpu_rasterization_;
+
+ DISALLOW_COPY_AND_ASSIGN(PicturePile);
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_PICTURE_PILE_H_
diff --git a/chromium/cc/resources/picture_pile_impl.cc b/chromium/cc/playback/picture_pile_impl.cc
index de25c04721b..96c6f63addb 100644
--- a/chromium/cc/resources/picture_pile_impl.cc
+++ b/chromium/cc/playback/picture_pile_impl.cc
@@ -4,11 +4,13 @@
#include <algorithm>
#include <limits>
+#include <set>
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/region.h"
#include "cc/debug/debug_colors.h"
-#include "cc/resources/picture_pile_impl.h"
+#include "cc/playback/picture_pile_impl.h"
+#include "cc/playback/raster_source_helper.h"
#include "skia/ext/analysis_canvas.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -16,131 +18,94 @@
namespace cc {
-scoped_refptr<PicturePileImpl> PicturePileImpl::Create() {
- return make_scoped_refptr(new PicturePileImpl);
-}
-
-scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther(
- const PicturePileBase* other) {
- return make_scoped_refptr(new PicturePileImpl(other));
+scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromPicturePile(
+ const PicturePile* other,
+ bool can_use_lcd_text) {
+ return make_scoped_refptr(new PicturePileImpl(other, can_use_lcd_text));
}
PicturePileImpl::PicturePileImpl()
: background_color_(SK_ColorTRANSPARENT),
- contents_opaque_(false),
- contents_fill_bounds_completely_(false),
+ requires_clear_(true),
+ can_use_lcd_text_(true),
is_solid_color_(false),
solid_color_(SK_ColorTRANSPARENT),
has_any_recordings_(false),
- is_mask_(false),
clear_canvas_with_debug_color_(false),
min_contents_scale_(0.f),
slow_down_raster_scale_factor_for_debug_(0),
- likely_to_be_used_for_transform_animation_(false) {
+ should_attempt_to_use_distance_field_text_(false),
+ picture_memory_usage_(0) {
}
-PicturePileImpl::PicturePileImpl(const PicturePileBase* other)
+PicturePileImpl::PicturePileImpl(const PicturePile* other,
+ bool can_use_lcd_text)
: picture_map_(other->picture_map_),
tiling_(other->tiling_),
background_color_(other->background_color_),
- contents_opaque_(other->contents_opaque_),
- contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
+ requires_clear_(other->requires_clear_),
+ can_use_lcd_text_(can_use_lcd_text),
is_solid_color_(other->is_solid_color_),
solid_color_(other->solid_color_),
recorded_viewport_(other->recorded_viewport_),
has_any_recordings_(other->has_any_recordings_),
- is_mask_(other->is_mask_),
clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
min_contents_scale_(other->min_contents_scale_),
slow_down_raster_scale_factor_for_debug_(
other->slow_down_raster_scale_factor_for_debug_),
- likely_to_be_used_for_transform_animation_(false) {
+ should_attempt_to_use_distance_field_text_(false),
+ picture_memory_usage_(0) {
+ // Figure out the picture size upon construction.
+ base::hash_set<const Picture*> pictures_seen;
+ for (const auto& map_value : picture_map_) {
+ const Picture* picture = map_value.second.get();
+ if (pictures_seen.insert(picture).second)
+ picture_memory_usage_ += picture->ApproximateMemoryUsage();
+ }
+}
+
+PicturePileImpl::PicturePileImpl(const PicturePileImpl* other,
+ bool can_use_lcd_text)
+ : picture_map_(other->picture_map_),
+ tiling_(other->tiling_),
+ background_color_(other->background_color_),
+ requires_clear_(other->requires_clear_),
+ can_use_lcd_text_(can_use_lcd_text),
+ is_solid_color_(other->is_solid_color_),
+ solid_color_(other->solid_color_),
+ recorded_viewport_(other->recorded_viewport_),
+ has_any_recordings_(other->has_any_recordings_),
+ clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
+ min_contents_scale_(other->min_contents_scale_),
+ slow_down_raster_scale_factor_for_debug_(
+ other->slow_down_raster_scale_factor_for_debug_),
+ should_attempt_to_use_distance_field_text_(
+ other->should_attempt_to_use_distance_field_text_),
+ picture_memory_usage_(other->picture_memory_usage_) {
}
PicturePileImpl::~PicturePileImpl() {
}
-void PicturePileImpl::RasterDirect(SkCanvas* canvas,
- const gfx::Rect& canvas_rect,
- float contents_scale) const {
- RasterCommon(canvas,
- NULL,
- canvas_rect,
- contents_scale,
- false);
+void PicturePileImpl::PlaybackToSharedCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale);
}
void PicturePileImpl::RasterForAnalysis(skia::AnalysisCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const {
- RasterCommon(canvas, canvas, canvas_rect, contents_scale, true);
+ RasterCommon(canvas, canvas, canvas_rect, contents_scale);
}
void PicturePileImpl::PlaybackToCanvas(SkCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const {
- canvas->discard();
- if (clear_canvas_with_debug_color_) {
- // Any non-painted areas in the content bounds will be left in this color.
- canvas->clear(DebugColors::NonPaintedFillColor());
- }
-
- // If this picture has opaque contents, it is guaranteeing that it will
- // draw an opaque rect the size of the layer. If it is not, then we must
- // clear this canvas ourselves.
- if (contents_opaque_ || contents_fill_bounds_completely_) {
- // Even if completely covered, for rasterizations that touch the edge of the
- // layer, we also need to raster the background color underneath the last
- // texel (since the recording won't cover it) and outside the last texel
- // (due to linear filtering when using this texture).
- gfx::Rect content_tiling_rect = gfx::ToEnclosingRect(
- gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale));
-
- // The final texel of content may only be partially covered by a
- // rasterization; this rect represents the content rect that is fully
- // covered by content.
- gfx::Rect deflated_content_tiling_rect = content_tiling_rect;
- deflated_content_tiling_rect.Inset(0, 0, 1, 1);
- if (!deflated_content_tiling_rect.Contains(canvas_rect)) {
- if (clear_canvas_with_debug_color_) {
- // Any non-painted areas outside of the content bounds are left in
- // this color. If this is seen then it means that cc neglected to
- // rerasterize a tile that used to intersect with the content rect
- // after the content bounds grew.
- canvas->save();
- canvas->translate(-canvas_rect.x(), -canvas_rect.y());
- canvas->clipRect(gfx::RectToSkRect(content_tiling_rect),
- SkRegion::kDifference_Op);
- canvas->drawColor(DebugColors::MissingResizeInvalidations(),
- SkXfermode::kSrc_Mode);
- canvas->restore();
- }
-
- // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X
- // faster than clearing, so special case this.
- canvas->save();
- canvas->translate(-canvas_rect.x(), -canvas_rect.y());
- gfx::Rect inflated_content_tiling_rect = content_tiling_rect;
- inflated_content_tiling_rect.Inset(0, 0, -1, -1);
- canvas->clipRect(gfx::RectToSkRect(inflated_content_tiling_rect),
- SkRegion::kReplace_Op);
- canvas->clipRect(gfx::RectToSkRect(deflated_content_tiling_rect),
- SkRegion::kDifference_Op);
- canvas->drawColor(background_color_, SkXfermode::kSrc_Mode);
- canvas->restore();
- }
- } else {
- TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
- // Clearing is about ~4x faster than drawing a rect even if the content
- // isn't covering a majority of the canvas.
- canvas->clear(SK_ColorTRANSPARENT);
- }
-
- RasterCommon(canvas,
- NULL,
- canvas_rect,
- contents_scale,
- false);
+ RasterSourceHelper::PrepareForPlaybackToCanvas(
+ canvas, canvas_rect, gfx::Rect(tiling_.tiling_size()), contents_scale,
+ background_color_, clear_canvas_with_debug_color_, requires_clear_);
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale);
}
void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect,
@@ -180,10 +145,8 @@ void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect,
PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
if (map_iter == picture_map_.end())
continue;
- const PictureInfo& info = map_iter->second;
- const Picture* picture = info.GetPicture();
- if (!picture)
- continue;
+ const Picture* picture = map_iter->second.get();
+ DCHECK(picture);
// This is intentionally *enclosed* rect, so that the clip is aligned on
// integral post-scale content pixels and does not extend past the edges
@@ -238,12 +201,10 @@ void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect,
}
}
-void PicturePileImpl::RasterCommon(
- SkCanvas* canvas,
- SkDrawPictureCallback* callback,
- const gfx::Rect& canvas_rect,
- float contents_scale,
- bool is_analysis) const {
+void PicturePileImpl::RasterCommon(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
DCHECK(contents_scale >= min_contents_scale_);
canvas->translate(-canvas_rect.x(), -canvas_rect.y());
@@ -306,11 +267,16 @@ skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() {
recorder.beginRecording(tiling_rect.width(), tiling_rect.height());
if (!tiling_rect.IsEmpty())
PlaybackToCanvas(canvas, tiling_rect, 1.0);
- skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
+ skia::RefPtr<SkPicture> picture =
+ skia::AdoptRef(recorder.endRecordingAsPicture());
return picture;
}
+size_t PicturePileImpl::GetPictureMemoryUsage() const {
+ return picture_memory_usage_;
+}
+
void PicturePileImpl::PerformSolidColorAnalysis(
const gfx::Rect& content_rect,
float contents_scale,
@@ -359,6 +325,23 @@ bool PicturePileImpl::CoversRect(const gfx::Rect& content_rect,
return CanRasterSlowTileCheck(layer_rect);
}
+gfx::Size PicturePileImpl::GetSize() const {
+ return tiling_.tiling_size();
+}
+
+bool PicturePileImpl::IsSolidColor() const {
+ return is_solid_color_;
+}
+
+SkColor PicturePileImpl::GetSolidColor() const {
+ DCHECK(IsSolidColor());
+ return solid_color_;
+}
+
+bool PicturePileImpl::HasRecordings() const {
+ return has_any_recordings_;
+}
+
gfx::Rect PicturePileImpl::PaddedRect(const PictureMapKey& key) const {
gfx::Rect padded_rect = tiling_.TileBounds(key.first, key.second);
padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(),
@@ -374,17 +357,20 @@ bool PicturePileImpl::CanRasterSlowTileCheck(
PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
if (map_iter == picture_map_.end())
return false;
- if (!map_iter->second.GetPicture())
- return false;
}
return true;
}
-bool PicturePileImpl::SuitableForDistanceFieldText() const {
- return likely_to_be_used_for_transform_animation_;
+void PicturePileImpl::SetShouldAttemptToUseDistanceFieldText() {
+ should_attempt_to_use_distance_field_text_ = true;
+}
+
+bool PicturePileImpl::ShouldAttemptToUseDistanceFieldText() const {
+ return should_attempt_to_use_distance_field_text_;
}
-void PicturePileImpl::AsValueInto(base::debug::TracedValue* pictures) const {
+void PicturePileImpl::AsValueInto(
+ base::trace_event::TracedValue* pictures) const {
gfx::Rect tiling_rect(tiling_.tiling_size());
std::set<const void*> appended_pictures;
bool include_borders = true;
@@ -394,14 +380,25 @@ void PicturePileImpl::AsValueInto(base::debug::TracedValue* pictures) const {
if (map_iter == picture_map_.end())
continue;
- const Picture* picture = map_iter->second.GetPicture();
- if (picture && (appended_pictures.count(picture) == 0)) {
+ const Picture* picture = map_iter->second.get();
+ if (appended_pictures.count(picture) == 0) {
appended_pictures.insert(picture);
TracedValue::AppendIDRef(picture, pictures);
}
}
}
+bool PicturePileImpl::CanUseLCDText() const {
+ return can_use_lcd_text_;
+}
+
+scoped_refptr<RasterSource> PicturePileImpl::CreateCloneWithoutLCDText() const {
+ DCHECK(CanUseLCDText());
+ bool can_use_lcd_text = false;
+ return scoped_refptr<RasterSource>(
+ new PicturePileImpl(this, can_use_lcd_text));
+}
+
PicturePileImpl::PixelRefIterator::PixelRefIterator(
const gfx::Rect& content_rect,
float contents_scale,
@@ -440,13 +437,13 @@ void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() {
if (it == picture_pile_->picture_map_.end())
continue;
- const Picture* picture = it->second.GetPicture();
- if (!picture || (processed_pictures_.count(picture) != 0) ||
+ const Picture* picture = it->second.get();
+ if ((processed_pictures_.count(picture) != 0) ||
!picture->WillPlayBackBitmaps())
continue;
processed_pictures_.insert(picture);
- pixel_ref_iterator_ = Picture::PixelRefIterator(layer_rect_, picture);
+ pixel_ref_iterator_ = picture->GetPixelRefMapIterator(layer_rect_);
if (pixel_ref_iterator_)
break;
}
@@ -454,11 +451,9 @@ void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() {
void PicturePileImpl::DidBeginTracing() {
std::set<const void*> processed_pictures;
- for (PictureMap::iterator it = picture_map_.begin();
- it != picture_map_.end();
- ++it) {
- const Picture* picture = it->second.GetPicture();
- if (picture && (processed_pictures.count(picture) == 0)) {
+ for (const auto& map_pair : picture_map_) {
+ const Picture* picture = map_pair.second.get();
+ if (processed_pictures.count(picture) == 0) {
picture->EmitTraceSnapshot();
processed_pictures.insert(picture);
}
diff --git a/chromium/cc/resources/picture_pile_impl.h b/chromium/cc/playback/picture_pile_impl.h
index 479846bb0ff..e8be323225a 100644
--- a/chromium/cc/resources/picture_pile_impl.h
+++ b/chromium/cc/playback/picture_pile_impl.h
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_PICTURE_PILE_IMPL_H_
-#define CC_RESOURCES_PICTURE_PILE_IMPL_H_
+#ifndef CC_PLAYBACK_PICTURE_PILE_IMPL_H_
+#define CC_PLAYBACK_PICTURE_PILE_IMPL_H_
-#include <list>
#include <map>
#include <set>
#include <vector>
@@ -13,20 +12,27 @@
#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/debug/rendering_stats_instrumentation.h"
-#include "cc/resources/picture_pile_base.h"
-#include "cc/resources/raster_source.h"
+#include "cc/playback/picture_pile.h"
+#include "cc/playback/pixel_ref_map.h"
+#include "cc/playback/raster_source.h"
#include "skia/ext/analysis_canvas.h"
#include "skia/ext/refptr.h"
-#include "third_party/skia/include/core/SkPicture.h"
+
+class SkCanvas;
+class SkPicture;
+class SkPixelRef;
+
+namespace gfx {
+class Rect;
+}
namespace cc {
-// TODO(vmpstr): Clean up PicturePileBase and make it a member.
class CC_EXPORT PicturePileImpl : public RasterSource {
public:
- static scoped_refptr<PicturePileImpl> Create();
- static scoped_refptr<PicturePileImpl> CreateFromOther(
- const PicturePileBase* other);
+ static scoped_refptr<PicturePileImpl> CreateFromPicturePile(
+ const PicturePile* other,
+ bool can_use_lcd_text);
// RasterSource overrides. See RasterSource header for full description.
// When slow-down-raster-scale-factor is set to a value greater than 1, the
@@ -35,6 +41,9 @@ class CC_EXPORT PicturePileImpl : public RasterSource {
void PlaybackToCanvas(SkCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const override;
+ void PlaybackToSharedCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const override;
void PerformSolidColorAnalysis(
const gfx::Rect& content_rect,
float contents_scale,
@@ -44,28 +53,20 @@ class CC_EXPORT PicturePileImpl : public RasterSource {
std::vector<SkPixelRef*>* pixel_refs) const override;
bool CoversRect(const gfx::Rect& content_rect,
float contents_scale) const override;
- bool SuitableForDistanceFieldText() const override;
-
- // Raster into the canvas without applying clips.
- void RasterDirect(SkCanvas* canvas,
- const gfx::Rect& canvas_rect,
- float contents_scale) const;
+ void SetShouldAttemptToUseDistanceFieldText() override;
+ bool ShouldAttemptToUseDistanceFieldText() const override;
+ gfx::Size GetSize() const override;
+ bool IsSolidColor() const override;
+ SkColor GetSolidColor() const override;
+ bool HasRecordings() const override;
+ bool CanUseLCDText() const override;
+ scoped_refptr<RasterSource> CreateCloneWithoutLCDText() const override;
// Tracing functionality.
- void DidBeginTracing();
- skia::RefPtr<SkPicture> GetFlattenedPicture();
-
- void set_likely_to_be_used_for_transform_animation() {
- likely_to_be_used_for_transform_animation_ = true;
- }
-
- gfx::Size tiling_size() const { return tiling_.tiling_size(); }
- bool is_solid_color() const { return is_solid_color_; }
- SkColor solid_color() const { return solid_color_; }
- // If this pile contains any valid recordings. May have false positives.
- bool HasRecordings() const { return has_any_recordings_; }
- void AsValueInto(base::debug::TracedValue* array) const;
- bool is_mask() const { return is_mask_; }
+ void DidBeginTracing() override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+ skia::RefPtr<SkPicture> GetFlattenedPicture() override;
+ size_t GetPictureMemoryUsage() const override;
// Iterator used to return SkPixelRefs from this picture pile.
// Public for testing.
@@ -87,7 +88,7 @@ class CC_EXPORT PicturePileImpl : public RasterSource {
const PicturePileImpl* picture_pile_;
gfx::Rect layer_rect_;
TilingData::Iterator tile_iterator_;
- Picture::PixelRefIterator pixel_ref_iterator_;
+ PixelRefMap::Iterator pixel_ref_iterator_;
std::set<const void*> processed_pictures_;
};
@@ -95,31 +96,35 @@ class CC_EXPORT PicturePileImpl : public RasterSource {
friend class PicturePile;
friend class PixelRefIterator;
- // TODO(vmpstr): Change this when pictures are split from invalidation info,
- // and when PicturePileBase goes away.
- using PictureMapKey = PicturePileBase::PictureMapKey;
- using PictureMap = PicturePileBase::PictureMap;
- using PictureInfo = PicturePileBase::PictureInfo;
+ using PictureMapKey = PicturePile::PictureMapKey;
+ using PictureMap = PicturePile::PictureMap;
PicturePileImpl();
- explicit PicturePileImpl(const PicturePileBase* other);
+ explicit PicturePileImpl(const PicturePile* other, bool can_use_lcd_text);
+ explicit PicturePileImpl(const PicturePileImpl* other, bool can_use_lcd_text);
~PicturePileImpl() override;
int buffer_pixels() const { return tiling_.border_texels(); }
- PictureMap picture_map_;
- TilingData tiling_;
- SkColor background_color_;
- bool contents_opaque_;
- bool contents_fill_bounds_completely_;
- bool is_solid_color_;
- SkColor solid_color_;
- gfx::Rect recorded_viewport_;
- bool has_any_recordings_;
- bool is_mask_;
- bool clear_canvas_with_debug_color_;
- float min_contents_scale_;
- int slow_down_raster_scale_factor_for_debug_;
+ // These members are const as this raster source may be in use on another
+ // thread and so should not be touched after construction.
+ const PictureMap picture_map_;
+ const TilingData tiling_;
+ const SkColor background_color_;
+ const bool requires_clear_;
+ const bool can_use_lcd_text_;
+ const bool is_solid_color_;
+ const SkColor solid_color_;
+ const gfx::Rect recorded_viewport_;
+ const bool has_any_recordings_;
+ const bool clear_canvas_with_debug_color_;
+ const float min_contents_scale_;
+ const int slow_down_raster_scale_factor_for_debug_;
+ // TODO(enne/vmiura): this has a read/write race between raster and compositor
+ // threads with multi-threaded Ganesh. Make this const or remove it.
+ bool should_attempt_to_use_distance_field_text_;
+
+ size_t picture_memory_usage_;
private:
typedef std::map<const Picture*, Region> PictureRegionMap;
@@ -135,12 +140,10 @@ class CC_EXPORT PicturePileImpl : public RasterSource {
float contents_scale,
PictureRegionMap* result) const;
- void RasterCommon(
- SkCanvas* canvas,
- SkDrawPictureCallback* callback,
- const gfx::Rect& canvas_rect,
- float contents_scale,
- bool is_analysis) const;
+ void RasterCommon(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const;
// An internal CanRaster check that goes to the picture_map rather than
// using the recorded_viewport hint.
@@ -148,11 +151,9 @@ class CC_EXPORT PicturePileImpl : public RasterSource {
gfx::Rect PaddedRect(const PictureMapKey& key) const;
- bool likely_to_be_used_for_transform_animation_;
-
DISALLOW_COPY_AND_ASSIGN(PicturePileImpl);
};
} // namespace cc
-#endif // CC_RESOURCES_PICTURE_PILE_IMPL_H_
+#endif // CC_PLAYBACK_PICTURE_PILE_IMPL_H_
diff --git a/chromium/cc/resources/picture_pile_impl_perftest.cc b/chromium/cc/playback/picture_pile_impl_perftest.cc
index 7e24724197c..a70fe68ebde 100644
--- a/chromium/cc/resources/picture_pile_impl_perftest.cc
+++ b/chromium/cc/playback/picture_pile_impl_perftest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/picture_pile_impl.h"
+#include "cc/playback/picture_pile_impl.h"
#include "cc/debug/lap_timer.h"
#include "cc/test/fake_picture_pile_impl.h"
diff --git a/chromium/cc/resources/picture_pile_impl_unittest.cc b/chromium/cc/playback/picture_pile_impl_unittest.cc
index 6dcf740e1ab..14b06eecd5d 100644
--- a/chromium/cc/resources/picture_pile_impl_unittest.cc
+++ b/chromium/cc/playback/picture_pile_impl_unittest.cc
@@ -19,21 +19,25 @@ TEST(PicturePileImplTest, AnalyzeIsSolidUnscaled) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_ptr<FakePicturePile> recording_source =
+ FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
- SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
SkPaint solid_paint;
+ SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
solid_paint.setColor(solid_color);
SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67);
SkPaint non_solid_paint;
non_solid_paint.setColor(non_solid_color);
- pile->add_draw_rect_with_paint(gfx::Rect(0, 0, 400, 400), solid_paint);
- pile->RerecordPile();
+ recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 400, 400),
+ solid_paint);
+ recording_source->Rerecord();
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
- // Ensure everything is solid
+ // Ensure everything is solid.
for (int y = 0; y <= 300; y += 100) {
for (int x = 0; x <= 300; x += 100) {
RasterSource::SolidColorAnalysis analysis;
@@ -44,9 +48,11 @@ TEST(PicturePileImplTest, AnalyzeIsSolidUnscaled) {
}
}
- // One pixel non solid
- pile->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1), non_solid_paint);
- pile->RerecordPile();
+ // Add one non-solid pixel and recreate the raster source.
+ recording_source->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1),
+ non_solid_paint);
+ recording_source->Rerecord();
+ pile = FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
RasterSource::SolidColorAnalysis analysis;
pile->PerformSolidColorAnalysis(gfx::Rect(0, 0, 100, 100), 1.0, &analysis);
@@ -56,7 +62,7 @@ TEST(PicturePileImplTest, AnalyzeIsSolidUnscaled) {
EXPECT_TRUE(analysis.is_solid_color);
EXPECT_EQ(analysis.solid_color, solid_color);
- // Boundaries should be clipped
+ // Boundaries should be clipped.
analysis.is_solid_color = false;
pile->PerformSolidColorAnalysis(gfx::Rect(350, 0, 100, 100), 1.0, &analysis);
EXPECT_TRUE(analysis.is_solid_color);
@@ -78,8 +84,8 @@ TEST(PicturePileImplTest, AnalyzeIsSolidScaled) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_ptr<FakePicturePile> recording_source =
+ FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
SkPaint solid_paint;
@@ -89,10 +95,14 @@ TEST(PicturePileImplTest, AnalyzeIsSolidScaled) {
SkPaint non_solid_paint;
non_solid_paint.setColor(non_solid_color);
- pile->add_draw_rect_with_paint(gfx::Rect(0, 0, 400, 400), solid_paint);
- pile->RerecordPile();
+ recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 400, 400),
+ solid_paint);
+ recording_source->Rerecord();
- // Ensure everything is solid
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
+
+ // Ensure everything is solid.
for (int y = 0; y <= 30; y += 10) {
for (int x = 0; x <= 30; x += 10) {
RasterSource::SolidColorAnalysis analysis;
@@ -103,9 +113,11 @@ TEST(PicturePileImplTest, AnalyzeIsSolidScaled) {
}
}
- // One pixel non solid
- pile->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1), non_solid_paint);
- pile->RerecordPile();
+ // Add one non-solid pixel and recreate the raster source.
+ recording_source->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1),
+ non_solid_paint);
+ recording_source->Rerecord();
+ pile = FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
RasterSource::SolidColorAnalysis analysis;
pile->PerformSolidColorAnalysis(gfx::Rect(0, 0, 10, 10), 0.1f, &analysis);
@@ -115,7 +127,7 @@ TEST(PicturePileImplTest, AnalyzeIsSolidScaled) {
EXPECT_TRUE(analysis.is_solid_color);
EXPECT_EQ(analysis.solid_color, solid_color);
- // Boundaries should be clipped
+ // Boundaries should be clipped.
analysis.is_solid_color = false;
pile->PerformSolidColorAnalysis(gfx::Rect(35, 0, 10, 10), 0.1f, &analysis);
EXPECT_TRUE(analysis.is_solid_color);
@@ -147,253 +159,12 @@ TEST(PicturePileImplTest, AnalyzeIsSolidEmpty) {
EXPECT_EQ(analysis.solid_color, SkColorSetARGB(0, 0, 0, 0));
}
-TEST(PicturePileImplTest, PixelRefIteratorEmpty) {
- gfx::Size tile_size(128, 128);
- gfx::Size layer_bounds(256, 256);
-
- // Create a filled pile with no recording.
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
- // Tile sized iterators.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 128, 128), 1.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 256, 256), 2.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 64, 64), 0.5, pile.get());
- EXPECT_FALSE(iterator);
- }
- // Shifted tile sized iterators.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(140, 140, 128, 128), 1.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(280, 280, 256, 256), 2.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(70, 70, 64, 64), 0.5, pile.get());
- EXPECT_FALSE(iterator);
- }
- // Layer sized iterators.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 256, 256), 1.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 512, 512), 2.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 128, 128), 0.5, pile.get());
- EXPECT_FALSE(iterator);
- }
-}
-
-TEST(PicturePileImplTest, PixelRefIteratorNoDiscardableRefs) {
- gfx::Size tile_size(128, 128);
- gfx::Size layer_bounds(256, 256);
-
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
- SkPaint simple_paint;
- simple_paint.setColor(SkColorSetARGB(255, 12, 23, 34));
-
- SkBitmap non_discardable_bitmap;
- CreateBitmap(gfx::Size(128, 128), "notdiscardable", &non_discardable_bitmap);
-
- pile->add_draw_rect_with_paint(gfx::Rect(0, 0, 256, 256), simple_paint);
- pile->add_draw_rect_with_paint(gfx::Rect(128, 128, 512, 512), simple_paint);
- pile->add_draw_rect_with_paint(gfx::Rect(512, 0, 256, 256), simple_paint);
- pile->add_draw_rect_with_paint(gfx::Rect(0, 512, 256, 256), simple_paint);
- pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(128, 0));
- pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 128));
- pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(150, 150));
-
- pile->RerecordPile();
-
- // Tile sized iterators.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 128, 128), 1.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 256, 256), 2.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 64, 64), 0.5, pile.get());
- EXPECT_FALSE(iterator);
- }
- // Shifted tile sized iterators.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(140, 140, 128, 128), 1.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(280, 280, 256, 256), 2.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(70, 70, 64, 64), 0.5, pile.get());
- EXPECT_FALSE(iterator);
- }
- // Layer sized iterators.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 256, 256), 1.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 512, 512), 2.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 128, 128), 0.5, pile.get());
- EXPECT_FALSE(iterator);
- }
-}
-
-TEST(PicturePileImplTest, PixelRefIteratorDiscardableRefs) {
- gfx::Size tile_size(128, 128);
- gfx::Size layer_bounds(256, 256);
-
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
- SkBitmap discardable_bitmap[2][2];
- CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][0]);
- CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][0]);
- CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][1]);
-
- // Discardable pixel refs are found in the following cells:
- // |---|---|
- // | x | |
- // |---|---|
- // | x | x |
- // |---|---|
- pile->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
- pile->add_draw_bitmap(discardable_bitmap[1][0], gfx::Point(0, 130));
- pile->add_draw_bitmap(discardable_bitmap[1][1], gfx::Point(140, 140));
-
- pile->RerecordPile();
-
- // Tile sized iterators. These should find only one pixel ref.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 128, 128), 1.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 256, 256), 2.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 64, 64), 0.5, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- // Shifted tile sized iterators. These should find only one pixel ref.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(140, 140, 128, 128), 1.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(280, 280, 256, 256), 2.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(70, 70, 64, 64), 0.5, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- // Ensure there's no discardable pixel refs in the empty cell
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(140, 0, 128, 128), 1.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- // Layer sized iterators. These should find all 3 pixel refs.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 256, 256), 1.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][0].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 512, 512), 2.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][0].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 128, 128), 0.5, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][0].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
-}
-
TEST(PicturePileImplTest, PixelRefIteratorDiscardableRefsOneTile) {
gfx::Size tile_size(256, 256);
gfx::Size layer_bounds(512, 512);
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_ptr<FakePicturePile> recording_source =
+ FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
SkBitmap discardable_bitmap[2][2];
CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][0]);
@@ -406,11 +177,16 @@ TEST(PicturePileImplTest, PixelRefIteratorDiscardableRefsOneTile) {
// |---|---|
// | | x |
// |---|---|
- pile->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
- pile->add_draw_bitmap(discardable_bitmap[0][1], gfx::Point(260, 0));
- pile->add_draw_bitmap(discardable_bitmap[1][1], gfx::Point(260, 260));
+ recording_source->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
+ recording_source->add_draw_bitmap(discardable_bitmap[0][1],
+ gfx::Point(260, 0));
+ recording_source->add_draw_bitmap(discardable_bitmap[1][1],
+ gfx::Point(260, 260));
+ recording_source->SetGatherPixelRefs(true);
+ recording_source->Rerecord();
- pile->RerecordPile();
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
// Tile sized iterators. These should find only one pixel ref.
{
@@ -519,147 +295,31 @@ TEST(PicturePileImplTest, PixelRefIteratorDiscardableRefsOneTile) {
EXPECT_FALSE(++copy);
}
-TEST(PicturePileImplTest, PixelRefIteratorDiscardableRefsBaseNonDiscardable) {
- gfx::Size tile_size(256, 256);
- gfx::Size layer_bounds(512, 512);
-
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
- SkBitmap non_discardable_bitmap;
- CreateBitmap(gfx::Size(512, 512), "notdiscardable", &non_discardable_bitmap);
-
- SkBitmap discardable_bitmap[2][2];
- CreateBitmap(gfx::Size(128, 128), "discardable", &discardable_bitmap[0][0]);
- CreateBitmap(gfx::Size(128, 128), "discardable", &discardable_bitmap[0][1]);
- CreateBitmap(gfx::Size(128, 128), "discardable", &discardable_bitmap[1][1]);
-
- // One large non-discardable bitmap covers the whole grid.
- // Discardable pixel refs are found in the following cells:
- // |---|---|
- // | x | x |
- // |---|---|
- // | | x |
- // |---|---|
- pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 0));
- pile->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
- pile->add_draw_bitmap(discardable_bitmap[0][1], gfx::Point(260, 0));
- pile->add_draw_bitmap(discardable_bitmap[1][1], gfx::Point(260, 260));
-
- pile->RerecordPile();
-
- // Tile sized iterators. These should find only one pixel ref.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 256, 256), 1.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 512, 512), 2.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 128, 128), 0.5, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- // Shifted tile sized iterators. These should find only one pixel ref.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(260, 260, 256, 256), 1.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(520, 520, 512, 512), 2.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(130, 130, 128, 128), 0.5, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- // Ensure there's no discardable pixel refs in the empty cell
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 256, 256, 256), 1.0, pile.get());
- EXPECT_FALSE(iterator);
- }
- // Layer sized iterators. These should find three pixel ref.
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 512, 512), 1.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 1024, 1024), 2.0, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
- {
- PicturePileImpl::PixelRefIterator iterator(
- gfx::Rect(0, 0, 256, 256), 0.5, pile.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
- EXPECT_FALSE(++iterator);
- }
-}
-
-class FullContentsTest : public ::testing::TestWithParam<bool> {};
-
-TEST_P(FullContentsTest, RasterFullContents) {
+TEST(PicturePileImplTest, RasterFullContents) {
gfx::Size tile_size(1000, 1000);
gfx::Size layer_bounds(3, 5);
float contents_scale = 1.5f;
float raster_divisions = 2.f;
- // Param in this case is whether the content is fully opaque
- // or just filled completely. For this test they should behave the same.
- bool contents_opaque = GetParam();
- bool fills_content = !GetParam();
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_ptr<FakePicturePile> recording_source =
+ FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
+ recording_source->SetBackgroundColor(SK_ColorBLACK);
+ recording_source->SetIsSolidColor(false);
+ recording_source->SetRequiresClear(false);
+ recording_source->SetClearCanvasWithDebugColor(false);
+
// Because the caller sets content opaque, it also promises that it
// has at least filled in layer_bounds opaquely.
SkPaint white_paint;
white_paint.setColor(SK_ColorWHITE);
- pile->add_draw_rect_with_paint(gfx::Rect(layer_bounds), white_paint);
+ recording_source->add_draw_rect_with_paint(gfx::Rect(layer_bounds),
+ white_paint);
- pile->SetMinContentsScale(contents_scale);
- pile->set_background_color(SK_ColorBLACK);
- pile->set_contents_opaque(contents_opaque);
- pile->set_contents_fill_bounds_completely(fills_content);
- pile->set_clear_canvas_with_debug_color(false);
- pile->RerecordPile();
+ recording_source->SetMinContentsScale(contents_scale);
+ recording_source->Rerecord();
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
gfx::Size content_bounds(
gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)));
@@ -705,23 +365,21 @@ TEST_P(FullContentsTest, RasterFullContents) {
}
}
-INSTANTIATE_TEST_CASE_P(PicturePileImpl,
- FullContentsTest,
- ::testing::Values(false, true));
-
TEST(PicturePileImpl, RasterContentsTransparent) {
gfx::Size tile_size(1000, 1000);
gfx::Size layer_bounds(5, 3);
float contents_scale = 0.5f;
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- pile->set_background_color(SK_ColorTRANSPARENT);
- pile->set_contents_opaque(false);
- pile->SetMinContentsScale(contents_scale);
- pile->set_clear_canvas_with_debug_color(false);
- pile->RerecordPile();
+ scoped_ptr<FakePicturePile> recording_source =
+ FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
+ recording_source->SetBackgroundColor(SK_ColorTRANSPARENT);
+ recording_source->SetRequiresClear(true);
+ recording_source->SetMinContentsScale(contents_scale);
+ recording_source->SetClearCanvasWithDebugColor(false);
+ recording_source->Rerecord();
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
gfx::Size content_bounds(
gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)));
@@ -754,21 +412,24 @@ TEST_P(OverlapTest, NoOverlap) {
// Pick an opaque color to not have to deal with premultiplication off-by-one.
SkColor test_color = SkColorSetARGB(255, 45, 56, 67);
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- pile->set_background_color(SK_ColorTRANSPARENT);
- pile->set_contents_opaque(false);
- pile->SetMinContentsScale(MinContentsScale());
- pile->set_clear_canvas_with_debug_color(true);
+ scoped_ptr<FakePicturePile> recording_source =
+ FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
+ recording_source->SetBackgroundColor(SK_ColorTRANSPARENT);
+ recording_source->SetRequiresClear(true);
+ recording_source->SetMinContentsScale(MinContentsScale());
+ recording_source->SetClearCanvasWithDebugColor(true);
+
SkPaint color_paint;
color_paint.setColor(test_color);
// Additive paint, so that if two paints overlap, the color will change.
color_paint.setXfermodeMode(SkXfermode::kPlus_Mode);
// Paint outside the layer to make sure that blending works.
- pile->add_draw_rect_with_paint(gfx::RectF(bigger_than_layer_bounds),
- color_paint);
- pile->RerecordPile();
+ recording_source->add_draw_rect_with_paint(
+ gfx::RectF(bigger_than_layer_bounds), color_paint);
+ recording_source->Rerecord();
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
gfx::Size content_bounds(
gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)));
@@ -804,25 +465,34 @@ TEST(PicturePileImplTest, PixelRefIteratorBorders) {
gfx::Size tile_size(128, 128);
gfx::Size layer_bounds(320, 128);
- // Fake picture pile impl uses a tile grid the size of the tile. So,
+ // Fake picture pile uses a tile grid the size of the tile. So,
// any iteration that intersects with a tile will return all pixel refs
// inside of it.
- scoped_refptr<FakePicturePileImpl> pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- pile->SetMinContentsScale(0.5f);
+ scoped_ptr<FakePicturePile> recording_source =
+ FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
+ recording_source->SetMinContentsScale(0.5f);
// Bitmaps 0-2 are exactly on tiles 0-2, so that they overlap the borders
// of adjacent tiles.
- gfx::Rect bitmap_rects[] = {pile->tiling().TileBounds(0, 0),
- pile->tiling().TileBounds(1, 0),
- pile->tiling().TileBounds(2, 0), };
+ gfx::Rect bitmap_rects[] = {
+ recording_source->tiling().TileBounds(0, 0),
+ recording_source->tiling().TileBounds(1, 0),
+ recording_source->tiling().TileBounds(2, 0),
+ };
SkBitmap discardable_bitmap[arraysize(bitmap_rects)];
for (size_t i = 0; i < arraysize(bitmap_rects); ++i) {
CreateBitmap(bitmap_rects[i].size(), "discardable", &discardable_bitmap[i]);
- pile->add_draw_bitmap(discardable_bitmap[i], bitmap_rects[i].origin());
+ recording_source->add_draw_bitmap(discardable_bitmap[i],
+ bitmap_rects[i].origin());
}
+ recording_source->SetGatherPixelRefs(true);
+ recording_source->Rerecord();
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
+
// Sanity check that bitmaps 0-2 intersect the borders of their adjacent
// tiles, but not the actual tiles.
EXPECT_TRUE(
@@ -838,8 +508,6 @@ TEST(PicturePileImplTest, PixelRefIteratorBorders) {
bitmap_rects[2].Intersects(pile->tiling().TileBoundsWithBorder(1, 0)));
EXPECT_FALSE(bitmap_rects[2].Intersects(pile->tiling().TileBounds(1, 0)));
- pile->RerecordPile();
-
// Tile-sized iterators.
{
// Because tile 0's borders extend onto tile 1, it will include both
diff --git a/chromium/cc/resources/picture_pile_unittest.cc b/chromium/cc/playback/picture_pile_unittest.cc
index 00b1b0c97fb..f929aeffb0a 100644
--- a/chromium/cc/resources/picture_pile_unittest.cc
+++ b/chromium/cc/playback/picture_pile_unittest.cc
@@ -5,9 +5,9 @@
#include <map>
#include <utility>
-#include "cc/resources/picture_pile.h"
+#include "cc/playback/picture_pile.h"
#include "cc/test/fake_content_layer_client.h"
-#include "cc/test/fake_rendering_stats_instrumentation.h"
+#include "cc/test/fake_picture_pile.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -15,38 +15,12 @@
namespace cc {
namespace {
-class TestPicturePile : public PicturePile {
- public:
- ~TestPicturePile() override {}
-
- using PicturePile::buffer_pixels;
- using PicturePile::CanRasterSlowTileCheck;
- using PicturePile::Clear;
-
- PictureMap& picture_map() { return picture_map_; }
- const gfx::Rect& recorded_viewport() const { return recorded_viewport_; }
-
- bool CanRasterLayerRect(gfx::Rect layer_rect) {
- layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
- if (recorded_viewport_.Contains(layer_rect))
- return true;
- return CanRasterSlowTileCheck(layer_rect);
- }
-
- bool HasRecordings() const { return has_any_recordings_; }
-
- typedef PicturePile::PictureInfo PictureInfo;
- typedef PicturePile::PictureMapKey PictureMapKey;
- typedef PicturePile::PictureMap PictureMap;
-};
-
class PicturePileTestBase {
public:
PicturePileTestBase()
- : background_color_(SK_ColorBLUE),
- min_scale_(0.125),
- frame_number_(0),
- contents_opaque_(false) {}
+ : min_scale_(0.125),
+ pile_(min_scale_, gfx::Size(1000, 1000)),
+ frame_number_(0) {}
void InitializeData() {
pile_.SetTileGridSize(gfx::Size(1000, 1000));
@@ -61,50 +35,40 @@ class PicturePileTestBase {
UpdateAndExpandInvalidation(&invalidation, tiling_size, viewport_rect);
}
- gfx::Size tiling_size() const { return pile_.tiling_size(); }
- gfx::Rect tiling_rect() const { return gfx::Rect(pile_.tiling_size()); }
+ gfx::Size tiling_size() const { return pile_.GetSize(); }
+ gfx::Rect tiling_rect() const { return gfx::Rect(pile_.GetSize()); }
bool UpdateAndExpandInvalidation(Region* invalidation,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect) {
frame_number_++;
- return pile_.UpdateAndExpandInvalidation(&client_,
- invalidation,
- background_color_,
- contents_opaque_,
- false,
- layer_size,
- visible_layer_rect,
- frame_number_,
- Picture::RECORD_NORMALLY,
- &stats_instrumentation_);
+ return pile_.UpdateAndExpandInvalidation(&client_, invalidation, layer_size,
+ visible_layer_rect, frame_number_,
+ RecordingSource::RECORD_NORMALLY);
}
bool UpdateWholePile() {
Region invalidation = tiling_rect();
- bool result = UpdateAndExpandInvalidation(
- &invalidation, tiling_size(), tiling_rect());
+ bool result = UpdateAndExpandInvalidation(&invalidation, tiling_size(),
+ tiling_rect());
EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString());
return result;
}
FakeContentLayerClient client_;
- FakeRenderingStatsInstrumentation stats_instrumentation_;
- TestPicturePile pile_;
- SkColor background_color_;
float min_scale_;
+ FakePicturePile pile_;
int frame_number_;
- bool contents_opaque_;
};
class PicturePileTest : public PicturePileTestBase, public testing::Test {
public:
- virtual void SetUp() override { InitializeData(); }
+ void SetUp() override { InitializeData(); }
};
TEST_F(PicturePileTest, InvalidationOnTileBorderOutsideInterestRect) {
// Don't expand the interest rect past what we invalidate.
- pile_.SetPixelRecordDistanceForTesting(0);
+ pile_.SetPixelRecordDistance(0);
gfx::Size tile_size(100, 100);
pile_.tiling().SetMaxTextureSize(tile_size);
@@ -187,17 +151,19 @@ TEST_F(PicturePileTest, SmallInvalidateInflated) {
EXPECT_EQ(1, pile_.tiling().num_tiles_x());
EXPECT_EQ(1, pile_.tiling().num_tiles_y());
- TestPicturePile::PictureInfo& picture_info =
- pile_.picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
- // We should have a picture.
- EXPECT_TRUE(!!picture_info.GetPicture());
- gfx::Rect picture_rect = gfx::ScaleToEnclosedRect(
- picture_info.GetPicture()->LayerRect(), min_scale_);
+ PicturePile::PictureMapKey key = FakePicturePile::PictureMapKey(0, 0);
+ PicturePile::PictureMap::iterator it = pile_.picture_map().find(key);
+ EXPECT_TRUE(it != pile_.picture_map().end());
+ const Picture* picture = it->second.get();
+ EXPECT_TRUE(picture);
+
+ gfx::Rect picture_rect =
+ gfx::ScaleToEnclosedRect(picture->LayerRect(), min_scale_);
// The the picture should be large enough that scaling it never makes a rect
// smaller than 1 px wide or tall.
- EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect " <<
- picture_rect.ToString();
+ EXPECT_FALSE(picture_rect.IsEmpty()) << "Picture rect "
+ << picture_rect.ToString();
}
TEST_F(PicturePileTest, LargeInvalidateInflated) {
@@ -209,169 +175,17 @@ TEST_F(PicturePileTest, LargeInvalidateInflated) {
EXPECT_EQ(1, pile_.tiling().num_tiles_x());
EXPECT_EQ(1, pile_.tiling().num_tiles_y());
- TestPicturePile::PictureInfo& picture_info =
- pile_.picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
- EXPECT_TRUE(!!picture_info.GetPicture());
+ PicturePile::PictureMapKey key = FakePicturePile::PictureMapKey(0, 0);
+ PicturePile::PictureMap::iterator it = pile_.picture_map().find(key);
+ EXPECT_TRUE(it != pile_.picture_map().end());
+ const Picture* picture = it->second.get();
+ EXPECT_TRUE(picture);
int expected_inflation = pile_.buffer_pixels();
- const Picture* base_picture = picture_info.GetPicture();
- gfx::Rect base_picture_rect(pile_.tiling_size());
+ gfx::Rect base_picture_rect(tiling_size());
base_picture_rect.Inset(-expected_inflation, -expected_inflation);
- EXPECT_EQ(base_picture_rect.ToString(),
- base_picture->LayerRect().ToString());
-}
-
-TEST_F(PicturePileTest, InvalidateOnTileBoundaryInflated) {
- gfx::Size new_tiling_size =
- gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 2.f));
- // This creates initial pictures.
- SetTilingSize(new_tiling_size);
-
- // Due to border pixels, we should have 3 tiles.
- EXPECT_EQ(3, pile_.tiling().num_tiles_x());
- EXPECT_EQ(3, pile_.tiling().num_tiles_y());
-
- // We should have 1/.125 - 1 = 7 border pixels.
- EXPECT_EQ(7, pile_.buffer_pixels());
- EXPECT_EQ(7, pile_.tiling().border_texels());
-
- // Invalidate everything to have a non zero invalidation frequency.
- UpdateWholePile();
-
- // Invalidate something just over a tile boundary by a single pixel.
- // This will invalidate the tile (1, 1), as well as 1 row of pixels in (1, 0).
- Region invalidate_rect(
- gfx::Rect(pile_.tiling().TileBoundsWithBorder(0, 0).right(),
- pile_.tiling().TileBoundsWithBorder(0, 0).bottom() - 1,
- 50,
- 50));
- Region expected_invalidation = invalidate_rect;
- UpdateAndExpandInvalidation(&invalidate_rect, tiling_size(), tiling_rect());
- EXPECT_EQ(expected_invalidation.ToString(), invalidate_rect.ToString());
-
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureInfo& picture_info =
- pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(i, j))
- ->second;
-
- // Expect (1, 1) and (1, 0) to be invalidated once more
- // than the rest of the tiles.
- if (i == 1 && (j == 0 || j == 1)) {
- EXPECT_FLOAT_EQ(
- 2.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
- picture_info.GetInvalidationFrequencyForTesting());
- } else {
- EXPECT_FLOAT_EQ(
- 1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
- picture_info.GetInvalidationFrequencyForTesting());
- }
- }
- }
-}
-
-TEST_F(PicturePileTest, InvalidateOnFullLayer) {
- UpdateWholePile();
-
- // Everything was invalidated once so far.
- for (auto& it : pile_.picture_map()) {
- EXPECT_FLOAT_EQ(
- 1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
- it.second.GetInvalidationFrequencyForTesting());
- }
-
- // Invalidate everything,
- Region invalidation = tiling_rect();
- UpdateAndExpandInvalidation(&invalidation, tiling_size(), tiling_rect());
-
- // Everything was invalidated again.
- for (auto& it : pile_.picture_map()) {
- EXPECT_FLOAT_EQ(
- 2.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
- it.second.GetInvalidationFrequencyForTesting());
- }
-}
-
-TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) {
- gfx::Size new_tiling_size =
- gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 4.f));
- SetTilingSize(new_tiling_size);
-
- gfx::Rect viewport(tiling_size().width(), 1);
-
- // Update the whole pile until the invalidation frequency is high.
- for (int frame = 0; frame < 33; ++frame) {
- UpdateWholePile();
- }
-
- // Make sure we have a high invalidation frequency.
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureInfo& picture_info =
- pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(i, j))
- ->second;
- EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting())
- << "i " << i << " j " << j;
- }
- }
-
- // Update once more with a small viewport.
- Region invalidation(tiling_rect());
- UpdateAndExpandInvalidation(&invalidation, tiling_size(), viewport);
- EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString());
-
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureInfo& picture_info =
- pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(i, j))
- ->second;
- EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting());
-
- // If the y far enough away we expect to find no picture (no re-recording
- // happened). For close y, the picture should change.
- if (j >= 2)
- EXPECT_FALSE(picture_info.GetPicture()) << "i " << i << " j " << j;
- else
- EXPECT_TRUE(picture_info.GetPicture()) << "i " << i << " j " << j;
- }
- }
-
- // Update a partial tile that doesn't get recorded. We should expand the
- // invalidation to the entire tiles that overlap it.
- Region small_invalidation =
- gfx::Rect(pile_.tiling().TileBounds(3, 4).x(),
- pile_.tiling().TileBounds(3, 4).y() + 10,
- 1,
- 1);
- UpdateAndExpandInvalidation(&small_invalidation, tiling_size(), viewport);
- EXPECT_TRUE(small_invalidation.Contains(gfx::UnionRects(
- pile_.tiling().TileBounds(2, 4), pile_.tiling().TileBounds(3, 4))))
- << small_invalidation.ToString();
-
- // Now update with no invalidation and full viewport
- Region empty_invalidation;
- UpdateAndExpandInvalidation(
- &empty_invalidation, tiling_size(), tiling_rect());
- EXPECT_EQ(Region().ToString(), empty_invalidation.ToString());
-
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureInfo& picture_info =
- pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(i, j))
- ->second;
- // Expect the invalidation frequency to be less than 1, since we just
- // updated with no invalidations.
- EXPECT_LT(picture_info.GetInvalidationFrequencyForTesting(), 1.f);
-
- // We expect that there are pictures everywhere now.
- EXPECT_TRUE(picture_info.GetPicture()) << "i " << i << " j " << j;
- }
- }
+ EXPECT_EQ(base_picture_rect.ToString(), picture->LayerRect().ToString());
}
TEST_F(PicturePileTest, ClearingInvalidatesRecordedRect) {
@@ -387,58 +201,6 @@ TEST_F(PicturePileTest, ClearingInvalidatesRecordedRect) {
EXPECT_FALSE(pile_.CanRasterSlowTileCheck(rect));
}
-TEST_F(PicturePileTest, FrequentInvalidationCanRaster) {
- // This test makes sure that if part of the page is frequently invalidated
- // and doesn't get re-recorded, then CanRaster is not true for any
- // tiles touching it, but is true for adjacent tiles, even if it
- // overlaps on borders (edge case).
- gfx::Size new_tiling_size =
- gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 4.f));
- SetTilingSize(new_tiling_size);
-
- gfx::Rect tile01_borders = pile_.tiling().TileBoundsWithBorder(0, 1);
- gfx::Rect tile02_borders = pile_.tiling().TileBoundsWithBorder(0, 2);
- gfx::Rect tile01_noborders = pile_.tiling().TileBounds(0, 1);
- gfx::Rect tile02_noborders = pile_.tiling().TileBounds(0, 2);
-
- // Sanity check these two tiles are overlapping with borders, since this is
- // what the test is trying to repro.
- EXPECT_TRUE(tile01_borders.Intersects(tile02_borders));
- EXPECT_FALSE(tile01_noborders.Intersects(tile02_noborders));
- UpdateWholePile();
- EXPECT_TRUE(pile_.CanRasterLayerRect(tile01_noborders));
- EXPECT_TRUE(pile_.CanRasterSlowTileCheck(tile01_noborders));
- EXPECT_TRUE(pile_.CanRasterLayerRect(tile02_noborders));
- EXPECT_TRUE(pile_.CanRasterSlowTileCheck(tile02_noborders));
- // Sanity check that an initial paint goes down the fast path of having
- // a valid recorded viewport.
- EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty());
-
- // Update the whole layer until the invalidation frequency is high.
- for (int frame = 0; frame < 33; ++frame) {
- UpdateWholePile();
- }
-
- // Update once more with a small viewport.
- gfx::Rect viewport(tiling_size().width(), 1);
- Region invalidation(tiling_rect());
- UpdateAndExpandInvalidation(&invalidation, tiling_size(), viewport);
- EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString());
-
- // Sanity check some pictures exist and others don't.
- EXPECT_TRUE(pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(0, 1))
- ->second.GetPicture());
- EXPECT_FALSE(pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(0, 2))
- ->second.GetPicture());
-
- EXPECT_TRUE(pile_.CanRasterLayerRect(tile01_noborders));
- EXPECT_TRUE(pile_.CanRasterSlowTileCheck(tile01_noborders));
- EXPECT_FALSE(pile_.CanRasterLayerRect(tile02_noborders));
- EXPECT_FALSE(pile_.CanRasterSlowTileCheck(tile02_noborders));
-}
-
TEST_F(PicturePileTest, NoInvalidationValidViewport) {
// This test validates that the recorded_viewport cache of full tiles
// is still valid for some use cases. If it's not, it's a performance
@@ -459,8 +221,8 @@ TEST_F(PicturePileTest, NoInvalidationValidViewport) {
// No invalidation, changing viewport.
invalidation = Region();
- UpdateAndExpandInvalidation(
- &invalidation, tiling_size(), gfx::Rect(5, 5, 5, 5));
+ UpdateAndExpandInvalidation(&invalidation, tiling_size(),
+ gfx::Rect(5, 5, 5, 5));
EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty());
EXPECT_EQ(Region().ToString(), invalidation.ToString());
}
@@ -563,7 +325,7 @@ enum Corner {
class PicturePileResizeCornerTest : public PicturePileTestBase,
public testing::TestWithParam<Corner> {
protected:
- virtual void SetUp() override { InitializeData(); }
+ void SetUp() override { InitializeData(); }
static gfx::Rect CornerSinglePixelRect(Corner corner, const gfx::Size& s) {
switch (corner) {
@@ -609,10 +371,10 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -627,10 +389,10 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
EXPECT_EQ(8, pile_.tiling().num_tiles_y());
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_EQ(j < 5, it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_EQ(j < 5, it != map.end() && it->second.get());
}
}
@@ -657,9 +419,9 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
bool expect_tile;
switch (corner) {
case TOP_LEFT:
@@ -675,7 +437,7 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
expect_tile = j < 5 || (j == 5 && i == 5);
break;
}
- EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.get());
}
}
@@ -719,10 +481,10 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_EQ(i < 5, it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_EQ(i < 5, it != map.end() && it->second.get());
}
}
@@ -749,9 +511,9 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
bool expect_tile;
switch (corner) {
case TOP_LEFT:
@@ -769,7 +531,7 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
expect_tile = i < 5 || (j == 5 && i == 5);
break;
}
- EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.get());
}
}
@@ -808,10 +570,10 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
EXPECT_EQ(8, pile_.tiling().num_tiles_y());
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_EQ(i < 5 && j < 5, it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_EQ(i < 5 && j < 5, it != map.end() && it->second.get());
}
}
@@ -840,9 +602,9 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
bool expect_tile;
switch (corner) {
case TOP_LEFT:
@@ -861,8 +623,8 @@ TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) {
expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5);
break;
}
- EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture())
- << i << "," << j;
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.get()) << i << ","
+ << j;
}
}
@@ -923,10 +685,10 @@ TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -949,9 +711,9 @@ TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
bool expect_tile;
switch (corner) {
case TOP_LEFT:
@@ -967,7 +729,7 @@ TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) {
expect_tile = j < 5 || (j == 5 && i == 5);
break;
}
- EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.get());
}
}
@@ -1015,9 +777,9 @@ TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
bool expect_tile;
switch (corner) {
case TOP_LEFT:
@@ -1033,7 +795,7 @@ TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) {
expect_tile = i < 5 || (j == 5 && i == 5);
break;
}
- EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.get());
}
}
@@ -1081,9 +843,9 @@ TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
bool expect_tile;
switch (corner) {
case TOP_LEFT:
@@ -1102,8 +864,8 @@ TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) {
expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5);
break;
}
- EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture())
- << i << "," << j;
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.get()) << i << ","
+ << j;
}
}
@@ -1180,10 +942,10 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1195,10 +957,10 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
EXPECT_EQ(8, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1221,10 +983,10 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1244,10 +1006,10 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1270,10 +1032,10 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1293,10 +1055,10 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
EXPECT_EQ(8, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1323,10 +1085,10 @@ TEST_F(PicturePileTest, ResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1361,10 +1123,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1376,10 +1138,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1397,10 +1159,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1419,10 +1181,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1440,10 +1202,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1462,10 +1224,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1483,10 +1245,10 @@ TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) {
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ EXPECT_TRUE(it != map.end() && it->second.get());
}
}
@@ -1569,12 +1331,12 @@ TEST_F(PicturePileTest, NonSolidRectangleOnOffsettedLayerIsNonSolid) {
TEST_F(PicturePileTest, SetEmptyBounds) {
EXPECT_TRUE(pile_.is_solid_color());
- EXPECT_FALSE(pile_.tiling_size().IsEmpty());
+ EXPECT_FALSE(pile_.GetSize().IsEmpty());
EXPECT_FALSE(pile_.picture_map().empty());
EXPECT_TRUE(pile_.HasRecordings());
pile_.SetEmptyBounds();
EXPECT_FALSE(pile_.is_solid_color());
- EXPECT_TRUE(pile_.tiling_size().IsEmpty());
+ EXPECT_TRUE(pile_.GetSize().IsEmpty());
EXPECT_TRUE(pile_.picture_map().empty());
EXPECT_FALSE(pile_.HasRecordings());
}
diff --git a/chromium/cc/playback/picture_unittest.cc b/chromium/cc/playback/picture_unittest.cc
new file mode 100644
index 00000000000..53310e37c81
--- /dev/null
+++ b/chromium/cc/playback/picture_unittest.cc
@@ -0,0 +1,181 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/playback/picture.h"
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/skia_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkGraphics.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+namespace {
+
+TEST(PictureTest, AsBase64String) {
+ SkGraphics::Init();
+
+ gfx::Rect layer_rect(100, 100);
+
+ gfx::Size tile_grid_size(100, 100);
+
+ FakeContentLayerClient content_layer_client;
+
+ scoped_ptr<base::Value> tmp;
+
+ SkPaint red_paint;
+ red_paint.setColor(SkColorSetARGB(255, 255, 0, 0));
+ SkPaint green_paint;
+ green_paint.setColor(SkColorSetARGB(255, 0, 255, 0));
+
+ // Invalid picture (not a dict).
+ tmp.reset(new base::StringValue("abc!@#$%"));
+ scoped_refptr<Picture> invalid_picture =
+ Picture::CreateFromValue(tmp.get());
+ EXPECT_FALSE(invalid_picture.get());
+
+ // Single full-size rect picture.
+ content_layer_client.add_draw_rect(layer_rect, red_paint);
+
+ scoped_refptr<Picture> one_rect_picture =
+ Picture::Create(layer_rect, &content_layer_client, tile_grid_size, false,
+ RecordingSource::RECORD_NORMALLY);
+ scoped_ptr<base::Value> serialized_one_rect(one_rect_picture->AsValue());
+
+ // Reconstruct the picture.
+ scoped_refptr<Picture> one_rect_picture_check =
+ Picture::CreateFromValue(serialized_one_rect.get());
+ EXPECT_TRUE(one_rect_picture_check);
+
+ // Check for equivalence.
+ unsigned char one_rect_buffer[4 * 100 * 100] = {0};
+ DrawPicture(one_rect_buffer, layer_rect, one_rect_picture);
+ unsigned char one_rect_buffer_check[4 * 100 * 100] = {0};
+ DrawPicture(one_rect_buffer_check, layer_rect, one_rect_picture_check);
+
+ EXPECT_EQ(one_rect_picture->LayerRect(), one_rect_picture_check->LayerRect());
+ EXPECT_EQ(0, memcmp(one_rect_buffer, one_rect_buffer_check, 4 * 100 * 100));
+
+ // Two rect picture.
+ content_layer_client.add_draw_rect(gfx::Rect(25, 25, 50, 50), green_paint);
+
+ scoped_refptr<Picture> two_rect_picture =
+ Picture::Create(layer_rect, &content_layer_client, tile_grid_size, false,
+ RecordingSource::RECORD_NORMALLY);
+
+ scoped_ptr<base::Value> serialized_two_rect(two_rect_picture->AsValue());
+
+ // Reconstruct the picture.
+ scoped_refptr<Picture> two_rect_picture_check =
+ Picture::CreateFromValue(serialized_two_rect.get());
+ EXPECT_TRUE(two_rect_picture_check);
+
+ // Check for equivalence.
+ unsigned char two_rect_buffer[4 * 100 * 100] = {0};
+ DrawPicture(two_rect_buffer, layer_rect, two_rect_picture);
+ unsigned char two_rect_buffer_check[4 * 100 * 100] = {0};
+ DrawPicture(two_rect_buffer_check, layer_rect, two_rect_picture_check);
+
+ EXPECT_EQ(two_rect_picture->LayerRect(), two_rect_picture_check->LayerRect());
+ EXPECT_EQ(0, memcmp(two_rect_buffer, two_rect_buffer_check, 4 * 100 * 100));
+}
+
+TEST(PictureTest, CreateFromSkpValue) {
+ SkGraphics::Init();
+
+ gfx::Rect layer_rect(100, 200);
+
+ gfx::Size tile_grid_size(100, 200);
+
+ FakeContentLayerClient content_layer_client;
+
+ scoped_ptr<base::Value> tmp;
+
+ SkPaint red_paint;
+ red_paint.setColor(SkColorSetARGB(255, 255, 0, 0));
+ SkPaint green_paint;
+ green_paint.setColor(SkColorSetARGB(255, 0, 255, 0));
+
+ // Invalid picture (not a dict).
+ tmp.reset(new base::StringValue("abc!@#$%"));
+ scoped_refptr<Picture> invalid_picture =
+ Picture::CreateFromSkpValue(tmp.get());
+ EXPECT_TRUE(!invalid_picture.get());
+
+ // Single full-size rect picture.
+ content_layer_client.add_draw_rect(layer_rect, red_paint);
+ scoped_refptr<Picture> one_rect_picture =
+ Picture::Create(layer_rect, &content_layer_client, tile_grid_size, false,
+ RecordingSource::RECORD_NORMALLY);
+ scoped_ptr<base::Value> serialized_one_rect(
+ one_rect_picture->AsValue());
+
+ const base::DictionaryValue* value = NULL;
+ EXPECT_TRUE(serialized_one_rect->GetAsDictionary(&value));
+
+ // Decode the picture from base64.
+ const base::Value* skp_value;
+ EXPECT_TRUE(value->Get("skp64", &skp_value));
+
+ // Reconstruct the picture.
+ scoped_refptr<Picture> one_rect_picture_check =
+ Picture::CreateFromSkpValue(skp_value);
+ EXPECT_TRUE(one_rect_picture_check);
+
+ EXPECT_EQ(100, one_rect_picture_check->LayerRect().width());
+ EXPECT_EQ(200, one_rect_picture_check->LayerRect().height());
+}
+
+TEST(PictureTest, RecordingModes) {
+ SkGraphics::Init();
+
+ gfx::Rect layer_rect(100, 200);
+
+ gfx::Size tile_grid_size(100, 200);
+
+ FakeContentLayerClient content_layer_client;
+ EXPECT_EQ(NULL, content_layer_client.last_canvas());
+
+ scoped_refptr<Picture> picture =
+ Picture::Create(layer_rect, &content_layer_client, tile_grid_size, false,
+ RecordingSource::RECORD_NORMALLY);
+ EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
+ EXPECT_EQ(ContentLayerClient::PAINTING_BEHAVIOR_NORMAL,
+ content_layer_client.last_painting_control());
+ EXPECT_TRUE(picture.get());
+
+ picture = Picture::Create(layer_rect, &content_layer_client, tile_grid_size,
+ false, RecordingSource::RECORD_WITH_SK_NULL_CANVAS);
+ EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
+ EXPECT_EQ(ContentLayerClient::PAINTING_BEHAVIOR_NORMAL,
+ content_layer_client.last_painting_control());
+ EXPECT_TRUE(picture.get());
+
+ picture =
+ Picture::Create(layer_rect, &content_layer_client, tile_grid_size, false,
+ RecordingSource::RECORD_WITH_PAINTING_DISABLED);
+ EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
+ EXPECT_EQ(ContentLayerClient::DISPLAY_LIST_PAINTING_DISABLED,
+ content_layer_client.last_painting_control());
+ EXPECT_TRUE(picture.get());
+
+ picture =
+ Picture::Create(layer_rect, &content_layer_client, tile_grid_size, false,
+ RecordingSource::RECORD_WITH_CACHING_DISABLED);
+ EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
+ EXPECT_EQ(ContentLayerClient::DISPLAY_LIST_CACHING_DISABLED,
+ content_layer_client.last_painting_control());
+ EXPECT_TRUE(picture.get());
+
+ // RECORD_WITH_CONSTRUCTION_DISABLED is not supported for Picture.
+
+ EXPECT_EQ(5, RecordingSource::RECORDING_MODE_COUNT);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/playback/pixel_ref_map.cc b/chromium/cc/playback/pixel_ref_map.cc
new file mode 100644
index 00000000000..bb5a84c37b5
--- /dev/null
+++ b/chromium/cc/playback/pixel_ref_map.cc
@@ -0,0 +1,172 @@
+// 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.
+
+#include "cc/playback/pixel_ref_map.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "cc/base/util.h"
+#include "cc/playback/display_item_list.h"
+#include "cc/playback/picture.h"
+#include "skia/ext/pixel_ref_utils.h"
+
+namespace cc {
+
+PixelRefMap::PixelRefMap(const gfx::Size& cell_size) : cell_size_(cell_size) {
+ DCHECK(!cell_size.IsEmpty());
+}
+
+PixelRefMap::~PixelRefMap() {
+}
+
+void PixelRefMap::GatherPixelRefsFromPicture(SkPicture* picture) {
+ DCHECK(picture);
+
+ int min_x = std::numeric_limits<int>::max();
+ int min_y = std::numeric_limits<int>::max();
+ int max_x = 0;
+ int max_y = 0;
+
+ skia::DiscardablePixelRefList pixel_refs;
+ skia::PixelRefUtils::GatherDiscardablePixelRefs(picture, &pixel_refs);
+ for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
+ it != pixel_refs.end(); ++it) {
+ gfx::Point min(
+ RoundDown(static_cast<int>(it->pixel_ref_rect.x()), cell_size_.width()),
+ RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
+ cell_size_.height()));
+ gfx::Point max(
+ RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
+ cell_size_.width()),
+ RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
+ cell_size_.height()));
+
+ for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
+ for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
+ PixelRefMapKey key(x, y);
+ data_hash_map_[key].push_back(it->pixel_ref);
+ }
+ }
+
+ min_x = std::min(min_x, min.x());
+ min_y = std::min(min_y, min.y());
+ max_x = std::max(max_x, max.x());
+ max_y = std::max(max_y, max.y());
+ }
+
+ min_pixel_cell_ = gfx::Point(min_x, min_y);
+ max_pixel_cell_ = gfx::Point(max_x, max_y);
+}
+
+base::LazyInstance<PixelRefs> PixelRefMap::Iterator::empty_pixel_refs_;
+
+PixelRefMap::Iterator::Iterator()
+ : target_pixel_ref_map_(NULL),
+ current_pixel_refs_(empty_pixel_refs_.Pointer()),
+ current_index_(0),
+ min_point_(-1, -1),
+ max_point_(-1, -1),
+ current_x_(0),
+ current_y_(0) {
+}
+
+PixelRefMap::Iterator::Iterator(const gfx::Rect& rect, const Picture* picture)
+ : target_pixel_ref_map_(&(picture->pixel_refs_)),
+ current_pixel_refs_(empty_pixel_refs_.Pointer()),
+ current_index_(0) {
+ map_layer_rect_ = picture->layer_rect_;
+ PointToFirstPixelRef(rect);
+}
+
+PixelRefMap::Iterator::Iterator(const gfx::Rect& rect,
+ const DisplayItemList* display_list)
+ : target_pixel_ref_map_(display_list->pixel_refs_.get()),
+ current_pixel_refs_(empty_pixel_refs_.Pointer()),
+ current_index_(0) {
+ map_layer_rect_ = display_list->layer_rect_;
+ PointToFirstPixelRef(rect);
+}
+
+PixelRefMap::Iterator::~Iterator() {
+}
+
+PixelRefMap::Iterator& PixelRefMap::Iterator::operator++() {
+ ++current_index_;
+ // If we're not at the end of the list, then we have the next item.
+ if (current_index_ < current_pixel_refs_->size())
+ return *this;
+
+ DCHECK(current_y_ <= max_point_.y());
+ while (true) {
+ gfx::Size cell_size = target_pixel_ref_map_->cell_size_;
+
+ // Advance the current grid cell.
+ current_x_ += cell_size.width();
+ if (current_x_ > max_point_.x()) {
+ current_y_ += cell_size.height();
+ current_x_ = min_point_.x();
+ if (current_y_ > max_point_.y()) {
+ current_pixel_refs_ = empty_pixel_refs_.Pointer();
+ current_index_ = 0;
+ break;
+ }
+ }
+
+ // If there are no pixel refs at this grid cell, keep incrementing.
+ PixelRefMapKey key(current_x_, current_y_);
+ PixelRefHashmap::const_iterator iter =
+ target_pixel_ref_map_->data_hash_map_.find(key);
+ if (iter == target_pixel_ref_map_->data_hash_map_.end())
+ continue;
+
+ // We found a non-empty list: store it and get the first pixel ref.
+ current_pixel_refs_ = &iter->second;
+ current_index_ = 0;
+ break;
+ }
+ return *this;
+}
+
+void PixelRefMap::Iterator::PointToFirstPixelRef(const gfx::Rect& rect) {
+ gfx::Rect query_rect(rect);
+ // Early out if the query rect doesn't intersect this picture.
+ if (!query_rect.Intersects(map_layer_rect_) || !target_pixel_ref_map_) {
+ min_point_ = gfx::Point(0, 0);
+ max_point_ = gfx::Point(0, 0);
+ current_x_ = 1;
+ current_y_ = 1;
+ return;
+ }
+
+ // First, subtract the layer origin as cells are stored in layer space.
+ query_rect.Offset(-map_layer_rect_.OffsetFromOrigin());
+
+ DCHECK(!target_pixel_ref_map_->cell_size_.IsEmpty());
+ gfx::Size cell_size(target_pixel_ref_map_->cell_size_);
+ // We have to find a cell_size aligned point that corresponds to
+ // query_rect. Point is a multiple of cell_size.
+ min_point_ = gfx::Point(RoundDown(query_rect.x(), cell_size.width()),
+ RoundDown(query_rect.y(), cell_size.height()));
+ max_point_ =
+ gfx::Point(RoundDown(query_rect.right() - 1, cell_size.width()),
+ RoundDown(query_rect.bottom() - 1, cell_size.height()));
+
+ // Limit the points to known pixel ref boundaries.
+ min_point_ = gfx::Point(
+ std::max(min_point_.x(), target_pixel_ref_map_->min_pixel_cell_.x()),
+ std::max(min_point_.y(), target_pixel_ref_map_->min_pixel_cell_.y()));
+ max_point_ = gfx::Point(
+ std::min(max_point_.x(), target_pixel_ref_map_->max_pixel_cell_.x()),
+ std::min(max_point_.y(), target_pixel_ref_map_->max_pixel_cell_.y()));
+
+ // Make the current x be cell_size.width() less than min point, so that
+ // the first increment will point at min_point_.
+ current_x_ = min_point_.x() - cell_size.width();
+ current_y_ = min_point_.y();
+ if (current_y_ <= max_point_.y())
+ ++(*this);
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/pixel_ref_map.h b/chromium/cc/playback/pixel_ref_map.h
new file mode 100644
index 00000000000..e1545217836
--- /dev/null
+++ b/chromium/cc/playback/pixel_ref_map.h
@@ -0,0 +1,94 @@
+// 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_PLAYBACK_PIXEL_REF_MAP_H_
+#define CC_PLAYBACK_PIXEL_REF_MAP_H_
+
+#include <utility>
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/memory/ref_counted.h"
+#include "cc/base/cc_export.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+class SkPixelRef;
+
+namespace cc {
+
+class Picture;
+class DisplayItemList;
+
+typedef std::pair<int, int> PixelRefMapKey;
+typedef std::vector<SkPixelRef*> PixelRefs;
+typedef base::hash_map<PixelRefMapKey, PixelRefs> PixelRefHashmap;
+
+// This class is used and owned by cc Picture class. It is used to gather pixel
+// refs which would happen after record. It takes in |cell_size| to decide how
+// big each grid cell should be.
+class CC_EXPORT PixelRefMap {
+ public:
+ explicit PixelRefMap(const gfx::Size& cell_size);
+ ~PixelRefMap();
+ void GatherPixelRefsFromPicture(SkPicture* picture);
+
+ bool empty() const { return data_hash_map_.empty(); }
+
+ // This iterator imprecisely returns the set of pixel refs that are needed to
+ // raster this layer rect from this picture. Internally, pixel refs are
+ // clumped into tile grid buckets, so there may be false positives.
+ class CC_EXPORT Iterator {
+ public:
+ // Default iterator constructor that is used as place holder for invalid
+ // Iterator.
+ Iterator();
+ Iterator(const gfx::Rect& layer_rect, const Picture* picture);
+ Iterator(const gfx::Rect& layer_rect, const DisplayItemList* picture);
+ ~Iterator();
+
+ SkPixelRef* operator->() const {
+ DCHECK_LT(current_index_, current_pixel_refs_->size());
+ return (*current_pixel_refs_)[current_index_];
+ }
+
+ SkPixelRef* operator*() const {
+ DCHECK_LT(current_index_, current_pixel_refs_->size());
+ return (*current_pixel_refs_)[current_index_];
+ }
+
+ Iterator& operator++();
+ operator bool() const {
+ return current_index_ < current_pixel_refs_->size();
+ }
+
+ private:
+ void PointToFirstPixelRef(const gfx::Rect& query_rect);
+
+ static base::LazyInstance<PixelRefs> empty_pixel_refs_;
+ const PixelRefMap* target_pixel_ref_map_;
+ const PixelRefs* current_pixel_refs_;
+ unsigned current_index_;
+
+ gfx::Rect map_layer_rect_;
+
+ gfx::Point min_point_;
+ gfx::Point max_point_;
+ int current_x_;
+ int current_y_;
+ };
+
+ private:
+ gfx::Point min_pixel_cell_;
+ gfx::Point max_pixel_cell_;
+ gfx::Size cell_size_;
+
+ PixelRefHashmap data_hash_map_;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_PIXEL_REF_MAP_H_
diff --git a/chromium/cc/playback/pixel_ref_map_unittest.cc b/chromium/cc/playback/pixel_ref_map_unittest.cc
new file mode 100644
index 00000000000..af88b44c873
--- /dev/null
+++ b/chromium/cc/playback/pixel_ref_map_unittest.cc
@@ -0,0 +1,292 @@
+// 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.
+
+#include "cc/playback/pixel_ref_map.h"
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "cc/playback/picture.h"
+#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/skia_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkGraphics.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+namespace {
+
+TEST(PixelRefMapTest, PixelRefMapIterator) {
+ gfx::Rect layer_rect(2048, 2048);
+
+ gfx::Size tile_grid_size(512, 512);
+
+ FakeContentLayerClient content_layer_client;
+
+ // Discardable pixel refs are found in the following grids:
+ // |---|---|---|---|
+ // | | x | | x |
+ // |---|---|---|---|
+ // | x | | x | |
+ // |---|---|---|---|
+ // | | x | | x |
+ // |---|---|---|---|
+ // | x | | x | |
+ // |---|---|---|---|
+ SkBitmap discardable_bitmap[4][4];
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ if ((x + y) & 1) {
+ CreateBitmap(gfx::Size(500, 500), "discardable",
+ &discardable_bitmap[y][x]);
+ SkPaint paint;
+ content_layer_client.add_draw_bitmap(
+ discardable_bitmap[y][x], gfx::Point(x * 512 + 6, y * 512 + 6),
+ paint);
+ }
+ }
+ }
+
+ scoped_refptr<Picture> picture =
+ Picture::Create(layer_rect, &content_layer_client, tile_grid_size, true,
+ RecordingSource::RECORD_NORMALLY);
+
+ // Default iterator does not have any pixel refs.
+ {
+ PixelRefMap::Iterator iterator;
+ EXPECT_FALSE(iterator);
+ }
+
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ PixelRefMap::Iterator iterator(gfx::Rect(x * 512, y * 512, 500, 500),
+ picture.get());
+ if ((x + y) & 1) {
+ EXPECT_TRUE(iterator) << x << " " << y;
+ EXPECT_TRUE(*iterator == discardable_bitmap[y][x].pixelRef())
+ << x << " " << y;
+ EXPECT_FALSE(++iterator) << x << " " << y;
+ } else {
+ EXPECT_FALSE(iterator) << x << " " << y;
+ }
+ }
+ }
+ // Capture 4 pixel refs.
+ {
+ PixelRefMap::Iterator iterator(gfx::Rect(512, 512, 2048, 2048),
+ picture.get());
+ EXPECT_TRUE(iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
+ EXPECT_FALSE(++iterator);
+ }
+
+ // Copy test.
+ PixelRefMap::Iterator iterator(gfx::Rect(512, 512, 2048, 2048),
+ picture.get());
+ EXPECT_TRUE(iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
+
+ // copy now points to the same spot as iterator,
+ // but both can be incremented independently.
+ PixelRefMap::Iterator copy = iterator;
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
+ EXPECT_FALSE(++iterator);
+
+ EXPECT_TRUE(copy);
+ EXPECT_TRUE(*copy == discardable_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(++copy);
+ EXPECT_TRUE(*copy == discardable_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(++copy);
+ EXPECT_TRUE(*copy == discardable_bitmap[3][2].pixelRef());
+ EXPECT_FALSE(++copy);
+}
+
+TEST(PixelRefMapTest, PixelRefMapIteratorNonZeroLayer) {
+ gfx::Rect layer_rect(1024, 0, 2048, 2048);
+
+ gfx::Size tile_grid_size(512, 512);
+
+ FakeContentLayerClient content_layer_client;
+
+ // Discardable pixel refs are found in the following grids:
+ // |---|---|---|---|
+ // | | x | | x |
+ // |---|---|---|---|
+ // | x | | x | |
+ // |---|---|---|---|
+ // | | x | | x |
+ // |---|---|---|---|
+ // | x | | x | |
+ // |---|---|---|---|
+ SkBitmap discardable_bitmap[4][4];
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ if ((x + y) & 1) {
+ CreateBitmap(gfx::Size(500, 500), "discardable",
+ &discardable_bitmap[y][x]);
+ SkPaint paint;
+ content_layer_client.add_draw_bitmap(
+ discardable_bitmap[y][x],
+ gfx::Point(1024 + x * 512 + 6, y * 512 + 6), paint);
+ }
+ }
+ }
+
+ scoped_refptr<Picture> picture =
+ Picture::Create(layer_rect, &content_layer_client, tile_grid_size, true,
+ RecordingSource::RECORD_NORMALLY);
+
+ // Default iterator does not have any pixel refs.
+ {
+ PixelRefMap::Iterator iterator;
+ EXPECT_FALSE(iterator);
+ }
+
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ PixelRefMap::Iterator iterator(
+ gfx::Rect(1024 + x * 512, y * 512, 500, 500), picture.get());
+ if ((x + y) & 1) {
+ EXPECT_TRUE(iterator) << x << " " << y;
+ EXPECT_TRUE(*iterator == discardable_bitmap[y][x].pixelRef());
+ EXPECT_FALSE(++iterator) << x << " " << y;
+ } else {
+ EXPECT_FALSE(iterator) << x << " " << y;
+ }
+ }
+ }
+ // Capture 4 pixel refs.
+ {
+ PixelRefMap::Iterator iterator(gfx::Rect(1024 + 512, 512, 2048, 2048),
+ picture.get());
+ EXPECT_TRUE(iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
+ EXPECT_FALSE(++iterator);
+ }
+
+ // Copy test.
+ {
+ PixelRefMap::Iterator iterator(gfx::Rect(1024 + 512, 512, 2048, 2048),
+ picture.get());
+ EXPECT_TRUE(iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
+
+ // copy now points to the same spot as iterator,
+ // but both can be incremented independently.
+ PixelRefMap::Iterator copy = iterator;
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
+ EXPECT_FALSE(++iterator);
+
+ EXPECT_TRUE(copy);
+ EXPECT_TRUE(*copy == discardable_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(++copy);
+ EXPECT_TRUE(*copy == discardable_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(++copy);
+ EXPECT_TRUE(*copy == discardable_bitmap[3][2].pixelRef());
+ EXPECT_FALSE(++copy);
+ }
+
+ // Non intersecting rects
+ {
+ PixelRefMap::Iterator iterator(gfx::Rect(0, 0, 1000, 1000), picture.get());
+ EXPECT_FALSE(iterator);
+ }
+ {
+ PixelRefMap::Iterator iterator(gfx::Rect(3500, 0, 1000, 1000),
+ picture.get());
+ EXPECT_FALSE(iterator);
+ }
+ {
+ PixelRefMap::Iterator iterator(gfx::Rect(0, 1100, 1000, 1000),
+ picture.get());
+ EXPECT_FALSE(iterator);
+ }
+ {
+ PixelRefMap::Iterator iterator(gfx::Rect(3500, 1100, 1000, 1000),
+ picture.get());
+ EXPECT_FALSE(iterator);
+ }
+}
+
+TEST(PixelRefMapTest, PixelRefMapIteratorOnePixelQuery) {
+ gfx::Rect layer_rect(2048, 2048);
+
+ gfx::Size tile_grid_size(512, 512);
+
+ FakeContentLayerClient content_layer_client;
+
+ // Discardable pixel refs are found in the following grids:
+ // |---|---|---|---|
+ // | | x | | x |
+ // |---|---|---|---|
+ // | x | | x | |
+ // |---|---|---|---|
+ // | | x | | x |
+ // |---|---|---|---|
+ // | x | | x | |
+ // |---|---|---|---|
+ SkBitmap discardable_bitmap[4][4];
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ if ((x + y) & 1) {
+ CreateBitmap(gfx::Size(500, 500), "discardable",
+ &discardable_bitmap[y][x]);
+ SkPaint paint;
+ content_layer_client.add_draw_bitmap(
+ discardable_bitmap[y][x], gfx::Point(x * 512 + 6, y * 512 + 6),
+ paint);
+ }
+ }
+ }
+
+ scoped_refptr<Picture> picture =
+ Picture::Create(layer_rect, &content_layer_client, tile_grid_size, true,
+ RecordingSource::RECORD_NORMALLY);
+
+ // Default iterator does not have any pixel refs.
+ {
+ PixelRefMap::Iterator iterator;
+ EXPECT_FALSE(iterator);
+ }
+
+ for (int y = 0; y < 4; ++y) {
+ for (int x = 0; x < 4; ++x) {
+ PixelRefMap::Iterator iterator(gfx::Rect(x * 512, y * 512 + 256, 1, 1),
+ picture.get());
+ if ((x + y) & 1) {
+ EXPECT_TRUE(iterator) << x << " " << y;
+ EXPECT_TRUE(*iterator == discardable_bitmap[y][x].pixelRef());
+ EXPECT_FALSE(++iterator) << x << " " << y;
+ } else {
+ EXPECT_FALSE(iterator) << x << " " << y;
+ }
+ }
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/resources/raster_source.h b/chromium/cc/playback/raster_source.h
index 3e2540830bf..c0a484aa8d9 100644
--- a/chromium/cc/resources/raster_source.h
+++ b/chromium/cc/playback/raster_source.h
@@ -2,19 +2,27 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_RASTER_SOURCE_H_
-#define CC_RESOURCES_RASTER_SOURCE_H_
+#ifndef CC_PLAYBACK_RASTER_SOURCE_H_
+#define CC_PLAYBACK_RASTER_SOURCE_H_
#include <vector>
#include "base/memory/ref_counted.h"
#include "cc/base/cc_export.h"
+#include "cc/debug/traced_value.h"
+#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPixelRef.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
class SkCanvas;
+class SkPicture;
namespace cc {
+class Picture;
+
class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
public:
struct CC_EXPORT SolidColorAnalysis {
@@ -30,10 +38,19 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
// assumed that contents_scale has already been applied to this canvas.
// Writes the total number of pixels rasterized and the time spent
// rasterizing to the stats if the respective pointer is not nullptr.
+ // It is assumed that the canvas passed here will only be rasterized by
+ // this raster source via this call.
virtual void PlaybackToCanvas(SkCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const = 0;
+ // Similar to above, except that the canvas passed here can (or was already)
+ // rasterized into by another raster source. That is, it is not safe to clear
+ // the canvas or discard its underlying memory.
+ virtual void PlaybackToSharedCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const = 0;
+
// Analyze to determine if the given rect at given scale is of solid color in
// this raster source.
virtual void PerformSolidColorAnalysis(
@@ -41,6 +58,16 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
float contents_scale,
SolidColorAnalysis* analysis) const = 0;
+ // Returns true iff the whole raster source is of solid color.
+ virtual bool IsSolidColor() const = 0;
+
+ // Returns the color of the raster source if it is solid color. The results
+ // are unspecified if IsSolidColor returns false.
+ virtual SkColor GetSolidColor() const = 0;
+
+ // Returns the size of this raster source.
+ virtual gfx::Size GetSize() const = 0;
+
// Populate the given list with all SkPixelRefs that may overlap the given
// rect at given scale.
virtual void GatherPixelRefs(const gfx::Rect& content_rect,
@@ -52,9 +79,27 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
virtual bool CoversRect(const gfx::Rect& content_rect,
float contents_scale) const = 0;
+ // Returns true if this raster source has anything to rasterize.
+ virtual bool HasRecordings() const = 0;
+
+ // Informs the raster source that it should attempt to use distance field text
+ // during rasterization.
+ virtual void SetShouldAttemptToUseDistanceFieldText() = 0;
+
// Return true iff this raster source would benefit from using distance
// field text.
- virtual bool SuitableForDistanceFieldText() const = 0;
+ virtual bool ShouldAttemptToUseDistanceFieldText() const = 0;
+
+ // Tracing functionality.
+ virtual void DidBeginTracing() = 0;
+ virtual void AsValueInto(base::trace_event::TracedValue* array) const = 0;
+ virtual skia::RefPtr<SkPicture> GetFlattenedPicture() = 0;
+ virtual size_t GetPictureMemoryUsage() const = 0;
+
+ // Return true if LCD anti-aliasing may be used when rastering text.
+ virtual bool CanUseLCDText() const = 0;
+
+ virtual scoped_refptr<RasterSource> CreateCloneWithoutLCDText() const = 0;
protected:
friend class base::RefCountedThreadSafe<RasterSource>;
@@ -68,4 +113,4 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
} // namespace cc
-#endif // CC_RESOURCES_RASTER_SOURCE_H_
+#endif // CC_PLAYBACK_RASTER_SOURCE_H_
diff --git a/chromium/cc/playback/raster_source_helper.cc b/chromium/cc/playback/raster_source_helper.cc
new file mode 100644
index 00000000000..6510b3c0e78
--- /dev/null
+++ b/chromium/cc/playback/raster_source_helper.cc
@@ -0,0 +1,81 @@
+// Copyright 2014 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/playback/raster_source_helper.h"
+
+#include "base/trace_event/trace_event.h"
+#include "cc/debug/debug_colors.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+void RasterSourceHelper::PrepareForPlaybackToCanvas(
+ SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ const gfx::Rect& source_rect,
+ float contents_scale,
+ SkColor background_color,
+ bool clear_canvas_with_debug_color,
+ bool requires_clear) {
+ canvas->discard();
+ if (clear_canvas_with_debug_color) {
+ // Any non-painted areas in the content bounds will be left in this color.
+ canvas->clear(DebugColors::NonPaintedFillColor());
+ }
+
+ // If this raster source has opaque contents, it is guaranteeing that it will
+ // draw an opaque rect the size of the layer. If it is not, then we must
+ // clear this canvas ourselves.
+ if (requires_clear) {
+ TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
+ // Clearing is about ~4x faster than drawing a rect even if the content
+ // isn't covering a majority of the canvas.
+ canvas->clear(SK_ColorTRANSPARENT);
+ } else {
+ // Even if completely covered, for rasterizations that touch the edge of the
+ // layer, we also need to raster the background color underneath the last
+ // texel (since the recording won't cover it) and outside the last texel
+ // (due to linear filtering when using this texture).
+ gfx::Rect content_rect =
+ gfx::ToEnclosingRect(gfx::ScaleRect(source_rect, contents_scale));
+
+ // The final texel of content may only be partially covered by a
+ // rasterization; this rect represents the content rect that is fully
+ // covered by content.
+ gfx::Rect deflated_content_rect = content_rect;
+ deflated_content_rect.Inset(0, 0, 1, 1);
+ if (!deflated_content_rect.Contains(canvas_rect)) {
+ if (clear_canvas_with_debug_color) {
+ // Any non-painted areas outside of the content bounds are left in
+ // this color. If this is seen then it means that cc neglected to
+ // rerasterize a tile that used to intersect with the content rect
+ // after the content bounds grew.
+ canvas->save();
+ canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+ canvas->clipRect(gfx::RectToSkRect(content_rect),
+ SkRegion::kDifference_Op);
+ canvas->drawColor(DebugColors::MissingResizeInvalidations(),
+ SkXfermode::kSrc_Mode);
+ canvas->restore();
+ }
+
+ // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X
+ // faster than clearing, so special case this.
+ canvas->save();
+ canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+ gfx::Rect inflated_content_rect = content_rect;
+ inflated_content_rect.Inset(0, 0, -1, -1);
+ canvas->clipRect(gfx::RectToSkRect(inflated_content_rect),
+ SkRegion::kReplace_Op);
+ canvas->clipRect(gfx::RectToSkRect(deflated_content_rect),
+ SkRegion::kDifference_Op);
+ canvas->drawColor(background_color, SkXfermode::kSrc_Mode);
+ canvas->restore();
+ }
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/raster_source_helper.h b/chromium/cc/playback/raster_source_helper.h
new file mode 100644
index 00000000000..30513030351
--- /dev/null
+++ b/chromium/cc/playback/raster_source_helper.h
@@ -0,0 +1,29 @@
+// Copyright 2014 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_PLAYBACK_RASTER_SOURCE_HELPER_H_
+#define CC_PLAYBACK_RASTER_SOURCE_HELPER_H_
+
+#include "cc/base/cc_export.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkCanvas;
+
+namespace cc {
+
+class CC_EXPORT RasterSourceHelper {
+ public:
+ static void PrepareForPlaybackToCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ const gfx::Rect& source_rect,
+ float contents_scale,
+ SkColor background_color,
+ bool clear_canvas_with_debug_color,
+ bool requires_clear);
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_RASTER_SOURCE_HELPER_H_
diff --git a/chromium/cc/playback/recording_source.h b/chromium/cc/playback/recording_source.h
new file mode 100644
index 00000000000..cf8c7c466f5
--- /dev/null
+++ b/chromium/cc/playback/recording_source.h
@@ -0,0 +1,63 @@
+// Copyright 2014 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_PLAYBACK_RECORDING_SOURCE_H_
+#define CC_PLAYBACK_RECORDING_SOURCE_H_
+
+#include "base/memory/ref_counted.h"
+#include "cc/base/cc_export.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace cc {
+class ContentLayerClient;
+class Region;
+class RasterSource;
+
+class CC_EXPORT RecordingSource {
+ public:
+ // TODO(schenney) Remove RECORD_WITH_SK_NULL_CANVAS when we no longer
+ // support a non-Slimming Paint path.
+ enum RecordingMode {
+ RECORD_NORMALLY,
+ RECORD_WITH_SK_NULL_CANVAS,
+ RECORD_WITH_PAINTING_DISABLED,
+ RECORD_WITH_CACHING_DISABLED,
+ RECORD_WITH_CONSTRUCTION_DISABLED,
+ RECORDING_MODE_COUNT, // Must be the last entry.
+ };
+
+ virtual ~RecordingSource() {}
+ // Re-record parts of the picture that are invalid.
+ // Invalidations are in layer space, and will be expanded to cover everything
+ // that was either recorded/changed or that has no recording, leaving out only
+ // pieces that we had a recording for and it was not changed.
+ // Return true iff the pile was modified.
+ virtual bool UpdateAndExpandInvalidation(ContentLayerClient* painter,
+ Region* invalidation,
+ const gfx::Size& layer_size,
+ const gfx::Rect& visible_layer_rect,
+ int frame_number,
+ RecordingMode recording_mode) = 0;
+
+ virtual scoped_refptr<RasterSource> CreateRasterSource(
+ bool can_use_lcd_text) const = 0;
+
+ virtual gfx::Size GetSize() const = 0;
+ virtual void SetEmptyBounds() = 0;
+ virtual void SetSlowdownRasterScaleFactor(int factor) = 0;
+ virtual void SetGatherPixelRefs(bool gather_pixel_refs) = 0;
+ virtual void SetBackgroundColor(SkColor background_color) = 0;
+ virtual void SetRequiresClear(bool requires_clear) = 0;
+ virtual bool IsSuitableForGpuRasterization() const = 0;
+
+ // TODO(hendrikw): Figure out how to remove this.
+ virtual void SetUnsuitableForGpuRasterizationForTesting() = 0;
+ virtual gfx::Size GetTileGridSizeForTesting() const = 0;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_RECORDING_SOURCE_H_
diff --git a/chromium/cc/playback/recording_source_unittest.cc b/chromium/cc/playback/recording_source_unittest.cc
new file mode 100644
index 00000000000..01a89a19ba3
--- /dev/null
+++ b/chromium/cc/playback/recording_source_unittest.cc
@@ -0,0 +1,470 @@
+// 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.
+
+#include <vector>
+
+#include "cc/playback/display_list_raster_source.h"
+#include "cc/test/fake_display_list_recording_source.h"
+#include "cc/test/fake_picture_pile.h"
+#include "cc/test/fake_picture_pile_impl.h"
+#include "cc/test/impl_side_painting_settings.h"
+#include "cc/test/skia_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+template <class T>
+scoped_ptr<T> CreateRecordingSource(const gfx::Rect& viewport,
+ const gfx::Size& grid_cell_size);
+
+template <>
+scoped_ptr<FakePicturePile> CreateRecordingSource<FakePicturePile>(
+ const gfx::Rect& viewport,
+ const gfx::Size& grid_cell_size) {
+ return FakePicturePile::CreateFilledPile(grid_cell_size, viewport.size());
+}
+
+template <>
+scoped_ptr<FakeDisplayListRecordingSource> CreateRecordingSource<
+ FakeDisplayListRecordingSource>(const gfx::Rect& viewport,
+ const gfx::Size& grid_cell_size) {
+ scoped_ptr<FakeDisplayListRecordingSource> recording_source =
+ FakeDisplayListRecordingSource::CreateRecordingSource(viewport);
+ recording_source->SetGridCellSize(grid_cell_size);
+
+ return recording_source.Pass();
+}
+
+template <class T>
+scoped_refptr<RasterSource> CreateRasterSource(T* recording_source);
+
+template <>
+scoped_refptr<RasterSource> CreateRasterSource(
+ FakePicturePile* recording_source) {
+ return FakePicturePileImpl::CreateFromPile(recording_source, nullptr);
+}
+
+template <>
+scoped_refptr<RasterSource> CreateRasterSource(
+ FakeDisplayListRecordingSource* recording_source) {
+ bool can_use_lcd_text = true;
+ return DisplayListRasterSource::CreateFromDisplayListRecordingSource(
+ recording_source, can_use_lcd_text);
+}
+
+template <typename T>
+class RecordingSourceTest : public testing::Test {};
+
+using testing::Types;
+
+typedef Types<FakePicturePile, FakeDisplayListRecordingSource>
+ RecordingSourceImplementations;
+
+TYPED_TEST_CASE(RecordingSourceTest, RecordingSourceImplementations);
+
+TYPED_TEST(RecordingSourceTest, NoGatherPixelRefEmptyPixelRefs) {
+ gfx::Size grid_cell_size(128, 128);
+ gfx::Rect recorded_viewport(0, 0, 256, 256);
+
+ scoped_ptr<TypeParam> recording_source =
+ CreateRecordingSource<TypeParam>(recorded_viewport, grid_cell_size);
+ recording_source->SetGatherPixelRefs(false);
+ recording_source->Rerecord();
+
+ scoped_refptr<RasterSource> raster_source =
+ CreateRasterSource<TypeParam>(recording_source.get());
+
+ // If recording source do not gather pixel ref, raster source is not going to
+ // get pixel refs.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(recorded_viewport, 1.0, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+}
+
+TYPED_TEST(RecordingSourceTest, EmptyPixelRefs) {
+ gfx::Size grid_cell_size(128, 128);
+ gfx::Rect recorded_viewport(0, 0, 256, 256);
+
+ scoped_ptr<TypeParam> recording_source =
+ CreateRecordingSource<TypeParam>(recorded_viewport, grid_cell_size);
+ recording_source->SetGatherPixelRefs(true);
+ recording_source->Rerecord();
+
+ scoped_refptr<RasterSource> raster_source =
+ CreateRasterSource<TypeParam>(recording_source.get());
+
+ // Tile sized iterators.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 1.0, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 2.0, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 64, 64), 0.5, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ // Shifted tile sized iterators.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(140, 140, 128, 128), 1.0,
+ &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(280, 280, 256, 256), 2.0,
+ &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(70, 70, 64, 64), 0.5, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ // Layer sized iterators.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 1.0, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 512, 512), 2.0, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 0.5, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+}
+
+TYPED_TEST(RecordingSourceTest, NoDiscardablePixelRefs) {
+ gfx::Size grid_cell_size(128, 128);
+ gfx::Rect recorded_viewport(0, 0, 256, 256);
+
+ scoped_ptr<TypeParam> recording_source =
+ CreateRecordingSource<TypeParam>(recorded_viewport, grid_cell_size);
+
+ SkPaint simple_paint;
+ simple_paint.setColor(SkColorSetARGB(255, 12, 23, 34));
+
+ SkBitmap non_discardable_bitmap;
+ CreateBitmap(gfx::Size(128, 128), "notdiscardable", &non_discardable_bitmap);
+
+ recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 256, 256),
+ simple_paint);
+ recording_source->add_draw_rect_with_paint(gfx::Rect(128, 128, 512, 512),
+ simple_paint);
+ recording_source->add_draw_rect_with_paint(gfx::Rect(512, 0, 256, 256),
+ simple_paint);
+ recording_source->add_draw_rect_with_paint(gfx::Rect(0, 512, 256, 256),
+ simple_paint);
+ recording_source->add_draw_bitmap(non_discardable_bitmap, gfx::Point(128, 0));
+ recording_source->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 128));
+ recording_source->add_draw_bitmap(non_discardable_bitmap,
+ gfx::Point(150, 150));
+ recording_source->SetGatherPixelRefs(true);
+ recording_source->Rerecord();
+
+ scoped_refptr<RasterSource> raster_source =
+ CreateRasterSource<TypeParam>(recording_source.get());
+
+ // Tile sized iterators.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 1.0, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 2.0, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 64, 64), 0.5, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ // Shifted tile sized iterators.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(140, 140, 128, 128), 1.0,
+ &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(280, 280, 256, 256), 2.0,
+ &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(70, 70, 64, 64), 0.5, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ // Layer sized iterators.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 1.0, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 512, 512), 2.0, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 0.5, &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+}
+
+TYPED_TEST(RecordingSourceTest, DiscardablePixelRefs) {
+ gfx::Size grid_cell_size(128, 128);
+ gfx::Rect recorded_viewport(0, 0, 256, 256);
+
+ scoped_ptr<TypeParam> recording_source =
+ CreateRecordingSource<TypeParam>(recorded_viewport, grid_cell_size);
+
+ SkBitmap discardable_bitmap[2][2];
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][0]);
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][0]);
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][1]);
+
+ // Discardable pixel refs are found in the following cells:
+ // |---|---|
+ // | x | |
+ // |---|---|
+ // | x | x |
+ // |---|---|
+ recording_source->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
+ recording_source->add_draw_bitmap(discardable_bitmap[1][0],
+ gfx::Point(0, 130));
+ recording_source->add_draw_bitmap(discardable_bitmap[1][1],
+ gfx::Point(140, 140));
+ recording_source->SetGatherPixelRefs(true);
+ recording_source->Rerecord();
+
+ scoped_refptr<RasterSource> raster_source =
+ CreateRasterSource<TypeParam>(recording_source.get());
+
+ // Tile sized iterators. These should find only one pixel ref.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 1.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 2.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 64, 64), 0.5, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+
+ // Shifted tile sized iterators. These should find only one pixel ref.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(140, 140, 128, 128), 1.0,
+ &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(280, 280, 256, 256), 2.0,
+ &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(70, 70, 64, 64), 0.5, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+
+ // Ensure there's no discardable pixel refs in the empty cell
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(140, 0, 128, 128), 1.0,
+ &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+
+ // Layer sized iterators. These should find all 3 pixel refs.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 1.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[1][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[2] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(3u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 512, 512), 2.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[1][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[2] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(3u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 0.5, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[1][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[2] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(3u, pixel_refs.size());
+ }
+}
+
+TYPED_TEST(RecordingSourceTest, DiscardablePixelRefsBaseNonDiscardable) {
+ gfx::Size grid_cell_size(256, 256);
+ gfx::Rect recorded_viewport(0, 0, 512, 512);
+
+ scoped_ptr<TypeParam> recording_source =
+ CreateRecordingSource<TypeParam>(recorded_viewport, grid_cell_size);
+
+ SkBitmap non_discardable_bitmap;
+ CreateBitmap(gfx::Size(512, 512), "notdiscardable", &non_discardable_bitmap);
+
+ SkBitmap discardable_bitmap[2][2];
+ CreateBitmap(gfx::Size(128, 128), "discardable", &discardable_bitmap[0][0]);
+ CreateBitmap(gfx::Size(128, 128), "discardable", &discardable_bitmap[0][1]);
+ CreateBitmap(gfx::Size(128, 128), "discardable", &discardable_bitmap[1][1]);
+
+ // One large non-discardable bitmap covers the whole grid.
+ // Discardable pixel refs are found in the following cells:
+ // |---|---|
+ // | x | x |
+ // |---|---|
+ // | | x |
+ // |---|---|
+ recording_source->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 0));
+ recording_source->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
+ recording_source->add_draw_bitmap(discardable_bitmap[0][1],
+ gfx::Point(260, 0));
+ recording_source->add_draw_bitmap(discardable_bitmap[1][1],
+ gfx::Point(260, 260));
+ recording_source->SetGatherPixelRefs(true);
+ recording_source->Rerecord();
+
+ scoped_refptr<RasterSource> raster_source =
+ CreateRasterSource<TypeParam>(recording_source.get());
+
+ // Tile sized iterators. These should find only one pixel ref.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 1.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 512, 512), 2.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 0.5, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ // Shifted tile sized iterators. These should find only one pixel ref.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(260, 260, 256, 256), 1.0,
+ &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(520, 520, 512, 512), 2.0,
+ &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(130, 130, 128, 128), 0.5,
+ &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(1u, pixel_refs.size());
+ }
+ // Ensure there's no discardable pixel refs in the empty cell
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 256, 256, 256), 1.0,
+ &pixel_refs);
+ EXPECT_TRUE(pixel_refs.empty());
+ }
+ // Layer sized iterators. These should find three pixel ref.
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 512, 512), 1.0, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(pixel_refs[2] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(3u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 1024, 1024), 2.0,
+ &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(pixel_refs[2] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(3u, pixel_refs.size());
+ }
+ {
+ std::vector<SkPixelRef*> pixel_refs;
+ raster_source->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 0.5, &pixel_refs);
+ EXPECT_FALSE(pixel_refs.empty());
+ EXPECT_TRUE(pixel_refs[0] == discardable_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(pixel_refs[1] == discardable_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(pixel_refs[2] == discardable_bitmap[1][1].pixelRef());
+ EXPECT_EQ(3u, pixel_refs.size());
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/playback/transform_display_item.cc b/chromium/cc/playback/transform_display_item.cc
new file mode 100644
index 00000000000..1f4e5dbd733
--- /dev/null
+++ b/chromium/cc/playback/transform_display_item.cc
@@ -0,0 +1,59 @@
+// Copyright 2014 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/playback/transform_display_item.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace cc {
+
+TransformDisplayItem::TransformDisplayItem()
+ : transform_(gfx::Transform::kSkipInitialization) {
+}
+
+TransformDisplayItem::~TransformDisplayItem() {
+}
+
+void TransformDisplayItem::SetNew(const gfx::Transform& transform) {
+ transform_ = transform;
+
+ size_t memory_usage = sizeof(gfx::Transform);
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 1 /* op_count */,
+ memory_usage);
+}
+
+void TransformDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->save();
+ if (!transform_.IsIdentity())
+ canvas->concat(transform_.matrix());
+}
+
+void TransformDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString(base::StringPrintf("TransformDisplayItem transform: [%s]",
+ transform_.ToString().c_str()));
+}
+
+EndTransformDisplayItem::EndTransformDisplayItem() {
+ DisplayItem::SetNew(true /* suitable_for_gpu_raster */, 0 /* op_count */,
+ 0 /* memory_usage */);
+}
+
+EndTransformDisplayItem::~EndTransformDisplayItem() {
+}
+
+void EndTransformDisplayItem::Raster(SkCanvas* canvas,
+ SkDrawPictureCallback* callback) const {
+ canvas->restore();
+}
+
+void EndTransformDisplayItem::AsValueInto(
+ base::trace_event::TracedValue* array) const {
+ array->AppendString("EndTransformDisplayItem");
+}
+
+} // namespace cc
diff --git a/chromium/cc/playback/transform_display_item.h b/chromium/cc/playback/transform_display_item.h
new file mode 100644
index 00000000000..731249d338e
--- /dev/null
+++ b/chromium/cc/playback/transform_display_item.h
@@ -0,0 +1,47 @@
+// Copyright 2014 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_PLAYBACK_TRANSFORM_DISPLAY_ITEM_H_
+#define CC_PLAYBACK_TRANSFORM_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/playback/display_item.h"
+#include "ui/gfx/transform.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT TransformDisplayItem : public DisplayItem {
+ public:
+ TransformDisplayItem();
+ ~TransformDisplayItem() override;
+
+ void SetNew(const gfx::Transform& transform);
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+
+ private:
+ gfx::Transform transform_;
+};
+
+class CC_EXPORT EndTransformDisplayItem : public DisplayItem {
+ public:
+ EndTransformDisplayItem();
+ ~EndTransformDisplayItem() override;
+
+ static scoped_ptr<EndTransformDisplayItem> Create() {
+ return make_scoped_ptr(new EndTransformDisplayItem());
+ }
+
+ void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+ void AsValueInto(base::trace_event::TracedValue* array) const override;
+};
+
+} // namespace cc
+
+#endif // CC_PLAYBACK_TRANSFORM_DISPLAY_ITEM_H_
diff --git a/chromium/cc/quads/checkerboard_draw_quad.cc b/chromium/cc/quads/checkerboard_draw_quad.cc
index 14517666452..db6ad1ea356 100644
--- a/chromium/cc/quads/checkerboard_draw_quad.cc
+++ b/chromium/cc/quads/checkerboard_draw_quad.cc
@@ -4,23 +4,26 @@
#include "cc/quads/checkerboard_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
namespace cc {
-CheckerboardDrawQuad::CheckerboardDrawQuad() : color(0) {}
+CheckerboardDrawQuad::CheckerboardDrawQuad() : color(0), scale(0.f) {
+}
void CheckerboardDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
- SkColor color) {
+ SkColor color,
+ float scale) {
gfx::Rect opaque_rect = SkColorGetA(color) == 255 ? rect : gfx::Rect();
bool needs_blending = false;
DrawQuad::SetAll(shared_quad_state, DrawQuad::CHECKERBOARD, rect, opaque_rect,
visible_rect, needs_blending);
this->color = color;
+ this->scale = scale;
}
void CheckerboardDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
@@ -28,10 +31,12 @@ void CheckerboardDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
const gfx::Rect& opaque_rect,
const gfx::Rect& visible_rect,
bool needs_blending,
- SkColor color) {
+ SkColor color,
+ float scale) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::CHECKERBOARD, rect, opaque_rect,
visible_rect, needs_blending);
this->color = color;
+ this->scale = scale;
}
void CheckerboardDrawQuad::IterateResources(
@@ -43,8 +48,10 @@ const CheckerboardDrawQuad* CheckerboardDrawQuad::MaterialCast(
return static_cast<const CheckerboardDrawQuad*>(quad);
}
-void CheckerboardDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void CheckerboardDrawQuad::ExtendValue(
+ base::trace_event::TracedValue* value) const {
value->SetInteger("color", color);
+ value->SetDouble("scale", scale);
}
} // namespace cc
diff --git a/chromium/cc/quads/checkerboard_draw_quad.h b/chromium/cc/quads/checkerboard_draw_quad.h
index 64c583fbba2..9ecf4f0fe23 100644
--- a/chromium/cc/quads/checkerboard_draw_quad.h
+++ b/chromium/cc/quads/checkerboard_draw_quad.h
@@ -19,23 +19,26 @@ class CC_EXPORT CheckerboardDrawQuad : public DrawQuad {
void SetNew(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
- SkColor color);
+ SkColor color,
+ float scale);
void SetAll(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
const gfx::Rect& opaque_rect,
const gfx::Rect& visible_rect,
bool needs_blending,
- SkColor color);
+ SkColor color,
+ float scale);
SkColor color;
+ float scale;
void IterateResources(const ResourceIteratorCallback& callback) override;
static const CheckerboardDrawQuad* MaterialCast(const DrawQuad*);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/content_draw_quad_base.cc b/chromium/cc/quads/content_draw_quad_base.cc
index fd6e91b2bec..66fa147beea 100644
--- a/chromium/cc/quads/content_draw_quad_base.cc
+++ b/chromium/cc/quads/content_draw_quad_base.cc
@@ -4,8 +4,8 @@
#include "cc/quads/content_draw_quad_base.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
@@ -25,13 +25,15 @@ void ContentDrawQuadBase::SetNew(const SharedQuadState* shared_quad_state,
const gfx::Rect& visible_rect,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
- bool swizzle_contents) {
+ bool swizzle_contents,
+ bool nearest_neighbor) {
bool needs_blending = false;
DrawQuad::SetAll(shared_quad_state, material, rect, opaque_rect,
visible_rect, needs_blending);
this->tex_coord_rect = tex_coord_rect;
this->texture_size = texture_size;
this->swizzle_contents = swizzle_contents;
+ this->nearest_neighbor = nearest_neighbor;
}
void ContentDrawQuadBase::SetAll(const SharedQuadState* shared_quad_state,
@@ -42,24 +44,23 @@ void ContentDrawQuadBase::SetAll(const SharedQuadState* shared_quad_state,
bool needs_blending,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
- bool swizzle_contents) {
+ bool swizzle_contents,
+ bool nearest_neighbor) {
DrawQuad::SetAll(shared_quad_state, material, rect, opaque_rect,
visible_rect, needs_blending);
this->tex_coord_rect = tex_coord_rect;
this->texture_size = texture_size;
this->swizzle_contents = swizzle_contents;
+ this->nearest_neighbor = nearest_neighbor;
}
-void ContentDrawQuadBase::ExtendValue(base::debug::TracedValue* value) const {
- value->BeginArray("tex_coord_rect");
- MathUtil::AddToTracedValue(tex_coord_rect, value);
- value->EndArray();
-
- value->BeginDictionary("texture_size");
- MathUtil::AddToTracedValue(texture_size, value);
- value->EndDictionary();
+void ContentDrawQuadBase::ExtendValue(
+ base::trace_event::TracedValue* value) const {
+ MathUtil::AddToTracedValue("tex_coord_rect", tex_coord_rect, value);
+ MathUtil::AddToTracedValue("texture_size", texture_size, value);
value->SetBoolean("swizzle_contents", swizzle_contents);
+ value->SetBoolean("nearest_neighbor", nearest_neighbor);
}
} // namespace cc
diff --git a/chromium/cc/quads/content_draw_quad_base.h b/chromium/cc/quads/content_draw_quad_base.h
index b0e53dcb0ad..f80e06c2fcf 100644
--- a/chromium/cc/quads/content_draw_quad_base.h
+++ b/chromium/cc/quads/content_draw_quad_base.h
@@ -8,7 +8,6 @@
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "cc/quads/draw_quad.h"
-#include "third_party/khronos/GLES2/gl2.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
@@ -23,7 +22,8 @@ class CC_EXPORT ContentDrawQuadBase : public DrawQuad {
const gfx::Rect& visible_rect,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
- bool swizzle_contents);
+ bool swizzle_contents,
+ bool nearest_neighbor);
void SetAll(const SharedQuadState* shared_quad_state,
DrawQuad::Material material,
@@ -33,16 +33,18 @@ class CC_EXPORT ContentDrawQuadBase : public DrawQuad {
bool needs_blending,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
- bool swizzle_contents);
+ bool swizzle_contents,
+ bool nearest_neighbor);
gfx::RectF tex_coord_rect;
gfx::Size texture_size;
bool swizzle_contents;
+ bool nearest_neighbor;
protected:
ContentDrawQuadBase();
~ContentDrawQuadBase() override;
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/debug_border_draw_quad.cc b/chromium/cc/quads/debug_border_draw_quad.cc
index c907be79a6f..f91bf3b84bf 100644
--- a/chromium/cc/quads/debug_border_draw_quad.cc
+++ b/chromium/cc/quads/debug_border_draw_quad.cc
@@ -4,8 +4,8 @@
#include "cc/quads/debug_border_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
namespace cc {
@@ -50,7 +50,8 @@ const DebugBorderDrawQuad* DebugBorderDrawQuad::MaterialCast(
return static_cast<const DebugBorderDrawQuad*>(quad);
}
-void DebugBorderDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void DebugBorderDrawQuad::ExtendValue(
+ base::trace_event::TracedValue* value) const {
value->SetInteger("color", color);
value->SetInteger("width", width);
}
diff --git a/chromium/cc/quads/debug_border_draw_quad.h b/chromium/cc/quads/debug_border_draw_quad.h
index a511ce1bb1d..7ee0d82f2d9 100644
--- a/chromium/cc/quads/debug_border_draw_quad.h
+++ b/chromium/cc/quads/debug_border_draw_quad.h
@@ -38,7 +38,7 @@ class CC_EXPORT DebugBorderDrawQuad : public DrawQuad {
static const DebugBorderDrawQuad* MaterialCast(const DrawQuad*);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/draw_polygon.cc b/chromium/cc/quads/draw_polygon.cc
index 71dbf366dab..6544b641acb 100644
--- a/chromium/cc/quads/draw_polygon.cc
+++ b/chromium/cc/quads/draw_polygon.cc
@@ -12,7 +12,7 @@
namespace {
// This allows for some imperfection in the normal comparison when checking if
// two pieces of geometry are coplanar.
-static const float coplanar_dot_epsilon = 0.01f;
+static const float coplanar_dot_epsilon = 0.001f;
// This threshold controls how "thick" a plane is. If a point's distance is
// <= |compare_threshold|, then it is considered on the plane. Only when this
// boundary is crossed do we consider doing splitting.
@@ -25,21 +25,23 @@ static const float compare_threshold = 1.0f;
// points that SHOULD be intersecting the "thick plane", but actually fail to
// test positively for it because |split_threshold| allowed them to be outside
// this range.
+// This is really supposd to be compare_threshold / 2.0f, but that would
+// create another static initializer.
static const float split_threshold = 0.5f;
+
+static const float normalized_threshold = 0.001f;
} // namespace
namespace cc {
-gfx::Vector3dF DrawPolygon::default_normal = gfx::Vector3dF(0.0f, 0.0f, -1.0f);
-
DrawPolygon::DrawPolygon() {
}
-DrawPolygon::DrawPolygon(DrawQuad* original,
+DrawPolygon::DrawPolygon(const DrawQuad* original,
const std::vector<gfx::Point3F>& in_points,
const gfx::Vector3dF& normal,
int draw_order_index)
- : order_index_(draw_order_index), original_ref_(original) {
+ : order_index_(draw_order_index), original_ref_(original), is_split_(true) {
for (size_t i = 0; i < in_points.size(); i++) {
points_.push_back(in_points[i]);
}
@@ -49,12 +51,14 @@ DrawPolygon::DrawPolygon(DrawQuad* original,
// This takes the original DrawQuad that this polygon should be based on,
// a visible content rect to make the 4 corner points from, and a transformation
// to move it and its normal into screen space.
-DrawPolygon::DrawPolygon(DrawQuad* original_ref,
+DrawPolygon::DrawPolygon(const DrawQuad* original_ref,
const gfx::RectF& visible_content_rect,
const gfx::Transform& transform,
int draw_order_index)
- : order_index_(draw_order_index), original_ref_(original_ref) {
- normal_ = default_normal;
+ : normal_(0.0f, 0.0f, 1.0f),
+ order_index_(draw_order_index),
+ original_ref_(original_ref),
+ is_split_(false) {
gfx::Point3F points[8];
int num_vertices_in_clipped_quad;
gfx::QuadF send_quad(visible_content_rect);
@@ -93,10 +97,13 @@ float DrawPolygon::SignedPointDistance(const gfx::Point3F& point) const {
// Checks whether or not shape a lies on the front or back side of b, or
// whether they should be considered coplanar. If on the back side, we
-// say ABeforeB because it should be drawn in that order.
+// say A_BEFORE_B because it should be drawn in that order.
// Assumes that layers are split and there are no intersecting planes.
BspCompareResult DrawPolygon::SideCompare(const DrawPolygon& a,
const DrawPolygon& b) {
+ // Let's make sure that both of these are normalized.
+ DCHECK_GE(normalized_threshold, std::abs(a.normal_.LengthSquared() - 1.0f));
+ DCHECK_GE(normalized_threshold, std::abs(b.normal_.LengthSquared() - 1.0f));
// Right away let's check if they're coplanar
double dot = gfx::DotProduct(a.normal_, b.normal_);
float sign = 0.0f;
@@ -105,7 +112,7 @@ BspCompareResult DrawPolygon::SideCompare(const DrawPolygon& a,
if (std::abs(dot) >= 1.0f - coplanar_dot_epsilon) {
normal_match = true;
// The normals are matching enough that we only have to test one point.
- sign = gfx::DotProduct(a.points_[0] - b.points_[0], b.normal_);
+ sign = b.SignedPointDistance(a.points_[0]);
// Is it on either side of the splitter?
if (sign < -compare_threshold) {
return BSP_BACK;
@@ -168,7 +175,7 @@ static bool LineIntersectPlane(const gfx::Point3F& line_start,
// The case where one vertex lies on the thick-plane and the other
// is outside of it.
- if (std::abs(start_distance) < distance_threshold &&
+ if (std::abs(start_distance) <= distance_threshold &&
std::abs(end_distance) > distance_threshold) {
intersection->SetPoint(line_start.x(), line_start.y(), line_start.z());
return true;
@@ -270,7 +277,7 @@ bool DrawPolygon::Split(const DrawPolygon& splitter,
break;
}
}
- if (current_vertex++ > points_size) {
+ if (current_vertex++ > (points_size)) {
break;
}
}
@@ -284,6 +291,7 @@ bool DrawPolygon::Split(const DrawPolygon& splitter,
// First polygon.
out_points[0].push_back(intersections[0]);
+ DCHECK_GE(vertex_before[1], start1);
for (size_t i = start1; i <= vertex_before[1]; i++) {
out_points[0].push_back(points_[i]);
--points_remaining;
@@ -306,6 +314,9 @@ bool DrawPolygon::Split(const DrawPolygon& splitter,
scoped_ptr<DrawPolygon> poly2(
new DrawPolygon(original_ref_, out_points[1], normal_, order_index_));
+ DCHECK_GE(poly1->points().size(), 3u);
+ DCHECK_GE(poly2->points().size(), 3u);
+
if (SideCompare(*poly1, splitter) == BSP_FRONT) {
*front = poly1.Pass();
*back = poly2.Pass();
diff --git a/chromium/cc/quads/draw_polygon.h b/chromium/cc/quads/draw_polygon.h
index 32643eed23c..b94ff1ef777 100644
--- a/chromium/cc/quads/draw_polygon.h
+++ b/chromium/cc/quads/draw_polygon.h
@@ -24,11 +24,11 @@ class CC_EXPORT DrawPolygon {
DrawPolygon();
~DrawPolygon();
- DrawPolygon(DrawQuad* original_ref,
+ DrawPolygon(const DrawQuad* original_ref,
const std::vector<gfx::Point3F>& in_points,
const gfx::Vector3dF& normal,
int draw_order_index = 0);
- DrawPolygon(DrawQuad* original_ref,
+ DrawPolygon(const DrawQuad* original_ref,
const gfx::RectF& visible_content_rect,
const gfx::Transform& transform,
int draw_order_index = 0);
@@ -56,11 +56,9 @@ class CC_EXPORT DrawPolygon {
const gfx::Vector3dF& normal() const { return normal_; }
const DrawQuad* original_ref() const { return original_ref_; }
int order_index() const { return order_index_; }
-
+ bool is_split() const { return is_split_; }
scoped_ptr<DrawPolygon> CreateCopy();
- static gfx::Vector3dF default_normal;
-
private:
void ApplyTransform(const gfx::Transform& transform);
void ApplyTransformToNormal(const gfx::Transform& transform);
@@ -76,7 +74,8 @@ class CC_EXPORT DrawPolygon {
// we need.
// This DrawQuad is owned by the caller and its lifetime must be preserved
// as long as this DrawPolygon is alive.
- DrawQuad* original_ref_;
+ const DrawQuad* original_ref_;
+ bool is_split_;
};
} // namespace cc
diff --git a/chromium/cc/quads/draw_quad.cc b/chromium/cc/quads/draw_quad.cc
index 7322a7afa1a..ac1b43e6c20 100644
--- a/chromium/cc/quads/draw_quad.cc
+++ b/chromium/cc/quads/draw_quad.cc
@@ -4,8 +4,8 @@
#include "cc/quads/draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
#include "cc/debug/traced_value.h"
@@ -25,9 +25,7 @@
namespace cc {
DrawQuad::DrawQuad()
- : material(INVALID),
- needs_blending(false),
- shared_quad_state() {
+ : material(INVALID), needs_blending(false), shared_quad_state(0) {
}
void DrawQuad::SetAll(const SharedQuadState* shared_quad_state,
@@ -57,43 +55,35 @@ void DrawQuad::SetAll(const SharedQuadState* shared_quad_state,
DrawQuad::~DrawQuad() {
}
-void DrawQuad::AsValueInto(base::debug::TracedValue* value) const {
+void DrawQuad::AsValueInto(base::trace_event::TracedValue* value) const {
value->SetInteger("material", material);
TracedValue::SetIDRef(shared_quad_state, value, "shared_state");
- value->BeginArray("content_space_rect");
- MathUtil::AddToTracedValue(rect, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("content_space_rect", rect, value);
bool rect_is_clipped;
gfx::QuadF rect_as_target_space_quad = MathUtil::MapQuad(
shared_quad_state->content_to_target_transform,
gfx::QuadF(rect),
&rect_is_clipped);
- value->BeginArray("rect_as_target_space_quad");
- MathUtil::AddToTracedValue(rect_as_target_space_quad, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("rect_as_target_space_quad",
+ rect_as_target_space_quad, value);
value->SetBoolean("rect_is_clipped", rect_is_clipped);
- value->BeginArray("content_space_opaque_rect");
- MathUtil::AddToTracedValue(opaque_rect, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("content_space_opaque_rect", opaque_rect, value);
bool opaque_rect_is_clipped;
gfx::QuadF opaque_rect_as_target_space_quad = MathUtil::MapQuad(
shared_quad_state->content_to_target_transform,
gfx::QuadF(opaque_rect),
&opaque_rect_is_clipped);
- value->BeginArray("opaque_rect_as_target_space_quad");
- MathUtil::AddToTracedValue(opaque_rect_as_target_space_quad, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("opaque_rect_as_target_space_quad",
+ opaque_rect_as_target_space_quad, value);
value->SetBoolean("opaque_rect_is_clipped", opaque_rect_is_clipped);
- value->BeginArray("content_space_visible_rect");
- MathUtil::AddToTracedValue(visible_rect, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("content_space_visible_rect", visible_rect, value);
bool visible_rect_is_clipped;
gfx::QuadF visible_rect_as_target_space_quad = MathUtil::MapQuad(
@@ -101,9 +91,8 @@ void DrawQuad::AsValueInto(base::debug::TracedValue* value) const {
gfx::QuadF(visible_rect),
&visible_rect_is_clipped);
- value->BeginArray("visible_rect_as_target_space_quad");
- MathUtil::AddToTracedValue(visible_rect_as_target_space_quad, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("visible_rect_as_target_space_quad",
+ visible_rect_as_target_space_quad, value);
value->SetBoolean("visible_rect_is_clipped", visible_rect_is_clipped);
diff --git a/chromium/cc/quads/draw_quad.h b/chromium/cc/quads/draw_quad.h
index 61ca35863f4..3897d1d1ce8 100644
--- a/chromium/cc/quads/draw_quad.h
+++ b/chromium/cc/quads/draw_quad.h
@@ -11,7 +11,7 @@
#include "cc/resources/resource_provider.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
class Value;
@@ -126,7 +126,7 @@ class CC_EXPORT DrawQuad {
return IsLeftEdge() || IsTopEdge() || IsRightEdge() || IsBottomEdge();
}
- void AsValueInto(base::debug::TracedValue* value) const;
+ void AsValueInto(base::trace_event::TracedValue* value) const;
protected:
DrawQuad();
@@ -137,7 +137,7 @@ class CC_EXPORT DrawQuad {
const gfx::Rect& opaque_rect,
const gfx::Rect& visible_rect,
bool needs_blending);
- virtual void ExtendValue(base::debug::TracedValue* value) const = 0;
+ virtual void ExtendValue(base::trace_event::TracedValue* value) const = 0;
};
} // namespace cc
diff --git a/chromium/cc/quads/draw_quad_unittest.cc b/chromium/cc/quads/draw_quad_unittest.cc
index d3753ca50d4..968a1d059fc 100644
--- a/chromium/cc/quads/draw_quad_unittest.cc
+++ b/chromium/cc/quads/draw_quad_unittest.cc
@@ -23,7 +23,7 @@
#include "cc/quads/texture_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
#include "cc/quads/yuv_video_draw_quad.h"
-#include "cc/resources/picture_pile_impl.h"
+#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
@@ -55,9 +55,9 @@ TEST(DrawQuadTest, CopySharedQuadState) {
scoped_ptr<SharedQuadState> copy(new SharedQuadState);
copy->CopyFrom(state.get());
EXPECT_EQ(quad_transform, copy->content_to_target_transform);
- EXPECT_RECT_EQ(visible_content_rect, copy->visible_content_rect);
+ EXPECT_EQ(visible_content_rect, copy->visible_content_rect);
EXPECT_EQ(opacity, copy->opacity);
- EXPECT_RECT_EQ(clip_rect, copy->clip_rect);
+ EXPECT_EQ(clip_rect, copy->clip_rect);
EXPECT_EQ(is_clipped, copy->is_clipped);
EXPECT_EQ(blend_mode, copy->blend_mode);
}
@@ -88,9 +88,9 @@ void CompareDrawQuad(DrawQuad* quad,
DrawQuad* copy,
SharedQuadState* copy_shared_state) {
EXPECT_EQ(quad->material, copy->material);
- EXPECT_RECT_EQ(quad->rect, copy->rect);
- EXPECT_RECT_EQ(quad->visible_rect, copy->visible_rect);
- EXPECT_RECT_EQ(quad->opaque_rect, copy->opaque_rect);
+ EXPECT_EQ(quad->rect, copy->rect);
+ EXPECT_EQ(quad->visible_rect, copy->visible_rect);
+ EXPECT_EQ(quad->opaque_rect, copy->opaque_rect);
EXPECT_EQ(quad->needs_blending, copy->needs_blending);
EXPECT_EQ(copy_shared_state, copy->shared_quad_state);
}
@@ -313,25 +313,31 @@ void CompareDrawQuad(DrawQuad* quad,
} \
SETUP_AND_COPY_QUAD_NEW(Type, quad_new);
-#define CREATE_QUAD_9_ALL(Type, a, b, c, d, e, f, g, h, i) \
- { \
- QUAD_DATA quad_all->SetAll(shared_state, \
- quad_rect, \
- quad_opaque_rect, \
- quad_visible_rect, \
- needs_blending, \
- a, \
- b, \
- c, \
- d, \
- e, \
- f, \
- g, \
- h, \
- i); \
- } \
+#define CREATE_QUAD_9_ALL(Type, a, b, c, d, e, f, g, h, i) \
+ Type* quad_all = render_pass->CreateAndAppendDrawQuad<Type>(); \
+ { \
+ QUAD_DATA quad_all->SetAll(shared_state, quad_rect, quad_opaque_rect, \
+ quad_visible_rect, needs_blending, a, b, c, d, \
+ e, f, g, h, i); \
+ } \
SETUP_AND_COPY_QUAD_ALL(Type, quad_all);
+#define CREATE_QUAD_10_NEW(Type, a, b, c, d, e, f, g, h, i, j) \
+ Type* quad_new = render_pass->CreateAndAppendDrawQuad<Type>(); \
+ { \
+ QUAD_DATA quad_new->SetNew( \
+ shared_state, quad_rect, a, b, c, d, e, f, g, h, i, j); \
+ } \
+ SETUP_AND_COPY_QUAD_NEW(Type, quad_new);
+
+#define CREATE_QUAD_11_NEW(Type, a, b, c, d, e, f, g, h, i, j, k) \
+ Type* quad_new = render_pass->CreateAndAppendDrawQuad<Type>(); \
+ { \
+ QUAD_DATA quad_new->SetNew(shared_state, quad_rect, a, b, c, d, e, f, g, \
+ h, i, j, k); \
+ } \
+ SETUP_AND_COPY_QUAD_NEW(Type, quad_new);
+
#define CREATE_QUAD_ALL_RP(Type, a, b, c, d, e, f, g, copy_a) \
Type* quad_all = render_pass->CreateAndAppendDrawQuad<Type>(); \
{ \
@@ -361,16 +367,19 @@ void CompareDrawQuad(DrawQuad* quad,
TEST(DrawQuadTest, CopyCheckerboardDrawQuad) {
gfx::Rect visible_rect(40, 50, 30, 20);
SkColor color = 0xfabb0011;
+ float scale = 2.3f;
CREATE_SHARED_STATE();
- CREATE_QUAD_2_NEW(CheckerboardDrawQuad, visible_rect, color);
+ CREATE_QUAD_3_NEW(CheckerboardDrawQuad, visible_rect, color, scale);
EXPECT_EQ(DrawQuad::CHECKERBOARD, copy_quad->material);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(color, copy_quad->color);
+ EXPECT_EQ(scale, copy_quad->scale);
- CREATE_QUAD_1_ALL(CheckerboardDrawQuad, color);
+ CREATE_QUAD_2_ALL(CheckerboardDrawQuad, color, scale);
EXPECT_EQ(DrawQuad::CHECKERBOARD, copy_quad->material);
EXPECT_EQ(color, copy_quad->color);
+ EXPECT_EQ(scale, copy_quad->scale);
}
TEST(DrawQuadTest, CopyDebugBorderDrawQuad) {
@@ -381,7 +390,7 @@ TEST(DrawQuadTest, CopyDebugBorderDrawQuad) {
CREATE_QUAD_3_NEW(DebugBorderDrawQuad, visible_rect, color, width);
EXPECT_EQ(DrawQuad::DEBUG_BORDER, copy_quad->material);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(color, copy_quad->color);
EXPECT_EQ(width, copy_quad->width);
@@ -406,8 +415,8 @@ TEST(DrawQuadTest, CopyIOSurfaceDrawQuad) {
resource_id,
orientation);
EXPECT_EQ(DrawQuad::IO_SURFACE_CONTENT, copy_quad->material);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
- EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
EXPECT_EQ(size, copy_quad->io_surface_size);
EXPECT_EQ(resource_id, copy_quad->io_surface_resource_id);
EXPECT_EQ(orientation, copy_quad->orientation);
@@ -446,7 +455,7 @@ TEST(DrawQuadTest, CopyRenderPassDrawQuad) {
background_filters,
copied_render_pass_id);
EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(copied_render_pass_id, copy_quad->render_pass_id);
EXPECT_EQ(mask_resource_id, copy_quad->mask_resource_id);
EXPECT_EQ(mask_uv_scale.ToString(), copy_quad->mask_uv_scale.ToString());
@@ -485,7 +494,7 @@ TEST(DrawQuadTest, CopySolidColorDrawQuad) {
CREATE_QUAD_3_NEW(
SolidColorDrawQuad, visible_rect, color, force_anti_aliasing_off);
EXPECT_EQ(DrawQuad::SOLID_COLOR, copy_quad->material);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(color, copy_quad->color);
EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off);
@@ -505,8 +514,8 @@ TEST(DrawQuadTest, CopyStreamVideoDrawQuad) {
CREATE_QUAD_4_NEW(
StreamVideoDrawQuad, opaque_rect, visible_rect, resource_id, matrix);
EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
- EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
EXPECT_EQ(resource_id, copy_quad->resource_id);
EXPECT_EQ(matrix, copy_quad->matrix);
@@ -523,7 +532,7 @@ TEST(DrawQuadTest, CopySurfaceDrawQuad) {
CREATE_QUAD_2_NEW(SurfaceDrawQuad, visible_rect, surface_id);
EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(surface_id, copy_quad->surface_id);
CREATE_QUAD_1_ALL(SurfaceDrawQuad, surface_id);
@@ -540,44 +549,49 @@ TEST(DrawQuadTest, CopyTextureDrawQuad) {
gfx::PointF uv_top_left(0.5f, 224.f);
gfx::PointF uv_bottom_right(51.5f, 260.f);
const float vertex_opacity[] = { 1.0f, 1.0f, 1.0f, 1.0f };
- bool flipped = true;
+ bool y_flipped = true;
+ bool nearest_neighbor = true;
CREATE_SHARED_STATE();
- CREATE_QUAD_9_NEW(TextureDrawQuad,
- opaque_rect,
- visible_rect,
- resource_id,
- premultiplied_alpha,
- uv_top_left,
- uv_bottom_right,
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
+ CREATE_QUAD_10_NEW(TextureDrawQuad,
+ opaque_rect,
+ visible_rect,
+ resource_id,
+ premultiplied_alpha,
+ uv_top_left,
+ uv_bottom_right,
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ y_flipped,
+ nearest_neighbor);
EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
- EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
EXPECT_EQ(resource_id, copy_quad->resource_id);
EXPECT_EQ(premultiplied_alpha, copy_quad->premultiplied_alpha);
EXPECT_EQ(uv_top_left, copy_quad->uv_top_left);
EXPECT_EQ(uv_bottom_right, copy_quad->uv_bottom_right);
EXPECT_FLOAT_ARRAY_EQ(vertex_opacity, copy_quad->vertex_opacity, 4);
- EXPECT_EQ(flipped, copy_quad->flipped);
+ EXPECT_EQ(y_flipped, copy_quad->y_flipped);
+ EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
- CREATE_QUAD_7_ALL(TextureDrawQuad,
+ CREATE_QUAD_8_ALL(TextureDrawQuad,
resource_id,
premultiplied_alpha,
uv_top_left,
uv_bottom_right,
SK_ColorTRANSPARENT,
vertex_opacity,
- flipped);
+ y_flipped,
+ nearest_neighbor);
EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material);
EXPECT_EQ(resource_id, copy_quad->resource_id);
EXPECT_EQ(premultiplied_alpha, copy_quad->premultiplied_alpha);
EXPECT_EQ(uv_top_left, copy_quad->uv_top_left);
EXPECT_EQ(uv_bottom_right, copy_quad->uv_bottom_right);
EXPECT_FLOAT_ARRAY_EQ(vertex_opacity, copy_quad->vertex_opacity, 4);
- EXPECT_EQ(flipped, copy_quad->flipped);
+ EXPECT_EQ(y_flipped, copy_quad->y_flipped);
+ EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
}
TEST(DrawQuadTest, CopyTileDrawQuad) {
@@ -587,74 +601,80 @@ TEST(DrawQuadTest, CopyTileDrawQuad) {
gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
gfx::Size texture_size(85, 32);
bool swizzle_contents = true;
+ bool nearest_neighbor = true;
CREATE_SHARED_STATE();
- CREATE_QUAD_6_NEW(TileDrawQuad,
+ CREATE_QUAD_7_NEW(TileDrawQuad,
opaque_rect,
visible_rect,
resource_id,
tex_coord_rect,
texture_size,
- swizzle_contents);
+ swizzle_contents,
+ nearest_neighbor);
EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
- EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(resource_id, copy_quad->resource_id);
EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
EXPECT_EQ(texture_size, copy_quad->texture_size);
EXPECT_EQ(swizzle_contents, copy_quad->swizzle_contents);
+ EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
- CREATE_QUAD_4_ALL(TileDrawQuad,
+ CREATE_QUAD_5_ALL(TileDrawQuad,
resource_id,
tex_coord_rect,
texture_size,
- swizzle_contents);
+ swizzle_contents,
+ nearest_neighbor);
EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
EXPECT_EQ(resource_id, copy_quad->resource_id);
EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
EXPECT_EQ(texture_size, copy_quad->texture_size);
EXPECT_EQ(swizzle_contents, copy_quad->swizzle_contents);
+ EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
}
TEST(DrawQuadTest, CopyYUVVideoDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
gfx::Rect visible_rect(40, 50, 30, 20);
- gfx::RectF tex_coord_rect(0.0f, 0.0f, 0.75f, 0.5f);
+ gfx::RectF ya_tex_coord_rect(40, 50, 30, 20);
+ gfx::RectF uv_tex_coord_rect(20, 25, 15, 10);
+ gfx::Size ya_tex_size(32, 68);
+ gfx::Size uv_tex_size(41, 51);
ResourceProvider::ResourceId y_plane_resource_id = 45;
ResourceProvider::ResourceId u_plane_resource_id = 532;
ResourceProvider::ResourceId v_plane_resource_id = 4;
ResourceProvider::ResourceId a_plane_resource_id = 63;
- YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601_JPEG;
+ YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::JPEG;
CREATE_SHARED_STATE();
- CREATE_QUAD_8_NEW(YUVVideoDrawQuad,
- opaque_rect,
- visible_rect,
- tex_coord_rect,
- y_plane_resource_id,
- u_plane_resource_id,
- v_plane_resource_id,
- a_plane_resource_id,
- color_space);
+ CREATE_QUAD_11_NEW(YUVVideoDrawQuad, opaque_rect, visible_rect,
+ ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size,
+ uv_tex_size, y_plane_resource_id, u_plane_resource_id,
+ v_plane_resource_id, a_plane_resource_id, color_space);
EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
- EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
- EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
+ EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(ya_tex_coord_rect, copy_quad->ya_tex_coord_rect);
+ EXPECT_EQ(uv_tex_coord_rect, copy_quad->uv_tex_coord_rect);
+ EXPECT_EQ(ya_tex_size, copy_quad->ya_tex_size);
+ EXPECT_EQ(uv_tex_size, copy_quad->uv_tex_size);
EXPECT_EQ(y_plane_resource_id, copy_quad->y_plane_resource_id);
EXPECT_EQ(u_plane_resource_id, copy_quad->u_plane_resource_id);
EXPECT_EQ(v_plane_resource_id, copy_quad->v_plane_resource_id);
EXPECT_EQ(a_plane_resource_id, copy_quad->a_plane_resource_id);
EXPECT_EQ(color_space, copy_quad->color_space);
- CREATE_QUAD_6_ALL(YUVVideoDrawQuad,
- tex_coord_rect,
- y_plane_resource_id,
- u_plane_resource_id,
- v_plane_resource_id,
- a_plane_resource_id,
- color_space);
+ CREATE_QUAD_9_ALL(YUVVideoDrawQuad, ya_tex_coord_rect, uv_tex_coord_rect,
+ ya_tex_size, uv_tex_size, y_plane_resource_id,
+ u_plane_resource_id, v_plane_resource_id,
+ a_plane_resource_id, color_space);
EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
- EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
+ EXPECT_EQ(ya_tex_coord_rect, copy_quad->ya_tex_coord_rect);
+ EXPECT_EQ(uv_tex_coord_rect, copy_quad->uv_tex_coord_rect);
+ EXPECT_EQ(ya_tex_size, copy_quad->ya_tex_size);
+ EXPECT_EQ(uv_tex_size, copy_quad->uv_tex_size);
EXPECT_EQ(y_plane_resource_id, copy_quad->y_plane_resource_id);
EXPECT_EQ(u_plane_resource_id, copy_quad->u_plane_resource_id);
EXPECT_EQ(v_plane_resource_id, copy_quad->v_plane_resource_id);
@@ -667,45 +687,40 @@ TEST(DrawQuadTest, CopyPictureDrawQuad) {
gfx::Rect visible_rect(40, 50, 30, 20);
gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
gfx::Size texture_size(85, 32);
+ bool nearest_neighbor = true;
ResourceFormat texture_format = RGBA_8888;
gfx::Rect content_rect(30, 40, 20, 30);
float contents_scale = 3.141592f;
- scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create();
+ scoped_refptr<RasterSource> raster_source =
+ FakePicturePileImpl::CreateEmptyPile(gfx::Size(100, 100),
+ gfx::Size(100, 100));
CREATE_SHARED_STATE();
- CREATE_QUAD_8_NEW(PictureDrawQuad,
- opaque_rect,
- visible_rect,
- tex_coord_rect,
- texture_size,
- texture_format,
- content_rect,
- contents_scale,
- picture_pile);
+ CREATE_QUAD_9_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
+ texture_size, nearest_neighbor, texture_format,
+ content_rect, contents_scale, raster_source);
EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
- EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
- EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
+ EXPECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
EXPECT_EQ(texture_size, copy_quad->texture_size);
+ EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
EXPECT_EQ(texture_format, copy_quad->texture_format);
- EXPECT_RECT_EQ(content_rect, copy_quad->content_rect);
+ EXPECT_EQ(content_rect, copy_quad->content_rect);
EXPECT_EQ(contents_scale, copy_quad->contents_scale);
- EXPECT_EQ(picture_pile, copy_quad->picture_pile);
+ EXPECT_EQ(raster_source, copy_quad->raster_source);
- CREATE_QUAD_6_ALL(PictureDrawQuad,
- tex_coord_rect,
- texture_size,
- texture_format,
- content_rect,
- contents_scale,
- picture_pile);
+ CREATE_QUAD_7_ALL(PictureDrawQuad, tex_coord_rect, texture_size,
+ nearest_neighbor, texture_format, content_rect,
+ contents_scale, raster_source);
EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
EXPECT_EQ(texture_size, copy_quad->texture_size);
+ EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
EXPECT_EQ(texture_format, copy_quad->texture_format);
- EXPECT_RECT_EQ(content_rect, copy_quad->content_rect);
+ EXPECT_EQ(content_rect, copy_quad->content_rect);
EXPECT_EQ(contents_scale, copy_quad->contents_scale);
- EXPECT_EQ(picture_pile, copy_quad->picture_pile);
+ EXPECT_EQ(raster_source, copy_quad->raster_source);
}
class DrawQuadIteratorTest : public testing::Test {
@@ -730,9 +745,10 @@ class DrawQuadIteratorTest : public testing::Test {
TEST_F(DrawQuadIteratorTest, CheckerboardDrawQuad) {
gfx::Rect visible_rect(40, 50, 30, 20);
SkColor color = 0xfabb0011;
+ float scale = 3.2f;
CREATE_SHARED_STATE();
- CREATE_QUAD_2_NEW(CheckerboardDrawQuad, visible_rect, color);
+ CREATE_QUAD_3_NEW(CheckerboardDrawQuad, visible_rect, color, scale);
EXPECT_EQ(0, IterateAndCount(quad_new));
}
@@ -841,19 +857,21 @@ TEST_F(DrawQuadIteratorTest, TextureDrawQuad) {
gfx::PointF uv_top_left(0.5f, 224.f);
gfx::PointF uv_bottom_right(51.5f, 260.f);
const float vertex_opacity[] = { 1.0f, 1.0f, 1.0f, 1.0f };
- bool flipped = true;
+ bool y_flipped = true;
+ bool nearest_neighbor = true;
CREATE_SHARED_STATE();
- CREATE_QUAD_9_NEW(TextureDrawQuad,
- opaque_rect,
- visible_rect,
- resource_id,
- premultiplied_alpha,
- uv_top_left,
- uv_bottom_right,
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
+ CREATE_QUAD_10_NEW(TextureDrawQuad,
+ opaque_rect,
+ visible_rect,
+ resource_id,
+ premultiplied_alpha,
+ uv_top_left,
+ uv_bottom_right,
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ y_flipped,
+ nearest_neighbor);
EXPECT_EQ(resource_id, quad_new->resource_id);
EXPECT_EQ(1, IterateAndCount(quad_new));
EXPECT_EQ(resource_id + 1, quad_new->resource_id);
@@ -866,15 +884,17 @@ TEST_F(DrawQuadIteratorTest, TileDrawQuad) {
gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
gfx::Size texture_size(85, 32);
bool swizzle_contents = true;
+ bool nearest_neighbor = true;
CREATE_SHARED_STATE();
- CREATE_QUAD_6_NEW(TileDrawQuad,
+ CREATE_QUAD_7_NEW(TileDrawQuad,
opaque_rect,
visible_rect,
resource_id,
tex_coord_rect,
texture_size,
- swizzle_contents);
+ swizzle_contents,
+ nearest_neighbor);
EXPECT_EQ(resource_id, quad_new->resource_id);
EXPECT_EQ(1, IterateAndCount(quad_new));
EXPECT_EQ(resource_id + 1, quad_new->resource_id);
@@ -883,23 +903,21 @@ TEST_F(DrawQuadIteratorTest, TileDrawQuad) {
TEST_F(DrawQuadIteratorTest, YUVVideoDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
gfx::Rect visible_rect(40, 50, 30, 20);
- gfx::RectF tex_coord_rect(0.0f, 0.0f, 0.75f, 0.5f);
+ gfx::RectF ya_tex_coord_rect(0.0f, 0.0f, 0.75f, 0.5f);
+ gfx::RectF uv_tex_coord_rect(0.0f, 0.0f, 0.375f, 0.25f);
+ gfx::Size ya_tex_size(32, 68);
+ gfx::Size uv_tex_size(41, 51);
ResourceProvider::ResourceId y_plane_resource_id = 45;
ResourceProvider::ResourceId u_plane_resource_id = 532;
ResourceProvider::ResourceId v_plane_resource_id = 4;
ResourceProvider::ResourceId a_plane_resource_id = 63;
- YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601_JPEG;
+ YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::JPEG;
CREATE_SHARED_STATE();
- CREATE_QUAD_8_NEW(YUVVideoDrawQuad,
- opaque_rect,
- visible_rect,
- tex_coord_rect,
- y_plane_resource_id,
- u_plane_resource_id,
- v_plane_resource_id,
- a_plane_resource_id,
- color_space);
+ CREATE_QUAD_11_NEW(YUVVideoDrawQuad, opaque_rect, visible_rect,
+ ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size,
+ uv_tex_size, y_plane_resource_id, u_plane_resource_id,
+ v_plane_resource_id, a_plane_resource_id, color_space);
EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
EXPECT_EQ(y_plane_resource_id, quad_new->y_plane_resource_id);
EXPECT_EQ(u_plane_resource_id, quad_new->u_plane_resource_id);
@@ -919,21 +937,18 @@ TEST_F(DrawQuadIteratorTest, DISABLED_PictureDrawQuad) {
gfx::Rect visible_rect(40, 50, 30, 20);
gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
gfx::Size texture_size(85, 32);
+ bool nearest_neighbor = true;
ResourceFormat texture_format = RGBA_8888;
gfx::Rect content_rect(30, 40, 20, 30);
float contents_scale = 3.141592f;
- scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create();
+ scoped_refptr<RasterSource> raster_source =
+ FakePicturePileImpl::CreateEmptyPile(gfx::Size(100, 100),
+ gfx::Size(100, 100));
CREATE_SHARED_STATE();
- CREATE_QUAD_8_NEW(PictureDrawQuad,
- opaque_rect,
- visible_rect,
- tex_coord_rect,
- texture_size,
- texture_format,
- content_rect,
- contents_scale,
- picture_pile);
+ CREATE_QUAD_9_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
+ texture_size, nearest_neighbor, texture_format,
+ content_rect, contents_scale, raster_source);
EXPECT_EQ(0, IterateAndCount(quad_new));
}
diff --git a/chromium/cc/quads/io_surface_draw_quad.cc b/chromium/cc/quads/io_surface_draw_quad.cc
index e565a43066b..8a37b0a6f06 100644
--- a/chromium/cc/quads/io_surface_draw_quad.cc
+++ b/chromium/cc/quads/io_surface_draw_quad.cc
@@ -4,8 +4,8 @@
#include "cc/quads/io_surface_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
@@ -57,10 +57,9 @@ const IOSurfaceDrawQuad* IOSurfaceDrawQuad::MaterialCast(
return static_cast<const IOSurfaceDrawQuad*>(quad);
}
-void IOSurfaceDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
- value->BeginDictionary("io_surface_size");
- MathUtil::AddToTracedValue(io_surface_size, value);
- value->EndDictionary();
+void IOSurfaceDrawQuad::ExtendValue(
+ base::trace_event::TracedValue* value) const {
+ MathUtil::AddToTracedValue("io_surface_size", io_surface_size, value);
value->SetInteger("io_surface_resource_id", io_surface_resource_id);
const char* orientation_string = NULL;
diff --git a/chromium/cc/quads/io_surface_draw_quad.h b/chromium/cc/quads/io_surface_draw_quad.h
index ba6438415ae..2c77905cd79 100644
--- a/chromium/cc/quads/io_surface_draw_quad.h
+++ b/chromium/cc/quads/io_surface_draw_quad.h
@@ -48,7 +48,7 @@ class CC_EXPORT IOSurfaceDrawQuad : public DrawQuad {
static const IOSurfaceDrawQuad* MaterialCast(const DrawQuad*);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/largest_draw_quad.cc b/chromium/cc/quads/largest_draw_quad.cc
index 55fcb22f43d..894be0fdbe4 100644
--- a/chromium/cc/quads/largest_draw_quad.cc
+++ b/chromium/cc/quads/largest_draw_quad.cc
@@ -6,15 +6,62 @@
#include <algorithm>
+#include "cc/quads/checkerboard_draw_quad.h"
+#include "cc/quads/debug_border_draw_quad.h"
+#include "cc/quads/io_surface_draw_quad.h"
+#include "cc/quads/picture_draw_quad.h"
#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/stream_video_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/quads/tile_draw_quad.h"
+#include "cc/quads/yuv_video_draw_quad.h"
+
+namespace {
+const size_t kLargestDrawQuadSize =
+ sizeof(cc::RenderPassDrawQuad) > sizeof(cc::StreamVideoDrawQuad)
+ ? sizeof(cc::RenderPassDrawQuad)
+ : sizeof(cc::StreamVideoDrawQuad);
+} // namespace
namespace cc {
size_t LargestDrawQuadSize() {
- // The largest quad is either a RenderPassDrawQuad or a StreamVideoDrawQuad
- // depends on hardware structure.
- return std::max(sizeof(RenderPassDrawQuad), sizeof(StreamVideoDrawQuad));
+ // Currently the largest quad is either a RenderPassDrawQuad or a
+ // StreamVideoDrawQuad depends on hardware structure.
+
+ // Use compile assert to make sure largest is actually larger than all other
+ // type of draw quads.
+ static_assert(sizeof(CheckerboardDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. CheckerboardDrawQuad is "
+ "currently largest.");
+ static_assert(sizeof(DebugBorderDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. DebugBorderDrawQuad is "
+ "currently largest.");
+ static_assert(sizeof(IOSurfaceDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. IOSurfaceDrawQuad is "
+ "currently largest.");
+ static_assert(sizeof(PictureDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. PictureDrawQuad is "
+ "currently largest.");
+ static_assert(sizeof(TextureDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. TextureDrawQuad is "
+ "currently largest.");
+ static_assert(sizeof(SolidColorDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. SolidColorDrawQuad is "
+ "currently largest.");
+ static_assert(sizeof(SurfaceDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. SurfaceDrawQuad is "
+ "currently largest.");
+ static_assert(sizeof(TileDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. TileDrawQuad is "
+ "currently largest.");
+ static_assert(sizeof(YUVVideoDrawQuad) <= kLargestDrawQuadSize,
+ "Largest Draw Quad size needs update. YUVVideoDrawQuad is "
+ "currently largest.");
+
+ return kLargestDrawQuadSize;
}
} // namespace cc
diff --git a/chromium/cc/quads/list_container.cc b/chromium/cc/quads/list_container.cc
index 04e1c972b8c..4edcbdfab56 100644
--- a/chromium/cc/quads/list_container.cc
+++ b/chromium/cc/quads/list_container.cc
@@ -8,6 +8,7 @@
#include <vector>
#include "cc/base/scoped_ptr_vector.h"
+#include "cc/playback/display_item.h"
#include "cc/quads/draw_quad.h"
#include "cc/quads/shared_quad_state.h"
@@ -138,6 +139,26 @@ class ListContainer<BaseElementType>::ListContainerCharAllocator {
return storage_[id];
}
+ size_t FirstInnerListId() const {
+ // |size_| > 0 means that at least one vector in |storage_| will be
+ // non-empty.
+ DCHECK_GT(size_, 0u);
+ size_t id = 0;
+ while (storage_[id]->size == 0)
+ ++id;
+ return id;
+ }
+
+ size_t LastInnerListId() const {
+ // |size_| > 0 means that at least one vector in |storage_| will be
+ // non-empty.
+ DCHECK_GT(size_, 0u);
+ size_t id = list_count_ - 1;
+ while (storage_[id]->size == 0)
+ --id;
+ return id;
+ }
+
void AllocateNewList(size_t list_size) {
++list_count_;
scoped_ptr<InnerList> new_list(new InnerList);
@@ -210,12 +231,16 @@ ListContainer<
typename ListContainerCharAllocator::InnerList* list =
ptr_to_container->InnerListById(vector_index);
if (item_iterator == list->LastElement()) {
- if (vector_index < ptr_to_container->list_count() - 1) {
+ ++vector_index;
+ while (vector_index < ptr_to_container->list_count()) {
+ if (ptr_to_container->InnerListById(vector_index)->size != 0)
+ break;
++vector_index;
+ }
+ if (vector_index < ptr_to_container->list_count())
item_iterator = ptr_to_container->InnerListById(vector_index)->Begin();
- } else {
+ else
item_iterator = NULL;
- }
} else {
item_iterator += list->step;
}
@@ -229,8 +254,16 @@ ListContainer<
typename ListContainerCharAllocator::InnerList* list =
ptr_to_container->InnerListById(vector_index);
if (item_iterator == list->Begin()) {
- if (vector_index > 0) {
+ --vector_index;
+ // Since |vector_index| is unsigned, we compare < list_count() instead of
+ // comparing >= 0, as the variable will wrap around when it goes out of
+ // range (below 0).
+ while (vector_index < ptr_to_container->list_count()) {
+ if (ptr_to_container->InnerListById(vector_index)->size != 0)
+ break;
--vector_index;
+ }
+ if (vector_index < ptr_to_container->list_count()) {
item_iterator =
ptr_to_container->InnerListById(vector_index)->LastElement();
} else {
@@ -281,17 +314,18 @@ template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstReverseIterator
ListContainer<BaseElementType>::crbegin() const {
if (data_->IsEmpty())
- return ConstReverseIterator(data_.get(), 0, NULL, 0);
+ return crend();
- size_t last_id = data_->list_count() - 1;
- return ConstReverseIterator(
- data_.get(), last_id, data_->InnerListById(last_id)->LastElement(), 0);
+ size_t id = data_->LastInnerListId();
+ return ConstReverseIterator(data_.get(), id,
+ data_->InnerListById(id)->LastElement(), 0);
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstReverseIterator
ListContainer<BaseElementType>::crend() const {
- return ConstReverseIterator(data_.get(), 0, NULL, size());
+ return ConstReverseIterator(data_.get(), static_cast<size_t>(-1), NULL,
+ size());
}
template <typename BaseElementType>
@@ -310,26 +344,27 @@ template <typename BaseElementType>
typename ListContainer<BaseElementType>::ReverseIterator
ListContainer<BaseElementType>::rbegin() {
if (data_->IsEmpty())
- return ReverseIterator(data_.get(), 0, NULL, 0);
+ return rend();
- size_t last_id = data_->list_count() - 1;
- return ReverseIterator(
- data_.get(), last_id, data_->InnerListById(last_id)->LastElement(), 0);
+ size_t id = data_->LastInnerListId();
+ return ReverseIterator(data_.get(), id,
+ data_->InnerListById(id)->LastElement(), 0);
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ReverseIterator
ListContainer<BaseElementType>::rend() {
- return ReverseIterator(data_.get(), 0, NULL, size());
+ return ReverseIterator(data_.get(), static_cast<size_t>(-1), NULL, size());
}
template <typename BaseElementType>
typename ListContainer<BaseElementType>::ConstIterator
ListContainer<BaseElementType>::cbegin() const {
if (data_->IsEmpty())
- return ConstIterator(data_.get(), 0, NULL, 0);
+ return cend();
- return ConstIterator(data_.get(), 0, data_->InnerListById(0)->Begin(), 0);
+ size_t id = data_->FirstInnerListId();
+ return ConstIterator(data_.get(), id, data_->InnerListById(id)->Begin(), 0);
}
template <typename BaseElementType>
@@ -338,8 +373,8 @@ ListContainer<BaseElementType>::cend() const {
if (data_->IsEmpty())
return ConstIterator(data_.get(), 0, NULL, size());
- size_t last_id = data_->list_count() - 1;
- return ConstIterator(data_.get(), last_id, NULL, size());
+ size_t id = data_->list_count();
+ return ConstIterator(data_.get(), id, NULL, size());
}
template <typename BaseElementType>
@@ -358,9 +393,10 @@ template <typename BaseElementType>
typename ListContainer<BaseElementType>::Iterator
ListContainer<BaseElementType>::begin() {
if (data_->IsEmpty())
- return Iterator(data_.get(), 0, NULL, 0);
+ return end();
- return Iterator(data_.get(), 0, data_->InnerListById(0)->Begin(), 0);
+ size_t id = data_->FirstInnerListId();
+ return Iterator(data_.get(), id, data_->InnerListById(id)->Begin(), 0);
}
template <typename BaseElementType>
@@ -369,8 +405,8 @@ ListContainer<BaseElementType>::end() {
if (data_->IsEmpty())
return Iterator(data_.get(), 0, NULL, size());
- size_t last_id = data_->list_count() - 1;
- return Iterator(data_.get(), last_id, NULL, size());
+ size_t id = data_->list_count();
+ return Iterator(data_.get(), id, NULL, size());
}
template <typename BaseElementType>
@@ -433,11 +469,10 @@ BaseElementType* ListContainer<BaseElementType>::ElementAt(size_t index) {
}
template <typename BaseElementType>
-BaseElementType* ListContainer<BaseElementType>::Allocate(
+void* ListContainer<BaseElementType>::Allocate(
size_t size_of_actual_element_in_bytes) {
DCHECK_LE(size_of_actual_element_in_bytes, data_->element_size());
- void* result = data_->Allocate();
- return static_cast<BaseElementType*>(result);
+ return data_->Allocate();
}
template <typename BaseElementType>
@@ -680,5 +715,6 @@ size_t ListContainer<BaseElementType>::ConstReverseIterator::index() const {
template class ListContainer<SharedQuadState>;
template class ListContainer<DrawQuad>;
+template class ListContainer<DisplayItem>;
} // namespace cc
diff --git a/chromium/cc/quads/list_container.h b/chromium/cc/quads/list_container.h
index dd313fc8b45..8abc33d62eb 100644
--- a/chromium/cc/quads/list_container.h
+++ b/chromium/cc/quads/list_container.h
@@ -10,8 +10,9 @@
#include "cc/base/cc_export.h"
namespace cc {
-class SharedQuadState;
+class DisplayItem;
class DrawQuad;
+class SharedQuadState;
// This class is a container type that handles allocating contiguous memory for
// new elements and traversing through elements with either iterator or reverse
@@ -209,6 +210,12 @@ class CC_EXPORT ListContainer {
return new (Allocate(sizeof(DerivedElementType)))
DerivedElementType(*source);
}
+ // Construct a new element on top of an existing one.
+ template <typename DerivedElementType>
+ DerivedElementType* ReplaceExistingElement(Iterator at) {
+ at->~BaseElementType();
+ return new (*at) DerivedElementType();
+ }
size_t size() const;
bool empty() const;
@@ -218,7 +225,7 @@ class CC_EXPORT ListContainer {
private:
// Hands out memory location for an element at the end of data structure.
- BaseElementType* Allocate(size_t size_of_actual_element_in_bytes);
+ void* Allocate(size_t size_of_actual_element_in_bytes);
scoped_ptr<ListContainerCharAllocator> data_;
@@ -228,6 +235,7 @@ class CC_EXPORT ListContainer {
#if !defined(COMPILER_MSVC)
extern template class ListContainer<SharedQuadState>;
extern template class ListContainer<DrawQuad>;
+extern template class ListContainer<DisplayItem>;
#endif
} // namespace cc
diff --git a/chromium/cc/quads/list_container_unittest.cc b/chromium/cc/quads/list_container_unittest.cc
index 3ef677c6641..5de1ddd1941 100644
--- a/chromium/cc/quads/list_container_unittest.cc
+++ b/chromium/cc/quads/list_container_unittest.cc
@@ -34,7 +34,7 @@ class SimpleDrawQuad : public DrawQuad {
void set_value(int val) { value = val; }
int get_value() { return value; }
- void ExtendValue(base::debug::TracedValue* value) const override {}
+ void ExtendValue(base::trace_event::TracedValue* value) const override {}
private:
int value;
@@ -54,17 +54,22 @@ class SimpleDrawQuadConstructMagicNumberTwo : public SimpleDrawQuad {
}
};
-class MockDrawQuad : public DrawQuad {
+class MockDrawQuad : public SimpleDrawQuadConstructMagicNumberOne {
public:
- virtual ~MockDrawQuad() { Destruct(); }
- virtual void IterateResources(
- const ResourceIteratorCallback& callback) override {}
- virtual void ExtendValue(base::debug::TracedValue* value) const override {}
+ ~MockDrawQuad() override { Destruct(); }
MOCK_METHOD0(Destruct, void());
};
+class MockDrawQuadSubclass : public MockDrawQuad {
+ public:
+ MockDrawQuadSubclass() { set_value(kMagicNumberToUseForDrawQuadTwo); }
+};
+
+const size_t kLargestQuadSize =
+ std::max(LargestDrawQuadSize(), sizeof(MockDrawQuadSubclass));
+
TEST(ListContainerTest, ConstructorCalledInAllocateAndConstruct) {
- ListContainer<DrawQuad> list(LargestDrawQuadSize());
+ ListContainer<DrawQuad> list(kLargestQuadSize);
size_t size = 2;
SimpleDrawQuadConstructMagicNumberOne* dq_1 =
@@ -81,7 +86,7 @@ TEST(ListContainerTest, ConstructorCalledInAllocateAndConstruct) {
}
TEST(ListContainerTest, DestructorCalled) {
- ListContainer<DrawQuad> list(LargestDrawQuadSize());
+ ListContainer<DrawQuad> list(kLargestQuadSize);
size_t size = 1;
MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
@@ -92,7 +97,7 @@ TEST(ListContainerTest, DestructorCalled) {
}
TEST(ListContainerTest, DestructorCalledOnceWhenClear) {
- ListContainer<DrawQuad> list(LargestDrawQuadSize());
+ ListContainer<DrawQuad> list(kLargestQuadSize);
size_t size = 1;
MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
@@ -113,8 +118,34 @@ TEST(ListContainerTest, DestructorCalledOnceWhenClear) {
separator.Call();
}
+TEST(ListContainerTest, ReplaceExistingElement) {
+ ListContainer<DrawQuad> list(kLargestQuadSize);
+ size_t size = 1;
+ MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
+
+ EXPECT_EQ(size, list.size());
+ EXPECT_EQ(dq_1, list.front());
+
+ // Make sure destructor is called once during clear, and won't be called
+ // again.
+ testing::MockFunction<void()> separator;
+ {
+ testing::InSequence s;
+ EXPECT_CALL(*dq_1, Destruct());
+ EXPECT_CALL(separator, Call());
+ EXPECT_CALL(*dq_1, Destruct()).Times(0);
+ }
+
+ list.ReplaceExistingElement<MockDrawQuadSubclass>(list.begin());
+ EXPECT_EQ(kMagicNumberToUseForDrawQuadTwo, dq_1->get_value());
+ separator.Call();
+
+ EXPECT_CALL(*dq_1, Destruct());
+ list.clear();
+}
+
TEST(ListContainerTest, DestructorCalledOnceWhenErase) {
- ListContainer<DrawQuad> list(LargestDrawQuadSize());
+ ListContainer<DrawQuad> list(kLargestQuadSize);
size_t size = 1;
MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
@@ -435,7 +466,7 @@ TEST(ListContainerTest, SimpleReverseInsertionSharedQuadState) {
}
TEST(ListContainerTest, SimpleDeletion) {
- ListContainer<DrawQuad> list(LargestDrawQuadSize());
+ ListContainer<DrawQuad> list(kLargestQuadSize);
std::vector<SimpleDrawQuad*> sdq_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
@@ -456,8 +487,89 @@ TEST(ListContainerTest, SimpleDeletion) {
}
}
+TEST(ListContainerTest, DeletionAllInAllocation) {
+ const size_t kReserve = 10;
+ ListContainer<DrawQuad> list(kLargestQuadSize, kReserve);
+ std::vector<SimpleDrawQuad*> sdq_list;
+ // Add enough quads to cause another allocation.
+ for (size_t i = 0; i < kReserve + 1; ++i) {
+ sdq_list.push_back(list.AllocateAndConstruct<SimpleDrawQuad>());
+ sdq_list.back()->set_value(static_cast<int>(i));
+ }
+ EXPECT_EQ(kReserve + 1, list.size());
+
+ // Remove everything in the first allocation.
+ for (size_t i = 0; i < kReserve; ++i)
+ list.EraseAndInvalidateAllPointers(list.begin());
+ EXPECT_EQ(1u, list.size());
+
+ // The last quad is left.
+ SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*list.begin());
+ EXPECT_EQ(static_cast<int>(kReserve), quad->get_value());
+
+ // Remove the quad from the 2nd allocation.
+ list.EraseAndInvalidateAllPointers(list.begin());
+ EXPECT_EQ(0u, list.size());
+}
+
+TEST(ListContainerTest, DeletionAllInAllocationReversed) {
+ const size_t kReserve = 10;
+ ListContainer<DrawQuad> list(kLargestQuadSize, kReserve);
+ std::vector<SimpleDrawQuad*> sdq_list;
+ // Add enough quads to cause another allocation.
+ for (size_t i = 0; i < kReserve + 1; ++i) {
+ sdq_list.push_back(list.AllocateAndConstruct<SimpleDrawQuad>());
+ sdq_list.back()->set_value(static_cast<int>(i));
+ }
+ EXPECT_EQ(kReserve + 1, list.size());
+
+ // Remove everything in the 2nd allocation.
+ auto it = list.begin();
+ for (size_t i = 0; i < kReserve; ++i)
+ ++it;
+ list.EraseAndInvalidateAllPointers(it);
+
+ // The 2nd-last quad is next, and the rest of the quads exist.
+ size_t i = kReserve - 1;
+ for (auto it = list.rbegin(); it != list.rend(); ++it) {
+ SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*it);
+ EXPECT_EQ(static_cast<int>(i), quad->get_value());
+ --i;
+ }
+
+ // Can forward iterate too.
+ i = 0;
+ for (auto it = list.begin(); it != list.end(); ++it) {
+ SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*it);
+ EXPECT_EQ(static_cast<int>(i), quad->get_value());
+ ++i;
+ }
+
+ // Remove the last thing from the 1st allocation.
+ it = list.begin();
+ for (size_t i = 0; i < kReserve - 1; ++i)
+ ++it;
+ list.EraseAndInvalidateAllPointers(it);
+
+ // The 2nd-last quad is next, and the rest of the quads exist.
+ i = kReserve - 2;
+ for (auto it = list.rbegin(); it != list.rend(); ++it) {
+ SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*it);
+ EXPECT_EQ(static_cast<int>(i), quad->get_value());
+ --i;
+ }
+
+ // Can forward iterate too.
+ i = 0;
+ for (auto it = list.begin(); it != list.end(); ++it) {
+ SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*it);
+ EXPECT_EQ(static_cast<int>(i), quad->get_value());
+ ++i;
+ }
+}
+
TEST(ListContainerTest, SimpleIterationAndManipulation) {
- ListContainer<DrawQuad> list(LargestDrawQuadSize());
+ ListContainer<DrawQuad> list(kLargestQuadSize);
std::vector<SimpleDrawQuad*> sdq_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
@@ -482,7 +594,7 @@ TEST(ListContainerTest, SimpleIterationAndManipulation) {
}
TEST(ListContainerTest, SimpleManipulationWithIndexSimpleDrawQuad) {
- ListContainer<DrawQuad> list(LargestDrawQuadSize());
+ ListContainer<DrawQuad> list(kLargestQuadSize);
std::vector<SimpleDrawQuad*> dq_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
diff --git a/chromium/cc/quads/picture_draw_quad.cc b/chromium/cc/quads/picture_draw_quad.cc
index af120a41e39..af6fba12db0 100644
--- a/chromium/cc/quads/picture_draw_quad.cc
+++ b/chromium/cc/quads/picture_draw_quad.cc
@@ -4,7 +4,7 @@
#include "cc/quads/picture_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
#include "cc/resources/platform_color.h"
@@ -23,10 +23,11 @@ void PictureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
const gfx::Rect& visible_rect,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
+ bool nearest_neighbor,
ResourceFormat texture_format,
const gfx::Rect& content_rect,
float contents_scale,
- scoped_refptr<PicturePileImpl> picture_pile) {
+ scoped_refptr<RasterSource> raster_source) {
ContentDrawQuadBase::SetNew(
shared_quad_state,
DrawQuad::PICTURE_CONTENT,
@@ -35,10 +36,11 @@ void PictureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
visible_rect,
tex_coord_rect,
texture_size,
- !PlatformColor::SameComponentOrder(texture_format));
+ !PlatformColor::SameComponentOrder(texture_format),
+ nearest_neighbor);
this->content_rect = content_rect;
this->contents_scale = contents_scale;
- this->picture_pile = picture_pile;
+ this->raster_source = raster_source;
this->texture_format = texture_format;
}
@@ -49,10 +51,11 @@ void PictureDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
bool needs_blending,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
+ bool nearest_neighbor,
ResourceFormat texture_format,
const gfx::Rect& content_rect,
float contents_scale,
- scoped_refptr<PicturePileImpl> picture_pile) {
+ scoped_refptr<RasterSource> raster_source) {
ContentDrawQuadBase::SetAll(shared_quad_state,
DrawQuad::PICTURE_CONTENT,
rect,
@@ -62,10 +65,11 @@ void PictureDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
tex_coord_rect,
texture_size,
!PlatformColor::SameComponentOrder(
- texture_format));
+ texture_format),
+ nearest_neighbor);
this->content_rect = content_rect;
this->contents_scale = contents_scale;
- this->picture_pile = picture_pile;
+ this->raster_source = raster_source;
this->texture_format = texture_format;
}
@@ -80,14 +84,12 @@ const PictureDrawQuad* PictureDrawQuad::MaterialCast(const DrawQuad* quad) {
return static_cast<const PictureDrawQuad*>(quad);
}
-void PictureDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void PictureDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
ContentDrawQuadBase::ExtendValue(value);
- value->BeginArray("content_rect");
- MathUtil::AddToTracedValue(content_rect, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("content_rect", content_rect, value);
value->SetDouble("contents_scale", contents_scale);
value->SetInteger("texture_format", texture_format);
- // TODO(piman): picture_pile?
+ // TODO(piman): raster_source?
}
} // namespace cc
diff --git a/chromium/cc/quads/picture_draw_quad.h b/chromium/cc/quads/picture_draw_quad.h
index 1bea1a20048..243a2f9d174 100644
--- a/chromium/cc/quads/picture_draw_quad.h
+++ b/chromium/cc/quads/picture_draw_quad.h
@@ -8,8 +8,8 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
+#include "cc/playback/raster_source.h"
#include "cc/quads/content_draw_quad_base.h"
-#include "cc/resources/picture_pile_impl.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
@@ -28,10 +28,11 @@ class CC_EXPORT PictureDrawQuad : public ContentDrawQuadBase {
const gfx::Rect& visible_rect,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
+ bool nearest_neighbor,
ResourceFormat texture_format,
const gfx::Rect& content_rect,
float contents_scale,
- scoped_refptr<PicturePileImpl> picture_pile);
+ scoped_refptr<RasterSource> raster_source);
void SetAll(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
@@ -40,14 +41,15 @@ class CC_EXPORT PictureDrawQuad : public ContentDrawQuadBase {
bool needs_blending,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
+ bool nearest_neighbor,
ResourceFormat texture_format,
const gfx::Rect& content_rect,
float contents_scale,
- scoped_refptr<PicturePileImpl> picture_pile);
+ scoped_refptr<RasterSource> raster_source);
gfx::Rect content_rect;
float contents_scale;
- scoped_refptr<PicturePileImpl> picture_pile;
+ scoped_refptr<RasterSource> raster_source;
ResourceFormat texture_format;
void IterateResources(const ResourceIteratorCallback& callback) override;
@@ -55,7 +57,7 @@ class CC_EXPORT PictureDrawQuad : public ContentDrawQuadBase {
static const PictureDrawQuad* MaterialCast(const DrawQuad* quad);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/render_pass.cc b/chromium/cc/quads/render_pass.cc
index a1426f53416..567145a82d6 100644
--- a/chromium/cc/quads/render_pass.cc
+++ b/chromium/cc/quads/render_pass.cc
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
#include "cc/debug/traced_value.h"
@@ -180,14 +180,9 @@ void RenderPass::SetAll(RenderPassId id,
DCHECK(shared_quad_state_list.empty());
}
-void RenderPass::AsValueInto(base::debug::TracedValue* value) const {
- value->BeginArray("output_rect");
- MathUtil::AddToTracedValue(output_rect, value);
- value->EndArray();
-
- value->BeginArray("damage_rect");
- MathUtil::AddToTracedValue(damage_rect, value);
- value->EndArray();
+void RenderPass::AsValueInto(base::trace_event::TracedValue* value) const {
+ MathUtil::AddToTracedValue("output_rect", output_rect, value);
+ MathUtil::AddToTracedValue("damage_rect", damage_rect, value);
value->SetBoolean("has_transparent_background", has_transparent_background);
value->SetInteger("copy_requests", copy_requests.size());
diff --git a/chromium/cc/quads/render_pass.h b/chromium/cc/quads/render_pass.h
index 28775883e5b..46a8084b387 100644
--- a/chromium/cc/quads/render_pass.h
+++ b/chromium/cc/quads/render_pass.h
@@ -20,11 +20,11 @@
#include "ui/gfx/transform.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
class Value;
-};
+}
namespace cc {
@@ -77,7 +77,7 @@ class CC_EXPORT RenderPass {
const gfx::Transform& transform_to_root_target,
bool has_transparent_background);
- void AsValueInto(base::debug::TracedValue* dict) const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
SharedQuadState* CreateAndAppendSharedQuadState();
diff --git a/chromium/cc/quads/render_pass_draw_quad.cc b/chromium/cc/quads/render_pass_draw_quad.cc
index 88f608d4ce8..963a1906ee7 100644
--- a/chromium/cc/quads/render_pass_draw_quad.cc
+++ b/chromium/cc/quads/render_pass_draw_quad.cc
@@ -4,7 +4,7 @@
#include "cc/quads/render_pass_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
#include "cc/debug/traced_value.h"
@@ -95,25 +95,17 @@ const RenderPassDrawQuad* RenderPassDrawQuad::MaterialCast(
return static_cast<const RenderPassDrawQuad*>(quad);
}
-void RenderPassDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void RenderPassDrawQuad::ExtendValue(
+ base::trace_event::TracedValue* value) const {
TracedValue::SetIDRef(render_pass_id.AsTracingId(), value, "render_pass_id");
value->SetInteger("mask_resource_id", mask_resource_id);
-
- value->BeginArray("mask_texture_size");
- MathUtil::AddToTracedValue(mask_texture_size, value);
- value->EndArray();
-
- value->BeginArray("mask_uv_scale");
- MathUtil::AddToTracedValue(mask_uv_scale, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("mask_texture_size", mask_texture_size, value);
+ MathUtil::AddToTracedValue("mask_uv_scale", mask_uv_scale, value);
value->BeginDictionary("filters");
filters.AsValueInto(value);
value->EndDictionary();
-
- value->BeginArray("filters_scale");
- MathUtil::AddToTracedValue(filters_scale, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("filters_scale", filters_scale, value);
value->BeginDictionary("background_filters");
background_filters.AsValueInto(value);
diff --git a/chromium/cc/quads/render_pass_draw_quad.h b/chromium/cc/quads/render_pass_draw_quad.h
index 95ca2f226b5..758b8e85004 100644
--- a/chromium/cc/quads/render_pass_draw_quad.h
+++ b/chromium/cc/quads/render_pass_draw_quad.h
@@ -70,7 +70,7 @@ class CC_EXPORT RenderPassDrawQuad : public DrawQuad {
static const RenderPassDrawQuad* MaterialCast(const DrawQuad*);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/render_pass_id.cc b/chromium/cc/quads/render_pass_id.cc
index d15240dba80..a84582c5ce3 100644
--- a/chromium/cc/quads/render_pass_id.cc
+++ b/chromium/cc/quads/render_pass_id.cc
@@ -7,8 +7,8 @@
namespace cc {
void* RenderPassId::AsTracingId() const {
- COMPILE_ASSERT(sizeof(size_t) <= sizeof(void*), // NOLINT
- size_t_bigger_than_pointer);
+ static_assert(sizeof(size_t) <= sizeof(void*), // NOLINT
+ "size of size_t should not be greater than that of a pointer");
return reinterpret_cast<void*>(base::HashPair(layer_id, index));
}
diff --git a/chromium/cc/quads/render_pass_unittest.cc b/chromium/cc/quads/render_pass_unittest.cc
index 4c3753f36b2..e6f39bcab82 100644
--- a/chromium/cc/quads/render_pass_unittest.cc
+++ b/chromium/cc/quads/render_pass_unittest.cc
@@ -41,10 +41,10 @@ static void CompareRenderPassLists(const RenderPassList& expected_list,
RenderPass* actual = actual_list[i];
EXPECT_EQ(expected->id, actual->id);
- EXPECT_RECT_EQ(expected->output_rect, actual->output_rect);
+ EXPECT_EQ(expected->output_rect, actual->output_rect);
EXPECT_EQ(expected->transform_to_root_target,
actual->transform_to_root_target);
- EXPECT_RECT_EQ(expected->damage_rect, actual->damage_rect);
+ EXPECT_EQ(expected->damage_rect, actual->damage_rect);
EXPECT_EQ(expected->has_transparent_background,
actual->has_transparent_background);
@@ -92,16 +92,16 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) {
CheckerboardDrawQuad* checkerboard_quad =
pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
- checkerboard_quad->SetNew(
- pass->shared_quad_state_list.back(), gfx::Rect(), gfx::Rect(), SkColor());
+ checkerboard_quad->SetNew(pass->shared_quad_state_list.back(), gfx::Rect(),
+ gfx::Rect(), SkColor(), 1.f);
RenderPassId new_id(63, 4);
scoped_ptr<RenderPass> copy = pass->Copy(new_id);
EXPECT_EQ(new_id, copy->id);
- EXPECT_RECT_EQ(pass->output_rect, copy->output_rect);
+ EXPECT_EQ(pass->output_rect, copy->output_rect);
EXPECT_EQ(pass->transform_to_root_target, copy->transform_to_root_target);
- EXPECT_RECT_EQ(pass->damage_rect, copy->damage_rect);
+ EXPECT_EQ(pass->damage_rect, copy->damage_rect);
EXPECT_EQ(pass->has_transparent_background, copy->has_transparent_background);
EXPECT_EQ(0u, copy->quad_list.size());
@@ -143,16 +143,14 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
CheckerboardDrawQuad* checkerboard_quad1 =
pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
checkerboard_quad1->SetNew(pass->shared_quad_state_list.back(),
- gfx::Rect(1, 1, 1, 1),
- gfx::Rect(1, 1, 1, 1),
- SkColor());
+ gfx::Rect(1, 1, 1, 1), gfx::Rect(1, 1, 1, 1),
+ SkColor(), 1.f);
CheckerboardDrawQuad* checkerboard_quad2 =
pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
checkerboard_quad2->SetNew(pass->shared_quad_state_list.back(),
- gfx::Rect(2, 2, 2, 2),
- gfx::Rect(2, 2, 2, 2),
- SkColor());
+ gfx::Rect(2, 2, 2, 2), gfx::Rect(2, 2, 2, 2),
+ SkColor(), 1.f);
// And two quads using another shared state.
SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
@@ -168,16 +166,14 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
CheckerboardDrawQuad* checkerboard_quad3 =
pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
checkerboard_quad3->SetNew(pass->shared_quad_state_list.back(),
- gfx::Rect(3, 3, 3, 3),
- gfx::Rect(3, 3, 3, 3),
- SkColor());
+ gfx::Rect(3, 3, 3, 3), gfx::Rect(3, 3, 3, 3),
+ SkColor(), 1.f);
CheckerboardDrawQuad* checkerboard_quad4 =
pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
checkerboard_quad4->SetNew(pass->shared_quad_state_list.back(),
- gfx::Rect(4, 4, 4, 4),
- gfx::Rect(4, 4, 4, 4),
- SkColor());
+ gfx::Rect(4, 4, 4, 4), gfx::Rect(4, 4, 4, 4),
+ SkColor(), 1.f);
// A second render pass with a quad.
RenderPassId contrib_id(4, 1);
@@ -208,9 +204,8 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
CheckerboardDrawQuad* contrib_quad =
contrib->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
contrib_quad->SetNew(contrib->shared_quad_state_list.back(),
- gfx::Rect(3, 3, 3, 3),
- gfx::Rect(3, 3, 3, 3),
- SkColor());
+ gfx::Rect(3, 3, 3, 3), gfx::Rect(3, 3, 3, 3), SkColor(),
+ 1.f);
// And a RenderPassDrawQuad for the contributing pass.
scoped_ptr<RenderPassDrawQuad> pass_quad =
@@ -267,9 +262,8 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) {
CheckerboardDrawQuad* checkerboard_quad1 =
pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
checkerboard_quad1->SetNew(pass->shared_quad_state_list.back(),
- gfx::Rect(1, 1, 1, 1),
- gfx::Rect(1, 1, 1, 1),
- SkColor());
+ gfx::Rect(1, 1, 1, 1), gfx::Rect(1, 1, 1, 1),
+ SkColor(), 1.f);
// A shared state with no quads, they were culled.
SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
@@ -307,9 +301,8 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) {
CheckerboardDrawQuad* checkerboard_quad2 =
pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
checkerboard_quad2->SetNew(pass->shared_quad_state_list.back(),
- gfx::Rect(3, 3, 3, 3),
- gfx::Rect(3, 3, 3, 3),
- SkColor());
+ gfx::Rect(3, 3, 3, 3), gfx::Rect(3, 3, 3, 3),
+ SkColor(), 1.f);
pass_list.push_back(pass.Pass());
diff --git a/chromium/cc/quads/shared_quad_state.cc b/chromium/cc/quads/shared_quad_state.cc
index 83df3657def..5e46fcc24d7 100644
--- a/chromium/cc/quads/shared_quad_state.cc
+++ b/chromium/cc/quads/shared_quad_state.cc
@@ -4,7 +4,7 @@
#include "cc/quads/shared_quad_state.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
#include "cc/debug/traced_value.h"
@@ -46,24 +46,15 @@ void SharedQuadState::SetAll(const gfx::Transform& content_to_target_transform,
this->sorting_context_id = sorting_context_id;
}
-void SharedQuadState::AsValueInto(base::debug::TracedValue* value) const {
- value->BeginArray("transform");
- MathUtil::AddToTracedValue(content_to_target_transform, value);
- value->EndArray();
-
- value->BeginDictionary("layer_content_bounds");
- MathUtil::AddToTracedValue(content_bounds, value);
- value->EndDictionary();
-
- value->BeginArray("layer_visible_content_rect");
- MathUtil::AddToTracedValue(visible_content_rect, value);
- value->EndArray();
+void SharedQuadState::AsValueInto(base::trace_event::TracedValue* value) const {
+ MathUtil::AddToTracedValue("transform", content_to_target_transform, value);
+ MathUtil::AddToTracedValue("layer_content_bounds", content_bounds, value);
+ MathUtil::AddToTracedValue("layer_visible_content_rect", visible_content_rect,
+ value);
value->SetBoolean("is_clipped", is_clipped);
- value->BeginArray("clip_rect");
- MathUtil::AddToTracedValue(clip_rect, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("clip_rect", clip_rect, value);
value->SetDouble("opacity", opacity);
value->SetString("blend_mode", SkXfermode::ModeName(blend_mode));
diff --git a/chromium/cc/quads/shared_quad_state.h b/chromium/cc/quads/shared_quad_state.h
index ebf7d11986e..6f0ef92908d 100644
--- a/chromium/cc/quads/shared_quad_state.h
+++ b/chromium/cc/quads/shared_quad_state.h
@@ -12,7 +12,7 @@
#include "ui/gfx/transform.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
class Value;
@@ -40,7 +40,7 @@ class CC_EXPORT SharedQuadState {
float opacity,
SkXfermode::Mode blend_mode,
int sorting_context_id);
- void AsValueInto(base::debug::TracedValue* dict) const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
// Transforms from quad's original content space to its target content space.
gfx::Transform content_to_target_transform;
diff --git a/chromium/cc/quads/solid_color_draw_quad.cc b/chromium/cc/quads/solid_color_draw_quad.cc
index a11b1518b2d..229e98b1426 100644
--- a/chromium/cc/quads/solid_color_draw_quad.cc
+++ b/chromium/cc/quads/solid_color_draw_quad.cc
@@ -4,8 +4,8 @@
#include "cc/quads/solid_color_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
namespace cc {
@@ -48,7 +48,8 @@ const SolidColorDrawQuad* SolidColorDrawQuad::MaterialCast(
return static_cast<const SolidColorDrawQuad*>(quad);
}
-void SolidColorDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void SolidColorDrawQuad::ExtendValue(
+ base::trace_event::TracedValue* value) const {
value->SetInteger("color", color);
value->SetBoolean("force_anti_aliasing_off", force_anti_aliasing_off);
}
diff --git a/chromium/cc/quads/solid_color_draw_quad.h b/chromium/cc/quads/solid_color_draw_quad.h
index f70e5e3ae6c..f0f5f5a28b4 100644
--- a/chromium/cc/quads/solid_color_draw_quad.h
+++ b/chromium/cc/quads/solid_color_draw_quad.h
@@ -38,7 +38,7 @@ class CC_EXPORT SolidColorDrawQuad : public DrawQuad {
static const SolidColorDrawQuad* MaterialCast(const DrawQuad*);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/stream_video_draw_quad.cc b/chromium/cc/quads/stream_video_draw_quad.cc
index 6b5a509d29e..fb6f728ee2e 100644
--- a/chromium/cc/quads/stream_video_draw_quad.cc
+++ b/chromium/cc/quads/stream_video_draw_quad.cc
@@ -4,8 +4,8 @@
#include "cc/quads/stream_video_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
@@ -50,11 +50,10 @@ const StreamVideoDrawQuad* StreamVideoDrawQuad::MaterialCast(
return static_cast<const StreamVideoDrawQuad*>(quad);
}
-void StreamVideoDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void StreamVideoDrawQuad::ExtendValue(
+ base::trace_event::TracedValue* value) const {
value->SetInteger("resource_id", resource_id);
- value->BeginArray("matrix");
- MathUtil::AddToTracedValue(matrix, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("matrix", matrix, value);
}
} // namespace cc
diff --git a/chromium/cc/quads/stream_video_draw_quad.h b/chromium/cc/quads/stream_video_draw_quad.h
index cdba60c159d..45c28f2f957 100644
--- a/chromium/cc/quads/stream_video_draw_quad.h
+++ b/chromium/cc/quads/stream_video_draw_quad.h
@@ -39,7 +39,7 @@ class CC_EXPORT StreamVideoDrawQuad : public DrawQuad {
static const StreamVideoDrawQuad* MaterialCast(const DrawQuad*);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/surface_draw_quad.cc b/chromium/cc/quads/surface_draw_quad.cc
index 7ed8f2eb837..5823558ae68 100644
--- a/chromium/cc/quads/surface_draw_quad.cc
+++ b/chromium/cc/quads/surface_draw_quad.cc
@@ -4,8 +4,8 @@
#include "cc/quads/surface_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
namespace cc {
@@ -43,7 +43,7 @@ const SurfaceDrawQuad* SurfaceDrawQuad::MaterialCast(const DrawQuad* quad) {
return static_cast<const SurfaceDrawQuad*>(quad);
}
-void SurfaceDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void SurfaceDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
value->SetInteger("surface_id", surface_id.id);
}
diff --git a/chromium/cc/quads/surface_draw_quad.h b/chromium/cc/quads/surface_draw_quad.h
index bdf78388d31..36dc8090895 100644
--- a/chromium/cc/quads/surface_draw_quad.h
+++ b/chromium/cc/quads/surface_draw_quad.h
@@ -35,7 +35,7 @@ class CC_EXPORT SurfaceDrawQuad : public DrawQuad {
static const SurfaceDrawQuad* MaterialCast(const DrawQuad* quad);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/texture_draw_quad.cc b/chromium/cc/quads/texture_draw_quad.cc
index 9ff9744a1db..4b8720a1ed7 100644
--- a/chromium/cc/quads/texture_draw_quad.cc
+++ b/chromium/cc/quads/texture_draw_quad.cc
@@ -4,8 +4,8 @@
#include "cc/quads/texture_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
#include "ui/gfx/geometry/vector2d_f.h"
@@ -16,7 +16,8 @@ TextureDrawQuad::TextureDrawQuad()
: resource_id(0),
premultiplied_alpha(false),
background_color(SK_ColorTRANSPARENT),
- flipped(false) {
+ y_flipped(false),
+ nearest_neighbor(false) {
this->vertex_opacity[0] = 0.f;
this->vertex_opacity[1] = 0.f;
this->vertex_opacity[2] = 0.f;
@@ -33,7 +34,8 @@ void TextureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
const gfx::PointF& uv_bottom_right,
SkColor background_color,
const float vertex_opacity[4],
- bool flipped) {
+ bool y_flipped,
+ bool nearest_neighbor) {
bool needs_blending = vertex_opacity[0] != 1.0f || vertex_opacity[1] != 1.0f
|| vertex_opacity[2] != 1.0f || vertex_opacity[3] != 1.0f;
DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
@@ -47,19 +49,23 @@ void TextureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
this->vertex_opacity[1] = vertex_opacity[1];
this->vertex_opacity[2] = vertex_opacity[2];
this->vertex_opacity[3] = vertex_opacity[3];
- this->flipped = flipped;
+ this->y_flipped = y_flipped;
+ this->nearest_neighbor = nearest_neighbor;
}
void TextureDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
const gfx::Rect& opaque_rect,
- const gfx::Rect& visible_rect, bool needs_blending,
- unsigned resource_id, bool premultiplied_alpha,
+ const gfx::Rect& visible_rect,
+ bool needs_blending,
+ unsigned resource_id,
+ bool premultiplied_alpha,
const gfx::PointF& uv_top_left,
const gfx::PointF& uv_bottom_right,
SkColor background_color,
const float vertex_opacity[4],
- bool flipped) {
+ bool y_flipped,
+ bool nearest_neighbor) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
opaque_rect, visible_rect, needs_blending);
this->resource_id = resource_id;
@@ -71,7 +77,8 @@ void TextureDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
this->vertex_opacity[1] = vertex_opacity[1];
this->vertex_opacity[2] = vertex_opacity[2];
this->vertex_opacity[3] = vertex_opacity[3];
- this->flipped = flipped;
+ this->y_flipped = y_flipped;
+ this->nearest_neighbor = nearest_neighbor;
}
void TextureDrawQuad::IterateResources(
@@ -84,16 +91,12 @@ const TextureDrawQuad* TextureDrawQuad::MaterialCast(const DrawQuad* quad) {
return static_cast<const TextureDrawQuad*>(quad);
}
-void TextureDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void TextureDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
value->SetInteger("resource_id", resource_id);
value->SetBoolean("premultiplied_alpha", premultiplied_alpha);
- value->BeginArray("uv_top_left");
- MathUtil::AddToTracedValue(uv_top_left, value);
- value->EndArray();
- value->BeginArray("uv_bottom_right");
- MathUtil::AddToTracedValue(uv_bottom_right, value);
- value->EndArray();
+ MathUtil::AddToTracedValue("uv_top_left", uv_top_left, value);
+ MathUtil::AddToTracedValue("uv_bottom_right", uv_bottom_right, value);
value->SetInteger("background_color", background_color);
@@ -102,7 +105,8 @@ void TextureDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
value->AppendDouble(vertex_opacity[i]);
value->EndArray();
- value->SetBoolean("flipped", flipped);
+ value->SetBoolean("y_flipped", y_flipped);
+ value->SetBoolean("nearest_neighbor", nearest_neighbor);
}
} // namespace cc
diff --git a/chromium/cc/quads/texture_draw_quad.h b/chromium/cc/quads/texture_draw_quad.h
index 9137d51beb5..70641492368 100644
--- a/chromium/cc/quads/texture_draw_quad.h
+++ b/chromium/cc/quads/texture_draw_quad.h
@@ -26,7 +26,8 @@ class CC_EXPORT TextureDrawQuad : public DrawQuad {
const gfx::PointF& uv_bottom_right,
SkColor background_color,
const float vertex_opacity[4],
- bool flipped);
+ bool y_flipped,
+ bool nearest_neighbor);
void SetAll(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
@@ -39,7 +40,8 @@ class CC_EXPORT TextureDrawQuad : public DrawQuad {
const gfx::PointF& uv_bottom_right,
SkColor background_color,
const float vertex_opacity[4],
- bool flipped);
+ bool y_flipped,
+ bool nearest_neighbor);
unsigned resource_id;
bool premultiplied_alpha;
@@ -47,14 +49,15 @@ class CC_EXPORT TextureDrawQuad : public DrawQuad {
gfx::PointF uv_bottom_right;
SkColor background_color;
float vertex_opacity[4];
- bool flipped;
+ bool y_flipped;
+ bool nearest_neighbor;
void IterateResources(const ResourceIteratorCallback& callback) override;
static const TextureDrawQuad* MaterialCast(const DrawQuad*);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/tile_draw_quad.cc b/chromium/cc/quads/tile_draw_quad.cc
index ea3a14a9a3a..aa8f748d8b8 100644
--- a/chromium/cc/quads/tile_draw_quad.cc
+++ b/chromium/cc/quads/tile_draw_quad.cc
@@ -4,10 +4,9 @@
#include "cc/quads/tile_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
-#include "third_party/khronos/GLES2/gl2.h"
namespace cc {
@@ -25,7 +24,8 @@ void TileDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
unsigned resource_id,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
- bool swizzle_contents) {
+ bool swizzle_contents,
+ bool nearest_neighbor) {
ContentDrawQuadBase::SetNew(shared_quad_state,
DrawQuad::TILED_CONTENT,
rect,
@@ -33,7 +33,8 @@ void TileDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
visible_rect,
tex_coord_rect,
texture_size,
- swizzle_contents);
+ swizzle_contents,
+ nearest_neighbor);
this->resource_id = resource_id;
}
@@ -45,10 +46,12 @@ void TileDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
unsigned resource_id,
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
- bool swizzle_contents) {
+ bool swizzle_contents,
+ bool nearest_neighbor) {
ContentDrawQuadBase::SetAll(shared_quad_state, DrawQuad::TILED_CONTENT, rect,
opaque_rect, visible_rect, needs_blending,
- tex_coord_rect, texture_size, swizzle_contents);
+ tex_coord_rect, texture_size, swizzle_contents,
+ nearest_neighbor);
this->resource_id = resource_id;
}
@@ -62,7 +65,7 @@ const TileDrawQuad* TileDrawQuad::MaterialCast(const DrawQuad* quad) {
return static_cast<const TileDrawQuad*>(quad);
}
-void TileDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void TileDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
ContentDrawQuadBase::ExtendValue(value);
value->SetInteger("resource_id", resource_id);
}
diff --git a/chromium/cc/quads/tile_draw_quad.h b/chromium/cc/quads/tile_draw_quad.h
index d776057ab5f..b858e148d23 100644
--- a/chromium/cc/quads/tile_draw_quad.h
+++ b/chromium/cc/quads/tile_draw_quad.h
@@ -19,9 +19,13 @@ class CC_EXPORT TileDrawQuad : public ContentDrawQuadBase {
const gfx::Rect& opaque_rect,
const gfx::Rect& visible_rect,
unsigned resource_id,
+ // |tex_coord_rect| contains non-normalized coordinates.
+ // TODO(reveman): Make the use of normalized vs non-normalized
+ // coordinates consistent across all quad types: crbug.com/487370
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
- bool swizzle_contents);
+ bool swizzle_contents,
+ bool nearest_neighbor);
void SetAll(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
@@ -29,9 +33,13 @@ class CC_EXPORT TileDrawQuad : public ContentDrawQuadBase {
const gfx::Rect& visible_rect,
bool needs_blending,
unsigned resource_id,
+ // |tex_coord_rect| contains non-normalized coordinates.
+ // TODO(reveman): Make the use of normalized vs non-normalized
+ // coordinates consistent across all quad types: crbug.com/487370
const gfx::RectF& tex_coord_rect,
const gfx::Size& texture_size,
- bool swizzle_contents);
+ bool swizzle_contents,
+ bool nearest_neighbor);
unsigned resource_id;
@@ -40,7 +48,7 @@ class CC_EXPORT TileDrawQuad : public ContentDrawQuadBase {
static const TileDrawQuad* MaterialCast(const DrawQuad*);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/quads/yuv_video_draw_quad.cc b/chromium/cc/quads/yuv_video_draw_quad.cc
index 612362e5e8c..5706f288cd5 100644
--- a/chromium/cc/quads/yuv_video_draw_quad.cc
+++ b/chromium/cc/quads/yuv_video_draw_quad.cc
@@ -4,8 +4,8 @@
#include "cc/quads/yuv_video_draw_quad.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
@@ -22,7 +22,10 @@ void YUVVideoDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
const gfx::Rect& opaque_rect,
const gfx::Rect& visible_rect,
- const gfx::RectF& tex_coord_rect,
+ const gfx::RectF& ya_tex_coord_rect,
+ const gfx::RectF& uv_tex_coord_rect,
+ const gfx::Size& ya_tex_size,
+ const gfx::Size& uv_tex_size,
unsigned y_plane_resource_id,
unsigned u_plane_resource_id,
unsigned v_plane_resource_id,
@@ -31,7 +34,10 @@ void YUVVideoDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
bool needs_blending = false;
DrawQuad::SetAll(shared_quad_state, DrawQuad::YUV_VIDEO_CONTENT, rect,
opaque_rect, visible_rect, needs_blending);
- this->tex_coord_rect = tex_coord_rect;
+ this->ya_tex_coord_rect = ya_tex_coord_rect;
+ this->uv_tex_coord_rect = uv_tex_coord_rect;
+ this->ya_tex_size = ya_tex_size;
+ this->uv_tex_size = uv_tex_size;
this->y_plane_resource_id = y_plane_resource_id;
this->u_plane_resource_id = u_plane_resource_id;
this->v_plane_resource_id = v_plane_resource_id;
@@ -44,7 +50,10 @@ void YUVVideoDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
const gfx::Rect& opaque_rect,
const gfx::Rect& visible_rect,
bool needs_blending,
- const gfx::RectF& tex_coord_rect,
+ const gfx::RectF& ya_tex_coord_rect,
+ const gfx::RectF& uv_tex_coord_rect,
+ const gfx::Size& ya_tex_size,
+ const gfx::Size& uv_tex_size,
unsigned y_plane_resource_id,
unsigned u_plane_resource_id,
unsigned v_plane_resource_id,
@@ -52,7 +61,10 @@ void YUVVideoDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
ColorSpace color_space) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::YUV_VIDEO_CONTENT, rect,
opaque_rect, visible_rect, needs_blending);
- this->tex_coord_rect = tex_coord_rect;
+ this->ya_tex_coord_rect = ya_tex_coord_rect;
+ this->uv_tex_coord_rect = uv_tex_coord_rect;
+ this->ya_tex_size = ya_tex_size;
+ this->uv_tex_size = uv_tex_size;
this->y_plane_resource_id = y_plane_resource_id;
this->u_plane_resource_id = u_plane_resource_id;
this->v_plane_resource_id = v_plane_resource_id;
@@ -75,10 +87,12 @@ const YUVVideoDrawQuad* YUVVideoDrawQuad::MaterialCast(
return static_cast<const YUVVideoDrawQuad*>(quad);
}
-void YUVVideoDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
- value->BeginArray("tex_coord_rect");
- MathUtil::AddToTracedValue(tex_coord_rect, value);
- value->EndArray();
+void YUVVideoDrawQuad::ExtendValue(
+ base::trace_event::TracedValue* value) const {
+ MathUtil::AddToTracedValue("ya_tex_coord_rect", ya_tex_coord_rect, value);
+ MathUtil::AddToTracedValue("uv_tex_coord_rect", uv_tex_coord_rect, value);
+ MathUtil::AddToTracedValue("ya_tex_size", ya_tex_size, value);
+ MathUtil::AddToTracedValue("uv_tex_size", uv_tex_size, value);
value->SetInteger("y_plane_resource_id", y_plane_resource_id);
value->SetInteger("u_plane_resource_id", u_plane_resource_id);
value->SetInteger("v_plane_resource_id", v_plane_resource_id);
diff --git a/chromium/cc/quads/yuv_video_draw_quad.h b/chromium/cc/quads/yuv_video_draw_quad.h
index e1c54109f65..deeca2c1cbc 100644
--- a/chromium/cc/quads/yuv_video_draw_quad.h
+++ b/chromium/cc/quads/yuv_video_draw_quad.h
@@ -8,7 +8,6 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
-#include "cc/layers/video_layer_impl.h"
#include "cc/quads/draw_quad.h"
namespace cc {
@@ -16,9 +15,10 @@ namespace cc {
class CC_EXPORT YUVVideoDrawQuad : public DrawQuad {
public:
enum ColorSpace {
- REC_601, // SDTV standard with restricted "studio swing" color range.
- REC_601_JPEG, // Full color range [0, 255] variant of the above.
- COLOR_SPACE_LAST = REC_601_JPEG
+ REC_601, // SDTV standard with restricted "studio swing" color range.
+ REC_709, // HDTV standard with restricted "studio swing" color range.
+ JPEG, // Full color range [0, 255] JPEG color space.
+ COLOR_SPACE_LAST = JPEG
};
~YUVVideoDrawQuad() override;
@@ -29,7 +29,13 @@ class CC_EXPORT YUVVideoDrawQuad : public DrawQuad {
const gfx::Rect& rect,
const gfx::Rect& opaque_rect,
const gfx::Rect& visible_rect,
- const gfx::RectF& tex_coord_rect,
+ // |*_tex_coord_rect| contains non-normalized coordinates.
+ // TODO(reveman): Make the use of normalized vs non-normalized
+ // coordinates consistent across all quad types: crbug.com/487370
+ const gfx::RectF& ya_tex_coord_rect,
+ const gfx::RectF& uv_tex_coord_rect,
+ const gfx::Size& ya_tex_size,
+ const gfx::Size& uv_tex_size,
unsigned y_plane_resource_id,
unsigned u_plane_resource_id,
unsigned v_plane_resource_id,
@@ -41,14 +47,23 @@ class CC_EXPORT YUVVideoDrawQuad : public DrawQuad {
const gfx::Rect& opaque_rect,
const gfx::Rect& visible_rect,
bool needs_blending,
- const gfx::RectF& tex_coord_rect,
+ // |*_tex_coord_rect| contains non-normalized coordinates.
+ // TODO(reveman): Make the use of normalized vs non-normalized
+ // coordinates consistent across all quad types: crbug.com/487370
+ const gfx::RectF& ya_tex_coord_rect,
+ const gfx::RectF& uv_tex_coord_rect,
+ const gfx::Size& ya_tex_size,
+ const gfx::Size& uv_tex_size,
unsigned y_plane_resource_id,
unsigned u_plane_resource_id,
unsigned v_plane_resource_id,
unsigned a_plane_resource_id,
ColorSpace color_space);
- gfx::RectF tex_coord_rect;
+ gfx::RectF ya_tex_coord_rect;
+ gfx::RectF uv_tex_coord_rect;
+ gfx::Size ya_tex_size;
+ gfx::Size uv_tex_size;
unsigned y_plane_resource_id;
unsigned u_plane_resource_id;
unsigned v_plane_resource_id;
@@ -60,7 +75,7 @@ class CC_EXPORT YUVVideoDrawQuad : public DrawQuad {
static const YUVVideoDrawQuad* MaterialCast(const DrawQuad*);
private:
- void ExtendValue(base::debug::TracedValue* value) const override;
+ void ExtendValue(base::trace_event::TracedValue* value) const override;
};
} // namespace cc
diff --git a/chromium/cc/raster/bitmap_tile_task_worker_pool.cc b/chromium/cc/raster/bitmap_tile_task_worker_pool.cc
new file mode 100644
index 00000000000..1792a2053da
--- /dev/null
+++ b/chromium/cc/raster/bitmap_tile_task_worker_pool.cc
@@ -0,0 +1,206 @@
+// Copyright 2014 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/raster/bitmap_tile_task_worker_pool.h"
+
+#include <algorithm>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/debug/traced_value.h"
+#include "cc/playback/raster_source.h"
+#include "cc/raster/raster_buffer.h"
+#include "cc/resources/resource.h"
+
+namespace cc {
+namespace {
+
+class RasterBufferImpl : public RasterBuffer {
+ public:
+ RasterBufferImpl(ResourceProvider* resource_provider,
+ const Resource* resource)
+ : lock_(resource_provider, resource->id()), resource_(resource) {}
+
+ // Overridden from RasterBuffer:
+ void Playback(const RasterSource* raster_source,
+ const gfx::Rect& rect,
+ float scale) override {
+ TileTaskWorkerPool::PlaybackToMemory(lock_.sk_bitmap().getPixels(),
+ resource_->format(), resource_->size(),
+ 0, raster_source, rect, scale);
+ }
+
+ private:
+ ResourceProvider::ScopedWriteLockSoftware lock_;
+ const Resource* resource_;
+
+ DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
+};
+
+} // namespace
+
+// static
+scoped_ptr<TileTaskWorkerPool> BitmapTileTaskWorkerPool::Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider) {
+ return make_scoped_ptr<TileTaskWorkerPool>(new BitmapTileTaskWorkerPool(
+ task_runner, task_graph_runner, resource_provider));
+}
+
+BitmapTileTaskWorkerPool::BitmapTileTaskWorkerPool(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider)
+ : task_runner_(task_runner),
+ task_graph_runner_(task_graph_runner),
+ namespace_token_(task_graph_runner->GetNamespaceToken()),
+ resource_provider_(resource_provider),
+ task_set_finished_weak_ptr_factory_(this) {
+}
+
+BitmapTileTaskWorkerPool::~BitmapTileTaskWorkerPool() {
+}
+
+TileTaskRunner* BitmapTileTaskWorkerPool::AsTileTaskRunner() {
+ return this;
+}
+
+void BitmapTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) {
+ client_ = client;
+}
+
+void BitmapTileTaskWorkerPool::Shutdown() {
+ TRACE_EVENT0("cc", "BitmapTileTaskWorkerPool::Shutdown");
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
+}
+
+void BitmapTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) {
+ TRACE_EVENT0("cc", "BitmapTileTaskWorkerPool::ScheduleTasks");
+
+ if (tasks_pending_.none())
+ TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
+
+ // Mark all task sets as pending.
+ tasks_pending_.set();
+
+ unsigned priority = kTileTaskPriorityBase;
+
+ graph_.Reset();
+
+ // Cancel existing OnTaskSetFinished callbacks.
+ task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+
+ scoped_refptr<TileTask> new_task_set_finished_tasks[kNumberOfTaskSets];
+
+ size_t task_count[kNumberOfTaskSets] = {0};
+
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
+ new_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask(
+ task_runner_.get(),
+ base::Bind(&BitmapTileTaskWorkerPool::OnTaskSetFinished,
+ task_set_finished_weak_ptr_factory_.GetWeakPtr(), task_set));
+ }
+
+ for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end(); ++it) {
+ const TileTaskQueue::Item& item = *it;
+ RasterTask* task = item.task;
+ DCHECK(!task->HasCompleted());
+
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
+ if (!item.task_sets[task_set])
+ continue;
+
+ ++task_count[task_set];
+
+ graph_.edges.push_back(
+ TaskGraph::Edge(task, new_task_set_finished_tasks[task_set].get()));
+ }
+
+ InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
+ }
+
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
+ InsertNodeForTask(&graph_, new_task_set_finished_tasks[task_set].get(),
+ kTaskSetFinishedTaskPriorityBase + task_set,
+ task_count[task_set]);
+ }
+
+ ScheduleTasksOnOriginThread(this, &graph_);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
+
+ std::copy(new_task_set_finished_tasks,
+ new_task_set_finished_tasks + kNumberOfTaskSets,
+ task_set_finished_tasks_);
+
+ TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state",
+ StateAsValue());
+}
+
+void BitmapTileTaskWorkerPool::CheckForCompletedTasks() {
+ TRACE_EVENT0("cc", "BitmapTileTaskWorkerPool::CheckForCompletedTasks");
+
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ &completed_tasks_);
+ for (Task::Vector::const_iterator it = completed_tasks_.begin();
+ it != completed_tasks_.end(); ++it) {
+ TileTask* task = static_cast<TileTask*>(it->get());
+
+ task->WillComplete();
+ task->CompleteOnOriginThread(this);
+ task->DidComplete();
+
+ task->RunReplyOnOriginThread();
+ }
+ completed_tasks_.clear();
+}
+
+ResourceFormat BitmapTileTaskWorkerPool::GetResourceFormat() {
+ return resource_provider_->best_texture_format();
+}
+
+scoped_ptr<RasterBuffer> BitmapTileTaskWorkerPool::AcquireBufferForRaster(
+ const Resource* resource) {
+ return make_scoped_ptr<RasterBuffer>(
+ new RasterBufferImpl(resource_provider_, resource));
+}
+
+void BitmapTileTaskWorkerPool::ReleaseBufferForRaster(
+ scoped_ptr<RasterBuffer> buffer) {
+ // Nothing to do here. RasterBufferImpl destructor cleans up after itself.
+}
+
+void BitmapTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) {
+ TRACE_EVENT1("cc", "BitmapTileTaskWorkerPool::OnTaskSetFinished", "task_set",
+ task_set);
+
+ DCHECK(tasks_pending_[task_set]);
+ tasks_pending_[task_set] = false;
+ if (tasks_pending_.any()) {
+ TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running",
+ "state", StateAsValue());
+ } else {
+ TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
+ }
+ client_->DidFinishRunningTileTasks(task_set);
+}
+
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+BitmapTileTaskWorkerPool::StateAsValue() const {
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
+
+ state->BeginArray("tasks_pending");
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
+ state->AppendBoolean(tasks_pending_[task_set]);
+ state->EndArray();
+ return state;
+}
+
+} // namespace cc
diff --git a/chromium/cc/raster/bitmap_tile_task_worker_pool.h b/chromium/cc/raster/bitmap_tile_task_worker_pool.h
new file mode 100644
index 00000000000..4fcfd5a33f9
--- /dev/null
+++ b/chromium/cc/raster/bitmap_tile_task_worker_pool.h
@@ -0,0 +1,81 @@
+// Copyright 2014 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_RASTER_BITMAP_TILE_TASK_WORKER_POOL_H_
+#define CC_RASTER_BITMAP_TILE_TASK_WORKER_POOL_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "cc/raster/tile_task_runner.h"
+#include "cc/raster/tile_task_worker_pool.h"
+
+namespace base {
+namespace trace_event {
+class ConvertableToTraceFormat;
+}
+}
+
+namespace cc {
+class ResourceProvider;
+
+class CC_EXPORT BitmapTileTaskWorkerPool : public TileTaskWorkerPool,
+ public TileTaskRunner,
+ public TileTaskClient {
+ public:
+ ~BitmapTileTaskWorkerPool() override;
+
+ static scoped_ptr<TileTaskWorkerPool> Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider);
+
+ // Overridden from TileTaskWorkerPool:
+ TileTaskRunner* AsTileTaskRunner() override;
+
+ // Overridden from TileTaskRunner:
+ void SetClient(TileTaskRunnerClient* client) override;
+ void Shutdown() override;
+ void ScheduleTasks(TileTaskQueue* queue) override;
+ void CheckForCompletedTasks() override;
+ ResourceFormat GetResourceFormat() override;
+
+ // Overridden from TileTaskClient:
+ scoped_ptr<RasterBuffer> AcquireBufferForRaster(
+ const Resource* resource) override;
+ void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override;
+
+ protected:
+ BitmapTileTaskWorkerPool(base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider);
+
+ private:
+ void OnTaskSetFinished(TaskSet task_set);
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
+ const;
+
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ TaskGraphRunner* task_graph_runner_;
+ const NamespaceToken namespace_token_;
+ TileTaskRunnerClient* client_;
+ ResourceProvider* resource_provider_;
+
+ TaskSetCollection tasks_pending_;
+
+ scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets];
+
+ // Task graph used when scheduling tasks and vector used to gather
+ // completed tasks.
+ TaskGraph graph_;
+ Task::Vector completed_tasks_;
+
+ base::WeakPtrFactory<BitmapTileTaskWorkerPool>
+ task_set_finished_weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BitmapTileTaskWorkerPool);
+};
+
+} // namespace cc
+
+#endif // CC_RASTER_BITMAP_TILE_TASK_WORKER_POOL_H_
diff --git a/chromium/cc/raster/gpu_rasterizer.cc b/chromium/cc/raster/gpu_rasterizer.cc
new file mode 100644
index 00000000000..17a9322bebe
--- /dev/null
+++ b/chromium/cc/raster/gpu_rasterizer.cc
@@ -0,0 +1,85 @@
+// 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.
+
+#include "cc/raster/gpu_rasterizer.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/metrics/histogram.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/debug/devtools_instrumentation.h"
+#include "cc/debug/frame_viewer_instrumentation.h"
+#include "cc/output/context_provider.h"
+#include "cc/playback/raster_source.h"
+#include "cc/raster/raster_buffer.h"
+#include "cc/raster/scoped_gpu_raster.h"
+#include "cc/resources/resource.h"
+#include "cc/resources/resource_provider.h"
+#include "cc/tiles/tile_manager.h"
+#include "gpu/command_buffer/client/gles2_interface.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"
+#include "third_party/skia/include/gpu/GrContext.h"
+
+namespace cc {
+
+GpuRasterizer::GpuRasterizer(ContextProvider* context_provider,
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text,
+ int msaa_sample_count)
+ : resource_provider_(resource_provider),
+ use_distance_field_text_(use_distance_field_text),
+ msaa_sample_count_(msaa_sample_count) {
+}
+
+GpuRasterizer::~GpuRasterizer() {
+}
+
+void GpuRasterizer::RasterizeSource(
+ ResourceProvider::ScopedWriteLockGr* write_lock,
+ const RasterSource* raster_source,
+ const gfx::Rect& rect,
+ float scale) {
+ // Play back raster_source into temp SkPicture.
+ SkPictureRecorder recorder;
+ gfx::Size size = write_lock->resource()->size;
+ const int flags = SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
+ skia::RefPtr<SkCanvas> canvas = skia::SharePtr(
+ recorder.beginRecording(size.width(), size.height(), NULL, flags));
+ canvas->save();
+ raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
+ canvas->restore();
+ skia::RefPtr<SkPicture> picture =
+ skia::AdoptRef(recorder.endRecordingAsPicture());
+
+ // Turn on distance fields for layers that have ever animated.
+ bool use_distance_field_text =
+ use_distance_field_text_ ||
+ raster_source->ShouldAttemptToUseDistanceFieldText();
+
+ // Playback picture into resource.
+ {
+ ScopedGpuRaster gpu_raster(
+ resource_provider_->output_surface()->worker_context_provider());
+ write_lock->InitSkSurface(use_distance_field_text,
+ raster_source->CanUseLCDText(),
+ msaa_sample_count_);
+
+ SkSurface* sk_surface = write_lock->sk_surface();
+
+ // Allocating an SkSurface will fail after a lost context. Pretend we
+ // rasterized, as the contents of the resource don't matter anymore.
+ if (!sk_surface)
+ return;
+
+ SkMultiPictureDraw multi_picture_draw;
+ multi_picture_draw.add(sk_surface->getCanvas(), picture.get());
+ multi_picture_draw.draw(msaa_sample_count_ > 0);
+ write_lock->ReleaseSkSurface();
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/raster/gpu_rasterizer.h b/chromium/cc/raster/gpu_rasterizer.h
new file mode 100644
index 00000000000..443e6efeb85
--- /dev/null
+++ b/chromium/cc/raster/gpu_rasterizer.h
@@ -0,0 +1,49 @@
+// 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_RASTER_GPU_RASTERIZER_H_
+#define CC_RASTER_GPU_RASTERIZER_H_
+
+#include <vector>
+
+#include "cc/base/cc_export.h"
+#include "cc/resources/resource_pool.h"
+#include "cc/tiles/tile.h"
+#include "third_party/skia/include/core/SkMultiPictureDraw.h"
+
+namespace cc {
+
+class ContextProvider;
+class ResourceProvider;
+class RasterSource;
+
+class CC_EXPORT GpuRasterizer {
+ public:
+ ~GpuRasterizer();
+
+ void RasterizeSource(ResourceProvider::ScopedWriteLockGr* write_lock,
+ const RasterSource* raster_source,
+ const gfx::Rect& rect,
+ float scale);
+
+ ResourceProvider* resource_provider() { return resource_provider_; }
+
+ private:
+ GpuRasterizer(ContextProvider* context_provider,
+ ResourceProvider* resource_provider,
+ bool use_distance_filed_text,
+ int msaa_sample_count);
+
+ ResourceProvider* resource_provider_;
+
+ bool use_distance_field_text_;
+ int msaa_sample_count_;
+
+ friend class GpuTileTaskWorkerPool;
+ DISALLOW_COPY_AND_ASSIGN(GpuRasterizer);
+};
+
+} // namespace cc
+
+#endif // CC_RASTER_GPU_RASTERIZER_H_
diff --git a/chromium/cc/raster/gpu_tile_task_worker_pool.cc b/chromium/cc/raster/gpu_tile_task_worker_pool.cc
new file mode 100644
index 00000000000..24a4710530e
--- /dev/null
+++ b/chromium/cc/raster/gpu_tile_task_worker_pool.cc
@@ -0,0 +1,229 @@
+// Copyright 2014 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/raster/gpu_tile_task_worker_pool.h"
+
+#include <algorithm>
+
+#include "base/trace_event/trace_event.h"
+#include "cc/playback/raster_source.h"
+#include "cc/raster/gpu_rasterizer.h"
+#include "cc/raster/raster_buffer.h"
+#include "cc/raster/scoped_gpu_raster.h"
+#include "cc/resources/resource.h"
+#include "gpu/command_buffer/client/gles2_interface.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"
+#include "third_party/skia/include/gpu/GrContext.h"
+
+namespace cc {
+namespace {
+
+class RasterBufferImpl : public RasterBuffer {
+ public:
+ RasterBufferImpl(GpuRasterizer* rasterizer, const Resource* resource)
+ : rasterizer_(rasterizer),
+ lock_(rasterizer->resource_provider(), resource->id()),
+ resource_(resource) {}
+
+ // Overridden from RasterBuffer:
+ void Playback(const RasterSource* raster_source,
+ const gfx::Rect& rect,
+ float scale) override {
+ TRACE_EVENT0("cc", "RasterBufferImpl::Playback");
+ ContextProvider* context_provider = rasterizer_->resource_provider()
+ ->output_surface()
+ ->worker_context_provider();
+
+ // The context lock must be held while accessing the context on a
+ // worker thread.
+ base::AutoLock context_lock(*context_provider->GetLock());
+
+ // Allow this worker thread to bind to context_provider.
+ context_provider->DetachFromThread();
+
+ // Rasterize source into resource.
+ rasterizer_->RasterizeSource(&lock_, raster_source, rect, scale);
+
+ // Barrier to sync worker context output to cc context.
+ context_provider->ContextGL()->OrderingBarrierCHROMIUM();
+
+ // Allow compositor thread to bind to context_provider.
+ context_provider->DetachFromThread();
+ }
+
+ private:
+ GpuRasterizer* rasterizer_;
+ ResourceProvider::ScopedWriteLockGr lock_;
+ const Resource* resource_;
+
+ DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
+};
+
+} // namespace
+
+// static
+scoped_ptr<TileTaskWorkerPool> GpuTileTaskWorkerPool::Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ContextProvider* context_provider,
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text,
+ int gpu_rasterization_msaa_sample_count) {
+ return make_scoped_ptr<TileTaskWorkerPool>(new GpuTileTaskWorkerPool(
+ task_runner, task_graph_runner, context_provider, resource_provider,
+ use_distance_field_text, gpu_rasterization_msaa_sample_count));
+}
+
+GpuTileTaskWorkerPool::GpuTileTaskWorkerPool(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ContextProvider* context_provider,
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text,
+ int gpu_rasterization_msaa_sample_count)
+ : task_runner_(task_runner),
+ task_graph_runner_(task_graph_runner),
+ namespace_token_(task_graph_runner_->GetNamespaceToken()),
+ rasterizer_(new GpuRasterizer(context_provider,
+ resource_provider,
+ use_distance_field_text,
+ gpu_rasterization_msaa_sample_count)),
+ task_set_finished_weak_ptr_factory_(this),
+ weak_ptr_factory_(this) {
+}
+
+GpuTileTaskWorkerPool::~GpuTileTaskWorkerPool() {
+ DCHECK_EQ(0u, completed_tasks_.size());
+}
+
+TileTaskRunner* GpuTileTaskWorkerPool::AsTileTaskRunner() {
+ return this;
+}
+
+void GpuTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) {
+ client_ = client;
+}
+
+void GpuTileTaskWorkerPool::Shutdown() {
+ TRACE_EVENT0("cc", "GpuTileTaskWorkerPool::Shutdown");
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
+}
+
+void GpuTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) {
+ TRACE_EVENT0("cc", "GpuTileTaskWorkerPool::ScheduleTasks");
+
+ // Mark all task sets as pending.
+ tasks_pending_.set();
+
+ unsigned priority = kTileTaskPriorityBase;
+
+ graph_.Reset();
+
+ // Cancel existing OnTaskSetFinished callbacks.
+ task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+
+ scoped_refptr<TileTask> new_task_set_finished_tasks[kNumberOfTaskSets];
+
+ size_t task_count[kNumberOfTaskSets] = {0};
+
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
+ new_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask(
+ task_runner_.get(),
+ base::Bind(&GpuTileTaskWorkerPool::OnTaskSetFinished,
+ task_set_finished_weak_ptr_factory_.GetWeakPtr(), task_set));
+ }
+
+ for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end(); ++it) {
+ const TileTaskQueue::Item& item = *it;
+ RasterTask* task = item.task;
+ DCHECK(!task->HasCompleted());
+
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
+ if (!item.task_sets[task_set])
+ continue;
+
+ ++task_count[task_set];
+
+ graph_.edges.push_back(
+ TaskGraph::Edge(task, new_task_set_finished_tasks[task_set].get()));
+ }
+
+ InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
+ }
+
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
+ InsertNodeForTask(&graph_, new_task_set_finished_tasks[task_set].get(),
+ kTaskSetFinishedTaskPriorityBase + task_set,
+ task_count[task_set]);
+ }
+
+ ScheduleTasksOnOriginThread(this, &graph_);
+
+ // Barrier to sync any new resources to the worker context.
+ rasterizer_->resource_provider()
+ ->output_surface()
+ ->context_provider()
+ ->ContextGL()
+ ->OrderingBarrierCHROMIUM();
+
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
+
+ std::copy(new_task_set_finished_tasks,
+ new_task_set_finished_tasks + kNumberOfTaskSets,
+ task_set_finished_tasks_);
+}
+
+void GpuTileTaskWorkerPool::CheckForCompletedTasks() {
+ TRACE_EVENT0("cc", "GpuTileTaskWorkerPool::CheckForCompletedTasks");
+
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ &completed_tasks_);
+ CompleteTasks(completed_tasks_);
+ completed_tasks_.clear();
+}
+
+ResourceFormat GpuTileTaskWorkerPool::GetResourceFormat() {
+ return rasterizer_->resource_provider()->best_texture_format();
+}
+
+void GpuTileTaskWorkerPool::CompleteTasks(const Task::Vector& tasks) {
+ for (auto& task : tasks) {
+ RasterTask* raster_task = static_cast<RasterTask*>(task.get());
+
+ raster_task->WillComplete();
+ raster_task->CompleteOnOriginThread(this);
+ raster_task->DidComplete();
+
+ raster_task->RunReplyOnOriginThread();
+ }
+ completed_tasks_.clear();
+}
+
+scoped_ptr<RasterBuffer> GpuTileTaskWorkerPool::AcquireBufferForRaster(
+ const Resource* resource) {
+ return make_scoped_ptr<RasterBuffer>(
+ new RasterBufferImpl(rasterizer_.get(), resource));
+}
+
+void GpuTileTaskWorkerPool::ReleaseBufferForRaster(
+ scoped_ptr<RasterBuffer> buffer) {
+ // Nothing to do here. RasterBufferImpl destructor cleans up after itself.
+}
+
+void GpuTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) {
+ TRACE_EVENT1("cc", "GpuTileTaskWorkerPool::OnTaskSetFinished", "task_set",
+ task_set);
+
+ DCHECK(tasks_pending_[task_set]);
+ tasks_pending_[task_set] = false;
+ client_->DidFinishRunningTileTasks(task_set);
+}
+
+} // namespace cc
diff --git a/chromium/cc/raster/gpu_tile_task_worker_pool.h b/chromium/cc/raster/gpu_tile_task_worker_pool.h
new file mode 100644
index 00000000000..4e35eaa380a
--- /dev/null
+++ b/chromium/cc/raster/gpu_tile_task_worker_pool.h
@@ -0,0 +1,82 @@
+// Copyright 2014 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_RASTER_GPU_TILE_TASK_WORKER_POOL_H_
+#define CC_RASTER_GPU_TILE_TASK_WORKER_POOL_H_
+
+#include "base/memory/weak_ptr.h"
+#include "cc/raster/tile_task_runner.h"
+#include "cc/raster/tile_task_worker_pool.h"
+
+namespace cc {
+class ContextProvider;
+class GpuRasterizer;
+class ResourceProvider;
+
+class CC_EXPORT GpuTileTaskWorkerPool : public TileTaskWorkerPool,
+ public TileTaskRunner,
+ public TileTaskClient {
+ public:
+ ~GpuTileTaskWorkerPool() override;
+
+ static scoped_ptr<TileTaskWorkerPool> Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ContextProvider* context_provider,
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text,
+ int gpu_rasterization_msaa_sample_count);
+
+ // Overridden from TileTaskWorkerPool:
+ TileTaskRunner* AsTileTaskRunner() override;
+
+ // Overridden from TileTaskRunner:
+ void SetClient(TileTaskRunnerClient* client) override;
+ void Shutdown() override;
+ void ScheduleTasks(TileTaskQueue* queue) override;
+ void CheckForCompletedTasks() override;
+ ResourceFormat GetResourceFormat() override;
+
+ // Overridden from TileTaskClient:
+ scoped_ptr<RasterBuffer> AcquireBufferForRaster(
+ const Resource* resource) override;
+ void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override;
+
+ private:
+ GpuTileTaskWorkerPool(base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ContextProvider* context_provider,
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text,
+ int gpu_rasterization_msaa_sample_count);
+
+ void OnTaskSetFinished(TaskSet task_set);
+ void CompleteTasks(const Task::Vector& tasks);
+
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ TaskGraphRunner* task_graph_runner_;
+ const NamespaceToken namespace_token_;
+ TileTaskRunnerClient* client_;
+ scoped_ptr<GpuRasterizer> rasterizer_;
+
+ TaskSetCollection tasks_pending_;
+
+ scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets];
+
+ // Task graph used when scheduling tasks and vector used to gather
+ // completed tasks.
+ TaskGraph graph_;
+ Task::Vector completed_tasks_;
+
+ base::WeakPtrFactory<GpuTileTaskWorkerPool>
+ task_set_finished_weak_ptr_factory_;
+
+ base::WeakPtrFactory<GpuTileTaskWorkerPool> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuTileTaskWorkerPool);
+};
+
+} // namespace cc
+
+#endif // CC_RASTER_GPU_TILE_TASK_WORKER_POOL_H_
diff --git a/chromium/cc/resources/one_copy_raster_worker_pool.cc b/chromium/cc/raster/one_copy_tile_task_worker_pool.cc
index a8b838e8390..d504be8fbf6 100644
--- a/chromium/cc/resources/one_copy_raster_worker_pool.cc
+++ b/chromium/cc/raster/one_copy_tile_task_worker_pool.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/one_copy_raster_worker_pool.h"
+#include "cc/raster/one_copy_tile_task_worker_pool.h"
#include <algorithm>
#include <limits>
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/debug/traced_value.h"
-#include "cc/resources/raster_buffer.h"
+#include "cc/raster/raster_buffer.h"
#include "cc/resources/resource_pool.h"
#include "cc/resources/scoped_resource.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -22,15 +22,17 @@ namespace {
class RasterBufferImpl : public RasterBuffer {
public:
- RasterBufferImpl(OneCopyRasterWorkerPool* worker_pool,
+ RasterBufferImpl(OneCopyTileTaskWorkerPool* worker_pool,
ResourceProvider* resource_provider,
ResourcePool* resource_pool,
+ ResourceFormat resource_format,
const Resource* resource)
: worker_pool_(worker_pool),
resource_provider_(resource_provider),
resource_pool_(resource_pool),
resource_(resource),
- raster_resource_(resource_pool->AcquireResource(resource->size())),
+ raster_resource_(
+ resource_pool->AcquireResource(resource->size(), resource_format)),
lock_(new ResourceProvider::ScopedWriteLockGpuMemoryBuffer(
resource_provider_,
raster_resource_->id())),
@@ -61,7 +63,7 @@ class RasterBufferImpl : public RasterBuffer {
}
private:
- OneCopyRasterWorkerPool* worker_pool_;
+ OneCopyTileTaskWorkerPool* worker_pool_;
ResourceProvider* resource_provider_;
ResourcePool* resource_pool_;
const Resource* resource_;
@@ -76,7 +78,7 @@ class RasterBufferImpl : public RasterBuffer {
const int kCopyFlushPeriod = 4;
// Number of in-flight copy operations to allow.
-const int kMaxCopyOperations = 16;
+const int kMaxCopyOperations = 32;
// Delay been checking for copy operations to complete.
const int kCheckForCompletedCopyOperationsTickRateMs = 1;
@@ -87,32 +89,29 @@ const int kFailedAttemptsBeforeWaitIfNeeded = 256;
} // namespace
-OneCopyRasterWorkerPool::CopyOperation::CopyOperation(
+OneCopyTileTaskWorkerPool::CopyOperation::CopyOperation(
scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> write_lock,
scoped_ptr<ScopedResource> src,
const Resource* dst)
: write_lock(write_lock.Pass()), src(src.Pass()), dst(dst) {
}
-OneCopyRasterWorkerPool::CopyOperation::~CopyOperation() {
+OneCopyTileTaskWorkerPool::CopyOperation::~CopyOperation() {
}
// static
-scoped_ptr<RasterWorkerPool> OneCopyRasterWorkerPool::Create(
+scoped_ptr<TileTaskWorkerPool> OneCopyTileTaskWorkerPool::Create(
base::SequencedTaskRunner* task_runner,
TaskGraphRunner* task_graph_runner,
ContextProvider* context_provider,
ResourceProvider* resource_provider,
ResourcePool* resource_pool) {
- return make_scoped_ptr<RasterWorkerPool>(
- new OneCopyRasterWorkerPool(task_runner,
- task_graph_runner,
- context_provider,
- resource_provider,
- resource_pool));
+ return make_scoped_ptr<TileTaskWorkerPool>(new OneCopyTileTaskWorkerPool(
+ task_runner, task_graph_runner, context_provider, resource_provider,
+ resource_pool));
}
-OneCopyRasterWorkerPool::OneCopyRasterWorkerPool(
+OneCopyTileTaskWorkerPool::OneCopyTileTaskWorkerPool(
base::SequencedTaskRunner* task_runner,
TaskGraphRunner* task_graph_runner,
ContextProvider* context_provider,
@@ -134,24 +133,24 @@ OneCopyRasterWorkerPool::OneCopyRasterWorkerPool(
check_for_completed_copy_operations_pending_(false),
shutdown_(false),
weak_ptr_factory_(this),
- raster_finished_weak_ptr_factory_(this) {
+ task_set_finished_weak_ptr_factory_(this) {
DCHECK(context_provider_);
}
-OneCopyRasterWorkerPool::~OneCopyRasterWorkerPool() {
+OneCopyTileTaskWorkerPool::~OneCopyTileTaskWorkerPool() {
DCHECK_EQ(scheduled_copy_operation_count_, 0u);
}
-Rasterizer* OneCopyRasterWorkerPool::AsRasterizer() {
+TileTaskRunner* OneCopyTileTaskWorkerPool::AsTileTaskRunner() {
return this;
}
-void OneCopyRasterWorkerPool::SetClient(RasterizerClient* client) {
+void OneCopyTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) {
client_ = client;
}
-void OneCopyRasterWorkerPool::Shutdown() {
- TRACE_EVENT0("cc", "OneCopyRasterWorkerPool::Shutdown");
+void OneCopyTileTaskWorkerPool::Shutdown() {
+ TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::Shutdown");
{
base::AutoLock lock(lock_);
@@ -165,40 +164,45 @@ void OneCopyRasterWorkerPool::Shutdown() {
task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
}
-void OneCopyRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
- TRACE_EVENT0("cc", "OneCopyRasterWorkerPool::ScheduleTasks");
+void OneCopyTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) {
+ TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::ScheduleTasks");
- if (raster_pending_.none())
+#if DCHECK_IS_ON()
+ {
+ base::AutoLock lock(lock_);
+ DCHECK(!shutdown_);
+ }
+#endif
+
+ if (tasks_pending_.none())
TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
// Mark all task sets as pending.
- raster_pending_.set();
+ tasks_pending_.set();
- unsigned priority = kRasterTaskPriorityBase;
+ unsigned priority = kTileTaskPriorityBase;
graph_.Reset();
- // Cancel existing OnRasterFinished callbacks.
- raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+ // Cancel existing OnTaskSetFinished callbacks.
+ task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
- scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets];
+ scoped_refptr<TileTask> new_task_set_finished_tasks[kNumberOfTaskSets];
size_t task_count[kNumberOfTaskSets] = {0};
for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- new_raster_finished_tasks[task_set] = CreateRasterFinishedTask(
+ new_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask(
task_runner_.get(),
- base::Bind(&OneCopyRasterWorkerPool::OnRasterFinished,
- raster_finished_weak_ptr_factory_.GetWeakPtr(),
- task_set));
+ base::Bind(&OneCopyTileTaskWorkerPool::OnTaskSetFinished,
+ task_set_finished_weak_ptr_factory_.GetWeakPtr(), task_set));
}
resource_pool_->CheckBusyResources(false);
- for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
- it != queue->items.end();
- ++it) {
- const RasterTaskQueue::Item& item = *it;
+ for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end(); ++it) {
+ const TileTaskQueue::Item& item = *it;
RasterTask* task = item.task;
DCHECK(!task->HasCompleted());
@@ -209,42 +213,40 @@ void OneCopyRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
++task_count[task_set];
graph_.edges.push_back(
- TaskGraph::Edge(task, new_raster_finished_tasks[task_set].get()));
+ TaskGraph::Edge(task, new_task_set_finished_tasks[task_set].get()));
}
InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
}
for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- InsertNodeForTask(&graph_,
- new_raster_finished_tasks[task_set].get(),
- kRasterFinishedTaskPriority,
+ InsertNodeForTask(&graph_, new_task_set_finished_tasks[task_set].get(),
+ kTaskSetFinishedTaskPriorityBase + task_set,
task_count[task_set]);
}
ScheduleTasksOnOriginThread(this, &graph_);
task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
- std::copy(new_raster_finished_tasks,
- new_raster_finished_tasks + kNumberOfTaskSets,
- raster_finished_tasks_);
+ std::copy(new_task_set_finished_tasks,
+ new_task_set_finished_tasks + kNumberOfTaskSets,
+ task_set_finished_tasks_);
resource_pool_->ReduceResourceUsage();
- TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue());
+ TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state",
+ StateAsValue());
}
-void OneCopyRasterWorkerPool::CheckForCompletedTasks() {
- TRACE_EVENT0("cc", "OneCopyRasterWorkerPool::CheckForCompletedTasks");
+void OneCopyTileTaskWorkerPool::CheckForCompletedTasks() {
+ TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::CheckForCompletedTasks");
task_graph_runner_->CollectCompletedTasks(namespace_token_,
&completed_tasks_);
for (Task::Vector::const_iterator it = completed_tasks_.begin();
- it != completed_tasks_.end();
- ++it) {
- RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
+ it != completed_tasks_.end(); ++it) {
+ TileTask* task = static_cast<TileTask*>(it->get());
task->WillComplete();
task->CompleteOnOriginThread(this);
@@ -255,20 +257,26 @@ void OneCopyRasterWorkerPool::CheckForCompletedTasks() {
completed_tasks_.clear();
}
-scoped_ptr<RasterBuffer> OneCopyRasterWorkerPool::AcquireBufferForRaster(
+ResourceFormat OneCopyTileTaskWorkerPool::GetResourceFormat() {
+ return resource_provider_->best_texture_format();
+}
+
+scoped_ptr<RasterBuffer> OneCopyTileTaskWorkerPool::AcquireBufferForRaster(
const Resource* resource) {
- DCHECK_EQ(resource->format(), resource_pool_->resource_format());
+ DCHECK_EQ(resource->format(), resource_provider_->best_texture_format());
return make_scoped_ptr<RasterBuffer>(
- new RasterBufferImpl(this, resource_provider_, resource_pool_, resource));
+ new RasterBufferImpl(this, resource_provider_, resource_pool_,
+ resource_provider_->best_texture_format(),
+ resource));
}
-void OneCopyRasterWorkerPool::ReleaseBufferForRaster(
+void OneCopyTileTaskWorkerPool::ReleaseBufferForRaster(
scoped_ptr<RasterBuffer> buffer) {
// Nothing to do here. RasterBufferImpl destructor cleans up after itself.
}
CopySequenceNumber
-OneCopyRasterWorkerPool::PlaybackAndScheduleCopyOnWorkerThread(
+OneCopyTileTaskWorkerPool::PlaybackAndScheduleCopyOnWorkerThread(
scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> write_lock,
scoped_ptr<ScopedResource> src,
const Resource* dst,
@@ -313,13 +321,13 @@ OneCopyRasterWorkerPool::PlaybackAndScheduleCopyOnWorkerThread(
gfx::GpuMemoryBuffer* gpu_memory_buffer = write_lock->GetGpuMemoryBuffer();
if (gpu_memory_buffer) {
- RasterWorkerPool::PlaybackToMemory(gpu_memory_buffer->Map(),
- src->format(),
- src->size(),
- gpu_memory_buffer->GetStride(),
- raster_source,
- rect,
- scale);
+ void* data = NULL;
+ bool rv = gpu_memory_buffer->Map(&data);
+ DCHECK(rv);
+ int stride;
+ gpu_memory_buffer->GetStride(&stride);
+ TileTaskWorkerPool::PlaybackToMemory(data, src->format(), src->size(),
+ stride, raster_source, rect, scale);
gpu_memory_buffer->Unmap();
}
}
@@ -335,15 +343,14 @@ OneCopyRasterWorkerPool::PlaybackAndScheduleCopyOnWorkerThread(
if ((sequence % kCopyFlushPeriod) == 0) {
task_runner_->PostTask(
FROM_HERE,
- base::Bind(&OneCopyRasterWorkerPool::AdvanceLastFlushedCopyTo,
- weak_ptr_factory_.GetWeakPtr(),
- sequence));
+ base::Bind(&OneCopyTileTaskWorkerPool::AdvanceLastFlushedCopyTo,
+ weak_ptr_factory_.GetWeakPtr(), sequence));
}
return sequence;
}
-void OneCopyRasterWorkerPool::AdvanceLastIssuedCopyTo(
+void OneCopyTileTaskWorkerPool::AdvanceLastIssuedCopyTo(
CopySequenceNumber sequence) {
if (last_issued_copy_operation_ >= sequence)
return;
@@ -352,7 +359,7 @@ void OneCopyRasterWorkerPool::AdvanceLastIssuedCopyTo(
last_issued_copy_operation_ = sequence;
}
-void OneCopyRasterWorkerPool::AdvanceLastFlushedCopyTo(
+void OneCopyTileTaskWorkerPool::AdvanceLastFlushedCopyTo(
CopySequenceNumber sequence) {
if (last_flushed_copy_operation_ >= sequence)
return;
@@ -364,24 +371,24 @@ void OneCopyRasterWorkerPool::AdvanceLastFlushedCopyTo(
last_flushed_copy_operation_ = last_issued_copy_operation_;
}
-void OneCopyRasterWorkerPool::OnRasterFinished(TaskSet task_set) {
- TRACE_EVENT1(
- "cc", "OneCopyRasterWorkerPool::OnRasterFinished", "task_set", task_set);
+void OneCopyTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) {
+ TRACE_EVENT1("cc", "OneCopyTileTaskWorkerPool::OnTaskSetFinished", "task_set",
+ task_set);
- DCHECK(raster_pending_[task_set]);
- raster_pending_[task_set] = false;
- if (raster_pending_.any()) {
- TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue());
+ DCHECK(tasks_pending_[task_set]);
+ tasks_pending_[task_set] = false;
+ if (tasks_pending_.any()) {
+ TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running",
+ "state", StateAsValue());
} else {
TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
}
- client_->DidFinishRunningTasks(task_set);
+ client_->DidFinishRunningTileTasks(task_set);
}
-void OneCopyRasterWorkerPool::IssueCopyOperations(int64 count) {
- TRACE_EVENT1(
- "cc", "OneCopyRasterWorkerPool::IssueCopyOperations", "count", count);
+void OneCopyTileTaskWorkerPool::IssueCopyOperations(int64 count) {
+ TRACE_EVENT1("cc", "OneCopyTileTaskWorkerPool::IssueCopyOperations", "count",
+ count);
CopyOperation::Deque copy_operations;
@@ -417,7 +424,7 @@ void OneCopyRasterWorkerPool::IssueCopyOperations(int64 count) {
}
}
-void OneCopyRasterWorkerPool::
+void OneCopyTileTaskWorkerPool::
ScheduleCheckForCompletedCopyOperationsWithLockAcquired(
bool wait_if_needed) {
lock_.AssertAcquired();
@@ -438,9 +445,8 @@ void OneCopyRasterWorkerPool::
task_runner_->PostDelayedTask(
FROM_HERE,
- base::Bind(&OneCopyRasterWorkerPool::CheckForCompletedCopyOperations,
- weak_ptr_factory_.GetWeakPtr(),
- wait_if_needed),
+ base::Bind(&OneCopyTileTaskWorkerPool::CheckForCompletedCopyOperations,
+ weak_ptr_factory_.GetWeakPtr(), wait_if_needed),
next_check_for_completed_copy_operations_time - now);
last_check_for_completed_copy_operations_time_ =
@@ -448,12 +454,11 @@ void OneCopyRasterWorkerPool::
check_for_completed_copy_operations_pending_ = true;
}
-void OneCopyRasterWorkerPool::CheckForCompletedCopyOperations(
+void OneCopyTileTaskWorkerPool::CheckForCompletedCopyOperations(
bool wait_if_needed) {
TRACE_EVENT1("cc",
- "OneCopyRasterWorkerPool::CheckForCompletedCopyOperations",
- "wait_if_needed",
- wait_if_needed);
+ "OneCopyTileTaskWorkerPool::CheckForCompletedCopyOperations",
+ "wait_if_needed", wait_if_needed);
resource_pool_->CheckBusyResources(wait_if_needed);
@@ -473,14 +478,14 @@ void OneCopyRasterWorkerPool::CheckForCompletedCopyOperations(
}
}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-OneCopyRasterWorkerPool::StateAsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+OneCopyTileTaskWorkerPool::StateAsValue() const {
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
state->BeginArray("tasks_pending");
for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
- state->AppendBoolean(raster_pending_[task_set]);
+ state->AppendBoolean(tasks_pending_[task_set]);
state->EndArray();
state->BeginDictionary("staging_state");
StagingStateAsValueInto(state.get());
@@ -489,8 +494,8 @@ OneCopyRasterWorkerPool::StateAsValue() const {
return state;
}
-void OneCopyRasterWorkerPool::StagingStateAsValueInto(
- base::debug::TracedValue* staging_state) const {
+void OneCopyTileTaskWorkerPool::StagingStateAsValueInto(
+ base::trace_event::TracedValue* staging_state) const {
staging_state->SetInteger("staging_resource_count",
resource_pool_->total_resource_count());
staging_state->SetInteger("bytes_used_for_staging_resources",
diff --git a/chromium/cc/resources/one_copy_raster_worker_pool.h b/chromium/cc/raster/one_copy_tile_task_worker_pool.h
index b209da274bf..35b8873033a 100644
--- a/chromium/cc/resources/one_copy_raster_worker_pool.h
+++ b/chromium/cc/raster/one_copy_tile_task_worker_pool.h
@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_ONE_COPY_RASTER_WORKER_POOL_H_
-#define CC_RESOURCES_ONE_COPY_RASTER_WORKER_POOL_H_
+#ifndef CC_RASTER_ONE_COPY_TILE_TASK_WORKER_POOL_H_
+#define CC_RASTER_ONE_COPY_TILE_TASK_WORKER_POOL_H_
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
#include "cc/base/scoped_ptr_deque.h"
#include "cc/output/context_provider.h"
-#include "cc/resources/raster_worker_pool.h"
-#include "cc/resources/rasterizer.h"
+#include "cc/raster/tile_task_runner.h"
+#include "cc/raster/tile_task_worker_pool.h"
#include "cc/resources/resource_provider.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
class TracedValue;
}
@@ -27,29 +27,30 @@ class ScopedResource;
typedef int64 CopySequenceNumber;
-class CC_EXPORT OneCopyRasterWorkerPool : public RasterWorkerPool,
- public Rasterizer,
- public RasterizerTaskClient {
+class CC_EXPORT OneCopyTileTaskWorkerPool : public TileTaskWorkerPool,
+ public TileTaskRunner,
+ public TileTaskClient {
public:
- ~OneCopyRasterWorkerPool() override;
+ ~OneCopyTileTaskWorkerPool() override;
- static scoped_ptr<RasterWorkerPool> Create(
+ static scoped_ptr<TileTaskWorkerPool> Create(
base::SequencedTaskRunner* task_runner,
TaskGraphRunner* task_graph_runner,
ContextProvider* context_provider,
ResourceProvider* resource_provider,
ResourcePool* resource_pool);
- // Overridden from RasterWorkerPool:
- Rasterizer* AsRasterizer() override;
+ // Overridden from TileTaskWorkerPool:
+ TileTaskRunner* AsTileTaskRunner() override;
- // Overridden from Rasterizer:
- void SetClient(RasterizerClient* client) override;
+ // Overridden from TileTaskRunner:
+ void SetClient(TileTaskRunnerClient* client) override;
void Shutdown() override;
- void ScheduleTasks(RasterTaskQueue* queue) override;
+ void ScheduleTasks(TileTaskQueue* queue) override;
void CheckForCompletedTasks() override;
+ ResourceFormat GetResourceFormat() override;
- // Overridden from RasterizerTaskClient:
+ // Overridden from TileTaskClient:
scoped_ptr<RasterBuffer> AcquireBufferForRaster(
const Resource* resource) override;
void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override;
@@ -69,11 +70,11 @@ class CC_EXPORT OneCopyRasterWorkerPool : public RasterWorkerPool,
void AdvanceLastIssuedCopyTo(CopySequenceNumber sequence);
protected:
- OneCopyRasterWorkerPool(base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ContextProvider* context_provider,
- ResourceProvider* resource_provider,
- ResourcePool* resource_pool);
+ OneCopyTileTaskWorkerPool(base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ContextProvider* context_provider,
+ ResourceProvider* resource_provider,
+ ResourcePool* resource_pool);
private:
struct CopyOperation {
@@ -90,24 +91,26 @@ class CC_EXPORT OneCopyRasterWorkerPool : public RasterWorkerPool,
const Resource* dst;
};
- void OnRasterFinished(TaskSet task_set);
+ void OnTaskSetFinished(TaskSet task_set);
void AdvanceLastFlushedCopyTo(CopySequenceNumber sequence);
void IssueCopyOperations(int64 count);
void ScheduleCheckForCompletedCopyOperationsWithLockAcquired(
bool wait_if_needed);
void CheckForCompletedCopyOperations(bool wait_if_needed);
- scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
- void StagingStateAsValueInto(base::debug::TracedValue* staging_state) const;
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
+ const;
+ void StagingStateAsValueInto(
+ base::trace_event::TracedValue* staging_state) const;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
TaskGraphRunner* task_graph_runner_;
const NamespaceToken namespace_token_;
- RasterizerClient* client_;
+ TileTaskRunnerClient* client_;
ContextProvider* context_provider_;
ResourceProvider* resource_provider_;
ResourcePool* resource_pool_;
- TaskSetCollection raster_pending_;
- scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets];
+ TaskSetCollection tasks_pending_;
+ scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets];
CopySequenceNumber last_issued_copy_operation_;
CopySequenceNumber last_flushed_copy_operation_;
@@ -127,15 +130,15 @@ class CC_EXPORT OneCopyRasterWorkerPool : public RasterWorkerPool,
base::TimeTicks last_check_for_completed_copy_operations_time_;
bool shutdown_;
- base::WeakPtrFactory<OneCopyRasterWorkerPool> weak_ptr_factory_;
+ base::WeakPtrFactory<OneCopyTileTaskWorkerPool> weak_ptr_factory_;
// "raster finished" tasks need their own factory as they need to be
// canceled when ScheduleTasks() is called.
- base::WeakPtrFactory<OneCopyRasterWorkerPool>
- raster_finished_weak_ptr_factory_;
+ base::WeakPtrFactory<OneCopyTileTaskWorkerPool>
+ task_set_finished_weak_ptr_factory_;
- DISALLOW_COPY_AND_ASSIGN(OneCopyRasterWorkerPool);
+ DISALLOW_COPY_AND_ASSIGN(OneCopyTileTaskWorkerPool);
};
} // namespace cc
-#endif // CC_RESOURCES_ONE_COPY_RASTER_WORKER_POOL_H_
+#endif // CC_RASTER_ONE_COPY_TILE_TASK_WORKER_POOL_H_
diff --git a/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc b/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.cc
index 175e7d40f22..674e145c534 100644
--- a/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc
+++ b/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.cc
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/pixel_buffer_raster_worker_pool.h"
+#include "cc/raster/pixel_buffer_tile_task_worker_pool.h"
#include <algorithm>
#include "base/containers/stack_container.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/debug/traced_value.h"
-#include "cc/resources/raster_buffer.h"
+#include "cc/raster/raster_buffer.h"
#include "cc/resources/resource.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -41,9 +41,9 @@ class RasterBufferImpl : public RasterBuffer {
if (!memory_)
return;
- RasterWorkerPool::PlaybackToMemory(memory_, resource_->format(),
- resource_->size(), stride_,
- raster_source, rect, scale);
+ TileTaskWorkerPool::PlaybackToMemory(memory_, resource_->format(),
+ resource_->size(), stride_,
+ raster_source, rect, scale);
}
private:
@@ -89,28 +89,25 @@ void RemoveTaskSetsFromTaskCounts(size_t* task_counts,
} // namespace
-PixelBufferRasterWorkerPool::RasterTaskState::RasterTaskState(
+PixelBufferTileTaskWorkerPool::RasterTaskState::RasterTaskState(
RasterTask* task,
const TaskSetCollection& task_sets)
: type(UNSCHEDULED), task(task), task_sets(task_sets) {
}
// static
-scoped_ptr<RasterWorkerPool> PixelBufferRasterWorkerPool::Create(
+scoped_ptr<TileTaskWorkerPool> PixelBufferTileTaskWorkerPool::Create(
base::SequencedTaskRunner* task_runner,
TaskGraphRunner* task_graph_runner,
ContextProvider* context_provider,
ResourceProvider* resource_provider,
size_t max_transfer_buffer_usage_bytes) {
- return make_scoped_ptr<RasterWorkerPool>(
- new PixelBufferRasterWorkerPool(task_runner,
- task_graph_runner,
- context_provider,
- resource_provider,
- max_transfer_buffer_usage_bytes));
+ return make_scoped_ptr<TileTaskWorkerPool>(new PixelBufferTileTaskWorkerPool(
+ task_runner, task_graph_runner, context_provider, resource_provider,
+ max_transfer_buffer_usage_bytes));
}
-PixelBufferRasterWorkerPool::PixelBufferRasterWorkerPool(
+PixelBufferTileTaskWorkerPool::PixelBufferTileTaskWorkerPool(
base::SequencedTaskRunner* task_runner,
TaskGraphRunner* task_graph_runner,
ContextProvider* context_provider,
@@ -128,16 +125,17 @@ PixelBufferRasterWorkerPool::PixelBufferRasterWorkerPool(
has_performed_uploads_since_last_flush_(false),
check_for_completed_raster_task_notifier_(
task_runner,
- base::Bind(&PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks,
- base::Unretained(this)),
+ base::Bind(
+ &PixelBufferTileTaskWorkerPool::CheckForCompletedRasterTasks,
+ base::Unretained(this)),
base::TimeDelta::FromMilliseconds(
kCheckForCompletedRasterTasksDelayMs)),
- raster_finished_weak_ptr_factory_(this) {
+ task_set_finished_weak_ptr_factory_(this) {
DCHECK(context_provider_);
std::fill(task_counts_, task_counts_ + kNumberOfTaskSets, 0);
}
-PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() {
+PixelBufferTileTaskWorkerPool::~PixelBufferTileTaskWorkerPool() {
DCHECK_EQ(0u, raster_task_states_.size());
DCHECK_EQ(0u, raster_tasks_with_pending_upload_.size());
DCHECK_EQ(0u, completed_raster_tasks_.size());
@@ -145,14 +143,16 @@ PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() {
DCHECK(NonEmptyTaskSetsFromTaskCounts(task_counts_).none());
}
-Rasterizer* PixelBufferRasterWorkerPool::AsRasterizer() { return this; }
+TileTaskRunner* PixelBufferTileTaskWorkerPool::AsTileTaskRunner() {
+ return this;
+}
-void PixelBufferRasterWorkerPool::SetClient(RasterizerClient* client) {
+void PixelBufferTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) {
client_ = client;
}
-void PixelBufferRasterWorkerPool::Shutdown() {
- TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::Shutdown");
+void PixelBufferTileTaskWorkerPool::Shutdown() {
+ TRACE_EVENT0("cc", "PixelBufferTileTaskWorkerPool::Shutdown");
shutdown_ = true;
@@ -166,8 +166,7 @@ void PixelBufferRasterWorkerPool::Shutdown() {
check_for_completed_raster_task_notifier_.Shutdown();
for (RasterTaskState::Vector::iterator it = raster_task_states_.begin();
- it != raster_task_states_.end();
- ++it) {
+ it != raster_task_states_.end(); ++it) {
RasterTaskState& state = *it;
// All unscheduled tasks need to be canceled.
@@ -179,8 +178,8 @@ void PixelBufferRasterWorkerPool::Shutdown() {
DCHECK_EQ(completed_raster_tasks_.size(), raster_task_states_.size());
}
-void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
- TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleTasks");
+void PixelBufferTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) {
+ TRACE_EVENT0("cc", "PixelBufferTileTaskWorkerPool::ScheduleTasks");
if (should_notify_client_if_no_tasks_are_pending_.none())
TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
@@ -189,27 +188,24 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
std::fill(task_counts_, task_counts_ + kNumberOfTaskSets, 0);
// Update raster task state and remove items from old queue.
- for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
- it != queue->items.end();
- ++it) {
- const RasterTaskQueue::Item& item = *it;
+ for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end(); ++it) {
+ const TileTaskQueue::Item& item = *it;
RasterTask* task = item.task;
// Remove any old items that are associated with this task. The result is
// that the old queue is left with all items not present in this queue,
// which we use below to determine what tasks need to be canceled.
- RasterTaskQueue::Item::Vector::iterator old_it =
- std::find_if(raster_tasks_.items.begin(),
- raster_tasks_.items.end(),
- RasterTaskQueue::Item::TaskComparator(task));
+ TileTaskQueue::Item::Vector::iterator old_it =
+ std::find_if(raster_tasks_.items.begin(), raster_tasks_.items.end(),
+ TileTaskQueue::Item::TaskComparator(task));
if (old_it != raster_tasks_.items.end()) {
std::swap(*old_it, raster_tasks_.items.back());
raster_tasks_.items.pop_back();
}
RasterTaskState::Vector::iterator state_it =
- std::find_if(raster_task_states_.begin(),
- raster_task_states_.end(),
+ std::find_if(raster_task_states_.begin(), raster_task_states_.end(),
RasterTaskState::TaskComparator(task));
if (state_it != raster_task_states_.end()) {
RasterTaskState& state = *state_it;
@@ -230,16 +226,14 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
}
// Determine what tasks in old queue need to be canceled.
- for (RasterTaskQueue::Item::Vector::const_iterator it =
+ for (TileTaskQueue::Item::Vector::const_iterator it =
raster_tasks_.items.begin();
- it != raster_tasks_.items.end();
- ++it) {
- const RasterTaskQueue::Item& item = *it;
+ it != raster_tasks_.items.end(); ++it) {
+ const TileTaskQueue::Item& item = *it;
RasterTask* task = item.task;
RasterTaskState::Vector::iterator state_it =
- std::find_if(raster_task_states_.begin(),
- raster_task_states_.end(),
+ std::find_if(raster_task_states_.begin(), raster_task_states_.end(),
RasterTaskState::TaskComparator(task));
// We've already processed completion if we can't find a RasterTaskState for
// this task.
@@ -277,33 +271,30 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
// Reschedule check for completed raster tasks.
check_for_completed_raster_task_notifier_.Schedule();
- TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, StateName(), "state", StateAsValue());
+ TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, StateName(),
+ "state", StateAsValue());
}
-void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
- TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::CheckForCompletedTasks");
+void PixelBufferTileTaskWorkerPool::CheckForCompletedTasks() {
+ TRACE_EVENT0("cc", "PixelBufferTileTaskWorkerPool::CheckForCompletedTasks");
CheckForCompletedRasterizerTasks();
CheckForCompletedUploads();
FlushUploads();
- for (RasterizerTask::Vector::const_iterator it =
+ for (TileTask::Vector::const_iterator it =
completed_image_decode_tasks_.begin();
- it != completed_image_decode_tasks_.end();
- ++it) {
- RasterizerTask* task = it->get();
+ it != completed_image_decode_tasks_.end(); ++it) {
+ TileTask* task = it->get();
task->RunReplyOnOriginThread();
}
completed_image_decode_tasks_.clear();
for (RasterTask::Vector::const_iterator it = completed_raster_tasks_.begin();
- it != completed_raster_tasks_.end();
- ++it) {
+ it != completed_raster_tasks_.end(); ++it) {
RasterTask* task = it->get();
RasterTaskState::Vector::iterator state_it =
- std::find_if(raster_task_states_.begin(),
- raster_task_states_.end(),
+ std::find_if(raster_task_states_.begin(), raster_task_states_.end(),
RasterTaskState::TaskComparator(task));
DCHECK(state_it != raster_task_states_.end());
DCHECK_EQ(RasterTaskState::COMPLETED, state_it->type);
@@ -316,22 +307,24 @@ void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
completed_raster_tasks_.clear();
}
-scoped_ptr<RasterBuffer> PixelBufferRasterWorkerPool::AcquireBufferForRaster(
+ResourceFormat PixelBufferTileTaskWorkerPool::GetResourceFormat() {
+ return resource_provider_->memory_efficient_texture_format();
+}
+
+scoped_ptr<RasterBuffer> PixelBufferTileTaskWorkerPool::AcquireBufferForRaster(
const Resource* resource) {
return make_scoped_ptr<RasterBuffer>(
new RasterBufferImpl(resource_provider_, resource));
}
-void PixelBufferRasterWorkerPool::ReleaseBufferForRaster(
+void PixelBufferTileTaskWorkerPool::ReleaseBufferForRaster(
scoped_ptr<RasterBuffer> buffer) {
// Nothing to do here. RasterBufferImpl destructor cleans up after itself.
}
-void PixelBufferRasterWorkerPool::OnRasterFinished(TaskSet task_set) {
- TRACE_EVENT2("cc",
- "PixelBufferRasterWorkerPool::OnRasterFinished",
- "task_set",
- task_set,
+void PixelBufferTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) {
+ TRACE_EVENT2("cc", "PixelBufferTileTaskWorkerPool::OnTaskSetFinished",
+ "task_set", task_set,
"should_notify_client_if_no_tasks_are_pending",
should_notify_client_if_no_tasks_are_pending_[task_set]);
@@ -339,7 +332,7 @@ void PixelBufferRasterWorkerPool::OnRasterFinished(TaskSet task_set) {
// already been notified.
if (!should_notify_client_if_no_tasks_are_pending_[task_set])
return;
- raster_finished_tasks_pending_[task_set] = false;
+ task_set_finished_tasks_pending_[task_set] = false;
// This reduces latency between the time when all tasks required for
// activation have finished running and the time when the client is
@@ -347,7 +340,7 @@ void PixelBufferRasterWorkerPool::OnRasterFinished(TaskSet task_set) {
CheckForCompletedRasterTasks();
}
-void PixelBufferRasterWorkerPool::FlushUploads() {
+void PixelBufferTileTaskWorkerPool::FlushUploads() {
if (!has_performed_uploads_since_last_flush_)
return;
@@ -355,20 +348,19 @@ void PixelBufferRasterWorkerPool::FlushUploads() {
has_performed_uploads_since_last_flush_ = false;
}
-void PixelBufferRasterWorkerPool::CheckForCompletedUploads() {
+void PixelBufferTileTaskWorkerPool::CheckForCompletedUploads() {
RasterTask::Vector tasks_with_completed_uploads;
// First check if any have completed.
while (!raster_tasks_with_pending_upload_.empty()) {
RasterTask* task = raster_tasks_with_pending_upload_.front().get();
- DCHECK(std::find_if(raster_task_states_.begin(),
- raster_task_states_.end(),
+ DCHECK(std::find_if(raster_task_states_.begin(), raster_task_states_.end(),
RasterTaskState::TaskComparator(task)) !=
raster_task_states_.end());
- DCHECK_EQ(RasterTaskState::UPLOADING,
- std::find_if(raster_task_states_.begin(),
- raster_task_states_.end(),
- RasterTaskState::TaskComparator(task))->type);
+ DCHECK_EQ(
+ RasterTaskState::UPLOADING,
+ std::find_if(raster_task_states_.begin(), raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task))->type);
// Uploads complete in the order they are issued.
if (!resource_provider_->DidSetPixelsComplete(task->resource()->id()))
@@ -390,8 +382,7 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() {
while (it != raster_tasks_with_pending_upload_.end()) {
RasterTask* task = it->get();
RasterTaskState::Vector::const_iterator state_it =
- std::find_if(raster_task_states_.begin(),
- raster_task_states_.end(),
+ std::find_if(raster_task_states_.begin(), raster_task_states_.end(),
RasterTaskState::TaskComparator(task));
DCHECK(state_it != raster_task_states_.end());
const RasterTaskState& state = *state_it;
@@ -413,8 +404,7 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() {
// all previous uploads, we would rather wait only once downstream.
for (RasterTask::Vector::reverse_iterator it =
tasks_with_uploads_to_force.rbegin();
- it != tasks_with_uploads_to_force.rend();
- ++it) {
+ it != tasks_with_uploads_to_force.rend(); ++it) {
RasterTask* task = it->get();
resource_provider_->ForceSetPixelsToComplete(task->resource()->id());
@@ -426,12 +416,10 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() {
// to |completed_raster_tasks_|.
for (RasterTask::Vector::const_iterator it =
tasks_with_completed_uploads.begin();
- it != tasks_with_completed_uploads.end();
- ++it) {
+ it != tasks_with_completed_uploads.end(); ++it) {
RasterTask* task = it->get();
RasterTaskState::Vector::iterator state_it =
- std::find_if(raster_task_states_.begin(),
- raster_task_states_.end(),
+ std::find_if(raster_task_states_.begin(), raster_task_states_.end(),
RasterTaskState::TaskComparator(task));
DCHECK(state_it != raster_task_states_.end());
RasterTaskState& state = *state_it;
@@ -454,9 +442,9 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() {
}
}
-void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
+void PixelBufferTileTaskWorkerPool::CheckForCompletedRasterTasks() {
TRACE_EVENT0("cc",
- "PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks");
+ "PixelBufferTileTaskWorkerPool::CheckForCompletedRasterTasks");
// Since this function can be called directly, cancel any pending checks.
check_for_completed_raster_task_notifier_.Cancel();
@@ -470,7 +458,7 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
// Determine what client notifications to generate.
TaskSetCollection will_notify_client_that_no_tasks_are_pending =
should_notify_client_if_no_tasks_are_pending_ &
- ~raster_finished_tasks_pending_ & ~PendingTasks();
+ ~task_set_finished_tasks_pending_ & ~PendingTasks();
// Adjust the need to generate notifications before scheduling more tasks.
should_notify_client_if_no_tasks_are_pending_ &=
@@ -480,8 +468,8 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
if (PendingRasterTaskCount())
ScheduleMoreTasks();
- TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, StateName(), "state", StateAsValue());
+ TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, StateName(),
+ "state", StateAsValue());
// Schedule another check for completed raster tasks while there are
// pending raster tasks or pending uploads.
@@ -495,17 +483,17 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
if (will_notify_client_that_no_tasks_are_pending[task_set]) {
DCHECK(!PendingTasks()[task_set]);
- client_->DidFinishRunningTasks(task_set);
+ client_->DidFinishRunningTileTasks(task_set);
}
}
}
-void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
- TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleMoreTasks");
+void PixelBufferTileTaskWorkerPool::ScheduleMoreTasks() {
+ TRACE_EVENT0("cc", "PixelBufferTileTaskWorkerPool::ScheduleMoreTasks");
RasterTaskVector tasks[kNumberOfTaskSets];
- unsigned priority = kRasterTaskPriorityBase;
+ unsigned priority = kTileTaskPriorityBase;
graph_.Reset();
@@ -513,19 +501,17 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
TaskSetCollection did_throttle_raster_tasks;
size_t scheduled_raster_task_count = 0;
- for (RasterTaskQueue::Item::Vector::const_iterator it =
+ for (TileTaskQueue::Item::Vector::const_iterator it =
raster_tasks_.items.begin();
- it != raster_tasks_.items.end();
- ++it) {
- const RasterTaskQueue::Item& item = *it;
+ it != raster_tasks_.items.end(); ++it) {
+ const TileTaskQueue::Item& item = *it;
RasterTask* task = item.task;
DCHECK(item.task_sets.any());
// |raster_task_states_| contains the state of all tasks that we have not
// yet run reply callbacks for.
RasterTaskState::Vector::iterator state_it =
- std::find_if(raster_task_states_.begin(),
- raster_task_states_.end(),
+ std::find_if(raster_task_states_.begin(), raster_task_states_.end(),
RasterTaskState::TaskComparator(task));
if (state_it == raster_task_states_.end())
continue;
@@ -581,36 +567,34 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
}
}
- // Cancel existing OnRasterFinished callbacks.
- raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+ // Cancel existing OnTaskSetFinished callbacks.
+ task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
- scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets];
+ scoped_refptr<TileTask> new_task_set_finished_tasks[kNumberOfTaskSets];
size_t scheduled_task_counts[kNumberOfTaskSets] = {0};
for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
scheduled_task_counts[task_set] = tasks[task_set].container().size();
DCHECK_LE(scheduled_task_counts[task_set], task_counts_[task_set]);
- // Schedule OnRasterFinished call for task set only when notification is
+ // Schedule OnTaskSetFinished call for task set only when notification is
// pending and throttling is not preventing all pending tasks in the set
// from being scheduled.
if (!did_throttle_raster_tasks[task_set] &&
should_notify_client_if_no_tasks_are_pending_[task_set]) {
- new_raster_finished_tasks[task_set] = CreateRasterFinishedTask(
+ new_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask(
task_runner_.get(),
- base::Bind(&PixelBufferRasterWorkerPool::OnRasterFinished,
- raster_finished_weak_ptr_factory_.GetWeakPtr(),
+ base::Bind(&PixelBufferTileTaskWorkerPool::OnTaskSetFinished,
+ task_set_finished_weak_ptr_factory_.GetWeakPtr(),
task_set));
- raster_finished_tasks_pending_[task_set] = true;
- InsertNodeForTask(&graph_,
- new_raster_finished_tasks[task_set].get(),
- kRasterFinishedTaskPriority,
+ task_set_finished_tasks_pending_[task_set] = true;
+ InsertNodeForTask(&graph_, new_task_set_finished_tasks[task_set].get(),
+ kTaskSetFinishedTaskPriorityBase + task_set,
scheduled_task_counts[task_set]);
for (RasterTaskVector::ContainerType::const_iterator it =
tasks[task_set].container().begin();
- it != tasks[task_set].container().end();
- ++it) {
+ it != tasks[task_set].container().end(); ++it) {
graph_.edges.push_back(
- TaskGraph::Edge(*it, new_raster_finished_tasks[task_set].get()));
+ TaskGraph::Edge(*it, new_task_set_finished_tasks[task_set].get()));
}
}
}
@@ -622,23 +606,23 @@ void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
scheduled_raster_task_count_ = scheduled_raster_task_count;
- std::copy(new_raster_finished_tasks,
- new_raster_finished_tasks + kNumberOfTaskSets,
- raster_finished_tasks_);
+ std::copy(new_task_set_finished_tasks,
+ new_task_set_finished_tasks + kNumberOfTaskSets,
+ task_set_finished_tasks_);
}
-unsigned PixelBufferRasterWorkerPool::PendingRasterTaskCount() const {
+unsigned PixelBufferTileTaskWorkerPool::PendingRasterTaskCount() const {
unsigned num_completed_raster_tasks =
raster_tasks_with_pending_upload_.size() + completed_raster_tasks_.size();
DCHECK_GE(raster_task_states_.size(), num_completed_raster_tasks);
return raster_task_states_.size() - num_completed_raster_tasks;
}
-TaskSetCollection PixelBufferRasterWorkerPool::PendingTasks() const {
+TaskSetCollection PixelBufferTileTaskWorkerPool::PendingTasks() const {
return NonEmptyTaskSetsFromTaskCounts(task_counts_);
}
-const char* PixelBufferRasterWorkerPool::StateName() const {
+const char* PixelBufferTileTaskWorkerPool::StateName() const {
if (scheduled_raster_task_count_)
return "rasterizing";
if (PendingRasterTaskCount())
@@ -649,16 +633,15 @@ const char* PixelBufferRasterWorkerPool::StateName() const {
return "finishing";
}
-void PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks() {
- TRACE_EVENT0("cc",
- "PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks");
+void PixelBufferTileTaskWorkerPool::CheckForCompletedRasterizerTasks() {
+ TRACE_EVENT0(
+ "cc", "PixelBufferTileTaskWorkerPool::CheckForCompletedRasterizerTasks");
task_graph_runner_->CollectCompletedTasks(namespace_token_,
&completed_tasks_);
for (Task::Vector::const_iterator it = completed_tasks_.begin();
- it != completed_tasks_.end();
- ++it) {
- RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
+ it != completed_tasks_.end(); ++it) {
+ TileTask* task = static_cast<TileTask*>(it->get());
RasterTask* raster_task = task->AsRasterTask();
if (!raster_task) {
@@ -671,8 +654,7 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks() {
}
RasterTaskState::Vector::iterator state_it =
- std::find_if(raster_task_states_.begin(),
- raster_task_states_.end(),
+ std::find_if(raster_task_states_.begin(), raster_task_states_.end(),
RasterTaskState::TaskComparator(raster_task));
DCHECK(state_it != raster_task_states_.end());
@@ -689,10 +671,9 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks() {
raster_task->CompleteOnOriginThread(this);
raster_task->DidComplete();
- RasterTaskQueue::Item::Vector::const_iterator item_it =
- std::find_if(raster_tasks_.items.begin(),
- raster_tasks_.items.end(),
- RasterTaskQueue::Item::TaskComparator(raster_task));
+ TileTaskQueue::Item::Vector::const_iterator item_it =
+ std::find_if(raster_tasks_.items.begin(), raster_tasks_.items.end(),
+ TileTaskQueue::Item::TaskComparator(raster_task));
if (item_it != raster_tasks_.items.end()) {
state.type = RasterTaskState::UNSCHEDULED;
continue;
@@ -720,10 +701,10 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks() {
completed_tasks_.clear();
}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-PixelBufferRasterWorkerPool::StateAsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+PixelBufferTileTaskWorkerPool::StateAsValue() const {
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
state->SetInteger("completed_count", completed_raster_tasks_.size());
state->BeginArray("pending_count");
for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
@@ -737,8 +718,8 @@ PixelBufferRasterWorkerPool::StateAsValue() const {
return state;
}
-void PixelBufferRasterWorkerPool::ThrottleStateAsValueInto(
- base::debug::TracedValue* throttle_state) const {
+void PixelBufferTileTaskWorkerPool::ThrottleStateAsValueInto(
+ base::trace_event::TracedValue* throttle_state) const {
throttle_state->SetInteger("bytes_available_for_upload",
max_bytes_pending_upload_ - bytes_pending_upload_);
throttle_state->SetInteger("bytes_pending_upload", bytes_pending_upload_);
diff --git a/chromium/cc/resources/pixel_buffer_raster_worker_pool.h b/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.h
index 7fb45ecd641..e6ddd39312d 100644
--- a/chromium/cc/resources/pixel_buffer_raster_worker_pool.h
+++ b/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_PIXEL_BUFFER_RASTER_WORKER_POOL_H_
-#define CC_RESOURCES_PIXEL_BUFFER_RASTER_WORKER_POOL_H_
+#ifndef CC_RASTER_PIXEL_BUFFER_TILE_TASK_WORKER_POOL_H_
+#define CC_RASTER_PIXEL_BUFFER_TILE_TASK_WORKER_POOL_H_
#include <deque>
#include <vector>
@@ -12,11 +12,11 @@
#include "base/values.h"
#include "cc/base/delayed_unique_notifier.h"
#include "cc/output/context_provider.h"
-#include "cc/resources/raster_worker_pool.h"
-#include "cc/resources/rasterizer.h"
+#include "cc/raster/tile_task_runner.h"
+#include "cc/raster/tile_task_worker_pool.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
class TracedValue;
}
@@ -25,29 +25,30 @@ class TracedValue;
namespace cc {
class ResourceProvider;
-class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool,
- public Rasterizer,
- public RasterizerTaskClient {
+class CC_EXPORT PixelBufferTileTaskWorkerPool : public TileTaskWorkerPool,
+ public TileTaskRunner,
+ public TileTaskClient {
public:
- ~PixelBufferRasterWorkerPool() override;
+ ~PixelBufferTileTaskWorkerPool() override;
- static scoped_ptr<RasterWorkerPool> Create(
+ static scoped_ptr<TileTaskWorkerPool> Create(
base::SequencedTaskRunner* task_runner,
TaskGraphRunner* task_graph_runner,
ContextProvider* context_provider,
ResourceProvider* resource_provider,
size_t max_transfer_buffer_usage_bytes);
- // Overridden from RasterWorkerPool:
- Rasterizer* AsRasterizer() override;
+ // Overridden from TileTaskWorkerPool:
+ TileTaskRunner* AsTileTaskRunner() override;
- // Overridden from Rasterizer:
- void SetClient(RasterizerClient* client) override;
+ // Overridden from TileTaskRunner:
+ void SetClient(TileTaskRunnerClient* client) override;
void Shutdown() override;
- void ScheduleTasks(RasterTaskQueue* queue) override;
+ void ScheduleTasks(TileTaskQueue* queue) override;
void CheckForCompletedTasks() override;
+ ResourceFormat GetResourceFormat() override;
- // Overridden from RasterizerTaskClient:
+ // Overridden from TileTaskClient:
scoped_ptr<RasterBuffer> AcquireBufferForRaster(
const Resource* resource) override;
void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override;
@@ -77,13 +78,13 @@ class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool,
typedef std::deque<scoped_refptr<RasterTask>> RasterTaskDeque;
- PixelBufferRasterWorkerPool(base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ContextProvider* context_provider,
- ResourceProvider* resource_provider,
- size_t max_transfer_buffer_usage_bytes);
+ PixelBufferTileTaskWorkerPool(base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ContextProvider* context_provider,
+ ResourceProvider* resource_provider,
+ size_t max_transfer_buffer_usage_bytes);
- void OnRasterFinished(TaskSet task_set);
+ void OnTaskSetFinished(TaskSet task_set);
void FlushUploads();
void CheckForCompletedUploads();
void CheckForCompletedRasterTasks();
@@ -93,23 +94,25 @@ class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool,
void CheckForCompletedRasterizerTasks();
const char* StateName() const;
- scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
- void ThrottleStateAsValueInto(base::debug::TracedValue* throttle_state) const;
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
+ const;
+ void ThrottleStateAsValueInto(
+ base::trace_event::TracedValue* throttle_state) const;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
TaskGraphRunner* task_graph_runner_;
const NamespaceToken namespace_token_;
- RasterizerClient* client_;
+ TileTaskRunnerClient* client_;
ContextProvider* context_provider_;
ResourceProvider* resource_provider_;
bool shutdown_;
- RasterTaskQueue raster_tasks_;
+ TileTaskQueue raster_tasks_;
RasterTaskState::Vector raster_task_states_;
RasterTaskDeque raster_tasks_with_pending_upload_;
RasterTask::Vector completed_raster_tasks_;
- RasterizerTask::Vector completed_image_decode_tasks_;
+ TileTask::Vector completed_image_decode_tasks_;
size_t scheduled_raster_task_count_;
size_t task_counts_[kNumberOfTaskSets];
@@ -118,23 +121,23 @@ class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool,
bool has_performed_uploads_since_last_flush_;
TaskSetCollection should_notify_client_if_no_tasks_are_pending_;
- TaskSetCollection raster_finished_tasks_pending_;
+ TaskSetCollection task_set_finished_tasks_pending_;
DelayedUniqueNotifier check_for_completed_raster_task_notifier_;
- scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets];
+ scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets];
// Task graph used when scheduling tasks and vector used to gather
// completed tasks.
TaskGraph graph_;
Task::Vector completed_tasks_;
- base::WeakPtrFactory<PixelBufferRasterWorkerPool>
- raster_finished_weak_ptr_factory_;
+ base::WeakPtrFactory<PixelBufferTileTaskWorkerPool>
+ task_set_finished_weak_ptr_factory_;
- DISALLOW_COPY_AND_ASSIGN(PixelBufferRasterWorkerPool);
+ DISALLOW_COPY_AND_ASSIGN(PixelBufferTileTaskWorkerPool);
};
} // namespace cc
-#endif // CC_RESOURCES_PIXEL_BUFFER_RASTER_WORKER_POOL_H_
+#endif // CC_RASTER_PIXEL_BUFFER_TILE_TASK_WORKER_POOL_H_
diff --git a/chromium/cc/resources/raster_buffer.cc b/chromium/cc/raster/raster_buffer.cc
index 8f5671720e3..390fbd6cbbc 100644
--- a/chromium/cc/resources/raster_buffer.cc
+++ b/chromium/cc/raster/raster_buffer.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/raster_buffer.h"
+#include "cc/raster/raster_buffer.h"
namespace cc {
diff --git a/chromium/cc/resources/raster_buffer.h b/chromium/cc/raster/raster_buffer.h
index 2a72203da4b..8f3a56200f6 100644
--- a/chromium/cc/resources/raster_buffer.h
+++ b/chromium/cc/raster/raster_buffer.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_RASTER_BUFFER_H_
-#define CC_RESOURCES_RASTER_BUFFER_H_
+#ifndef CC_RASTER_RASTER_BUFFER_H_
+#define CC_RASTER_RASTER_BUFFER_H_
#include "cc/base/cc_export.h"
#include "ui/gfx/geometry/rect.h"
@@ -23,4 +23,4 @@ class CC_EXPORT RasterBuffer {
} // namespace cc
-#endif // CC_RESOURCES_RASTER_BUFFER_H_
+#endif // CC_RASTER_RASTER_BUFFER_H_
diff --git a/chromium/cc/resources/scoped_gpu_raster.cc b/chromium/cc/raster/scoped_gpu_raster.cc
index 517c7a7d814..f548515b698 100644
--- a/chromium/cc/resources/scoped_gpu_raster.cc
+++ b/chromium/cc/raster/scoped_gpu_raster.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/scoped_gpu_raster.h"
+#include "cc/raster/scoped_gpu_raster.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
@@ -30,18 +30,17 @@ void ScopedGpuRaster::BeginGpuRaster() {
gl->PushGroupMarkerEXT(0, "GpuRasterization");
class GrContext* gr_context = context_provider_->GrContext();
- // TODO(sohanjg): Remove when TestContextProvider gives a GrContext.
- if (gr_context)
- gr_context->resetContext();
+ gr_context->resetContext();
}
void ScopedGpuRaster::EndGpuRaster() {
+ class GrContext* gr_context = context_provider_->GrContext();
+ gr_context->flush();
+
GLES2Interface* gl = context_provider_->ContextGL();
- class GrContext* gr_context = context_provider_->GrContext();
- // TODO(sohanjg): Remove when TestContextProvider gives a GrContext.
- if (gr_context)
- gr_context->flush();
+ // Restore default GL unpack alignment. TextureUploader expects this.
+ gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4);
// TODO(alokp): Use a trace macro to push/pop markers.
// Using push/pop functions directly incurs cost to evaluate function
diff --git a/chromium/cc/resources/scoped_gpu_raster.h b/chromium/cc/raster/scoped_gpu_raster.h
index a322ccbbe9a..d9613b3c5fb 100644
--- a/chromium/cc/resources/scoped_gpu_raster.h
+++ b/chromium/cc/raster/scoped_gpu_raster.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_SCOPED_GPU_RASTER_H_
-#define CC_RESOURCES_SCOPED_GPU_RASTER_H_
+#ifndef CC_RASTER_SCOPED_GPU_RASTER_H_
+#define CC_RASTER_SCOPED_GPU_RASTER_H_
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -17,7 +17,7 @@ namespace cc {
// GL resources while an instance of this class is alive.
class CC_EXPORT ScopedGpuRaster {
public:
- ScopedGpuRaster(ContextProvider* context_provider);
+ explicit ScopedGpuRaster(ContextProvider* context_provider);
~ScopedGpuRaster();
private:
@@ -31,4 +31,4 @@ class CC_EXPORT ScopedGpuRaster {
} // namespace cc
-#endif // CC_RESOURCES_SCOPED_GPU_RASTER_H_
+#endif // CC_RASTER_SCOPED_GPU_RASTER_H_
diff --git a/chromium/cc/raster/scoped_gpu_raster_unittest.cc b/chromium/cc/raster/scoped_gpu_raster_unittest.cc
new file mode 100644
index 00000000000..7ffb464176d
--- /dev/null
+++ b/chromium/cc/raster/scoped_gpu_raster_unittest.cc
@@ -0,0 +1,39 @@
+// Copyright 2014 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/raster/scoped_gpu_raster.h"
+#include "cc/test/test_context_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class ScopedGpuRasterTest : public testing::Test {
+ public:
+ ScopedGpuRasterTest() {}
+};
+
+// Releasing ScopedGpuRaster should restore GL_UNPACK_ALIGNMENT == 4.
+TEST(ScopedGpuRasterTest, RestoresUnpackAlignment) {
+ scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
+ EXPECT_TRUE(provider->BindToCurrentThread());
+ gpu::gles2::GLES2Interface* gl = provider->ContextGL();
+ GLint unpack_alignment = 0;
+ gl->GetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
+ EXPECT_EQ(4, unpack_alignment);
+
+ {
+ scoped_ptr<ScopedGpuRaster> scoped_gpu_raster(
+ new ScopedGpuRaster(provider.get()));
+ gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ gl->GetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
+ EXPECT_EQ(1, unpack_alignment);
+ }
+
+ gl->GetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
+ EXPECT_EQ(4, unpack_alignment);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/resources/task_graph_runner.cc b/chromium/cc/raster/task_graph_runner.cc
index bcbc0dd351c..c810aa59c0b 100644
--- a/chromium/cc/resources/task_graph_runner.cc
+++ b/chromium/cc/raster/task_graph_runner.cc
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/task_graph_runner.h"
+#include "cc/raster/task_graph_runner.h"
#include <algorithm>
-#include "base/debug/trace_event.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
+#include "base/trace_event/trace_event.h"
namespace cc {
namespace {
@@ -290,6 +290,7 @@ void TaskGraphRunner::WaitForTasksToFinishRunning(NamespaceToken token) {
{
base::AutoLock lock(lock_);
+ base::ThreadRestrictions::ScopedAllowWait allow_wait;
TaskNamespaceMap::const_iterator it = namespaces_.find(token.id_);
if (it == namespaces_.end())
diff --git a/chromium/cc/resources/task_graph_runner.h b/chromium/cc/raster/task_graph_runner.h
index 2ff085d76cb..a54984353b0 100644
--- a/chromium/cc/resources/task_graph_runner.h
+++ b/chromium/cc/raster/task_graph_runner.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_TASK_GRAPH_RUNNER_H_
-#define CC_RESOURCES_TASK_GRAPH_RUNNER_H_
+#ifndef CC_RASTER_TASK_GRAPH_RUNNER_H_
+#define CC_RASTER_TASK_GRAPH_RUNNER_H_
#include <map>
#include <vector>
@@ -229,4 +229,4 @@ class CC_EXPORT TaskGraphRunner {
} // namespace cc
-#endif // CC_RESOURCES_TASK_GRAPH_RUNNER_H_
+#endif // CC_RASTER_TASK_GRAPH_RUNNER_H_
diff --git a/chromium/cc/resources/task_graph_runner_perftest.cc b/chromium/cc/raster/task_graph_runner_perftest.cc
index 7809e587975..cc617443e17 100644
--- a/chromium/cc/resources/task_graph_runner_perftest.cc
+++ b/chromium/cc/raster/task_graph_runner_perftest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/task_graph_runner.h"
+#include "cc/raster/task_graph_runner.h"
#include <vector>
@@ -45,17 +45,11 @@ class TaskGraphRunnerPerfTest : public testing::Test {
kTimeCheckInterval) {}
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
task_graph_runner_ = make_scoped_ptr(new TaskGraphRunner);
namespace_token_ = task_graph_runner_->GetNamespaceToken();
}
- virtual void TearDown() override { task_graph_runner_ = nullptr; }
-
- void AfterTest(const std::string& test_name) {
- // Format matches chrome/test/perf/perf_test.h:PrintResult
- printf(
- "*RESULT %s: %.2f runs/s\n", test_name.c_str(), timer_.LapsPerSecond());
- }
+ void TearDown() override { task_graph_runner_ = nullptr; }
void RunBuildTaskGraphTest(const std::string& test_name,
int num_top_level_tasks,
diff --git a/chromium/cc/resources/task_graph_runner_unittest.cc b/chromium/cc/raster/task_graph_runner_unittest.cc
index ad23b66087a..eb9b6d954b7 100644
--- a/chromium/cc/resources/task_graph_runner_unittest.cc
+++ b/chromium/cc/raster/task_graph_runner_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/task_graph_runner.h"
+#include "cc/raster/task_graph_runner.h"
#include <vector>
@@ -167,7 +167,7 @@ class TaskGraphRunnerTest : public TaskGraphRunnerTestBase,
public base::DelegateSimpleThread::Delegate {
public:
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
const size_t num_threads = GetParam();
while (workers_.size() < num_threads) {
scoped_ptr<base::DelegateSimpleThread> worker =
@@ -179,7 +179,7 @@ class TaskGraphRunnerTest : public TaskGraphRunnerTestBase,
for (int i = 0; i < kNamespaceCount; ++i)
namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
}
- virtual void TearDown() override {
+ void TearDown() override {
task_graph_runner_->Shutdown();
while (workers_.size()) {
scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front();
@@ -285,14 +285,14 @@ class TaskGraphRunnerSingleThreadTest
public base::DelegateSimpleThread::Delegate {
public:
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
worker_.reset(new base::DelegateSimpleThread(this, "TestWorker"));
worker_->Start();
for (int i = 0; i < kNamespaceCount; ++i)
namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
}
- virtual void TearDown() override {
+ void TearDown() override {
task_graph_runner_->Shutdown();
worker_->Join();
}
diff --git a/chromium/cc/raster/texture_compressor.cc b/chromium/cc/raster/texture_compressor.cc
new file mode 100644
index 00000000000..b8992bb9eef
--- /dev/null
+++ b/chromium/cc/raster/texture_compressor.cc
@@ -0,0 +1,34 @@
+// 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.
+
+#include "cc/raster/texture_compressor.h"
+
+#include "base/logging.h"
+#include "cc/raster/texture_compressor_etc1.h"
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#include "base/cpu.h"
+#include "cc/raster/texture_compressor_etc1_sse.h"
+#endif
+
+namespace cc {
+
+scoped_ptr<TextureCompressor> TextureCompressor::Create(Format format) {
+ switch (format) {
+ case kFormatETC1: {
+#if defined(ARCH_CPU_X86_FAMILY)
+ base::CPU cpu;
+ if (cpu.has_sse2()) {
+ return make_scoped_ptr(new TextureCompressorETC1SSE());
+ }
+#endif
+ return make_scoped_ptr(new TextureCompressorETC1());
+ }
+ }
+
+ NOTREACHED();
+ return nullptr;
+}
+
+} // namespace cc
diff --git a/chromium/cc/raster/texture_compressor.h b/chromium/cc/raster/texture_compressor.h
new file mode 100644
index 00000000000..95536bcb40c
--- /dev/null
+++ b/chromium/cc/raster/texture_compressor.h
@@ -0,0 +1,46 @@
+// 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_RASTER_TEXTURE_COMPRESSOR_H_
+#define CC_RASTER_TEXTURE_COMPRESSOR_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+class CC_EXPORT TextureCompressor {
+ public:
+ enum Format {
+ kFormatETC1,
+ };
+
+ enum Quality {
+ kQualityLow,
+ kQualityMedium,
+ kQualityHigh,
+ };
+
+ static scoped_ptr<TextureCompressor> Create(Format format);
+ virtual ~TextureCompressor() {}
+
+ virtual void Compress(const uint8_t* src,
+ uint8_t* dst,
+ int width,
+ int height,
+ Quality quality) = 0;
+
+ protected:
+ TextureCompressor() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureCompressor);
+};
+
+} // namespace cc
+
+#endif // CC_RASTER_TEXTURE_COMPRESSOR_H_
diff --git a/chromium/cc/raster/texture_compressor_etc1.cc b/chromium/cc/raster/texture_compressor_etc1.cc
new file mode 100644
index 00000000000..e02737cc078
--- /dev/null
+++ b/chromium/cc/raster/texture_compressor_etc1.cc
@@ -0,0 +1,332 @@
+// 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.
+
+// See the following specification for details on the ETC1 format:
+// https://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
+
+#include "cc/raster/texture_compressor_etc1.h"
+
+#include <string.h>
+#include <limits>
+
+#include "base/logging.h"
+
+// Defining the following macro will cause the error metric function to weigh
+// each color channel differently depending on how the human eye can perceive
+// them. This can give a slight improvement in image quality at the cost of a
+// performance hit.
+// #define USE_PERCEIVED_ERROR_METRIC
+
+namespace cc {
+
+namespace {
+
+// Constructs a color from a given base color and luminance value.
+inline Color MakeColor(const Color& base, int16_t lum) {
+ int b = static_cast<int>(base.channels.b) + lum;
+ int g = static_cast<int>(base.channels.g) + lum;
+ int r = static_cast<int>(base.channels.r) + lum;
+ Color color;
+ color.channels.b = static_cast<uint8_t>(clamp(b, 0, 255));
+ color.channels.g = static_cast<uint8_t>(clamp(g, 0, 255));
+ color.channels.r = static_cast<uint8_t>(clamp(r, 0, 255));
+ return color;
+}
+
+// Calculates the error metric for two colors. A small error signals that the
+// colors are similar to each other, a large error the signals the opposite.
+inline uint32_t GetColorError(const Color& u, const Color& v) {
+#ifdef USE_PERCEIVED_ERROR_METRIC
+ float delta_b = static_cast<float>(u.channels.b) - v.channels.b;
+ float delta_g = static_cast<float>(u.channels.g) - v.channels.g;
+ float delta_r = static_cast<float>(u.channels.r) - v.channels.r;
+ return static_cast<uint32_t>(0.299f * delta_b * delta_b +
+ 0.587f * delta_g * delta_g +
+ 0.114f * delta_r * delta_r);
+#else
+ int delta_b = static_cast<int>(u.channels.b) - v.channels.b;
+ int delta_g = static_cast<int>(u.channels.g) - v.channels.g;
+ int delta_r = static_cast<int>(u.channels.r) - v.channels.r;
+ return delta_b * delta_b + delta_g * delta_g + delta_r * delta_r;
+#endif
+}
+
+void GetAverageColor(const Color* src, float* avg_color) {
+ uint32_t sum_b = 0, sum_g = 0, sum_r = 0;
+
+ for (unsigned int i = 0; i < 8; ++i) {
+ sum_b += src[i].channels.b;
+ sum_g += src[i].channels.g;
+ sum_r += src[i].channels.r;
+ }
+
+ const float kInv8 = 1.0f / 8.0f;
+ avg_color[0] = static_cast<float>(sum_b) * kInv8;
+ avg_color[1] = static_cast<float>(sum_g) * kInv8;
+ avg_color[2] = static_cast<float>(sum_r) * kInv8;
+}
+
+void ComputeLuminance(uint8_t* block,
+ const Color* src,
+ const Color& base,
+ int sub_block_id,
+ const uint8_t* idx_to_num_tab) {
+ uint32_t best_tbl_err = std::numeric_limits<uint32_t>::max();
+ uint8_t best_tbl_idx = 0;
+ uint8_t best_mod_idx[8][8]; // [table][texel]
+
+ // Try all codeword tables to find the one giving the best results for this
+ // block.
+ for (unsigned int tbl_idx = 0; tbl_idx < 8; ++tbl_idx) {
+ // Pre-compute all the candidate colors; combinations of the base color and
+ // all available luminance values.
+ Color candidate_color[4]; // [modifier]
+ for (unsigned int mod_idx = 0; mod_idx < 4; ++mod_idx) {
+ int16_t lum = g_codeword_tables[tbl_idx][mod_idx];
+ candidate_color[mod_idx] = MakeColor(base, lum);
+ }
+
+ uint32_t tbl_err = 0;
+
+ for (unsigned int i = 0; i < 8; ++i) {
+ // Try all modifiers in the current table to find which one gives the
+ // smallest error.
+ uint32_t best_mod_err = std::numeric_limits<uint32_t>::max();
+ for (unsigned int mod_idx = 0; mod_idx < 4; ++mod_idx) {
+ const Color& color = candidate_color[mod_idx];
+
+ uint32_t mod_err = GetColorError(src[i], color);
+ if (mod_err < best_mod_err) {
+ best_mod_idx[tbl_idx][i] = mod_idx;
+ best_mod_err = mod_err;
+
+ if (mod_err == 0)
+ break; // We cannot do any better than this.
+ }
+ }
+
+ tbl_err += best_mod_err;
+ if (tbl_err > best_tbl_err)
+ break; // We're already doing worse than the best table so skip.
+ }
+
+ if (tbl_err < best_tbl_err) {
+ best_tbl_err = tbl_err;
+ best_tbl_idx = tbl_idx;
+
+ if (tbl_err == 0)
+ break; // We cannot do any better than this.
+ }
+ }
+
+ WriteCodewordTable(block, sub_block_id, best_tbl_idx);
+
+ uint32_t pix_data = 0;
+
+ for (unsigned int i = 0; i < 8; ++i) {
+ uint8_t mod_idx = best_mod_idx[best_tbl_idx][i];
+ uint8_t pix_idx = g_mod_to_pix[mod_idx];
+
+ uint32_t lsb = pix_idx & 0x1;
+ uint32_t msb = pix_idx >> 1;
+
+ // Obtain the texel number as specified in the standard.
+ int texel_num = idx_to_num_tab[i];
+ pix_data |= msb << (texel_num + 16);
+ pix_data |= lsb << (texel_num);
+ }
+
+ WritePixelData(block, pix_data);
+}
+
+/**
+ * Tries to compress the block under the assumption that it's a single color
+ * block. If it's not the function will bail out without writing anything to
+ * the destination buffer.
+ */
+bool TryCompressSolidBlock(uint8_t* dst, const Color* src) {
+ for (unsigned int i = 1; i < 16; ++i) {
+ if (src[i].bits != src[0].bits)
+ return false;
+ }
+
+ // Clear destination buffer so that we can "or" in the results.
+ memset(dst, 0, 8);
+
+ float src_color_float[3] = {static_cast<float>(src->channels.b),
+ static_cast<float>(src->channels.g),
+ static_cast<float>(src->channels.r)};
+ Color base = MakeColor555(src_color_float);
+
+ WriteDiff(dst, true);
+ WriteFlip(dst, false);
+ WriteColors555(dst, base, base);
+
+ uint8_t best_tbl_idx = 0;
+ uint8_t best_mod_idx = 0;
+ uint32_t best_mod_err = std::numeric_limits<uint32_t>::max();
+
+ // Try all codeword tables to find the one giving the best results for this
+ // block.
+ for (unsigned int tbl_idx = 0; tbl_idx < 8; ++tbl_idx) {
+ // Try all modifiers in the current table to find which one gives the
+ // smallest error.
+ for (unsigned int mod_idx = 0; mod_idx < 4; ++mod_idx) {
+ int16_t lum = g_codeword_tables[tbl_idx][mod_idx];
+ const Color& color = MakeColor(base, lum);
+
+ uint32_t mod_err = GetColorError(*src, color);
+ if (mod_err < best_mod_err) {
+ best_tbl_idx = tbl_idx;
+ best_mod_idx = mod_idx;
+ best_mod_err = mod_err;
+
+ if (mod_err == 0)
+ break; // We cannot do any better than this.
+ }
+ }
+
+ if (best_mod_err == 0)
+ break;
+ }
+
+ WriteCodewordTable(dst, 0, best_tbl_idx);
+ WriteCodewordTable(dst, 1, best_tbl_idx);
+
+ uint8_t pix_idx = g_mod_to_pix[best_mod_idx];
+ uint32_t lsb = pix_idx & 0x1;
+ uint32_t msb = pix_idx >> 1;
+
+ uint32_t pix_data = 0;
+ for (unsigned int i = 0; i < 2; ++i) {
+ for (unsigned int j = 0; j < 8; ++j) {
+ // Obtain the texel number as specified in the standard.
+ int texel_num = g_idx_to_num[i][j];
+ pix_data |= msb << (texel_num + 16);
+ pix_data |= lsb << (texel_num);
+ }
+ }
+
+ WritePixelData(dst, pix_data);
+ return true;
+}
+
+void CompressBlock(uint8_t* dst, const Color* ver_src, const Color* hor_src) {
+ if (TryCompressSolidBlock(dst, ver_src))
+ return;
+
+ const Color* sub_block_src[4] = {ver_src, ver_src + 8, hor_src, hor_src + 8};
+
+ Color sub_block_avg[4];
+ bool use_differential[2] = {true, true};
+
+ // Compute the average color for each sub block and determine if differential
+ // coding can be used.
+ for (unsigned int i = 0, j = 1; i < 4; i += 2, j += 2) {
+ float avg_color_0[3];
+ GetAverageColor(sub_block_src[i], avg_color_0);
+ Color avg_color_555_0 = MakeColor555(avg_color_0);
+
+ float avg_color_1[3];
+ GetAverageColor(sub_block_src[j], avg_color_1);
+ Color avg_color_555_1 = MakeColor555(avg_color_1);
+
+ for (unsigned int light_idx = 0; light_idx < 3; ++light_idx) {
+ int u = avg_color_555_0.components[light_idx] >> 3;
+ int v = avg_color_555_1.components[light_idx] >> 3;
+
+ int component_diff = v - u;
+ if (component_diff < -4 || component_diff > 3) {
+ use_differential[i / 2] = false;
+ sub_block_avg[i] = MakeColor444(avg_color_0);
+ sub_block_avg[j] = MakeColor444(avg_color_1);
+ } else {
+ sub_block_avg[i] = avg_color_555_0;
+ sub_block_avg[j] = avg_color_555_1;
+ }
+ }
+ }
+
+ // Compute the error of each sub block before adjusting for luminance. These
+ // error values are later used for determining if we should flip the sub
+ // block or not.
+ uint32_t sub_block_err[4] = {0};
+ for (unsigned int i = 0; i < 4; ++i) {
+ for (unsigned int j = 0; j < 8; ++j) {
+ sub_block_err[i] += GetColorError(sub_block_avg[i], sub_block_src[i][j]);
+ }
+ }
+
+ bool flip =
+ sub_block_err[2] + sub_block_err[3] < sub_block_err[0] + sub_block_err[1];
+
+ // Clear destination buffer so that we can "or" in the results.
+ memset(dst, 0, 8);
+
+ WriteDiff(dst, use_differential[!!flip]);
+ WriteFlip(dst, flip);
+
+ uint8_t sub_block_off_0 = flip ? 2 : 0;
+ uint8_t sub_block_off_1 = sub_block_off_0 + 1;
+
+ if (use_differential[!!flip]) {
+ WriteColors555(dst, sub_block_avg[sub_block_off_0],
+ sub_block_avg[sub_block_off_1]);
+ } else {
+ WriteColors444(dst, sub_block_avg[sub_block_off_0],
+ sub_block_avg[sub_block_off_1]);
+ }
+
+ // Compute luminance for the first sub block.
+ ComputeLuminance(dst, sub_block_src[sub_block_off_0],
+ sub_block_avg[sub_block_off_0], 0,
+ g_idx_to_num[sub_block_off_0]);
+ // Compute luminance for the second sub block.
+ ComputeLuminance(dst, sub_block_src[sub_block_off_1],
+ sub_block_avg[sub_block_off_1], 1,
+ g_idx_to_num[sub_block_off_1]);
+}
+
+} // namespace
+
+void TextureCompressorETC1::Compress(const uint8_t* src,
+ uint8_t* dst,
+ int width,
+ int height,
+ Quality quality) {
+ DCHECK_GE(width, 4);
+ DCHECK_EQ((width & 3), 0);
+ DCHECK_GE(height, 4);
+ DCHECK_EQ((height & 3), 0);
+
+ Color ver_blocks[16];
+ Color hor_blocks[16];
+
+ for (int y = 0; y < height; y += 4, src += width * 4 * 4) {
+ for (int x = 0; x < width; x += 4, dst += 8) {
+ const Color* row0 = reinterpret_cast<const Color*>(src + x * 4);
+ const Color* row1 = row0 + width;
+ const Color* row2 = row1 + width;
+ const Color* row3 = row2 + width;
+
+ memcpy(ver_blocks, row0, 8);
+ memcpy(ver_blocks + 2, row1, 8);
+ memcpy(ver_blocks + 4, row2, 8);
+ memcpy(ver_blocks + 6, row3, 8);
+ memcpy(ver_blocks + 8, row0 + 2, 8);
+ memcpy(ver_blocks + 10, row1 + 2, 8);
+ memcpy(ver_blocks + 12, row2 + 2, 8);
+ memcpy(ver_blocks + 14, row3 + 2, 8);
+
+ memcpy(hor_blocks, row0, 16);
+ memcpy(hor_blocks + 4, row1, 16);
+ memcpy(hor_blocks + 8, row2, 16);
+ memcpy(hor_blocks + 12, row3, 16);
+
+ CompressBlock(dst, ver_blocks, hor_blocks);
+ }
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/raster/texture_compressor_etc1.h b/chromium/cc/raster/texture_compressor_etc1.h
new file mode 100644
index 00000000000..2d2771a888c
--- /dev/null
+++ b/chromium/cc/raster/texture_compressor_etc1.h
@@ -0,0 +1,206 @@
+// 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_RASTER_TEXTURE_COMPRESSOR_ETC1_H_
+#define CC_RASTER_TEXTURE_COMPRESSOR_ETC1_H_
+
+#include "cc/raster/texture_compressor.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+
+namespace cc {
+
+template <typename T>
+inline T clamp(T val, T min, T max) {
+ return val < min ? min : (val > max ? max : val);
+}
+
+inline uint8_t round_to_5_bits(float val) {
+ return clamp<uint8_t>(val * 31.0f / 255.0f + 0.5f, 0, 31);
+}
+
+inline uint8_t round_to_4_bits(float val) {
+ return clamp<uint8_t>(val * 15.0f / 255.0f + 0.5f, 0, 15);
+}
+
+union Color {
+ struct BgraColorType {
+ uint8_t b;
+ uint8_t g;
+ uint8_t r;
+ uint8_t a;
+ } channels;
+ uint8_t components[4];
+ uint32_t bits;
+};
+
+// Codeword tables.
+// See: Table 3.17.2
+ALIGNAS(16) static const int16_t g_codeword_tables[8][4] = {
+ {-8, -2, 2, 8},
+ {-17, -5, 5, 17},
+ {-29, -9, 9, 29},
+ {-42, -13, 13, 42},
+ {-60, -18, 18, 60},
+ {-80, -24, 24, 80},
+ {-106, -33, 33, 106},
+ {-183, -47, 47, 183}};
+
+// Maps modifier indices to pixel index values.
+// See: Table 3.17.3
+static const uint8_t g_mod_to_pix[4] = {3, 2, 0, 1};
+
+// The ETC1 specification index texels as follows:
+// [a][e][i][m] [ 0][ 4][ 8][12]
+// [b][f][j][n] <-> [ 1][ 5][ 9][13]
+// [c][g][k][o] [ 2][ 6][10][14]
+// [d][h][l][p] [ 3][ 7][11][15]
+
+// [ 0][ 1][ 2][ 3] [ 0][ 1][ 4][ 5]
+// [ 4][ 5][ 6][ 7] <-> [ 8][ 9][12][13]
+// [ 8][ 9][10][11] [ 2][ 3][ 6][ 7]
+// [12][13][14][15] [10][11][14][15]
+
+// However, when extracting sub blocks from BGRA data the natural array
+// indexing order ends up different:
+// vertical0: [a][e][b][f] horizontal0: [a][e][i][m]
+// [c][g][d][h] [b][f][j][n]
+// vertical1: [i][m][j][n] horizontal1: [c][g][k][o]
+// [k][o][l][p] [d][h][l][p]
+
+// In order to translate from the natural array indices in a sub block to the
+// indices (number) used by specification and hardware we use this table.
+static const uint8_t g_idx_to_num[4][8] = {
+ {0, 4, 1, 5, 2, 6, 3, 7}, // Vertical block 0.
+ {8, 12, 9, 13, 10, 14, 11, 15}, // Vertical block 1.
+ {0, 4, 8, 12, 1, 5, 9, 13}, // Horizontal block 0.
+ {2, 6, 10, 14, 3, 7, 11, 15} // Horizontal block 1.
+};
+
+inline void WriteColors444(uint8_t* block,
+ const Color& color0,
+ const Color& color1) {
+ // Write output color for BGRA textures.
+ block[0] = (color0.channels.r & 0xf0) | (color1.channels.r >> 4);
+ block[1] = (color0.channels.g & 0xf0) | (color1.channels.g >> 4);
+ block[2] = (color0.channels.b & 0xf0) | (color1.channels.b >> 4);
+}
+
+inline void WriteColors555(uint8_t* block,
+ const Color& color0,
+ const Color& color1) {
+ // Table for conversion to 3-bit two complement format.
+ static const uint8_t two_compl_trans_table[8] = {
+ 4, // -4 (100b)
+ 5, // -3 (101b)
+ 6, // -2 (110b)
+ 7, // -1 (111b)
+ 0, // 0 (000b)
+ 1, // 1 (001b)
+ 2, // 2 (010b)
+ 3, // 3 (011b)
+ };
+
+ int16_t delta_r =
+ static_cast<int16_t>(color1.channels.r >> 3) - (color0.channels.r >> 3);
+ int16_t delta_g =
+ static_cast<int16_t>(color1.channels.g >> 3) - (color0.channels.g >> 3);
+ int16_t delta_b =
+ static_cast<int16_t>(color1.channels.b >> 3) - (color0.channels.b >> 3);
+ DCHECK_GE(delta_r, -4);
+ DCHECK_LE(delta_r, 3);
+ DCHECK_GE(delta_g, -4);
+ DCHECK_LE(delta_g, 3);
+ DCHECK_GE(delta_b, -4);
+ DCHECK_LE(delta_b, 3);
+
+ // Write output color for BGRA textures.
+ block[0] = (color0.channels.r & 0xf8) | two_compl_trans_table[delta_r + 4];
+ block[1] = (color0.channels.g & 0xf8) | two_compl_trans_table[delta_g + 4];
+ block[2] = (color0.channels.b & 0xf8) | two_compl_trans_table[delta_b + 4];
+}
+
+inline void WriteCodewordTable(uint8_t* block,
+ uint8_t sub_block_id,
+ uint8_t table) {
+ DCHECK_LT(sub_block_id, 2);
+ DCHECK_LT(table, 8);
+
+ uint8_t shift = (2 + (3 - sub_block_id * 3));
+ block[3] &= ~(0x07 << shift);
+ block[3] |= table << shift;
+}
+
+inline void WritePixelData(uint8_t* block, uint32_t pixel_data) {
+ block[4] |= pixel_data >> 24;
+ block[5] |= (pixel_data >> 16) & 0xff;
+ block[6] |= (pixel_data >> 8) & 0xff;
+ block[7] |= pixel_data & 0xff;
+}
+
+inline void WriteFlip(uint8_t* block, bool flip) {
+ block[3] &= ~0x01;
+ block[3] |= static_cast<uint8_t>(flip);
+}
+
+inline void WriteDiff(uint8_t* block, bool diff) {
+ block[3] &= ~0x02;
+ block[3] |= static_cast<uint8_t>(diff) << 1;
+}
+
+// Compress and rounds BGR888 into BGR444. The resulting BGR444 color is
+// expanded to BGR888 as it would be in hardware after decompression. The
+// actual 444-bit data is available in the four most significant bits of each
+// channel.
+inline Color MakeColor444(const float* bgr) {
+ uint8_t b4 = round_to_4_bits(bgr[0]);
+ uint8_t g4 = round_to_4_bits(bgr[1]);
+ uint8_t r4 = round_to_4_bits(bgr[2]);
+ Color bgr444;
+ bgr444.channels.b = (b4 << 4) | b4;
+ bgr444.channels.g = (g4 << 4) | g4;
+ bgr444.channels.r = (r4 << 4) | r4;
+ // Added to distinguish between expanded 555 and 444 colors.
+ bgr444.channels.a = 0x44;
+ return bgr444;
+}
+
+// Compress and rounds BGR888 into BGR555. The resulting BGR555 color is
+// expanded to BGR888 as it would be in hardware after decompression. The
+// actual 555-bit data is available in the five most significant bits of each
+// channel.
+inline Color MakeColor555(const float* bgr) {
+ uint8_t b5 = round_to_5_bits(bgr[0]);
+ uint8_t g5 = round_to_5_bits(bgr[1]);
+ uint8_t r5 = round_to_5_bits(bgr[2]);
+ Color bgr555;
+ bgr555.channels.b = (b5 << 3) | (b5 >> 2);
+ bgr555.channels.g = (g5 << 3) | (g5 >> 2);
+ bgr555.channels.r = (r5 << 3) | (r5 >> 2);
+ // Added to distinguish between expanded 555 and 444 colors.
+ bgr555.channels.a = 0x55;
+ return bgr555;
+}
+
+class CC_EXPORT TextureCompressorETC1 : public TextureCompressor {
+ public:
+ TextureCompressorETC1() {}
+
+ // Compress a texture using ETC1. Note that the |quality| parameter is
+ // ignored. The current implementation does not support different quality
+ // settings.
+ void Compress(const uint8_t* src,
+ uint8_t* dst,
+ int width,
+ int height,
+ Quality quality) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureCompressorETC1);
+};
+
+} // namespace cc
+
+#endif // CC_RASTER_TEXTURE_COMPRESSOR_ETC1_H_
diff --git a/chromium/cc/raster/texture_compressor_etc1_sse.cc b/chromium/cc/raster/texture_compressor_etc1_sse.cc
new file mode 100644
index 00000000000..229782238be
--- /dev/null
+++ b/chromium/cc/raster/texture_compressor_etc1_sse.cc
@@ -0,0 +1,821 @@
+// 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.
+
+#include "cc/raster/texture_compressor_etc1_sse.h"
+
+#include <emmintrin.h>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+// Using this header for common functions such as Color handling
+// and codeword table.
+#include "cc/raster/texture_compressor_etc1.h"
+
+namespace cc {
+
+namespace {
+
+inline uint32_t SetETC1MaxError(uint32_t avg_error) {
+ // ETC1 codeword table is sorted in ascending order.
+ // Our algorithm will try to identify the index that generates the minimum
+ // error.
+ // The min error calculated during ComputeLuminance main loop will converge
+ // towards that value.
+ // We use this threshold to determine when it doesn't make sense to iterate
+ // further through the array.
+ return avg_error + avg_error / 2 + 384;
+}
+
+struct __sse_data {
+ // This is used to store raw data.
+ uint8_t* block;
+ // This is used to store 8 bit packed values.
+ __m128i* packed;
+ // This is used to store 32 bit zero extended values into 4x4 arrays.
+ __m128i* blue;
+ __m128i* green;
+ __m128i* red;
+};
+
+// Commonly used registers throughout the code.
+static const __m128i __sse_zero = _mm_set1_epi32(0);
+static const __m128i __sse_max_int = _mm_set1_epi32(0x7FFFFFFF);
+
+inline __m128i AddAndClamp(const __m128i x, const __m128i y) {
+ static const __m128i color_max = _mm_set1_epi32(0xFF);
+ return _mm_max_epi16(__sse_zero,
+ _mm_min_epi16(_mm_add_epi16(x, y), color_max));
+}
+
+inline __m128i GetColorErrorSSE(const __m128i x, const __m128i y) {
+ // Changed from _mm_mullo_epi32 (SSE4) to _mm_mullo_epi16 (SSE2).
+ __m128i ret = _mm_sub_epi16(x, y);
+ return _mm_mullo_epi16(ret, ret);
+}
+
+inline __m128i AddChannelError(const __m128i x,
+ const __m128i y,
+ const __m128i z) {
+ return _mm_add_epi32(x, _mm_add_epi32(y, z));
+}
+
+inline uint32_t SumSSE(const __m128i x) {
+ __m128i sum = _mm_add_epi32(x, _mm_shuffle_epi32(x, 0x4E));
+ sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, 0xB1));
+
+ return _mm_cvtsi128_si32(sum);
+}
+
+inline uint32_t GetVerticalError(const __sse_data* data,
+ const __m128i* blue_avg,
+ const __m128i* green_avg,
+ const __m128i* red_avg,
+ uint32_t* verror) {
+ __m128i error = __sse_zero;
+
+ for (int i = 0; i < 4; i++) {
+ error = _mm_add_epi32(error, GetColorErrorSSE(data->blue[i], blue_avg[0]));
+ error =
+ _mm_add_epi32(error, GetColorErrorSSE(data->green[i], green_avg[0]));
+ error = _mm_add_epi32(error, GetColorErrorSSE(data->red[i], red_avg[0]));
+ }
+
+ error = _mm_add_epi32(error, _mm_shuffle_epi32(error, 0x4E));
+
+ verror[0] = _mm_cvtsi128_si32(error);
+ verror[1] = _mm_cvtsi128_si32(_mm_shuffle_epi32(error, 0xB1));
+
+ return verror[0] + verror[1];
+}
+
+inline uint32_t GetHorizontalError(const __sse_data* data,
+ const __m128i* blue_avg,
+ const __m128i* green_avg,
+ const __m128i* red_avg,
+ uint32_t* verror) {
+ __m128i error = __sse_zero;
+ int first_index, second_index;
+
+ for (int i = 0; i < 2; i++) {
+ first_index = 2 * i;
+ second_index = first_index + 1;
+
+ error = _mm_add_epi32(
+ error, GetColorErrorSSE(data->blue[first_index], blue_avg[i]));
+ error = _mm_add_epi32(
+ error, GetColorErrorSSE(data->blue[second_index], blue_avg[i]));
+ error = _mm_add_epi32(
+ error, GetColorErrorSSE(data->green[first_index], green_avg[i]));
+ error = _mm_add_epi32(
+ error, GetColorErrorSSE(data->green[second_index], green_avg[i]));
+ error = _mm_add_epi32(error,
+ GetColorErrorSSE(data->red[first_index], red_avg[i]));
+ error = _mm_add_epi32(
+ error, GetColorErrorSSE(data->red[second_index], red_avg[i]));
+ }
+
+ error = _mm_add_epi32(error, _mm_shuffle_epi32(error, 0x4E));
+
+ verror[0] = _mm_cvtsi128_si32(error);
+ verror[1] = _mm_cvtsi128_si32(_mm_shuffle_epi32(error, 0xB1));
+
+ return verror[0] + verror[1];
+}
+
+inline void GetAvgColors(const __sse_data* data,
+ float* output,
+ bool* __sse_use_diff) {
+ __m128i sum[2], tmp;
+
+ // TODO(radu.velea): _mm_avg_epu8 on packed data maybe.
+
+ // Compute avg red value.
+ // [S0 S0 S1 S1]
+ sum[0] = _mm_add_epi32(data->red[0], data->red[1]);
+ sum[0] = _mm_add_epi32(sum[0], _mm_shuffle_epi32(sum[0], 0xB1));
+
+ // [S2 S2 S3 S3]
+ sum[1] = _mm_add_epi32(data->red[2], data->red[3]);
+ sum[1] = _mm_add_epi32(sum[1], _mm_shuffle_epi32(sum[1], 0xB1));
+
+ float hred[2], vred[2];
+ hred[0] = (_mm_cvtsi128_si32(
+ _mm_add_epi32(sum[0], _mm_shuffle_epi32(sum[0], 0x4E)))) /
+ 8.0f;
+ hred[1] = (_mm_cvtsi128_si32(
+ _mm_add_epi32(sum[1], _mm_shuffle_epi32(sum[1], 0x4E)))) /
+ 8.0f;
+
+ tmp = _mm_add_epi32(sum[0], sum[1]);
+ vred[0] = (_mm_cvtsi128_si32(tmp)) / 8.0f;
+ vred[1] = (_mm_cvtsi128_si32(_mm_shuffle_epi32(tmp, 0x2))) / 8.0f;
+
+ // Compute avg green value.
+ // [S0 S0 S1 S1]
+ sum[0] = _mm_add_epi32(data->green[0], data->green[1]);
+ sum[0] = _mm_add_epi32(sum[0], _mm_shuffle_epi32(sum[0], 0xB1));
+
+ // [S2 S2 S3 S3]
+ sum[1] = _mm_add_epi32(data->green[2], data->green[3]);
+ sum[1] = _mm_add_epi32(sum[1], _mm_shuffle_epi32(sum[1], 0xB1));
+
+ float hgreen[2], vgreen[2];
+ hgreen[0] = (_mm_cvtsi128_si32(
+ _mm_add_epi32(sum[0], _mm_shuffle_epi32(sum[0], 0x4E)))) /
+ 8.0f;
+ hgreen[1] = (_mm_cvtsi128_si32(
+ _mm_add_epi32(sum[1], _mm_shuffle_epi32(sum[1], 0x4E)))) /
+ 8.0f;
+
+ tmp = _mm_add_epi32(sum[0], sum[1]);
+ vgreen[0] = (_mm_cvtsi128_si32(tmp)) / 8.0f;
+ vgreen[1] = (_mm_cvtsi128_si32(_mm_shuffle_epi32(tmp, 0x2))) / 8.0f;
+
+ // Compute avg blue value.
+ // [S0 S0 S1 S1]
+ sum[0] = _mm_add_epi32(data->blue[0], data->blue[1]);
+ sum[0] = _mm_add_epi32(sum[0], _mm_shuffle_epi32(sum[0], 0xB1));
+
+ // [S2 S2 S3 S3]
+ sum[1] = _mm_add_epi32(data->blue[2], data->blue[3]);
+ sum[1] = _mm_add_epi32(sum[1], _mm_shuffle_epi32(sum[1], 0xB1));
+
+ float hblue[2], vblue[2];
+ hblue[0] = (_mm_cvtsi128_si32(
+ _mm_add_epi32(sum[0], _mm_shuffle_epi32(sum[0], 0x4E)))) /
+ 8.0f;
+ hblue[1] = (_mm_cvtsi128_si32(
+ _mm_add_epi32(sum[1], _mm_shuffle_epi32(sum[1], 0x4E)))) /
+ 8.0f;
+
+ tmp = _mm_add_epi32(sum[0], sum[1]);
+ vblue[0] = (_mm_cvtsi128_si32(tmp)) / 8.0f;
+ vblue[1] = (_mm_cvtsi128_si32(_mm_shuffle_epi32(tmp, 0x2))) / 8.0f;
+
+ // TODO(radu.velea): Return int's instead of floats, based on Quality.
+ output[0] = vblue[0];
+ output[1] = vgreen[0];
+ output[2] = vred[0];
+
+ output[3] = vblue[1];
+ output[4] = vgreen[1];
+ output[5] = vred[1];
+
+ output[6] = hblue[0];
+ output[7] = hgreen[0];
+ output[8] = hred[0];
+
+ output[9] = hblue[1];
+ output[10] = hgreen[1];
+ output[11] = hred[1];
+
+ __m128i threshold_upper = _mm_set1_epi32(3);
+ __m128i threshold_lower = _mm_set1_epi32(-4);
+
+ __m128 factor_v = _mm_set1_ps(31.0f / 255.0f);
+ __m128 rounding_v = _mm_set1_ps(0.5f);
+ __m128 h_avg_0 = _mm_set_ps(hblue[0], hgreen[0], hred[0], 0);
+ __m128 h_avg_1 = _mm_set_ps(hblue[1], hgreen[1], hred[1], 0);
+
+ __m128 v_avg_0 = _mm_set_ps(vblue[0], vgreen[0], vred[0], 0);
+ __m128 v_avg_1 = _mm_set_ps(vblue[1], vgreen[1], vred[1], 0);
+
+ h_avg_0 = _mm_mul_ps(h_avg_0, factor_v);
+ h_avg_1 = _mm_mul_ps(h_avg_1, factor_v);
+ v_avg_0 = _mm_mul_ps(v_avg_0, factor_v);
+ v_avg_1 = _mm_mul_ps(v_avg_1, factor_v);
+
+ h_avg_0 = _mm_add_ps(h_avg_0, rounding_v);
+ h_avg_1 = _mm_add_ps(h_avg_1, rounding_v);
+ v_avg_0 = _mm_add_ps(v_avg_0, rounding_v);
+ v_avg_1 = _mm_add_ps(v_avg_1, rounding_v);
+
+ __m128i h_avg_0i = _mm_cvttps_epi32(h_avg_0);
+ __m128i h_avg_1i = _mm_cvttps_epi32(h_avg_1);
+
+ __m128i v_avg_0i = _mm_cvttps_epi32(v_avg_0);
+ __m128i v_avg_1i = _mm_cvttps_epi32(v_avg_1);
+
+ h_avg_0i = _mm_sub_epi32(h_avg_1i, h_avg_0i);
+ v_avg_0i = _mm_sub_epi32(v_avg_1i, v_avg_0i);
+
+ __sse_use_diff[0] =
+ (0 == _mm_movemask_epi8(_mm_cmplt_epi32(v_avg_0i, threshold_lower)));
+ __sse_use_diff[0] &=
+ (0 == _mm_movemask_epi8(_mm_cmpgt_epi32(v_avg_0i, threshold_upper)));
+
+ __sse_use_diff[1] =
+ (0 == _mm_movemask_epi8(_mm_cmplt_epi32(h_avg_0i, threshold_lower)));
+ __sse_use_diff[1] &=
+ (0 == _mm_movemask_epi8(_mm_cmpgt_epi32(h_avg_0i, threshold_upper)));
+}
+
+void ComputeLuminance(uint8_t* block,
+ const Color& base,
+ const int sub_block_id,
+ const uint8_t* idx_to_num_tab,
+ const __sse_data* data,
+ const uint32_t expected_error) {
+ uint8_t best_tbl_idx = 0;
+ uint32_t best_error = 0x7FFFFFFF;
+ uint8_t best_mod_idx[8][8]; // [table][texel]
+
+ const __m128i base_blue = _mm_set1_epi32(base.channels.b);
+ const __m128i base_green = _mm_set1_epi32(base.channels.g);
+ const __m128i base_red = _mm_set1_epi32(base.channels.r);
+
+ __m128i test_red, test_blue, test_green, tmp, tmp_blue, tmp_green, tmp_red;
+ __m128i block_error, mask;
+
+ // This will have the minimum errors for each 4 pixels.
+ __m128i first_half_min;
+ __m128i second_half_min;
+
+ // This will have the matching table index combo for each 4 pixels.
+ __m128i first_half_pattern;
+ __m128i second_half_pattern;
+
+ const __m128i first_blue_data_block = data->blue[2 * sub_block_id];
+ const __m128i first_green_data_block = data->green[2 * sub_block_id];
+ const __m128i first_red_data_block = data->red[2 * sub_block_id];
+
+ const __m128i second_blue_data_block = data->blue[2 * sub_block_id + 1];
+ const __m128i second_green_data_block = data->green[2 * sub_block_id + 1];
+ const __m128i second_red_data_block = data->red[2 * sub_block_id + 1];
+
+ uint32_t min;
+ // Fail early to increase speed.
+ long delta = INT32_MAX;
+ uint32_t last_min = INT32_MAX;
+
+ const uint8_t shuffle_mask[] = {
+ 0x1B, 0x4E, 0xB1, 0xE4}; // Important they are sorted ascending.
+
+ for (unsigned int tbl_idx = 0; tbl_idx < 8; ++tbl_idx) {
+ tmp = _mm_set_epi32(
+ g_codeword_tables[tbl_idx][3], g_codeword_tables[tbl_idx][2],
+ g_codeword_tables[tbl_idx][1], g_codeword_tables[tbl_idx][0]);
+
+ test_blue = AddAndClamp(tmp, base_blue);
+ test_green = AddAndClamp(tmp, base_green);
+ test_red = AddAndClamp(tmp, base_red);
+
+ first_half_min = __sse_max_int;
+ second_half_min = __sse_max_int;
+
+ first_half_pattern = __sse_zero;
+ second_half_pattern = __sse_zero;
+
+ for (uint8_t imm8 : shuffle_mask) {
+ switch (imm8) {
+ case 0x1B:
+ tmp_blue = _mm_shuffle_epi32(test_blue, 0x1B);
+ tmp_green = _mm_shuffle_epi32(test_green, 0x1B);
+ tmp_red = _mm_shuffle_epi32(test_red, 0x1B);
+ break;
+ case 0x4E:
+ tmp_blue = _mm_shuffle_epi32(test_blue, 0x4E);
+ tmp_green = _mm_shuffle_epi32(test_green, 0x4E);
+ tmp_red = _mm_shuffle_epi32(test_red, 0x4E);
+ break;
+ case 0xB1:
+ tmp_blue = _mm_shuffle_epi32(test_blue, 0xB1);
+ tmp_green = _mm_shuffle_epi32(test_green, 0xB1);
+ tmp_red = _mm_shuffle_epi32(test_red, 0xB1);
+ break;
+ case 0xE4:
+ tmp_blue = _mm_shuffle_epi32(test_blue, 0xE4);
+ tmp_green = _mm_shuffle_epi32(test_green, 0xE4);
+ tmp_red = _mm_shuffle_epi32(test_red, 0xE4);
+ break;
+ default:
+ tmp_blue = test_blue;
+ tmp_green = test_green;
+ tmp_red = test_red;
+ }
+
+ tmp = _mm_set1_epi32(imm8);
+
+ block_error =
+ AddChannelError(GetColorErrorSSE(tmp_blue, first_blue_data_block),
+ GetColorErrorSSE(tmp_green, first_green_data_block),
+ GetColorErrorSSE(tmp_red, first_red_data_block));
+
+ // Save winning pattern.
+ first_half_pattern = _mm_max_epi16(
+ first_half_pattern,
+ _mm_and_si128(tmp, _mm_cmpgt_epi32(first_half_min, block_error)));
+ // Should use _mm_min_epi32(first_half_min, block_error); from SSE4
+ // otherwise we have a small performance penalty.
+ mask = _mm_cmplt_epi32(block_error, first_half_min);
+ first_half_min = _mm_add_epi32(_mm_and_si128(mask, block_error),
+ _mm_andnot_si128(mask, first_half_min));
+
+ // Compute second part of the block.
+ block_error =
+ AddChannelError(GetColorErrorSSE(tmp_blue, second_blue_data_block),
+ GetColorErrorSSE(tmp_green, second_green_data_block),
+ GetColorErrorSSE(tmp_red, second_red_data_block));
+
+ // Save winning pattern.
+ second_half_pattern = _mm_max_epi16(
+ second_half_pattern,
+ _mm_and_si128(tmp, _mm_cmpgt_epi32(second_half_min, block_error)));
+ // Should use _mm_min_epi32(second_half_min, block_error); from SSE4
+ // otherwise we have a small performance penalty.
+ mask = _mm_cmplt_epi32(block_error, second_half_min);
+ second_half_min = _mm_add_epi32(_mm_and_si128(mask, block_error),
+ _mm_andnot_si128(mask, second_half_min));
+ }
+
+ first_half_min = _mm_add_epi32(first_half_min, second_half_min);
+ first_half_min =
+ _mm_add_epi32(first_half_min, _mm_shuffle_epi32(first_half_min, 0x4E));
+ first_half_min =
+ _mm_add_epi32(first_half_min, _mm_shuffle_epi32(first_half_min, 0xB1));
+
+ min = _mm_cvtsi128_si32(first_half_min);
+
+ delta = min - last_min;
+ last_min = min;
+
+ if (min < best_error) {
+ best_tbl_idx = tbl_idx;
+ best_error = min;
+
+ best_mod_idx[tbl_idx][0] =
+ (_mm_cvtsi128_si32(first_half_pattern) >> (0)) & 3;
+ best_mod_idx[tbl_idx][4] =
+ (_mm_cvtsi128_si32(second_half_pattern) >> (0)) & 3;
+
+ best_mod_idx[tbl_idx][1] =
+ (_mm_cvtsi128_si32(_mm_shuffle_epi32(first_half_pattern, 0x1)) >>
+ (2)) &
+ 3;
+ best_mod_idx[tbl_idx][5] =
+ (_mm_cvtsi128_si32(_mm_shuffle_epi32(second_half_pattern, 0x1)) >>
+ (2)) &
+ 3;
+
+ best_mod_idx[tbl_idx][2] =
+ (_mm_cvtsi128_si32(_mm_shuffle_epi32(first_half_pattern, 0x2)) >>
+ (4)) &
+ 3;
+ best_mod_idx[tbl_idx][6] =
+ (_mm_cvtsi128_si32(_mm_shuffle_epi32(second_half_pattern, 0x2)) >>
+ (4)) &
+ 3;
+
+ best_mod_idx[tbl_idx][3] =
+ (_mm_cvtsi128_si32(_mm_shuffle_epi32(first_half_pattern, 0x3)) >>
+ (6)) &
+ 3;
+ best_mod_idx[tbl_idx][7] =
+ (_mm_cvtsi128_si32(_mm_shuffle_epi32(second_half_pattern, 0x3)) >>
+ (6)) &
+ 3;
+
+ if (best_error == 0) {
+ break;
+ }
+ } else if (delta > 0 && expected_error < min) {
+ // The error is growing and is well beyond expected threshold.
+ break;
+ }
+ }
+
+ WriteCodewordTable(block, sub_block_id, best_tbl_idx);
+
+ uint32_t pix_data = 0;
+ uint8_t mod_idx;
+ uint8_t pix_idx;
+ uint32_t lsb;
+ uint32_t msb;
+ int texel_num;
+
+ for (unsigned int i = 0; i < 8; ++i) {
+ mod_idx = best_mod_idx[best_tbl_idx][i];
+ pix_idx = g_mod_to_pix[mod_idx];
+
+ lsb = pix_idx & 0x1;
+ msb = pix_idx >> 1;
+
+ // Obtain the texel number as specified in the standard.
+ texel_num = idx_to_num_tab[i];
+ pix_data |= msb << (texel_num + 16);
+ pix_data |= lsb << (texel_num);
+ }
+
+ WritePixelData(block, pix_data);
+}
+
+void CompressBlock(uint8_t* dst, __sse_data* data) {
+ // First 3 values are for vertical 1, second 3 vertical 2, third 3 horizontal
+ // 1, last 3
+ // horizontal 2.
+ float __sse_avg_colors[12] = {
+ 0,
+ };
+ bool use_differential[2] = {true, true};
+ GetAvgColors(data, __sse_avg_colors, use_differential);
+ Color sub_block_avg[4];
+
+ // TODO(radu.velea): Remove floating point operations and use only int's +
+ // normal rounding and shifts for reduced Quality.
+ for (int i = 0, j = 1; i < 4; i += 2, j += 2) {
+ if (use_differential[i / 2] == false) {
+ sub_block_avg[i] = MakeColor444(&__sse_avg_colors[i * 3]);
+ sub_block_avg[j] = MakeColor444(&__sse_avg_colors[j * 3]);
+ } else {
+ sub_block_avg[i] = MakeColor555(&__sse_avg_colors[i * 3]);
+ sub_block_avg[j] = MakeColor555(&__sse_avg_colors[j * 3]);
+ }
+ }
+
+ __m128i red_avg[2], green_avg[2], blue_avg[2];
+
+ // TODO(radu.velea): Perfect accuracy, maybe skip floating variables.
+ blue_avg[0] = _mm_set_epi32(static_cast<int>(__sse_avg_colors[3]),
+ static_cast<int>(__sse_avg_colors[3]),
+ static_cast<int>(__sse_avg_colors[0]),
+ static_cast<int>(__sse_avg_colors[0]));
+
+ green_avg[0] = _mm_set_epi32(static_cast<int>(__sse_avg_colors[4]),
+ static_cast<int>(__sse_avg_colors[4]),
+ static_cast<int>(__sse_avg_colors[1]),
+ static_cast<int>(__sse_avg_colors[1]));
+
+ red_avg[0] = _mm_set_epi32(static_cast<int>(__sse_avg_colors[5]),
+ static_cast<int>(__sse_avg_colors[5]),
+ static_cast<int>(__sse_avg_colors[2]),
+ static_cast<int>(__sse_avg_colors[2]));
+
+ uint32_t vertical_error[2];
+ GetVerticalError(data, blue_avg, green_avg, red_avg, vertical_error);
+
+ // TODO(radu.velea): Perfect accuracy, maybe skip floating variables.
+ blue_avg[0] = _mm_set1_epi32(static_cast<int>(__sse_avg_colors[6]));
+ blue_avg[1] = _mm_set1_epi32(static_cast<int>(__sse_avg_colors[9]));
+
+ green_avg[0] = _mm_set1_epi32(static_cast<int>(__sse_avg_colors[7]));
+ green_avg[1] = _mm_set1_epi32(static_cast<int>(__sse_avg_colors[10]));
+
+ red_avg[0] = _mm_set1_epi32(static_cast<int>(__sse_avg_colors[8]));
+ red_avg[1] = _mm_set1_epi32(static_cast<int>(__sse_avg_colors[11]));
+
+ uint32_t horizontal_error[2];
+ GetHorizontalError(data, blue_avg, green_avg, red_avg, horizontal_error);
+
+ bool flip = (horizontal_error[0] + horizontal_error[1]) <
+ (vertical_error[0] + vertical_error[1]);
+ uint32_t* expected_errors = flip ? horizontal_error : vertical_error;
+
+ // Clear destination buffer so that we can "or" in the results.
+ memset(dst, 0, 8);
+
+ WriteDiff(dst, use_differential[!!flip]);
+ WriteFlip(dst, flip);
+
+ uint8_t sub_block_off_0 = flip ? 2 : 0;
+ uint8_t sub_block_off_1 = sub_block_off_0 + 1;
+
+ if (use_differential[!!flip]) {
+ WriteColors555(dst, sub_block_avg[sub_block_off_0],
+ sub_block_avg[sub_block_off_1]);
+ } else {
+ WriteColors444(dst, sub_block_avg[sub_block_off_0],
+ sub_block_avg[sub_block_off_1]);
+ }
+
+ if (!flip) {
+ // Transpose vertical data into horizontal lines.
+ __m128i tmp;
+ for (int i = 0; i < 4; i += 2) {
+ tmp = data->blue[i];
+ data->blue[i] = _mm_add_epi32(
+ _mm_move_epi64(data->blue[i]),
+ _mm_shuffle_epi32(_mm_move_epi64(data->blue[i + 1]), 0x4E));
+ data->blue[i + 1] = _mm_add_epi32(
+ _mm_move_epi64(_mm_shuffle_epi32(tmp, 0x4E)),
+ _mm_shuffle_epi32(
+ _mm_move_epi64(_mm_shuffle_epi32(data->blue[i + 1], 0x4E)),
+ 0x4E));
+
+ tmp = data->green[i];
+ data->green[i] = _mm_add_epi32(
+ _mm_move_epi64(data->green[i]),
+ _mm_shuffle_epi32(_mm_move_epi64(data->green[i + 1]), 0x4E));
+ data->green[i + 1] = _mm_add_epi32(
+ _mm_move_epi64(_mm_shuffle_epi32(tmp, 0x4E)),
+ _mm_shuffle_epi32(
+ _mm_move_epi64(_mm_shuffle_epi32(data->green[i + 1], 0x4E)),
+ 0x4E));
+
+ tmp = data->red[i];
+ data->red[i] = _mm_add_epi32(
+ _mm_move_epi64(data->red[i]),
+ _mm_shuffle_epi32(_mm_move_epi64(data->red[i + 1]), 0x4E));
+ data->red[i + 1] = _mm_add_epi32(
+ _mm_move_epi64(_mm_shuffle_epi32(tmp, 0x4E)),
+ _mm_shuffle_epi32(
+ _mm_move_epi64(_mm_shuffle_epi32(data->red[i + 1], 0x4E)), 0x4E));
+ }
+
+ tmp = data->blue[1];
+ data->blue[1] = data->blue[2];
+ data->blue[2] = tmp;
+
+ tmp = data->green[1];
+ data->green[1] = data->green[2];
+ data->green[2] = tmp;
+
+ tmp = data->red[1];
+ data->red[1] = data->red[2];
+ data->red[2] = tmp;
+ }
+
+ // Compute luminance for the first sub block.
+ ComputeLuminance(dst, sub_block_avg[sub_block_off_0], 0,
+ g_idx_to_num[sub_block_off_0], data,
+ SetETC1MaxError(expected_errors[0]));
+ // Compute luminance for the second sub block.
+ ComputeLuminance(dst, sub_block_avg[sub_block_off_1], 1,
+ g_idx_to_num[sub_block_off_1], data,
+ SetETC1MaxError(expected_errors[1]));
+}
+
+static void ExtractBlock(uint8_t* dst, const uint8_t* src, int width) {
+ for (int j = 0; j < 4; ++j) {
+ memcpy(&dst[j * 4 * 4], src, 4 * 4);
+ src += width * 4;
+ }
+}
+
+inline bool TransposeBlock(uint8_t* block, __m128i* transposed) {
+ // This function transforms an incommig block of RGBA or GBRA pixels into 4
+ // registers, each containing the data corresponding for a single channel.
+ // Ex: transposed[0] will have all the R values for a RGBA block,
+ // transposed[1] will have G, etc.
+ // The values are packed as 8 bit unsigned values in the SSE registers.
+
+ // Before doing any work we check if the block is solid.
+ __m128i tmp3, tmp2, tmp1, tmp0;
+ __m128i test_solid = _mm_set1_epi32(*((uint32_t*)block));
+ uint16_t mask = 0xFFFF;
+
+ // a0,a1,a2,...a7, ...a15
+ transposed[0] = _mm_loadu_si128((__m128i*)(block));
+ // b0, b1,b2,...b7.... b15
+ transposed[1] = _mm_loadu_si128((__m128i*)(block + 16));
+ // c0, c1,c2,...c7....c15
+ transposed[2] = _mm_loadu_si128((__m128i*)(block + 32));
+ // d0,d1,d2,...d7....d15
+ transposed[3] = _mm_loadu_si128((__m128i*)(block + 48));
+
+ for (int i = 0; i < 4; i++) {
+ mask &= _mm_movemask_epi8(_mm_cmpeq_epi8(transposed[i], test_solid));
+ }
+
+ if (mask == 0xFFFF) {
+ // Block is solid, no need to do any more work.
+ return false;
+ }
+
+ // a0,b0, a1,b1, a2,b2, a3,b3,....a7,b7
+ tmp0 = _mm_unpacklo_epi8(transposed[0], transposed[1]);
+ // c0,d0, c1,d1, c2,d2, c3,d3,... c7,d7
+ tmp1 = _mm_unpacklo_epi8(transposed[2], transposed[3]);
+ // a8,b8, a9,b9, a10,b10, a11,b11,...a15,b15
+ tmp2 = _mm_unpackhi_epi8(transposed[0], transposed[1]);
+ // c8,d8, c9,d9, c10,d10, c11,d11,...c15,d15
+ tmp3 = _mm_unpackhi_epi8(transposed[2], transposed[3]);
+
+ // a0,a8, b0,b8, a1,a9, b1,b9, ....a3,a11, b3,b11
+ transposed[0] = _mm_unpacklo_epi8(tmp0, tmp2);
+ // a4,a12, b4,b12, a5,a13, b5,b13,....a7,a15,b7,b15
+ transposed[1] = _mm_unpackhi_epi8(tmp0, tmp2);
+ // c0,c8, d0,d8, c1,c9, d1,d9.....d3,d11
+ transposed[2] = _mm_unpacklo_epi8(tmp1, tmp3);
+ // c4,c12,d4,d12, c5,c13, d5,d13,....d7,d15
+ transposed[3] = _mm_unpackhi_epi8(tmp1, tmp3);
+
+ // a0,a8, b0,b8, c0,c8, d0,d8, a1,a9, b1,b9, c1,c9, d1,d9
+ tmp0 = _mm_unpacklo_epi32(transposed[0], transposed[2]);
+ // a2,a10, b2,b10, c2,c10, d2,d10, a3,a11, b3,b11, c3,c11, d3,d11
+ tmp1 = _mm_unpackhi_epi32(transposed[0], transposed[2]);
+ // a4,a12, b4,b12, c4,c12, d4,d12, a5,a13, b5,b13, c5,c13, d5,d13
+ tmp2 = _mm_unpacklo_epi32(transposed[1], transposed[3]);
+ // a6,a14, b6,b14, c6,c14, d6,d14, a7,a15, b7,b15, c7,c15, d7,d15
+ tmp3 = _mm_unpackhi_epi32(transposed[1], transposed[3]);
+
+ // a0,a4, a8,a12, b0,b4, b8,b12, c0,c4, c8,c12, d0,d4, d8,d12
+ transposed[0] = _mm_unpacklo_epi8(tmp0, tmp2);
+ // a1,a5, a9,a13, b1,b5, b9,b13, c1,c5, c9,c13, d1,d5, d9,d13
+ transposed[1] = _mm_unpackhi_epi8(tmp0, tmp2);
+ // a2,a6, a10,a14, b2,b6, b10,b14, c2,c6, c10,c14, d2,d6, d10,d14
+ transposed[2] = _mm_unpacklo_epi8(tmp1, tmp3);
+ // a3,a7, a11,a15, b3,b7, b11,b15, c3,c7, c11,c15, d3,d7, d11,d15
+ transposed[3] = _mm_unpackhi_epi8(tmp1, tmp3);
+
+ return true;
+}
+
+inline void UnpackBlock(__m128i* packed,
+ __m128i* red,
+ __m128i* green,
+ __m128i* blue,
+ __m128i* alpha) {
+ const __m128i zero = _mm_set1_epi8(0);
+ __m128i tmp_low, tmp_high;
+
+ // Unpack red.
+ tmp_low = _mm_unpacklo_epi8(packed[0], zero);
+ tmp_high = _mm_unpackhi_epi8(packed[0], zero);
+
+ red[0] = _mm_unpacklo_epi16(tmp_low, zero);
+ red[1] = _mm_unpackhi_epi16(tmp_low, zero);
+
+ red[2] = _mm_unpacklo_epi16(tmp_high, zero);
+ red[3] = _mm_unpackhi_epi16(tmp_high, zero);
+
+ // Unpack green.
+ tmp_low = _mm_unpacklo_epi8(packed[1], zero);
+ tmp_high = _mm_unpackhi_epi8(packed[1], zero);
+
+ green[0] = _mm_unpacklo_epi16(tmp_low, zero);
+ green[1] = _mm_unpackhi_epi16(tmp_low, zero);
+
+ green[2] = _mm_unpacklo_epi16(tmp_high, zero);
+ green[3] = _mm_unpackhi_epi16(tmp_high, zero);
+
+ // Unpack blue.
+ tmp_low = _mm_unpacklo_epi8(packed[2], zero);
+ tmp_high = _mm_unpackhi_epi8(packed[2], zero);
+
+ blue[0] = _mm_unpacklo_epi16(tmp_low, zero);
+ blue[1] = _mm_unpackhi_epi16(tmp_low, zero);
+
+ blue[2] = _mm_unpacklo_epi16(tmp_high, zero);
+ blue[3] = _mm_unpackhi_epi16(tmp_high, zero);
+
+ // Unpack alpha - unused for ETC1.
+ tmp_low = _mm_unpacklo_epi8(packed[3], zero);
+ tmp_high = _mm_unpackhi_epi8(packed[3], zero);
+
+ alpha[0] = _mm_unpacklo_epi16(tmp_low, zero);
+ alpha[1] = _mm_unpackhi_epi16(tmp_low, zero);
+
+ alpha[2] = _mm_unpacklo_epi16(tmp_high, zero);
+ alpha[3] = _mm_unpackhi_epi16(tmp_high, zero);
+}
+
+inline void CompressSolid(uint8_t* dst, uint8_t* block) {
+ // Clear destination buffer so that we can "or" in the results.
+ memset(dst, 0, 8);
+
+ const float src_color_float[3] = {static_cast<float>(block[0]),
+ static_cast<float>(block[1]),
+ static_cast<float>(block[2])};
+ const Color base = MakeColor555(src_color_float);
+ const __m128i base_v =
+ _mm_set_epi32(0, base.channels.r, base.channels.g, base.channels.b);
+
+ const __m128i constant = _mm_set_epi32(0, block[2], block[1], block[0]);
+ __m128i lum;
+ __m128i colors[4];
+ static const __m128i rgb =
+ _mm_set_epi32(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
+
+ WriteDiff(dst, true);
+ WriteFlip(dst, false);
+
+ WriteColors555(dst, base, base);
+
+ uint8_t best_tbl_idx = 0;
+ uint8_t best_mod_idx = 0;
+ uint32_t best_mod_err = INT32_MAX;
+
+ for (unsigned int tbl_idx = 0; tbl_idx < 8; ++tbl_idx) {
+ lum = _mm_set_epi32(
+ g_codeword_tables[tbl_idx][3], g_codeword_tables[tbl_idx][2],
+ g_codeword_tables[tbl_idx][1], g_codeword_tables[tbl_idx][0]);
+ colors[0] = AddAndClamp(base_v, _mm_shuffle_epi32(lum, 0x0));
+ colors[1] = AddAndClamp(base_v, _mm_shuffle_epi32(lum, 0x55));
+ colors[2] = AddAndClamp(base_v, _mm_shuffle_epi32(lum, 0xAA));
+ colors[3] = AddAndClamp(base_v, _mm_shuffle_epi32(lum, 0xFF));
+
+ for (int i = 0; i < 4; i++) {
+ uint32_t mod_err =
+ SumSSE(GetColorErrorSSE(constant, _mm_and_si128(colors[i], rgb)));
+ colors[i] = _mm_and_si128(colors[i], rgb);
+ if (mod_err < best_mod_err) {
+ best_tbl_idx = tbl_idx;
+ best_mod_idx = i;
+ best_mod_err = mod_err;
+
+ if (mod_err == 0) {
+ break; // We cannot do any better than this.
+ }
+ }
+ }
+ }
+
+ WriteCodewordTable(dst, 0, best_tbl_idx);
+ WriteCodewordTable(dst, 1, best_tbl_idx);
+
+ uint8_t pix_idx = g_mod_to_pix[best_mod_idx];
+ uint32_t lsb = pix_idx & 0x1;
+ uint32_t msb = pix_idx >> 1;
+
+ uint32_t pix_data = 0;
+ for (unsigned int i = 0; i < 2; ++i) {
+ for (unsigned int j = 0; j < 8; ++j) {
+ // Obtain the texel number as specified in the standard.
+ int texel_num = g_idx_to_num[i][j];
+ pix_data |= msb << (texel_num + 16);
+ pix_data |= lsb << (texel_num);
+ }
+ }
+
+ WritePixelData(dst, pix_data);
+}
+
+} // namespace
+
+void TextureCompressorETC1SSE::Compress(const uint8_t* src,
+ uint8_t* dst,
+ int width,
+ int height,
+ Quality quality) {
+ DCHECK_GE(width, 4);
+ DCHECK_EQ((width & 3), 0);
+ DCHECK_GE(height, 4);
+ DCHECK_EQ((height & 3), 0);
+
+ ALIGNAS(16) uint8_t block[64];
+ __m128i packed[4];
+ __m128i red[4], green[4], blue[4], alpha[4];
+ __sse_data data;
+
+ for (int y = 0; y < height; y += 4, src += width * 4 * 4) {
+ for (int x = 0; x < width; x += 4, dst += 8) {
+ ExtractBlock(block, src + x * 4, width);
+ if (TransposeBlock(block, packed) == false) {
+ CompressSolid(dst, block);
+ } else {
+ UnpackBlock(packed, blue, green, red, alpha);
+
+ data.block = block;
+ data.packed = packed;
+ data.red = red;
+ data.blue = blue;
+ data.green = green;
+
+ CompressBlock(dst, &data);
+ }
+ }
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/raster/texture_compressor_etc1_sse.h b/chromium/cc/raster/texture_compressor_etc1_sse.h
new file mode 100644
index 00000000000..3822699e4d0
--- /dev/null
+++ b/chromium/cc/raster/texture_compressor_etc1_sse.h
@@ -0,0 +1,31 @@
+// 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_RASTER_TEXTURE_COMPRESSOR_ETC1_SSE_H_
+#define CC_RASTER_TEXTURE_COMPRESSOR_ETC1_SSE_H_
+
+#include "cc/raster/texture_compressor.h"
+
+namespace cc {
+
+class CC_EXPORT TextureCompressorETC1SSE : public TextureCompressor {
+ public:
+ TextureCompressorETC1SSE() {}
+
+ // Compress a texture using ETC1. Note that the |quality| parameter is
+ // ignored. The current implementation does not support different quality
+ // settings.
+ void Compress(const uint8_t* src,
+ uint8_t* dst,
+ int width,
+ int height,
+ Quality quality) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureCompressorETC1SSE);
+};
+
+} // namespace cc
+
+#endif // CC_RASTER_TEXTURE_COMPRESSOR_ETC1_SSE_H_
diff --git a/chromium/cc/raster/texture_compressor_etc1_unittest.cc b/chromium/cc/raster/texture_compressor_etc1_unittest.cc
new file mode 100644
index 00000000000..98ccd77560f
--- /dev/null
+++ b/chromium/cc/raster/texture_compressor_etc1_unittest.cc
@@ -0,0 +1,56 @@
+// 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.
+
+#include "cc/raster/texture_compressor.h"
+
+#include "cc/base/util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+const int kImageWidth = 256;
+const int kImageHeight = 256;
+const int kImageChannels = 4;
+const int kImageSizeInBytes = kImageWidth * kImageHeight * kImageChannels;
+
+TEST(TextureCompressorETC1Test, Compress256x256Ratio) {
+ scoped_ptr<TextureCompressor> compressor =
+ TextureCompressor::Create(TextureCompressor::kFormatETC1);
+ uint8_t src[kImageSizeInBytes];
+ uint8_t dst[kImageSizeInBytes];
+ const unsigned int kImagePoison = 0xDEADBEEF;
+
+ // Poison destination bytes so we can see how much has been
+ // overwritten by compression algorithm.
+ uint32_t* dst_32 = reinterpret_cast<uint32_t*>(dst);
+ for (int i = 0; i < kImageWidth * kImageHeight; i++) {
+ dst_32[i] = kImagePoison;
+ }
+
+ // Generate test texture.
+ for (int i = 0; i < kImageSizeInBytes; i++) {
+ src[i] = i % 256;
+ }
+
+ compressor->Compress(src, dst, kImageWidth, kImageHeight,
+ TextureCompressor::kQualityLow);
+
+ int compressed_size = 0;
+ for (compressed_size = 0; compressed_size < kImageWidth * kImageHeight;
+ compressed_size++) {
+ if (dst_32[compressed_size] == kImagePoison) {
+ // Represents size in bytes of the compressed block.
+ compressed_size = compressed_size * 4;
+ break;
+ }
+ }
+
+ // Check if compression ratio is 8:1 for RGBA or BGRA images, after discarding
+ // alpha channel.
+ EXPECT_EQ(kImageSizeInBytes, compressed_size * 8);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/raster/texture_compressor_perftest.cc b/chromium/cc/raster/texture_compressor_perftest.cc
new file mode 100644
index 00000000000..4b2967c0ba6
--- /dev/null
+++ b/chromium/cc/raster/texture_compressor_perftest.cc
@@ -0,0 +1,121 @@
+// 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.
+
+#include "base/logging.h"
+#include "cc/debug/lap_timer.h"
+#include "cc/raster/texture_compressor.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+namespace {
+
+const int kTimeLimitMillis = 2000;
+const int kWarmupRuns = 5;
+const int kTimeCheckInterval = 10;
+
+const int kImageWidth = 256;
+const int kImageHeight = 256;
+const int kImageChannels = 4;
+const int kImageSizeInBytes = kImageWidth * kImageHeight * kImageChannels;
+
+std::string FormatName(TextureCompressor::Format format) {
+ switch (format) {
+ case TextureCompressor::kFormatETC1:
+ return "ETC1";
+ }
+
+ NOTREACHED();
+ return "";
+}
+
+std::string QualityName(TextureCompressor::Quality quality) {
+ switch (quality) {
+ case TextureCompressor::kQualityLow:
+ return "Low";
+ case TextureCompressor::kQualityMedium:
+ return "Medium";
+ case TextureCompressor::kQualityHigh:
+ return "High";
+ }
+
+ NOTREACHED();
+ return "";
+}
+
+class TextureCompressorPerfTest
+ : public testing::TestWithParam<
+ ::testing::tuple<TextureCompressor::Quality,
+ TextureCompressor::Format>> {
+ public:
+ TextureCompressorPerfTest()
+ : timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval) {}
+
+ void SetUp() override {
+ TextureCompressor::Format format = ::testing::get<1>(GetParam());
+ compressor_ = TextureCompressor::Create(format);
+ }
+
+ void RunTest(const std::string& name) {
+ TextureCompressor::Quality quality = ::testing::get<0>(GetParam());
+ timer_.Reset();
+ do {
+ compressor_->Compress(src_, dst_, kImageWidth, kImageHeight, quality);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ TextureCompressor::Format format = ::testing::get<1>(GetParam());
+ std::string str = FormatName(format) + " " + QualityName(quality);
+ perf_test::PrintResult("Compress256x256", name, str, timer_.MsPerLap(),
+ "us", true);
+ }
+
+ protected:
+ LapTimer timer_;
+ scoped_ptr<TextureCompressor> compressor_;
+ uint8_t src_[kImageSizeInBytes];
+ uint8_t dst_[kImageSizeInBytes];
+};
+
+TEST_P(TextureCompressorPerfTest, Compress256x256BlackAndWhiteGradientImage) {
+ for (int i = 0; i < kImageSizeInBytes; ++i)
+ src_[i] = i % 256;
+
+ RunTest("BlackAndWhiteGradientImage");
+}
+
+TEST_P(TextureCompressorPerfTest, Compress256x256SolidBlackImage) {
+ memset(src_, 0, kImageSizeInBytes);
+
+ RunTest("SolidBlackImage");
+}
+
+TEST_P(TextureCompressorPerfTest, Compress256x256SolidColorImage) {
+ for (int i = 0; i < kImageSizeInBytes; ++i)
+ src_[i] = (4 - i % 4) * 50;
+
+ RunTest("SolidColorImage");
+}
+
+TEST_P(TextureCompressorPerfTest, Compress256x256RandomColorImage) {
+ unsigned int kImageSeed = 1234567890;
+ srand(kImageSeed);
+ for (int i = 0; i < kImageSizeInBytes; ++i)
+ src_[i] = rand() % 256; // NOLINT
+
+ RunTest("RandomColorImage");
+}
+
+INSTANTIATE_TEST_CASE_P(
+ TextureCompressorPerfTests,
+ TextureCompressorPerfTest,
+ ::testing::Combine(::testing::Values(TextureCompressor::kQualityLow,
+ TextureCompressor::kQualityMedium,
+ TextureCompressor::kQualityHigh),
+ ::testing::Values(TextureCompressor::kFormatETC1)));
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/raster/tile_task_runner.cc b/chromium/cc/raster/tile_task_runner.cc
new file mode 100644
index 00000000000..5450c5f777e
--- /dev/null
+++ b/chromium/cc/raster/tile_task_runner.cc
@@ -0,0 +1,100 @@
+// Copyright 2014 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/raster/tile_task_runner.h"
+
+#include <algorithm>
+
+namespace cc {
+
+TileTask::TileTask() : did_schedule_(false), did_complete_(false) {
+}
+
+TileTask::~TileTask() {
+ DCHECK(!did_schedule_);
+ DCHECK(!did_run_ || did_complete_);
+}
+
+ImageDecodeTask* TileTask::AsImageDecodeTask() {
+ return NULL;
+}
+
+RasterTask* TileTask::AsRasterTask() {
+ return NULL;
+}
+
+void TileTask::WillSchedule() {
+ DCHECK(!did_schedule_);
+}
+
+void TileTask::DidSchedule() {
+ did_schedule_ = true;
+ did_complete_ = false;
+}
+
+bool TileTask::HasBeenScheduled() const {
+ return did_schedule_;
+}
+
+void TileTask::WillComplete() {
+ DCHECK(!did_complete_);
+}
+
+void TileTask::DidComplete() {
+ DCHECK(did_schedule_);
+ DCHECK(!did_complete_);
+ did_schedule_ = false;
+ did_complete_ = true;
+}
+
+bool TileTask::HasCompleted() const {
+ return did_complete_;
+}
+
+ImageDecodeTask::ImageDecodeTask() {
+}
+
+ImageDecodeTask::~ImageDecodeTask() {
+}
+
+ImageDecodeTask* ImageDecodeTask::AsImageDecodeTask() {
+ return this;
+}
+
+RasterTask::RasterTask(const Resource* resource,
+ ImageDecodeTask::Vector* dependencies)
+ : resource_(resource) {
+ dependencies_.swap(*dependencies);
+}
+
+RasterTask::~RasterTask() {
+}
+
+RasterTask* RasterTask::AsRasterTask() {
+ return this;
+}
+
+TileTaskQueue::Item::Item(RasterTask* task, const TaskSetCollection& task_sets)
+ : task(task), task_sets(task_sets) {
+ DCHECK(task_sets.any());
+}
+
+TileTaskQueue::Item::~Item() {
+}
+
+TileTaskQueue::TileTaskQueue() {
+}
+
+TileTaskQueue::~TileTaskQueue() {
+}
+
+void TileTaskQueue::Swap(TileTaskQueue* other) {
+ items.swap(other->items);
+}
+
+void TileTaskQueue::Reset() {
+ items.clear();
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/rasterizer.h b/chromium/cc/raster/tile_task_runner.h
index 526058c338d..234ca6f04ab 100644
--- a/chromium/cc/resources/rasterizer.h
+++ b/chromium/cc/raster/tile_task_runner.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_RASTERIZER_H_
-#define CC_RESOURCES_RASTERIZER_H_
+#ifndef CC_RASTER_TILE_TASK_RUNNER_H_
+#define CC_RASTER_TILE_TASK_RUNNER_H_
#include <bitset>
#include <vector>
#include "base/callback.h"
+#include "cc/raster/task_graph_runner.h"
#include "cc/resources/resource_format.h"
-#include "cc/resources/task_graph_runner.h"
namespace cc {
class ImageDecodeTask;
@@ -18,22 +18,22 @@ class RasterTask;
class Resource;
class RasterBuffer;
-class CC_EXPORT RasterizerTaskClient {
+class CC_EXPORT TileTaskClient {
public:
virtual scoped_ptr<RasterBuffer> AcquireBufferForRaster(
const Resource* resource) = 0;
virtual void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) = 0;
protected:
- virtual ~RasterizerTaskClient() {}
+ virtual ~TileTaskClient() {}
};
-class CC_EXPORT RasterizerTask : public Task {
+class CC_EXPORT TileTask : public Task {
public:
- typedef std::vector<scoped_refptr<RasterizerTask>> Vector;
+ typedef std::vector<scoped_refptr<TileTask>> Vector;
- virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) = 0;
- virtual void CompleteOnOriginThread(RasterizerTaskClient* client) = 0;
+ virtual void ScheduleOnOriginThread(TileTaskClient* client) = 0;
+ virtual void CompleteOnOriginThread(TileTaskClient* client) = 0;
virtual void RunReplyOnOriginThread() = 0;
// Type-checking downcast routines.
@@ -49,18 +49,18 @@ class CC_EXPORT RasterizerTask : public Task {
bool HasCompleted() const;
protected:
- RasterizerTask();
- ~RasterizerTask() override;
+ TileTask();
+ ~TileTask() override;
bool did_schedule_;
bool did_complete_;
};
-class CC_EXPORT ImageDecodeTask : public RasterizerTask {
+class CC_EXPORT ImageDecodeTask : public TileTask {
public:
typedef std::vector<scoped_refptr<ImageDecodeTask>> Vector;
- // Overridden from RasterizerTask:
+ // Overridden from TileTask:
ImageDecodeTask* AsImageDecodeTask() override;
protected:
@@ -68,11 +68,11 @@ class CC_EXPORT ImageDecodeTask : public RasterizerTask {
~ImageDecodeTask() override;
};
-class CC_EXPORT RasterTask : public RasterizerTask {
+class CC_EXPORT RasterTask : public TileTask {
public:
typedef std::vector<scoped_refptr<RasterTask>> Vector;
- // Overridden from RasterizerTask:
+ // Overridden from TileTask:
RasterTask* AsRasterTask() override;
const Resource* resource() const { return resource_; }
@@ -87,20 +87,24 @@ class CC_EXPORT RasterTask : public RasterizerTask {
ImageDecodeTask::Vector dependencies_;
};
-static const size_t kNumberOfTaskSets = 2;
+// kNumberOfTaskSets must be greater or equal to the number of values in
+// TileManager::NamedTaskSet.
+// TODO(reveman): Use template specialization to make it easy for client code to
+// check at compile time that the number of supported task sets is correct.
+static const size_t kNumberOfTaskSets = 3;
typedef size_t TaskSet;
typedef std::bitset<kNumberOfTaskSets> TaskSetCollection;
-class CC_EXPORT RasterizerClient {
+class CC_EXPORT TileTaskRunnerClient {
public:
- virtual void DidFinishRunningTasks(TaskSet task_set) = 0;
+ virtual void DidFinishRunningTileTasks(TaskSet task_set) = 0;
virtual TaskSetCollection TasksThatShouldBeForcedToComplete() const = 0;
protected:
- virtual ~RasterizerClient() {}
+ virtual ~TileTaskRunnerClient() {}
};
-struct CC_EXPORT RasterTaskQueue {
+struct CC_EXPORT TileTaskQueue {
struct CC_EXPORT Item {
class TaskComparator {
public:
@@ -121,44 +125,48 @@ struct CC_EXPORT RasterTaskQueue {
TaskSetCollection task_sets;
};
- RasterTaskQueue();
- ~RasterTaskQueue();
+ TileTaskQueue();
+ ~TileTaskQueue();
- void Swap(RasterTaskQueue* other);
+ void Swap(TileTaskQueue* other);
void Reset();
Item::Vector items;
};
-// This interface can be used to schedule and run raster tasks. The client will
+// This interface can be used to schedule and run tile tasks. The client will
// be notified asynchronously when the set of tasks marked as "required for
-// activation" have finished running and when all scheduled tasks have finished
-// running. The client can call CheckForCompletedTasks() at any time to dispatch
+// activation" have finished running, when tasks marked "required for draw"
+// have finished running, and when all scheduled tasks have finished running.
+// The client can call CheckForCompletedTasks() at any time to dispatch
// pending completion callbacks for all tasks that have finished running.
-class CC_EXPORT Rasterizer {
+class CC_EXPORT TileTaskRunner {
public:
// Set the client instance to be notified when finished running tasks.
- virtual void SetClient(RasterizerClient* client) = 0;
+ virtual void SetClient(TileTaskRunnerClient* client) = 0;
// Tells the worker pool to shutdown after canceling all previously scheduled
// tasks. Reply callbacks are still guaranteed to run when
// CheckForCompletedTasks() is called.
virtual void Shutdown() = 0;
- // Schedule running of raster tasks in |queue| and all dependencies.
+ // Schedule running of tile tasks in |queue| and all dependencies.
// Previously scheduled tasks that are not in |queue| will be canceled unless
// already running. Once scheduled, reply callbacks are guaranteed to run for
// all tasks even if they later get canceled by another call to
// ScheduleTasks().
- virtual void ScheduleTasks(RasterTaskQueue* queue) = 0;
+ virtual void ScheduleTasks(TileTaskQueue* queue) = 0;
// Check for completed tasks and dispatch reply callbacks.
virtual void CheckForCompletedTasks() = 0;
+ // Returns the format to use for the tiles.
+ virtual ResourceFormat GetResourceFormat() = 0;
+
protected:
- virtual ~Rasterizer() {}
+ virtual ~TileTaskRunner() {}
};
} // namespace cc
-#endif // CC_RESOURCES_RASTERIZER_H_
+#endif // CC_RASTER_TILE_TASK_RUNNER_H_
diff --git a/chromium/cc/raster/tile_task_worker_pool.cc b/chromium/cc/raster/tile_task_worker_pool.cc
new file mode 100644
index 00000000000..477acc31263
--- /dev/null
+++ b/chromium/cc/raster/tile_task_worker_pool.cc
@@ -0,0 +1,207 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/raster/tile_task_worker_pool.h"
+
+#include <algorithm>
+
+#include "base/trace_event/trace_event.h"
+#include "cc/playback/raster_source.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+
+namespace cc {
+namespace {
+
+class TaskSetFinishedTaskImpl : public TileTask {
+ public:
+ explicit TaskSetFinishedTaskImpl(
+ base::SequencedTaskRunner* task_runner,
+ const base::Closure& on_task_set_finished_callback)
+ : task_runner_(task_runner),
+ on_task_set_finished_callback_(on_task_set_finished_callback) {}
+
+ // Overridden from Task:
+ void RunOnWorkerThread() override {
+ TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread");
+ TaskSetFinished();
+ }
+
+ // Overridden from TileTask:
+ void ScheduleOnOriginThread(TileTaskClient* client) override {}
+ void CompleteOnOriginThread(TileTaskClient* client) override {}
+ void RunReplyOnOriginThread() override {}
+
+ protected:
+ ~TaskSetFinishedTaskImpl() override {}
+
+ void TaskSetFinished() {
+ task_runner_->PostTask(FROM_HERE, on_task_set_finished_callback_);
+ }
+
+ private:
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ const base::Closure on_task_set_finished_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskSetFinishedTaskImpl);
+};
+
+} // namespace
+
+// This allows a micro benchmark system to run tasks with highest priority,
+// since it should finish as quickly as possible.
+unsigned TileTaskWorkerPool::kBenchmarkTaskPriority = 0u;
+// Task priorities that make sure task set finished tasks run before any
+// other remaining tasks. This is combined with the task set type to ensure
+// proper prioritization ordering between task set types.
+unsigned TileTaskWorkerPool::kTaskSetFinishedTaskPriorityBase = 1u;
+// For correctness, |kTileTaskPriorityBase| must be greater than
+// |kTaskSetFinishedTaskPriorityBase + kNumberOfTaskSets|.
+unsigned TileTaskWorkerPool::kTileTaskPriorityBase = 10u;
+
+TileTaskWorkerPool::TileTaskWorkerPool() {
+}
+
+TileTaskWorkerPool::~TileTaskWorkerPool() {
+}
+
+// static
+scoped_refptr<TileTask> TileTaskWorkerPool::CreateTaskSetFinishedTask(
+ base::SequencedTaskRunner* task_runner,
+ const base::Closure& on_task_set_finished_callback) {
+ return make_scoped_refptr(
+ new TaskSetFinishedTaskImpl(task_runner, on_task_set_finished_callback));
+}
+
+// static
+void TileTaskWorkerPool::ScheduleTasksOnOriginThread(TileTaskClient* client,
+ TaskGraph* graph) {
+ TRACE_EVENT0("cc", "TileTaskWorkerPool::ScheduleTasksOnOriginThread");
+
+ for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
+ it != graph->nodes.end(); ++it) {
+ TaskGraph::Node& node = *it;
+ TileTask* task = static_cast<TileTask*>(node.task);
+
+ if (!task->HasBeenScheduled()) {
+ task->WillSchedule();
+ task->ScheduleOnOriginThread(client);
+ task->DidSchedule();
+ }
+ }
+}
+
+// static
+void TileTaskWorkerPool::InsertNodeForTask(TaskGraph* graph,
+ TileTask* task,
+ unsigned priority,
+ size_t dependencies) {
+ DCHECK(std::find_if(graph->nodes.begin(), graph->nodes.end(),
+ TaskGraph::Node::TaskComparator(task)) ==
+ graph->nodes.end());
+ graph->nodes.push_back(TaskGraph::Node(task, priority, dependencies));
+}
+
+// static
+void TileTaskWorkerPool::InsertNodesForRasterTask(
+ TaskGraph* graph,
+ RasterTask* raster_task,
+ const ImageDecodeTask::Vector& decode_tasks,
+ unsigned priority) {
+ size_t dependencies = 0u;
+
+ // Insert image decode tasks.
+ for (ImageDecodeTask::Vector::const_iterator it = decode_tasks.begin();
+ it != decode_tasks.end(); ++it) {
+ ImageDecodeTask* decode_task = it->get();
+
+ // Skip if already decoded.
+ if (decode_task->HasCompleted())
+ continue;
+
+ dependencies++;
+
+ // Add decode task if it doesn't already exists in graph.
+ TaskGraph::Node::Vector::iterator decode_it =
+ std::find_if(graph->nodes.begin(), graph->nodes.end(),
+ TaskGraph::Node::TaskComparator(decode_task));
+ if (decode_it == graph->nodes.end())
+ InsertNodeForTask(graph, decode_task, priority, 0u);
+
+ graph->edges.push_back(TaskGraph::Edge(decode_task, raster_task));
+ }
+
+ InsertNodeForTask(graph, raster_task, priority, dependencies);
+}
+
+static bool IsSupportedPlaybackToMemoryFormat(ResourceFormat format) {
+ switch (format) {
+ case RGBA_4444:
+ case RGBA_8888:
+ case BGRA_8888:
+ return true;
+ case ALPHA_8:
+ case LUMINANCE_8:
+ case RGB_565:
+ case ETC1:
+ case RED_8:
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
+
+// static
+void TileTaskWorkerPool::PlaybackToMemory(void* memory,
+ ResourceFormat format,
+ const gfx::Size& size,
+ int stride,
+ const RasterSource* raster_source,
+ const gfx::Rect& rect,
+ float scale) {
+ DCHECK(IsSupportedPlaybackToMemoryFormat(format)) << format;
+
+ // Uses kPremul_SkAlphaType since the result is not known to be opaque.
+ SkImageInfo info =
+ SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType);
+ SkColorType buffer_color_type = ResourceFormatToSkColorType(format);
+ bool needs_copy = buffer_color_type != info.colorType();
+
+ // Use unknown pixel geometry to disable LCD text.
+ SkSurfaceProps surface_props(0, kUnknown_SkPixelGeometry);
+ if (raster_source->CanUseLCDText()) {
+ // LegacyFontHost will get LCD text and skia figures out what type to use.
+ surface_props = SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
+ }
+
+ if (!stride)
+ stride = info.minRowBytes();
+ DCHECK_GT(stride, 0);
+
+ if (!needs_copy) {
+ skia::RefPtr<SkSurface> surface = skia::AdoptRef(
+ SkSurface::NewRasterDirect(info, memory, stride, &surface_props));
+ skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas());
+ raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
+ return;
+ }
+
+ skia::RefPtr<SkSurface> surface =
+ skia::AdoptRef(SkSurface::NewRaster(info, &surface_props));
+ skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas());
+ raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
+
+ SkImageInfo dst_info = info;
+ dst_info.fColorType = buffer_color_type;
+ // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
+ // bitmap data. There will be no need to call SkAlign4 once crbug.com/293728
+ // is fixed.
+ const size_t dst_row_bytes = SkAlign4(dst_info.minRowBytes());
+ DCHECK_EQ(0u, dst_row_bytes % 4);
+ bool success = canvas->readPixels(dst_info, memory, dst_row_bytes, 0, 0);
+ DCHECK_EQ(true, success);
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/raster_worker_pool.h b/chromium/cc/raster/tile_task_worker_pool.h
index 5259f835492..75916f5dd6f 100644
--- a/chromium/cc/resources/raster_worker_pool.h
+++ b/chromium/cc/raster/tile_task_worker_pool.h
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_RASTER_WORKER_POOL_H_
-#define CC_RESOURCES_RASTER_WORKER_POOL_H_
+#ifndef CC_RASTER_TILE_TASK_WORKER_POOL_H_
+#define CC_RASTER_TILE_TASK_WORKER_POOL_H_
-#include "cc/resources/rasterizer.h"
+#include "cc/raster/tile_task_runner.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -17,42 +17,31 @@ namespace cc {
class RasterSource;
class RenderingStatsInstrumentation;
-class CC_EXPORT RasterWorkerPool {
+class CC_EXPORT TileTaskWorkerPool {
public:
- static unsigned kBenchmarkRasterTaskPriority;
- static unsigned kRasterFinishedTaskPriority;
- static unsigned kRasterTaskPriorityBase;
+ static unsigned kBenchmarkTaskPriority;
+ static unsigned kTaskSetFinishedTaskPriorityBase;
+ static unsigned kTileTaskPriorityBase;
- RasterWorkerPool();
- virtual ~RasterWorkerPool();
+ TileTaskWorkerPool();
+ virtual ~TileTaskWorkerPool();
- // Set the number of threads to use for the global TaskGraphRunner instance.
- // This can only be called once and must be called prior to
- // GetNumRasterThreads().
- static void SetNumRasterThreads(int num_threads);
-
- // Returns the number of threads used for the global TaskGraphRunner instance.
- static int GetNumRasterThreads();
-
- // Returns a pointer to the global TaskGraphRunner instance.
- static TaskGraphRunner* GetTaskGraphRunner();
-
- // Utility function that can be used to create a "raster finished" task that
+ // Utility function that can be used to create a "Task set finished" task that
// posts |callback| to |task_runner| when run.
- static scoped_refptr<RasterizerTask> CreateRasterFinishedTask(
+ static scoped_refptr<TileTask> CreateTaskSetFinishedTask(
base::SequencedTaskRunner* task_runner,
const base::Closure& callback);
// Utility function that can be used to call ::ScheduleOnOriginThread() for
// each task in |graph|.
- static void ScheduleTasksOnOriginThread(RasterizerTaskClient* client,
+ static void ScheduleTasksOnOriginThread(TileTaskClient* client,
TaskGraph* graph);
// Utility function that can be used to build a task graph. Inserts a node
// that represents |task| in |graph|. See TaskGraph definition for valid
// |priority| values.
static void InsertNodeForTask(TaskGraph* graph,
- RasterizerTask* task,
+ TileTask* task,
unsigned priority,
size_t dependencies);
@@ -75,9 +64,9 @@ class CC_EXPORT RasterWorkerPool {
float scale);
// Type-checking downcast routine.
- virtual Rasterizer* AsRasterizer() = 0;
+ virtual TileTaskRunner* AsTileTaskRunner() = 0;
};
} // namespace cc
-#endif // CC_RESOURCES_RASTER_WORKER_POOL_H_
+#endif // CC_RASTER_TILE_TASK_WORKER_POOL_H_
diff --git a/chromium/cc/resources/raster_worker_pool_perftest.cc b/chromium/cc/raster/tile_task_worker_pool_perftest.cc
index 0f7a845e8a0..508f966eeb7 100644
--- a/chromium/cc/resources/raster_worker_pool_perftest.cc
+++ b/chromium/cc/raster/tile_task_worker_pool_perftest.cc
@@ -2,22 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/raster_worker_pool.h"
+#include "cc/raster/tile_task_worker_pool.h"
#include "base/test/test_simple_task_runner.h"
#include "base/time/time.h"
#include "cc/debug/lap_timer.h"
#include "cc/output/context_provider.h"
-#include "cc/resources/bitmap_raster_worker_pool.h"
-#include "cc/resources/gpu_raster_worker_pool.h"
-#include "cc/resources/one_copy_raster_worker_pool.h"
-#include "cc/resources/pixel_buffer_raster_worker_pool.h"
-#include "cc/resources/raster_buffer.h"
-#include "cc/resources/rasterizer.h"
+#include "cc/raster/bitmap_tile_task_worker_pool.h"
+#include "cc/raster/gpu_rasterizer.h"
+#include "cc/raster/gpu_tile_task_worker_pool.h"
+#include "cc/raster/one_copy_tile_task_worker_pool.h"
+#include "cc/raster/pixel_buffer_tile_task_worker_pool.h"
+#include "cc/raster/raster_buffer.h"
+#include "cc/raster/tile_task_runner.h"
+#include "cc/raster/zero_copy_tile_task_worker_pool.h"
#include "cc/resources/resource_pool.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/scoped_resource.h"
-#include "cc/resources/zero_copy_raster_worker_pool.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/test_context_support.h"
@@ -27,6 +28,8 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
namespace cc {
namespace {
@@ -77,8 +80,22 @@ class PerfContextProvider : public ContextProvider {
gpu::gles2::GLES2Interface* ContextGL() override { return context_gl_.get(); }
gpu::ContextSupport* ContextSupport() override { return &support_; }
class GrContext* GrContext() override {
- return NULL;
+ if (gr_context_)
+ return gr_context_.get();
+
+ skia::RefPtr<const GrGLInterface> null_interface =
+ skia::AdoptRef(GrGLCreateNullInterface());
+ gr_context_ = skia::AdoptRef(GrContext::Create(
+ kOpenGL_GrBackend,
+ reinterpret_cast<GrBackendContext>(null_interface.get())));
+ return gr_context_.get();
}
+ void InvalidateGrContext(uint32_t state) override {
+ if (gr_context_)
+ gr_context_.get()->resetContext(state);
+ }
+ void SetupLock() override {}
+ base::Lock* GetLock() override { return &context_lock_; }
bool IsContextLost() override { return false; }
void VerifyContexts() override {}
void DeleteCachedResources() override {}
@@ -91,15 +108,17 @@ class PerfContextProvider : public ContextProvider {
~PerfContextProvider() override {}
scoped_ptr<PerfGLES2Interface> context_gl_;
+ skia::RefPtr<class GrContext> gr_context_;
TestContextSupport support_;
+ base::Lock context_lock_;
};
-enum RasterWorkerPoolType {
- RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
- RASTER_WORKER_POOL_TYPE_ZERO_COPY,
- RASTER_WORKER_POOL_TYPE_ONE_COPY,
- RASTER_WORKER_POOL_TYPE_GPU,
- RASTER_WORKER_POOL_TYPE_BITMAP
+enum TileTaskWorkerPoolType {
+ TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER,
+ TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY,
+ TILE_TASK_WORKER_POOL_TYPE_ONE_COPY,
+ TILE_TASK_WORKER_POOL_TYPE_GPU,
+ TILE_TASK_WORKER_POOL_TYPE_BITMAP
};
static const int kTimeLimitMillis = 2000;
@@ -113,9 +132,9 @@ class PerfImageDecodeTaskImpl : public ImageDecodeTask {
// Overridden from Task:
void RunOnWorkerThread() override {}
- // Overridden from RasterizerTask:
- void ScheduleOnOriginThread(RasterizerTaskClient* client) override {}
- void CompleteOnOriginThread(RasterizerTaskClient* client) override {}
+ // Overridden from TileTask:
+ void ScheduleOnOriginThread(TileTaskClient* client) override {}
+ void CompleteOnOriginThread(TileTaskClient* client) override {}
void RunReplyOnOriginThread() override { Reset(); }
void Reset() {
@@ -139,11 +158,11 @@ class PerfRasterTaskImpl : public RasterTask {
// Overridden from Task:
void RunOnWorkerThread() override {}
- // Overridden from RasterizerTask:
- void ScheduleOnOriginThread(RasterizerTaskClient* client) override {
+ // Overridden from TileTask:
+ void ScheduleOnOriginThread(TileTaskClient* client) override {
raster_buffer_ = client->AcquireBufferForRaster(resource());
}
- void CompleteOnOriginThread(RasterizerTaskClient* client) override {
+ void CompleteOnOriginThread(TileTaskClient* client) override {
client->ReleaseBufferForRaster(raster_buffer_.Pass());
}
void RunReplyOnOriginThread() override { Reset(); }
@@ -163,13 +182,13 @@ class PerfRasterTaskImpl : public RasterTask {
DISALLOW_COPY_AND_ASSIGN(PerfRasterTaskImpl);
};
-class RasterWorkerPoolPerfTestBase {
+class TileTaskWorkerPoolPerfTestBase {
public:
typedef std::vector<scoped_refptr<RasterTask>> RasterTaskVector;
- enum NamedTaskSet { REQUIRED_FOR_ACTIVATION = 0, ALL = 1 };
+ enum NamedTaskSet { REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW, ALL };
- RasterWorkerPoolPerfTestBase()
+ TileTaskWorkerPoolPerfTestBase()
: context_provider_(make_scoped_refptr(new PerfContextProvider)),
task_runner_(new base::TestSimpleTaskRunner),
task_graph_runner_(new TaskGraphRunner),
@@ -191,8 +210,8 @@ class RasterWorkerPoolPerfTestBase {
for (unsigned i = 0; i < num_raster_tasks; ++i) {
scoped_ptr<ScopedResource> resource(
ScopedResource::Create(resource_provider_.get()));
- resource->Allocate(
- size, ResourceProvider::TextureHintImmutable, RGBA_8888);
+ resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
ImageDecodeTask::Vector dependencies = image_decode_tasks;
raster_tasks->push_back(
@@ -200,15 +219,15 @@ class RasterWorkerPoolPerfTestBase {
}
}
- void BuildRasterTaskQueue(RasterTaskQueue* queue,
- const RasterTaskVector& raster_tasks) {
+ void BuildTileTaskQueue(TileTaskQueue* queue,
+ const RasterTaskVector& raster_tasks) {
for (size_t i = 0u; i < raster_tasks.size(); ++i) {
bool required_for_activation = (i % 2) == 0;
TaskSetCollection task_set_collection;
task_set_collection[ALL] = true;
task_set_collection[REQUIRED_FOR_ACTIVATION] = required_for_activation;
queue->items.push_back(
- RasterTaskQueue::Item(raster_tasks[i].get(), task_set_collection));
+ TileTaskQueue::Item(raster_tasks[i].get(), task_set_collection));
}
}
@@ -222,69 +241,61 @@ class RasterWorkerPoolPerfTestBase {
LapTimer timer_;
};
-class RasterWorkerPoolPerfTest
- : public RasterWorkerPoolPerfTestBase,
- public testing::TestWithParam<RasterWorkerPoolType>,
- public RasterizerClient {
+class TileTaskWorkerPoolPerfTest
+ : public TileTaskWorkerPoolPerfTestBase,
+ public testing::TestWithParam<TileTaskWorkerPoolType>,
+ public TileTaskRunnerClient {
public:
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
switch (GetParam()) {
- case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
+ case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER:
Create3dOutputSurfaceAndResourceProvider();
- raster_worker_pool_ = PixelBufferRasterWorkerPool::Create(
- task_runner_.get(),
- task_graph_runner_.get(),
- context_provider_.get(),
- resource_provider_.get(),
+ tile_task_worker_pool_ = PixelBufferTileTaskWorkerPool::Create(
+ task_runner_.get(), task_graph_runner_.get(),
+ context_provider_.get(), resource_provider_.get(),
std::numeric_limits<size_t>::max());
break;
- case RASTER_WORKER_POOL_TYPE_ZERO_COPY:
+ case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY:
Create3dOutputSurfaceAndResourceProvider();
- raster_worker_pool_ =
- ZeroCopyRasterWorkerPool::Create(task_runner_.get(),
- task_graph_runner_.get(),
- resource_provider_.get());
+ tile_task_worker_pool_ = ZeroCopyTileTaskWorkerPool::Create(
+ task_runner_.get(), task_graph_runner_.get(),
+ resource_provider_.get());
break;
- case RASTER_WORKER_POOL_TYPE_ONE_COPY:
+ case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY:
Create3dOutputSurfaceAndResourceProvider();
- staging_resource_pool_ = ResourcePool::Create(
- resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888);
- raster_worker_pool_ =
- OneCopyRasterWorkerPool::Create(task_runner_.get(),
- task_graph_runner_.get(),
- context_provider_.get(),
- resource_provider_.get(),
- staging_resource_pool_.get());
+ staging_resource_pool_ = ResourcePool::Create(resource_provider_.get(),
+ GL_TEXTURE_2D);
+ tile_task_worker_pool_ = OneCopyTileTaskWorkerPool::Create(
+ task_runner_.get(), task_graph_runner_.get(),
+ context_provider_.get(), resource_provider_.get(),
+ staging_resource_pool_.get());
break;
- case RASTER_WORKER_POOL_TYPE_GPU:
+ case TILE_TASK_WORKER_POOL_TYPE_GPU:
Create3dOutputSurfaceAndResourceProvider();
- raster_worker_pool_ =
- GpuRasterWorkerPool::Create(task_runner_.get(),
- context_provider_.get(),
- resource_provider_.get(),
- false);
+ tile_task_worker_pool_ = GpuTileTaskWorkerPool::Create(
+ task_runner_.get(), task_graph_runner_.get(),
+ context_provider_.get(), resource_provider_.get(), false, 0);
break;
- case RASTER_WORKER_POOL_TYPE_BITMAP:
+ case TILE_TASK_WORKER_POOL_TYPE_BITMAP:
CreateSoftwareOutputSurfaceAndResourceProvider();
- raster_worker_pool_ =
- BitmapRasterWorkerPool::Create(task_runner_.get(),
- task_graph_runner_.get(),
- resource_provider_.get());
+ tile_task_worker_pool_ = BitmapTileTaskWorkerPool::Create(
+ task_runner_.get(), task_graph_runner_.get(),
+ resource_provider_.get());
break;
}
- DCHECK(raster_worker_pool_);
- raster_worker_pool_->AsRasterizer()->SetClient(this);
+ DCHECK(tile_task_worker_pool_);
+ tile_task_worker_pool_->AsTileTaskRunner()->SetClient(this);
}
- virtual void TearDown() override {
- raster_worker_pool_->AsRasterizer()->Shutdown();
- raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ void TearDown() override {
+ tile_task_worker_pool_->AsTileTaskRunner()->Shutdown();
+ tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks();
}
- // Overriden from RasterizerClient:
- void DidFinishRunningTasks(TaskSet task_set) override {
- raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ // Overriden from TileTaskRunnerClient:
+ void DidFinishRunningTileTasks(TaskSet task_set) override {
+ tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks();
}
TaskSetCollection TasksThatShouldBeForcedToComplete() const override {
return TaskSetCollection();
@@ -304,27 +315,23 @@ class RasterWorkerPoolPerfTest
CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks);
// Avoid unnecessary heap allocations by reusing the same queue.
- RasterTaskQueue queue;
+ TileTaskQueue queue;
timer_.Reset();
do {
queue.Reset();
- BuildRasterTaskQueue(&queue, raster_tasks);
- raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
- raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ BuildTileTaskQueue(&queue, raster_tasks);
+ tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&queue);
+ tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks();
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
- RasterTaskQueue empty;
- raster_worker_pool_->AsRasterizer()->ScheduleTasks(&empty);
+ TileTaskQueue empty;
+ tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&empty);
RunMessageLoopUntilAllTasksHaveCompleted();
- perf_test::PrintResult("schedule_tasks",
- TestModifierString(),
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
+ perf_test::PrintResult("schedule_tasks", TestModifierString(), test_name,
+ timer_.LapsPerSecond(), "runs/s", true);
}
void RunScheduleAlternateTasksTest(const std::string& test_name,
@@ -335,34 +342,30 @@ class RasterWorkerPoolPerfTest
RasterTaskVector raster_tasks[kNumVersions];
for (size_t i = 0; i < kNumVersions; ++i) {
CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks[i]);
- CreateRasterTasks(
- num_raster_tasks, image_decode_tasks[i], &raster_tasks[i]);
+ CreateRasterTasks(num_raster_tasks, image_decode_tasks[i],
+ &raster_tasks[i]);
}
// Avoid unnecessary heap allocations by reusing the same queue.
- RasterTaskQueue queue;
+ TileTaskQueue queue;
size_t count = 0;
timer_.Reset();
do {
queue.Reset();
- BuildRasterTaskQueue(&queue, raster_tasks[count % kNumVersions]);
- raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
- raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ BuildTileTaskQueue(&queue, raster_tasks[count % kNumVersions]);
+ tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&queue);
+ tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks();
++count;
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
- RasterTaskQueue empty;
- raster_worker_pool_->AsRasterizer()->ScheduleTasks(&empty);
+ TileTaskQueue empty;
+ tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&empty);
RunMessageLoopUntilAllTasksHaveCompleted();
- perf_test::PrintResult("schedule_alternate_tasks",
- TestModifierString(),
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
+ perf_test::PrintResult("schedule_alternate_tasks", TestModifierString(),
+ test_name, timer_.LapsPerSecond(), "runs/s", true);
}
void RunScheduleAndExecuteTasksTest(const std::string& test_name,
@@ -374,79 +377,67 @@ class RasterWorkerPoolPerfTest
CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks);
// Avoid unnecessary heap allocations by reusing the same queue.
- RasterTaskQueue queue;
+ TileTaskQueue queue;
timer_.Reset();
do {
queue.Reset();
- BuildRasterTaskQueue(&queue, raster_tasks);
- raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
+ BuildTileTaskQueue(&queue, raster_tasks);
+ tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&queue);
RunMessageLoopUntilAllTasksHaveCompleted();
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
- RasterTaskQueue empty;
- raster_worker_pool_->AsRasterizer()->ScheduleTasks(&empty);
+ TileTaskQueue empty;
+ tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&empty);
RunMessageLoopUntilAllTasksHaveCompleted();
- perf_test::PrintResult("schedule_and_execute_tasks",
- TestModifierString(),
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
+ perf_test::PrintResult("schedule_and_execute_tasks", TestModifierString(),
+ test_name, timer_.LapsPerSecond(), "runs/s", true);
}
private:
void Create3dOutputSurfaceAndResourceProvider() {
output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ = ResourceProvider::Create(output_surface_.get(),
- NULL,
+ resource_provider_ = ResourceProvider::Create(output_surface_.get(), NULL,
&gpu_memory_buffer_manager_,
- NULL,
- 0,
- false,
- 1).Pass();
+ NULL, 0, false, 1).Pass();
}
void CreateSoftwareOutputSurfaceAndResourceProvider() {
output_surface_ = FakeOutputSurface::CreateSoftware(
make_scoped_ptr(new SoftwareOutputDevice));
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ = ResourceProvider::Create(output_surface_.get(),
- &shared_bitmap_manager_,
- NULL,
- NULL,
- 0,
- false,
- 1).Pass();
+ resource_provider_ =
+ ResourceProvider::Create(output_surface_.get(), &shared_bitmap_manager_,
+ NULL, NULL, 0, false, 1).Pass();
}
std::string TestModifierString() const {
switch (GetParam()) {
- case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
- return std::string("_pixel_raster_worker_pool");
- case RASTER_WORKER_POOL_TYPE_ZERO_COPY:
- return std::string("_zero_copy_raster_worker_pool");
- case RASTER_WORKER_POOL_TYPE_ONE_COPY:
- return std::string("_one_copy_raster_worker_pool");
- case RASTER_WORKER_POOL_TYPE_GPU:
- return std::string("_gpu_raster_worker_pool");
- case RASTER_WORKER_POOL_TYPE_BITMAP:
- return std::string("_bitmap_raster_worker_pool");
+ case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER:
+ return std::string("_pixel_tile_task_worker_pool");
+ case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY:
+ return std::string("_zero_copy_tile_task_worker_pool");
+ case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY:
+ return std::string("_one_copy_tile_task_worker_pool");
+ case TILE_TASK_WORKER_POOL_TYPE_GPU:
+ return std::string("_gpu_tile_task_worker_pool");
+ case TILE_TASK_WORKER_POOL_TYPE_BITMAP:
+ return std::string("_bitmap_tile_task_worker_pool");
}
NOTREACHED();
return std::string();
}
scoped_ptr<ResourcePool> staging_resource_pool_;
- scoped_ptr<RasterWorkerPool> raster_worker_pool_;
+ scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_;
TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
TestSharedBitmapManager shared_bitmap_manager_;
};
-TEST_P(RasterWorkerPoolPerfTest, ScheduleTasks) {
+TEST_P(TileTaskWorkerPoolPerfTest, ScheduleTasks) {
RunScheduleTasksTest("1_0", 1, 0);
RunScheduleTasksTest("32_0", 32, 0);
RunScheduleTasksTest("1_1", 1, 1);
@@ -455,7 +446,7 @@ TEST_P(RasterWorkerPoolPerfTest, ScheduleTasks) {
RunScheduleTasksTest("32_4", 32, 4);
}
-TEST_P(RasterWorkerPoolPerfTest, ScheduleAlternateTasks) {
+TEST_P(TileTaskWorkerPoolPerfTest, ScheduleAlternateTasks) {
RunScheduleAlternateTasksTest("1_0", 1, 0);
RunScheduleAlternateTasksTest("32_0", 32, 0);
RunScheduleAlternateTasksTest("1_1", 1, 1);
@@ -464,7 +455,7 @@ TEST_P(RasterWorkerPoolPerfTest, ScheduleAlternateTasks) {
RunScheduleAlternateTasksTest("32_4", 32, 4);
}
-TEST_P(RasterWorkerPoolPerfTest, ScheduleAndExecuteTasks) {
+TEST_P(TileTaskWorkerPoolPerfTest, ScheduleAndExecuteTasks) {
RunScheduleAndExecuteTasksTest("1_0", 1, 0);
RunScheduleAndExecuteTasksTest("32_0", 32, 0);
RunScheduleAndExecuteTasksTest("1_1", 1, 1);
@@ -473,60 +464,57 @@ TEST_P(RasterWorkerPoolPerfTest, ScheduleAndExecuteTasks) {
RunScheduleAndExecuteTasksTest("32_4", 32, 4);
}
-INSTANTIATE_TEST_CASE_P(RasterWorkerPoolPerfTests,
- RasterWorkerPoolPerfTest,
- ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
- RASTER_WORKER_POOL_TYPE_ZERO_COPY,
- RASTER_WORKER_POOL_TYPE_ONE_COPY,
- RASTER_WORKER_POOL_TYPE_GPU,
- RASTER_WORKER_POOL_TYPE_BITMAP));
-
-class RasterWorkerPoolCommonPerfTest : public RasterWorkerPoolPerfTestBase,
- public testing::Test {
+INSTANTIATE_TEST_CASE_P(
+ TileTaskWorkerPoolPerfTests,
+ TileTaskWorkerPoolPerfTest,
+ ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER,
+ TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY,
+ TILE_TASK_WORKER_POOL_TYPE_ONE_COPY,
+ TILE_TASK_WORKER_POOL_TYPE_GPU,
+ TILE_TASK_WORKER_POOL_TYPE_BITMAP));
+
+class TileTaskWorkerPoolCommonPerfTest : public TileTaskWorkerPoolPerfTestBase,
+ public testing::Test {
public:
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
CHECK(output_surface_->BindToClient(&output_surface_client_));
resource_provider_ =
- ResourceProvider::Create(
- output_surface_.get(), NULL, NULL, NULL, 0, false, 1).Pass();
+ ResourceProvider::Create(output_surface_.get(), NULL, NULL, NULL, 0,
+ false, 1).Pass();
}
- void RunBuildRasterTaskQueueTest(const std::string& test_name,
- unsigned num_raster_tasks,
- unsigned num_image_decode_tasks) {
+ void RunBuildTileTaskQueueTest(const std::string& test_name,
+ unsigned num_raster_tasks,
+ unsigned num_image_decode_tasks) {
ImageDecodeTask::Vector image_decode_tasks;
RasterTaskVector raster_tasks;
CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks);
// Avoid unnecessary heap allocations by reusing the same queue.
- RasterTaskQueue queue;
+ TileTaskQueue queue;
timer_.Reset();
do {
queue.Reset();
- BuildRasterTaskQueue(&queue, raster_tasks);
+ BuildTileTaskQueue(&queue, raster_tasks);
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
- perf_test::PrintResult("build_raster_task_queue",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
+ perf_test::PrintResult("build_raster_task_queue", "", test_name,
+ timer_.LapsPerSecond(), "runs/s", true);
}
};
-TEST_F(RasterWorkerPoolCommonPerfTest, BuildRasterTaskQueue) {
- RunBuildRasterTaskQueueTest("1_0", 1, 0);
- RunBuildRasterTaskQueueTest("32_0", 32, 0);
- RunBuildRasterTaskQueueTest("1_1", 1, 1);
- RunBuildRasterTaskQueueTest("32_1", 32, 1);
- RunBuildRasterTaskQueueTest("1_4", 1, 4);
- RunBuildRasterTaskQueueTest("32_4", 32, 4);
+TEST_F(TileTaskWorkerPoolCommonPerfTest, BuildTileTaskQueue) {
+ RunBuildTileTaskQueueTest("1_0", 1, 0);
+ RunBuildTileTaskQueueTest("32_0", 32, 0);
+ RunBuildTileTaskQueueTest("1_1", 1, 1);
+ RunBuildTileTaskQueueTest("32_1", 32, 1);
+ RunBuildTileTaskQueueTest("1_4", 1, 4);
+ RunBuildTileTaskQueueTest("32_4", 32, 4);
}
} // namespace
diff --git a/chromium/cc/resources/raster_worker_pool_unittest.cc b/chromium/cc/raster/tile_task_worker_pool_unittest.cc
index 9aee8e7bc74..7394af59a90 100644
--- a/chromium/cc/resources/raster_worker_pool_unittest.cc
+++ b/chromium/cc/raster/tile_task_worker_pool_unittest.cc
@@ -2,30 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/raster_worker_pool.h"
+#include "cc/raster/tile_task_worker_pool.h"
#include <limits>
#include <vector>
#include "base/cancelable_callback.h"
-#include "cc/resources/bitmap_raster_worker_pool.h"
-#include "cc/resources/gpu_raster_worker_pool.h"
-#include "cc/resources/one_copy_raster_worker_pool.h"
-#include "cc/resources/picture_pile.h"
-#include "cc/resources/picture_pile_impl.h"
-#include "cc/resources/pixel_buffer_raster_worker_pool.h"
-#include "cc/resources/raster_buffer.h"
-#include "cc/resources/rasterizer.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "cc/base/unique_notifier.h"
+#include "cc/playback/picture_pile.h"
+#include "cc/playback/picture_pile_impl.h"
+#include "cc/raster/bitmap_tile_task_worker_pool.h"
+#include "cc/raster/gpu_rasterizer.h"
+#include "cc/raster/gpu_tile_task_worker_pool.h"
+#include "cc/raster/one_copy_tile_task_worker_pool.h"
+#include "cc/raster/pixel_buffer_tile_task_worker_pool.h"
+#include "cc/raster/raster_buffer.h"
+#include "cc/raster/tile_task_runner.h"
+#include "cc/raster/zero_copy_tile_task_worker_pool.h"
#include "cc/resources/resource_pool.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/scoped_resource.h"
-#include "cc/resources/zero_copy_raster_worker_pool.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
+#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
@@ -36,12 +43,12 @@ const size_t kMaxTransferBufferUsageBytes = 10000U;
// buffer constant.
const size_t kLargeResourceDimension = 1000U;
-enum RasterWorkerPoolType {
- RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
- RASTER_WORKER_POOL_TYPE_ZERO_COPY,
- RASTER_WORKER_POOL_TYPE_ONE_COPY,
- RASTER_WORKER_POOL_TYPE_GPU,
- RASTER_WORKER_POOL_TYPE_BITMAP
+enum TileTaskWorkerPoolType {
+ TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER,
+ TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY,
+ TILE_TASK_WORKER_POOL_TYPE_ONE_COPY,
+ TILE_TASK_WORKER_POOL_TYPE_GPU,
+ TILE_TASK_WORKER_POOL_TYPE_BITMAP
};
class TestRasterTaskImpl : public RasterTask {
@@ -62,11 +69,11 @@ class TestRasterTaskImpl : public RasterTask {
raster_buffer_->Playback(picture_pile_.get(), gfx::Rect(0, 0, 1, 1), 1.0);
}
- // Overridden from RasterizerTask:
- void ScheduleOnOriginThread(RasterizerTaskClient* client) override {
+ // Overridden from TileTask:
+ void ScheduleOnOriginThread(TileTaskClient* client) override {
raster_buffer_ = client->AcquireBufferForRaster(resource());
}
- void CompleteOnOriginThread(RasterizerTaskClient* client) override {
+ void CompleteOnOriginThread(TileTaskClient* client) override {
client->ReleaseBufferForRaster(raster_buffer_.Pass());
}
void RunReplyOnOriginThread() override {
@@ -98,7 +105,7 @@ class BlockingTestRasterTaskImpl : public TestRasterTaskImpl {
TestRasterTaskImpl::RunOnWorkerThread();
}
- // Overridden from RasterizerTask:
+ // Overridden from TileTask:
void RunReplyOnOriginThread() override {}
protected:
@@ -110,9 +117,9 @@ class BlockingTestRasterTaskImpl : public TestRasterTaskImpl {
DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl);
};
-class RasterWorkerPoolTest
- : public testing::TestWithParam<RasterWorkerPoolType>,
- public RasterizerClient {
+class TileTaskWorkerPoolTest
+ : public testing::TestWithParam<TileTaskWorkerPoolType>,
+ public TileTaskRunnerClient {
public:
struct RasterTaskResult {
unsigned id;
@@ -121,87 +128,91 @@ class RasterWorkerPoolTest
typedef std::vector<scoped_refptr<RasterTask>> RasterTaskVector;
- enum NamedTaskSet { REQUIRED_FOR_ACTIVATION = 0, ALL = 1 };
+ enum NamedTaskSet { REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW, ALL };
- RasterWorkerPoolTest()
+ TileTaskWorkerPoolTest()
: context_provider_(TestContextProvider::Create()),
+ worker_context_provider_(TestContextProvider::Create()),
+ all_tile_tasks_finished_(
+ base::ThreadTaskRunnerHandle::Get().get(),
+ base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished,
+ base::Unretained(this))),
timeout_seconds_(5),
timed_out_(false) {}
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
switch (GetParam()) {
- case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
+ case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER:
Create3dOutputSurfaceAndResourceProvider();
- raster_worker_pool_ = PixelBufferRasterWorkerPool::Create(
- base::MessageLoopProxy::current().get(),
- RasterWorkerPool::GetTaskGraphRunner(),
- context_provider_.get(),
- resource_provider_.get(),
+ tile_task_worker_pool_ = PixelBufferTileTaskWorkerPool::Create(
+ base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_,
+ context_provider_.get(), resource_provider_.get(),
kMaxTransferBufferUsageBytes);
break;
- case RASTER_WORKER_POOL_TYPE_ZERO_COPY:
+ case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY:
Create3dOutputSurfaceAndResourceProvider();
- raster_worker_pool_ = ZeroCopyRasterWorkerPool::Create(
- base::MessageLoopProxy::current().get(),
- RasterWorkerPool::GetTaskGraphRunner(),
+ tile_task_worker_pool_ = ZeroCopyTileTaskWorkerPool::Create(
+ base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_,
resource_provider_.get());
break;
- case RASTER_WORKER_POOL_TYPE_ONE_COPY:
+ case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY:
Create3dOutputSurfaceAndResourceProvider();
- staging_resource_pool_ = ResourcePool::Create(
- resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888);
- raster_worker_pool_ = OneCopyRasterWorkerPool::Create(
- base::MessageLoopProxy::current().get(),
- RasterWorkerPool::GetTaskGraphRunner(),
- context_provider_.get(),
- resource_provider_.get(),
+ staging_resource_pool_ = ResourcePool::Create(resource_provider_.get(),
+ GL_TEXTURE_2D);
+ tile_task_worker_pool_ = OneCopyTileTaskWorkerPool::Create(
+ base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_,
+ context_provider_.get(), resource_provider_.get(),
staging_resource_pool_.get());
break;
- case RASTER_WORKER_POOL_TYPE_GPU:
+ case TILE_TASK_WORKER_POOL_TYPE_GPU:
Create3dOutputSurfaceAndResourceProvider();
- raster_worker_pool_ =
- GpuRasterWorkerPool::Create(base::MessageLoopProxy::current().get(),
- context_provider_.get(),
- resource_provider_.get(),
- false);
+ tile_task_worker_pool_ = GpuTileTaskWorkerPool::Create(
+ base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_,
+ context_provider_.get(), resource_provider_.get(), false, 0);
break;
- case RASTER_WORKER_POOL_TYPE_BITMAP:
+ case TILE_TASK_WORKER_POOL_TYPE_BITMAP:
CreateSoftwareOutputSurfaceAndResourceProvider();
- raster_worker_pool_ = BitmapRasterWorkerPool::Create(
- base::MessageLoopProxy::current().get(),
- RasterWorkerPool::GetTaskGraphRunner(),
+ tile_task_worker_pool_ = BitmapTileTaskWorkerPool::Create(
+ base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_,
resource_provider_.get());
break;
}
- DCHECK(raster_worker_pool_);
- raster_worker_pool_->AsRasterizer()->SetClient(this);
+ DCHECK(tile_task_worker_pool_);
+ tile_task_worker_pool_->AsTileTaskRunner()->SetClient(this);
}
- virtual void TearDown() override {
- raster_worker_pool_->AsRasterizer()->Shutdown();
- raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ void TearDown() override {
+ tile_task_worker_pool_->AsTileTaskRunner()->Shutdown();
+ tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks();
}
- // Overriden from RasterWorkerPoolClient:
- void DidFinishRunningTasks(TaskSet task_set) override {
+ void AllTileTasksFinished() {
+ tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks();
+ base::MessageLoop::current()->Quit();
+ }
+
+ // Overriden from TileTaskWorkerPoolClient:
+ void DidFinishRunningTileTasks(TaskSet task_set) override {
+ EXPECT_FALSE(completed_task_sets_[task_set]);
+ completed_task_sets_[task_set] = true;
if (task_set == ALL) {
- raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
- base::MessageLoop::current()->Quit();
+ EXPECT_TRUE((~completed_task_sets_).none());
+ all_tile_tasks_finished_.Schedule();
}
}
+
TaskSetCollection TasksThatShouldBeForcedToComplete() const override {
return TaskSetCollection();
}
void RunMessageLoopUntilAllTasksHaveCompleted() {
if (timeout_seconds_) {
- timeout_.Reset(
- base::Bind(&RasterWorkerPoolTest::OnTimeout, base::Unretained(this)));
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- timeout_.callback(),
+ timeout_.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout,
+ base::Unretained(this)));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, timeout_.callback(),
base::TimeDelta::FromSeconds(timeout_seconds_));
}
@@ -213,32 +224,33 @@ class RasterWorkerPoolTest
}
void ScheduleTasks() {
- RasterTaskQueue queue;
+ TileTaskQueue queue;
for (RasterTaskVector::const_iterator it = tasks_.begin();
- it != tasks_.end();
- ++it) {
+ it != tasks_.end(); ++it) {
TaskSetCollection task_sets;
+ task_sets[REQUIRED_FOR_ACTIVATION] = true;
+ task_sets[REQUIRED_FOR_DRAW] = true;
task_sets[ALL] = true;
- queue.items.push_back(RasterTaskQueue::Item(it->get(), task_sets));
+ queue.items.push_back(TileTaskQueue::Item(it->get(), task_sets));
}
- raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
+ completed_task_sets_.reset();
+ tile_task_worker_pool_->AsTileTaskRunner()->ScheduleTasks(&queue);
}
void AppendTask(unsigned id, const gfx::Size& size) {
scoped_ptr<ScopedResource> resource(
ScopedResource::Create(resource_provider_.get()));
- resource->Allocate(size, ResourceProvider::TextureHintImmutable, RGBA_8888);
+ resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
const Resource* const_resource = resource.get();
ImageDecodeTask::Vector empty;
tasks_.push_back(new TestRasterTaskImpl(
const_resource,
- base::Bind(&RasterWorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- base::Passed(&resource),
- id),
+ base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted,
+ base::Unretained(this), base::Passed(&resource), id),
&empty));
}
@@ -249,50 +261,49 @@ class RasterWorkerPoolTest
scoped_ptr<ScopedResource> resource(
ScopedResource::Create(resource_provider_.get()));
- resource->Allocate(size, ResourceProvider::TextureHintImmutable, RGBA_8888);
+ resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
const Resource* const_resource = resource.get();
ImageDecodeTask::Vector empty;
tasks_.push_back(new BlockingTestRasterTaskImpl(
const_resource,
- base::Bind(&RasterWorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- base::Passed(&resource),
- id),
- lock,
- &empty));
+ base::Bind(&TileTaskWorkerPoolTest::OnTaskCompleted,
+ base::Unretained(this), base::Passed(&resource), id),
+ lock, &empty));
}
const std::vector<RasterTaskResult>& completed_tasks() const {
return completed_tasks_;
}
+ void LoseContext(ContextProvider* context_provider) {
+ if (!context_provider)
+ return;
+ context_provider->ContextGL()->LoseContextCHROMIUM(
+ GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
+ context_provider->ContextGL()->Flush();
+ }
+
private:
void Create3dOutputSurfaceAndResourceProvider() {
- output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
+ output_surface_ = FakeOutputSurface::Create3d(
+ context_provider_, worker_context_provider_).Pass();
CHECK(output_surface_->BindToClient(&output_surface_client_));
TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
context3d->set_support_sync_query(true);
- resource_provider_ = ResourceProvider::Create(output_surface_.get(),
- NULL,
+ resource_provider_ = ResourceProvider::Create(output_surface_.get(), NULL,
&gpu_memory_buffer_manager_,
- NULL,
- 0,
- false,
- 1).Pass();
+ NULL, 0, false, 1).Pass();
}
void CreateSoftwareOutputSurfaceAndResourceProvider() {
output_surface_ = FakeOutputSurface::CreateSoftware(
make_scoped_ptr(new SoftwareOutputDevice));
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ = ResourceProvider::Create(output_surface_.get(),
- &shared_bitmap_manager_,
- NULL,
- NULL,
- 0,
- false,
- 1).Pass();
+ resource_provider_ =
+ ResourceProvider::Create(output_surface_.get(), &shared_bitmap_manager_,
+ NULL, NULL, 0, false, 1).Pass();
}
void OnTaskCompleted(scoped_ptr<ScopedResource> resource,
@@ -312,21 +323,25 @@ class RasterWorkerPoolTest
protected:
scoped_refptr<TestContextProvider> context_provider_;
+ scoped_refptr<TestContextProvider> worker_context_provider_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<ResourcePool> staging_resource_pool_;
- scoped_ptr<RasterWorkerPool> raster_worker_pool_;
+ scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_;
TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
base::CancelableClosure timeout_;
+ UniqueNotifier all_tile_tasks_finished_;
int timeout_seconds_;
bool timed_out_;
RasterTaskVector tasks_;
std::vector<RasterTaskResult> completed_tasks_;
+ TaskSetCollection completed_task_sets_;
};
-TEST_P(RasterWorkerPoolTest, Basic) {
+TEST_P(TileTaskWorkerPoolTest, Basic) {
AppendTask(0u);
AppendTask(1u);
ScheduleTasks();
@@ -338,8 +353,8 @@ TEST_P(RasterWorkerPoolTest, Basic) {
EXPECT_FALSE(completed_tasks()[1].canceled);
}
-TEST_P(RasterWorkerPoolTest, FailedMapResource) {
- if (GetParam() == RASTER_WORKER_POOL_TYPE_BITMAP)
+TEST_P(TileTaskWorkerPoolTest, FailedMapResource) {
+ if (GetParam() == TILE_TASK_WORKER_POOL_TYPE_BITMAP)
return;
TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
@@ -354,8 +369,8 @@ TEST_P(RasterWorkerPoolTest, FailedMapResource) {
}
// This test checks that replacing a pending raster task with another does
-// not prevent the DidFinishRunningTasks notification from being sent.
-TEST_P(RasterWorkerPoolTest, FalseThrottling) {
+// not prevent the DidFinishRunningTileTasks notification from being sent.
+TEST_P(TileTaskWorkerPoolTest, FalseThrottling) {
base::Lock lock;
// Schedule a task that is prevented from completing with a lock.
@@ -365,7 +380,7 @@ TEST_P(RasterWorkerPoolTest, FalseThrottling) {
// Schedule another task to replace the still-pending task. Because the old
// task is not a throttled task in the new task set, it should not prevent
- // DidFinishRunningTasks from getting signaled.
+ // DidFinishRunningTileTasks from getting signaled.
RasterTaskVector tasks;
tasks.swap(tasks_);
AppendTask(1u);
@@ -377,14 +392,15 @@ TEST_P(RasterWorkerPoolTest, FalseThrottling) {
RunMessageLoopUntilAllTasksHaveCompleted();
}
-TEST_P(RasterWorkerPoolTest, LargeResources) {
+TEST_P(TileTaskWorkerPoolTest, LargeResources) {
gfx::Size size(kLargeResourceDimension, kLargeResourceDimension);
{
// Verify a resource of this size is larger than the transfer buffer.
scoped_ptr<ScopedResource> resource(
ScopedResource::Create(resource_provider_.get()));
- resource->Allocate(size, ResourceProvider::TextureHintImmutable, RGBA_8888);
+ resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
EXPECT_GE(resource->bytes(), kMaxTransferBufferUsageBytes);
}
@@ -398,13 +414,29 @@ TEST_P(RasterWorkerPoolTest, LargeResources) {
RunMessageLoopUntilAllTasksHaveCompleted();
}
-INSTANTIATE_TEST_CASE_P(RasterWorkerPoolTests,
- RasterWorkerPoolTest,
- ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
- RASTER_WORKER_POOL_TYPE_ZERO_COPY,
- RASTER_WORKER_POOL_TYPE_ONE_COPY,
- RASTER_WORKER_POOL_TYPE_GPU,
- RASTER_WORKER_POOL_TYPE_BITMAP));
+TEST_P(TileTaskWorkerPoolTest, LostContext) {
+ LoseContext(output_surface_->context_provider());
+ LoseContext(output_surface_->worker_context_provider());
+
+ AppendTask(0u);
+ AppendTask(1u);
+ ScheduleTasks();
+
+ RunMessageLoopUntilAllTasksHaveCompleted();
+
+ ASSERT_EQ(2u, completed_tasks().size());
+ EXPECT_FALSE(completed_tasks()[0].canceled);
+ EXPECT_FALSE(completed_tasks()[1].canceled);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ TileTaskWorkerPoolTests,
+ TileTaskWorkerPoolTest,
+ ::testing::Values(TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER,
+ TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY,
+ TILE_TASK_WORKER_POOL_TYPE_ONE_COPY,
+ TILE_TASK_WORKER_POOL_TYPE_GPU,
+ TILE_TASK_WORKER_POOL_TYPE_BITMAP));
} // namespace
} // namespace cc
diff --git a/chromium/cc/raster/zero_copy_tile_task_worker_pool.cc b/chromium/cc/raster/zero_copy_tile_task_worker_pool.cc
new file mode 100644
index 00000000000..5a1dc23058b
--- /dev/null
+++ b/chromium/cc/raster/zero_copy_tile_task_worker_pool.cc
@@ -0,0 +1,216 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/raster/zero_copy_tile_task_worker_pool.h"
+
+#include <algorithm>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/debug/traced_value.h"
+#include "cc/raster/raster_buffer.h"
+#include "cc/resources/resource.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace cc {
+namespace {
+
+class RasterBufferImpl : public RasterBuffer {
+ public:
+ RasterBufferImpl(ResourceProvider* resource_provider,
+ const Resource* resource)
+ : lock_(resource_provider, resource->id()), resource_(resource) {}
+
+ // Overridden from RasterBuffer:
+ void Playback(const RasterSource* raster_source,
+ const gfx::Rect& rect,
+ float scale) override {
+ gfx::GpuMemoryBuffer* gpu_memory_buffer = lock_.GetGpuMemoryBuffer();
+ if (!gpu_memory_buffer)
+ return;
+
+ void* data = NULL;
+ bool rv = gpu_memory_buffer->Map(&data);
+ DCHECK(rv);
+ int stride;
+ gpu_memory_buffer->GetStride(&stride);
+ TileTaskWorkerPool::PlaybackToMemory(data, resource_->format(),
+ resource_->size(), stride,
+ raster_source, rect, scale);
+ gpu_memory_buffer->Unmap();
+ }
+
+ private:
+ ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock_;
+ const Resource* resource_;
+
+ DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
+};
+
+} // namespace
+
+// static
+scoped_ptr<TileTaskWorkerPool> ZeroCopyTileTaskWorkerPool::Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider) {
+ return make_scoped_ptr<TileTaskWorkerPool>(new ZeroCopyTileTaskWorkerPool(
+ task_runner, task_graph_runner, resource_provider));
+}
+
+ZeroCopyTileTaskWorkerPool::ZeroCopyTileTaskWorkerPool(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider)
+ : task_runner_(task_runner),
+ task_graph_runner_(task_graph_runner),
+ namespace_token_(task_graph_runner->GetNamespaceToken()),
+ resource_provider_(resource_provider),
+ task_set_finished_weak_ptr_factory_(this) {
+}
+
+ZeroCopyTileTaskWorkerPool::~ZeroCopyTileTaskWorkerPool() {
+}
+
+TileTaskRunner* ZeroCopyTileTaskWorkerPool::AsTileTaskRunner() {
+ return this;
+}
+
+void ZeroCopyTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) {
+ client_ = client;
+}
+
+void ZeroCopyTileTaskWorkerPool::Shutdown() {
+ TRACE_EVENT0("cc", "ZeroCopyTileTaskWorkerPool::Shutdown");
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
+}
+
+void ZeroCopyTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) {
+ TRACE_EVENT0("cc", "ZeroCopyTileTaskWorkerPool::ScheduleTasks");
+
+ if (tasks_pending_.none())
+ TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
+
+ // Mark all task sets as pending.
+ tasks_pending_.set();
+
+ unsigned priority = kTileTaskPriorityBase;
+
+ graph_.Reset();
+
+ // Cancel existing OnTaskSetFinished callbacks.
+ task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+
+ scoped_refptr<TileTask> new_task_set_finished_tasks[kNumberOfTaskSets];
+
+ size_t task_count[kNumberOfTaskSets] = {0};
+
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
+ new_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask(
+ task_runner_.get(),
+ base::Bind(&ZeroCopyTileTaskWorkerPool::OnTaskSetFinished,
+ task_set_finished_weak_ptr_factory_.GetWeakPtr(), task_set));
+ }
+
+ for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end(); ++it) {
+ const TileTaskQueue::Item& item = *it;
+ RasterTask* task = item.task;
+ DCHECK(!task->HasCompleted());
+
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
+ if (!item.task_sets[task_set])
+ continue;
+
+ ++task_count[task_set];
+
+ graph_.edges.push_back(
+ TaskGraph::Edge(task, new_task_set_finished_tasks[task_set].get()));
+ }
+
+ InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
+ }
+
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
+ InsertNodeForTask(&graph_, new_task_set_finished_tasks[task_set].get(),
+ kTaskSetFinishedTaskPriorityBase + task_set,
+ task_count[task_set]);
+ }
+
+ ScheduleTasksOnOriginThread(this, &graph_);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
+
+ std::copy(new_task_set_finished_tasks,
+ new_task_set_finished_tasks + kNumberOfTaskSets,
+ task_set_finished_tasks_);
+
+ TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state",
+ StateAsValue());
+}
+
+void ZeroCopyTileTaskWorkerPool::CheckForCompletedTasks() {
+ TRACE_EVENT0("cc", "ZeroCopyTileTaskWorkerPool::CheckForCompletedTasks");
+
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ &completed_tasks_);
+ for (Task::Vector::const_iterator it = completed_tasks_.begin();
+ it != completed_tasks_.end(); ++it) {
+ TileTask* task = static_cast<TileTask*>(it->get());
+
+ task->WillComplete();
+ task->CompleteOnOriginThread(this);
+ task->DidComplete();
+
+ task->RunReplyOnOriginThread();
+ }
+ completed_tasks_.clear();
+}
+
+ResourceFormat ZeroCopyTileTaskWorkerPool::GetResourceFormat() {
+ return resource_provider_->best_texture_format();
+}
+
+scoped_ptr<RasterBuffer> ZeroCopyTileTaskWorkerPool::AcquireBufferForRaster(
+ const Resource* resource) {
+ return make_scoped_ptr<RasterBuffer>(
+ new RasterBufferImpl(resource_provider_, resource));
+}
+
+void ZeroCopyTileTaskWorkerPool::ReleaseBufferForRaster(
+ scoped_ptr<RasterBuffer> buffer) {
+ // Nothing to do here. RasterBufferImpl destructor cleans up after itself.
+}
+
+void ZeroCopyTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) {
+ TRACE_EVENT1("cc", "ZeroCopyTileTaskWorkerPool::OnTaskSetFinished",
+ "task_set", task_set);
+
+ DCHECK(tasks_pending_[task_set]);
+ tasks_pending_[task_set] = false;
+ if (tasks_pending_.any()) {
+ TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running",
+ "state", StateAsValue());
+ } else {
+ TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
+ }
+ client_->DidFinishRunningTileTasks(task_set);
+}
+
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ZeroCopyTileTaskWorkerPool::StateAsValue() const {
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
+
+ state->BeginArray("tasks_pending");
+ for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
+ state->AppendBoolean(tasks_pending_[task_set]);
+ state->EndArray();
+ return state;
+}
+
+} // namespace cc
diff --git a/chromium/cc/raster/zero_copy_tile_task_worker_pool.h b/chromium/cc/raster/zero_copy_tile_task_worker_pool.h
new file mode 100644
index 00000000000..193eeda373d
--- /dev/null
+++ b/chromium/cc/raster/zero_copy_tile_task_worker_pool.h
@@ -0,0 +1,81 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RASTER_ZERO_COPY_TILE_TASK_WORKER_POOL_H_
+#define CC_RASTER_ZERO_COPY_TILE_TASK_WORKER_POOL_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "cc/raster/tile_task_runner.h"
+#include "cc/raster/tile_task_worker_pool.h"
+
+namespace base {
+namespace trace_event {
+class ConvertableToTraceFormat;
+}
+}
+
+namespace cc {
+class ResourceProvider;
+
+class CC_EXPORT ZeroCopyTileTaskWorkerPool : public TileTaskWorkerPool,
+ public TileTaskRunner,
+ public TileTaskClient {
+ public:
+ ~ZeroCopyTileTaskWorkerPool() override;
+
+ static scoped_ptr<TileTaskWorkerPool> Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider);
+
+ // Overridden from TileTaskWorkerPool:
+ TileTaskRunner* AsTileTaskRunner() override;
+
+ // Overridden from TileTaskRunner:
+ void SetClient(TileTaskRunnerClient* client) override;
+ void Shutdown() override;
+ void ScheduleTasks(TileTaskQueue* queue) override;
+ void CheckForCompletedTasks() override;
+ ResourceFormat GetResourceFormat() override;
+
+ // Overridden from TileTaskClient:
+ scoped_ptr<RasterBuffer> AcquireBufferForRaster(
+ const Resource* resource) override;
+ void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override;
+
+ protected:
+ ZeroCopyTileTaskWorkerPool(base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider);
+
+ private:
+ void OnTaskSetFinished(TaskSet task_set);
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
+ const;
+
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ TaskGraphRunner* task_graph_runner_;
+ const NamespaceToken namespace_token_;
+ TileTaskRunnerClient* client_;
+ ResourceProvider* resource_provider_;
+
+ TaskSetCollection tasks_pending_;
+
+ scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets];
+
+ // Task graph used when scheduling tasks and vector used to gather
+ // completed tasks.
+ TaskGraph graph_;
+ Task::Vector completed_tasks_;
+
+ base::WeakPtrFactory<ZeroCopyTileTaskWorkerPool>
+ task_set_finished_weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZeroCopyTileTaskWorkerPool);
+};
+
+} // namespace cc
+
+#endif // CC_RASTER_ZERO_COPY_TILE_TASK_WORKER_POOL_H_
diff --git a/chromium/cc/resources/bitmap_content_layer_updater.cc b/chromium/cc/resources/bitmap_content_layer_updater.cc
index 63ba336a152..31a62c3d7a9 100644
--- a/chromium/cc/resources/bitmap_content_layer_updater.cc
+++ b/chromium/cc/resources/bitmap_content_layer_updater.cc
@@ -32,19 +32,17 @@ void BitmapContentLayerUpdater::Resource::Update(
scoped_refptr<BitmapContentLayerUpdater> BitmapContentLayerUpdater::Create(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
int layer_id) {
return make_scoped_refptr(
new BitmapContentLayerUpdater(painter.Pass(),
- stats_instrumentation,
layer_id));
}
BitmapContentLayerUpdater::BitmapContentLayerUpdater(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
int layer_id)
- : ContentLayerUpdater(painter.Pass(), stats_instrumentation, layer_id) {}
+ : ContentLayerUpdater(painter.Pass(), layer_id) {
+}
BitmapContentLayerUpdater::~BitmapContentLayerUpdater() {}
@@ -71,17 +69,11 @@ void BitmapContentLayerUpdater::PrepareToUpdate(const gfx::Size& content_size,
DCHECK_EQ(paint_rect.height(), canvas_->getBaseLayerSize().height());
}
- base::TimeTicks start_time =
- rendering_stats_instrumentation_->StartRecording();
PaintContents(canvas_.get(),
content_size,
paint_rect,
contents_width_scale,
contents_height_scale);
- base::TimeDelta duration =
- rendering_stats_instrumentation_->EndRecording(start_time);
- rendering_stats_instrumentation_->AddPaint(
- duration, paint_rect.width() * paint_rect.height());
}
void BitmapContentLayerUpdater::UpdateTexture(ResourceUpdateQueue* queue,
diff --git a/chromium/cc/resources/bitmap_content_layer_updater.h b/chromium/cc/resources/bitmap_content_layer_updater.h
index 5ddc35f48a7..34776002000 100644
--- a/chromium/cc/resources/bitmap_content_layer_updater.h
+++ b/chromium/cc/resources/bitmap_content_layer_updater.h
@@ -42,7 +42,6 @@ class CC_EXPORT BitmapContentLayerUpdater : public ContentLayerUpdater {
static scoped_refptr<BitmapContentLayerUpdater> Create(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumenation,
int layer_id);
scoped_ptr<LayerUpdater::Resource> CreateResource(
@@ -63,7 +62,6 @@ class CC_EXPORT BitmapContentLayerUpdater : public ContentLayerUpdater {
protected:
BitmapContentLayerUpdater(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumenation,
int layer_id);
~BitmapContentLayerUpdater() override;
diff --git a/chromium/cc/resources/bitmap_raster_worker_pool.cc b/chromium/cc/resources/bitmap_raster_worker_pool.cc
deleted file mode 100644
index 3b3739a3ccc..00000000000
--- a/chromium/cc/resources/bitmap_raster_worker_pool.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2014 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/bitmap_raster_worker_pool.h"
-
-#include <algorithm>
-
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
-#include "base/strings/stringprintf.h"
-#include "cc/debug/traced_value.h"
-#include "cc/resources/raster_buffer.h"
-#include "cc/resources/raster_source.h"
-#include "cc/resources/resource.h"
-
-namespace cc {
-namespace {
-
-class RasterBufferImpl : public RasterBuffer {
- public:
- RasterBufferImpl(ResourceProvider* resource_provider,
- const Resource* resource)
- : lock_(resource_provider, resource->id()) {}
-
- // Overridden from RasterBuffer:
- void Playback(const RasterSource* raster_source,
- const gfx::Rect& rect,
- float scale) override {
- raster_source->PlaybackToCanvas(lock_.sk_canvas(), rect, scale);
- }
-
- private:
- ResourceProvider::ScopedWriteLockSoftware lock_;
-
- DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
-};
-
-} // namespace
-
-// static
-scoped_ptr<RasterWorkerPool> BitmapRasterWorkerPool::Create(
- base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ResourceProvider* resource_provider) {
- return make_scoped_ptr<RasterWorkerPool>(new BitmapRasterWorkerPool(
- task_runner, task_graph_runner, resource_provider));
-}
-
-BitmapRasterWorkerPool::BitmapRasterWorkerPool(
- base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ResourceProvider* resource_provider)
- : task_runner_(task_runner),
- task_graph_runner_(task_graph_runner),
- namespace_token_(task_graph_runner->GetNamespaceToken()),
- resource_provider_(resource_provider),
- raster_finished_weak_ptr_factory_(this) {
-}
-
-BitmapRasterWorkerPool::~BitmapRasterWorkerPool() {
-}
-
-Rasterizer* BitmapRasterWorkerPool::AsRasterizer() {
- return this;
-}
-
-void BitmapRasterWorkerPool::SetClient(RasterizerClient* client) {
- client_ = client;
-}
-
-void BitmapRasterWorkerPool::Shutdown() {
- TRACE_EVENT0("cc", "BitmapRasterWorkerPool::Shutdown");
-
- TaskGraph empty;
- task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
- task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
-}
-
-void BitmapRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
- TRACE_EVENT0("cc", "BitmapRasterWorkerPool::ScheduleTasks");
-
- if (raster_pending_.none())
- TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
-
- // Mark all task sets as pending.
- raster_pending_.set();
-
- unsigned priority = kRasterTaskPriorityBase;
-
- graph_.Reset();
-
- // Cancel existing OnRasterFinished callbacks.
- raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
-
- scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets];
-
- size_t task_count[kNumberOfTaskSets] = {0};
-
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- new_raster_finished_tasks[task_set] = CreateRasterFinishedTask(
- task_runner_.get(),
- base::Bind(&BitmapRasterWorkerPool::OnRasterFinished,
- raster_finished_weak_ptr_factory_.GetWeakPtr(),
- task_set));
- }
-
- for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
- it != queue->items.end();
- ++it) {
- const RasterTaskQueue::Item& item = *it;
- RasterTask* task = item.task;
- DCHECK(!task->HasCompleted());
-
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- if (!item.task_sets[task_set])
- continue;
-
- ++task_count[task_set];
-
- graph_.edges.push_back(
- TaskGraph::Edge(task, new_raster_finished_tasks[task_set].get()));
- }
-
- InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
- }
-
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- InsertNodeForTask(&graph_,
- new_raster_finished_tasks[task_set].get(),
- kRasterFinishedTaskPriority,
- task_count[task_set]);
- }
-
- ScheduleTasksOnOriginThread(this, &graph_);
- task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
-
- std::copy(new_raster_finished_tasks,
- new_raster_finished_tasks + kNumberOfTaskSets,
- raster_finished_tasks_);
-
- TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue());
-}
-
-void BitmapRasterWorkerPool::CheckForCompletedTasks() {
- TRACE_EVENT0("cc", "BitmapRasterWorkerPool::CheckForCompletedTasks");
-
- task_graph_runner_->CollectCompletedTasks(namespace_token_,
- &completed_tasks_);
- for (Task::Vector::const_iterator it = completed_tasks_.begin();
- it != completed_tasks_.end();
- ++it) {
- RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
-
- task->WillComplete();
- task->CompleteOnOriginThread(this);
- task->DidComplete();
-
- task->RunReplyOnOriginThread();
- }
- completed_tasks_.clear();
-}
-
-scoped_ptr<RasterBuffer> BitmapRasterWorkerPool::AcquireBufferForRaster(
- const Resource* resource) {
- return make_scoped_ptr<RasterBuffer>(
- new RasterBufferImpl(resource_provider_, resource));
-}
-
-void BitmapRasterWorkerPool::ReleaseBufferForRaster(
- scoped_ptr<RasterBuffer> buffer) {
- // Nothing to do here. RasterBufferImpl destructor cleans up after itself.
-}
-
-void BitmapRasterWorkerPool::OnRasterFinished(TaskSet task_set) {
- TRACE_EVENT1(
- "cc", "BitmapRasterWorkerPool::OnRasterFinished", "task_set", task_set);
-
- DCHECK(raster_pending_[task_set]);
- raster_pending_[task_set] = false;
- if (raster_pending_.any()) {
- TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue());
- } else {
- TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
- }
- client_->DidFinishRunningTasks(task_set);
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-BitmapRasterWorkerPool::StateAsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
-
- state->BeginArray("tasks_pending");
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
- state->AppendBoolean(raster_pending_[task_set]);
- state->EndArray();
- return state;
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/bitmap_raster_worker_pool.h b/chromium/cc/resources/bitmap_raster_worker_pool.h
deleted file mode 100644
index 624318b5e74..00000000000
--- a/chromium/cc/resources/bitmap_raster_worker_pool.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 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_BITMAP_RASTER_WORKER_POOL_H_
-#define CC_RESOURCES_BITMAP_RASTER_WORKER_POOL_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/values.h"
-#include "cc/resources/raster_worker_pool.h"
-#include "cc/resources/rasterizer.h"
-
-namespace base {
-namespace debug {
-class ConvertableToTraceFormat;
-}
-}
-
-namespace cc {
-class ResourceProvider;
-
-class CC_EXPORT BitmapRasterWorkerPool : public RasterWorkerPool,
- public Rasterizer,
- public RasterizerTaskClient {
- public:
- ~BitmapRasterWorkerPool() override;
-
- static scoped_ptr<RasterWorkerPool> Create(
- base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ResourceProvider* resource_provider);
-
- // Overridden from RasterWorkerPool:
- Rasterizer* AsRasterizer() override;
-
- // Overridden from Rasterizer:
- void SetClient(RasterizerClient* client) override;
- void Shutdown() override;
- void ScheduleTasks(RasterTaskQueue* queue) override;
- void CheckForCompletedTasks() override;
-
- // Overridden from RasterizerTaskClient:
- scoped_ptr<RasterBuffer> AcquireBufferForRaster(
- const Resource* resource) override;
- void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override;
-
- protected:
- BitmapRasterWorkerPool(base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ResourceProvider* resource_provider);
-
- private:
- void OnRasterFinished(TaskSet task_set);
- scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
-
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
- TaskGraphRunner* task_graph_runner_;
- const NamespaceToken namespace_token_;
- RasterizerClient* client_;
- ResourceProvider* resource_provider_;
-
- TaskSetCollection raster_pending_;
-
- scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets];
-
- // Task graph used when scheduling tasks and vector used to gather
- // completed tasks.
- TaskGraph graph_;
- Task::Vector completed_tasks_;
-
- base::WeakPtrFactory<BitmapRasterWorkerPool>
- raster_finished_weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(BitmapRasterWorkerPool);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_BITMAP_RASTER_WORKER_POOL_H_
diff --git a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc
index 5b8e5e43f2e..a78a9df4ded 100644
--- a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc
+++ b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc
@@ -53,9 +53,8 @@ BitmapSkPictureContentLayerUpdater::BitmapSkPictureContentLayerUpdater(
scoped_ptr<LayerPainter> painter,
RenderingStatsInstrumentation* stats_instrumentation,
int layer_id)
- : SkPictureContentLayerUpdater(painter.Pass(),
- stats_instrumentation,
- layer_id) {}
+ : SkPictureContentLayerUpdater(painter.Pass(), layer_id) {
+}
BitmapSkPictureContentLayerUpdater::~BitmapSkPictureContentLayerUpdater() {}
diff --git a/chromium/cc/resources/content_layer_updater.cc b/chromium/cc/resources/content_layer_updater.cc
index 971362fb8b8..7101dd13d84 100644
--- a/chromium/cc/resources/content_layer_updater.cc
+++ b/chromium/cc/resources/content_layer_updater.cc
@@ -4,8 +4,7 @@
#include "cc/resources/content_layer_updater.h"
-#include "base/debug/trace_event.h"
-#include "cc/debug/rendering_stats_instrumentation.h"
+#include "base/trace_event/trace_event.h"
#include "cc/resources/layer_painter.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRect.h"
@@ -16,12 +15,9 @@
namespace cc {
-ContentLayerUpdater::ContentLayerUpdater(
- scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
- int layer_id)
- : rendering_stats_instrumentation_(stats_instrumentation),
- layer_id_(layer_id),
+ContentLayerUpdater::ContentLayerUpdater(scoped_ptr<LayerPainter> painter,
+ int layer_id)
+ : layer_id_(layer_id),
layer_is_opaque_(false),
layer_fills_bounds_completely_(false),
painter_(painter.Pass()),
@@ -30,11 +26,6 @@ ContentLayerUpdater::ContentLayerUpdater(
ContentLayerUpdater::~ContentLayerUpdater() {}
-void ContentLayerUpdater::set_rendering_stats_instrumentation(
- RenderingStatsInstrumentation* rsi) {
- rendering_stats_instrumentation_ = rsi;
-}
-
void ContentLayerUpdater::PaintContents(SkCanvas* canvas,
const gfx::Size& layer_content_size,
const gfx::Rect& paint_rect,
diff --git a/chromium/cc/resources/content_layer_updater.h b/chromium/cc/resources/content_layer_updater.h
index 4ba18ba9e40..0f26b820ff4 100644
--- a/chromium/cc/resources/content_layer_updater.h
+++ b/chromium/cc/resources/content_layer_updater.h
@@ -21,15 +21,12 @@ class RenderingStatsInstrumentation;
// their respective PaintContents implementations.
class CC_EXPORT ContentLayerUpdater : public LayerUpdater {
public:
- void set_rendering_stats_instrumentation(RenderingStatsInstrumentation* rsi);
void SetOpaque(bool opaque) override;
void SetFillsBoundsCompletely(bool fills_bounds) override;
void SetBackgroundColor(SkColor background_color) override;
protected:
- ContentLayerUpdater(scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
- int layer_id);
+ ContentLayerUpdater(scoped_ptr<LayerPainter> painter, int layer_id);
~ContentLayerUpdater() override;
// Paints the contents. |content_size| size of the underlying layer in
@@ -49,7 +46,6 @@ class CC_EXPORT ContentLayerUpdater : public LayerUpdater {
SkColor background_color() const { return background_color_; }
- RenderingStatsInstrumentation* rendering_stats_instrumentation_;
int layer_id_;
// True when it is known that all output pixels will be opaque.
diff --git a/chromium/cc/resources/eviction_tile_priority_queue.cc b/chromium/cc/resources/eviction_tile_priority_queue.cc
deleted file mode 100644
index 9f05e816764..00000000000
--- a/chromium/cc/resources/eviction_tile_priority_queue.cc
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright 2014 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/eviction_tile_priority_queue.h"
-
-namespace cc {
-
-namespace {
-
-class EvictionOrderComparator {
- public:
- explicit EvictionOrderComparator(TreePriority tree_priority)
- : tree_priority_(tree_priority) {}
-
- bool operator()(
- const EvictionTilePriorityQueue::PairedPictureLayerQueue* a,
- const EvictionTilePriorityQueue::PairedPictureLayerQueue* b) const {
- // Note that in this function, we have to return true if and only if
- // b is strictly lower priority than a. Note that for the sake of
- // completeness, empty queue is considered to have lowest priority.
- if (a->IsEmpty() || b->IsEmpty())
- return b->IsEmpty() < a->IsEmpty();
-
- WhichTree a_tree = a->NextTileIteratorTree(tree_priority_);
- const PictureLayerImpl::LayerEvictionTileIterator* a_iterator =
- a_tree == ACTIVE_TREE ? &a->active_iterator : &a->pending_iterator;
-
- WhichTree b_tree = b->NextTileIteratorTree(tree_priority_);
- const PictureLayerImpl::LayerEvictionTileIterator* b_iterator =
- b_tree == ACTIVE_TREE ? &b->active_iterator : &b->pending_iterator;
-
- const Tile* a_tile = **a_iterator;
- const Tile* b_tile = **b_iterator;
-
- const TilePriority& a_priority =
- a_tile->priority_for_tree_priority(tree_priority_);
- const TilePriority& b_priority =
- b_tile->priority_for_tree_priority(tree_priority_);
- bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY;
-
- // If the priority bin differs, b is lower priority if it has the higher
- // priority bin.
- if (a_priority.priority_bin != b_priority.priority_bin)
- return b_priority.priority_bin > a_priority.priority_bin;
-
- // Otherwise if the resolution differs, then the order will be determined by
- // whether we prioritize low res or not.
- // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile
- // class but instead produced by the iterators.
- if (b_priority.resolution != a_priority.resolution) {
- // Non ideal resolution should be sorted higher than other resolutions.
- if (a_priority.resolution == NON_IDEAL_RESOLUTION)
- return false;
-
- if (b_priority.resolution == NON_IDEAL_RESOLUTION)
- return true;
-
- if (prioritize_low_res)
- return a_priority.resolution == LOW_RESOLUTION;
- return a_priority.resolution == HIGH_RESOLUTION;
- }
-
- // Otherwise if the occlusion differs, b is lower priority if it is
- // occluded.
- bool a_is_occluded = a_tile->is_occluded_for_tree_priority(tree_priority_);
- bool b_is_occluded = b_tile->is_occluded_for_tree_priority(tree_priority_);
- if (a_is_occluded != b_is_occluded)
- return b_is_occluded;
-
- // b is lower priorty if it is farther from visible.
- return b_priority.distance_to_visible > a_priority.distance_to_visible;
- }
-
- private:
- TreePriority tree_priority_;
-};
-
-} // namespace
-
-EvictionTilePriorityQueue::EvictionTilePriorityQueue() {
-}
-
-EvictionTilePriorityQueue::~EvictionTilePriorityQueue() {
-}
-
-void EvictionTilePriorityQueue::Build(
- const std::vector<PictureLayerImpl::Pair>& paired_layers,
- TreePriority tree_priority) {
- tree_priority_ = tree_priority;
-
- for (std::vector<PictureLayerImpl::Pair>::const_iterator it =
- paired_layers.begin();
- it != paired_layers.end();
- ++it) {
- paired_queues_.push_back(
- make_scoped_ptr(new PairedPictureLayerQueue(*it, tree_priority_)));
- }
-
- paired_queues_.make_heap(EvictionOrderComparator(tree_priority_));
-}
-
-void EvictionTilePriorityQueue::Reset() {
- paired_queues_.clear();
-}
-
-bool EvictionTilePriorityQueue::IsEmpty() const {
- return paired_queues_.empty() || paired_queues_.front()->IsEmpty();
-}
-
-Tile* EvictionTilePriorityQueue::Top() {
- DCHECK(!IsEmpty());
- return paired_queues_.front()->Top(tree_priority_);
-}
-
-void EvictionTilePriorityQueue::Pop() {
- DCHECK(!IsEmpty());
-
- paired_queues_.pop_heap(EvictionOrderComparator(tree_priority_));
- PairedPictureLayerQueue* paired_queue = paired_queues_.back();
- paired_queue->Pop(tree_priority_);
- paired_queues_.push_heap(EvictionOrderComparator(tree_priority_));
-}
-
-EvictionTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue() {
-}
-
-EvictionTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue(
- const PictureLayerImpl::Pair& layer_pair,
- TreePriority tree_priority)
- : active_iterator(
- layer_pair.active
- ? PictureLayerImpl::LayerEvictionTileIterator(layer_pair.active,
- tree_priority)
- : PictureLayerImpl::LayerEvictionTileIterator()),
- pending_iterator(
- layer_pair.pending
- ? PictureLayerImpl::LayerEvictionTileIterator(layer_pair.pending,
- tree_priority)
- : PictureLayerImpl::LayerEvictionTileIterator()) {
-}
-
-EvictionTilePriorityQueue::PairedPictureLayerQueue::~PairedPictureLayerQueue() {
-}
-
-bool EvictionTilePriorityQueue::PairedPictureLayerQueue::IsEmpty() const {
- return !active_iterator && !pending_iterator;
-}
-
-Tile* EvictionTilePriorityQueue::PairedPictureLayerQueue::Top(
- TreePriority tree_priority) {
- DCHECK(!IsEmpty());
-
- WhichTree next_tree = NextTileIteratorTree(tree_priority);
- PictureLayerImpl::LayerEvictionTileIterator* next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
- DCHECK(*next_iterator);
-
- Tile* tile = **next_iterator;
- DCHECK(std::find(returned_shared_tiles.begin(),
- returned_shared_tiles.end(),
- tile) == returned_shared_tiles.end());
- return tile;
-}
-
-void EvictionTilePriorityQueue::PairedPictureLayerQueue::Pop(
- TreePriority tree_priority) {
- DCHECK(!IsEmpty());
-
- WhichTree next_tree = NextTileIteratorTree(tree_priority);
- PictureLayerImpl::LayerEvictionTileIterator* next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
- DCHECK(*next_iterator);
- returned_shared_tiles.push_back(**next_iterator);
- ++(*next_iterator);
-
- if (IsEmpty())
- return;
-
- next_tree = NextTileIteratorTree(tree_priority);
- next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
- while (std::find(returned_shared_tiles.begin(),
- returned_shared_tiles.end(),
- **next_iterator) != returned_shared_tiles.end()) {
- ++(*next_iterator);
- if (IsEmpty())
- break;
- next_tree = NextTileIteratorTree(tree_priority);
- next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
- }
-}
-
-WhichTree
-EvictionTilePriorityQueue::PairedPictureLayerQueue::NextTileIteratorTree(
- TreePriority tree_priority) const {
- DCHECK(!IsEmpty());
-
- // If we only have one iterator with tiles, return it.
- if (!active_iterator)
- return PENDING_TREE;
- if (!pending_iterator)
- return ACTIVE_TREE;
-
- const Tile* active_tile = *active_iterator;
- const Tile* pending_tile = *pending_iterator;
- if (active_tile == pending_tile)
- return ACTIVE_TREE;
-
- const TilePriority& active_priority =
- active_tile->priority_for_tree_priority(tree_priority);
- const TilePriority& pending_priority =
- pending_tile->priority_for_tree_priority(tree_priority);
-
- if (pending_priority.IsHigherPriorityThan(active_priority))
- return ACTIVE_TREE;
- return PENDING_TREE;
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/eviction_tile_priority_queue.h b/chromium/cc/resources/eviction_tile_priority_queue.h
deleted file mode 100644
index e91f0d2a682..00000000000
--- a/chromium/cc/resources/eviction_tile_priority_queue.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 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_EVICTION_TILE_PRIORITY_QUEUE_H_
-#define CC_RESOURCES_EVICTION_TILE_PRIORITY_QUEUE_H_
-
-#include <utility>
-#include <vector>
-
-#include "cc/base/cc_export.h"
-#include "cc/layers/picture_layer_impl.h"
-#include "cc/resources/tile_priority.h"
-
-namespace cc {
-
-class CC_EXPORT EvictionTilePriorityQueue {
- public:
- struct PairedPictureLayerQueue {
- PairedPictureLayerQueue();
- PairedPictureLayerQueue(const PictureLayerImpl::Pair& layer_pair,
- TreePriority tree_priority);
- ~PairedPictureLayerQueue();
-
- bool IsEmpty() const;
- Tile* Top(TreePriority tree_priority);
- void Pop(TreePriority tree_priority);
-
- WhichTree NextTileIteratorTree(TreePriority tree_priority) const;
-
- PictureLayerImpl::LayerEvictionTileIterator active_iterator;
- PictureLayerImpl::LayerEvictionTileIterator pending_iterator;
-
- // TODO(vmpstr): Investigate removing this.
- std::vector<Tile*> returned_shared_tiles;
- };
-
- EvictionTilePriorityQueue();
- ~EvictionTilePriorityQueue();
-
- void Build(const std::vector<PictureLayerImpl::Pair>& paired_layers,
- TreePriority tree_priority);
- void Reset();
-
- bool IsEmpty() const;
- Tile* Top();
- void Pop();
-
- private:
- // TODO(vmpstr): This is potentially unnecessary if it becomes the case that
- // PairedPictureLayerQueue is fast enough to copy. In that case, we can use
- // objects directly (ie std::vector<PairedPictureLayerQueue>).
- ScopedPtrVector<PairedPictureLayerQueue> paired_queues_;
- TreePriority tree_priority_;
-
- DISALLOW_COPY_AND_ASSIGN(EvictionTilePriorityQueue);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_EVICTION_TILE_PRIORITY_QUEUE_H_
diff --git a/chromium/cc/resources/gpu_raster_worker_pool.cc b/chromium/cc/resources/gpu_raster_worker_pool.cc
deleted file mode 100644
index 04724f120f0..00000000000
--- a/chromium/cc/resources/gpu_raster_worker_pool.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2014 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/gpu_raster_worker_pool.h"
-
-#include <algorithm>
-
-#include "base/debug/trace_event.h"
-#include "cc/output/context_provider.h"
-#include "cc/resources/raster_buffer.h"
-#include "cc/resources/raster_source.h"
-#include "cc/resources/resource.h"
-#include "cc/resources/resource_provider.h"
-#include "cc/resources/scoped_gpu_raster.h"
-#include "gpu/command_buffer/client/gles2_interface.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"
-#include "third_party/skia/include/gpu/GrContext.h"
-
-namespace cc {
-namespace {
-
-class RasterBufferImpl : public RasterBuffer {
- public:
- RasterBufferImpl(ResourceProvider* resource_provider,
- const Resource* resource,
- SkMultiPictureDraw* multi_picture_draw,
- bool use_distance_field_text)
- : lock_(resource_provider, resource->id()),
- resource_(resource),
- multi_picture_draw_(multi_picture_draw),
- use_distance_field_text_(use_distance_field_text) {}
-
- // Overridden from RasterBuffer:
- void Playback(const RasterSource* raster_source,
- const gfx::Rect& rect,
- float scale) override {
- // Turn on distance fields for layers that have ever animated.
- bool use_distance_field_text =
- use_distance_field_text_ ||
- raster_source->SuitableForDistanceFieldText();
- SkSurface* sk_surface = lock_.GetSkSurface(use_distance_field_text);
-
- if (!sk_surface)
- return;
-
- SkPictureRecorder recorder;
- gfx::Size size = resource_->size();
- skia::RefPtr<SkCanvas> canvas =
- skia::SharePtr(recorder.beginRecording(size.width(), size.height()));
-
- canvas->save();
- raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
- canvas->restore();
-
- // Add the canvas and recorded picture to |multi_picture_draw_|.
- skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
- multi_picture_draw_->add(sk_surface->getCanvas(), picture.get());
- }
-
- private:
- ResourceProvider::ScopedWriteLockGr lock_;
- const Resource* resource_;
- SkMultiPictureDraw* multi_picture_draw_;
- bool use_distance_field_text_;
-
- DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
-};
-
-} // namespace
-
-// static
-scoped_ptr<RasterWorkerPool> GpuRasterWorkerPool::Create(
- base::SequencedTaskRunner* task_runner,
- ContextProvider* context_provider,
- ResourceProvider* resource_provider,
- bool use_distance_field_text) {
- return make_scoped_ptr<RasterWorkerPool>(
- new GpuRasterWorkerPool(task_runner,
- context_provider,
- resource_provider,
- use_distance_field_text));
-}
-
-GpuRasterWorkerPool::GpuRasterWorkerPool(base::SequencedTaskRunner* task_runner,
- ContextProvider* context_provider,
- ResourceProvider* resource_provider,
- bool use_distance_field_text)
- : task_runner_(task_runner),
- task_graph_runner_(new TaskGraphRunner),
- namespace_token_(task_graph_runner_->GetNamespaceToken()),
- context_provider_(context_provider),
- resource_provider_(resource_provider),
- run_tasks_on_origin_thread_pending_(false),
- use_distance_field_text_(use_distance_field_text),
- raster_finished_weak_ptr_factory_(this),
- weak_ptr_factory_(this) {
- DCHECK(context_provider_);
-}
-
-GpuRasterWorkerPool::~GpuRasterWorkerPool() {
- DCHECK_EQ(0u, completed_tasks_.size());
-}
-
-Rasterizer* GpuRasterWorkerPool::AsRasterizer() {
- return this;
-}
-
-void GpuRasterWorkerPool::SetClient(RasterizerClient* client) {
- client_ = client;
-}
-
-void GpuRasterWorkerPool::Shutdown() {
- TRACE_EVENT0("cc", "GpuRasterWorkerPool::Shutdown");
-
- TaskGraph empty;
- task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
- task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
-}
-
-void GpuRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
- TRACE_EVENT0("cc", "GpuRasterWorkerPool::ScheduleTasks");
-
- // Mark all task sets as pending.
- raster_pending_.set();
-
- unsigned priority = kRasterTaskPriorityBase;
-
- graph_.Reset();
-
- // Cancel existing OnRasterFinished callbacks.
- raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
-
- scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets];
-
- size_t task_count[kNumberOfTaskSets] = {0};
-
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- new_raster_finished_tasks[task_set] = CreateRasterFinishedTask(
- task_runner_.get(),
- base::Bind(&GpuRasterWorkerPool::OnRasterFinished,
- raster_finished_weak_ptr_factory_.GetWeakPtr(),
- task_set));
- }
-
- for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
- it != queue->items.end();
- ++it) {
- const RasterTaskQueue::Item& item = *it;
- RasterTask* task = item.task;
- DCHECK(!task->HasCompleted());
-
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- if (!item.task_sets[task_set])
- continue;
-
- ++task_count[task_set];
-
- graph_.edges.push_back(
- TaskGraph::Edge(task, new_raster_finished_tasks[task_set].get()));
- }
-
- InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
- }
-
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- InsertNodeForTask(&graph_,
- new_raster_finished_tasks[task_set].get(),
- kRasterFinishedTaskPriority,
- task_count[task_set]);
- }
-
- ScheduleTasksOnOriginThread(this, &graph_);
- task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
-
- ScheduleRunTasksOnOriginThread();
-
- std::copy(new_raster_finished_tasks,
- new_raster_finished_tasks + kNumberOfTaskSets,
- raster_finished_tasks_);
-}
-
-void GpuRasterWorkerPool::CheckForCompletedTasks() {
- TRACE_EVENT0("cc", "GpuRasterWorkerPool::CheckForCompletedTasks");
-
- task_graph_runner_->CollectCompletedTasks(namespace_token_,
- &completed_tasks_);
- for (Task::Vector::const_iterator it = completed_tasks_.begin();
- it != completed_tasks_.end();
- ++it) {
- RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
-
- task->WillComplete();
- task->CompleteOnOriginThread(this);
- task->DidComplete();
-
- task->RunReplyOnOriginThread();
- }
- completed_tasks_.clear();
-}
-
-scoped_ptr<RasterBuffer> GpuRasterWorkerPool::AcquireBufferForRaster(
- const Resource* resource) {
- return make_scoped_ptr<RasterBuffer>(
- new RasterBufferImpl(resource_provider_,
- resource,
- &multi_picture_draw_,
- use_distance_field_text_));
-}
-
-void GpuRasterWorkerPool::ReleaseBufferForRaster(
- scoped_ptr<RasterBuffer> buffer) {
- // Nothing to do here. RasterBufferImpl destructor cleans up after itself.
-}
-
-void GpuRasterWorkerPool::OnRasterFinished(TaskSet task_set) {
- TRACE_EVENT1(
- "cc", "GpuRasterWorkerPool::OnRasterFinished", "task_set", task_set);
-
- DCHECK(raster_pending_[task_set]);
- raster_pending_[task_set] = false;
- client_->DidFinishRunningTasks(task_set);
-}
-
-void GpuRasterWorkerPool::ScheduleRunTasksOnOriginThread() {
- if (run_tasks_on_origin_thread_pending_)
- return;
-
- task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&GpuRasterWorkerPool::RunTasksOnOriginThread,
- weak_ptr_factory_.GetWeakPtr()));
- run_tasks_on_origin_thread_pending_ = true;
-}
-
-void GpuRasterWorkerPool::RunTasksOnOriginThread() {
- TRACE_EVENT0("cc", "GpuRasterWorkerPool::RunTasksOnOriginThread");
-
- DCHECK(run_tasks_on_origin_thread_pending_);
- run_tasks_on_origin_thread_pending_ = false;
-
- ScopedGpuRaster gpu_raster(context_provider_);
- task_graph_runner_->RunUntilIdle();
-
- // Draw each all of the pictures that were collected. This will also clear
- // the pictures and canvases added to |multi_picture_draw_|
- multi_picture_draw_.draw();
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/gpu_raster_worker_pool.h b/chromium/cc/resources/gpu_raster_worker_pool.h
deleted file mode 100644
index c5ff13f1361..00000000000
--- a/chromium/cc/resources/gpu_raster_worker_pool.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2014 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_GPU_RASTER_WORKER_POOL_H_
-#define CC_RESOURCES_GPU_RASTER_WORKER_POOL_H_
-
-#include "base/memory/weak_ptr.h"
-#include "cc/resources/raster_worker_pool.h"
-#include "cc/resources/rasterizer.h"
-#include "third_party/skia/include/core/SkMultiPictureDraw.h"
-
-namespace cc {
-class ContextProvider;
-class ResourceProvider;
-
-class CC_EXPORT GpuRasterWorkerPool : public RasterWorkerPool,
- public Rasterizer,
- public RasterizerTaskClient {
- public:
- ~GpuRasterWorkerPool() override;
-
- static scoped_ptr<RasterWorkerPool> Create(
- base::SequencedTaskRunner* task_runner,
- ContextProvider* context_provider,
- ResourceProvider* resource_provider,
- bool use_distance_field_text);
-
- // Overridden from RasterWorkerPool:
- Rasterizer* AsRasterizer() override;
-
- // Overridden from Rasterizer:
- void SetClient(RasterizerClient* client) override;
- void Shutdown() override;
- void ScheduleTasks(RasterTaskQueue* queue) override;
- void CheckForCompletedTasks() override;
-
- // Overridden from RasterizerTaskClient:
- scoped_ptr<RasterBuffer> AcquireBufferForRaster(
- const Resource* resource) override;
- void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override;
-
- private:
- GpuRasterWorkerPool(base::SequencedTaskRunner* task_runner,
- ContextProvider* context_provider,
- ResourceProvider* resource_provider,
- bool use_distance_field_text);
-
- void OnRasterFinished(TaskSet task_set);
- void ScheduleRunTasksOnOriginThread();
- void RunTasksOnOriginThread();
- void RunTaskOnOriginThread(RasterizerTask* task);
-
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
- scoped_ptr<TaskGraphRunner> task_graph_runner_;
- const NamespaceToken namespace_token_;
- RasterizerClient* client_;
- ContextProvider* context_provider_;
- ResourceProvider* resource_provider_;
- SkMultiPictureDraw multi_picture_draw_;
-
- bool run_tasks_on_origin_thread_pending_;
- bool use_distance_field_text_;
-
- TaskSetCollection raster_pending_;
-
- scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets];
-
- // Task graph used when scheduling tasks and vector used to gather
- // completed tasks.
- TaskGraph graph_;
- Task::Vector completed_tasks_;
-
- base::WeakPtrFactory<GpuRasterWorkerPool> raster_finished_weak_ptr_factory_;
-
- base::WeakPtrFactory<GpuRasterWorkerPool> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuRasterWorkerPool);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_GPU_RASTER_WORKER_POOL_H_
diff --git a/chromium/cc/resources/layer_quad.cc b/chromium/cc/resources/layer_quad.cc
deleted file mode 100644
index 38ec7b32b01..00000000000
--- a/chromium/cc/resources/layer_quad.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/layer_quad.h"
-
-#include "base/logging.h"
-#include "ui/gfx/geometry/quad_f.h"
-
-namespace cc {
-
-LayerQuad::Edge::Edge(const gfx::PointF& p, const gfx::PointF& q) {
- DCHECK(p != q);
-
- gfx::Vector2dF tangent(p.y() - q.y(), q.x() - p.x());
- float cross2 = p.x() * q.y() - q.x() * p.y();
-
- set(tangent.x(), tangent.y(), cross2);
- scale(1.0f / tangent.Length());
-}
-
-LayerQuad::LayerQuad(const gfx::QuadF& quad) {
- // Create edges.
- left_ = Edge(quad.p4(), quad.p1());
- right_ = Edge(quad.p2(), quad.p3());
- top_ = Edge(quad.p1(), quad.p2());
- bottom_ = Edge(quad.p3(), quad.p4());
-
- float sign = quad.IsCounterClockwise() ? -1 : 1;
- left_.scale(sign);
- right_.scale(sign);
- top_.scale(sign);
- bottom_.scale(sign);
-}
-
-LayerQuad::LayerQuad(const Edge& left,
- const Edge& top,
- const Edge& right,
- const Edge& bottom)
- : left_(left),
- top_(top),
- right_(right),
- bottom_(bottom) {}
-
-gfx::QuadF LayerQuad::ToQuadF() const {
- return gfx::QuadF(left_.Intersect(top_),
- top_.Intersect(right_),
- right_.Intersect(bottom_),
- bottom_.Intersect(left_));
-}
-
-void LayerQuad::ToFloatArray(float flattened[12]) const {
- flattened[0] = left_.x();
- flattened[1] = left_.y();
- flattened[2] = left_.z();
- flattened[3] = top_.x();
- flattened[4] = top_.y();
- flattened[5] = top_.z();
- flattened[6] = right_.x();
- flattened[7] = right_.y();
- flattened[8] = right_.z();
- flattened[9] = bottom_.x();
- flattened[10] = bottom_.y();
- flattened[11] = bottom_.z();
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/managed_tile_state.cc b/chromium/cc/resources/managed_tile_state.cc
deleted file mode 100644
index 2841711dd81..00000000000
--- a/chromium/cc/resources/managed_tile_state.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/managed_tile_state.h"
-
-#include <limits>
-#include <string>
-
-#include "base/debug/trace_event_argument.h"
-#include "cc/base/math_util.h"
-
-namespace cc {
-
-std::string ManagedTileBinToString(ManagedTileBin bin) {
- switch (bin) {
- case NOW_AND_READY_TO_DRAW_BIN:
- return "NOW_AND_READY_TO_DRAW_BIN";
- case NOW_BIN:
- return "NOW_BIN";
- case SOON_BIN:
- return "SOON_BIN";
- case EVENTUALLY_AND_ACTIVE_BIN:
- return "EVENTUALLY_AND_ACTIVE_BIN";
- case EVENTUALLY_BIN:
- return "EVENTUALLY_BIN";
- case AT_LAST_AND_ACTIVE_BIN:
- return "AT_LAST_AND_ACTIVE_BIN";
- case AT_LAST_BIN:
- return "AT_LAST_BIN";
- case NEVER_BIN:
- return "NEVER_BIN";
- case NUM_BINS:
- NOTREACHED();
- return "Invalid Bin (NUM_BINS)";
- }
- return "Invalid Bin (UNKNOWN)";
-}
-
-ManagedTileState::ManagedTileState()
- : bin(NEVER_BIN),
- resolution(NON_IDEAL_RESOLUTION),
- required_for_activation(false),
- priority_bin(TilePriority::EVENTUALLY),
- distance_to_visible(std::numeric_limits<float>::infinity()),
- visible_and_ready_to_draw(false),
- scheduled_priority(0) {
-}
-
-ManagedTileState::DrawInfo::DrawInfo()
- : mode_(RESOURCE_MODE), solid_color_(SK_ColorWHITE) {
-}
-
-ManagedTileState::DrawInfo::~DrawInfo() {
- DCHECK(!resource_);
-}
-
-bool ManagedTileState::DrawInfo::IsReadyToDraw() const {
- switch (mode_) {
- case RESOURCE_MODE:
- return !!resource_;
- case SOLID_COLOR_MODE:
- case PICTURE_PILE_MODE:
- return true;
- }
- NOTREACHED();
- return false;
-}
-
-ManagedTileState::~ManagedTileState() {}
-
-void ManagedTileState::AsValueInto(base::debug::TracedValue* state) const {
- bool has_resource = (draw_info.resource_.get() != 0);
- bool has_active_task = (raster_task.get() != 0);
-
- bool is_using_gpu_memory = has_resource || has_active_task;
-
- state->SetBoolean("has_resource", has_resource);
- state->SetBoolean("is_using_gpu_memory", is_using_gpu_memory);
- state->SetString("bin", ManagedTileBinToString(bin));
- state->SetString("resolution", TileResolutionToString(resolution));
- state->SetString("priority_bin", TilePriorityBinToString(priority_bin));
- state->SetDouble("distance_to_visible",
- MathUtil::AsFloatSafely(distance_to_visible));
- state->SetBoolean("required_for_activation", required_for_activation);
- state->SetBoolean("is_solid_color",
- draw_info.mode_ == DrawInfo::SOLID_COLOR_MODE);
- state->SetBoolean("is_transparent",
- draw_info.mode_ == DrawInfo::SOLID_COLOR_MODE &&
- !SkColorGetA(draw_info.solid_color_));
- state->SetInteger("scheduled_priority", scheduled_priority);
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/managed_tile_state.h b/chromium/cc/resources/managed_tile_state.h
deleted file mode 100644
index 58b77c60fc3..00000000000
--- a/chromium/cc/resources/managed_tile_state.h
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_MANAGED_TILE_STATE_H_
-#define CC_RESOURCES_MANAGED_TILE_STATE_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "cc/resources/platform_color.h"
-#include "cc/resources/rasterizer.h"
-#include "cc/resources/resource_pool.h"
-#include "cc/resources/resource_provider.h"
-#include "cc/resources/scoped_resource.h"
-#include "cc/resources/tile_priority.h"
-
-namespace cc {
-
-class TileManager;
-
-// Tile manager classifying tiles into a few basic bins:
-enum ManagedTileBin {
- NOW_AND_READY_TO_DRAW_BIN = 0, // Ready to draw and within viewport.
- NOW_BIN = 1, // Needed ASAP.
- SOON_BIN = 2, // Impl-side version of prepainting.
- EVENTUALLY_AND_ACTIVE_BIN = 3, // Nice to have, and has a task or resource.
- EVENTUALLY_BIN = 4, // Nice to have, if we've got memory and time.
- AT_LAST_AND_ACTIVE_BIN = 5, // Only do this after all other bins.
- AT_LAST_BIN = 6, // Only do this after all other bins.
- NEVER_BIN = 7, // Dont bother.
- NUM_BINS = 8
- // NOTE: Be sure to update ManagedTileBinAsValue and kBinPolicyMap when adding
- // or reordering fields.
-};
-scoped_ptr<base::Value> ManagedTileBinAsValue(ManagedTileBin bin);
-
-// This is state that is specific to a tile that is
-// managed by the TileManager.
-class CC_EXPORT ManagedTileState {
- public:
- // This class holds all the state relevant to drawing a tile.
- class CC_EXPORT DrawInfo {
- public:
- enum Mode { RESOURCE_MODE, SOLID_COLOR_MODE, PICTURE_PILE_MODE };
-
- DrawInfo();
- ~DrawInfo();
-
- Mode mode() const { return mode_; }
-
- bool IsReadyToDraw() const;
-
- ResourceProvider::ResourceId get_resource_id() const {
- DCHECK(mode_ == RESOURCE_MODE);
- DCHECK(resource_);
-
- return resource_->id();
- }
-
- SkColor get_solid_color() const {
- DCHECK(mode_ == SOLID_COLOR_MODE);
-
- return solid_color_;
- }
-
- bool contents_swizzled() const {
- DCHECK(resource_);
- return !PlatformColor::SameComponentOrder(resource_->format());
- }
-
- bool requires_resource() const {
- return mode_ == RESOURCE_MODE || mode_ == PICTURE_PILE_MODE;
- }
-
- inline bool has_resource() const { return !!resource_; }
-
- void SetSolidColorForTesting(SkColor color) { set_solid_color(color); }
- void SetResourceForTesting(scoped_ptr<ScopedResource> resource) {
- resource_ = resource.Pass();
- }
-
- private:
- friend class TileManager;
- friend class PrioritizedTileSet;
- friend class Tile;
- friend class ManagedTileState;
-
- void set_use_resource() { mode_ = RESOURCE_MODE; }
-
- void set_solid_color(const SkColor& color) {
- mode_ = SOLID_COLOR_MODE;
- solid_color_ = color;
- }
-
- void set_rasterize_on_demand() { mode_ = PICTURE_PILE_MODE; }
-
- Mode mode_;
- SkColor solid_color_;
- scoped_ptr<ScopedResource> resource_;
- };
-
- ManagedTileState();
- ~ManagedTileState();
-
- void AsValueInto(base::debug::TracedValue* dict) const;
-
- // Persisted state: valid all the time.
- DrawInfo draw_info;
- scoped_refptr<RasterTask> raster_task;
-
- ManagedTileBin bin;
-
- TileResolution resolution;
- bool required_for_activation;
- TilePriority::PriorityBin priority_bin;
- float distance_to_visible;
- bool visible_and_ready_to_draw;
-
- // Priority for this state from the last time we assigned memory.
- unsigned scheduled_priority;
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_MANAGED_TILE_STATE_H_
diff --git a/chromium/cc/resources/picture.cc b/chromium/cc/resources/picture.cc
deleted file mode 100644
index c35da96848e..00000000000
--- a/chromium/cc/resources/picture.cc
+++ /dev/null
@@ -1,520 +0,0 @@
-// Copyright 2012 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/picture.h"
-
-#include <algorithm>
-#include <limits>
-#include <set>
-
-#include "base/base64.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
-#include "base/values.h"
-#include "cc/base/math_util.h"
-#include "cc/base/util.h"
-#include "cc/debug/traced_picture.h"
-#include "cc/debug/traced_value.h"
-#include "cc/layers/content_layer_client.h"
-#include "skia/ext/pixel_ref_utils.h"
-#include "third_party/skia/include/core/SkBBHFactory.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkPictureRecorder.h"
-#include "third_party/skia/include/core/SkStream.h"
-#include "third_party/skia/include/utils/SkNullCanvas.h"
-#include "ui/gfx/codec/jpeg_codec.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/skia_util.h"
-
-namespace cc {
-
-namespace {
-
-SkData* EncodeBitmap(size_t* offset, const SkBitmap& bm) {
- const int kJpegQuality = 80;
- std::vector<unsigned char> data;
-
- // If bitmap is opaque, encode as JPEG.
- // Otherwise encode as PNG.
- bool encoding_succeeded = false;
- if (bm.isOpaque()) {
- SkAutoLockPixels lock_bitmap(bm);
- if (bm.empty())
- return NULL;
-
- encoding_succeeded = gfx::JPEGCodec::Encode(
- reinterpret_cast<unsigned char*>(bm.getAddr32(0, 0)),
- gfx::JPEGCodec::FORMAT_SkBitmap,
- bm.width(),
- bm.height(),
- bm.rowBytes(),
- kJpegQuality,
- &data);
- } else {
- encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data);
- }
-
- if (encoding_succeeded) {
- *offset = 0;
- return SkData::NewWithCopy(&data.front(), data.size());
- }
- return NULL;
-}
-
-bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
- const unsigned char* data = static_cast<const unsigned char *>(buffer);
-
- // Try PNG first.
- if (gfx::PNGCodec::Decode(data, size, bm))
- return true;
-
- // Try JPEG.
- scoped_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodec::Decode(data, size));
- if (decoded_jpeg) {
- *bm = *decoded_jpeg;
- return true;
- }
- return false;
-}
-
-} // namespace
-
-scoped_refptr<Picture> Picture::Create(
- const gfx::Rect& layer_rect,
- ContentLayerClient* client,
- const SkTileGridFactory::TileGridInfo& tile_grid_info,
- bool gather_pixel_refs,
- RecordingMode recording_mode) {
- scoped_refptr<Picture> picture = make_scoped_refptr(new Picture(layer_rect));
-
- picture->Record(client, tile_grid_info, recording_mode);
- if (gather_pixel_refs)
- picture->GatherPixelRefs(tile_grid_info);
-
- return picture;
-}
-
-Picture::Picture(const gfx::Rect& layer_rect)
- : layer_rect_(layer_rect),
- cell_size_(layer_rect.size()) {
- // Instead of recording a trace event for object creation here, we wait for
- // the picture to be recorded in Picture::Record.
-}
-
-scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) {
- // Decode the picture from base64.
- std::string encoded;
- if (!value->GetAsString(&encoded))
- return NULL;
-
- std::string decoded;
- base::Base64Decode(encoded, &decoded);
- SkMemoryStream stream(decoded.data(), decoded.size());
-
- // Read the picture. This creates an empty picture on failure.
- SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
- if (skpicture == NULL)
- return NULL;
-
- gfx::Rect layer_rect(skpicture->width(), skpicture->height());
- return make_scoped_refptr(new Picture(skpicture, layer_rect));
-}
-
-scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
- const base::DictionaryValue* value = NULL;
- if (!raw_value->GetAsDictionary(&value))
- return NULL;
-
- // Decode the picture from base64.
- std::string encoded;
- if (!value->GetString("skp64", &encoded))
- return NULL;
-
- std::string decoded;
- base::Base64Decode(encoded, &decoded);
- SkMemoryStream stream(decoded.data(), decoded.size());
-
- const base::Value* layer_rect_value = NULL;
- if (!value->Get("params.layer_rect", &layer_rect_value))
- return NULL;
-
- gfx::Rect layer_rect;
- if (!MathUtil::FromValue(layer_rect_value, &layer_rect))
- return NULL;
-
- // Read the picture. This creates an empty picture on failure.
- SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
- if (skpicture == NULL)
- return NULL;
-
- return make_scoped_refptr(new Picture(skpicture, layer_rect));
-}
-
-Picture::Picture(SkPicture* picture, const gfx::Rect& layer_rect)
- : layer_rect_(layer_rect),
- picture_(skia::AdoptRef(picture)),
- cell_size_(layer_rect.size()) {
-}
-
-Picture::Picture(const skia::RefPtr<SkPicture>& picture,
- const gfx::Rect& layer_rect,
- const PixelRefMap& pixel_refs) :
- layer_rect_(layer_rect),
- picture_(picture),
- pixel_refs_(pixel_refs),
- cell_size_(layer_rect.size()) {
-}
-
-Picture::~Picture() {
- TRACE_EVENT_OBJECT_DELETED_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
-}
-
-bool Picture::IsSuitableForGpuRasterization() const {
- DCHECK(picture_);
-
- // TODO(alokp): SkPicture::suitableForGpuRasterization needs a GrContext.
- // Ideally this GrContext should be the same as that for rasterizing this
- // picture. But we are on the main thread while the rasterization context
- // may be on the compositor or raster thread.
- // SkPicture::suitableForGpuRasterization is not implemented yet.
- // Pass a NULL context for now and discuss with skia folks if the context
- // is really needed.
- return picture_->suitableForGpuRasterization(NULL);
-}
-
-int Picture::ApproximateOpCount() const {
- DCHECK(picture_);
- return picture_->approximateOpCount();
-}
-
-bool Picture::HasText() const {
- DCHECK(picture_);
- return picture_->hasText();
-}
-
-void Picture::Record(ContentLayerClient* painter,
- const SkTileGridFactory::TileGridInfo& tile_grid_info,
- RecordingMode recording_mode) {
- TRACE_EVENT2("cc",
- "Picture::Record",
- "data",
- AsTraceableRecordData(),
- "recording_mode",
- recording_mode);
-
- DCHECK(!picture_);
- DCHECK(!tile_grid_info.fTileInterval.isEmpty());
-
- SkTileGridFactory factory(tile_grid_info);
- SkPictureRecorder recorder;
-
- skia::RefPtr<SkCanvas> canvas;
- canvas = skia::SharePtr(recorder.beginRecording(
- layer_rect_.width(), layer_rect_.height(), &factory));
-
- ContentLayerClient::GraphicsContextStatus graphics_context_status =
- ContentLayerClient::GRAPHICS_CONTEXT_ENABLED;
-
- switch (recording_mode) {
- case RECORD_NORMALLY:
- // Already setup for normal recording.
- break;
- case RECORD_WITH_SK_NULL_CANVAS:
- canvas = skia::AdoptRef(SkCreateNullCanvas());
- break;
- case RECORD_WITH_PAINTING_DISABLED:
- // We pass a disable flag through the paint calls when perfromance
- // testing (the only time this case should ever arise) when we want to
- // prevent the Blink GraphicsContext object from consuming any compute
- // time.
- canvas = skia::AdoptRef(SkCreateNullCanvas());
- graphics_context_status = ContentLayerClient::GRAPHICS_CONTEXT_DISABLED;
- break;
- default:
- NOTREACHED();
- }
-
- canvas->save();
- canvas->translate(SkFloatToScalar(-layer_rect_.x()),
- SkFloatToScalar(-layer_rect_.y()));
-
- SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
- layer_rect_.y(),
- layer_rect_.width(),
- layer_rect_.height());
- canvas->clipRect(layer_skrect);
-
- painter->PaintContents(canvas.get(), layer_rect_, graphics_context_status);
-
- canvas->restore();
- picture_ = skia::AdoptRef(recorder.endRecording());
- DCHECK(picture_);
-
- EmitTraceSnapshot();
-}
-
-void Picture::GatherPixelRefs(
- const SkTileGridFactory::TileGridInfo& tile_grid_info) {
- TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
- "width", layer_rect_.width(),
- "height", layer_rect_.height());
-
- DCHECK(picture_);
- DCHECK(pixel_refs_.empty());
- if (!WillPlayBackBitmaps())
- return;
- cell_size_ = gfx::Size(
- tile_grid_info.fTileInterval.width() +
- 2 * tile_grid_info.fMargin.width(),
- tile_grid_info.fTileInterval.height() +
- 2 * tile_grid_info.fMargin.height());
- DCHECK_GT(cell_size_.width(), 0);
- DCHECK_GT(cell_size_.height(), 0);
-
- int min_x = std::numeric_limits<int>::max();
- int min_y = std::numeric_limits<int>::max();
- int max_x = 0;
- int max_y = 0;
-
- skia::DiscardablePixelRefList pixel_refs;
- skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_.get(), &pixel_refs);
- for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
- it != pixel_refs.end();
- ++it) {
- gfx::Point min(
- RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
- cell_size_.width()),
- RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
- cell_size_.height()));
- gfx::Point max(
- RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
- cell_size_.width()),
- RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
- cell_size_.height()));
-
- for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
- for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
- PixelRefMapKey key(x, y);
- pixel_refs_[key].push_back(it->pixel_ref);
- }
- }
-
- min_x = std::min(min_x, min.x());
- min_y = std::min(min_y, min.y());
- max_x = std::max(max_x, max.x());
- max_y = std::max(max_y, max.y());
- }
-
- min_pixel_cell_ = gfx::Point(min_x, min_y);
- max_pixel_cell_ = gfx::Point(max_x, max_y);
-}
-
-int Picture::Raster(SkCanvas* canvas,
- SkDrawPictureCallback* callback,
- const Region& negated_content_region,
- float contents_scale) const {
- TRACE_EVENT_BEGIN1(
- "cc",
- "Picture::Raster",
- "data",
- AsTraceableRasterData(contents_scale));
-
- DCHECK(picture_);
-
- canvas->save();
-
- for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
- canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
-
- canvas->scale(contents_scale, contents_scale);
- canvas->translate(layer_rect_.x(), layer_rect_.y());
- if (callback) {
- // If we have a callback, we need to call |draw()|, |drawPicture()| doesn't
- // take a callback. This is used by |AnalysisCanvas| to early out.
- picture_->draw(canvas, callback);
- } else {
- // Prefer to call |drawPicture()| on the canvas since it could place the
- // entire picture on the canvas instead of parsing the skia operations.
- canvas->drawPicture(picture_.get());
- }
- SkIRect bounds;
- canvas->getClipDeviceBounds(&bounds);
- canvas->restore();
- TRACE_EVENT_END1(
- "cc", "Picture::Raster",
- "num_pixels_rasterized", bounds.width() * bounds.height());
- return bounds.width() * bounds.height();
-}
-
-void Picture::Replay(SkCanvas* canvas) {
- TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
- DCHECK(picture_);
- picture_->draw(canvas);
- SkIRect bounds;
- canvas->getClipDeviceBounds(&bounds);
- TRACE_EVENT_END1("cc", "Picture::Replay",
- "num_pixels_replayed", bounds.width() * bounds.height());
-}
-
-scoped_ptr<base::Value> Picture::AsValue() const {
- SkDynamicMemoryWStream stream;
- picture_->serialize(&stream, &EncodeBitmap);
-
- // Encode the picture as base64.
- scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
- res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
-
- size_t serialized_size = stream.bytesWritten();
- scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
- stream.copyTo(serialized_picture.get());
- std::string b64_picture;
- base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
- &b64_picture);
- res->SetString("skp64", b64_picture);
- return res.Pass();
-}
-
-void Picture::EmitTraceSnapshot() const {
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
- "devtools.timeline.picture"),
- "cc::Picture",
- this,
- TracedPicture::AsTraceablePicture(this));
-}
-
-void Picture::EmitTraceSnapshotAlias(Picture* original) const {
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
- "devtools.timeline.picture"),
- "cc::Picture",
- this,
- TracedPicture::AsTraceablePictureAlias(original));
-}
-
-base::LazyInstance<Picture::PixelRefs>
- Picture::PixelRefIterator::empty_pixel_refs_;
-
-Picture::PixelRefIterator::PixelRefIterator()
- : picture_(NULL),
- current_pixel_refs_(empty_pixel_refs_.Pointer()),
- current_index_(0),
- min_point_(-1, -1),
- max_point_(-1, -1),
- current_x_(0),
- current_y_(0) {
-}
-
-Picture::PixelRefIterator::PixelRefIterator(
- const gfx::Rect& rect,
- const Picture* picture)
- : picture_(picture),
- current_pixel_refs_(empty_pixel_refs_.Pointer()),
- current_index_(0) {
- gfx::Rect layer_rect = picture->layer_rect_;
- gfx::Size cell_size = picture->cell_size_;
- DCHECK(!cell_size.IsEmpty());
-
- gfx::Rect query_rect(rect);
- // Early out if the query rect doesn't intersect this picture.
- if (!query_rect.Intersects(layer_rect)) {
- min_point_ = gfx::Point(0, 0);
- max_point_ = gfx::Point(0, 0);
- current_x_ = 1;
- current_y_ = 1;
- return;
- }
-
- // First, subtract the layer origin as cells are stored in layer space.
- query_rect.Offset(-layer_rect.OffsetFromOrigin());
-
- // We have to find a cell_size aligned point that corresponds to
- // query_rect. Point is a multiple of cell_size.
- min_point_ = gfx::Point(
- RoundDown(query_rect.x(), cell_size.width()),
- RoundDown(query_rect.y(), cell_size.height()));
- max_point_ = gfx::Point(
- RoundDown(query_rect.right() - 1, cell_size.width()),
- RoundDown(query_rect.bottom() - 1, cell_size.height()));
-
- // Limit the points to known pixel ref boundaries.
- min_point_ = gfx::Point(
- std::max(min_point_.x(), picture->min_pixel_cell_.x()),
- std::max(min_point_.y(), picture->min_pixel_cell_.y()));
- max_point_ = gfx::Point(
- std::min(max_point_.x(), picture->max_pixel_cell_.x()),
- std::min(max_point_.y(), picture->max_pixel_cell_.y()));
-
- // Make the current x be cell_size.width() less than min point, so that
- // the first increment will point at min_point_.
- current_x_ = min_point_.x() - cell_size.width();
- current_y_ = min_point_.y();
- if (current_y_ <= max_point_.y())
- ++(*this);
-}
-
-Picture::PixelRefIterator::~PixelRefIterator() {
-}
-
-Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
- ++current_index_;
- // If we're not at the end of the list, then we have the next item.
- if (current_index_ < current_pixel_refs_->size())
- return *this;
-
- DCHECK(current_y_ <= max_point_.y());
- while (true) {
- gfx::Size cell_size = picture_->cell_size_;
-
- // Advance the current grid cell.
- current_x_ += cell_size.width();
- if (current_x_ > max_point_.x()) {
- current_y_ += cell_size.height();
- current_x_ = min_point_.x();
- if (current_y_ > max_point_.y()) {
- current_pixel_refs_ = empty_pixel_refs_.Pointer();
- current_index_ = 0;
- break;
- }
- }
-
- // If there are no pixel refs at this grid cell, keep incrementing.
- PixelRefMapKey key(current_x_, current_y_);
- PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
- if (iter == picture_->pixel_refs_.end())
- continue;
-
- // We found a non-empty list: store it and get the first pixel ref.
- current_pixel_refs_ = &iter->second;
- current_index_ = 0;
- break;
- }
- return *this;
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
- Picture::AsTraceableRasterData(float scale) const {
- scoped_refptr<base::debug::TracedValue> raster_data =
- new base::debug::TracedValue();
- TracedValue::SetIDRef(this, raster_data.get(), "picture_id");
- raster_data->SetDouble("scale", scale);
- return raster_data;
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
- Picture::AsTraceableRecordData() const {
- scoped_refptr<base::debug::TracedValue> record_data =
- new base::debug::TracedValue();
- TracedValue::SetIDRef(this, record_data.get(), "picture_id");
- record_data->BeginArray("layer_rect");
- MathUtil::AddToTracedValue(layer_rect_, record_data.get());
- record_data->EndArray();
- return record_data;
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/picture_layer_tiling.cc b/chromium/cc/resources/picture_layer_tiling.cc
deleted file mode 100644
index d8885e7bc13..00000000000
--- a/chromium/cc/resources/picture_layer_tiling.cc
+++ /dev/null
@@ -1,1243 +0,0 @@
-// Copyright 2012 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/picture_layer_tiling.h"
-
-#include <algorithm>
-#include <cmath>
-#include <limits>
-#include <set>
-
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
-#include "base/logging.h"
-#include "cc/base/math_util.h"
-#include "cc/resources/tile.h"
-#include "cc/resources/tile_priority.h"
-#include "ui/gfx/geometry/point_conversions.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/geometry/safe_integer_conversions.h"
-#include "ui/gfx/geometry/size_conversions.h"
-
-namespace cc {
-namespace {
-
-const float kSoonBorderDistanceInScreenPixels = 312.f;
-
-class TileEvictionOrder {
- public:
- explicit TileEvictionOrder(TreePriority tree_priority)
- : tree_priority_(tree_priority) {}
- ~TileEvictionOrder() {}
-
- bool operator()(const Tile* a, const Tile* b) {
- const TilePriority& a_priority =
- a->priority_for_tree_priority(tree_priority_);
- const TilePriority& b_priority =
- b->priority_for_tree_priority(tree_priority_);
-
- DCHECK(a_priority.priority_bin == b_priority.priority_bin);
- DCHECK(a->required_for_activation() == b->required_for_activation());
-
- // Or if a is occluded and b is unoccluded.
- bool a_is_occluded = a->is_occluded_for_tree_priority(tree_priority_);
- bool b_is_occluded = b->is_occluded_for_tree_priority(tree_priority_);
- if (a_is_occluded != b_is_occluded)
- return a_is_occluded;
-
- // Or if a is farther away from visible.
- return a_priority.distance_to_visible > b_priority.distance_to_visible;
- }
-
- private:
- TreePriority tree_priority_;
-};
-
-} // namespace
-
-scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
- float contents_scale,
- const gfx::Size& layer_bounds,
- PictureLayerTilingClient* client) {
- return make_scoped_ptr(new PictureLayerTiling(contents_scale,
- layer_bounds,
- client));
-}
-
-PictureLayerTiling::PictureLayerTiling(float contents_scale,
- const gfx::Size& layer_bounds,
- PictureLayerTilingClient* client)
- : contents_scale_(contents_scale),
- layer_bounds_(layer_bounds),
- resolution_(NON_IDEAL_RESOLUTION),
- client_(client),
- tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels),
- last_impl_frame_time_in_seconds_(0.0),
- content_to_screen_scale_(0.f),
- can_require_tiles_for_activation_(false),
- has_visible_rect_tiles_(false),
- has_skewport_rect_tiles_(false),
- has_soon_border_rect_tiles_(false),
- has_eventually_rect_tiles_(false),
- eviction_tiles_cache_valid_(false),
- eviction_cache_tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES) {
- gfx::Size content_bounds =
- gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale));
- gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
- if (tile_size.IsEmpty()) {
- layer_bounds_ = gfx::Size();
- content_bounds = gfx::Size();
- }
-
- DCHECK(!gfx::ToFlooredSize(
- gfx::ScaleSize(layer_bounds, contents_scale)).IsEmpty()) <<
- "Tiling created with scale too small as contents become empty." <<
- " Layer bounds: " << layer_bounds.ToString() <<
- " Contents scale: " << contents_scale;
-
- tiling_data_.SetTilingSize(content_bounds);
- tiling_data_.SetMaxTextureSize(tile_size);
-}
-
-PictureLayerTiling::~PictureLayerTiling() {
- for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
- it->second->set_shared(false);
-}
-
-void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) {
- client_ = client;
-}
-
-Tile* PictureLayerTiling::CreateTile(int i,
- int j,
- const PictureLayerTiling* twin_tiling) {
- TileMapKey key(i, j);
- DCHECK(tiles_.find(key) == tiles_.end());
-
- gfx::Rect paint_rect = tiling_data_.TileBoundsWithBorder(i, j);
- gfx::Rect tile_rect = paint_rect;
- tile_rect.set_size(tiling_data_.max_texture_size());
-
- // Check our twin for a valid tile.
- if (twin_tiling &&
- tiling_data_.max_texture_size() ==
- twin_tiling->tiling_data_.max_texture_size()) {
- if (Tile* candidate_tile = twin_tiling->TileAt(i, j)) {
- gfx::Rect rect =
- gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_);
- const Region* invalidation = client_->GetPendingInvalidation();
- if (!invalidation || !invalidation->Intersects(rect)) {
- DCHECK(!candidate_tile->is_shared());
- DCHECK_EQ(i, candidate_tile->tiling_i_index());
- DCHECK_EQ(j, candidate_tile->tiling_j_index());
- candidate_tile->set_shared(true);
- tiles_[key] = candidate_tile;
- return candidate_tile;
- }
- }
- }
-
- // Create a new tile because our twin didn't have a valid one.
- scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect);
- if (tile.get()) {
- DCHECK(!tile->is_shared());
- tile->set_tiling_index(i, j);
- tiles_[key] = tile;
- }
- eviction_tiles_cache_valid_ = false;
- return tile.get();
-}
-
-void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
- const PictureLayerTiling* twin_tiling =
- client_->GetPendingOrActiveTwinTiling(this);
- bool include_borders = false;
- for (TilingData::Iterator iter(
- &tiling_data_, live_tiles_rect_, include_borders);
- iter;
- ++iter) {
- TileMapKey key = iter.index();
- TileMap::iterator find = tiles_.find(key);
- if (find != tiles_.end())
- continue;
- CreateTile(key.first, key.second, twin_tiling);
- }
-
- VerifyLiveTilesRect();
-}
-
-void PictureLayerTiling::UpdateTilesToCurrentPile(
- const Region& layer_invalidation,
- const gfx::Size& new_layer_bounds) {
- DCHECK(!new_layer_bounds.IsEmpty());
-
- gfx::Size tile_size = tiling_data_.max_texture_size();
-
- if (new_layer_bounds != layer_bounds_) {
- gfx::Size content_bounds =
- gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
-
- tile_size = client_->CalculateTileSize(content_bounds);
- if (tile_size.IsEmpty()) {
- layer_bounds_ = gfx::Size();
- content_bounds = gfx::Size();
- } else {
- layer_bounds_ = new_layer_bounds;
- }
-
- // The SetLiveTilesRect() method would drop tiles outside the new bounds,
- // but may do so incorrectly if resizing the tiling causes the number of
- // tiles in the tiling_data_ to change.
- gfx::Rect content_rect(content_bounds);
- int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x());
- int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y());
- int before_right =
- tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
- int before_bottom =
- tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
-
- // The live_tiles_rect_ is clamped to stay within the tiling size as we
- // change it.
- live_tiles_rect_.Intersect(content_rect);
- tiling_data_.SetTilingSize(content_bounds);
-
- int after_right = -1;
- int after_bottom = -1;
- if (!live_tiles_rect_.IsEmpty()) {
- after_right =
- tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
- after_bottom =
- tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
- }
-
- // There is no recycled twin since this is run on the pending tiling.
- PictureLayerTiling* recycled_twin = NULL;
- DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this));
- DCHECK_EQ(PENDING_TREE, client_->GetTree());
-
- // Drop tiles outside the new layer bounds if the layer shrank.
- for (int i = after_right + 1; i <= before_right; ++i) {
- for (int j = before_top; j <= before_bottom; ++j)
- RemoveTileAt(i, j, recycled_twin);
- }
- for (int i = before_left; i <= after_right; ++i) {
- for (int j = after_bottom + 1; j <= before_bottom; ++j)
- RemoveTileAt(i, j, recycled_twin);
- }
-
- // If the layer grew, the live_tiles_rect_ is not changed, but a new row
- // and/or column of tiles may now exist inside the same live_tiles_rect_.
- const PictureLayerTiling* twin_tiling =
- client_->GetPendingOrActiveTwinTiling(this);
- if (after_right > before_right) {
- DCHECK_EQ(after_right, before_right + 1);
- for (int j = before_top; j <= after_bottom; ++j)
- CreateTile(after_right, j, twin_tiling);
- }
- if (after_bottom > before_bottom) {
- DCHECK_EQ(after_bottom, before_bottom + 1);
- for (int i = before_left; i <= before_right; ++i)
- CreateTile(i, after_bottom, twin_tiling);
- }
- }
-
- if (tile_size != tiling_data_.max_texture_size()) {
- tiling_data_.SetMaxTextureSize(tile_size);
- // When the tile size changes, the TilingData positions no longer work
- // as valid keys to the TileMap, so just drop all tiles.
- Reset();
- } else {
- Invalidate(layer_invalidation);
- }
-
- RasterSource* raster_source = client_->GetRasterSource();
- for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
- it->second->set_raster_source(raster_source);
- VerifyLiveTilesRect();
-}
-
-void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) {
- bool recreate_invalidated_tiles = false;
- DoInvalidate(layer_region, recreate_invalidated_tiles);
-}
-
-void PictureLayerTiling::Invalidate(const Region& layer_region) {
- bool recreate_invalidated_tiles = true;
- DoInvalidate(layer_region, recreate_invalidated_tiles);
-}
-
-void PictureLayerTiling::DoInvalidate(const Region& layer_region,
- bool recreate_invalidated_tiles) {
- std::vector<TileMapKey> new_tile_keys;
- gfx::Rect expanded_live_tiles_rect =
- tiling_data_.ExpandRectIgnoringBordersToTileBounds(live_tiles_rect_);
- for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) {
- gfx::Rect layer_rect = iter.rect();
- gfx::Rect content_rect =
- gfx::ScaleToEnclosingRect(layer_rect, contents_scale_);
- // Consider tiles inside the live tiles rect even if only their border
- // pixels intersect the invalidation. But don't consider tiles outside
- // the live tiles rect with the same conditions, as they won't exist.
- int border_pixels = tiling_data_.border_texels();
- content_rect.Inset(-border_pixels, -border_pixels);
- // Avoid needless work by not bothering to invalidate where there aren't
- // tiles.
- content_rect.Intersect(expanded_live_tiles_rect);
- if (content_rect.IsEmpty())
- continue;
- // Since the content_rect includes border pixels already, don't include
- // borders when iterating to avoid double counting them.
- bool include_borders = false;
- for (TilingData::Iterator iter(
- &tiling_data_, content_rect, include_borders);
- iter;
- ++iter) {
- // There is no recycled twin since this is run on the pending tiling.
- PictureLayerTiling* recycled_twin = NULL;
- DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this));
- DCHECK_EQ(PENDING_TREE, client_->GetTree());
- if (RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin))
- new_tile_keys.push_back(iter.index());
- }
- }
-
- if (recreate_invalidated_tiles && !new_tile_keys.empty()) {
- for (size_t i = 0; i < new_tile_keys.size(); ++i) {
- // Don't try to share a tile with the twin layer, it's been invalidated so
- // we have to make our own tile here.
- const PictureLayerTiling* twin_tiling = NULL;
- CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling);
- }
- }
-}
-
-PictureLayerTiling::CoverageIterator::CoverageIterator()
- : tiling_(NULL),
- current_tile_(NULL),
- tile_i_(0),
- tile_j_(0),
- left_(0),
- top_(0),
- right_(-1),
- bottom_(-1) {
-}
-
-PictureLayerTiling::CoverageIterator::CoverageIterator(
- const PictureLayerTiling* tiling,
- float dest_scale,
- const gfx::Rect& dest_rect)
- : tiling_(tiling),
- dest_rect_(dest_rect),
- dest_to_content_scale_(0),
- current_tile_(NULL),
- tile_i_(0),
- tile_j_(0),
- left_(0),
- top_(0),
- right_(-1),
- bottom_(-1) {
- DCHECK(tiling_);
- if (dest_rect_.IsEmpty())
- return;
-
- dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale;
-
- gfx::Rect content_rect =
- gfx::ScaleToEnclosingRect(dest_rect_,
- dest_to_content_scale_,
- dest_to_content_scale_);
- // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to
- // check for non-intersection first.
- content_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
- if (content_rect.IsEmpty())
- return;
-
- left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x());
- top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y());
- right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(
- content_rect.right() - 1);
- bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(
- content_rect.bottom() - 1);
-
- tile_i_ = left_ - 1;
- tile_j_ = top_;
- ++(*this);
-}
-
-PictureLayerTiling::CoverageIterator::~CoverageIterator() {
-}
-
-PictureLayerTiling::CoverageIterator&
-PictureLayerTiling::CoverageIterator::operator++() {
- if (tile_j_ > bottom_)
- return *this;
-
- bool first_time = tile_i_ < left_;
- bool new_row = false;
- tile_i_++;
- if (tile_i_ > right_) {
- tile_i_ = left_;
- tile_j_++;
- new_row = true;
- if (tile_j_ > bottom_) {
- current_tile_ = NULL;
- return *this;
- }
- }
-
- current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
-
- // Calculate the current geometry rect. Due to floating point rounding
- // and ToEnclosingRect, tiles might overlap in destination space on the
- // edges.
- gfx::Rect last_geometry_rect = current_geometry_rect_;
-
- gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_);
-
- current_geometry_rect_ =
- gfx::ScaleToEnclosingRect(content_rect,
- 1 / dest_to_content_scale_,
- 1 / dest_to_content_scale_);
-
- current_geometry_rect_.Intersect(dest_rect_);
-
- if (first_time)
- return *this;
-
- // Iteration happens left->right, top->bottom. Running off the bottom-right
- // edge is handled by the intersection above with dest_rect_. Here we make
- // sure that the new current geometry rect doesn't overlap with the last.
- int min_left;
- int min_top;
- if (new_row) {
- min_left = dest_rect_.x();
- min_top = last_geometry_rect.bottom();
- } else {
- min_left = last_geometry_rect.right();
- min_top = last_geometry_rect.y();
- }
-
- int inset_left = std::max(0, min_left - current_geometry_rect_.x());
- int inset_top = std::max(0, min_top - current_geometry_rect_.y());
- current_geometry_rect_.Inset(inset_left, inset_top, 0, 0);
-
- if (!new_row) {
- DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
- DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom());
- DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y());
- }
-
- return *this;
-}
-
-gfx::Rect PictureLayerTiling::CoverageIterator::geometry_rect() const {
- return current_geometry_rect_;
-}
-
-gfx::Rect
-PictureLayerTiling::CoverageIterator::full_tile_geometry_rect() const {
- gfx::Rect rect = tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_);
- rect.set_size(tiling_->tiling_data_.max_texture_size());
- return rect;
-}
-
-gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const {
- gfx::PointF tex_origin =
- tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_).origin();
-
- // Convert from dest space => content space => texture space.
- gfx::RectF texture_rect(current_geometry_rect_);
- texture_rect.Scale(dest_to_content_scale_,
- dest_to_content_scale_);
- texture_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
- if (texture_rect.IsEmpty())
- return texture_rect;
- texture_rect.Offset(-tex_origin.OffsetFromOrigin());
-
- return texture_rect;
-}
-
-gfx::Size PictureLayerTiling::CoverageIterator::texture_size() const {
- return tiling_->tiling_data_.max_texture_size();
-}
-
-bool PictureLayerTiling::RemoveTileAt(int i,
- int j,
- PictureLayerTiling* recycled_twin) {
- TileMap::iterator found = tiles_.find(TileMapKey(i, j));
- if (found == tiles_.end())
- return false;
- found->second->set_shared(false);
- tiles_.erase(found);
- eviction_tiles_cache_valid_ = false;
- if (recycled_twin) {
- // Recycled twin does not also have a recycled twin, so pass NULL.
- recycled_twin->RemoveTileAt(i, j, NULL);
- }
- return true;
-}
-
-void PictureLayerTiling::Reset() {
- live_tiles_rect_ = gfx::Rect();
- PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
- for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
- it->second->set_shared(false);
- if (recycled_twin)
- recycled_twin->RemoveTileAt(it->first.first, it->first.second, NULL);
- }
- tiles_.clear();
- eviction_tiles_cache_valid_ = false;
-}
-
-gfx::Rect PictureLayerTiling::ComputeSkewport(
- double current_frame_time_in_seconds,
- const gfx::Rect& visible_rect_in_content_space) const {
- gfx::Rect skewport = visible_rect_in_content_space;
- if (last_impl_frame_time_in_seconds_ == 0.0)
- return skewport;
-
- double time_delta =
- current_frame_time_in_seconds - last_impl_frame_time_in_seconds_;
- if (time_delta == 0.0)
- return skewport;
-
- float skewport_target_time_in_seconds =
- client_->GetSkewportTargetTimeInSeconds();
- double extrapolation_multiplier =
- skewport_target_time_in_seconds / time_delta;
-
- int old_x = last_visible_rect_in_content_space_.x();
- int old_y = last_visible_rect_in_content_space_.y();
- int old_right = last_visible_rect_in_content_space_.right();
- int old_bottom = last_visible_rect_in_content_space_.bottom();
-
- int new_x = visible_rect_in_content_space.x();
- int new_y = visible_rect_in_content_space.y();
- int new_right = visible_rect_in_content_space.right();
- int new_bottom = visible_rect_in_content_space.bottom();
-
- int skewport_limit = client_->GetSkewportExtrapolationLimitInContentPixels();
-
- // Compute the maximum skewport based on |skewport_limit|.
- gfx::Rect max_skewport = skewport;
- max_skewport.Inset(
- -skewport_limit, -skewport_limit, -skewport_limit, -skewport_limit);
-
- // Inset the skewport by the needed adjustment.
- skewport.Inset(extrapolation_multiplier * (new_x - old_x),
- extrapolation_multiplier * (new_y - old_y),
- extrapolation_multiplier * (old_right - new_right),
- extrapolation_multiplier * (old_bottom - new_bottom));
-
- // Clip the skewport to |max_skewport|.
- skewport.Intersect(max_skewport);
-
- // Finally, ensure that visible rect is contained in the skewport.
- skewport.Union(visible_rect_in_content_space);
- return skewport;
-}
-
-void PictureLayerTiling::ComputeTilePriorityRects(
- WhichTree tree,
- const gfx::Rect& viewport_in_layer_space,
- float ideal_contents_scale,
- double current_frame_time_in_seconds,
- const Occlusion& occlusion_in_layer_space) {
- if (!NeedsUpdateForFrameAtTimeAndViewport(current_frame_time_in_seconds,
- viewport_in_layer_space)) {
- // This should never be zero for the purposes of has_ever_been_updated().
- DCHECK_NE(current_frame_time_in_seconds, 0.0);
- return;
- }
-
- gfx::Rect visible_rect_in_content_space =
- gfx::ScaleToEnclosingRect(viewport_in_layer_space, contents_scale_);
-
- if (tiling_size().IsEmpty()) {
- last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
- last_viewport_in_layer_space_ = viewport_in_layer_space;
- last_visible_rect_in_content_space_ = visible_rect_in_content_space;
- return;
- }
-
- // Calculate the skewport.
- gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds,
- visible_rect_in_content_space);
- DCHECK(skewport.Contains(visible_rect_in_content_space));
-
- // Calculate the eventually/live tiles rect.
- size_t max_tiles_for_interest_area = client_->GetMaxTilesForInterestArea();
-
- gfx::Size tile_size = tiling_data_.max_texture_size();
- int64 eventually_rect_area =
- max_tiles_for_interest_area * tile_size.width() * tile_size.height();
-
- gfx::Rect eventually_rect =
- ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space,
- eventually_rect_area,
- gfx::Rect(tiling_size()),
- &expansion_cache_);
-
- DCHECK(eventually_rect.IsEmpty() ||
- gfx::Rect(tiling_size()).Contains(eventually_rect))
- << "tiling_size: " << tiling_size().ToString()
- << " eventually_rect: " << eventually_rect.ToString();
-
- // Calculate the soon border rect.
- content_to_screen_scale_ = ideal_contents_scale / contents_scale_;
- gfx::Rect soon_border_rect = visible_rect_in_content_space;
- float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale_;
- soon_border_rect.Inset(-border, -border, -border, -border);
-
- // Update the tiling state.
- SetLiveTilesRect(eventually_rect);
-
- last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
- last_viewport_in_layer_space_ = viewport_in_layer_space;
- last_visible_rect_in_content_space_ = visible_rect_in_content_space;
-
- eviction_tiles_cache_valid_ = false;
-
- current_visible_rect_ = visible_rect_in_content_space;
- current_skewport_rect_ = skewport;
- current_soon_border_rect_ = soon_border_rect;
- current_eventually_rect_ = eventually_rect;
- current_occlusion_in_layer_space_ = occlusion_in_layer_space;
-
- // Update has_*_tiles state.
- gfx::Rect tiling_rect(tiling_size());
-
- has_visible_rect_tiles_ = tiling_rect.Intersects(current_visible_rect_);
- has_skewport_rect_tiles_ = tiling_rect.Intersects(current_skewport_rect_);
- has_soon_border_rect_tiles_ =
- tiling_rect.Intersects(current_soon_border_rect_);
- has_eventually_rect_tiles_ = tiling_rect.Intersects(current_eventually_rect_);
-}
-
-void PictureLayerTiling::SetLiveTilesRect(
- const gfx::Rect& new_live_tiles_rect) {
- DCHECK(new_live_tiles_rect.IsEmpty() ||
- gfx::Rect(tiling_size()).Contains(new_live_tiles_rect))
- << "tiling_size: " << tiling_size().ToString()
- << " new_live_tiles_rect: " << new_live_tiles_rect.ToString();
- if (live_tiles_rect_ == new_live_tiles_rect)
- return;
-
- // Iterate to delete all tiles outside of our new live_tiles rect.
- PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
- for (TilingData::DifferenceIterator iter(&tiling_data_,
- live_tiles_rect_,
- new_live_tiles_rect);
- iter;
- ++iter) {
- RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin);
- }
-
- const PictureLayerTiling* twin_tiling =
- client_->GetPendingOrActiveTwinTiling(this);
-
- // Iterate to allocate new tiles for all regions with newly exposed area.
- for (TilingData::DifferenceIterator iter(&tiling_data_,
- new_live_tiles_rect,
- live_tiles_rect_);
- iter;
- ++iter) {
- TileMapKey key(iter.index());
- CreateTile(key.first, key.second, twin_tiling);
- }
-
- live_tiles_rect_ = new_live_tiles_rect;
- VerifyLiveTilesRect();
-}
-
-void PictureLayerTiling::VerifyLiveTilesRect() {
-#if DCHECK_IS_ON
- for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
- if (!it->second.get())
- continue;
- DCHECK(it->first.first < tiling_data_.num_tiles_x())
- << this << " " << it->first.first << "," << it->first.second
- << " num_tiles_x " << tiling_data_.num_tiles_x() << " live_tiles_rect "
- << live_tiles_rect_.ToString();
- DCHECK(it->first.second < tiling_data_.num_tiles_y())
- << this << " " << it->first.first << "," << it->first.second
- << " num_tiles_y " << tiling_data_.num_tiles_y() << " live_tiles_rect "
- << live_tiles_rect_.ToString();
- DCHECK(tiling_data_.TileBounds(it->first.first, it->first.second)
- .Intersects(live_tiles_rect_))
- << this << " " << it->first.first << "," << it->first.second
- << " tile bounds "
- << tiling_data_.TileBounds(it->first.first, it->first.second).ToString()
- << " live_tiles_rect " << live_tiles_rect_.ToString();
- }
-#endif
-}
-
-bool PictureLayerTiling::IsTileOccluded(const Tile* tile) const {
- DCHECK(tile);
-
- if (!current_occlusion_in_layer_space_.HasOcclusion())
- return false;
-
- gfx::Rect tile_query_rect =
- gfx::IntersectRects(tile->content_rect(), current_visible_rect_);
-
- // Explicitly check if the tile is outside the viewport. If so, we need to
- // return false, since occlusion for this tile is unknown.
- // TODO(vmpstr): Since the current visible rect is really a viewport in
- // layer space, we should probably clip tile query rect to tiling bounds
- // or live tiles rect.
- if (tile_query_rect.IsEmpty())
- return false;
-
- if (contents_scale_ != 1.f) {
- tile_query_rect =
- gfx::ScaleToEnclosingRect(tile_query_rect, 1.0f / contents_scale_);
- }
-
- return current_occlusion_in_layer_space_.IsOccluded(tile_query_rect);
-}
-
-bool PictureLayerTiling::IsTileRequiredForActivation(const Tile* tile) const {
- DCHECK_EQ(PENDING_TREE, client_->GetTree());
-
- // Note that although this function will determine whether tile is required
- // for activation assuming that it is in visible (ie in the viewport). That is
- // to say, even if the tile is outside of the viewport, it will be treated as
- // if it was inside (there are no explicit checks for this). Hence, this
- // function is only called for visible tiles to ensure we don't block
- // activation on tiles outside of the viewport.
-
- // If we are not allowed to mark tiles as required for activation, then don't
- // do it.
- if (!can_require_tiles_for_activation_)
- return false;
-
- if (resolution_ != HIGH_RESOLUTION)
- return false;
-
- if (IsTileOccluded(tile))
- return false;
-
- if (client_->RequiresHighResToDraw())
- return true;
-
- const PictureLayerTiling* twin_tiling =
- client_->GetPendingOrActiveTwinTiling(this);
- if (!twin_tiling)
- return true;
-
- if (twin_tiling->layer_bounds() != layer_bounds())
- return true;
-
- if (twin_tiling->current_visible_rect_ != current_visible_rect_)
- return true;
-
- Tile* twin_tile =
- twin_tiling->TileAt(tile->tiling_i_index(), tile->tiling_j_index());
- // If twin tile is missing, it might not have a recording, so we don't need
- // this tile to be required for activation.
- if (!twin_tile)
- return false;
-
- return true;
-}
-
-void PictureLayerTiling::UpdateTileAndTwinPriority(Tile* tile) const {
- UpdateTilePriority(tile);
-
- const PictureLayerTiling* twin_tiling =
- client_->GetPendingOrActiveTwinTiling(this);
- if (!tile->is_shared() || !twin_tiling) {
- WhichTree tree = client_->GetTree();
- WhichTree twin_tree = tree == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE;
- tile->SetPriority(twin_tree, TilePriority());
- tile->set_is_occluded(twin_tree, false);
- if (twin_tree == PENDING_TREE)
- tile->set_required_for_activation(false);
- return;
- }
-
- twin_tiling->UpdateTilePriority(tile);
-}
-
-void PictureLayerTiling::UpdateTilePriority(Tile* tile) const {
- // TODO(vmpstr): This code should return the priority instead of setting it on
- // the tile. This should be a part of the change to move tile priority from
- // tiles into iterators.
- WhichTree tree = client_->GetTree();
-
- DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile);
- gfx::Rect tile_bounds =
- tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
-
- if (current_visible_rect_.Intersects(tile_bounds)) {
- tile->SetPriority(tree, TilePriority(resolution_, TilePriority::NOW, 0));
- if (tree == PENDING_TREE)
- tile->set_required_for_activation(IsTileRequiredForActivation(tile));
- tile->set_is_occluded(tree, IsTileOccluded(tile));
- return;
- }
-
- if (tree == PENDING_TREE)
- tile->set_required_for_activation(false);
- tile->set_is_occluded(tree, false);
-
- DCHECK_GT(content_to_screen_scale_, 0.f);
- float distance_to_visible =
- current_visible_rect_.ManhattanInternalDistance(tile_bounds) *
- content_to_screen_scale_;
-
- if (current_soon_border_rect_.Intersects(tile_bounds) ||
- current_skewport_rect_.Intersects(tile_bounds)) {
- tile->SetPriority(
- tree,
- TilePriority(resolution_, TilePriority::SOON, distance_to_visible));
- return;
- }
-
- tile->SetPriority(
- tree,
- TilePriority(resolution_, TilePriority::EVENTUALLY, distance_to_visible));
-}
-
-void PictureLayerTiling::GetAllTilesForTracing(
- std::set<const Tile*>* tiles) const {
- for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
- tiles->insert(it->second.get());
-}
-
-void PictureLayerTiling::AsValueInto(base::debug::TracedValue* state) const {
- state->SetInteger("num_tiles", tiles_.size());
- state->SetDouble("content_scale", contents_scale_);
- state->BeginDictionary("tiling_size");
- MathUtil::AddToTracedValue(tiling_size(), state);
- state->EndDictionary();
-}
-
-size_t PictureLayerTiling::GPUMemoryUsageInBytes() const {
- size_t amount = 0;
- for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
- const Tile* tile = it->second.get();
- amount += tile->GPUMemoryUsageInBytes();
- }
- return amount;
-}
-
-PictureLayerTiling::RectExpansionCache::RectExpansionCache()
- : previous_target(0) {
-}
-
-namespace {
-
-// This struct represents an event at which the expending rect intersects
-// one of its boundaries. 4 intersection events will occur during expansion.
-struct EdgeEvent {
- enum { BOTTOM, TOP, LEFT, RIGHT } edge;
- int* num_edges;
- int distance;
-};
-
-// Compute the delta to expand from edges to cover target_area.
-int ComputeExpansionDelta(int num_x_edges, int num_y_edges,
- int width, int height,
- int64 target_area) {
- // Compute coefficients for the quadratic equation:
- // a*x^2 + b*x + c = 0
- int a = num_y_edges * num_x_edges;
- int b = num_y_edges * width + num_x_edges * height;
- int64 c = static_cast<int64>(width) * height - target_area;
-
- // Compute the delta for our edges using the quadratic equation.
- int delta =
- (a == 0) ? -c / b : (-b + static_cast<int>(std::sqrt(
- static_cast<int64>(b) * b - 4.0 * a * c))) /
- (2 * a);
- return std::max(0, delta);
-}
-
-} // namespace
-
-gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy(
- const gfx::Rect& starting_rect,
- int64 target_area,
- const gfx::Rect& bounding_rect,
- RectExpansionCache* cache) {
- if (starting_rect.IsEmpty())
- return starting_rect;
-
- if (cache &&
- cache->previous_start == starting_rect &&
- cache->previous_bounds == bounding_rect &&
- cache->previous_target == target_area)
- return cache->previous_result;
-
- if (cache) {
- cache->previous_start = starting_rect;
- cache->previous_bounds = bounding_rect;
- cache->previous_target = target_area;
- }
-
- DCHECK(!bounding_rect.IsEmpty());
- DCHECK_GT(target_area, 0);
-
- // Expand the starting rect to cover target_area, if it is smaller than it.
- int delta = ComputeExpansionDelta(
- 2, 2, starting_rect.width(), starting_rect.height(), target_area);
- gfx::Rect expanded_starting_rect = starting_rect;
- if (delta > 0)
- expanded_starting_rect.Inset(-delta, -delta);
-
- gfx::Rect rect = IntersectRects(expanded_starting_rect, bounding_rect);
- if (rect.IsEmpty()) {
- // The starting_rect and bounding_rect are far away.
- if (cache)
- cache->previous_result = rect;
- return rect;
- }
- if (delta >= 0 && rect == expanded_starting_rect) {
- // The starting rect already covers the entire bounding_rect and isn't too
- // large for the target_area.
- if (cache)
- cache->previous_result = rect;
- return rect;
- }
-
- // Continue to expand/shrink rect to let it cover target_area.
-
- // These values will be updated by the loop and uses as the output.
- int origin_x = rect.x();
- int origin_y = rect.y();
- int width = rect.width();
- int height = rect.height();
-
- // In the beginning we will consider 2 edges in each dimension.
- int num_y_edges = 2;
- int num_x_edges = 2;
-
- // Create an event list.
- EdgeEvent events[] = {
- { EdgeEvent::BOTTOM, &num_y_edges, rect.y() - bounding_rect.y() },
- { EdgeEvent::TOP, &num_y_edges, bounding_rect.bottom() - rect.bottom() },
- { EdgeEvent::LEFT, &num_x_edges, rect.x() - bounding_rect.x() },
- { EdgeEvent::RIGHT, &num_x_edges, bounding_rect.right() - rect.right() }
- };
-
- // Sort the events by distance (closest first).
- if (events[0].distance > events[1].distance) std::swap(events[0], events[1]);
- if (events[2].distance > events[3].distance) std::swap(events[2], events[3]);
- if (events[0].distance > events[2].distance) std::swap(events[0], events[2]);
- if (events[1].distance > events[3].distance) std::swap(events[1], events[3]);
- if (events[1].distance > events[2].distance) std::swap(events[1], events[2]);
-
- for (int event_index = 0; event_index < 4; event_index++) {
- const EdgeEvent& event = events[event_index];
-
- int delta = ComputeExpansionDelta(
- num_x_edges, num_y_edges, width, height, target_area);
-
- // Clamp delta to our event distance.
- if (delta > event.distance)
- delta = event.distance;
-
- // Adjust the edge count for this kind of edge.
- --*event.num_edges;
-
- // Apply the delta to the edges and edge events.
- for (int i = event_index; i < 4; i++) {
- switch (events[i].edge) {
- case EdgeEvent::BOTTOM:
- origin_y -= delta;
- height += delta;
- break;
- case EdgeEvent::TOP:
- height += delta;
- break;
- case EdgeEvent::LEFT:
- origin_x -= delta;
- width += delta;
- break;
- case EdgeEvent::RIGHT:
- width += delta;
- break;
- }
- events[i].distance -= delta;
- }
-
- // If our delta is less then our event distance, we're done.
- if (delta < event.distance)
- break;
- }
-
- gfx::Rect result(origin_x, origin_y, width, height);
- if (cache)
- cache->previous_result = result;
- return result;
-}
-
-void PictureLayerTiling::UpdateEvictionCacheIfNeeded(
- TreePriority tree_priority) {
- if (eviction_tiles_cache_valid_ &&
- eviction_cache_tree_priority_ == tree_priority)
- return;
-
- eviction_tiles_now_.clear();
- eviction_tiles_now_and_required_for_activation_.clear();
- eviction_tiles_soon_.clear();
- eviction_tiles_soon_and_required_for_activation_.clear();
- eviction_tiles_eventually_.clear();
- eviction_tiles_eventually_and_required_for_activation_.clear();
-
- for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
- Tile* tile = it->second.get();
- UpdateTileAndTwinPriority(tile);
- const TilePriority& priority =
- tile->priority_for_tree_priority(tree_priority);
- switch (priority.priority_bin) {
- case TilePriority::EVENTUALLY:
- if (tile->required_for_activation())
- eviction_tiles_eventually_and_required_for_activation_.push_back(
- tile);
- else
- eviction_tiles_eventually_.push_back(tile);
- break;
- case TilePriority::SOON:
- if (tile->required_for_activation())
- eviction_tiles_soon_and_required_for_activation_.push_back(tile);
- else
- eviction_tiles_soon_.push_back(tile);
- break;
- case TilePriority::NOW:
- if (tile->required_for_activation())
- eviction_tiles_now_and_required_for_activation_.push_back(tile);
- else
- eviction_tiles_now_.push_back(tile);
- break;
- }
- }
-
- // TODO(vmpstr): Do this lazily. One option is to have a "sorted" flag that
- // can be updated for each of the queues.
- TileEvictionOrder sort_order(tree_priority);
- std::sort(eviction_tiles_now_.begin(), eviction_tiles_now_.end(), sort_order);
- std::sort(eviction_tiles_now_and_required_for_activation_.begin(),
- eviction_tiles_now_and_required_for_activation_.end(),
- sort_order);
- std::sort(
- eviction_tiles_soon_.begin(), eviction_tiles_soon_.end(), sort_order);
- std::sort(eviction_tiles_soon_and_required_for_activation_.begin(),
- eviction_tiles_soon_and_required_for_activation_.end(),
- sort_order);
- std::sort(eviction_tiles_eventually_.begin(),
- eviction_tiles_eventually_.end(),
- sort_order);
- std::sort(eviction_tiles_eventually_and_required_for_activation_.begin(),
- eviction_tiles_eventually_and_required_for_activation_.end(),
- sort_order);
-
- eviction_tiles_cache_valid_ = true;
- eviction_cache_tree_priority_ = tree_priority;
-}
-
-const std::vector<Tile*>* PictureLayerTiling::GetEvictionTiles(
- TreePriority tree_priority,
- EvictionCategory category) {
- UpdateEvictionCacheIfNeeded(tree_priority);
- switch (category) {
- case EVENTUALLY:
- return &eviction_tiles_eventually_;
- case EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
- return &eviction_tiles_eventually_and_required_for_activation_;
- case SOON:
- return &eviction_tiles_soon_;
- case SOON_AND_REQUIRED_FOR_ACTIVATION:
- return &eviction_tiles_soon_and_required_for_activation_;
- case NOW:
- return &eviction_tiles_now_;
- case NOW_AND_REQUIRED_FOR_ACTIVATION:
- return &eviction_tiles_now_and_required_for_activation_;
- }
- NOTREACHED();
- return &eviction_tiles_eventually_;
-}
-
-PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator()
- : tiling_(NULL), current_tile_(NULL) {}
-
-PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator(
- PictureLayerTiling* tiling)
- : tiling_(tiling), phase_(VISIBLE_RECT), current_tile_(NULL) {
- if (!tiling_->has_visible_rect_tiles_) {
- AdvancePhase();
- return;
- }
-
- visible_iterator_ = TilingData::Iterator(&tiling_->tiling_data_,
- tiling_->current_visible_rect_,
- false /* include_borders */);
- if (!visible_iterator_) {
- AdvancePhase();
- return;
- }
-
- current_tile_ =
- tiling_->TileAt(visible_iterator_.index_x(), visible_iterator_.index_y());
- if (!current_tile_ || !TileNeedsRaster(current_tile_)) {
- ++(*this);
- return;
- }
- tiling_->UpdateTileAndTwinPriority(current_tile_);
-}
-
-PictureLayerTiling::TilingRasterTileIterator::~TilingRasterTileIterator() {}
-
-void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() {
- DCHECK_LT(phase_, EVENTUALLY_RECT);
-
- do {
- phase_ = static_cast<Phase>(phase_ + 1);
- switch (phase_) {
- case VISIBLE_RECT:
- NOTREACHED();
- return;
- case SKEWPORT_RECT:
- if (!tiling_->has_skewport_rect_tiles_)
- continue;
-
- spiral_iterator_ = TilingData::SpiralDifferenceIterator(
- &tiling_->tiling_data_,
- tiling_->current_skewport_rect_,
- tiling_->current_visible_rect_,
- tiling_->current_visible_rect_);
- break;
- case SOON_BORDER_RECT:
- if (!tiling_->has_soon_border_rect_tiles_)
- continue;
-
- spiral_iterator_ = TilingData::SpiralDifferenceIterator(
- &tiling_->tiling_data_,
- tiling_->current_soon_border_rect_,
- tiling_->current_skewport_rect_,
- tiling_->current_visible_rect_);
- break;
- case EVENTUALLY_RECT:
- if (!tiling_->has_eventually_rect_tiles_) {
- current_tile_ = NULL;
- return;
- }
-
- spiral_iterator_ = TilingData::SpiralDifferenceIterator(
- &tiling_->tiling_data_,
- tiling_->current_eventually_rect_,
- tiling_->current_skewport_rect_,
- tiling_->current_soon_border_rect_);
- break;
- }
-
- while (spiral_iterator_) {
- current_tile_ = tiling_->TileAt(spiral_iterator_.index_x(),
- spiral_iterator_.index_y());
- if (current_tile_ && TileNeedsRaster(current_tile_))
- break;
- ++spiral_iterator_;
- }
-
- if (!spiral_iterator_ && phase_ == EVENTUALLY_RECT) {
- current_tile_ = NULL;
- break;
- }
- } while (!spiral_iterator_);
-
- if (current_tile_)
- tiling_->UpdateTileAndTwinPriority(current_tile_);
-}
-
-PictureLayerTiling::TilingRasterTileIterator&
-PictureLayerTiling::TilingRasterTileIterator::
-operator++() {
- current_tile_ = NULL;
- while (!current_tile_ || !TileNeedsRaster(current_tile_)) {
- std::pair<int, int> next_index;
- switch (phase_) {
- case VISIBLE_RECT:
- ++visible_iterator_;
- if (!visible_iterator_) {
- AdvancePhase();
- return *this;
- }
- next_index = visible_iterator_.index();
- break;
- case SKEWPORT_RECT:
- case SOON_BORDER_RECT:
- ++spiral_iterator_;
- if (!spiral_iterator_) {
- AdvancePhase();
- return *this;
- }
- next_index = spiral_iterator_.index();
- break;
- case EVENTUALLY_RECT:
- ++spiral_iterator_;
- if (!spiral_iterator_) {
- current_tile_ = NULL;
- return *this;
- }
- next_index = spiral_iterator_.index();
- break;
- }
- current_tile_ = tiling_->TileAt(next_index.first, next_index.second);
- }
-
- if (current_tile_)
- tiling_->UpdateTileAndTwinPriority(current_tile_);
- return *this;
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator()
- : eviction_tiles_(NULL), current_eviction_tiles_index_(0u) {
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator(
- PictureLayerTiling* tiling,
- TreePriority tree_priority,
- EvictionCategory category)
- : eviction_tiles_(tiling->GetEvictionTiles(tree_priority, category)),
- // Note: initializing to "0 - 1" works as overflow is well defined for
- // unsigned integers.
- current_eviction_tiles_index_(static_cast<size_t>(0) - 1) {
- DCHECK(eviction_tiles_);
- ++(*this);
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::operator bool() const {
- return eviction_tiles_ &&
- current_eviction_tiles_index_ != eviction_tiles_->size();
-}
-
-Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() {
- DCHECK(*this);
- return (*eviction_tiles_)[current_eviction_tiles_index_];
-}
-
-const Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() const {
- DCHECK(*this);
- return (*eviction_tiles_)[current_eviction_tiles_index_];
-}
-
-PictureLayerTiling::TilingEvictionTileIterator&
-PictureLayerTiling::TilingEvictionTileIterator::
-operator++() {
- DCHECK(*this);
- do {
- ++current_eviction_tiles_index_;
- } while (current_eviction_tiles_index_ != eviction_tiles_->size() &&
- !(*eviction_tiles_)[current_eviction_tiles_index_]->HasResources());
-
- return *this;
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/picture_layer_tiling_perftest.cc b/chromium/cc/resources/picture_layer_tiling_perftest.cc
deleted file mode 100644
index 8f91763c79f..00000000000
--- a/chromium/cc/resources/picture_layer_tiling_perftest.cc
+++ /dev/null
@@ -1,360 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/debug/lap_timer.h"
-#include "cc/resources/picture_layer_tiling.h"
-#include "cc/resources/resource_provider.h"
-#include "cc/resources/scoped_resource.h"
-#include "cc/test/fake_output_surface.h"
-#include "cc/test/fake_output_surface_client.h"
-#include "cc/test/fake_picture_layer_tiling_client.h"
-#include "cc/test/test_context_provider.h"
-#include "cc/test/test_shared_bitmap_manager.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
-
-namespace cc {
-
-namespace {
-
-static const int kTimeLimitMillis = 2000;
-static const int kWarmupRuns = 5;
-static const int kTimeCheckInterval = 10;
-
-class PictureLayerTilingPerfTest : public testing::Test {
- public:
- PictureLayerTilingPerfTest()
- : timer_(kWarmupRuns,
- base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
- kTimeCheckInterval),
- context_provider_(TestContextProvider::Create()) {
- output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
- CHECK(output_surface_->BindToClient(&output_surface_client_));
-
- shared_bitmap_manager_.reset(new TestSharedBitmapManager());
- resource_provider_ = ResourceProvider::Create(output_surface_.get(),
- shared_bitmap_manager_.get(),
- NULL,
- NULL,
- 0,
- false,
- 1).Pass();
- }
-
- virtual void SetUp() override {
- picture_layer_tiling_client_.SetTileSize(gfx::Size(256, 256));
- picture_layer_tiling_client_.set_max_tiles_for_interest_area(250);
- picture_layer_tiling_client_.set_tree(PENDING_TREE);
- picture_layer_tiling_ = PictureLayerTiling::Create(
- 1, gfx::Size(256 * 50, 256 * 50), &picture_layer_tiling_client_);
- picture_layer_tiling_->CreateAllTilesForTesting();
- }
-
- virtual void TearDown() override {
- picture_layer_tiling_.reset(NULL);
- }
-
- void RunInvalidateTest(const std::string& test_name, const Region& region) {
- timer_.Reset();
- do {
- picture_layer_tiling_->UpdateTilesToCurrentPile(
- region, picture_layer_tiling_->tiling_size());
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- perf_test::PrintResult(
- "invalidation", "", test_name, timer_.LapsPerSecond(), "runs/s", true);
- }
-
- void RunComputeTilePriorityRectsStationaryTest(
- const std::string& test_name,
- const gfx::Transform& transform) {
- gfx::Rect viewport_rect(0, 0, 1024, 768);
-
- timer_.Reset();
- do {
- picture_layer_tiling_->ComputeTilePriorityRects(
- PENDING_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion());
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- perf_test::PrintResult("compute_tile_priority_rects_stationary",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
- }
-
- void RunComputeTilePriorityRectsScrollingTest(
- const std::string& test_name,
- const gfx::Transform& transform) {
- gfx::Size viewport_size(1024, 768);
- gfx::Rect viewport_rect(viewport_size);
- int xoffsets[] = {10, 0, -10, 0};
- int yoffsets[] = {0, 10, 0, -10};
- int offsetIndex = 0;
- int offsetCount = 0;
- const int maxOffsetCount = 1000;
-
- timer_.Reset();
- do {
- picture_layer_tiling_->ComputeTilePriorityRects(
- PENDING_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion());
-
- viewport_rect = gfx::Rect(viewport_rect.x() + xoffsets[offsetIndex],
- viewport_rect.y() + yoffsets[offsetIndex],
- viewport_rect.width(),
- viewport_rect.height());
-
- if (++offsetCount > maxOffsetCount) {
- offsetCount = 0;
- offsetIndex = (offsetIndex + 1) % 4;
- }
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- perf_test::PrintResult("compute_tile_priority_rects_scrolling",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
- }
-
- void RunRasterIteratorConstructTest(const std::string& test_name,
- const gfx::Rect& viewport) {
- gfx::Size bounds(viewport.size());
- picture_layer_tiling_ =
- PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
- picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
-
- timer_.Reset();
- do {
- PictureLayerTiling::TilingRasterTileIterator it(
- picture_layer_tiling_.get());
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- perf_test::PrintResult("tiling_raster_tile_iterator_construct",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
- }
-
- void RunRasterIteratorConstructAndIterateTest(const std::string& test_name,
- int num_tiles,
- const gfx::Rect& viewport) {
- gfx::Size bounds(10000, 10000);
- picture_layer_tiling_ =
- PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
- picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
-
- timer_.Reset();
- do {
- int count = num_tiles;
- PictureLayerTiling::TilingRasterTileIterator it(
- picture_layer_tiling_.get());
- while (count--) {
- ASSERT_TRUE(it) << "count: " << count;
- ASSERT_TRUE(*it != NULL) << "count: " << count;
- ++it;
- }
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- perf_test::PrintResult("tiling_raster_tile_iterator_construct_and_iterate",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
- }
-
- void RunEvictionIteratorConstructTest(const std::string& test_name,
- const gfx::Rect& viewport) {
- gfx::Size bounds(viewport.size());
- picture_layer_tiling_ =
- PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
- picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
-
- timer_.Reset();
- TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
- SMOOTHNESS_TAKES_PRIORITY,
- NEW_CONTENT_TAKES_PRIORITY};
- int priority_count = 0;
- do {
- PictureLayerTiling::TilingEvictionTileIterator it(
- picture_layer_tiling_.get(),
- priorities[priority_count],
- PictureLayerTiling::NOW);
- priority_count = (priority_count + 1) % arraysize(priorities);
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- perf_test::PrintResult("tiling_eviction_tile_iterator_construct",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
- }
-
- void RunEvictionIteratorConstructAndIterateTest(const std::string& test_name,
- int num_tiles,
- const gfx::Rect& viewport) {
- gfx::Size bounds(10000, 10000);
- picture_layer_tiling_ =
- PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
- picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
-
- TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
- SMOOTHNESS_TAKES_PRIORITY,
- NEW_CONTENT_TAKES_PRIORITY};
-
- // Ensure all tiles have resources.
- std::vector<Tile*> all_tiles = picture_layer_tiling_->AllTilesForTesting();
- for (std::vector<Tile*>::iterator tile_it = all_tiles.begin();
- tile_it != all_tiles.end();
- ++tile_it) {
- Tile* tile = *tile_it;
- ManagedTileState::DrawInfo& draw_info = tile->draw_info();
- draw_info.SetResourceForTesting(
- ScopedResource::Create(resource_provider_.get()).Pass());
- }
-
- int priority_count = 0;
- timer_.Reset();
- do {
- int count = num_tiles;
- PictureLayerTiling::TilingEvictionTileIterator it(
- picture_layer_tiling_.get(),
- priorities[priority_count],
- PictureLayerTiling::EVENTUALLY);
- while (count--) {
- ASSERT_TRUE(it) << "count: " << count;
- ASSERT_TRUE(*it != NULL) << "count: " << count;
- ++it;
- }
- priority_count = (priority_count + 1) % arraysize(priorities);
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- // Remove all resources from tiles to make sure the tile version destructor
- // doesn't complain.
- for (std::vector<Tile*>::iterator tile_it = all_tiles.begin();
- tile_it != all_tiles.end();
- ++tile_it) {
- Tile* tile = *tile_it;
- ManagedTileState::DrawInfo& draw_info = tile->draw_info();
- draw_info.SetResourceForTesting(nullptr);
- }
-
- perf_test::PrintResult(
- "tiling_eviction_tile_iterator_construct_and_iterate",
- "",
- test_name,
- timer_.LapsPerSecond(),
- "runs/s",
- true);
- }
-
- private:
- FakePictureLayerTilingClient picture_layer_tiling_client_;
- scoped_ptr<PictureLayerTiling> picture_layer_tiling_;
-
- LapTimer timer_;
-
- scoped_refptr<ContextProvider> context_provider_;
- FakeOutputSurfaceClient output_surface_client_;
- scoped_ptr<FakeOutputSurface> output_surface_;
- scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
- scoped_ptr<ResourceProvider> resource_provider_;
-};
-
-TEST_F(PictureLayerTilingPerfTest, Invalidate) {
- Region one_tile(gfx::Rect(256, 256));
- RunInvalidateTest("1x1", one_tile);
-
- Region half_region(gfx::Rect(25 * 256, 50 * 256));
- RunInvalidateTest("25x50", half_region);
-
- Region full_region(gfx::Rect(50 * 256, 50 * 256));
- RunInvalidateTest("50x50", full_region);
-}
-
-#if defined(OS_ANDROID)
-// TODO(vmpstr): Investigate why this is noisy (crbug.com/310220).
-TEST_F(PictureLayerTilingPerfTest, DISABLED_ComputeTilePriorityRects) {
-#else
-TEST_F(PictureLayerTilingPerfTest, ComputeTilePriorityRects) {
-#endif // defined(OS_ANDROID)
- gfx::Transform transform;
-
- RunComputeTilePriorityRectsStationaryTest("no_transform", transform);
- RunComputeTilePriorityRectsScrollingTest("no_transform", transform);
-
- transform.Rotate(10);
- RunComputeTilePriorityRectsStationaryTest("rotation", transform);
- RunComputeTilePriorityRectsScrollingTest("rotation", transform);
-
- transform.ApplyPerspectiveDepth(10);
- RunComputeTilePriorityRectsStationaryTest("perspective", transform);
- RunComputeTilePriorityRectsScrollingTest("perspective", transform);
-}
-
-TEST_F(PictureLayerTilingPerfTest, TilingRasterTileIteratorConstruct) {
- RunRasterIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
- RunRasterIteratorConstructTest("50_0_100x100", gfx::Rect(50, 0, 100, 100));
- RunRasterIteratorConstructTest("100_0_100x100", gfx::Rect(100, 0, 100, 100));
- RunRasterIteratorConstructTest("150_0_100x100", gfx::Rect(150, 0, 100, 100));
-}
-
-TEST_F(PictureLayerTilingPerfTest,
- TilingRasterTileIteratorConstructAndIterate) {
- RunRasterIteratorConstructAndIterateTest(
- "32_100x100", 32, gfx::Rect(0, 0, 100, 100));
- RunRasterIteratorConstructAndIterateTest(
- "32_500x500", 32, gfx::Rect(0, 0, 500, 500));
- RunRasterIteratorConstructAndIterateTest(
- "64_100x100", 64, gfx::Rect(0, 0, 100, 100));
- RunRasterIteratorConstructAndIterateTest(
- "64_500x500", 64, gfx::Rect(0, 0, 500, 500));
-}
-
-TEST_F(PictureLayerTilingPerfTest, TilingEvictionTileIteratorConstruct) {
- RunEvictionIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
- RunEvictionIteratorConstructTest("50_0_100x100", gfx::Rect(50, 0, 100, 100));
- RunEvictionIteratorConstructTest("100_0_100x100",
- gfx::Rect(100, 0, 100, 100));
- RunEvictionIteratorConstructTest("150_0_100x100",
- gfx::Rect(150, 0, 100, 100));
-}
-
-TEST_F(PictureLayerTilingPerfTest,
- TilingEvictionTileIteratorConstructAndIterate) {
- RunEvictionIteratorConstructAndIterateTest(
- "32_100x100", 32, gfx::Rect(0, 0, 100, 100));
- RunEvictionIteratorConstructAndIterateTest(
- "32_500x500", 32, gfx::Rect(0, 0, 500, 500));
- RunEvictionIteratorConstructAndIterateTest(
- "64_100x100", 64, gfx::Rect(0, 0, 100, 100));
- RunEvictionIteratorConstructAndIterateTest(
- "64_500x500", 64, gfx::Rect(0, 0, 500, 500));
-}
-
-} // namespace
-
-} // namespace cc
diff --git a/chromium/cc/resources/picture_layer_tiling_set.cc b/chromium/cc/resources/picture_layer_tiling_set.cc
deleted file mode 100644
index b2b86b5464c..00000000000
--- a/chromium/cc/resources/picture_layer_tiling_set.cc
+++ /dev/null
@@ -1,374 +0,0 @@
-// Copyright 2012 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/picture_layer_tiling_set.h"
-
-#include <limits>
-
-namespace cc {
-
-namespace {
-
-class LargestToSmallestScaleFunctor {
- public:
- bool operator() (PictureLayerTiling* left, PictureLayerTiling* right) {
- return left->contents_scale() > right->contents_scale();
- }
-};
-
-} // namespace
-
-PictureLayerTilingSet::PictureLayerTilingSet(PictureLayerTilingClient* client)
- : client_(client) {
-}
-
-PictureLayerTilingSet::~PictureLayerTilingSet() {
-}
-
-void PictureLayerTilingSet::SetClient(PictureLayerTilingClient* client) {
- client_ = client;
- for (size_t i = 0; i < tilings_.size(); ++i)
- tilings_[i]->SetClient(client_);
-}
-
-void PictureLayerTilingSet::RemoveTilesInRegion(const Region& region) {
- for (size_t i = 0; i < tilings_.size(); ++i)
- tilings_[i]->RemoveTilesInRegion(region);
-}
-
-bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other,
- const gfx::Size& new_layer_bounds,
- const Region& layer_invalidation,
- float minimum_contents_scale) {
- if (new_layer_bounds.IsEmpty()) {
- RemoveAllTilings();
- return false;
- }
-
- tilings_.reserve(other.tilings_.size());
-
- // Remove any tilings that aren't in |other| or don't meet the minimum.
- for (size_t i = 0; i < tilings_.size(); ++i) {
- float scale = tilings_[i]->contents_scale();
- if (scale >= minimum_contents_scale && !!other.TilingAtScale(scale))
- continue;
- // Swap with the last element and remove it.
- tilings_.swap(tilings_.begin() + i, tilings_.end() - 1);
- tilings_.pop_back();
- --i;
- }
-
- bool have_high_res_tiling = false;
-
- // Add any missing tilings from |other| that meet the minimum.
- for (size_t i = 0; i < other.tilings_.size(); ++i) {
- float contents_scale = other.tilings_[i]->contents_scale();
- if (contents_scale < minimum_contents_scale)
- continue;
- if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) {
- this_tiling->set_resolution(other.tilings_[i]->resolution());
-
- this_tiling->UpdateTilesToCurrentPile(layer_invalidation,
- new_layer_bounds);
- this_tiling->CreateMissingTilesInLiveTilesRect();
- if (this_tiling->resolution() == HIGH_RESOLUTION)
- have_high_res_tiling = true;
-
- DCHECK(this_tiling->tile_size() ==
- client_->CalculateTileSize(this_tiling->tiling_size()))
- << "tile_size: " << this_tiling->tile_size().ToString()
- << " tiling_size: " << this_tiling->tiling_size().ToString()
- << " CalculateTileSize: "
- << client_->CalculateTileSize(this_tiling->tiling_size()).ToString();
- continue;
- }
- scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
- contents_scale,
- new_layer_bounds,
- client_);
- new_tiling->set_resolution(other.tilings_[i]->resolution());
- if (new_tiling->resolution() == HIGH_RESOLUTION)
- have_high_res_tiling = true;
- tilings_.push_back(new_tiling.Pass());
- }
- tilings_.sort(LargestToSmallestScaleFunctor());
-
- return have_high_res_tiling;
-}
-
-PictureLayerTiling* PictureLayerTilingSet::AddTiling(
- float contents_scale,
- const gfx::Size& layer_bounds) {
- for (size_t i = 0; i < tilings_.size(); ++i)
- DCHECK_NE(tilings_[i]->contents_scale(), contents_scale);
-
- tilings_.push_back(
- PictureLayerTiling::Create(contents_scale, layer_bounds, client_));
- PictureLayerTiling* appended = tilings_.back();
-
- tilings_.sort(LargestToSmallestScaleFunctor());
- return appended;
-}
-
-int PictureLayerTilingSet::NumHighResTilings() const {
- int num_high_res = 0;
- for (size_t i = 0; i < tilings_.size(); ++i) {
- if (tilings_[i]->resolution() == HIGH_RESOLUTION)
- num_high_res++;
- }
- return num_high_res;
-}
-
-PictureLayerTiling* PictureLayerTilingSet::TilingAtScale(float scale) const {
- for (size_t i = 0; i < tilings_.size(); ++i) {
- if (tilings_[i]->contents_scale() == scale)
- return tilings_[i];
- }
- return NULL;
-}
-
-void PictureLayerTilingSet::RemoveAllTilings() {
- tilings_.clear();
-}
-
-void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) {
- ScopedPtrVector<PictureLayerTiling>::iterator iter =
- std::find(tilings_.begin(), tilings_.end(), tiling);
- if (iter == tilings_.end())
- return;
- tilings_.erase(iter);
-}
-
-void PictureLayerTilingSet::RemoveAllTiles() {
- for (size_t i = 0; i < tilings_.size(); ++i)
- tilings_[i]->Reset();
-}
-
-PictureLayerTilingSet::CoverageIterator::CoverageIterator(
- const PictureLayerTilingSet* set,
- float contents_scale,
- const gfx::Rect& content_rect,
- float ideal_contents_scale)
- : set_(set),
- contents_scale_(contents_scale),
- ideal_contents_scale_(ideal_contents_scale),
- current_tiling_(-1) {
- missing_region_.Union(content_rect);
-
- for (ideal_tiling_ = 0;
- static_cast<size_t>(ideal_tiling_) < set_->tilings_.size();
- ++ideal_tiling_) {
- PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_];
- if (tiling->contents_scale() < ideal_contents_scale_) {
- if (ideal_tiling_ > 0)
- ideal_tiling_--;
- break;
- }
- }
-
- DCHECK_LE(set_->tilings_.size(),
- static_cast<size_t>(std::numeric_limits<int>::max()));
-
- int num_tilings = set_->tilings_.size();
- if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0)
- ideal_tiling_--;
-
- ++(*this);
-}
-
-PictureLayerTilingSet::CoverageIterator::~CoverageIterator() {
-}
-
-gfx::Rect PictureLayerTilingSet::CoverageIterator::geometry_rect() const {
- if (!tiling_iter_) {
- if (!region_iter_.has_rect())
- return gfx::Rect();
- return region_iter_.rect();
- }
- return tiling_iter_.geometry_rect();
-}
-
-gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const {
- if (!tiling_iter_)
- return gfx::RectF();
- return tiling_iter_.texture_rect();
-}
-
-gfx::Size PictureLayerTilingSet::CoverageIterator::texture_size() const {
- if (!tiling_iter_)
- return gfx::Size();
- return tiling_iter_.texture_size();
-}
-
-Tile* PictureLayerTilingSet::CoverageIterator::operator->() const {
- if (!tiling_iter_)
- return NULL;
- return *tiling_iter_;
-}
-
-Tile* PictureLayerTilingSet::CoverageIterator::operator*() const {
- if (!tiling_iter_)
- return NULL;
- return *tiling_iter_;
-}
-
-TileResolution PictureLayerTilingSet::CoverageIterator::resolution() const {
- const PictureLayerTiling* tiling = CurrentTiling();
- DCHECK(tiling);
- return tiling->resolution();
-}
-
-PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling()
- const {
- if (current_tiling_ < 0)
- return NULL;
- if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size())
- return NULL;
- return set_->tilings_[current_tiling_];
-}
-
-int PictureLayerTilingSet::CoverageIterator::NextTiling() const {
- // Order returned by this method is:
- // 1. Ideal tiling index
- // 2. Tiling index < Ideal in decreasing order (higher res than ideal)
- // 3. Tiling index > Ideal in increasing order (lower res than ideal)
- // 4. Tiling index > tilings.size() (invalid index)
- if (current_tiling_ < 0)
- return ideal_tiling_;
- else if (current_tiling_ > ideal_tiling_)
- return current_tiling_ + 1;
- else if (current_tiling_)
- return current_tiling_ - 1;
- else
- return ideal_tiling_ + 1;
-}
-
-PictureLayerTilingSet::CoverageIterator&
-PictureLayerTilingSet::CoverageIterator::operator++() {
- bool first_time = current_tiling_ < 0;
-
- if (!*this && !first_time)
- return *this;
-
- if (tiling_iter_)
- ++tiling_iter_;
-
- // Loop until we find a valid place to stop.
- while (true) {
- while (tiling_iter_ &&
- (!*tiling_iter_ || !tiling_iter_->IsReadyToDraw())) {
- missing_region_.Union(tiling_iter_.geometry_rect());
- ++tiling_iter_;
- }
- if (tiling_iter_)
- return *this;
-
- // If the set of current rects for this tiling is done, go to the next
- // tiling and set up to iterate through all of the remaining holes.
- // This will also happen the first time through the loop.
- if (!region_iter_.has_rect()) {
- current_tiling_ = NextTiling();
- current_region_.Swap(&missing_region_);
- missing_region_.Clear();
- region_iter_ = Region::Iterator(current_region_);
-
- // All done and all filled.
- if (!region_iter_.has_rect()) {
- current_tiling_ = set_->tilings_.size();
- return *this;
- }
-
- // No more valid tiles, return this checkerboard rect.
- if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
- return *this;
- }
-
- // Pop a rect off. If there are no more tilings, then these will be
- // treated as geometry with null tiles that the caller can checkerboard.
- gfx::Rect last_rect = region_iter_.rect();
- region_iter_.next();
-
- // Done, found next checkerboard rect to return.
- if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
- return *this;
-
- // Construct a new iterator for the next tiling, but we need to loop
- // again until we get to a valid one.
- tiling_iter_ = PictureLayerTiling::CoverageIterator(
- set_->tilings_[current_tiling_],
- contents_scale_,
- last_rect);
- }
-
- return *this;
-}
-
-PictureLayerTilingSet::CoverageIterator::operator bool() const {
- return current_tiling_ < static_cast<int>(set_->tilings_.size()) ||
- region_iter_.has_rect();
-}
-
-void PictureLayerTilingSet::AsValueInto(base::debug::TracedValue* state) const {
- for (size_t i = 0; i < tilings_.size(); ++i) {
- state->BeginDictionary();
- tilings_[i]->AsValueInto(state);
- state->EndDictionary();
- }
-}
-
-size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const {
- size_t amount = 0;
- for (size_t i = 0; i < tilings_.size(); ++i)
- amount += tilings_[i]->GPUMemoryUsageInBytes();
- return amount;
-}
-
-PictureLayerTilingSet::TilingRange PictureLayerTilingSet::GetTilingRange(
- TilingRangeType type) const {
- // Doesn't seem to be the case right now but if it ever becomes a performance
- // problem to compute these ranges each time this function is called, we can
- // compute them only when the tiling set has changed instead.
- TilingRange high_res_range(0, 0);
- TilingRange low_res_range(tilings_.size(), tilings_.size());
- for (size_t i = 0; i < tilings_.size(); ++i) {
- const PictureLayerTiling* tiling = tilings_[i];
- if (tiling->resolution() == HIGH_RESOLUTION)
- high_res_range = TilingRange(i, i + 1);
- if (tiling->resolution() == LOW_RESOLUTION)
- low_res_range = TilingRange(i, i + 1);
- }
-
- TilingRange range(0, 0);
- switch (type) {
- case HIGHER_THAN_HIGH_RES:
- range = TilingRange(0, high_res_range.start);
- break;
- case HIGH_RES:
- range = high_res_range;
- break;
- case BETWEEN_HIGH_AND_LOW_RES:
- // TODO(vmpstr): This code assumes that high res tiling will come before
- // low res tiling, however there are cases where this assumption is
- // violated. As a result, it's better to be safe in these situations,
- // since otherwise we can end up accessing a tiling that doesn't exist.
- // See crbug.com/429397 for high res tiling appearing after low res
- // tiling discussion/fixes.
- if (high_res_range.start <= low_res_range.start)
- range = TilingRange(high_res_range.end, low_res_range.start);
- else
- range = TilingRange(low_res_range.end, high_res_range.start);
- break;
- case LOW_RES:
- range = low_res_range;
- break;
- case LOWER_THAN_LOW_RES:
- range = TilingRange(low_res_range.end, tilings_.size());
- break;
- }
-
- DCHECK_LE(range.start, range.end);
- return range;
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/picture_layer_tiling_set.h b/chromium/cc/resources/picture_layer_tiling_set.h
deleted file mode 100644
index ddde1d7be42..00000000000
--- a/chromium/cc/resources/picture_layer_tiling_set.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2012 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_PICTURE_LAYER_TILING_SET_H_
-#define CC_RESOURCES_PICTURE_LAYER_TILING_SET_H_
-
-#include "cc/base/region.h"
-#include "cc/base/scoped_ptr_vector.h"
-#include "cc/resources/picture_layer_tiling.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace base {
-namespace debug {
-class TracedValue;
-}
-}
-
-namespace cc {
-
-class CC_EXPORT PictureLayerTilingSet {
- public:
- enum TilingRangeType {
- HIGHER_THAN_HIGH_RES,
- HIGH_RES,
- BETWEEN_HIGH_AND_LOW_RES,
- LOW_RES,
- LOWER_THAN_LOW_RES
- };
- struct TilingRange {
- TilingRange(size_t start, size_t end) : start(start), end(end) {}
-
- size_t start;
- size_t end;
- };
-
- explicit PictureLayerTilingSet(PictureLayerTilingClient* client);
- ~PictureLayerTilingSet();
-
- void SetClient(PictureLayerTilingClient* client);
- const PictureLayerTilingClient* client() const { return client_; }
-
- void RemoveTilesInRegion(const Region& region);
-
- // Make this set of tilings match the same set of content scales from |other|.
- // Delete any tilings that don't meet |minimum_contents_scale|. Recreate
- // any tiles that intersect |layer_invalidation|. Update the size of all
- // tilings to |new_layer_bounds|.
- // Returns true if we had at least one high res tiling synced.
- bool SyncTilings(const PictureLayerTilingSet& other,
- const gfx::Size& new_layer_bounds,
- const Region& layer_invalidation,
- float minimum_contents_scale);
-
- PictureLayerTiling* AddTiling(float contents_scale,
- const gfx::Size& layer_bounds);
- size_t num_tilings() const { return tilings_.size(); }
- int NumHighResTilings() const;
- PictureLayerTiling* tiling_at(size_t idx) { return tilings_[idx]; }
- const PictureLayerTiling* tiling_at(size_t idx) const {
- return tilings_[idx];
- }
-
- PictureLayerTiling* TilingAtScale(float scale) const;
-
- // Remove all tilings.
- void RemoveAllTilings();
-
- // Remove one tiling.
- void Remove(PictureLayerTiling* tiling);
-
- // Remove all tiles; keep all tilings.
- void RemoveAllTiles();
-
- // For a given rect, iterates through tiles that can fill it. If no
- // set of tiles with resources can fill the rect, then it will iterate
- // through null tiles with valid geometry_rect() until the rect is full.
- // If all tiles have resources, the union of all geometry_rects will
- // exactly fill rect with no overlap.
- class CC_EXPORT CoverageIterator {
- public:
- CoverageIterator(const PictureLayerTilingSet* set,
- float contents_scale,
- const gfx::Rect& content_rect,
- float ideal_contents_scale);
- ~CoverageIterator();
-
- // Visible rect (no borders), always in the space of rect,
- // regardless of the relative contents scale of the tiling.
- gfx::Rect geometry_rect() const;
- // Texture rect (in texels) for geometry_rect
- gfx::RectF texture_rect() const;
- // Texture size in texels
- gfx::Size texture_size() const;
-
- Tile* operator->() const;
- Tile* operator*() const;
-
- CoverageIterator& operator++();
- operator bool() const;
-
- TileResolution resolution() const;
- PictureLayerTiling* CurrentTiling() const;
-
- private:
- int NextTiling() const;
-
- const PictureLayerTilingSet* set_;
- float contents_scale_;
- float ideal_contents_scale_;
- PictureLayerTiling::CoverageIterator tiling_iter_;
- int current_tiling_;
- int ideal_tiling_;
-
- Region current_region_;
- Region missing_region_;
- Region::Iterator region_iter_;
- };
-
- void AsValueInto(base::debug::TracedValue* array) const;
- size_t GPUMemoryUsageInBytes() const;
-
- TilingRange GetTilingRange(TilingRangeType type) const;
-
- private:
- PictureLayerTilingClient* client_;
- ScopedPtrVector<PictureLayerTiling> tilings_;
-
- friend class Iterator;
- DISALLOW_COPY_AND_ASSIGN(PictureLayerTilingSet);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_PICTURE_LAYER_TILING_SET_H_
diff --git a/chromium/cc/resources/picture_layer_tiling_set_unittest.cc b/chromium/cc/resources/picture_layer_tiling_set_unittest.cc
deleted file mode 100644
index 0fe8b3c9587..00000000000
--- a/chromium/cc/resources/picture_layer_tiling_set_unittest.cc
+++ /dev/null
@@ -1,562 +0,0 @@
-// Copyright 2012 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/picture_layer_tiling_set.h"
-
-#include <map>
-#include <vector>
-
-#include "cc/resources/resource_provider.h"
-#include "cc/test/fake_output_surface.h"
-#include "cc/test/fake_output_surface_client.h"
-#include "cc/test/fake_picture_layer_tiling_client.h"
-#include "cc/test/test_shared_bitmap_manager.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/size_conversions.h"
-
-namespace cc {
-namespace {
-
-TEST(PictureLayerTilingSetTest, NoResources) {
- FakePictureLayerTilingClient client;
- gfx::Size layer_bounds(1000, 800);
- PictureLayerTilingSet set(&client);
- client.SetTileSize(gfx::Size(256, 256));
-
- set.AddTiling(1.0, layer_bounds);
- set.AddTiling(1.5, layer_bounds);
- set.AddTiling(2.0, layer_bounds);
-
- float contents_scale = 2.0;
- gfx::Size content_bounds(
- gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)));
- gfx::Rect content_rect(content_bounds);
-
- Region remaining(content_rect);
- PictureLayerTilingSet::CoverageIterator iter(
- &set,
- contents_scale,
- content_rect,
- contents_scale);
- for (; iter; ++iter) {
- gfx::Rect geometry_rect = iter.geometry_rect();
- EXPECT_TRUE(content_rect.Contains(geometry_rect));
- ASSERT_TRUE(remaining.Contains(geometry_rect));
- remaining.Subtract(geometry_rect);
-
- // No tiles have resources, so no iter represents a real tile.
- EXPECT_FALSE(*iter);
- }
- EXPECT_TRUE(remaining.IsEmpty());
-}
-
-TEST(PictureLayerTilingSetTest, TilingRange) {
- FakePictureLayerTilingClient client;
- gfx::Size layer_bounds(10, 10);
- PictureLayerTilingSet::TilingRange higher_than_high_res_range(0, 0);
- PictureLayerTilingSet::TilingRange high_res_range(0, 0);
- PictureLayerTilingSet::TilingRange between_high_and_low_res_range(0, 0);
- PictureLayerTilingSet::TilingRange low_res_range(0, 0);
- PictureLayerTilingSet::TilingRange lower_than_low_res_range(0, 0);
- PictureLayerTiling* high_res_tiling;
- PictureLayerTiling* low_res_tiling;
-
- PictureLayerTilingSet set(&client);
- set.AddTiling(2.0, layer_bounds);
- high_res_tiling = set.AddTiling(1.0, layer_bounds);
- high_res_tiling->set_resolution(HIGH_RESOLUTION);
- set.AddTiling(0.5, layer_bounds);
- low_res_tiling = set.AddTiling(0.25, layer_bounds);
- low_res_tiling->set_resolution(LOW_RESOLUTION);
- set.AddTiling(0.125, layer_bounds);
-
- higher_than_high_res_range =
- set.GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
- EXPECT_EQ(0u, higher_than_high_res_range.start);
- EXPECT_EQ(1u, higher_than_high_res_range.end);
-
- high_res_range = set.GetTilingRange(PictureLayerTilingSet::HIGH_RES);
- EXPECT_EQ(1u, high_res_range.start);
- EXPECT_EQ(2u, high_res_range.end);
-
- between_high_and_low_res_range =
- set.GetTilingRange(PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
- EXPECT_EQ(2u, between_high_and_low_res_range.start);
- EXPECT_EQ(3u, between_high_and_low_res_range.end);
-
- low_res_range = set.GetTilingRange(PictureLayerTilingSet::LOW_RES);
- EXPECT_EQ(3u, low_res_range.start);
- EXPECT_EQ(4u, low_res_range.end);
-
- lower_than_low_res_range =
- set.GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES);
- EXPECT_EQ(4u, lower_than_low_res_range.start);
- EXPECT_EQ(5u, lower_than_low_res_range.end);
-
- PictureLayerTilingSet set_without_low_res(&client);
- set_without_low_res.AddTiling(2.0, layer_bounds);
- high_res_tiling = set_without_low_res.AddTiling(1.0, layer_bounds);
- high_res_tiling->set_resolution(HIGH_RESOLUTION);
- set_without_low_res.AddTiling(0.5, layer_bounds);
- set_without_low_res.AddTiling(0.25, layer_bounds);
-
- higher_than_high_res_range = set_without_low_res.GetTilingRange(
- PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
- EXPECT_EQ(0u, higher_than_high_res_range.start);
- EXPECT_EQ(1u, higher_than_high_res_range.end);
-
- high_res_range =
- set_without_low_res.GetTilingRange(PictureLayerTilingSet::HIGH_RES);
- EXPECT_EQ(1u, high_res_range.start);
- EXPECT_EQ(2u, high_res_range.end);
-
- between_high_and_low_res_range = set_without_low_res.GetTilingRange(
- PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
- EXPECT_EQ(2u, between_high_and_low_res_range.start);
- EXPECT_EQ(4u, between_high_and_low_res_range.end);
-
- low_res_range =
- set_without_low_res.GetTilingRange(PictureLayerTilingSet::LOW_RES);
- EXPECT_EQ(0u, low_res_range.end - low_res_range.start);
-
- lower_than_low_res_range = set_without_low_res.GetTilingRange(
- PictureLayerTilingSet::LOWER_THAN_LOW_RES);
- EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
-
- PictureLayerTilingSet set_with_only_high_and_low_res(&client);
- high_res_tiling = set_with_only_high_and_low_res.AddTiling(1.0, layer_bounds);
- high_res_tiling->set_resolution(HIGH_RESOLUTION);
- low_res_tiling = set_with_only_high_and_low_res.AddTiling(0.5, layer_bounds);
- low_res_tiling->set_resolution(LOW_RESOLUTION);
-
- higher_than_high_res_range = set_with_only_high_and_low_res.GetTilingRange(
- PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
- EXPECT_EQ(0u,
- higher_than_high_res_range.end - higher_than_high_res_range.start);
-
- high_res_range = set_with_only_high_and_low_res.GetTilingRange(
- PictureLayerTilingSet::HIGH_RES);
- EXPECT_EQ(0u, high_res_range.start);
- EXPECT_EQ(1u, high_res_range.end);
-
- between_high_and_low_res_range =
- set_with_only_high_and_low_res.GetTilingRange(
- PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
- EXPECT_EQ(0u,
- between_high_and_low_res_range.end -
- between_high_and_low_res_range.start);
-
- low_res_range = set_with_only_high_and_low_res.GetTilingRange(
- PictureLayerTilingSet::LOW_RES);
- EXPECT_EQ(1u, low_res_range.start);
- EXPECT_EQ(2u, low_res_range.end);
-
- lower_than_low_res_range = set_with_only_high_and_low_res.GetTilingRange(
- PictureLayerTilingSet::LOWER_THAN_LOW_RES);
- EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
-
- PictureLayerTilingSet set_with_only_high_res(&client);
- high_res_tiling = set_with_only_high_res.AddTiling(1.0, layer_bounds);
- high_res_tiling->set_resolution(HIGH_RESOLUTION);
-
- higher_than_high_res_range = set_with_only_high_res.GetTilingRange(
- PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
- EXPECT_EQ(0u,
- higher_than_high_res_range.end - higher_than_high_res_range.start);
-
- high_res_range =
- set_with_only_high_res.GetTilingRange(PictureLayerTilingSet::HIGH_RES);
- EXPECT_EQ(0u, high_res_range.start);
- EXPECT_EQ(1u, high_res_range.end);
-
- between_high_and_low_res_range = set_with_only_high_res.GetTilingRange(
- PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
- EXPECT_EQ(0u,
- between_high_and_low_res_range.end -
- between_high_and_low_res_range.start);
-
- low_res_range =
- set_with_only_high_res.GetTilingRange(PictureLayerTilingSet::LOW_RES);
- EXPECT_EQ(0u, low_res_range.end - low_res_range.start);
-
- lower_than_low_res_range = set_with_only_high_res.GetTilingRange(
- PictureLayerTilingSet::LOWER_THAN_LOW_RES);
- EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
-}
-
-class PictureLayerTilingSetTestWithResources : public testing::Test {
- public:
- void runTest(
- int num_tilings,
- float min_scale,
- float scale_increment,
- float ideal_contents_scale,
- float expected_scale) {
- FakeOutputSurfaceClient output_surface_client;
- scoped_ptr<FakeOutputSurface> output_surface =
- FakeOutputSurface::Create3d();
- CHECK(output_surface->BindToClient(&output_surface_client));
-
- scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
- new TestSharedBitmapManager());
- scoped_ptr<ResourceProvider> resource_provider =
- ResourceProvider::Create(output_surface.get(),
- shared_bitmap_manager.get(),
- NULL,
- NULL,
- 0,
- false,
- 1);
-
- FakePictureLayerTilingClient client(resource_provider.get());
- client.SetTileSize(gfx::Size(256, 256));
- client.set_tree(PENDING_TREE);
- gfx::Size layer_bounds(1000, 800);
- PictureLayerTilingSet set(&client);
-
- float scale = min_scale;
- for (int i = 0; i < num_tilings; ++i, scale += scale_increment) {
- PictureLayerTiling* tiling = set.AddTiling(scale, layer_bounds);
- tiling->CreateAllTilesForTesting();
- std::vector<Tile*> tiles = tiling->AllTilesForTesting();
- client.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
- }
-
- float max_contents_scale = scale;
- gfx::Size content_bounds(
- gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, max_contents_scale)));
- gfx::Rect content_rect(content_bounds);
-
- Region remaining(content_rect);
- PictureLayerTilingSet::CoverageIterator iter(
- &set,
- max_contents_scale,
- content_rect,
- ideal_contents_scale);
- for (; iter; ++iter) {
- gfx::Rect geometry_rect = iter.geometry_rect();
- EXPECT_TRUE(content_rect.Contains(geometry_rect));
- ASSERT_TRUE(remaining.Contains(geometry_rect));
- remaining.Subtract(geometry_rect);
-
- float scale = iter.CurrentTiling()->contents_scale();
- EXPECT_EQ(expected_scale, scale);
-
- if (num_tilings)
- EXPECT_TRUE(*iter);
- else
- EXPECT_FALSE(*iter);
- }
- EXPECT_TRUE(remaining.IsEmpty());
- }
-};
-
-TEST_F(PictureLayerTilingSetTestWithResources, NoTilings) {
- runTest(0, 0.f, 0.f, 2.f, 0.f);
-}
-TEST_F(PictureLayerTilingSetTestWithResources, OneTiling_Smaller) {
- runTest(1, 1.f, 0.f, 2.f, 1.f);
-}
-TEST_F(PictureLayerTilingSetTestWithResources, OneTiling_Larger) {
- runTest(1, 3.f, 0.f, 2.f, 3.f);
-}
-TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_Smaller) {
- runTest(2, 1.f, 1.f, 3.f, 2.f);
-}
-
-TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_SmallerEqual) {
- runTest(2, 1.f, 1.f, 2.f, 2.f);
-}
-
-TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_LargerEqual) {
- runTest(2, 1.f, 1.f, 1.f, 1.f);
-}
-
-TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_Larger) {
- runTest(2, 2.f, 8.f, 1.f, 2.f);
-}
-
-TEST_F(PictureLayerTilingSetTestWithResources, ManyTilings_Equal) {
- runTest(10, 1.f, 1.f, 5.f, 5.f);
-}
-
-TEST_F(PictureLayerTilingSetTestWithResources, ManyTilings_NotEqual) {
- runTest(10, 1.f, 1.f, 4.5f, 5.f);
-}
-
-class PictureLayerTilingSetSyncTest : public testing::Test {
- public:
- PictureLayerTilingSetSyncTest()
- : tile_size_(gfx::Size(10, 10)),
- source_bounds_(gfx::Size(30, 20)),
- target_bounds_(gfx::Size(30, 30)) {
- source_client_.SetTileSize(tile_size_);
- source_client_.set_tree(PENDING_TREE);
- target_client_.SetTileSize(tile_size_);
- target_client_.set_tree(PENDING_TREE);
- source_.reset(new PictureLayerTilingSet(&source_client_));
- target_.reset(new PictureLayerTilingSet(&target_client_));
- }
-
- // Sync from source to target.
- void SyncTilings(const gfx::Size& new_bounds,
- const Region& invalidation,
- float minimum_scale) {
- for (size_t i = 0; i < source_->num_tilings(); ++i)
- source_->tiling_at(i)->CreateAllTilesForTesting();
- for (size_t i = 0; i < target_->num_tilings(); ++i)
- target_->tiling_at(i)->CreateAllTilesForTesting();
-
- target_->SyncTilings(
- *source_.get(), new_bounds, invalidation, minimum_scale);
- }
- void SyncTilings(const gfx::Size& new_bounds) {
- Region invalidation;
- SyncTilings(new_bounds, invalidation, 0.f);
- }
- void SyncTilings(const gfx::Size& new_bounds, const Region& invalidation) {
- SyncTilings(new_bounds, invalidation, 0.f);
- }
- void SyncTilings(const gfx::Size& new_bounds, float minimum_scale) {
- Region invalidation;
- SyncTilings(new_bounds, invalidation, minimum_scale);
- }
-
- void VerifyTargetEqualsSource(const gfx::Size& new_bounds) {
- ASSERT_FALSE(new_bounds.IsEmpty());
- EXPECT_EQ(target_->num_tilings(), source_->num_tilings());
-
- for (size_t i = 0; i < target_->num_tilings(); ++i) {
- ASSERT_GT(source_->num_tilings(), i);
- const PictureLayerTiling* source_tiling = source_->tiling_at(i);
- const PictureLayerTiling* target_tiling = target_->tiling_at(i);
- EXPECT_EQ(target_tiling->layer_bounds().ToString(),
- new_bounds.ToString());
- EXPECT_EQ(source_tiling->contents_scale(),
- target_tiling->contents_scale());
- }
-
- EXPECT_EQ(source_->client(), &source_client_);
- EXPECT_EQ(target_->client(), &target_client_);
- ValidateTargetTilingSet();
- }
-
- void ValidateTargetTilingSet() {
- // Tilings should be sorted largest to smallest.
- if (target_->num_tilings() > 0) {
- float last_scale = target_->tiling_at(0)->contents_scale();
- for (size_t i = 1; i < target_->num_tilings(); ++i) {
- const PictureLayerTiling* target_tiling = target_->tiling_at(i);
- EXPECT_LT(target_tiling->contents_scale(), last_scale);
- last_scale = target_tiling->contents_scale();
- }
- }
-
- for (size_t i = 0; i < target_->num_tilings(); ++i)
- ValidateTiling(target_->tiling_at(i), target_client_.GetRasterSource());
- }
-
- void ValidateTiling(const PictureLayerTiling* tiling,
- const RasterSource* raster_source) {
- if (tiling->tiling_size().IsEmpty()) {
- EXPECT_TRUE(tiling->live_tiles_rect().IsEmpty());
- } else if (!tiling->live_tiles_rect().IsEmpty()) {
- gfx::Rect tiling_rect(tiling->tiling_size());
- EXPECT_TRUE(tiling_rect.Contains(tiling->live_tiles_rect()));
- }
-
- std::vector<Tile*> tiles = tiling->AllTilesForTesting();
- for (size_t i = 0; i < tiles.size(); ++i) {
- const Tile* tile = tiles[i];
- ASSERT_TRUE(!!tile);
- EXPECT_EQ(tile->raster_source(), raster_source);
- EXPECT_TRUE(tile->content_rect().Intersects(tiling->live_tiles_rect()))
- << "All tiles must be inside the live tiles rect."
- << " Tile rect: " << tile->content_rect().ToString()
- << " Live rect: " << tiling->live_tiles_rect().ToString()
- << " Scale: " << tiling->contents_scale();
- }
-
- for (PictureLayerTiling::CoverageIterator iter(
- tiling, tiling->contents_scale(), tiling->live_tiles_rect());
- iter;
- ++iter) {
- EXPECT_TRUE(*iter) << "The live tiles rect must be full.";
- }
- }
-
- gfx::Size tile_size_;
-
- FakePictureLayerTilingClient source_client_;
- gfx::Size source_bounds_;
- scoped_ptr<PictureLayerTilingSet> source_;
-
- FakePictureLayerTilingClient target_client_;
- gfx::Size target_bounds_;
- scoped_ptr<PictureLayerTilingSet> target_;
-};
-
-TEST_F(PictureLayerTilingSetSyncTest, EmptyBounds) {
- float source_scales[] = {1.f, 1.2f};
- for (size_t i = 0; i < arraysize(source_scales); ++i)
- source_->AddTiling(source_scales[i], source_bounds_);
-
- gfx::Size empty_bounds;
- SyncTilings(empty_bounds);
- EXPECT_EQ(target_->num_tilings(), 0u);
-}
-
-TEST_F(PictureLayerTilingSetSyncTest, AllNew) {
- float source_scales[] = {0.5f, 1.f, 1.2f};
- for (size_t i = 0; i < arraysize(source_scales); ++i)
- source_->AddTiling(source_scales[i], source_bounds_);
- float target_scales[] = {0.75f, 1.4f, 3.f};
- for (size_t i = 0; i < arraysize(target_scales); ++i)
- target_->AddTiling(target_scales[i], target_bounds_);
-
- gfx::Size new_bounds(15, 40);
- SyncTilings(new_bounds);
- VerifyTargetEqualsSource(new_bounds);
-}
-
-Tile* FindTileAtOrigin(PictureLayerTiling* tiling) {
- std::vector<Tile*> tiles = tiling->AllTilesForTesting();
- for (size_t i = 0; i < tiles.size(); ++i) {
- if (tiles[i]->content_rect().origin() == gfx::Point())
- return tiles[i];
- }
- return NULL;
-}
-
-TEST_F(PictureLayerTilingSetSyncTest, KeepExisting) {
- float source_scales[] = {0.7f, 1.f, 1.1f, 2.f};
- for (size_t i = 0; i < arraysize(source_scales); ++i)
- source_->AddTiling(source_scales[i], source_bounds_);
- float target_scales[] = {0.5f, 1.f, 2.f};
- for (size_t i = 0; i < arraysize(target_scales); ++i)
- target_->AddTiling(target_scales[i], target_bounds_);
-
- PictureLayerTiling* tiling1 = source_->TilingAtScale(1.f);
- ASSERT_TRUE(tiling1);
- tiling1->CreateAllTilesForTesting();
- EXPECT_EQ(tiling1->contents_scale(), 1.f);
- Tile* tile1 = FindTileAtOrigin(tiling1);
- ASSERT_TRUE(tile1);
-
- PictureLayerTiling* tiling2 = source_->TilingAtScale(2.f);
- tiling2->CreateAllTilesForTesting();
- ASSERT_TRUE(tiling2);
- EXPECT_EQ(tiling2->contents_scale(), 2.f);
- Tile* tile2 = FindTileAtOrigin(tiling2);
- ASSERT_TRUE(tile2);
-
- gfx::Size new_bounds(15, 40);
- SyncTilings(new_bounds);
- VerifyTargetEqualsSource(new_bounds);
-
- EXPECT_EQ(tiling1, source_->TilingAtScale(1.f));
- EXPECT_EQ(tile1, FindTileAtOrigin(tiling1));
- EXPECT_FALSE(tiling1->live_tiles_rect().IsEmpty());
-
- EXPECT_EQ(tiling2, source_->TilingAtScale(2.f));
- EXPECT_EQ(tile2, FindTileAtOrigin(tiling2));
- EXPECT_FALSE(tiling2->live_tiles_rect().IsEmpty());
-}
-
-TEST_F(PictureLayerTilingSetSyncTest, EmptySet) {
- float target_scales[] = {0.2f, 1.f};
- for (size_t i = 0; i < arraysize(target_scales); ++i)
- target_->AddTiling(target_scales[i], target_bounds_);
-
- gfx::Size new_bounds(15, 40);
- SyncTilings(new_bounds);
- VerifyTargetEqualsSource(new_bounds);
-}
-
-TEST_F(PictureLayerTilingSetSyncTest, MinimumScale) {
- float source_scales[] = {0.7f, 1.f, 1.1f, 2.f};
- for (size_t i = 0; i < arraysize(source_scales); ++i)
- source_->AddTiling(source_scales[i], source_bounds_);
- float target_scales[] = {0.5f, 0.7f, 1.f, 1.1f, 2.f};
- for (size_t i = 0; i < arraysize(target_scales); ++i)
- target_->AddTiling(target_scales[i], target_bounds_);
-
- gfx::Size new_bounds(15, 40);
- float minimum_scale = 1.5f;
- SyncTilings(new_bounds, minimum_scale);
-
- EXPECT_EQ(target_->num_tilings(), 1u);
- EXPECT_EQ(target_->tiling_at(0)->contents_scale(), 2.f);
- ValidateTargetTilingSet();
-}
-
-TEST_F(PictureLayerTilingSetSyncTest, Invalidation) {
- source_->AddTiling(2.f, source_bounds_);
- target_->AddTiling(2.f, target_bounds_);
- target_->tiling_at(0)->CreateAllTilesForTesting();
-
- Region layer_invalidation;
- layer_invalidation.Union(gfx::Rect(0, 0, 1, 1));
- layer_invalidation.Union(gfx::Rect(0, 15, 1, 1));
- // Out of bounds layer_invalidation.
- layer_invalidation.Union(gfx::Rect(100, 100, 1, 1));
-
- Region content_invalidation;
- for (Region::Iterator iter(layer_invalidation); iter.has_rect();
- iter.next()) {
- gfx::Rect content_rect = gfx::ScaleToEnclosingRect(iter.rect(), 2.f);
- content_invalidation.Union(content_rect);
- }
-
- std::vector<Tile*> old_tiles = target_->tiling_at(0)->AllTilesForTesting();
- std::map<gfx::Point, scoped_refptr<Tile>> old_tile_map;
- for (size_t i = 0; i < old_tiles.size(); ++i)
- old_tile_map[old_tiles[i]->content_rect().origin()] = old_tiles[i];
-
- SyncTilings(target_bounds_, layer_invalidation);
- VerifyTargetEqualsSource(target_bounds_);
-
- std::vector<Tile*> new_tiles = target_->tiling_at(0)->AllTilesForTesting();
- for (size_t i = 0; i < new_tiles.size(); ++i) {
- const Tile* tile = new_tiles[i];
- std::map<gfx::Point, scoped_refptr<Tile>>::iterator find =
- old_tile_map.find(tile->content_rect().origin());
- if (content_invalidation.Intersects(tile->content_rect()))
- EXPECT_NE(tile, find->second.get());
- else
- EXPECT_EQ(tile, find->second.get());
- }
-}
-
-TEST_F(PictureLayerTilingSetSyncTest, TileSizeChange) {
- source_->AddTiling(1.f, source_bounds_);
- target_->AddTiling(1.f, target_bounds_);
-
- target_->tiling_at(0)->CreateAllTilesForTesting();
- std::vector<Tile*> original_tiles =
- target_->tiling_at(0)->AllTilesForTesting();
- EXPECT_GT(original_tiles.size(), 0u);
- gfx::Size new_tile_size(100, 100);
- target_client_.SetTileSize(new_tile_size);
- EXPECT_NE(target_->tiling_at(0)->tile_size().ToString(),
- new_tile_size.ToString());
-
- gfx::Size new_bounds(15, 40);
- SyncTilings(new_bounds);
- VerifyTargetEqualsSource(new_bounds);
-
- EXPECT_EQ(target_->tiling_at(0)->tile_size().ToString(),
- new_tile_size.ToString());
-
- // All old tiles should not be present in new tiles.
- std::vector<Tile*> new_tiles = target_->tiling_at(0)->AllTilesForTesting();
- for (size_t i = 0; i < original_tiles.size(); ++i) {
- std::vector<Tile*>::iterator find =
- std::find(new_tiles.begin(), new_tiles.end(), original_tiles[i]);
- EXPECT_TRUE(find == new_tiles.end());
- }
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/resources/picture_pile.h b/chromium/cc/resources/picture_pile.h
deleted file mode 100644
index 18e1e5273aa..00000000000
--- a/chromium/cc/resources/picture_pile.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2012 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_PICTURE_PILE_H_
-#define CC_RESOURCES_PICTURE_PILE_H_
-
-#include "base/memory/ref_counted.h"
-#include "cc/resources/picture_pile_base.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace cc {
-class PicturePileImpl;
-class Region;
-class RenderingStatsInstrumentation;
-
-class CC_EXPORT PicturePile : public PicturePileBase {
- public:
- PicturePile();
- ~PicturePile() override;
-
- // Re-record parts of the picture that are invalid.
- // Invalidations are in layer space, and will be expanded to cover everything
- // that was either recorded/changed or that has no recording, leaving out only
- // pieces that we had a recording for and it was not changed.
- // Return true iff the pile was modified.
- bool UpdateAndExpandInvalidation(
- ContentLayerClient* painter,
- Region* invalidation,
- SkColor background_color,
- bool contents_opaque,
- bool contents_fill_bounds_completely,
- const gfx::Size& layer_size,
- const gfx::Rect& visible_layer_rect,
- int frame_number,
- Picture::RecordingMode recording_mode,
- RenderingStatsInstrumentation* stats_instrumentation);
-
- void SetEmptyBounds();
-
- void set_slow_down_raster_scale_factor(int factor) {
- slow_down_raster_scale_factor_for_debug_ = factor;
- }
-
- void set_show_debug_picture_borders(bool show) {
- show_debug_picture_borders_ = show;
- }
-
- bool is_suitable_for_gpu_rasterization() const {
- return is_suitable_for_gpu_rasterization_;
- }
- void SetUnsuitableForGpuRasterizationForTesting() {
- is_suitable_for_gpu_rasterization_ = false;
- }
-
- void SetPixelRecordDistanceForTesting(int d) { pixel_record_distance_ = d; }
-
- protected:
- // An internal CanRaster check that goes to the picture_map rather than
- // using the recorded_viewport hint.
- bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const;
-
- private:
- friend class PicturePileImpl;
-
- void DetermineIfSolidColor();
-
- bool is_suitable_for_gpu_rasterization_;
- int pixel_record_distance_;
-
- DISALLOW_COPY_AND_ASSIGN(PicturePile);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_PICTURE_PILE_H_
diff --git a/chromium/cc/resources/picture_pile_base.cc b/chromium/cc/resources/picture_pile_base.cc
deleted file mode 100644
index 1184cf1e2a6..00000000000
--- a/chromium/cc/resources/picture_pile_base.cc
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/picture_pile_base.h"
-
-#include <algorithm>
-#include <set>
-#include <vector>
-
-#include "base/debug/trace_event_argument.h"
-#include "base/logging.h"
-#include "base/values.h"
-#include "cc/debug/traced_value.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-
-namespace {
-// Dimensions of the tiles in this picture pile as well as the dimensions of
-// the base picture in each tile.
-const int kBasePictureSize = 512;
-const int kTileGridBorderPixels = 1;
-#ifdef NDEBUG
-const bool kDefaultClearCanvasSetting = false;
-#else
-const bool kDefaultClearCanvasSetting = true;
-#endif
-
-// Invalidation frequency settings. kInvalidationFrequencyThreshold is a value
-// between 0 and 1 meaning invalidation frequency between 0% and 100% that
-// indicates when to stop invalidating offscreen regions.
-// kFrequentInvalidationDistanceThreshold defines what it means to be
-// "offscreen" in terms of distance to visible in css pixels.
-const float kInvalidationFrequencyThreshold = 0.75f;
-const int kFrequentInvalidationDistanceThreshold = 512;
-
-} // namespace
-
-namespace cc {
-
-PicturePileBase::PicturePileBase()
- : min_contents_scale_(0),
- background_color_(SkColorSetARGBInline(0, 0, 0, 0)),
- slow_down_raster_scale_factor_for_debug_(0),
- contents_opaque_(false),
- contents_fill_bounds_completely_(false),
- show_debug_picture_borders_(false),
- clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
- has_any_recordings_(false),
- is_mask_(false),
- is_solid_color_(false),
- solid_color_(SK_ColorTRANSPARENT) {
- tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
- tile_grid_info_.fTileInterval.setEmpty();
- tile_grid_info_.fMargin.setEmpty();
- tile_grid_info_.fOffset.setZero();
-}
-
-PicturePileBase::PicturePileBase(const PicturePileBase* other)
- : picture_map_(other->picture_map_),
- tiling_(other->tiling_),
- recorded_viewport_(other->recorded_viewport_),
- min_contents_scale_(other->min_contents_scale_),
- tile_grid_info_(other->tile_grid_info_),
- background_color_(other->background_color_),
- slow_down_raster_scale_factor_for_debug_(
- other->slow_down_raster_scale_factor_for_debug_),
- contents_opaque_(other->contents_opaque_),
- contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
- show_debug_picture_borders_(other->show_debug_picture_borders_),
- clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
- has_any_recordings_(other->has_any_recordings_),
- is_mask_(other->is_mask_),
- is_solid_color_(other->is_solid_color_),
- solid_color_(other->solid_color_) {
-}
-
-PicturePileBase::~PicturePileBase() {
-}
-
-void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
- DCHECK(min_contents_scale);
- if (min_contents_scale_ == min_contents_scale)
- return;
-
- // Picture contents are played back scaled. When the final contents scale is
- // less than 1 (i.e. low res), then multiple recorded pixels will be used
- // to raster one final pixel. To avoid splitting a final pixel across
- // pictures (which would result in incorrect rasterization due to blending), a
- // buffer margin is added so that any picture can be snapped to integral
- // final pixels.
- //
- // For example, if a 1/4 contents scale is used, then that would be 3 buffer
- // pixels, since that's the minimum number of pixels to add so that resulting
- // content can be snapped to a four pixel aligned grid.
- int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
- buffer_pixels = std::max(0, buffer_pixels);
- SetBufferPixels(buffer_pixels);
- min_contents_scale_ = min_contents_scale;
-}
-
-// static
-void PicturePileBase::ComputeTileGridInfo(
- const gfx::Size& tile_grid_size,
- SkTileGridFactory::TileGridInfo* info) {
- DCHECK(info);
- info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
- tile_grid_size.height() - 2 * kTileGridBorderPixels);
- DCHECK_GT(info->fTileInterval.width(), 0);
- DCHECK_GT(info->fTileInterval.height(), 0);
- info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
- // Offset the tile grid coordinate space to take into account the fact
- // that the top-most and left-most tiles do not have top and left borders
- // respectively.
- info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
-}
-
-void PicturePileBase::SetTileGridSize(const gfx::Size& tile_grid_size) {
- ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
-}
-
-void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
- if (new_buffer_pixels == buffer_pixels())
- return;
-
- Clear();
- tiling_.SetBorderTexels(new_buffer_pixels);
-}
-
-void PicturePileBase::Clear() {
- picture_map_.clear();
- recorded_viewport_ = gfx::Rect();
- has_any_recordings_ = false;
- is_solid_color_ = false;
-}
-
-bool PicturePileBase::HasRecordingAt(int x, int y) {
- PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
- if (found == picture_map_.end())
- return false;
- return !!found->second.GetPicture();
-}
-
-gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) const {
- gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
- return PadRect(tile);
-}
-
-gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) const {
- gfx::Rect padded_rect = rect;
- padded_rect.Inset(
- -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
- return padded_rect;
-}
-
-PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
-
-PicturePileBase::PictureInfo::~PictureInfo() {}
-
-void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
- int frame_number) {
- DCHECK_GE(frame_number, last_frame_number_);
- if (frame_number == last_frame_number_)
- return;
-
- invalidation_history_ <<= (frame_number - last_frame_number_);
- last_frame_number_ = frame_number;
-}
-
-bool PicturePileBase::PictureInfo::Invalidate(int frame_number) {
- AdvanceInvalidationHistory(frame_number);
- invalidation_history_.set(0);
-
- bool did_invalidate = !!picture_.get();
- picture_ = NULL;
- return did_invalidate;
-}
-
-bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number,
- int distance_to_visible) {
- AdvanceInvalidationHistory(frame_number);
-
- // We only need recording if we don't have a picture. Furthermore, we only
- // need a recording if we're within frequent invalidation distance threshold
- // or the invalidation is not frequent enough (below invalidation frequency
- // threshold).
- return !picture_.get() &&
- ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
- (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
-}
-
-void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
- picture_ = picture;
-}
-
-const Picture* PicturePileBase::PictureInfo::GetPicture() const {
- return picture_.get();
-}
-
-float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
- return invalidation_history_.count() /
- static_cast<float>(INVALIDATION_FRAMES_TRACKED);
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/picture_pile_base.h b/chromium/cc/resources/picture_pile_base.h
deleted file mode 100644
index 66d37d81b88..00000000000
--- a/chromium/cc/resources/picture_pile_base.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_PICTURE_PILE_BASE_H_
-#define CC_RESOURCES_PICTURE_PILE_BASE_H_
-
-#include <bitset>
-#include <list>
-#include <utility>
-
-#include "base/containers/hash_tables.h"
-#include "cc/base/cc_export.h"
-#include "cc/base/region.h"
-#include "cc/base/tiling_data.h"
-#include "cc/resources/picture.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace base {
-namespace debug {
-class TracedValue;
-}
-class Value;
-}
-
-namespace cc {
-
-class CC_EXPORT PicturePileBase {
- public:
- PicturePileBase();
- explicit PicturePileBase(const PicturePileBase* other);
-
- gfx::Size tiling_size() const { return tiling_.tiling_size(); }
- void SetMinContentsScale(float min_contents_scale);
-
- // If non-empty, all pictures tiles inside this rect are recorded. There may
- // be recordings outside this rect, but everything inside the rect is
- // recorded.
- gfx::Rect recorded_viewport() const { return recorded_viewport_; }
-
- int num_tiles_x() const { return tiling_.num_tiles_x(); }
- int num_tiles_y() const { return tiling_.num_tiles_y(); }
- gfx::Rect tile_bounds(int x, int y) const { return tiling_.TileBounds(x, y); }
- bool HasRecordingAt(int x, int y);
-
- bool is_solid_color() const { return is_solid_color_; }
- SkColor solid_color() const { return solid_color_; }
-
- void set_is_mask(bool is_mask) { is_mask_ = is_mask; }
-
- static void ComputeTileGridInfo(const gfx::Size& tile_grid_size,
- SkTileGridFactory::TileGridInfo* info);
-
- void SetTileGridSize(const gfx::Size& tile_grid_size);
- TilingData& tiling() { return tiling_; }
-
- SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const {
- return tile_grid_info_;
- }
-
- void SetRecordedViewportForTesting(const gfx::Rect& viewport) {
- recorded_viewport_ = viewport;
- }
- void SetHasAnyRecordingsForTesting(bool has_recordings) {
- has_any_recordings_ = has_recordings;
- }
-
- protected:
- class CC_EXPORT PictureInfo {
- public:
- enum {
- INVALIDATION_FRAMES_TRACKED = 32
- };
-
- PictureInfo();
- ~PictureInfo();
-
- bool Invalidate(int frame_number);
- bool NeedsRecording(int frame_number, int distance_to_visible);
- void SetPicture(scoped_refptr<Picture> picture);
- const Picture* GetPicture() const;
-
- float GetInvalidationFrequencyForTesting() const {
- return GetInvalidationFrequency();
- }
-
- private:
- void AdvanceInvalidationHistory(int frame_number);
- float GetInvalidationFrequency() const;
-
- int last_frame_number_;
- scoped_refptr<const Picture> picture_;
- std::bitset<INVALIDATION_FRAMES_TRACKED> invalidation_history_;
- };
-
- typedef std::pair<int, int> PictureMapKey;
- typedef base::hash_map<PictureMapKey, PictureInfo> PictureMap;
-
- virtual ~PicturePileBase();
-
- int buffer_pixels() const { return tiling_.border_texels(); }
- void Clear();
-
- gfx::Rect PaddedRect(const PictureMapKey& key) const;
- gfx::Rect PadRect(const gfx::Rect& rect) const;
-
- // A picture pile is a tiled set of pictures. The picture map is a map of tile
- // indices to picture infos.
- PictureMap picture_map_;
- TilingData tiling_;
- gfx::Rect recorded_viewport_;
- float min_contents_scale_;
- SkTileGridFactory::TileGridInfo tile_grid_info_;
- SkColor background_color_;
- int slow_down_raster_scale_factor_for_debug_;
- bool contents_opaque_;
- bool contents_fill_bounds_completely_;
- bool show_debug_picture_borders_;
- bool clear_canvas_with_debug_color_;
- // A hint about whether there are any recordings. This may be a false
- // positive.
- bool has_any_recordings_;
- bool is_mask_;
- bool is_solid_color_;
- SkColor solid_color_;
-
- private:
- friend class PicturePileImpl;
-
- void SetBufferPixels(int buffer_pixels);
-
- DISALLOW_COPY_AND_ASSIGN(PicturePileBase);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_PICTURE_PILE_BASE_H_
diff --git a/chromium/cc/resources/picture_unittest.cc b/chromium/cc/resources/picture_unittest.cc
deleted file mode 100644
index 07faf0cf4a6..00000000000
--- a/chromium/cc/resources/picture_unittest.cc
+++ /dev/null
@@ -1,475 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/picture.h"
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/values.h"
-#include "cc/test/fake_content_layer_client.h"
-#include "cc/test/skia_common.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBBHFactory.h"
-#include "third_party/skia/include/core/SkGraphics.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/skia_util.h"
-
-namespace cc {
-namespace {
-
-TEST(PictureTest, AsBase64String) {
- SkGraphics::Init();
-
- gfx::Rect layer_rect(100, 100);
-
- SkTileGridFactory::TileGridInfo tile_grid_info;
- tile_grid_info.fTileInterval = SkISize::Make(100, 100);
- tile_grid_info.fMargin.setEmpty();
- tile_grid_info.fOffset.setZero();
-
- FakeContentLayerClient content_layer_client;
-
- scoped_ptr<base::Value> tmp;
-
- SkPaint red_paint;
- red_paint.setColor(SkColorSetARGB(255, 255, 0, 0));
- SkPaint green_paint;
- green_paint.setColor(SkColorSetARGB(255, 0, 255, 0));
-
- // Invalid picture (not a dict).
- tmp.reset(new base::StringValue("abc!@#$%"));
- scoped_refptr<Picture> invalid_picture =
- Picture::CreateFromValue(tmp.get());
- EXPECT_FALSE(invalid_picture.get());
-
- // Single full-size rect picture.
- content_layer_client.add_draw_rect(layer_rect, red_paint);
-
- scoped_refptr<Picture> one_rect_picture =
- Picture::Create(layer_rect,
- &content_layer_client,
- tile_grid_info,
- false,
- Picture::RECORD_NORMALLY);
- scoped_ptr<base::Value> serialized_one_rect(one_rect_picture->AsValue());
-
- // Reconstruct the picture.
- scoped_refptr<Picture> one_rect_picture_check =
- Picture::CreateFromValue(serialized_one_rect.get());
- EXPECT_TRUE(!!one_rect_picture_check.get());
-
- // Check for equivalence.
- unsigned char one_rect_buffer[4 * 100 * 100] = {0};
- DrawPicture(one_rect_buffer, layer_rect, one_rect_picture);
- unsigned char one_rect_buffer_check[4 * 100 * 100] = {0};
- DrawPicture(one_rect_buffer_check, layer_rect, one_rect_picture_check);
-
- EXPECT_EQ(one_rect_picture->LayerRect(), one_rect_picture_check->LayerRect());
- EXPECT_EQ(0, memcmp(one_rect_buffer, one_rect_buffer_check, 4 * 100 * 100));
-
- // Two rect picture.
- content_layer_client.add_draw_rect(gfx::Rect(25, 25, 50, 50), green_paint);
-
- scoped_refptr<Picture> two_rect_picture =
- Picture::Create(layer_rect,
- &content_layer_client,
- tile_grid_info,
- false,
- Picture::RECORD_NORMALLY);
-
- scoped_ptr<base::Value> serialized_two_rect(two_rect_picture->AsValue());
-
- // Reconstruct the picture.
- scoped_refptr<Picture> two_rect_picture_check =
- Picture::CreateFromValue(serialized_two_rect.get());
- EXPECT_TRUE(!!two_rect_picture_check.get());
-
- // Check for equivalence.
- unsigned char two_rect_buffer[4 * 100 * 100] = {0};
- DrawPicture(two_rect_buffer, layer_rect, two_rect_picture);
- unsigned char two_rect_buffer_check[4 * 100 * 100] = {0};
- DrawPicture(two_rect_buffer_check, layer_rect, two_rect_picture_check);
-
- EXPECT_EQ(two_rect_picture->LayerRect(), two_rect_picture_check->LayerRect());
- EXPECT_EQ(0, memcmp(two_rect_buffer, two_rect_buffer_check, 4 * 100 * 100));
-}
-
-TEST(PictureTest, PixelRefIterator) {
- gfx::Rect layer_rect(2048, 2048);
-
- SkTileGridFactory::TileGridInfo tile_grid_info;
- tile_grid_info.fTileInterval = SkISize::Make(512, 512);
- tile_grid_info.fMargin.setEmpty();
- tile_grid_info.fOffset.setZero();
-
- FakeContentLayerClient content_layer_client;
-
- // Discardable pixel refs are found in the following grids:
- // |---|---|---|---|
- // | | x | | x |
- // |---|---|---|---|
- // | x | | x | |
- // |---|---|---|---|
- // | | x | | x |
- // |---|---|---|---|
- // | x | | x | |
- // |---|---|---|---|
- SkBitmap discardable_bitmap[4][4];
- for (int y = 0; y < 4; ++y) {
- for (int x = 0; x < 4; ++x) {
- if ((x + y) & 1) {
- CreateBitmap(
- gfx::Size(500, 500), "discardable", &discardable_bitmap[y][x]);
- SkPaint paint;
- content_layer_client.add_draw_bitmap(
- discardable_bitmap[y][x],
- gfx::Point(x * 512 + 6, y * 512 + 6), paint);
- }
- }
- }
-
- scoped_refptr<Picture> picture = Picture::Create(layer_rect,
- &content_layer_client,
- tile_grid_info,
- true,
- Picture::RECORD_NORMALLY);
-
- // Default iterator does not have any pixel refs
- {
- Picture::PixelRefIterator iterator;
- EXPECT_FALSE(iterator);
- }
- for (int y = 0; y < 4; ++y) {
- for (int x = 0; x < 4; ++x) {
- Picture::PixelRefIterator iterator(gfx::Rect(x * 512, y * 512, 500, 500),
- picture.get());
- if ((x + y) & 1) {
- EXPECT_TRUE(iterator) << x << " " << y;
- EXPECT_TRUE(*iterator == discardable_bitmap[y][x].pixelRef()) << x <<
- " " << y;
- EXPECT_FALSE(++iterator) << x << " " << y;
- } else {
- EXPECT_FALSE(iterator) << x << " " << y;
- }
- }
- }
- // Capture 4 pixel refs.
- {
- Picture::PixelRefIterator iterator(gfx::Rect(512, 512, 2048, 2048),
- picture.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
- EXPECT_FALSE(++iterator);
- }
-
- // Copy test.
- Picture::PixelRefIterator iterator(gfx::Rect(512, 512, 2048, 2048),
- picture.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
-
- // copy now points to the same spot as iterator,
- // but both can be incremented independently.
- Picture::PixelRefIterator copy = iterator;
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
- EXPECT_FALSE(++iterator);
-
- EXPECT_TRUE(copy);
- EXPECT_TRUE(*copy == discardable_bitmap[2][1].pixelRef());
- EXPECT_TRUE(++copy);
- EXPECT_TRUE(*copy == discardable_bitmap[2][3].pixelRef());
- EXPECT_TRUE(++copy);
- EXPECT_TRUE(*copy == discardable_bitmap[3][2].pixelRef());
- EXPECT_FALSE(++copy);
-}
-
-TEST(PictureTest, PixelRefIteratorNonZeroLayer) {
- gfx::Rect layer_rect(1024, 0, 2048, 2048);
-
- SkTileGridFactory::TileGridInfo tile_grid_info;
- tile_grid_info.fTileInterval = SkISize::Make(512, 512);
- tile_grid_info.fMargin.setEmpty();
- tile_grid_info.fOffset.setZero();
-
- FakeContentLayerClient content_layer_client;
-
- // Discardable pixel refs are found in the following grids:
- // |---|---|---|---|
- // | | x | | x |
- // |---|---|---|---|
- // | x | | x | |
- // |---|---|---|---|
- // | | x | | x |
- // |---|---|---|---|
- // | x | | x | |
- // |---|---|---|---|
- SkBitmap discardable_bitmap[4][4];
- for (int y = 0; y < 4; ++y) {
- for (int x = 0; x < 4; ++x) {
- if ((x + y) & 1) {
- CreateBitmap(
- gfx::Size(500, 500), "discardable", &discardable_bitmap[y][x]);
- SkPaint paint;
- content_layer_client.add_draw_bitmap(
- discardable_bitmap[y][x],
- gfx::Point(1024 + x * 512 + 6, y * 512 + 6), paint);
- }
- }
- }
-
- scoped_refptr<Picture> picture = Picture::Create(layer_rect,
- &content_layer_client,
- tile_grid_info,
- true,
- Picture::RECORD_NORMALLY);
-
- // Default iterator does not have any pixel refs
- {
- Picture::PixelRefIterator iterator;
- EXPECT_FALSE(iterator);
- }
- for (int y = 0; y < 4; ++y) {
- for (int x = 0; x < 4; ++x) {
- Picture::PixelRefIterator iterator(
- gfx::Rect(1024 + x * 512, y * 512, 500, 500), picture.get());
- if ((x + y) & 1) {
- EXPECT_TRUE(iterator) << x << " " << y;
- EXPECT_TRUE(*iterator == discardable_bitmap[y][x].pixelRef());
- EXPECT_FALSE(++iterator) << x << " " << y;
- } else {
- EXPECT_FALSE(iterator) << x << " " << y;
- }
- }
- }
- // Capture 4 pixel refs.
- {
- Picture::PixelRefIterator iterator(gfx::Rect(1024 + 512, 512, 2048, 2048),
- picture.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
- EXPECT_FALSE(++iterator);
- }
-
- // Copy test.
- {
- Picture::PixelRefIterator iterator(gfx::Rect(1024 + 512, 512, 2048, 2048),
- picture.get());
- EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
-
- // copy now points to the same spot as iterator,
- // but both can be incremented independently.
- Picture::PixelRefIterator copy = iterator;
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
- EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
- EXPECT_FALSE(++iterator);
-
- EXPECT_TRUE(copy);
- EXPECT_TRUE(*copy == discardable_bitmap[2][1].pixelRef());
- EXPECT_TRUE(++copy);
- EXPECT_TRUE(*copy == discardable_bitmap[2][3].pixelRef());
- EXPECT_TRUE(++copy);
- EXPECT_TRUE(*copy == discardable_bitmap[3][2].pixelRef());
- EXPECT_FALSE(++copy);
- }
-
- // Non intersecting rects
- {
- Picture::PixelRefIterator iterator(gfx::Rect(0, 0, 1000, 1000),
- picture.get());
- EXPECT_FALSE(iterator);
- }
- {
- Picture::PixelRefIterator iterator(gfx::Rect(3500, 0, 1000, 1000),
- picture.get());
- EXPECT_FALSE(iterator);
- }
- {
- Picture::PixelRefIterator iterator(gfx::Rect(0, 1100, 1000, 1000),
- picture.get());
- EXPECT_FALSE(iterator);
- }
- {
- Picture::PixelRefIterator iterator(gfx::Rect(3500, 1100, 1000, 1000),
- picture.get());
- EXPECT_FALSE(iterator);
- }
-}
-
-TEST(PictureTest, PixelRefIteratorOnePixelQuery) {
- gfx::Rect layer_rect(2048, 2048);
-
- SkTileGridFactory::TileGridInfo tile_grid_info;
- tile_grid_info.fTileInterval = SkISize::Make(512, 512);
- tile_grid_info.fMargin.setEmpty();
- tile_grid_info.fOffset.setZero();
-
- FakeContentLayerClient content_layer_client;
-
- // Discardable pixel refs are found in the following grids:
- // |---|---|---|---|
- // | | x | | x |
- // |---|---|---|---|
- // | x | | x | |
- // |---|---|---|---|
- // | | x | | x |
- // |---|---|---|---|
- // | x | | x | |
- // |---|---|---|---|
- SkBitmap discardable_bitmap[4][4];
- for (int y = 0; y < 4; ++y) {
- for (int x = 0; x < 4; ++x) {
- if ((x + y) & 1) {
- CreateBitmap(
- gfx::Size(500, 500), "discardable", &discardable_bitmap[y][x]);
- SkPaint paint;
- content_layer_client.add_draw_bitmap(
- discardable_bitmap[y][x],
- gfx::Point(x * 512 + 6, y * 512 + 6), paint);
- }
- }
- }
-
- scoped_refptr<Picture> picture = Picture::Create(layer_rect,
- &content_layer_client,
- tile_grid_info,
- true,
- Picture::RECORD_NORMALLY);
-
- for (int y = 0; y < 4; ++y) {
- for (int x = 0; x < 4; ++x) {
- Picture::PixelRefIterator iterator(
- gfx::Rect(x * 512, y * 512 + 256, 1, 1), picture.get());
- if ((x + y) & 1) {
- EXPECT_TRUE(iterator) << x << " " << y;
- EXPECT_TRUE(*iterator == discardable_bitmap[y][x].pixelRef());
- EXPECT_FALSE(++iterator) << x << " " << y;
- } else {
- EXPECT_FALSE(iterator) << x << " " << y;
- }
- }
- }
-}
-
-TEST(PictureTest, CreateFromSkpValue) {
- SkGraphics::Init();
-
- gfx::Rect layer_rect(100, 200);
-
- SkTileGridFactory::TileGridInfo tile_grid_info;
- tile_grid_info.fTileInterval = SkISize::Make(100, 200);
- tile_grid_info.fMargin.setEmpty();
- tile_grid_info.fOffset.setZero();
-
- FakeContentLayerClient content_layer_client;
-
- scoped_ptr<base::Value> tmp;
-
- SkPaint red_paint;
- red_paint.setColor(SkColorSetARGB(255, 255, 0, 0));
- SkPaint green_paint;
- green_paint.setColor(SkColorSetARGB(255, 0, 255, 0));
-
- // Invalid picture (not a dict).
- tmp.reset(new base::StringValue("abc!@#$%"));
- scoped_refptr<Picture> invalid_picture =
- Picture::CreateFromSkpValue(tmp.get());
- EXPECT_TRUE(!invalid_picture.get());
-
- // Single full-size rect picture.
- content_layer_client.add_draw_rect(layer_rect, red_paint);
- scoped_refptr<Picture> one_rect_picture =
- Picture::Create(layer_rect,
- &content_layer_client,
- tile_grid_info,
- false,
- Picture::RECORD_NORMALLY);
- scoped_ptr<base::Value> serialized_one_rect(
- one_rect_picture->AsValue());
-
- const base::DictionaryValue* value = NULL;
- EXPECT_TRUE(serialized_one_rect->GetAsDictionary(&value));
-
- // Decode the picture from base64.
- const base::Value* skp_value;
- EXPECT_TRUE(value->Get("skp64", &skp_value));
-
- // Reconstruct the picture.
- scoped_refptr<Picture> one_rect_picture_check =
- Picture::CreateFromSkpValue(skp_value);
- EXPECT_TRUE(!!one_rect_picture_check.get());
-
- EXPECT_EQ(100, one_rect_picture_check->LayerRect().width());
- EXPECT_EQ(200, one_rect_picture_check->LayerRect().height());
-}
-
-TEST(PictureTest, RecordingModes) {
- SkGraphics::Init();
-
- gfx::Rect layer_rect(100, 200);
-
- SkTileGridFactory::TileGridInfo tile_grid_info;
- tile_grid_info.fTileInterval = SkISize::Make(100, 200);
- tile_grid_info.fMargin.setEmpty();
- tile_grid_info.fOffset.setZero();
-
- FakeContentLayerClient content_layer_client;
- EXPECT_EQ(NULL, content_layer_client.last_canvas());
-
- scoped_refptr<Picture> picture = Picture::Create(layer_rect,
- &content_layer_client,
- tile_grid_info,
- false,
- Picture::RECORD_NORMALLY);
- EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
- EXPECT_EQ(ContentLayerClient::GRAPHICS_CONTEXT_ENABLED,
- content_layer_client.last_context_status());
- EXPECT_TRUE(picture.get());
-
- picture = Picture::Create(layer_rect,
- &content_layer_client,
- tile_grid_info,
- false,
- Picture::RECORD_WITH_SK_NULL_CANVAS);
- EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
- EXPECT_EQ(ContentLayerClient::GRAPHICS_CONTEXT_ENABLED,
- content_layer_client.last_context_status());
- EXPECT_TRUE(picture.get());
-
- picture = Picture::Create(layer_rect,
- &content_layer_client,
- tile_grid_info,
- false,
- Picture::RECORD_WITH_PAINTING_DISABLED);
- EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
- EXPECT_EQ(ContentLayerClient::GRAPHICS_CONTEXT_DISABLED,
- content_layer_client.last_context_status());
- EXPECT_TRUE(picture.get());
-
- EXPECT_EQ(3, Picture::RECORDING_MODE_COUNT);
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/resources/platform_color.h b/chromium/cc/resources/platform_color.h
index 4945dccadc5..17eddc1faa7 100644
--- a/chromium/cc/resources/platform_color.h
+++ b/chromium/cc/resources/platform_color.h
@@ -8,8 +8,6 @@
#include "base/basictypes.h"
#include "base/logging.h"
#include "cc/resources/resource_format.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkTypes.h"
namespace cc {
diff --git a/chromium/cc/resources/platform_color_unittest.cc b/chromium/cc/resources/platform_color_unittest.cc
new file mode 100644
index 00000000000..83b2a1e47f3
--- /dev/null
+++ b/chromium/cc/resources/platform_color_unittest.cc
@@ -0,0 +1,42 @@
+// 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.
+
+#include "cc/resources/platform_color.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+// Verify SameComponentOrder on this platform.
+TEST(PlatformColorTest, SameComponentOrder) {
+ bool rgba = !!SK_B32_SHIFT;
+
+ for (size_t i = 0; i <= RESOURCE_FORMAT_MAX; ++i) {
+ ResourceFormat format = static_cast<ResourceFormat>(i);
+ switch (format) {
+ case RGBA_8888:
+ EXPECT_EQ(rgba, PlatformColor::SameComponentOrder(format));
+ break;
+ case RGBA_4444:
+ // RGBA_4444 indicates the number of bytes per pixel but the format
+ // doesn't actually imply RGBA ordering. It uses the native ordering.
+ EXPECT_EQ(true, PlatformColor::SameComponentOrder(format));
+ break;
+ case BGRA_8888:
+ EXPECT_NE(rgba, PlatformColor::SameComponentOrder(format));
+ break;
+ case ALPHA_8:
+ case LUMINANCE_8:
+ case RGB_565:
+ case ETC1:
+ case RED_8:
+ EXPECT_FALSE(PlatformColor::SameComponentOrder(format));
+ break;
+ }
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/resources/prioritized_resource.cc b/chromium/cc/resources/prioritized_resource.cc
index 462f7f1bb0c..968083cb968 100644
--- a/chromium/cc/resources/prioritized_resource.cc
+++ b/chromium/cc/resources/prioritized_resource.cc
@@ -126,7 +126,7 @@ PrioritizedResource::Backing::Backing(unsigned id,
was_above_priority_cutoff_at_last_priority_update_(false),
in_drawing_impl_tree_(false),
in_parent_compositor_(false),
-#if !DCHECK_IS_ON
+#if !DCHECK_IS_ON()
resource_has_been_deleted_(false) {
#else
resource_has_been_deleted_(false),
@@ -143,7 +143,7 @@ void PrioritizedResource::Backing::DeleteResource(
ResourceProvider* resource_provider) {
DCHECK(!proxy() || proxy()->IsImplThread());
DCHECK(!resource_has_been_deleted_);
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(resource_provider == resource_provider_);
#endif
diff --git a/chromium/cc/resources/prioritized_resource.h b/chromium/cc/resources/prioritized_resource.h
index e3bb2bc4d1c..3b6ecc028e8 100644
--- a/chromium/cc/resources/prioritized_resource.h
+++ b/chromium/cc/resources/prioritized_resource.h
@@ -142,7 +142,7 @@ class CC_EXPORT PrioritizedResource {
bool resource_has_been_deleted_;
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
ResourceProvider* resource_provider_;
#endif
DISALLOW_COPY_AND_ASSIGN(Backing);
diff --git a/chromium/cc/resources/prioritized_resource_manager.cc b/chromium/cc/resources/prioritized_resource_manager.cc
index 657c14f4ddf..236377b8511 100644
--- a/chromium/cc/resources/prioritized_resource_manager.cc
+++ b/chromium/cc/resources/prioritized_resource_manager.cc
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/priority_calculator.h"
#include "cc/trees/proxy.h"
@@ -451,11 +451,8 @@ PrioritizedResource::Backing* PrioritizedResourceManager::CreateBacking(
DCHECK(resource_provider);
ResourceProvider::ResourceId resource_id =
resource_provider->CreateManagedResource(
- size,
- GL_TEXTURE_2D,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- format);
+ size, GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
PrioritizedResource::Backing* backing = new PrioritizedResource::Backing(
resource_id, resource_provider, size, format);
memory_use_bytes_ += backing->bytes();
@@ -481,7 +478,7 @@ void PrioritizedResourceManager::EvictFirstBackingResource(
}
void PrioritizedResourceManager::AssertInvariants() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked());
// If we hit any of these asserts, there is a bug in this class. To see
@@ -540,7 +537,7 @@ void PrioritizedResourceManager::AssertInvariants() {
DCHECK(backing->CanBeRecycledIfNotInExternalUse());
previous_backing = backing;
}
-#endif // DCHECK_IS_ON
+#endif // DCHECK_IS_ON()
}
const Proxy* PrioritizedResourceManager::ProxyForDebug() const {
diff --git a/chromium/cc/resources/prioritized_resource_unittest.cc b/chromium/cc/resources/prioritized_resource_unittest.cc
index 8869e706036..f08af8b752e 100644
--- a/chromium/cc/resources/prioritized_resource_unittest.cc
+++ b/chromium/cc/resources/prioritized_resource_unittest.cc
@@ -37,7 +37,7 @@ class PrioritizedResourceTest : public testing::Test {
1);
}
- virtual ~PrioritizedResourceTest() {
+ ~PrioritizedResourceTest() override {
DebugScopedSetImplThread impl_thread(&proxy_);
resource_provider_ = nullptr;
}
diff --git a/chromium/cc/resources/raster_tile_priority_queue.cc b/chromium/cc/resources/raster_tile_priority_queue.cc
deleted file mode 100644
index 667d54d89c1..00000000000
--- a/chromium/cc/resources/raster_tile_priority_queue.cc
+++ /dev/null
@@ -1,310 +0,0 @@
-// Copyright 2014 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/raster_tile_priority_queue.h"
-
-namespace cc {
-
-namespace {
-
-class RasterOrderComparator {
- public:
- explicit RasterOrderComparator(TreePriority tree_priority)
- : tree_priority_(tree_priority) {}
-
- bool operator()(
- const RasterTilePriorityQueue::PairedPictureLayerQueue* a,
- const RasterTilePriorityQueue::PairedPictureLayerQueue* b) const {
- // Note that in this function, we have to return true if and only if
- // a is strictly lower priority than b. Note that for the sake of
- // completeness, empty queue is considered to have lowest priority.
- if (a->IsEmpty() || b->IsEmpty())
- return b->IsEmpty() < a->IsEmpty();
-
- WhichTree a_tree = a->NextTileIteratorTree(tree_priority_);
- const PictureLayerImpl::LayerRasterTileIterator* a_iterator =
- a_tree == ACTIVE_TREE ? &a->active_iterator : &a->pending_iterator;
-
- WhichTree b_tree = b->NextTileIteratorTree(tree_priority_);
- const PictureLayerImpl::LayerRasterTileIterator* b_iterator =
- b_tree == ACTIVE_TREE ? &b->active_iterator : &b->pending_iterator;
-
- const Tile* a_tile = **a_iterator;
- const Tile* b_tile = **b_iterator;
-
- const TilePriority& a_priority =
- a_tile->priority_for_tree_priority(tree_priority_);
- const TilePriority& b_priority =
- b_tile->priority_for_tree_priority(tree_priority_);
- bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY;
-
- // In smoothness mode, we should return pending NOW tiles before active
- // EVENTUALLY tiles. So if both priorities here are eventually, we need to
- // check the pending priority.
- if (prioritize_low_res &&
- a_priority.priority_bin == TilePriority::EVENTUALLY &&
- b_priority.priority_bin == TilePriority::EVENTUALLY) {
- bool a_is_pending_now =
- a_tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW;
- bool b_is_pending_now =
- b_tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW;
- if (a_is_pending_now || b_is_pending_now)
- return a_is_pending_now < b_is_pending_now;
-
- // In case neither one is pending now, fall through.
- }
-
- // If the bin is the same but the resolution is not, then the order will be
- // determined by whether we prioritize low res or not.
- // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile
- // class but instead produced by the iterators.
- if (b_priority.priority_bin == a_priority.priority_bin &&
- b_priority.resolution != a_priority.resolution) {
- // Non ideal resolution should be sorted lower than other resolutions.
- if (a_priority.resolution == NON_IDEAL_RESOLUTION)
- return true;
-
- if (b_priority.resolution == NON_IDEAL_RESOLUTION)
- return false;
-
- if (prioritize_low_res)
- return b_priority.resolution == LOW_RESOLUTION;
- return b_priority.resolution == HIGH_RESOLUTION;
- }
-
- return b_priority.IsHigherPriorityThan(a_priority);
- }
-
- private:
- TreePriority tree_priority_;
-};
-
-WhichTree HigherPriorityTree(
- TreePriority tree_priority,
- const PictureLayerImpl::LayerRasterTileIterator* active_iterator,
- const PictureLayerImpl::LayerRasterTileIterator* pending_iterator,
- const Tile* shared_tile) {
- switch (tree_priority) {
- case SMOOTHNESS_TAKES_PRIORITY: {
- const Tile* active_tile = shared_tile ? shared_tile : **active_iterator;
- const Tile* pending_tile = shared_tile ? shared_tile : **pending_iterator;
-
- const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE);
- const TilePriority& pending_priority =
- pending_tile->priority(PENDING_TREE);
-
- // If we're down to eventually bin tiles on the active tree, process the
- // pending tree to allow tiles required for activation to be initialized
- // when memory policy only allows prepaint.
- if (active_priority.priority_bin == TilePriority::EVENTUALLY &&
- pending_priority.priority_bin == TilePriority::NOW) {
- return PENDING_TREE;
- }
- return ACTIVE_TREE;
- }
- case NEW_CONTENT_TAKES_PRIORITY:
- return PENDING_TREE;
- case SAME_PRIORITY_FOR_BOTH_TREES: {
- const Tile* active_tile = shared_tile ? shared_tile : **active_iterator;
- const Tile* pending_tile = shared_tile ? shared_tile : **pending_iterator;
-
- const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE);
- const TilePriority& pending_priority =
- pending_tile->priority(PENDING_TREE);
-
- if (active_priority.IsHigherPriorityThan(pending_priority))
- return ACTIVE_TREE;
- return PENDING_TREE;
- }
- default:
- NOTREACHED();
- return ACTIVE_TREE;
- }
-}
-
-} // namespace
-
-RasterTilePriorityQueue::RasterTilePriorityQueue() {
-}
-
-RasterTilePriorityQueue::~RasterTilePriorityQueue() {
-}
-
-void RasterTilePriorityQueue::Build(
- const std::vector<PictureLayerImpl::Pair>& paired_layers,
- TreePriority tree_priority) {
- tree_priority_ = tree_priority;
- for (std::vector<PictureLayerImpl::Pair>::const_iterator it =
- paired_layers.begin();
- it != paired_layers.end();
- ++it) {
- paired_queues_.push_back(
- make_scoped_ptr(new PairedPictureLayerQueue(*it, tree_priority_)));
- }
- paired_queues_.make_heap(RasterOrderComparator(tree_priority_));
-}
-
-void RasterTilePriorityQueue::Reset() {
- paired_queues_.clear();
-}
-
-bool RasterTilePriorityQueue::IsEmpty() const {
- return paired_queues_.empty() || paired_queues_.front()->IsEmpty();
-}
-
-Tile* RasterTilePriorityQueue::Top() {
- DCHECK(!IsEmpty());
- return paired_queues_.front()->Top(tree_priority_);
-}
-
-void RasterTilePriorityQueue::Pop() {
- DCHECK(!IsEmpty());
-
- paired_queues_.pop_heap(RasterOrderComparator(tree_priority_));
- PairedPictureLayerQueue* paired_queue = paired_queues_.back();
- paired_queue->Pop(tree_priority_);
- paired_queues_.push_heap(RasterOrderComparator(tree_priority_));
-}
-
-RasterTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue() {
-}
-
-RasterTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue(
- const PictureLayerImpl::Pair& layer_pair,
- TreePriority tree_priority)
- : active_iterator(layer_pair.active
- ? PictureLayerImpl::LayerRasterTileIterator(
- layer_pair.active,
- tree_priority == SMOOTHNESS_TAKES_PRIORITY)
- : PictureLayerImpl::LayerRasterTileIterator()),
- pending_iterator(layer_pair.pending
- ? PictureLayerImpl::LayerRasterTileIterator(
- layer_pair.pending,
- tree_priority == SMOOTHNESS_TAKES_PRIORITY)
- : PictureLayerImpl::LayerRasterTileIterator()),
- has_both_layers(layer_pair.active && layer_pair.pending) {
- if (has_both_layers)
- SkipTilesReturnedByTwin(tree_priority);
- TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "PairedPictureLayerQueue::PairedPictureLayerQueue",
- TRACE_EVENT_SCOPE_THREAD,
- "state",
- StateAsValue());
-}
-
-RasterTilePriorityQueue::PairedPictureLayerQueue::~PairedPictureLayerQueue() {
- TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "PairedPictureLayerQueue::~PairedPictureLayerQueue",
- TRACE_EVENT_SCOPE_THREAD,
- "state",
- StateAsValue());
-}
-
-bool RasterTilePriorityQueue::PairedPictureLayerQueue::IsEmpty() const {
- return !active_iterator && !pending_iterator;
-}
-
-Tile* RasterTilePriorityQueue::PairedPictureLayerQueue::Top(
- TreePriority tree_priority) {
- DCHECK(!IsEmpty());
-
- WhichTree next_tree = NextTileIteratorTree(tree_priority);
- PictureLayerImpl::LayerRasterTileIterator* next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
- DCHECK(*next_iterator);
- Tile* tile = **next_iterator;
- DCHECK(returned_tiles_for_debug.find(tile) == returned_tiles_for_debug.end());
- return tile;
-}
-
-void RasterTilePriorityQueue::PairedPictureLayerQueue::Pop(
- TreePriority tree_priority) {
- DCHECK(!IsEmpty());
-
- WhichTree next_tree = NextTileIteratorTree(tree_priority);
- PictureLayerImpl::LayerRasterTileIterator* next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
- DCHECK(*next_iterator);
- DCHECK(returned_tiles_for_debug.insert(**next_iterator).second);
- ++(*next_iterator);
-
- if (has_both_layers)
- SkipTilesReturnedByTwin(tree_priority);
-
- // If no empty, use Top to do DCHECK the next iterator.
- DCHECK(IsEmpty() || Top(tree_priority));
-}
-
-void RasterTilePriorityQueue::PairedPictureLayerQueue::SkipTilesReturnedByTwin(
- TreePriority tree_priority) {
- // We have both layers (active and pending) thus we can encounter shared
- // tiles twice (from the active iterator and from the pending iterator).
- while (!IsEmpty()) {
- WhichTree next_tree = NextTileIteratorTree(tree_priority);
- PictureLayerImpl::LayerRasterTileIterator* next_iterator =
- next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
-
- // Accept all non-shared tiles.
- const Tile* tile = **next_iterator;
- if (!tile->is_shared())
- break;
-
- // Accept a shared tile if the next tree is the higher priority one
- // corresponding the iterator (active or pending) which usually (but due
- // to spiral iterators not always) returns the shared tile first.
- if (next_tree == HigherPriorityTree(tree_priority, nullptr, nullptr, tile))
- break;
-
- ++(*next_iterator);
- }
-}
-
-WhichTree
-RasterTilePriorityQueue::PairedPictureLayerQueue::NextTileIteratorTree(
- TreePriority tree_priority) const {
- DCHECK(!IsEmpty());
-
- // If we only have one iterator with tiles, return it.
- if (!active_iterator)
- return PENDING_TREE;
- if (!pending_iterator)
- return ACTIVE_TREE;
-
- // Now both iterators have tiles, so we have to decide based on tree priority.
- return HigherPriorityTree(
- tree_priority, &active_iterator, &pending_iterator, nullptr);
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-RasterTilePriorityQueue::PairedPictureLayerQueue::StateAsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
- state->BeginDictionary("active_iterator");
- TilePriority::PriorityBin active_priority_bin =
- active_iterator ? (*active_iterator)->priority(ACTIVE_TREE).priority_bin
- : TilePriority::EVENTUALLY;
- TilePriority::PriorityBin pending_priority_bin =
- active_iterator ? (*active_iterator)->priority(PENDING_TREE).priority_bin
- : TilePriority::EVENTUALLY;
- state->SetBoolean("has_tile", !!active_iterator);
- state->SetInteger("active_priority_bin", active_priority_bin);
- state->SetInteger("pending_priority_bin", pending_priority_bin);
- state->EndDictionary();
-
- state->BeginDictionary("pending_iterator");
- active_priority_bin =
- pending_iterator ? (*pending_iterator)->priority(ACTIVE_TREE).priority_bin
- : TilePriority::EVENTUALLY;
- pending_priority_bin =
- pending_iterator
- ? (*pending_iterator)->priority(PENDING_TREE).priority_bin
- : TilePriority::EVENTUALLY;
- state->SetBoolean("has_tile", !!pending_iterator);
- state->SetInteger("active_priority_bin", active_priority_bin);
- state->SetInteger("pending_priority_bin", pending_priority_bin);
- state->EndDictionary();
- return state;
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/raster_tile_priority_queue.h b/chromium/cc/resources/raster_tile_priority_queue.h
deleted file mode 100644
index 3f04e97ae9d..00000000000
--- a/chromium/cc/resources/raster_tile_priority_queue.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2014 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_RASTER_TILE_PRIORITY_QUEUE_H_
-#define CC_RESOURCES_RASTER_TILE_PRIORITY_QUEUE_H_
-
-#include <set>
-#include <utility>
-#include <vector>
-
-#include "cc/base/cc_export.h"
-#include "cc/layers/picture_layer_impl.h"
-#include "cc/resources/tile_priority.h"
-
-namespace cc {
-
-class CC_EXPORT RasterTilePriorityQueue {
- public:
- struct PairedPictureLayerQueue {
- PairedPictureLayerQueue();
- PairedPictureLayerQueue(const PictureLayerImpl::Pair& layer_pair,
- TreePriority tree_priority);
- ~PairedPictureLayerQueue();
-
- bool IsEmpty() const;
- Tile* Top(TreePriority tree_priority);
- void Pop(TreePriority tree_priority);
-
- WhichTree NextTileIteratorTree(TreePriority tree_priority) const;
- void SkipTilesReturnedByTwin(TreePriority tree_priority);
-
- scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
-
- PictureLayerImpl::LayerRasterTileIterator active_iterator;
- PictureLayerImpl::LayerRasterTileIterator pending_iterator;
- bool has_both_layers;
-
- // Set of returned tiles (excluding the current one) for DCHECKing.
- std::set<const Tile*> returned_tiles_for_debug;
- };
-
- RasterTilePriorityQueue();
- ~RasterTilePriorityQueue();
-
- void Build(const std::vector<PictureLayerImpl::Pair>& paired_layers,
- TreePriority tree_priority);
- void Reset();
-
- bool IsEmpty() const;
- Tile* Top();
- void Pop();
-
- private:
- // TODO(vmpstr): This is potentially unnecessary if it becomes the case that
- // PairedPictureLayerQueue is fast enough to copy. In that case, we can use
- // objects directly (ie std::vector<PairedPictureLayerQueue>.
- ScopedPtrVector<PairedPictureLayerQueue> paired_queues_;
- TreePriority tree_priority_;
-
- DISALLOW_COPY_AND_ASSIGN(RasterTilePriorityQueue);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_RASTER_TILE_PRIORITY_QUEUE_H_
diff --git a/chromium/cc/resources/raster_worker_pool.cc b/chromium/cc/resources/raster_worker_pool.cc
deleted file mode 100644
index ca26edd6a41..00000000000
--- a/chromium/cc/resources/raster_worker_pool.cc
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/raster_worker_pool.h"
-
-#include <algorithm>
-
-#include "base/debug/trace_event.h"
-#include "base/lazy_instance.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/simple_thread.h"
-#include "cc/base/scoped_ptr_deque.h"
-#include "cc/resources/raster_source.h"
-#include "skia/ext/refptr.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkSurface.h"
-
-namespace cc {
-namespace {
-
-class RasterTaskGraphRunner : public TaskGraphRunner,
- public base::DelegateSimpleThread::Delegate {
- public:
- RasterTaskGraphRunner() {
- size_t num_threads = RasterWorkerPool::GetNumRasterThreads();
- while (workers_.size() < num_threads) {
- scoped_ptr<base::DelegateSimpleThread> worker =
- make_scoped_ptr(new base::DelegateSimpleThread(
- this,
- base::StringPrintf("CompositorRasterWorker%u",
- static_cast<unsigned>(workers_.size() + 1))
- .c_str()));
- worker->Start();
-#if defined(OS_ANDROID) || defined(OS_LINUX)
- worker->SetThreadPriority(base::kThreadPriority_Background);
-#endif
- workers_.push_back(worker.Pass());
- }
- }
-
- ~RasterTaskGraphRunner() override { NOTREACHED(); }
-
- private:
- // Overridden from base::DelegateSimpleThread::Delegate:
- void Run() override { TaskGraphRunner::Run(); }
-
- ScopedPtrDeque<base::DelegateSimpleThread> workers_;
-};
-
-base::LazyInstance<RasterTaskGraphRunner>::Leaky g_task_graph_runner =
- LAZY_INSTANCE_INITIALIZER;
-
-const int kDefaultNumRasterThreads = 1;
-
-int g_num_raster_threads = 0;
-
-class RasterFinishedTaskImpl : public RasterizerTask {
- public:
- explicit RasterFinishedTaskImpl(
- base::SequencedTaskRunner* task_runner,
- const base::Closure& on_raster_finished_callback)
- : task_runner_(task_runner),
- on_raster_finished_callback_(on_raster_finished_callback) {}
-
- // Overridden from Task:
- void RunOnWorkerThread() override {
- TRACE_EVENT0("cc", "RasterFinishedTaskImpl::RunOnWorkerThread");
- RasterFinished();
- }
-
- // Overridden from RasterizerTask:
- void ScheduleOnOriginThread(RasterizerTaskClient* client) override {}
- void CompleteOnOriginThread(RasterizerTaskClient* client) override {}
- void RunReplyOnOriginThread() override {}
-
- protected:
- ~RasterFinishedTaskImpl() override {}
-
- void RasterFinished() {
- task_runner_->PostTask(FROM_HERE, on_raster_finished_callback_);
- }
-
- private:
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
- const base::Closure on_raster_finished_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(RasterFinishedTaskImpl);
-};
-
-} // namespace
-
-// This allows a micro benchmark system to run tasks with highest priority,
-// since it should finish as quickly as possible.
-unsigned RasterWorkerPool::kBenchmarkRasterTaskPriority = 0u;
-// Task priorities that make sure raster finished tasks run before any
-// remaining raster tasks.
-unsigned RasterWorkerPool::kRasterFinishedTaskPriority = 1u;
-unsigned RasterWorkerPool::kRasterTaskPriorityBase = 2u;
-
-RasterWorkerPool::RasterWorkerPool() {}
-
-RasterWorkerPool::~RasterWorkerPool() {}
-
-// static
-void RasterWorkerPool::SetNumRasterThreads(int num_threads) {
- DCHECK_LT(0, num_threads);
- DCHECK_EQ(0, g_num_raster_threads);
-
- g_num_raster_threads = num_threads;
-}
-
-// static
-int RasterWorkerPool::GetNumRasterThreads() {
- if (!g_num_raster_threads)
- g_num_raster_threads = kDefaultNumRasterThreads;
-
- return g_num_raster_threads;
-}
-
-// static
-TaskGraphRunner* RasterWorkerPool::GetTaskGraphRunner() {
- return g_task_graph_runner.Pointer();
-}
-
-// static
-scoped_refptr<RasterizerTask> RasterWorkerPool::CreateRasterFinishedTask(
- base::SequencedTaskRunner* task_runner,
- const base::Closure& on_raster_finished_callback) {
- return make_scoped_refptr(
- new RasterFinishedTaskImpl(task_runner, on_raster_finished_callback));
-}
-
-// static
-void RasterWorkerPool::ScheduleTasksOnOriginThread(RasterizerTaskClient* client,
- TaskGraph* graph) {
- TRACE_EVENT0("cc", "Rasterizer::ScheduleTasksOnOriginThread");
-
- for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
- it != graph->nodes.end();
- ++it) {
- TaskGraph::Node& node = *it;
- RasterizerTask* task = static_cast<RasterizerTask*>(node.task);
-
- if (!task->HasBeenScheduled()) {
- task->WillSchedule();
- task->ScheduleOnOriginThread(client);
- task->DidSchedule();
- }
- }
-}
-
-// static
-void RasterWorkerPool::InsertNodeForTask(TaskGraph* graph,
- RasterizerTask* task,
- unsigned priority,
- size_t dependencies) {
- DCHECK(std::find_if(graph->nodes.begin(),
- graph->nodes.end(),
- TaskGraph::Node::TaskComparator(task)) ==
- graph->nodes.end());
- graph->nodes.push_back(TaskGraph::Node(task, priority, dependencies));
-}
-
-// static
-void RasterWorkerPool::InsertNodesForRasterTask(
- TaskGraph* graph,
- RasterTask* raster_task,
- const ImageDecodeTask::Vector& decode_tasks,
- unsigned priority) {
- size_t dependencies = 0u;
-
- // Insert image decode tasks.
- for (ImageDecodeTask::Vector::const_iterator it = decode_tasks.begin();
- it != decode_tasks.end();
- ++it) {
- ImageDecodeTask* decode_task = it->get();
-
- // Skip if already decoded.
- if (decode_task->HasCompleted())
- continue;
-
- dependencies++;
-
- // Add decode task if it doesn't already exists in graph.
- TaskGraph::Node::Vector::iterator decode_it =
- std::find_if(graph->nodes.begin(),
- graph->nodes.end(),
- TaskGraph::Node::TaskComparator(decode_task));
- if (decode_it == graph->nodes.end())
- InsertNodeForTask(graph, decode_task, priority, 0u);
-
- graph->edges.push_back(TaskGraph::Edge(decode_task, raster_task));
- }
-
- InsertNodeForTask(graph, raster_task, priority, dependencies);
-}
-
-static bool IsSupportedPlaybackToMemoryFormat(ResourceFormat format) {
- switch (format) {
- case RGBA_4444:
- case RGBA_8888:
- case BGRA_8888:
- return true;
- case ALPHA_8:
- case LUMINANCE_8:
- case RGB_565:
- case ETC1:
- return false;
- }
- NOTREACHED();
- return false;
-}
-
-// static
-void RasterWorkerPool::PlaybackToMemory(void* memory,
- ResourceFormat format,
- const gfx::Size& size,
- int stride,
- const RasterSource* raster_source,
- const gfx::Rect& rect,
- float scale) {
- DCHECK(IsSupportedPlaybackToMemoryFormat(format)) << format;
-
- // Uses kPremul_SkAlphaType since the result is not known to be opaque.
- SkImageInfo info =
- SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType);
- SkColorType buffer_color_type = ResourceFormatToSkColorType(format);
- bool needs_copy = buffer_color_type != info.colorType();
-
- // TODO(danakj): Make a SkSurfaceProps with an SkPixelGeometry to enable or
- // disable LCD text.
- // TODO(danakj): Disable LCD text on Mac during layout tests:
- // https://cs.chromium.org#chromium/src/third_party/WebKit/Source/platform/fonts/mac/FontPlatformDataMac.mm&l=55
- // TODO(danakj): On Windows when LCD text is disabled, ask skia to draw LCD
- // text offscreen and downsample it to AA text.
- // https://cs.chromium.org#chromium/src/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp&l=86
- SkSurfaceProps* surface_props = nullptr;
-
- if (!stride)
- stride = info.minRowBytes();
-
- if (!needs_copy) {
- skia::RefPtr<SkSurface> surface = skia::AdoptRef(
- SkSurface::NewRasterDirect(info, memory, stride, surface_props));
- skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas());
- raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
- return;
- }
-
- skia::RefPtr<SkSurface> surface =
- skia::AdoptRef(SkSurface::NewRaster(info, surface_props));
- skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas());
- raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
-
- SkImageInfo dst_info = info;
- dst_info.fColorType = buffer_color_type;
- // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
- // bitmap data. There will be no need to call SkAlign4 once crbug.com/293728
- // is fixed.
- const size_t dst_row_bytes = SkAlign4(dst_info.minRowBytes());
- DCHECK_EQ(0u, dst_row_bytes % 4);
- bool success = canvas->readPixels(dst_info, memory, dst_row_bytes, 0, 0);
- DCHECK_EQ(true, success);
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/rasterizer.cc b/chromium/cc/resources/rasterizer.cc
deleted file mode 100644
index 4ce8987e8ca..00000000000
--- a/chromium/cc/resources/rasterizer.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2014 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/rasterizer.h"
-
-#include <algorithm>
-
-namespace cc {
-
-RasterizerTask::RasterizerTask() : did_schedule_(false), did_complete_(false) {}
-
-RasterizerTask::~RasterizerTask() {
- // Debugging CHECKs to help track down a use-after-free.
- CHECK(!did_schedule_);
- CHECK(!did_run_ || did_complete_);
-}
-
-ImageDecodeTask* RasterizerTask::AsImageDecodeTask() { return NULL; }
-
-RasterTask* RasterizerTask::AsRasterTask() { return NULL; }
-
-void RasterizerTask::WillSchedule() { DCHECK(!did_schedule_); }
-
-void RasterizerTask::DidSchedule() {
- did_schedule_ = true;
- did_complete_ = false;
-}
-
-bool RasterizerTask::HasBeenScheduled() const { return did_schedule_; }
-
-void RasterizerTask::WillComplete() { DCHECK(!did_complete_); }
-
-void RasterizerTask::DidComplete() {
- DCHECK(did_schedule_);
- DCHECK(!did_complete_);
- did_schedule_ = false;
- did_complete_ = true;
-}
-
-bool RasterizerTask::HasCompleted() const { return did_complete_; }
-
-ImageDecodeTask::ImageDecodeTask() {}
-
-ImageDecodeTask::~ImageDecodeTask() {}
-
-ImageDecodeTask* ImageDecodeTask::AsImageDecodeTask() { return this; }
-
-RasterTask::RasterTask(const Resource* resource,
- ImageDecodeTask::Vector* dependencies)
- : resource_(resource) {
- dependencies_.swap(*dependencies);
-}
-
-RasterTask::~RasterTask() {}
-
-RasterTask* RasterTask::AsRasterTask() { return this; }
-
-RasterTaskQueue::Item::Item(RasterTask* task,
- const TaskSetCollection& task_sets)
- : task(task), task_sets(task_sets) {
- DCHECK(task_sets.any());
-}
-
-RasterTaskQueue::Item::~Item() {}
-
-RasterTaskQueue::RasterTaskQueue() {
-}
-
-RasterTaskQueue::~RasterTaskQueue() {}
-
-void RasterTaskQueue::Swap(RasterTaskQueue* other) {
- items.swap(other->items);
-}
-
-void RasterTaskQueue::Reset() {
- items.clear();
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/resource.h b/chromium/cc/resources/resource.h
index 707d77e20bf..edafaefcfa3 100644
--- a/chromium/cc/resources/resource.h
+++ b/chromium/cc/resources/resource.h
@@ -7,7 +7,6 @@
#include "cc/base/cc_export.h"
#include "cc/resources/resource_provider.h"
-#include "third_party/khronos/GLES2/gl2.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
diff --git a/chromium/cc/resources/resource_format.cc b/chromium/cc/resources/resource_format.cc
index 6cd0a93e921..45581b800f1 100644
--- a/chromium/cc/resources/resource_format.cc
+++ b/chromium/cc/resources/resource_format.cc
@@ -17,6 +17,7 @@ SkColorType ResourceFormatToSkColorType(ResourceFormat format) {
case ALPHA_8:
case LUMINANCE_8:
case RGB_565:
+ case RED_8:
NOTREACHED();
break;
}
diff --git a/chromium/cc/resources/resource_format.h b/chromium/cc/resources/resource_format.h
index b51ac7cfe72..d785ab7382b 100644
--- a/chromium/cc/resources/resource_format.h
+++ b/chromium/cc/resources/resource_format.h
@@ -19,7 +19,8 @@ enum ResourceFormat {
LUMINANCE_8,
RGB_565,
ETC1,
- RESOURCE_FORMAT_MAX = ETC1,
+ RED_8,
+ RESOURCE_FORMAT_MAX = RED_8,
};
SkColorType ResourceFormatToSkColorType(ResourceFormat format);
diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc
index 45f36e27816..22847809ba3 100644
--- a/chromium/cc/resources/resource_pool.cc
+++ b/chromium/cc/resources/resource_pool.cc
@@ -9,12 +9,9 @@
namespace cc {
-ResourcePool::ResourcePool(ResourceProvider* resource_provider,
- GLenum target,
- ResourceFormat format)
+ResourcePool::ResourcePool(ResourceProvider* resource_provider, GLenum target)
: resource_provider_(resource_provider),
target_(target),
- format_(format),
max_memory_usage_bytes_(0),
max_unused_memory_usage_bytes_(0),
max_resource_count_(0),
@@ -36,13 +33,15 @@ ResourcePool::~ResourcePool() {
}
scoped_ptr<ScopedResource> ResourcePool::AcquireResource(
- const gfx::Size& size) {
+ const gfx::Size& size, ResourceFormat format) {
for (ResourceList::iterator it = unused_resources_.begin();
it != unused_resources_.end();
++it) {
ScopedResource* resource = *it;
DCHECK(resource_provider_->CanLockForWrite(resource->id()));
+ if (resource->format() != format)
+ continue;
if (resource->size() != size)
continue;
@@ -53,7 +52,7 @@ scoped_ptr<ScopedResource> ResourcePool::AcquireResource(
scoped_ptr<ScopedResource> resource =
ScopedResource::Create(resource_provider_);
- resource->AllocateManaged(size, target_, format_);
+ resource->AllocateManaged(size, target_, format);
memory_usage_bytes_ += resource->bytes();
++resource_count_;
diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h
index e1ee35aa72c..f79455905dd 100644
--- a/chromium/cc/resources/resource_pool.h
+++ b/chromium/cc/resources/resource_pool.h
@@ -19,14 +19,14 @@ class ScopedResource;
class CC_EXPORT ResourcePool {
public:
static scoped_ptr<ResourcePool> Create(ResourceProvider* resource_provider,
- GLenum target,
- ResourceFormat format) {
- return make_scoped_ptr(new ResourcePool(resource_provider, target, format));
+ GLenum target) {
+ return make_scoped_ptr(new ResourcePool(resource_provider, target));
}
virtual ~ResourcePool();
- scoped_ptr<ScopedResource> AcquireResource(const gfx::Size& size);
+ scoped_ptr<ScopedResource> AcquireResource(const gfx::Size& size,
+ ResourceFormat format);
void ReleaseResource(scoped_ptr<ScopedResource>);
void SetResourceUsageLimits(size_t max_memory_usage_bytes,
@@ -49,12 +49,8 @@ class CC_EXPORT ResourcePool {
}
size_t busy_resource_count() const { return busy_resources_.size(); }
- ResourceFormat resource_format() const { return format_; }
-
protected:
- ResourcePool(ResourceProvider* resource_provider,
- GLenum target,
- ResourceFormat format);
+ ResourcePool(ResourceProvider* resource_provider, GLenum target);
bool ResourceUsageTooHigh();
@@ -63,7 +59,6 @@ class CC_EXPORT ResourcePool {
ResourceProvider* resource_provider_;
const GLenum target_;
- const ResourceFormat format_;
size_t max_memory_usage_bytes_;
size_t max_unused_memory_usage_bytes_;
size_t max_resource_count_;
diff --git a/chromium/cc/resources/resource_provider.cc b/chromium/cc/resources/resource_provider.cc
index 023a1cdbf06..eb774fe10b3 100644
--- a/chromium/cc/resources/resource_provider.cc
+++ b/chromium/cc/resources/resource_provider.cc
@@ -8,12 +8,12 @@
#include <limits>
#include "base/containers/hash_tables.h"
-#include "base/debug/trace_event.h"
+#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/util.h"
-#include "cc/output/gl_renderer.h" // For the GLC() macro.
#include "cc/resources/platform_color.h"
#include "cc/resources/returned_resource.h"
#include "cc/resources/shared_bitmap_manager.h"
@@ -26,6 +26,7 @@
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/GrTextureProvider.h"
#include "ui/gfx/frame_time.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
@@ -75,6 +76,7 @@ GLenum TextureToStorageFormat(ResourceFormat format) {
case LUMINANCE_8:
case RGB_565:
case ETC1:
+ case RED_8:
NOTREACHED();
break;
}
@@ -93,6 +95,7 @@ bool IsFormatSupportedForStorage(ResourceFormat format, bool use_bgra) {
case LUMINANCE_8:
case RGB_565:
case ETC1:
+ case RED_8:
return false;
}
return false;
@@ -124,6 +127,7 @@ gfx::GpuMemoryBuffer::Format ToGpuMemoryBufferFormat(ResourceFormat format) {
case LUMINANCE_8:
case RGB_565:
case ETC1:
+ case RED_8:
break;
}
NOTREACHED();
@@ -137,13 +141,13 @@ class ScopedSetActiveTexture {
DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
if (unit_ != GL_TEXTURE0)
- GLC(gl_, gl_->ActiveTexture(unit_));
+ gl_->ActiveTexture(unit_);
}
~ScopedSetActiveTexture() {
// Active unit being GL_TEXTURE0 is effectively the ground state.
if (unit_ != GL_TEXTURE0)
- GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0));
+ gl_->ActiveTexture(GL_TEXTURE0);
}
private:
@@ -198,11 +202,11 @@ class BufferIdAllocator : public IdAllocator {
DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
};
-// Generic fence implementation for query objects. Fence has passed when query
-// result is available.
-class QueryFence : public ResourceProvider::Fence {
+// Query object based fence implementation used to detect completion of copy
+// texture operations. Fence has passed when query result is available.
+class CopyTextureFence : public ResourceProvider::Fence {
public:
- QueryFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
+ CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
: gl_(gl), query_id_(query_id) {}
// Overridden from ResourceProvider::Fence:
@@ -211,61 +215,35 @@ class QueryFence : public ResourceProvider::Fence {
unsigned available = 1;
gl_->GetQueryObjectuivEXT(
query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
- return !!available;
+ if (!available)
+ return false;
+
+ ProcessResult();
+ return true;
}
void Wait() override {
- unsigned result = 0;
- gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
+ // ProcessResult() will wait for result to become available.
+ ProcessResult();
}
private:
- ~QueryFence() override {}
+ ~CopyTextureFence() override {}
+
+ void ProcessResult() {
+ unsigned time_elapsed_us = 0;
+ gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &time_elapsed_us);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CopyTextureLatency", time_elapsed_us,
+ 0, 256000, 50);
+ }
gpu::gles2::GLES2Interface* gl_;
unsigned query_id_;
- DISALLOW_COPY_AND_ASSIGN(QueryFence);
+ DISALLOW_COPY_AND_ASSIGN(CopyTextureFence);
};
} // namespace
-ResourceProvider::Resource::Resource()
- : child_id(0),
- gl_id(0),
- gl_pixel_buffer_id(0),
- gl_upload_query_id(0),
- gl_read_lock_query_id(0),
- pixels(NULL),
- lock_for_read_count(0),
- imported_count(0),
- exported_count(0),
- dirty_image(false),
- locked_for_write(false),
- lost(false),
- marked_for_deletion(false),
- pending_set_pixels(false),
- set_pixels_completion_forced(false),
- allocated(false),
- read_lock_fences_enabled(false),
- has_shared_bitmap_id(false),
- allow_overlay(false),
- read_lock_fence(NULL),
- size(),
- origin(Internal),
- target(0),
- original_filter(0),
- filter(0),
- image_id(0),
- bound_image_id(0),
- texture_pool(0),
- wrap_mode(0),
- hint(TextureHintImmutable),
- type(InvalidType),
- format(RGBA_8888),
- shared_bitmap(NULL),
- gpu_memory_buffer(NULL) {
-}
-
ResourceProvider::Resource::~Resource() {}
ResourceProvider::Resource::Resource(GLuint texture_id,
@@ -307,12 +285,12 @@ ResourceProvider::Resource::Resource(GLuint texture_id,
texture_pool(texture_pool),
wrap_mode(wrap_mode),
hint(hint),
- type(GLTexture),
+ type(RESOURCE_TYPE_GL_TEXTURE),
format(format),
shared_bitmap(NULL),
gpu_memory_buffer(NULL) {
DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
- DCHECK_EQ(origin == Internal, !!texture_pool);
+ DCHECK_EQ(origin == INTERNAL, !!texture_pool);
}
ResourceProvider::Resource::Resource(uint8_t* pixels,
@@ -350,13 +328,13 @@ ResourceProvider::Resource::Resource(uint8_t* pixels,
bound_image_id(0),
texture_pool(0),
wrap_mode(wrap_mode),
- hint(TextureHintImmutable),
- type(Bitmap),
+ hint(TEXTURE_HINT_IMMUTABLE),
+ type(RESOURCE_TYPE_BITMAP),
format(RGBA_8888),
shared_bitmap(bitmap),
gpu_memory_buffer(NULL) {
DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
- DCHECK(origin == Delegated || pixels);
+ DCHECK(origin == DELEGATED || pixels);
if (bitmap)
shared_bitmap_id = bitmap->id();
}
@@ -395,8 +373,8 @@ ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
bound_image_id(0),
texture_pool(0),
wrap_mode(wrap_mode),
- hint(TextureHintImmutable),
- type(Bitmap),
+ hint(TEXTURE_HINT_IMMUTABLE),
+ type(RESOURCE_TYPE_BITMAP),
format(RGBA_8888),
shared_bitmap_id(bitmap_id),
shared_bitmap(NULL),
@@ -404,7 +382,9 @@ ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
}
-ResourceProvider::Child::Child() : marked_for_deletion(false) {}
+ResourceProvider::Child::Child()
+ : marked_for_deletion(false), needs_sync_points(true) {
+}
ResourceProvider::Child::~Child() {}
@@ -416,31 +396,53 @@ scoped_ptr<ResourceProvider> ResourceProvider::Create(
int highp_threshold_min,
bool use_rgba_4444_texture_format,
size_t id_allocation_chunk_size) {
- scoped_ptr<ResourceProvider> resource_provider(
- new ResourceProvider(output_surface,
- shared_bitmap_manager,
- gpu_memory_buffer_manager,
- blocking_main_thread_task_runner,
- highp_threshold_min,
- use_rgba_4444_texture_format,
- id_allocation_chunk_size));
-
- if (resource_provider->ContextGL())
+ ContextProvider* context_provider = output_surface->context_provider();
+ GLES2Interface* gl =
+ context_provider ? context_provider->ContextGL() : nullptr;
+ ResourceType default_resource_type =
+ gl ? RESOURCE_TYPE_GL_TEXTURE : RESOURCE_TYPE_BITMAP;
+
+ scoped_ptr<ResourceProvider> resource_provider(new ResourceProvider(
+ output_surface, shared_bitmap_manager, gpu_memory_buffer_manager,
+ blocking_main_thread_task_runner, highp_threshold_min,
+ default_resource_type, use_rgba_4444_texture_format,
+ id_allocation_chunk_size));
+
+ if (gl)
resource_provider->InitializeGL();
else
resource_provider->InitializeSoftware();
- DCHECK_NE(InvalidType, resource_provider->default_resource_type());
return resource_provider.Pass();
}
ResourceProvider::~ResourceProvider() {
while (!children_.empty())
- DestroyChildInternal(children_.begin(), ForShutdown);
+ DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
while (!resources_.empty())
- DeleteResourceInternal(resources_.begin(), ForShutdown);
+ DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
+
+ GLES2Interface* gl = ContextGL();
+ if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) {
+ // We are not in GL mode, but double check before returning.
+ DCHECK(!gl);
+ DCHECK(!texture_uploader_);
+ return;
+ }
+
+ DCHECK(gl);
+#if DCHECK_IS_ON()
+ // Check that all GL resources has been deleted.
+ for (ResourceMap::const_iterator itr = resources_.begin();
+ itr != resources_.end(); ++itr) {
+ DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type);
+ }
+#endif // DCHECK_IS_ON()
- CleanUpGLIfNeeded();
+ texture_uploader_ = nullptr;
+ texture_id_allocator_ = nullptr;
+ buffer_id_allocator_ = nullptr;
+ gl->Finish();
}
bool ResourceProvider::InUseByConsumer(ResourceId id) {
@@ -466,18 +468,16 @@ ResourceProvider::ResourceId ResourceProvider::CreateResource(
ResourceFormat format) {
DCHECK(!size.IsEmpty());
switch (default_resource_type_) {
- case GLTexture:
+ case RESOURCE_TYPE_GL_TEXTURE:
return CreateGLTexture(size,
GL_TEXTURE_2D,
GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
wrap_mode,
hint,
format);
- case Bitmap:
+ case RESOURCE_TYPE_BITMAP:
DCHECK_EQ(RGBA_8888, format);
return CreateBitmap(size, wrap_mode);
- case InvalidType:
- break;
}
LOG(FATAL) << "Invalid default resource type.";
@@ -492,18 +492,16 @@ ResourceProvider::ResourceId ResourceProvider::CreateManagedResource(
ResourceFormat format) {
DCHECK(!size.IsEmpty());
switch (default_resource_type_) {
- case GLTexture:
+ case RESOURCE_TYPE_GL_TEXTURE:
return CreateGLTexture(size,
target,
GL_TEXTURE_POOL_MANAGED_CHROMIUM,
wrap_mode,
hint,
format);
- case Bitmap:
+ case RESOURCE_TYPE_BITMAP:
DCHECK_EQ(RGBA_8888, format);
return CreateBitmap(size, wrap_mode);
- case InvalidType:
- break;
}
LOG(FATAL) << "Invalid default resource type.";
@@ -522,17 +520,10 @@ ResourceProvider::ResourceId ResourceProvider::CreateGLTexture(
DCHECK(thread_checker_.CalledOnValidThread());
ResourceId id = next_id_++;
- Resource resource(0,
- size,
- Resource::Internal,
- target,
- GL_LINEAR,
- texture_pool,
- wrap_mode,
- hint,
- format);
- resource.allocated = false;
- resources_[id] = resource;
+ Resource* resource = InsertResource(
+ id, Resource(0, size, Resource::INTERNAL, target, GL_LINEAR, texture_pool,
+ wrap_mode, hint, format));
+ resource->allocated = false;
return id;
}
@@ -540,24 +531,16 @@ ResourceProvider::ResourceId ResourceProvider::CreateBitmap(
const gfx::Size& size, GLint wrap_mode) {
DCHECK(thread_checker_.CalledOnValidThread());
- scoped_ptr<SharedBitmap> bitmap;
- if (shared_bitmap_manager_)
- bitmap = shared_bitmap_manager_->AllocateSharedBitmap(size);
-
- uint8_t* pixels;
- if (bitmap) {
- pixels = bitmap->pixels();
- } else {
- size_t bytes = SharedBitmap::CheckedSizeInBytes(size);
- pixels = new uint8_t[bytes];
- }
+ scoped_ptr<SharedBitmap> bitmap =
+ shared_bitmap_manager_->AllocateSharedBitmap(size);
+ uint8_t* pixels = bitmap->pixels();
DCHECK(pixels);
ResourceId id = next_id_++;
- Resource resource(
- pixels, bitmap.release(), size, Resource::Internal, GL_LINEAR, wrap_mode);
- resource.allocated = true;
- resources_[id] = resource;
+ Resource* resource =
+ InsertResource(id, Resource(pixels, bitmap.release(), size,
+ Resource::INTERNAL, GL_LINEAR, wrap_mode));
+ resource->allocated = true;
return id;
}
@@ -567,23 +550,17 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface(
DCHECK(thread_checker_.CalledOnValidThread());
ResourceId id = next_id_++;
- Resource resource(0,
- gfx::Size(),
- Resource::Internal,
- GL_TEXTURE_RECTANGLE_ARB,
- GL_LINEAR,
- GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
- GL_CLAMP_TO_EDGE,
- TextureHintImmutable,
- RGBA_8888);
- LazyCreate(&resource);
+ Resource* resource = InsertResource(
+ id, Resource(0, gfx::Size(), Resource::INTERNAL, GL_TEXTURE_RECTANGLE_ARB,
+ GL_LINEAR, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
+ GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
+ LazyCreate(resource);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource.gl_id);
+ gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource->gl_id);
gl->TexImageIOSurface2DCHROMIUM(
GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
- resource.allocated = true;
- resources_[id] = resource;
+ resource->allocated = true;
return id;
}
@@ -594,41 +571,27 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
// Just store the information. Mailbox will be consumed in LockForRead().
ResourceId id = next_id_++;
DCHECK(mailbox.IsValid());
- Resource& resource = resources_[id];
+ Resource* resource = nullptr;
if (mailbox.IsTexture()) {
- resource = Resource(0,
- gfx::Size(),
- Resource::External,
- mailbox.target(),
- GL_LINEAR,
- 0,
- GL_CLAMP_TO_EDGE,
- TextureHintImmutable,
- RGBA_8888);
+ resource = InsertResource(
+ id, Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
+ mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
+ GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
} else {
DCHECK(mailbox.IsSharedMemory());
- base::SharedMemory* shared_memory = mailbox.shared_memory();
- DCHECK(shared_memory->memory());
- uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory());
+ SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
+ uint8_t* pixels = shared_bitmap->pixels();
DCHECK(pixels);
- scoped_ptr<SharedBitmap> shared_bitmap;
- if (shared_bitmap_manager_) {
- shared_bitmap =
- shared_bitmap_manager_->GetBitmapForSharedMemory(shared_memory);
- }
- resource = Resource(pixels,
- shared_bitmap.release(),
- mailbox.shared_memory_size(),
- Resource::External,
- GL_LINEAR,
- GL_CLAMP_TO_EDGE);
+ resource = InsertResource(
+ id, Resource(pixels, shared_bitmap, mailbox.shared_memory_size(),
+ Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE));
}
- resource.allocated = true;
- resource.mailbox = mailbox;
- resource.release_callback_impl =
+ resource->allocated = true;
+ resource->mailbox = mailbox;
+ resource->release_callback_impl =
base::Bind(&SingleReleaseCallbackImpl::Run,
base::Owned(release_callback_impl.release()));
- resource.allow_overlay = mailbox.allow_overlay();
+ resource->allow_overlay = mailbox.allow_overlay();
return id;
}
@@ -645,7 +608,7 @@ void ResourceProvider::DeleteResource(ResourceId id) {
resource->marked_for_deletion = true;
return;
} else {
- DeleteResourceInternal(it, Normal);
+ DeleteResourceInternal(it, NORMAL);
}
}
@@ -655,57 +618,52 @@ void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
Resource* resource = &it->second;
bool lost_resource = resource->lost;
- DCHECK(resource->exported_count == 0 || style != Normal);
- if (style == ForShutdown && resource->exported_count > 0)
+ DCHECK(resource->exported_count == 0 || style != NORMAL);
+ if (style == FOR_SHUTDOWN && resource->exported_count > 0)
lost_resource = true;
if (resource->image_id) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id));
+ gl->DestroyImageCHROMIUM(resource->image_id);
}
if (resource->gl_upload_query_id) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id));
+ gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id);
}
if (resource->gl_read_lock_query_id) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id));
+ gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id);
}
if (resource->gl_pixel_buffer_id) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id));
+ gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id);
}
- if (resource->origin == Resource::External) {
+ if (resource->origin == Resource::EXTERNAL) {
DCHECK(resource->mailbox.IsValid());
GLuint sync_point = resource->mailbox.sync_point();
- if (resource->type == GLTexture) {
+ if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
DCHECK(resource->mailbox.IsTexture());
lost_resource |= lost_output_surface_;
GLES2Interface* gl = ContextGL();
DCHECK(gl);
if (resource->gl_id) {
- GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
+ gl->DeleteTextures(1, &resource->gl_id);
resource->gl_id = 0;
if (!lost_resource)
sync_point = gl->InsertSyncPointCHROMIUM();
}
} else {
DCHECK(resource->mailbox.IsSharedMemory());
- base::SharedMemory* shared_memory = resource->mailbox.shared_memory();
- if (resource->pixels && shared_memory) {
- DCHECK(shared_memory->memory() == resource->pixels);
- resource->pixels = NULL;
- delete resource->shared_bitmap;
- resource->shared_bitmap = NULL;
- }
+ resource->shared_bitmap = nullptr;
+ resource->pixels = nullptr;
}
resource->release_callback_impl.Run(
sync_point, lost_resource, blocking_main_thread_task_runner_);
@@ -713,22 +671,22 @@ void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
if (resource->gl_id) {
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
+ gl->DeleteTextures(1, &resource->gl_id);
resource->gl_id = 0;
}
if (resource->shared_bitmap) {
- DCHECK(resource->origin != Resource::External);
- DCHECK_EQ(Bitmap, resource->type);
+ DCHECK(resource->origin != Resource::EXTERNAL);
+ DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
delete resource->shared_bitmap;
resource->pixels = NULL;
}
if (resource->pixels) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
delete[] resource->pixels;
resource->pixels = NULL;
}
if (resource->gpu_memory_buffer) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
delete resource->gpu_memory_buffer;
resource->gpu_memory_buffer = NULL;
}
@@ -748,12 +706,12 @@ void ResourceProvider::SetPixels(ResourceId id,
Resource* resource = GetResource(id);
DCHECK(!resource->locked_for_write);
DCHECK(!resource->lock_for_read_count);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(ReadLockFenceHasPassed(resource));
LazyAllocate(resource);
- if (resource->type == GLTexture) {
+ if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
DCHECK(resource->gl_id);
DCHECK(!resource->pending_set_pixels);
DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
@@ -768,7 +726,7 @@ void ResourceProvider::SetPixels(ResourceId id,
resource->format,
resource->size);
} else {
- DCHECK_EQ(Bitmap, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
DCHECK(resource->allocated);
DCHECK_EQ(RGBA_8888, resource->format);
DCHECK(source_rect.x() >= image_rect.x());
@@ -782,9 +740,57 @@ void ResourceProvider::SetPixels(ResourceId id,
image += source_offset.y() * image_row_bytes + source_offset.x() * 4;
ScopedWriteLockSoftware lock(this, id);
- SkCanvas* dest = lock.sk_canvas();
- dest->writePixels(
- source_info, image, image_row_bytes, dest_offset.x(), dest_offset.y());
+ SkCanvas dest(lock.sk_bitmap());
+ dest.writePixels(source_info, image, image_row_bytes, dest_offset.x(),
+ dest_offset.y());
+ }
+}
+
+void ResourceProvider::CopyToResource(ResourceId id,
+ const uint8_t* image,
+ const gfx::Size& image_size) {
+ Resource* resource = GetResource(id);
+ DCHECK(!resource->locked_for_write);
+ DCHECK(!resource->lock_for_read_count);
+ DCHECK(resource->origin == Resource::INTERNAL);
+ DCHECK_EQ(resource->exported_count, 0);
+ DCHECK(ReadLockFenceHasPassed(resource));
+ LazyAllocate(resource);
+
+ DCHECK_EQ(image_size.width(), resource->size.width());
+ DCHECK_EQ(image_size.height(), resource->size.height());
+
+ if (resource->type == RESOURCE_TYPE_BITMAP) {
+ DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
+ DCHECK(resource->allocated);
+ DCHECK_EQ(RGBA_8888, resource->format);
+ SkImageInfo source_info =
+ SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
+ size_t image_stride = image_size.width() * 4;
+
+ ScopedWriteLockSoftware lock(this, id);
+ SkCanvas dest(lock.sk_bitmap());
+ dest.writePixels(source_info, image, image_stride, 0, 0);
+ } else {
+ DCHECK(resource->gl_id);
+ DCHECK(!resource->pending_set_pixels);
+ DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ DCHECK(texture_uploader_.get());
+ gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
+
+ if (resource->format == ETC1) {
+ size_t num_bytes = static_cast<size_t>(image_size.width()) *
+ image_size.height() * BitsPerPixel(ETC1) / 8;
+ gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
+ image_size.width(), image_size.height(), 0,
+ num_bytes, image);
+ } else {
+ gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
+ image_size.height(), GLDataFormat(resource->format),
+ GLDataType(resource->format), image);
+ }
}
}
@@ -847,10 +853,20 @@ base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime(
return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads;
}
+ResourceProvider::Resource* ResourceProvider::InsertResource(
+ ResourceId id,
+ const Resource& resource) {
+ std::pair<ResourceMap::iterator, bool> result =
+ resources_.insert(ResourceMap::value_type(id, resource));
+ DCHECK(result.second);
+ return &result.first->second;
+}
+
ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(id);
ResourceMap::iterator it = resources_.find(id);
- CHECK(it != resources_.end());
+ DCHECK(it != resources_.end());
return &it->second;
}
@@ -866,8 +882,8 @@ const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
LazyCreate(resource);
- if (resource->type == GLTexture && !resource->gl_id) {
- DCHECK(resource->origin != Resource::Internal);
+ if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
+ DCHECK(resource->origin != Resource::INTERNAL);
DCHECK(resource->mailbox.IsTexture());
// Mailbox sync_points must be processed by a call to
@@ -876,11 +892,8 @@ const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- resource->gl_id = texture_id_allocator_->NextId();
- GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
- GLC(gl,
- gl->ConsumeTextureCHROMIUM(resource->mailbox.target(),
- resource->mailbox.name()));
+ resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM(
+ resource->mailbox.target(), resource->mailbox.name());
}
if (!resource->pixels && resource->has_shared_bitmap_id &&
@@ -916,12 +929,12 @@ void ResourceProvider::UnlockForRead(ResourceId id) {
if (resource->marked_for_deletion && !resource->lock_for_read_count) {
if (!resource->child_id) {
// The resource belongs to this ResourceProvider, so it can be destroyed.
- DeleteResourceInternal(it, Normal);
+ DeleteResourceInternal(it, NORMAL);
} else {
ChildMap::iterator child_it = children_.find(resource->child_id);
ResourceIdArray unused;
unused.push_back(id);
- DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused);
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
}
}
}
@@ -937,14 +950,14 @@ ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) {
bool ResourceProvider::CanLockForWrite(ResourceId id) {
Resource* resource = GetResource(id);
return !resource->locked_for_write && !resource->lock_for_read_count &&
- !resource->exported_count && resource->origin == Resource::Internal &&
+ !resource->exported_count && resource->origin == Resource::INTERNAL &&
!resource->lost && ReadLockFenceHasPassed(resource);
}
void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
DCHECK(resource->locked_for_write);
DCHECK_EQ(resource->exported_count, 0);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
resource->locked_for_write = false;
}
@@ -953,8 +966,8 @@ ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
ResourceProvider::ResourceId resource_id)
: resource_provider_(resource_provider),
resource_id_(resource_id),
- texture_id_(resource_provider->LockForRead(resource_id)->gl_id) {
- DCHECK(texture_id_);
+ resource_(resource_provider->LockForRead(resource_id)) {
+ DCHECK(resource_);
}
ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
@@ -1026,7 +1039,6 @@ ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
resource_(resource_provider->LockForWrite(resource_id)) {
ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_);
DCHECK(valid());
- sk_canvas_.reset(new SkCanvas(sk_bitmap_));
}
ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
@@ -1043,7 +1055,7 @@ ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
gpu_memory_buffer_(nullptr),
size_(resource_->size),
format_(resource_->format) {
- DCHECK_EQ(GLTexture, resource_->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type);
std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
}
@@ -1058,11 +1070,16 @@ ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
GLES2Interface* gl = resource_provider_->ContextGL();
DCHECK(gl);
- resource_->image_id =
- gl->CreateImageCHROMIUM(gpu_memory_buffer_->AsClientBuffer(),
- size_.width(),
- size_.height(),
- GL_RGBA);
+#if defined(OS_CHROMEOS)
+ // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
+ // on ChromeOS to avoid some performance issues. This only works with
+ // shared memory backed buffers. crbug.com/436314
+ DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER);
+#endif
+
+ resource_->image_id = gl->CreateImageCHROMIUM(
+ gpu_memory_buffer_->AsClientBuffer(), size_.width(), size_.height(),
+ GLInternalFormat(resource_->format));
}
std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
@@ -1092,48 +1109,56 @@ ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
ResourceProvider::ResourceId resource_id)
: resource_provider_(resource_provider),
resource_(resource_provider->LockForWrite(resource_id)) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ resource_provider_->LazyAllocate(resource_);
}
ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(resource_->locked_for_write);
resource_provider_->UnlockForWrite(resource_);
}
-SkSurface* ResourceProvider::ScopedWriteLockGr::GetSkSurface(
- bool use_distance_field_text) {
- DCHECK(thread_checker_.CalledOnValidThread());
+void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
+ bool use_distance_field_text,
+ bool can_use_lcd_text,
+ int msaa_sample_count) {
DCHECK(resource_->locked_for_write);
- // If the surface doesn't exist, or doesn't have the correct dff setting,
- // recreate the surface within the resource.
- if (!resource_->sk_surface ||
- use_distance_field_text !=
- resource_->sk_surface->props().isUseDistanceFieldFonts()) {
- class GrContext* gr_context = resource_provider_->GrContext();
- // TODO(alokp): Implement TestContextProvider::GrContext().
- if (!gr_context)
- return nullptr;
-
- resource_provider_->LazyAllocate(resource_);
-
- GrBackendTextureDesc desc;
- desc.fFlags = kRenderTarget_GrBackendTextureFlag;
- desc.fWidth = resource_->size.width();
- desc.fHeight = resource_->size.height();
- desc.fConfig = ToGrPixelConfig(resource_->format);
- desc.fOrigin = kTopLeft_GrSurfaceOrigin;
- desc.fTextureHandle = resource_->gl_id;
- skia::RefPtr<GrTexture> gr_texture =
- skia::AdoptRef(gr_context->wrapBackendTexture(desc));
- if (!gr_texture)
- return nullptr;
- SkSurface::TextRenderMode text_render_mode =
- use_distance_field_text ? SkSurface::kDistanceField_TextRenderMode
- : SkSurface::kStandard_TextRenderMode;
- resource_->sk_surface = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
- gr_texture->asRenderTarget(), text_render_mode));
+ GrBackendTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrBackendTextureFlag;
+ desc.fWidth = resource_->size.width();
+ desc.fHeight = resource_->size.height();
+ desc.fConfig = ToGrPixelConfig(resource_->format);
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fTextureHandle = resource_->gl_id;
+ desc.fSampleCnt = msaa_sample_count;
+
+ bool use_worker_context = true;
+ class GrContext* gr_context =
+ resource_provider_->GrContext(use_worker_context);
+ skia::RefPtr<GrTexture> gr_texture =
+ skia::AdoptRef(gr_context->textureProvider()->wrapBackendTexture(desc));
+ if (gr_texture) {
+ 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);
+ }
+ sk_surface_ = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
+ gr_texture->asRenderTarget(), &surface_props));
+ return;
}
- return resource_->sk_surface.get();
+ sk_surface_.clear();
+}
+
+void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
+ sk_surface_.clear();
}
ResourceProvider::SynchronousFence::SynchronousFence(
@@ -1171,6 +1196,7 @@ ResourceProvider::ResourceProvider(
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
BlockingTaskRunner* blocking_main_thread_task_runner,
int highp_threshold_min,
+ ResourceType default_resource_type,
bool use_rgba_4444_texture_format,
size_t id_allocation_chunk_size)
: output_surface_(output_surface),
@@ -1181,11 +1207,12 @@ ResourceProvider::ResourceProvider(
highp_threshold_min_(highp_threshold_min),
next_id_(1),
next_child_(1),
- default_resource_type_(InvalidType),
+ default_resource_type_(default_resource_type),
use_texture_storage_ext_(false),
use_texture_format_bgra_(false),
use_texture_usage_hint_(false),
use_compressed_texture_etc1_(false),
+ yuv_resource_format_(LUMINANCE_8),
max_texture_size_(0),
best_texture_format_(RGBA_8888),
use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
@@ -1197,11 +1224,7 @@ ResourceProvider::ResourceProvider(
void ResourceProvider::InitializeSoftware() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_NE(Bitmap, default_resource_type_);
-
- CleanUpGLIfNeeded();
-
- default_resource_type_ = Bitmap;
+ DCHECK_EQ(default_resource_type_, RESOURCE_TYPE_BITMAP);
// Pick an arbitrary limit here similar to what hardware might.
max_texture_size_ = 16 * 1024;
best_texture_format_ = RGBA_8888;
@@ -1209,13 +1232,11 @@ void ResourceProvider::InitializeSoftware() {
void ResourceProvider::InitializeGL() {
DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_EQ(default_resource_type_, RESOURCE_TYPE_GL_TEXTURE);
DCHECK(!texture_uploader_);
- DCHECK_NE(GLTexture, default_resource_type_);
DCHECK(!texture_id_allocator_);
DCHECK(!buffer_id_allocator_);
- default_resource_type_ = GLTexture;
-
const ContextProvider::Capabilities& caps =
output_surface_->context_provider()->ContextCapabilities();
@@ -1224,6 +1245,7 @@ void ResourceProvider::InitializeGL() {
use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
use_texture_usage_hint_ = caps.gpu.texture_usage;
use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
+ yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
use_sync_query_ = caps.gpu.sync_query;
GLES2Interface* gl = ContextGL();
@@ -1231,7 +1253,7 @@ void ResourceProvider::InitializeGL() {
texture_uploader_ = TextureUploader::Create(gl);
max_texture_size_ = 0; // Context expects cleared value.
- GLC(gl, gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_));
+ gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra);
texture_id_allocator_.reset(
@@ -1240,31 +1262,6 @@ void ResourceProvider::InitializeGL() {
new BufferIdAllocator(gl, id_allocation_chunk_size_));
}
-void ResourceProvider::CleanUpGLIfNeeded() {
- GLES2Interface* gl = ContextGL();
- if (default_resource_type_ != GLTexture) {
- // We are not in GL mode, but double check before returning.
- DCHECK(!gl);
- DCHECK(!texture_uploader_);
- return;
- }
-
- DCHECK(gl);
-#if DCHECK_IS_ON
- // Check that all GL resources has been deleted.
- for (ResourceMap::const_iterator itr = resources_.begin();
- itr != resources_.end();
- ++itr) {
- DCHECK_NE(GLTexture, itr->second.type);
- }
-#endif // DCHECK_IS_ON
-
- texture_uploader_ = nullptr;
- texture_id_allocator_ = nullptr;
- buffer_id_allocator_ = nullptr;
- gl->Finish();
-}
-
int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -1276,10 +1273,16 @@ int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
return child;
}
+void ResourceProvider::SetChildNeedsSyncPoints(int child_id, bool needs) {
+ ChildMap::iterator it = children_.find(child_id);
+ DCHECK(it != children_.end());
+ it->second.needs_sync_points = needs;
+}
+
void ResourceProvider::DestroyChild(int child_id) {
ChildMap::iterator it = children_.find(child_id);
DCHECK(it != children_.end());
- DestroyChildInternal(it, Normal);
+ DestroyChildInternal(it, NORMAL);
}
void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
@@ -1287,7 +1290,7 @@ void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
DCHECK(thread_checker_.CalledOnValidThread());
Child& child = it->second;
- DCHECK(style == ForShutdown || !child.marked_for_deletion);
+ DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
ResourceIdArray resources_for_child;
@@ -1298,8 +1301,6 @@ void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
resources_for_child.push_back(id);
}
- // If the child is going away, don't consider any resources in use.
- child.in_use_resources.clear();
child.marked_for_deletion = true;
DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
@@ -1329,7 +1330,8 @@ void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
++resources_.find(*it)->second.exported_count;
list->push_back(resource);
}
- if (need_sync_point) {
+ if (need_sync_point &&
+ output_surface_->capabilities().delegated_sync_points_required) {
GLuint sync_point = gl->InsertSyncPointCHROMIUM();
for (TransferableResourceArray::iterator it = list->begin();
it != list->end();
@@ -1352,9 +1354,9 @@ void ResourceProvider::ReceiveFromChild(
ResourceIdMap::iterator resource_in_map_it =
child_info.child_to_parent_map.find(it->id);
if (resource_in_map_it != child_info.child_to_parent_map.end()) {
- Resource& resource = resources_[resource_in_map_it->second];
- resource.marked_for_deletion = false;
- resource.imported_count++;
+ Resource* resource = GetResource(resource_in_map_it->second);
+ resource->marked_for_deletion = false;
+ resource->imported_count++;
continue;
}
@@ -1369,32 +1371,27 @@ void ResourceProvider::ReceiveFromChild(
}
ResourceId local_id = next_id_++;
- Resource& resource = resources_[local_id];
+ Resource* resource = nullptr;
if (it->is_software) {
- resource = Resource(it->mailbox_holder.mailbox,
- it->size,
- Resource::Delegated,
- GL_LINEAR,
- it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE);
+ resource = InsertResource(
+ local_id,
+ Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
+ GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
} else {
- resource = Resource(0,
- it->size,
- Resource::Delegated,
- it->mailbox_holder.texture_target,
- it->filter,
- 0,
- it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
- TextureHintImmutable,
- it->format);
- resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox,
- it->mailbox_holder.texture_target,
- it->mailbox_holder.sync_point);
+ resource = InsertResource(
+ local_id, Resource(0, it->size, Resource::DELEGATED,
+ it->mailbox_holder.texture_target, it->filter, 0,
+ it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
+ TEXTURE_HINT_IMMUTABLE, it->format));
+ resource->mailbox = TextureMailbox(it->mailbox_holder.mailbox,
+ it->mailbox_holder.texture_target,
+ it->mailbox_holder.sync_point);
}
- resource.child_id = child;
+ resource->child_id = child;
// Don't allocate a texture for a child.
- resource.allocated = true;
- resource.imported_count = 1;
- resource.allow_overlay = it->allow_overlay;
+ resource->allocated = true;
+ resource->imported_count = 1;
+ resource->allow_overlay = it->allow_overlay;
child_info.parent_to_child_map[local_id] = it->id;
child_info.child_to_parent_map[it->id] = local_id;
}
@@ -1402,46 +1399,24 @@ void ResourceProvider::ReceiveFromChild(
void ResourceProvider::DeclareUsedResourcesFromChild(
int child,
- const ResourceIdArray& resources_from_child) {
+ const ResourceIdSet& resources_from_child) {
DCHECK(thread_checker_.CalledOnValidThread());
ChildMap::iterator child_it = children_.find(child);
DCHECK(child_it != children_.end());
Child& child_info = child_it->second;
DCHECK(!child_info.marked_for_deletion);
- child_info.in_use_resources.clear();
-
- for (size_t i = 0; i < resources_from_child.size(); ++i) {
- ResourceIdMap::iterator it =
- child_info.child_to_parent_map.find(resources_from_child[i]);
- DCHECK(it != child_info.child_to_parent_map.end());
-
- ResourceId local_id = it->second;
- DCHECK(!resources_[local_id].marked_for_deletion);
- child_info.in_use_resources.insert(local_id);
- }
ResourceIdArray unused;
for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
it != child_info.child_to_parent_map.end();
++it) {
ResourceId local_id = it->second;
- bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0;
+ bool resource_is_in_use = resources_from_child.count(it->first) > 0;
if (!resource_is_in_use)
unused.push_back(local_id);
}
- DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused);
-}
-
-// static
-bool ResourceProvider::CompareResourceMapIteratorsByChildId(
- const std::pair<ReturnedResource, ResourceMap::iterator>& a,
- const std::pair<ReturnedResource, ResourceMap::iterator>& b) {
- const ResourceMap::iterator& a_it = a.second;
- const ResourceMap::iterator& b_it = b.second;
- const Resource& a_resource = a_it->second;
- const Resource& b_resource = b_it->second;
- return a_resource.child_id < b_resource.child_id;
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
}
void ResourceProvider::ReceiveReturnsFromParent(
@@ -1449,36 +1424,16 @@ void ResourceProvider::ReceiveReturnsFromParent(
DCHECK(thread_checker_.CalledOnValidThread());
GLES2Interface* gl = ContextGL();
- int child_id = 0;
- ResourceIdArray resources_for_child;
-
- std::vector<std::pair<ReturnedResource, ResourceMap::iterator>>
- sorted_resources;
+ base::hash_map<int, ResourceIdArray> resources_for_child;
- for (ReturnedResourceArray::const_iterator it = resources.begin();
- it != resources.end();
- ++it) {
- ResourceId local_id = it->id;
+ for (const ReturnedResource& returned : resources) {
+ ResourceId local_id = returned.id;
ResourceMap::iterator map_iterator = resources_.find(local_id);
-
// Resource was already lost (e.g. it belonged to a child that was
// destroyed).
if (map_iterator == resources_.end())
continue;
- sorted_resources.push_back(
- std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator));
- }
-
- std::sort(sorted_resources.begin(),
- sorted_resources.end(),
- CompareResourceMapIteratorsByChildId);
-
- ChildMap::iterator child_it = children_.end();
- for (size_t i = 0; i < sorted_resources.size(); ++i) {
- ReturnedResource& returned = sorted_resources[i].first;
- ResourceMap::iterator& map_iterator = sorted_resources[i].second;
- ResourceId local_id = map_iterator->first;
Resource* resource = &map_iterator->second;
CHECK_GE(resource->exported_count, returned.count);
@@ -1497,9 +1452,9 @@ void ResourceProvider::ReceiveReturnsFromParent(
if (returned.sync_point) {
DCHECK(!resource->has_shared_bitmap_id);
- if (resource->origin == Resource::Internal) {
+ if (resource->origin == Resource::INTERNAL) {
DCHECK(resource->gl_id);
- GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point));
+ gl->WaitSyncPointCHROMIUM(returned.sync_point);
} else {
DCHECK(!resource->gl_id);
resource->mailbox.set_sync_point(returned.sync_point);
@@ -1511,33 +1466,18 @@ void ResourceProvider::ReceiveReturnsFromParent(
if (!resource->child_id) {
// The resource belongs to this ResourceProvider, so it can be destroyed.
- DeleteResourceInternal(map_iterator, Normal);
+ DeleteResourceInternal(map_iterator, NORMAL);
continue;
}
- DCHECK(resource->origin == Resource::Delegated);
- // Delete the resource and return it to the child it came from one.
- if (resource->child_id != child_id) {
- if (child_id) {
- DCHECK_NE(resources_for_child.size(), 0u);
- DCHECK(child_it != children_.end());
- DeleteAndReturnUnusedResourcesToChild(
- child_it, Normal, resources_for_child);
- resources_for_child.clear();
- }
-
- child_it = children_.find(resource->child_id);
- DCHECK(child_it != children_.end());
- child_id = resource->child_id;
- }
- resources_for_child.push_back(local_id);
+ DCHECK(resource->origin == Resource::DELEGATED);
+ resources_for_child[resource->child_id].push_back(local_id);
}
- if (child_id) {
- DCHECK_NE(resources_for_child.size(), 0u);
+ for (const auto& children : resources_for_child) {
+ ChildMap::iterator child_it = children_.find(children.first);
DCHECK(child_it != children_.end());
- DeleteAndReturnUnusedResourcesToChild(
- child_it, Normal, resources_for_child);
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, children.second);
}
}
@@ -1547,7 +1487,7 @@ void ResourceProvider::TransferResource(GLES2Interface* gl,
Resource* source = GetResource(id);
DCHECK(!source->locked_for_write);
DCHECK(!source->lock_for_read_count);
- DCHECK(source->origin != Resource::External || source->mailbox.IsValid());
+ DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
DCHECK(source->allocated);
resource->id = id;
resource->format = source->format;
@@ -1557,35 +1497,31 @@ void ResourceProvider::TransferResource(GLES2Interface* gl,
resource->is_repeated = (source->wrap_mode == GL_REPEAT);
resource->allow_overlay = source->allow_overlay;
- if (source->type == Bitmap) {
+ if (source->type == RESOURCE_TYPE_BITMAP) {
resource->mailbox_holder.mailbox = source->shared_bitmap_id;
resource->is_software = true;
} else if (!source->mailbox.IsValid()) {
LazyCreate(source);
DCHECK(source->gl_id);
- DCHECK(source->origin == Resource::Internal);
- GLC(gl,
- gl->BindTexture(resource->mailbox_holder.texture_target,
- source->gl_id));
+ DCHECK(source->origin == Resource::INTERNAL);
if (source->image_id) {
DCHECK(source->dirty_image);
BindImageForSampling(source);
}
// This is a resource allocated by the compositor, we need to produce it.
// Don't set a sync point, the caller will do it.
- GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name));
- GLC(gl,
- gl->ProduceTextureCHROMIUM(resource->mailbox_holder.texture_target,
- resource->mailbox_holder.mailbox.name));
+ gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name);
+ gl->ProduceTextureDirectCHROMIUM(source->gl_id,
+ resource->mailbox_holder.texture_target,
+ resource->mailbox_holder.mailbox.name);
+
source->mailbox = TextureMailbox(resource->mailbox_holder);
} else {
DCHECK(source->mailbox.IsTexture());
if (source->image_id && source->dirty_image) {
DCHECK(source->gl_id);
- DCHECK(source->origin == Resource::Internal);
- GLC(gl,
- gl->BindTexture(resource->mailbox_holder.texture_target,
- source->gl_id));
+ DCHECK(source->origin == Resource::INTERNAL);
+ gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
BindImageForSampling(source);
}
// This is either an external resource, or a compositor resource that we
@@ -1620,16 +1556,16 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
Resource& resource = it->second;
DCHECK(!resource.locked_for_write);
- DCHECK_EQ(0u, child_info->in_use_resources.count(local_id));
DCHECK(child_info->parent_to_child_map.count(local_id));
ResourceId child_id = child_info->parent_to_child_map[local_id];
DCHECK(child_info->child_to_parent_map.count(child_id));
bool is_lost =
- resource.lost || (resource.type == GLTexture && lost_output_surface_);
+ resource.lost ||
+ (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
- if (style != ForShutdown) {
+ if (style != FOR_SHUTDOWN) {
// Defer this until we receive the resource back from the parent or
// the read lock is released.
resource.marked_for_deletion = true;
@@ -1644,21 +1580,17 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
DCHECK(resource.target);
DCHECK(resource.gl_id);
- GLC(gl, gl->BindTexture(resource.target, resource.gl_id));
- GLC(gl,
- gl->TexParameteri(resource.target,
- GL_TEXTURE_MIN_FILTER,
- resource.original_filter));
- GLC(gl,
- gl->TexParameteri(resource.target,
- GL_TEXTURE_MAG_FILTER,
- resource.original_filter));
+ gl->BindTexture(resource.target, resource.gl_id);
+ gl->TexParameteri(resource.target, GL_TEXTURE_MIN_FILTER,
+ resource.original_filter);
+ gl->TexParameteri(resource.target, GL_TEXTURE_MAG_FILTER,
+ resource.original_filter);
}
ReturnedResource returned;
returned.id = child_id;
returned.sync_point = resource.mailbox.sync_point();
- if (!returned.sync_point && resource.type == GLTexture)
+ if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
need_sync_point = true;
returned.count = resource.imported_count;
returned.lost = is_lost;
@@ -1669,7 +1601,7 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
resource.imported_count = 0;
DeleteResourceInternal(it, style);
}
- if (need_sync_point) {
+ if (need_sync_point && child_info->needs_sync_points) {
DCHECK(gl);
GLuint sync_point = gl->InsertSyncPointCHROMIUM();
for (size_t i = 0; i < to_return.size(); ++i) {
@@ -1694,12 +1626,12 @@ void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
"ResourceProvider::AcquirePixelBuffer");
Resource* resource = GetResource(id);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
DCHECK_NE(ETC1, resource->format);
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
if (!resource->gl_pixel_buffer_id)
@@ -1720,7 +1652,7 @@ void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
"ResourceProvider::ReleasePixelBuffer");
Resource* resource = GetResource(id);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
@@ -1736,7 +1668,7 @@ void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
resource->locked_for_write = false;
}
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
if (!resource->gl_pixel_buffer_id)
return;
GLES2Interface* gl = ContextGL();
@@ -1753,12 +1685,12 @@ uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) {
"ResourceProvider::MapPixelBuffer");
Resource* resource = GetResource(id);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
*stride = 0;
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
DCHECK(resource->gl_pixel_buffer_id);
@@ -1777,11 +1709,11 @@ void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
"ResourceProvider::UnmapPixelBuffer");
Resource* resource = GetResource(id);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
DCHECK(resource->gl_pixel_buffer_id);
@@ -1804,10 +1736,10 @@ GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
ScopedSetActiveTexture scoped_active_tex(gl, unit);
GLenum target = resource->target;
- GLC(gl, gl->BindTexture(target, resource->gl_id));
+ gl->BindTexture(target, resource->gl_id);
if (filter != resource->filter) {
- GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter));
- GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter));
+ gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
+ gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
resource->filter = filter;
}
@@ -1825,7 +1757,7 @@ void ResourceProvider::BeginSetPixels(ResourceId id) {
DCHECK(!resource->pending_set_pixels);
LazyCreate(resource);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK(resource->gl_id || resource->allocated);
DCHECK(ReadLockFenceHasPassed(resource));
DCHECK(!resource->image_id);
@@ -1834,7 +1766,7 @@ void ResourceProvider::BeginSetPixels(ResourceId id) {
resource->allocated = true;
LockForWrite(id);
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
DCHECK(resource->gl_id);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
@@ -1887,9 +1819,9 @@ void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
if (resource->gl_id) {
GLES2Interface* gl = ContextGL();
- GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
- GLC(gl, gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D));
- GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0));
+ gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
+ gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D);
+ gl->BindTexture(GL_TEXTURE_2D, 0);
}
resource->set_pixels_completion_forced = true;
@@ -1936,14 +1868,15 @@ GLenum ResourceProvider::TargetForTesting(ResourceId id) {
}
void ResourceProvider::LazyCreate(Resource* resource) {
- if (resource->type != GLTexture || resource->origin != Resource::Internal)
+ if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
+ resource->origin != Resource::INTERNAL)
return;
if (resource->gl_id)
return;
DCHECK(resource->texture_pool);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK(!resource->mailbox.IsValid());
resource->gl_id = texture_id_allocator_->NextId();
@@ -1951,27 +1884,18 @@ void ResourceProvider::LazyCreate(Resource* resource) {
DCHECK(gl);
// Create and set texture properties. Allocation is delayed until needed.
- GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
- GLC(gl,
- gl->TexParameteri(
- resource->target, GL_TEXTURE_MIN_FILTER, resource->original_filter));
- GLC(gl,
- gl->TexParameteri(
- resource->target, GL_TEXTURE_MAG_FILTER, resource->original_filter));
- GLC(gl,
- gl->TexParameteri(
- resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode));
- GLC(gl,
- gl->TexParameteri(
- resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode));
- GLC(gl,
- gl->TexParameteri(
- resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool));
- if (use_texture_usage_hint_ && (resource->hint & TextureHintFramebuffer)) {
- GLC(gl,
- gl->TexParameteri(resource->target,
- GL_TEXTURE_USAGE_ANGLE,
- GL_FRAMEBUFFER_ATTACHMENT_ANGLE));
+ gl->BindTexture(resource->target, resource->gl_id);
+ gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER,
+ resource->original_filter);
+ gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER,
+ resource->original_filter);
+ gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode);
+ gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode);
+ gl->TexParameteri(resource->target, GL_TEXTURE_POOL_CHROMIUM,
+ resource->texture_pool);
+ if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
+ gl->TexParameteri(resource->target, GL_TEXTURE_USAGE_ANGLE,
+ GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
}
}
@@ -1991,27 +1915,19 @@ void ResourceProvider::LazyAllocate(Resource* resource) {
gfx::Size& size = resource->size;
DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
ResourceFormat format = resource->format;
- GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
+ gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
if (use_texture_storage_ext_ &&
IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
- (resource->hint & TextureHintImmutable)) {
+ (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
GLenum storage_format = TextureToStorageFormat(format);
- GLC(gl,
- gl->TexStorage2DEXT(
- GL_TEXTURE_2D, 1, storage_format, size.width(), size.height()));
+ gl->TexStorage2DEXT(GL_TEXTURE_2D, 1, storage_format, size.width(),
+ size.height());
} else {
// ETC1 does not support preallocation.
if (format != ETC1) {
- GLC(gl,
- gl->TexImage2D(GL_TEXTURE_2D,
- 0,
- GLInternalFormat(format),
- size.width(),
- size.height(),
- 0,
- GLDataFormat(format),
- GLDataType(format),
- NULL));
+ gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format), size.width(),
+ size.height(), 0, GLDataFormat(format), GLDataType(format),
+ NULL);
}
}
}
@@ -2034,19 +1950,19 @@ void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) {
Resource* source_resource = GetResource(source_id);
DCHECK(!source_resource->lock_for_read_count);
- DCHECK(source_resource->origin == Resource::Internal);
+ DCHECK(source_resource->origin == Resource::INTERNAL);
DCHECK_EQ(source_resource->exported_count, 0);
- DCHECK_EQ(GLTexture, source_resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
DCHECK(source_resource->allocated);
LazyCreate(source_resource);
Resource* dest_resource = GetResource(dest_id);
DCHECK(!dest_resource->locked_for_write);
DCHECK(!dest_resource->lock_for_read_count);
- DCHECK(dest_resource->origin == Resource::Internal);
+ DCHECK(dest_resource->origin == Resource::INTERNAL);
DCHECK_EQ(dest_resource->exported_count, 0);
- DCHECK_EQ(GLTexture, dest_resource->type);
- LazyCreate(dest_resource);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type);
+ LazyAllocate(dest_resource);
DCHECK_EQ(source_resource->type, dest_resource->type);
DCHECK_EQ(source_resource->format, dest_resource->format);
@@ -2061,23 +1977,31 @@ void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) {
if (use_sync_query_) {
if (!source_resource->gl_read_lock_query_id)
gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
+#if defined(OS_CHROMEOS)
+ // TODO(reveman): This avoids a performance problem on some ChromeOS
+ // devices. This needs to be removed to support native GpuMemoryBuffer
+ // implementations. crbug.com/436314
+ gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM,
+ source_resource->gl_read_lock_query_id);
+#else
gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
source_resource->gl_read_lock_query_id);
+#endif
}
DCHECK(!dest_resource->image_id);
dest_resource->allocated = true;
- gl->CopyTextureCHROMIUM(dest_resource->target,
- source_resource->gl_id,
- dest_resource->gl_id,
- 0,
- GLInternalFormat(dest_resource->format),
- GLDataType(dest_resource->format));
+ gl->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id,
+ dest_resource->gl_id, 0, 0);
if (source_resource->gl_read_lock_query_id) {
// End query and create a read lock fence that will prevent access to
- // source resource until CopyTextureCHROMIUM command has completed.
+// source resource until CopySubTextureCHROMIUM command has completed.
+#if defined(OS_CHROMEOS)
+ gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
+#else
gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
+#endif
source_resource->read_lock_fence = make_scoped_refptr(
- new QueryFence(gl, source_resource->gl_read_lock_query_id));
+ new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
} else {
// Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
// Try to use one synchronous fence for as many CopyResource operations as
@@ -2094,14 +2018,14 @@ void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
Resource* resource = GetResource(id);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(resource->allocated);
- if (resource->type != GLTexture || resource->gl_id)
+ if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
return;
if (!resource->mailbox.sync_point())
return;
DCHECK(resource->mailbox.IsValid());
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point()));
+ gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point());
resource->mailbox.set_sync_point(0);
}
@@ -2120,13 +2044,21 @@ GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
return active_unit;
}
+void ResourceProvider::ValidateResource(ResourceId id) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(id);
+ DCHECK(resources_.find(id) != resources_.end());
+}
+
GLES2Interface* ResourceProvider::ContextGL() const {
ContextProvider* context_provider = output_surface_->context_provider();
return context_provider ? context_provider->ContextGL() : NULL;
}
-class GrContext* ResourceProvider::GrContext() const {
- ContextProvider* context_provider = output_surface_->context_provider();
+class GrContext* ResourceProvider::GrContext(bool worker_context) const {
+ ContextProvider* context_provider =
+ worker_context ? output_surface_->worker_context_provider()
+ : output_surface_->context_provider();
return context_provider ? context_provider->GrContext() : NULL;
}
diff --git a/chromium/cc/resources/resource_provider.h b/chromium/cc/resources/resource_provider.h
index 40103f6b3e3..f7baac1e3bb 100644
--- a/chromium/cc/resources/resource_provider.h
+++ b/chromium/cc/resources/resource_provider.h
@@ -64,19 +64,18 @@ class CC_EXPORT ResourceProvider {
public:
typedef unsigned ResourceId;
typedef std::vector<ResourceId> ResourceIdArray;
- typedef std::set<ResourceId> ResourceIdSet;
+ typedef base::hash_set<ResourceId> ResourceIdSet;
typedef base::hash_map<ResourceId, ResourceId> ResourceIdMap;
enum TextureHint {
- TextureHintDefault = 0x0,
- TextureHintImmutable = 0x1,
- TextureHintFramebuffer = 0x2,
- TextureHintImmutableFramebuffer =
- TextureHintImmutable | TextureHintFramebuffer
+ TEXTURE_HINT_DEFAULT = 0x0,
+ TEXTURE_HINT_IMMUTABLE = 0x1,
+ TEXTURE_HINT_FRAMEBUFFER = 0x2,
+ TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER =
+ TEXTURE_HINT_IMMUTABLE | TEXTURE_HINT_FRAMEBUFFER
};
enum ResourceType {
- InvalidType = 0,
- GLTexture = 1,
- Bitmap,
+ RESOURCE_TYPE_GL_TEXTURE,
+ RESOURCE_TYPE_BITMAP,
};
static scoped_ptr<ResourceProvider> Create(
@@ -89,9 +88,6 @@ class CC_EXPORT ResourceProvider {
size_t id_allocation_chunk_size);
virtual ~ResourceProvider();
- void InitializeSoftware();
- void InitializeGL();
-
void DidLoseOutputSurface() { lost_output_surface_ = true; }
int max_texture_size() const { return max_texture_size_; }
@@ -99,6 +95,7 @@ class CC_EXPORT ResourceProvider {
return use_rgba_4444_texture_format_ ? RGBA_4444 : best_texture_format_;
}
ResourceFormat best_texture_format() const { return best_texture_format_; }
+ ResourceFormat yuv_resource_format() const { return yuv_resource_format_; }
bool use_sync_query() const { return use_sync_query_; }
size_t num_resources() const { return resources_.size(); }
@@ -149,11 +146,15 @@ class CC_EXPORT ResourceProvider {
// Update pixels from image, copying source_rect (in image) to dest_offset (in
// the resource).
+ // NOTE: DEPRECATED. Use CopyToResource() instead.
void SetPixels(ResourceId id,
const uint8_t* image,
const gfx::Rect& image_rect,
const gfx::Rect& source_rect,
const gfx::Vector2d& dest_offset);
+ void CopyToResource(ResourceId id,
+ const uint8_t* image,
+ const gfx::Size& image_size);
// Check upload status.
size_t NumBlockingUploads();
@@ -173,6 +174,10 @@ class CC_EXPORT ResourceProvider {
// Destroys accounting for the child, deleting all accounted resources.
void DestroyChild(int child);
+ // Sets whether resources need sync points set on them when returned to this
+ // child. Defaults to true.
+ void SetChildNeedsSyncPoints(int child, bool needs_sync_points);
+
// Gets the child->parent resource ID map.
const ResourceIdMap& GetChildToParentMap(int child) const;
@@ -198,9 +203,8 @@ class CC_EXPORT ResourceProvider {
// Once a set of resources have been received, they may or may not be used.
// This declares what set of resources are currently in use from the child,
// releasing any other resources back to the child.
- void DeclareUsedResourcesFromChild(
- int child,
- const ResourceIdArray& resources_from_child);
+ void DeclareUsedResourcesFromChild(int child,
+ const ResourceIdSet& resources_from_child);
// Receives resources from the parent, moving them from mailboxes. Resource
// IDs passed are in the child namespace.
@@ -219,14 +223,15 @@ class CC_EXPORT ResourceProvider {
ResourceProvider::ResourceId resource_id);
virtual ~ScopedReadLockGL();
- unsigned texture_id() const { return texture_id_; }
+ unsigned texture_id() const { return resource_->gl_id; }
+ GLenum target() const { return resource_->target; }
protected:
ResourceProvider* resource_provider_;
ResourceProvider::ResourceId resource_id_;
private:
- unsigned texture_id_;
+ const ResourceProvider::Resource* resource_;
DISALLOW_COPY_AND_ASSIGN(ScopedReadLockGL);
};
@@ -296,14 +301,13 @@ class CC_EXPORT ResourceProvider {
ResourceProvider::ResourceId resource_id);
~ScopedWriteLockSoftware();
- SkCanvas* sk_canvas() { return sk_canvas_.get(); }
+ SkBitmap& sk_bitmap() { return sk_bitmap_; }
bool valid() const { return !!sk_bitmap_.getPixels(); }
private:
ResourceProvider* resource_provider_;
ResourceProvider::Resource* resource_;
SkBitmap sk_bitmap_;
- scoped_ptr<SkCanvas> sk_canvas_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockSoftware);
@@ -335,12 +339,19 @@ class CC_EXPORT ResourceProvider {
ResourceProvider::ResourceId resource_id);
~ScopedWriteLockGr();
- SkSurface* GetSkSurface(bool use_distance_field_text);
+ void InitSkSurface(bool use_distance_field_text,
+ bool can_use_lcd_text,
+ int msaa_sample_count);
+ void ReleaseSkSurface();
+
+ SkSurface* sk_surface() { return sk_surface_.get(); }
+ ResourceProvider::Resource* resource() { return resource_; }
private:
ResourceProvider* resource_provider_;
ResourceProvider::Resource* resource_;
base::ThreadChecker thread_checker_;
+ skia::RefPtr<SkSurface> sk_surface_;
DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGr);
};
@@ -422,11 +433,14 @@ class CC_EXPORT ResourceProvider {
static GLint GetActiveTextureUnit(gpu::gles2::GLES2Interface* gl);
+ OutputSurface* output_surface() { return output_surface_; }
+
+ void ValidateResource(ResourceId id) const;
+
private:
struct Resource {
- enum Origin { Internal, External, Delegated };
+ enum Origin { INTERNAL, EXTERNAL, DELEGATED };
- Resource();
~Resource();
Resource(unsigned texture_id,
const gfx::Size& size,
@@ -490,14 +504,9 @@ class CC_EXPORT ResourceProvider {
SharedBitmapId shared_bitmap_id;
SharedBitmap* shared_bitmap;
gfx::GpuMemoryBuffer* gpu_memory_buffer;
- skia::RefPtr<SkSurface> sk_surface;
};
typedef base::hash_map<ResourceId, Resource> ResourceMap;
- static bool CompareResourceMapIteratorsByChildId(
- const std::pair<ReturnedResource, ResourceMap::iterator>& a,
- const std::pair<ReturnedResource, ResourceMap::iterator>& b);
-
struct Child {
Child();
~Child();
@@ -505,8 +514,8 @@ class CC_EXPORT ResourceProvider {
ResourceIdMap child_to_parent_map;
ResourceIdMap parent_to_child_map;
ReturnCallback return_callback;
- ResourceIdSet in_use_resources;
bool marked_for_deletion;
+ bool needs_sync_points;
};
typedef base::hash_map<int, Child> ChildMap;
@@ -520,11 +529,14 @@ class CC_EXPORT ResourceProvider {
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
BlockingTaskRunner* blocking_main_thread_task_runner,
int highp_threshold_min,
+ ResourceType default_resource_type,
bool use_rgba_4444_texture_format,
size_t id_allocation_chunk_size);
- void CleanUpGLIfNeeded();
+ void InitializeSoftware();
+ void InitializeGL();
+ Resource* InsertResource(ResourceId id, const Resource& resource);
Resource* GetResource(ResourceId id);
const Resource* LockForRead(ResourceId id);
void UnlockForRead(ResourceId id);
@@ -538,8 +550,8 @@ class CC_EXPORT ResourceProvider {
ResourceId id,
TransferableResource* resource);
enum DeleteStyle {
- Normal,
- ForShutdown,
+ NORMAL,
+ FOR_SHUTDOWN,
};
void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style);
void DeleteAndReturnUnusedResourcesToChild(ChildMap::iterator child_it,
@@ -557,7 +569,7 @@ class CC_EXPORT ResourceProvider {
// Returns NULL if the output_surface_ does not have a ContextProvider.
gpu::gles2::GLES2Interface* ContextGL() const;
- class GrContext* GrContext() const;
+ class GrContext* GrContext(bool worker_context) const;
OutputSurface* output_surface_;
SharedBitmapManager* shared_bitmap_manager_;
@@ -570,11 +582,12 @@ class CC_EXPORT ResourceProvider {
int next_child_;
ChildMap children_;
- ResourceType default_resource_type_;
+ const ResourceType default_resource_type_;
bool use_texture_storage_ext_;
bool use_texture_format_bgra_;
bool use_texture_usage_hint_;
bool use_compressed_texture_etc1_;
+ ResourceFormat yuv_resource_format_;
scoped_ptr<TextureUploader> texture_uploader_;
int max_texture_size_;
ResourceFormat best_texture_format_;
@@ -595,33 +608,38 @@ class CC_EXPORT ResourceProvider {
DISALLOW_COPY_AND_ASSIGN(ResourceProvider);
};
-
// TODO(epenner): Move these format conversions to resource_format.h
// once that builds on mac (npapi.h currently #includes OpenGL.h).
inline unsigned BitsPerPixel(ResourceFormat format) {
- DCHECK_LE(format, RESOURCE_FORMAT_MAX);
- static const unsigned format_bits_per_pixel[RESOURCE_FORMAT_MAX + 1] = {
- 32, // RGBA_8888
- 16, // RGBA_4444
- 32, // BGRA_8888
- 8, // ALPHA_8
- 8, // LUMINANCE_8
- 16, // RGB_565,
- 4 // ETC1
- };
- return format_bits_per_pixel[format];
+ switch (format) {
+ case BGRA_8888:
+ case RGBA_8888:
+ return 32;
+ case RGBA_4444:
+ case RGB_565:
+ return 16;
+ case ALPHA_8:
+ case LUMINANCE_8:
+ case RED_8:
+ return 8;
+ case ETC1:
+ return 4;
+ }
+ NOTREACHED();
+ return 0;
}
inline GLenum GLDataType(ResourceFormat format) {
DCHECK_LE(format, RESOURCE_FORMAT_MAX);
static const unsigned format_gl_data_type[RESOURCE_FORMAT_MAX + 1] = {
- GL_UNSIGNED_BYTE, // RGBA_8888
- GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444
- GL_UNSIGNED_BYTE, // BGRA_8888
- GL_UNSIGNED_BYTE, // ALPHA_8
- GL_UNSIGNED_BYTE, // LUMINANCE_8
- GL_UNSIGNED_SHORT_5_6_5, // RGB_565,
- GL_UNSIGNED_BYTE // ETC1
+ GL_UNSIGNED_BYTE, // RGBA_8888
+ GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444
+ GL_UNSIGNED_BYTE, // BGRA_8888
+ GL_UNSIGNED_BYTE, // ALPHA_8
+ GL_UNSIGNED_BYTE, // LUMINANCE_8
+ GL_UNSIGNED_SHORT_5_6_5, // RGB_565,
+ GL_UNSIGNED_BYTE, // ETC1
+ GL_UNSIGNED_BYTE // RED_8
};
return format_gl_data_type[format];
}
@@ -629,13 +647,14 @@ inline GLenum GLDataType(ResourceFormat format) {
inline GLenum GLDataFormat(ResourceFormat format) {
DCHECK_LE(format, RESOURCE_FORMAT_MAX);
static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = {
- GL_RGBA, // RGBA_8888
- GL_RGBA, // RGBA_4444
- GL_BGRA_EXT, // BGRA_8888
- GL_ALPHA, // ALPHA_8
- GL_LUMINANCE, // LUMINANCE_8
- GL_RGB, // RGB_565
- GL_ETC1_RGB8_OES // ETC1
+ GL_RGBA, // RGBA_8888
+ GL_RGBA, // RGBA_4444
+ GL_BGRA_EXT, // BGRA_8888
+ GL_ALPHA, // ALPHA_8
+ GL_LUMINANCE, // LUMINANCE_8
+ GL_RGB, // RGB_565
+ GL_ETC1_RGB8_OES, // ETC1
+ GL_RED_EXT // RED_8
};
return format_gl_data_format[format];
}
diff --git a/chromium/cc/resources/resource_provider_unittest.cc b/chromium/cc/resources/resource_provider_unittest.cc
index e507ad67a93..3ca1ab41dd7 100644
--- a/chromium/cc/resources/resource_provider_unittest.cc
+++ b/chromium/cc/resources/resource_provider_unittest.cc
@@ -59,15 +59,15 @@ static void ReleaseCallback(
*release_main_thread_task_runner = main_thread_task_runner;
}
-static void SharedMemoryReleaseCallback(
- scoped_ptr<base::SharedMemory> memory,
+static void SharedBitmapReleaseCallback(
+ scoped_ptr<SharedBitmap> bitmap,
uint32 sync_point,
bool lost_resource,
BlockingTaskRunner* main_thread_task_runner) {
}
-static void ReleaseSharedMemoryCallback(
- scoped_ptr<base::SharedMemory> shared_memory,
+static void ReleaseSharedBitmapCallback(
+ scoped_ptr<SharedBitmap> shared_bitmap,
bool* release_called,
uint32* release_sync_point,
bool* lost_resource_result,
@@ -79,15 +79,16 @@ static void ReleaseSharedMemoryCallback(
*lost_resource_result = lost_resource;
}
-static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory(
+static scoped_ptr<SharedBitmap> CreateAndFillSharedBitmap(
+ SharedBitmapManager* manager,
const gfx::Size& size,
uint32_t value) {
- scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
- CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea()));
- uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory());
+ scoped_ptr<SharedBitmap> shared_bitmap = manager->AllocateSharedBitmap(size);
+ CHECK(shared_bitmap);
+ uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_bitmap->pixels());
CHECK(pixels);
std::fill_n(pixels, size.GetArea(), value);
- return shared_memory.Pass();
+ return shared_bitmap.Pass();
}
class TextureStateTrackingContext : public TestWebGraphicsContext3D {
@@ -96,18 +97,18 @@ class TextureStateTrackingContext : public TestWebGraphicsContext3D {
MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param));
MOCK_METHOD1(waitSyncPoint, void(GLuint sync_point));
MOCK_METHOD0(insertSyncPoint, GLuint(void));
- MOCK_METHOD2(produceTextureCHROMIUM,
- void(GLenum target, const GLbyte* mailbox));
- MOCK_METHOD2(consumeTextureCHROMIUM,
- void(GLenum target, const GLbyte* mailbox));
+ MOCK_METHOD3(produceTextureDirectCHROMIUM,
+ void(GLuint texture, GLenum target, const GLbyte* mailbox));
+ MOCK_METHOD2(createAndConsumeTextureCHROMIUM,
+ unsigned(GLenum target, const GLbyte* mailbox));
// Force all textures to be consecutive numbers starting at "1",
// so we easily can test for them.
- virtual GLuint NextTextureId() override {
+ GLuint NextTextureId() override {
base::AutoLock lock(namespace_->lock);
return namespace_->next_texture_id++;
}
- virtual void RetireTextureId(GLuint) override {}
+ void RetireTextureId(GLuint) override {}
};
// Shared data between multiple ResourceProviderContext. This contains mailbox
@@ -257,25 +258,27 @@ class ResourceProviderContext : public TestWebGraphicsContext3D {
return shared_data_->GenMailbox(mailbox);
}
- void produceTextureCHROMIUM(GLenum target, const GLbyte* mailbox) override {
- CheckTextureIsBound(target);
-
+ void produceTextureDirectCHROMIUM(GLuint texture,
+ GLenum target,
+ const GLbyte* mailbox) override {
// Delay moving the texture into the mailbox until the next
// InsertSyncPoint, so that it is not visible to other contexts that
// haven't waited on that sync point.
scoped_ptr<PendingProduceTexture> pending(new PendingProduceTexture);
memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox));
base::AutoLock lock_for_texture_access(namespace_->lock);
- pending->texture = BoundTexture(target);
+ pending->texture = UnboundTexture(texture);
pending_produce_textures_.push_back(pending.Pass());
}
- void consumeTextureCHROMIUM(GLenum target, const GLbyte* mailbox) override {
- CheckTextureIsBound(target);
+ GLuint createAndConsumeTextureCHROMIUM(GLenum target,
+ const GLbyte* mailbox) override {
+ GLuint texture_id = createTexture();
base::AutoLock lock_for_texture_access(namespace_->lock);
scoped_refptr<TestTexture> texture =
shared_data_->ConsumeTexture(mailbox, last_waited_sync_point_);
- namespace_->textures.Replace(BoundTextureId(target), texture);
+ namespace_->textures.Replace(texture_id, texture);
+ return texture_id;
}
void GetPixels(const gfx::Size& size,
@@ -353,14 +356,14 @@ void GetResourcePixels(ResourceProvider* resource_provider,
uint8_t* pixels) {
resource_provider->WaitSyncPointIfNeeded(id);
switch (resource_provider->default_resource_type()) {
- case ResourceProvider::GLTexture: {
+ case ResourceProvider::RESOURCE_TYPE_GL_TEXTURE: {
ResourceProvider::ScopedReadLockGL lock_gl(resource_provider, id);
ASSERT_NE(0U, lock_gl.texture_id());
context->bindTexture(GL_TEXTURE_2D, lock_gl.texture_id());
context->GetPixels(size, format, pixels);
break;
}
- case ResourceProvider::Bitmap: {
+ case ResourceProvider::RESOURCE_TYPE_BITMAP: {
ResourceProvider::ScopedReadLockSoftware lock_software(resource_provider,
id);
memcpy(pixels,
@@ -368,22 +371,19 @@ void GetResourcePixels(ResourceProvider* resource_provider,
lock_software.sk_bitmap()->getSize());
break;
}
- case ResourceProvider::InvalidType:
- NOTREACHED();
- break;
}
}
class ResourceProviderTest
: public testing::TestWithParam<ResourceProvider::ResourceType> {
public:
- ResourceProviderTest()
+ explicit ResourceProviderTest(bool child_needs_sync_point)
: shared_data_(ContextSharedData::Create()),
context3d_(NULL),
child_context_(NULL),
main_thread_task_runner_(BlockingTaskRunner::Create(NULL)) {
switch (GetParam()) {
- case ResourceProvider::GLTexture: {
+ case ResourceProvider::RESOURCE_TYPE_GL_TEXTURE: {
scoped_ptr<ResourceProviderContext> context3d(
ResourceProviderContext::Create(shared_data_.get()));
context3d_ = context3d.get();
@@ -396,19 +396,21 @@ class ResourceProviderTest
scoped_ptr<ResourceProviderContext> child_context_owned =
ResourceProviderContext::Create(shared_data_.get());
child_context_ = child_context_owned.get();
- child_output_surface_ =
- FakeOutputSurface::Create3d(child_context_owned.Pass());
+ if (child_needs_sync_point) {
+ child_output_surface_ =
+ FakeOutputSurface::Create3d(child_context_owned.Pass());
+ } else {
+ child_output_surface_ = FakeOutputSurface::CreateNoRequireSyncPoint(
+ child_context_owned.Pass());
+ }
break;
}
- case ResourceProvider::Bitmap:
+ case ResourceProvider::RESOURCE_TYPE_BITMAP:
output_surface_ = FakeOutputSurface::CreateSoftware(
make_scoped_ptr(new SoftwareOutputDevice));
child_output_surface_ = FakeOutputSurface::CreateSoftware(
make_scoped_ptr(new SoftwareOutputDevice));
break;
- case ResourceProvider::InvalidType:
- NOTREACHED();
- break;
}
CHECK(output_surface_->BindToClient(&output_surface_client_));
CHECK(child_output_surface_->BindToClient(&child_output_surface_client_));
@@ -434,6 +436,8 @@ class ResourceProviderTest
1);
}
+ ResourceProviderTest() : ResourceProviderTest(true) {}
+
static void CollectResources(ReturnedResourceArray* array,
const ReturnedResourceArray& returned,
BlockingTaskRunner* main_thread_task_runner) {
@@ -457,41 +461,35 @@ class ResourceProviderTest
bool* lost_resource,
bool* release_called,
uint32* sync_point) {
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
unsigned texture = child_context_->createTexture();
gpu::Mailbox gpu_mailbox;
- child_context_->bindTexture(GL_TEXTURE_2D, texture);
child_context_->genMailboxCHROMIUM(gpu_mailbox.name);
- child_context_->produceTextureCHROMIUM(GL_TEXTURE_2D, gpu_mailbox.name);
+ child_context_->produceTextureDirectCHROMIUM(texture, GL_TEXTURE_2D,
+ gpu_mailbox.name);
*sync_point = child_context_->insertSyncPoint();
EXPECT_LT(0u, *sync_point);
- scoped_ptr<base::SharedMemory> shared_memory;
+ scoped_ptr<SharedBitmap> shared_bitmap;
scoped_ptr<SingleReleaseCallbackImpl> callback =
- SingleReleaseCallbackImpl::Create(
- base::Bind(ReleaseSharedMemoryCallback,
- base::Passed(&shared_memory),
- release_called,
- release_sync_point,
- lost_resource));
+ SingleReleaseCallbackImpl::Create(base::Bind(
+ ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
+ release_called, release_sync_point, lost_resource));
return child_resource_provider_->CreateResourceFromTextureMailbox(
TextureMailbox(gpu_mailbox, GL_TEXTURE_2D, *sync_point),
callback.Pass());
} else {
gfx::Size size(64, 64);
- scoped_ptr<base::SharedMemory> shared_memory(
- CreateAndFillSharedMemory(size, 0));
+ scoped_ptr<SharedBitmap> shared_bitmap(
+ CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, 0));
- base::SharedMemory* shared_memory_ptr = shared_memory.get();
+ SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
scoped_ptr<SingleReleaseCallbackImpl> callback =
- SingleReleaseCallbackImpl::Create(
- base::Bind(ReleaseSharedMemoryCallback,
- base::Passed(&shared_memory),
- release_called,
- release_sync_point,
- lost_resource));
+ SingleReleaseCallbackImpl::Create(base::Bind(
+ ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
+ release_called, release_sync_point, lost_resource));
return child_resource_provider_->CreateResourceFromTextureMailbox(
- TextureMailbox(shared_memory_ptr, size), callback.Pass());
+ TextureMailbox(shared_bitmap_ptr, size), callback.Pass());
}
}
@@ -521,15 +519,14 @@ void CheckCreateResource(ResourceProvider::ResourceType expected_default_type,
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_EQ(1, static_cast<int>(resource_provider->num_resources()));
- if (expected_default_type == ResourceProvider::GLTexture)
+ if (expected_default_type == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_EQ(0u, context->NumTextures());
uint8_t data[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
- if (expected_default_type == ResourceProvider::GLTexture)
+ resource_provider->CopyToResource(id, data, size);
+ if (expected_default_type == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_EQ(1u, context->NumTextures());
uint8_t result[4] = { 0 };
@@ -538,7 +535,7 @@ void CheckCreateResource(ResourceProvider::ResourceType expected_default_type,
resource_provider->DeleteResource(id);
EXPECT_EQ(0, static_cast<int>(resource_provider->num_resources()));
- if (expected_default_type == ResourceProvider::GLTexture)
+ if (expected_default_type == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_EQ(0u, context->NumTextures());
}
@@ -553,7 +550,7 @@ TEST_P(ResourceProviderTest, Upload) {
ASSERT_EQ(16U, pixel_size);
ResourceProvider::ResourceId id = resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t image[16] = { 0 };
gfx::Rect image_rect(size);
@@ -613,8 +610,40 @@ TEST_P(ResourceProviderTest, Upload) {
resource_provider_->DeleteResource(id);
}
+TEST_P(ResourceProviderTest, SimpleUpload) {
+ gfx::Size size(2, 2);
+ ResourceFormat format = RGBA_8888;
+ size_t pixel_size = TextureSizeBytes(size, format);
+ ASSERT_EQ(16U, pixel_size);
+
+ ResourceProvider::ResourceId id = resource_provider_->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
+
+ uint8_t image[16] = {0};
+ resource_provider_->CopyToResource(id, image, size);
+ {
+ uint8_t result[16] = {0};
+ uint8_t expected[16] = {0};
+ GetResourcePixels(resource_provider_.get(), context(), id, size, format,
+ result);
+ EXPECT_EQ(0, memcmp(expected, result, pixel_size));
+ }
+
+ for (uint8_t i = 0; i < pixel_size; ++i)
+ image[i] = i;
+ resource_provider_->CopyToResource(id, image, size);
+ {
+ uint8_t result[16] = {0};
+ uint8_t expected[16] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ GetResourcePixels(resource_provider_.get(), context(), id, size, format,
+ result);
+ EXPECT_EQ(0, memcmp(expected, result, pixel_size));
+ }
+}
+
TEST_P(ResourceProviderTest, TransferGLResources) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -622,31 +651,29 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data2[4] = { 5, 5, 5, 5 };
- child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id2, data2, size);
ResourceProvider::ResourceId id3 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
{
ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock(
child_resource_provider_.get(), id3);
- EXPECT_TRUE(!!lock.GetGpuMemoryBuffer());
+ EXPECT_TRUE(lock.GetGpuMemoryBuffer());
}
GLuint external_texture_id = child_context_->createExternalTexture();
- child_context_->bindTexture(GL_TEXTURE_EXTERNAL_OES, external_texture_id);
gpu::Mailbox external_mailbox;
child_context_->genMailboxCHROMIUM(external_mailbox.name);
- child_context_->produceTextureCHROMIUM(GL_TEXTURE_EXTERNAL_OES,
- external_mailbox.name);
+ child_context_->produceTextureDirectCHROMIUM(
+ external_texture_id, GL_TEXTURE_EXTERNAL_OES, external_mailbox.name);
const GLuint external_sync_point = child_context_->insertSyncPoint();
ResourceProvider::ResourceId id4 =
child_resource_provider_->CreateResourceFromTextureMailbox(
@@ -698,8 +725,13 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
}
EXPECT_EQ(list[0].mailbox_holder.sync_point,
context3d_->last_waited_sync_point());
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id1);
+ resource_ids_to_receive.insert(id2);
+ resource_ids_to_receive.insert(id3);
+ resource_ids_to_receive.insert(id4);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
EXPECT_EQ(4u, resource_provider_->num_resources());
@@ -761,7 +793,7 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
// Transfer resources back from the parent to the child. Set no resources as
// being in use.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
ASSERT_EQ(4u, returned_to_child.size());
@@ -838,8 +870,13 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4));
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id1);
+ resource_ids_to_receive.insert(id2);
+ resource_ids_to_receive.insert(id3);
+ resource_ids_to_receive.insert(id4);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
EXPECT_EQ(0u, returned_to_child.size());
@@ -859,17 +896,124 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
EXPECT_FALSE(returned_to_child[3].lost);
}
+class ResourceProviderTestNoSyncPoint : public ResourceProviderTest {
+ public:
+ ResourceProviderTestNoSyncPoint() : ResourceProviderTest(false) {
+ EXPECT_EQ(ResourceProvider::RESOURCE_TYPE_GL_TEXTURE, GetParam());
+ }
+};
+
+TEST_P(ResourceProviderTestNoSyncPoint, TransferGLResources) {
+ gfx::Size size(1, 1);
+ ResourceFormat format = RGBA_8888;
+ size_t pixel_size = TextureSizeBytes(size, format);
+ ASSERT_EQ(4U, pixel_size);
+
+ ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
+ uint8_t data1[4] = {1, 2, 3, 4};
+ child_resource_provider_->CopyToResource(id1, data1, size);
+
+ ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
+ {
+ // Ensure locking the memory buffer doesn't create an unnecessary sync
+ // point.
+ ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock(
+ child_resource_provider_.get(), id2);
+ EXPECT_TRUE(lock.GetGpuMemoryBuffer());
+ }
+
+ GLuint external_texture_id = child_context_->createExternalTexture();
+
+ // A sync point is specified directly and should be used.
+ gpu::Mailbox external_mailbox;
+ child_context_->genMailboxCHROMIUM(external_mailbox.name);
+ child_context_->produceTextureDirectCHROMIUM(
+ external_texture_id, GL_TEXTURE_EXTERNAL_OES, external_mailbox.name);
+ const GLuint external_sync_point = child_context_->insertSyncPoint();
+ ResourceProvider::ResourceId id3 =
+ child_resource_provider_->CreateResourceFromTextureMailbox(
+ TextureMailbox(external_mailbox, GL_TEXTURE_EXTERNAL_OES,
+ external_sync_point),
+ SingleReleaseCallbackImpl::Create(base::Bind(&EmptyReleaseCallback)));
+
+ ReturnedResourceArray returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+ resource_provider_->SetChildNeedsSyncPoints(child_id, false);
+ {
+ // Transfer some resources to the parent.
+ ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ resource_ids_to_transfer.push_back(id1);
+ resource_ids_to_transfer.push_back(id2);
+ resource_ids_to_transfer.push_back(id3);
+ TransferableResourceArray list;
+ child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+ &list);
+ ASSERT_EQ(3u, list.size());
+ // Standard resources shouldn't require creating and sending a sync point.
+ EXPECT_EQ(0u, list[0].mailbox_holder.sync_point);
+ EXPECT_EQ(0u, list[1].mailbox_holder.sync_point);
+ // A given sync point should be passed through.
+ EXPECT_EQ(external_sync_point, list[2].mailbox_holder.sync_point);
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id1);
+ resource_ids_to_receive.insert(id2);
+ resource_ids_to_receive.insert(id3);
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ resource_ids_to_receive);
+ }
+
+ {
+ EXPECT_EQ(0u, returned_to_child.size());
+
+ // Transfer resources back from the parent to the child. Set no resources as
+ // being in use.
+ ResourceProvider::ResourceIdSet no_resources;
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
+
+ ASSERT_EQ(3u, returned_to_child.size());
+ std::map<ResourceProvider::ResourceId, unsigned int> returned_sync_points;
+ for (const auto& returned : returned_to_child)
+ returned_sync_points[returned.id] = returned.sync_point;
+
+ EXPECT_TRUE(returned_sync_points.find(id1) != returned_sync_points.end());
+ // No new sync point should be created transferring back.
+ EXPECT_TRUE(returned_sync_points.find(id1) != returned_sync_points.end());
+ EXPECT_EQ(0u, returned_sync_points[id1]);
+ EXPECT_TRUE(returned_sync_points.find(id2) != returned_sync_points.end());
+ EXPECT_EQ(0u, returned_sync_points[id2]);
+ // Original sync point given should be returned.
+ EXPECT_TRUE(returned_sync_points.find(id3) != returned_sync_points.end());
+ EXPECT_EQ(external_sync_point, returned_sync_points[id3]);
+ EXPECT_FALSE(returned_to_child[0].lost);
+ EXPECT_FALSE(returned_to_child[1].lost);
+ EXPECT_FALSE(returned_to_child[2].lost);
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+ returned_to_child.clear();
+ }
+
+ resource_provider_->DestroyChild(child_id);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ ResourceProviderTests,
+ ResourceProviderTestNoSyncPoint,
+ ::testing::Values(ResourceProvider::RESOURCE_TYPE_GL_TEXTURE));
+
TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = {1, 2, 3, 4};
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -891,7 +1035,7 @@ TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) {
list[0].id);
resource_provider_->DeclareUsedResourcesFromChild(
- child_id, ResourceProvider::ResourceIdArray());
+ child_id, ResourceProvider::ResourceIdSet());
EXPECT_EQ(0u, returned_to_child.size());
}
@@ -913,7 +1057,7 @@ TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) {
TEST_P(ResourceProviderTest, AllowOverlayTransfersToParent) {
// Overlays only supported on the GL path.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
uint32 sync_point = 0;
@@ -950,7 +1094,7 @@ TEST_P(ResourceProviderTest, AllowOverlayTransfersToParent) {
EXPECT_FALSE(resource_provider_->AllowOverlay(list[1].id));
resource_provider_->DeclareUsedResourcesFromChild(
- child_id, ResourceProvider::ResourceIdArray());
+ child_id, ResourceProvider::ResourceIdSet());
EXPECT_EQ(2u, returned_to_child.size());
child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
@@ -963,7 +1107,7 @@ TEST_P(ResourceProviderTest, AllowOverlayTransfersToParent) {
}
TEST_P(ResourceProviderTest, TransferSoftwareResources) {
- if (GetParam() != ResourceProvider::Bitmap)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_BITMAP)
return;
gfx::Size size(1, 1);
@@ -972,24 +1116,23 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data2[4] = { 5, 5, 5, 5 };
- child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id2, data2, size);
- scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
- shared_memory->CreateAndMapAnonymous(1);
- base::SharedMemory* shared_memory_ptr = shared_memory.get();
+ scoped_ptr<SharedBitmap> shared_bitmap(CreateAndFillSharedBitmap(
+ shared_bitmap_manager_.get(), gfx::Size(1, 1), 0));
+ SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
ResourceProvider::ResourceId id3 =
child_resource_provider_->CreateResourceFromTextureMailbox(
- TextureMailbox(shared_memory_ptr, gfx::Size(1, 1)),
+ TextureMailbox(shared_bitmap_ptr, gfx::Size(1, 1)),
SingleReleaseCallbackImpl::Create(base::Bind(
- &SharedMemoryReleaseCallback, base::Passed(&shared_memory))));
+ &SharedBitmapReleaseCallback, base::Passed(&shared_bitmap))));
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1011,8 +1154,12 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id1);
+ resource_ids_to_receive.insert(id2);
+ resource_ids_to_receive.insert(id3);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
EXPECT_EQ(3u, resource_provider_->num_resources());
@@ -1062,7 +1209,7 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
// Transfer resources back from the parent to the child. Set no resources as
// being in use.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
ASSERT_EQ(3u, returned_to_child.size());
@@ -1120,8 +1267,12 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id1);
+ resource_ids_to_receive.insert(id2);
+ resource_ids_to_receive.insert(id3);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
EXPECT_EQ(0u, returned_to_child.size());
@@ -1148,7 +1299,7 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
}
TEST_P(ResourceProviderTest, TransferGLToSoftware) {
- if (GetParam() != ResourceProvider::Bitmap)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_BITMAP)
return;
scoped_ptr<ResourceProviderContext> child_context_owned(
@@ -1174,10 +1325,9 @@ TEST_P(ResourceProviderTest, TransferGLToSoftware) {
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider->CopyToResource(id1, data1, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1212,7 +1362,7 @@ TEST_P(ResourceProviderTest, TransferGLToSoftware) {
}
TEST_P(ResourceProviderTest, TransferInvalidSoftware) {
- if (GetParam() != ResourceProvider::Bitmap)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_BITMAP)
return;
gfx::Size size(1, 1);
@@ -1221,10 +1371,9 @@ TEST_P(ResourceProviderTest, TransferInvalidSoftware) {
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1269,15 +1418,14 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) {
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data2[4] = {5, 5, 5, 5};
- child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id2, data2, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1291,15 +1439,18 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) {
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
ASSERT_EQ(2u, list.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id1);
+ resource_ids_to_receive.insert(id2);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
EXPECT_EQ(2u, resource_provider_->num_resources());
@@ -1321,7 +1472,7 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) {
resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
ASSERT_EQ(2u, list.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
@@ -1330,7 +1481,7 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) {
// Release the resource in the parent. Set no resources as being in use. The
// resources are exported so that can't be transferred back yet.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
EXPECT_EQ(0u, returned_to_child.size());
@@ -1347,7 +1498,7 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) {
EXPECT_EQ(0u, resource_provider_->num_resources());
ASSERT_EQ(2u, returned_to_child.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, returned_to_child[0].sync_point);
EXPECT_NE(0u, returned_to_child[1].sync_point);
}
@@ -1363,15 +1514,14 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = {1, 2, 3, 4};
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data2[4] = {5, 5, 5, 5};
- child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id2, data2, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1385,15 +1535,18 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
ASSERT_EQ(2u, list.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id1);
+ resource_ids_to_receive.insert(id2);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
EXPECT_EQ(2u, resource_provider_->num_resources());
@@ -1415,7 +1568,7 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
ASSERT_EQ(2u, list.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
@@ -1424,7 +1577,7 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
// Release the resource in the parent. Set no resources as being in use. The
// resources are exported so that can't be transferred back yet.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
// Destroy the child, the resources should not be returned yet.
@@ -1450,7 +1603,7 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
EXPECT_EQ(1u, resource_provider_->num_resources());
ASSERT_EQ(1u, returned_to_child.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, returned_to_child[0].sync_point);
}
EXPECT_FALSE(returned_to_child[0].lost);
@@ -1460,7 +1613,7 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
// lost at this point, and returned.
resource_provider_ = nullptr;
ASSERT_EQ(1u, returned_to_child.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, returned_to_child[0].sync_point);
}
EXPECT_TRUE(returned_to_child[0].lost);
@@ -1474,10 +1627,9 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) {
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id, data, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1490,12 +1642,14 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) {
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
ASSERT_EQ(1u, list.size());
- if (GetParam() == ResourceProvider::GLTexture)
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
// Delete textures in the child, while they are transfered.
@@ -1506,11 +1660,11 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) {
// Transfer resources back from the parent to the child. Set no resources as
// being in use.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
ASSERT_EQ(1u, returned_to_child.size());
- if (GetParam() == ResourceProvider::GLTexture)
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_NE(0u, returned_to_child[0].sync_point);
child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
}
@@ -1524,10 +1678,9 @@ TEST_P(ResourceProviderTest, UnuseTransferredResources) {
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data[4] = {1, 2, 3, 4};
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id, data, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1543,8 +1696,10 @@ TEST_P(ResourceProviderTest, UnuseTransferredResources) {
&list);
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
TransferableResourceArray sent_to_top_level;
{
@@ -1559,7 +1714,7 @@ TEST_P(ResourceProviderTest, UnuseTransferredResources) {
}
{
// Stop using resource.
- ResourceProvider::ResourceIdArray empty;
+ ResourceProvider::ResourceIdSet empty;
resource_provider_->DeclareUsedResourcesFromChild(child_id, empty);
// Resource is not yet returned to the child, since it's in use by the
// top-level.
@@ -1574,8 +1729,10 @@ TEST_P(ResourceProviderTest, UnuseTransferredResources) {
&list);
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
{
// Receive returns back from top-level.
@@ -1614,7 +1771,7 @@ TEST_P(ResourceProviderTest, UnuseTransferredResources) {
}
{
// Stop using resource.
- ResourceProvider::ResourceIdArray empty;
+ ResourceProvider::ResourceIdSet empty;
resource_provider_->DeclareUsedResourcesFromChild(child_id, empty);
// Resource should have been returned to the child, since it's no longer in
// use by the top-level.
@@ -1677,7 +1834,8 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id = child_resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ format);
// The new texture is created with GL_LINEAR.
EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id))
@@ -1700,10 +1858,9 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
Mock::VerifyAndClearExpectations(child_context);
uint8_t data[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id));
- child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
+ child_resource_provider->CopyToResource(id, data, size);
Mock::VerifyAndClearExpectations(child_context);
// The texture is set to |child_filter| in the child.
@@ -1728,9 +1885,8 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
resource_ids_to_transfer.push_back(id);
TransferableResourceArray list;
- EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id));
EXPECT_CALL(*child_context,
- produceTextureCHROMIUM(GL_TEXTURE_2D, _));
+ produceTextureDirectCHROMIUM(_, GL_TEXTURE_2D, _));
EXPECT_CALL(*child_context, insertSyncPoint());
child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
&list);
@@ -1740,8 +1896,9 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
EXPECT_EQ(static_cast<unsigned>(child_filter), list[0].filter);
EXPECT_CALL(*parent_context,
- bindTexture(GL_TEXTURE_2D, parent_texture_id));
- EXPECT_CALL(*parent_context, consumeTextureCHROMIUM(GL_TEXTURE_2D, _));
+ createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, _))
+ .WillOnce(Return(parent_texture_id));
+
parent_resource_provider->ReceiveFromChild(child_id, list);
{
parent_resource_provider->WaitSyncPointIfNeeded(list[0].id);
@@ -1750,8 +1907,10 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
}
Mock::VerifyAndClearExpectations(parent_context);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id);
parent_resource_provider->DeclareUsedResourcesFromChild(
- child_id, resource_ids_to_transfer);
+ child_id, resource_ids_to_receive);
Mock::VerifyAndClearExpectations(parent_context);
}
ResourceProvider::ResourceIdMap resource_map =
@@ -1785,7 +1944,7 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
// Transfer resources back from the parent to the child. Set no resources
// as being in use.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
EXPECT_CALL(*parent_context, insertSyncPoint());
parent_resource_provider->DeclareUsedResourcesFromChild(child_id,
no_resources);
@@ -1803,20 +1962,20 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
};
TEST_P(ResourceProviderTest, TextureFilters_ChildNearestParentLinear) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
ResourceProviderTestTextureFilters::RunTest(GL_NEAREST, GL_LINEAR);
}
TEST_P(ResourceProviderTest, TextureFilters_ChildLinearParentNearest) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
ResourceProviderTestTextureFilters::RunTest(GL_LINEAR, GL_NEAREST);
}
TEST_P(ResourceProviderTest, TransferMailboxResources) {
// Other mailbox transfers tested elsewhere.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
unsigned texture = context()->createTexture();
context()->bindTexture(GL_TEXTURE_2D, texture);
@@ -1825,7 +1984,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data);
gpu::Mailbox mailbox;
context()->genMailboxCHROMIUM(mailbox.name);
- context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ context()->produceTextureDirectCHROMIUM(texture, GL_TEXTURE_2D, mailbox.name);
uint32 sync_point = context()->insertSyncPoint();
// All the logic below assumes that the sync points are all positive.
@@ -1859,14 +2018,15 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
EXPECT_EQ(0u, release_sync_point);
context()->waitSyncPoint(list[0].mailbox_holder.sync_point);
- unsigned other_texture = context()->createTexture();
- context()->bindTexture(GL_TEXTURE_2D, other_texture);
- context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ unsigned other_texture =
+ context()->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
uint8_t test_data[4] = { 0 };
context()->GetPixels(
gfx::Size(1, 1), RGBA_8888, test_data);
EXPECT_EQ(0, memcmp(data, test_data, sizeof(data)));
- context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+
+ context()->produceTextureDirectCHROMIUM(other_texture, GL_TEXTURE_2D,
+ mailbox.name);
context()->deleteTexture(other_texture);
list[0].mailbox_holder.sync_point = context()->insertSyncPoint();
EXPECT_LT(0u, list[0].mailbox_holder.sync_point);
@@ -1910,14 +2070,15 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
EXPECT_EQ(0u, release_sync_point);
context()->waitSyncPoint(list[0].mailbox_holder.sync_point);
- unsigned other_texture = context()->createTexture();
- context()->bindTexture(GL_TEXTURE_2D, other_texture);
- context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ unsigned other_texture =
+ context()->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
uint8_t test_data[4] = { 0 };
context()->GetPixels(
gfx::Size(1, 1), RGBA_8888, test_data);
EXPECT_EQ(0, memcmp(data, test_data, sizeof(data)));
- context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+
+ context()->produceTextureDirectCHROMIUM(other_texture, GL_TEXTURE_2D,
+ mailbox.name);
context()->deleteTexture(other_texture);
list[0].mailbox_holder.sync_point = context()->insertSyncPoint();
EXPECT_LT(0u, list[0].mailbox_holder.sync_point);
@@ -1938,8 +2099,8 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
}
context()->waitSyncPoint(release_sync_point);
- context()->bindTexture(GL_TEXTURE_2D, texture);
- context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ texture =
+ context()->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
context()->deleteTexture(texture);
}
@@ -1948,13 +2109,12 @@ TEST_P(ResourceProviderTest, LostResourceInParent) {
ResourceFormat format = RGBA_8888;
ResourceProvider::ResourceId resource =
child_resource_provider_->CreateResource(
- size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
format);
child_resource_provider_->AllocateForTesting(resource);
// Expect a GL resource to be lost.
- bool should_lose_resource = GetParam() == ResourceProvider::GLTexture;
+ bool should_lose_resource =
+ GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE;
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1969,8 +2129,10 @@ TEST_P(ResourceProviderTest, LostResourceInParent) {
EXPECT_EQ(1u, list.size());
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(resource);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
// Lose the output surface in the parent.
@@ -1981,7 +2143,7 @@ TEST_P(ResourceProviderTest, LostResourceInParent) {
// Transfer resources back from the parent to the child. Set no resources as
// being in use.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
// Expect a GL resource to be lost.
@@ -2004,9 +2166,7 @@ TEST_P(ResourceProviderTest, LostResourceInGrandParent) {
ResourceFormat format = RGBA_8888;
ResourceProvider::ResourceId resource =
child_resource_provider_->CreateResource(
- size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
format);
child_resource_provider_->AllocateForTesting(resource);
@@ -2023,8 +2183,10 @@ TEST_P(ResourceProviderTest, LostResourceInGrandParent) {
EXPECT_EQ(1u, list.size());
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(resource);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
{
@@ -2061,7 +2223,7 @@ TEST_P(ResourceProviderTest, LostResourceInGrandParent) {
// Transfer resources back from the parent to the child. Set no resources as
// being in use.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
// Expect the resource to be lost.
@@ -2099,8 +2261,10 @@ TEST_P(ResourceProviderTest, LostMailboxInParent) {
EXPECT_EQ(1u, list.size());
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(resource);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
// Lose the output surface in the parent.
@@ -2111,13 +2275,13 @@ TEST_P(ResourceProviderTest, LostMailboxInParent) {
// Transfer resources back from the parent to the child. Set no resources as
// being in use.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
ASSERT_EQ(1u, returned_to_child.size());
// Losing an output surface only loses hardware resources.
EXPECT_EQ(returned_to_child[0].lost,
- GetParam() == ResourceProvider::GLTexture);
+ GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE);
child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
returned_to_child.clear();
}
@@ -2125,7 +2289,8 @@ TEST_P(ResourceProviderTest, LostMailboxInParent) {
// Delete the resource in the child. Expect the resource to be lost if it's
// a GL texture.
child_resource_provider_->DeleteResource(resource);
- EXPECT_EQ(lost_resource, GetParam() == ResourceProvider::GLTexture);
+ EXPECT_EQ(lost_resource,
+ GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE);
}
TEST_P(ResourceProviderTest, LostMailboxInGrandParent) {
@@ -2149,8 +2314,10 @@ TEST_P(ResourceProviderTest, LostMailboxInGrandParent) {
EXPECT_EQ(1u, list.size());
resource_provider_->ReceiveFromChild(child_id, list);
+ ResourceProvider::ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(resource);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
- resource_ids_to_transfer);
+ resource_ids_to_receive);
}
{
@@ -2181,7 +2348,7 @@ TEST_P(ResourceProviderTest, LostMailboxInGrandParent) {
// Transfer resources back from the parent to the child. Set no resources as
// being in use.
- ResourceProvider::ResourceIdArray no_resources;
+ ResourceProvider::ResourceIdSet no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
// Expect the resource to be lost.
@@ -2209,7 +2376,7 @@ TEST_P(ResourceProviderTest, Shutdown) {
child_resource_provider_ = nullptr;
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_LE(sync_point, release_sync_point);
}
EXPECT_TRUE(release_called);
@@ -2243,13 +2410,13 @@ TEST_P(ResourceProviderTest, ShutdownWithExportedResource) {
TEST_P(ResourceProviderTest, LostContext) {
// TextureMailbox callbacks only exist for GL textures for now.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
unsigned texture = context()->createTexture();
context()->bindTexture(GL_TEXTURE_2D, texture);
gpu::Mailbox mailbox;
context()->genMailboxCHROMIUM(mailbox.name);
- context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ context()->produceTextureDirectCHROMIUM(texture, GL_TEXTURE_2D, mailbox.name);
uint32 sync_point = context()->insertSyncPoint();
EXPECT_LT(0u, sync_point);
@@ -2279,7 +2446,7 @@ TEST_P(ResourceProviderTest, LostContext) {
TEST_P(ResourceProviderTest, ScopedSampler) {
// Sampling is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2305,7 +2472,7 @@ TEST_P(ResourceProviderTest, ScopedSampler) {
int texture_id = 1;
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
// Check that the texture gets created with the right sampler settings.
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id))
@@ -2366,7 +2533,7 @@ TEST_P(ResourceProviderTest, ScopedSampler) {
TEST_P(ResourceProviderTest, ManagedResource) {
// Sampling is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2393,11 +2560,8 @@ TEST_P(ResourceProviderTest, ManagedResource) {
// Check that the texture gets created with the right sampler settings.
ResourceProvider::ResourceId id = resource_provider->CreateManagedResource(
- size,
- GL_TEXTURE_2D,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- format);
+ size, GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
EXPECT_CALL(*context,
texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
@@ -2421,7 +2585,7 @@ TEST_P(ResourceProviderTest, ManagedResource) {
TEST_P(ResourceProviderTest, TextureWrapMode) {
// Sampling is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2450,12 +2614,8 @@ TEST_P(ResourceProviderTest, TextureWrapMode) {
GLint wrap_mode = texture_id == 1 ? GL_CLAMP_TO_EDGE : GL_REPEAT;
// Check that the texture gets created with the right sampler settings.
ResourceProvider::ResourceId id = resource_provider->CreateGLTexture(
- size,
- GL_TEXTURE_2D,
- texture_pool,
- wrap_mode,
- ResourceProvider::TextureHintImmutable,
- format);
+ size, GL_TEXTURE_2D, texture_pool, wrap_mode,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
EXPECT_CALL(*context,
texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
@@ -2478,7 +2638,7 @@ TEST_P(ResourceProviderTest, TextureWrapMode) {
TEST_P(ResourceProviderTest, TextureHint) {
// Sampling is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2506,10 +2666,10 @@ TEST_P(ResourceProviderTest, TextureHint) {
GLenum texture_pool = GL_TEXTURE_POOL_UNMANAGED_CHROMIUM;
const ResourceProvider::TextureHint hints[4] = {
- ResourceProvider::TextureHintDefault,
- ResourceProvider::TextureHintImmutable,
- ResourceProvider::TextureHintFramebuffer,
- ResourceProvider::TextureHintImmutableFramebuffer,
+ ResourceProvider::TEXTURE_HINT_DEFAULT,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ ResourceProvider::TEXTURE_HINT_FRAMEBUFFER,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER,
};
for (GLuint texture_id = 1; texture_id <= arraysize(hints); ++texture_id) {
// Check that the texture gets created with the right sampler settings.
@@ -2535,9 +2695,9 @@ TEST_P(ResourceProviderTest, TextureHint) {
texParameteri(GL_TEXTURE_2D,
GL_TEXTURE_POOL_CHROMIUM,
GL_TEXTURE_POOL_UNMANAGED_CHROMIUM));
- // Check only TextureHintFramebuffer set GL_TEXTURE_USAGE_ANGLE.
+ // Check only TEXTURE_HINT_FRAMEBUFFER set GL_TEXTURE_USAGE_ANGLE.
bool is_framebuffer_hint =
- hints[texture_id - 1] & ResourceProvider::TextureHintFramebuffer;
+ hints[texture_id - 1] & ResourceProvider::TEXTURE_HINT_FRAMEBUFFER;
EXPECT_CALL(*context,
texParameteri(GL_TEXTURE_2D,
GL_TEXTURE_USAGE_ANGLE,
@@ -2551,13 +2711,13 @@ TEST_P(ResourceProviderTest, TextureHint) {
}
TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) {
- if (GetParam() != ResourceProvider::Bitmap)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_BITMAP)
return;
gfx::Size size(64, 64);
const uint32_t kBadBeef = 0xbadbeef;
- scoped_ptr<base::SharedMemory> shared_memory(
- CreateAndFillSharedMemory(size, kBadBeef));
+ scoped_ptr<SharedBitmap> shared_bitmap(
+ CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, kBadBeef));
FakeOutputSurfaceClient output_surface_client;
scoped_ptr<OutputSurface> output_surface(
@@ -2582,7 +2742,7 @@ TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) {
&release_sync_point,
&lost_resource,
&main_thread_task_runner));
- TextureMailbox mailbox(shared_memory.get(), size);
+ TextureMailbox mailbox(shared_bitmap.get(), size);
ResourceProvider::ResourceId id =
resource_provider->CreateResourceFromTextureMailbox(
@@ -2603,94 +2763,161 @@ TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) {
EXPECT_EQ(main_thread_task_runner_.get(), main_thread_task_runner);
}
-TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) {
- // Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
- return;
+class ResourceProviderTestTextureMailboxGLFilters
+ : public ResourceProviderTest {
+ public:
+ static void RunTest(TestSharedBitmapManager* shared_bitmap_manager,
+ TestGpuMemoryBufferManager* gpu_memory_buffer_manager,
+ BlockingTaskRunner* main_thread_task_runner,
+ bool mailbox_nearest_neighbor,
+ GLenum sampler_filter) {
+ scoped_ptr<TextureStateTrackingContext> context_owned(
+ new TextureStateTrackingContext);
+ TextureStateTrackingContext* context = context_owned.get();
- scoped_ptr<TextureStateTrackingContext> context_owned(
- new TextureStateTrackingContext);
- TextureStateTrackingContext* context = context_owned.get();
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(context_owned.Pass()));
+ CHECK(output_surface->BindToClient(&output_surface_client));
- FakeOutputSurfaceClient output_surface_client;
- scoped_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(context_owned.Pass()));
- CHECK(output_surface->BindToClient(&output_surface_client));
-
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(),
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
- main_thread_task_runner_.get(),
- 0,
- false,
- 1));
+ scoped_ptr<ResourceProvider> resource_provider(
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager,
+ gpu_memory_buffer_manager,
+ main_thread_task_runner,
+ 0,
+ false,
+ 1));
- unsigned texture_id = 1;
- uint32 sync_point = 30;
- unsigned target = GL_TEXTURE_2D;
+ unsigned texture_id = 1;
+ uint32 sync_point = 30;
+ unsigned target = GL_TEXTURE_2D;
- EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
- EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
- EXPECT_CALL(*context, insertSyncPoint()).Times(0);
- EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
- EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
+ EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
+ EXPECT_CALL(*context, insertSyncPoint()).Times(0);
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0);
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0);
+
+ gpu::Mailbox gpu_mailbox;
+ memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
+ uint32 release_sync_point = 0;
+ bool lost_resource = false;
+ BlockingTaskRunner* mailbox_task_runner = NULL;
+ scoped_ptr<SingleReleaseCallbackImpl> callback =
+ SingleReleaseCallbackImpl::Create(base::Bind(&ReleaseCallback,
+ &release_sync_point,
+ &lost_resource,
+ &mailbox_task_runner));
+
+ TextureMailbox mailbox(gpu_mailbox, target, sync_point);
+ mailbox.set_nearest_neighbor(mailbox_nearest_neighbor);
- gpu::Mailbox gpu_mailbox;
- memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
- uint32 release_sync_point = 0;
- bool lost_resource = false;
- BlockingTaskRunner* main_thread_task_runner = NULL;
- scoped_ptr<SingleReleaseCallbackImpl> callback =
- SingleReleaseCallbackImpl::Create(base::Bind(&ReleaseCallback,
- &release_sync_point,
- &lost_resource,
- &main_thread_task_runner));
+ ResourceProvider::ResourceId id =
+ resource_provider->CreateResourceFromTextureMailbox(mailbox,
+ callback.Pass());
+ EXPECT_NE(0u, id);
- TextureMailbox mailbox(gpu_mailbox, target, sync_point);
+ Mock::VerifyAndClearExpectations(context);
- ResourceProvider::ResourceId id =
- resource_provider->CreateResourceFromTextureMailbox(
- mailbox, callback.Pass());
- EXPECT_NE(0u, id);
+ {
+ // Mailbox sync point WaitSyncPoint before using the texture.
+ EXPECT_CALL(*context, waitSyncPoint(sync_point));
+ resource_provider->WaitSyncPointIfNeeded(id);
+ Mock::VerifyAndClearExpectations(context);
- Mock::VerifyAndClearExpectations(context);
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(target, _))
+ .WillOnce(Return(texture_id));
+ EXPECT_CALL(*context, bindTexture(target, texture_id));
- {
- // Mailbox sync point WaitSyncPoint before using the texture.
- EXPECT_CALL(*context, waitSyncPoint(sync_point));
- resource_provider->WaitSyncPointIfNeeded(id);
- Mock::VerifyAndClearExpectations(context);
+ EXPECT_CALL(*context, insertSyncPoint()).Times(0);
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0);
- // Using the texture does a consume of the mailbox.
- EXPECT_CALL(*context, bindTexture(target, texture_id));
- EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _));
+ // The sampler will reset these if |mailbox_nearest_neighbor| does not
+ // match |sampler_filter|.
+ if (mailbox_nearest_neighbor != (sampler_filter == GL_NEAREST)) {
+ EXPECT_CALL(*context, texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, sampler_filter));
+ EXPECT_CALL(*context, texParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sampler_filter));
+ }
- EXPECT_CALL(*context, insertSyncPoint()).Times(0);
- EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
+ ResourceProvider::ScopedSamplerGL lock(
+ resource_provider.get(), id, sampler_filter);
+ Mock::VerifyAndClearExpectations(context);
- ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id);
- Mock::VerifyAndClearExpectations(context);
+ // When done with it, a sync point should be inserted, but no produce is
+ // necessary.
+ EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
+ EXPECT_CALL(*context, insertSyncPoint());
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0);
- // When done with it, a sync point should be inserted, but no produce is
- // necessary.
- EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
- EXPECT_CALL(*context, insertSyncPoint());
- EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0);
+ }
- EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
- EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
+ resource_provider->DeleteResource(id);
+ EXPECT_EQ(0u, release_sync_point);
+ EXPECT_FALSE(lost_resource);
+ EXPECT_EQ(main_thread_task_runner, mailbox_task_runner);
}
+};
- resource_provider->DeleteResource(id);
- EXPECT_EQ(0u, release_sync_point);
- EXPECT_FALSE(lost_resource);
- EXPECT_EQ(main_thread_task_runner_.get(), main_thread_task_runner);
+TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D_LinearToLinear) {
+ // Mailboxing is only supported for GL textures.
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
+ return;
+
+ ResourceProviderTestTextureMailboxGLFilters::RunTest(
+ shared_bitmap_manager_.get(),
+ gpu_memory_buffer_manager_.get(),
+ main_thread_task_runner_.get(),
+ false,
+ GL_LINEAR);
+}
+
+TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D_NearestToNearest) {
+ // Mailboxing is only supported for GL textures.
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
+ return;
+
+ ResourceProviderTestTextureMailboxGLFilters::RunTest(
+ shared_bitmap_manager_.get(),
+ gpu_memory_buffer_manager_.get(),
+ main_thread_task_runner_.get(),
+ true,
+ GL_NEAREST);
+}
+
+TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D_NearestToLinear) {
+ // Mailboxing is only supported for GL textures.
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
+ return;
+
+ ResourceProviderTestTextureMailboxGLFilters::RunTest(
+ shared_bitmap_manager_.get(),
+ gpu_memory_buffer_manager_.get(),
+ main_thread_task_runner_.get(),
+ true,
+ GL_LINEAR);
+}
+
+TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D_LinearToNearest) {
+ // Mailboxing is only supported for GL textures.
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
+ return;
+
+ ResourceProviderTestTextureMailboxGLFilters::RunTest(
+ shared_bitmap_manager_.get(),
+ gpu_memory_buffer_manager_.get(),
+ main_thread_task_runner_.get(),
+ false,
+ GL_NEAREST);
}
TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2711,15 +2938,14 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) {
false,
1));
- unsigned texture_id = 1;
uint32 sync_point = 30;
unsigned target = GL_TEXTURE_EXTERNAL_OES;
EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
EXPECT_CALL(*context, insertSyncPoint()).Times(0);
- EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
- EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0);
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0);
gpu::Mailbox gpu_mailbox;
memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
@@ -2741,12 +2967,13 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) {
resource_provider->WaitSyncPointIfNeeded(id);
Mock::VerifyAndClearExpectations(context);
- // Using the texture does a consume of the mailbox.
- EXPECT_CALL(*context, bindTexture(target, texture_id));
- EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _));
+ unsigned texture_id = 1;
+
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(target, _))
+ .WillOnce(Return(texture_id));
EXPECT_CALL(*context, insertSyncPoint()).Times(0);
- EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0);
ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id);
Mock::VerifyAndClearExpectations(context);
@@ -2755,17 +2982,17 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) {
// necessary.
EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
EXPECT_CALL(*context, insertSyncPoint());
- EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0);
EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
- EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0);
}
}
TEST_P(ResourceProviderTest,
TextureMailbox_WaitSyncPointIfNeeded_WithSyncPoint) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2792,8 +3019,8 @@ TEST_P(ResourceProviderTest,
EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
EXPECT_CALL(*context, insertSyncPoint()).Times(0);
- EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
- EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0);
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0);
gpu::Mailbox gpu_mailbox;
memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
@@ -2824,7 +3051,7 @@ TEST_P(ResourceProviderTest,
TEST_P(ResourceProviderTest, TextureMailbox_WaitSyncPointIfNeeded_NoSyncPoint) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2851,8 +3078,8 @@ TEST_P(ResourceProviderTest, TextureMailbox_WaitSyncPointIfNeeded_NoSyncPoint) {
EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
EXPECT_CALL(*context, insertSyncPoint()).Times(0);
- EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
- EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _, _)).Times(0);
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_, _)).Times(0);
gpu::Mailbox gpu_mailbox;
memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
@@ -2951,7 +3178,7 @@ class AllocationTrackingContext3D : public TestWebGraphicsContext3D {
TEST_P(ResourceProviderTest, TextureAllocation) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -2973,7 +3200,6 @@ TEST_P(ResourceProviderTest, TextureAllocation) {
gfx::Size size(2, 2);
gfx::Vector2d offset(0, 0);
- gfx::Rect rect(0, 0, 2, 2);
ResourceFormat format = RGBA_8888;
ResourceProvider::ResourceId id = 0;
uint8_t pixels[16] = { 0 };
@@ -2981,7 +3207,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) {
// Lazy allocation. Don't allocate when creating the resource.
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1);
@@ -2994,13 +3220,13 @@ TEST_P(ResourceProviderTest, TextureAllocation) {
// Do allocate when we set the pixels.
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3);
EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1);
EXPECT_CALL(*context, texSubImage2D(_, _, _, _, 2, 2, _, _, _)).Times(1);
- resource_provider->SetPixels(id, pixels, rect, rect, offset);
+ resource_provider->CopyToResource(id, pixels, size);
EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
resource_provider->DeleteResource(id);
@@ -3009,7 +3235,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) {
// Same for async version.
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
resource_provider->AcquirePixelBuffer(id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
@@ -3029,7 +3255,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) {
TEST_P(ResourceProviderTest, TextureAllocationHint) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3055,10 +3281,10 @@ TEST_P(ResourceProviderTest, TextureAllocationHint) {
const ResourceFormat formats[2] = {RGBA_8888, BGRA_8888};
const ResourceProvider::TextureHint hints[4] = {
- ResourceProvider::TextureHintDefault,
- ResourceProvider::TextureHintImmutable,
- ResourceProvider::TextureHintFramebuffer,
- ResourceProvider::TextureHintImmutableFramebuffer,
+ ResourceProvider::TEXTURE_HINT_DEFAULT,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ ResourceProvider::TEXTURE_HINT_FRAMEBUFFER,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER,
};
for (size_t i = 0; i < arraysize(formats); ++i) {
for (GLuint texture_id = 1; texture_id <= arraysize(hints); ++texture_id) {
@@ -3069,7 +3295,7 @@ TEST_P(ResourceProviderTest, TextureAllocationHint) {
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
bool is_immutable_hint =
- hints[texture_id - 1] & ResourceProvider::TextureHintImmutable;
+ hints[texture_id - 1] & ResourceProvider::TEXTURE_HINT_IMMUTABLE;
bool support_immutable_texture =
is_immutable_hint && formats[i] == RGBA_8888;
EXPECT_CALL(*context, texStorage2DEXT(_, _, _, 2, 2))
@@ -3088,7 +3314,7 @@ TEST_P(ResourceProviderTest, TextureAllocationHint) {
TEST_P(ResourceProviderTest, TextureAllocationHint_BGRA) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3115,10 +3341,10 @@ TEST_P(ResourceProviderTest, TextureAllocationHint_BGRA) {
const ResourceFormat formats[2] = {RGBA_8888, BGRA_8888};
const ResourceProvider::TextureHint hints[4] = {
- ResourceProvider::TextureHintDefault,
- ResourceProvider::TextureHintImmutable,
- ResourceProvider::TextureHintFramebuffer,
- ResourceProvider::TextureHintImmutableFramebuffer,
+ ResourceProvider::TEXTURE_HINT_DEFAULT,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ ResourceProvider::TEXTURE_HINT_FRAMEBUFFER,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER,
};
for (size_t i = 0; i < arraysize(formats); ++i) {
for (GLuint texture_id = 1; texture_id <= arraysize(hints); ++texture_id) {
@@ -3129,7 +3355,7 @@ TEST_P(ResourceProviderTest, TextureAllocationHint_BGRA) {
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
bool is_immutable_hint =
- hints[texture_id - 1] & ResourceProvider::TextureHintImmutable;
+ hints[texture_id - 1] & ResourceProvider::TEXTURE_HINT_IMMUTABLE;
EXPECT_CALL(*context, texStorage2DEXT(_, _, _, 2, 2))
.Times(is_immutable_hint ? 1 : 0);
EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _))
@@ -3145,7 +3371,7 @@ TEST_P(ResourceProviderTest, TextureAllocationHint_BGRA) {
}
TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3171,7 +3397,7 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
1));
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
resource_provider->AcquirePixelBuffer(id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
@@ -3192,7 +3418,7 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3218,7 +3444,7 @@ TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) {
1));
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
resource_provider->AcquirePixelBuffer(id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
@@ -3267,7 +3493,7 @@ TEST_P(ResourceProviderTest, PixelBufferLostContext) {
EXPECT_CALL(*context, NextTextureId()).WillRepeatedly(Return(texture_id));
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
GL_INNOCENT_CONTEXT_RESET_ARB);
@@ -3281,7 +3507,7 @@ TEST_P(ResourceProviderTest, PixelBufferLostContext) {
TEST_P(ResourceProviderTest, Image_GLTexture) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3310,7 +3536,7 @@ TEST_P(ResourceProviderTest, Image_GLTexture) {
1));
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, createImageCHROMIUM(_, kWidth, kHeight, GL_RGBA))
.WillOnce(Return(kImageId))
@@ -3318,7 +3544,7 @@ TEST_P(ResourceProviderTest, Image_GLTexture) {
{
ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock(
resource_provider.get(), id);
- EXPECT_TRUE(!!lock.GetGpuMemoryBuffer());
+ EXPECT_TRUE(lock.GetGpuMemoryBuffer());
}
EXPECT_CALL(*context, NextTextureId())
@@ -3339,7 +3565,7 @@ TEST_P(ResourceProviderTest, Image_GLTexture) {
{
ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock(
resource_provider.get(), id);
- EXPECT_TRUE(!!lock.GetGpuMemoryBuffer());
+ EXPECT_TRUE(lock.GetGpuMemoryBuffer());
}
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(1)
@@ -3365,7 +3591,7 @@ TEST_P(ResourceProviderTest, Image_GLTexture) {
}
TEST_P(ResourceProviderTest, CopyResource_GLTexture) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3397,7 +3623,7 @@ TEST_P(ResourceProviderTest, CopyResource_GLTexture) {
1));
source_id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, createImageCHROMIUM(_, kWidth, kHeight, GL_RGBA))
.WillOnce(Return(kImageId))
@@ -3405,17 +3631,21 @@ TEST_P(ResourceProviderTest, CopyResource_GLTexture) {
{
ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock(
resource_provider.get(), source_id);
- EXPECT_TRUE(!!lock.GetGpuMemoryBuffer());
+ EXPECT_TRUE(lock.GetGpuMemoryBuffer());
}
Mock::VerifyAndClearExpectations(context);
dest_id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, NextTextureId())
.WillOnce(Return(kDestTextureId))
.RetiresOnSaturation();
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kDestTextureId))
+ .Times(2)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*context, texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, nullptr))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*context, NextTextureId())
@@ -3443,58 +3673,8 @@ TEST_P(ResourceProviderTest, CopyResource_GLTexture) {
resource_provider->DeleteResource(dest_id);
}
-void InitializeGLAndCheck(ContextSharedData* shared_data,
- ResourceProvider* resource_provider,
- FakeOutputSurface* output_surface) {
- scoped_ptr<ResourceProviderContext> context_owned =
- ResourceProviderContext::Create(shared_data);
- ResourceProviderContext* context = context_owned.get();
-
- scoped_refptr<TestContextProvider> context_provider =
- TestContextProvider::Create(context_owned.Pass());
- output_surface->InitializeAndSetContext3d(context_provider);
- resource_provider->InitializeGL();
-
- CheckCreateResource(ResourceProvider::GLTexture, resource_provider, context);
-}
-
-TEST(ResourceProviderTest, BasicInitializeGLSoftware) {
- scoped_ptr<ContextSharedData> shared_data = ContextSharedData::Create();
- bool delegated_rendering = false;
- scoped_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice),
- delegated_rendering));
- FakeOutputSurfaceClient client(output_surface.get());
- EXPECT_TRUE(output_surface->BindToClient(&client));
- scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
- new TestSharedBitmapManager());
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(),
- shared_bitmap_manager.get(),
- NULL,
- NULL,
- 0,
- false,
- 1));
-
- CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
-
- InitializeGLAndCheck(shared_data.get(),
- resource_provider.get(),
- output_surface.get());
-
- resource_provider->InitializeSoftware();
- output_surface->ReleaseGL();
- CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
-
- InitializeGLAndCheck(shared_data.get(),
- resource_provider.get(),
- output_surface.get());
-}
-
TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
@@ -3519,7 +3699,7 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) {
int texture_id = 123;
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, ETC1);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, ETC1);
EXPECT_NE(0u, id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
@@ -3529,8 +3709,8 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) {
resource_provider->DeleteResource(id);
}
-TEST_P(ResourceProviderTest, CompressedTextureETC1SetPixels) {
- if (GetParam() != ResourceProvider::GLTexture)
+TEST_P(ResourceProviderTest, CompressedTextureETC1Upload) {
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
@@ -3556,15 +3736,14 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1SetPixels) {
uint8_t pixels[8];
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, ETC1);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, ETC1);
EXPECT_NE(0u, id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3);
EXPECT_CALL(*context,
compressedTexImage2D(
_, 0, _, size.width(), size.height(), _, _, _)).Times(1);
- resource_provider->SetPixels(
- id, pixels, gfx::Rect(size), gfx::Rect(size), gfx::Vector2d(0, 0));
+ resource_provider->CopyToResource(id, pixels, size);
EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
resource_provider->DeleteResource(id);
@@ -3573,7 +3752,8 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1SetPixels) {
INSTANTIATE_TEST_CASE_P(
ResourceProviderTests,
ResourceProviderTest,
- ::testing::Values(ResourceProvider::GLTexture, ResourceProvider::Bitmap));
+ ::testing::Values(ResourceProvider::RESOURCE_TYPE_GL_TEXTURE,
+ ResourceProvider::RESOURCE_TYPE_BITMAP));
class TextureIdAllocationTrackingContext : public TestWebGraphicsContext3D {
public:
@@ -3615,7 +3795,8 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) {
kTextureAllocationChunkSize));
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ format);
resource_provider->AllocateForTesting(id);
Mock::VerifyAndClearExpectations(context);
@@ -3635,7 +3816,8 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) {
kTextureAllocationChunkSize));
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ format);
resource_provider->AllocateForTesting(id);
Mock::VerifyAndClearExpectations(context);
diff --git a/chromium/cc/resources/resource_update_controller.h b/chromium/cc/resources/resource_update_controller.h
index 994ae2f2df9..1946df47c16 100644
--- a/chromium/cc/resources/resource_update_controller.h
+++ b/chromium/cc/resources/resource_update_controller.h
@@ -71,7 +71,6 @@ class CC_EXPORT ResourceUpdateController {
ResourceUpdateControllerClient* client_;
scoped_ptr<ResourceUpdateQueue> queue_;
- bool contents_textures_purged_;
ResourceProvider* resource_provider_;
base::TimeTicks time_limit_;
size_t texture_updates_per_tick_;
diff --git a/chromium/cc/resources/resource_update_controller_unittest.cc b/chromium/cc/resources/resource_update_controller_unittest.cc
index d6b4f39b40b..1aa0902d469 100644
--- a/chromium/cc/resources/resource_update_controller_unittest.cc
+++ b/chromium/cc/resources/resource_update_controller_unittest.cc
@@ -66,7 +66,7 @@ class ResourceUpdateControllerTest : public Test {
num_total_uploads_(0),
num_total_flushes_(0) {}
- virtual ~ResourceUpdateControllerTest() {
+ ~ResourceUpdateControllerTest() override {
DebugScopedSetImplThreadAndMainThreadBlocked
impl_thread_and_main_thread_blocked(&proxy_);
resource_manager_->ClearAllMemory(resource_provider_.get());
@@ -106,7 +106,7 @@ class ResourceUpdateControllerTest : public Test {
}
protected:
- virtual void SetUp() {
+ void SetUp() override {
bitmap_.allocN32Pixels(300, 150);
for (int i = 0; i < 4; i++) {
diff --git a/chromium/cc/resources/scoped_resource.cc b/chromium/cc/resources/scoped_resource.cc
index c83efb59fd9..e7011822d36 100644
--- a/chromium/cc/resources/scoped_resource.cc
+++ b/chromium/cc/resources/scoped_resource.cc
@@ -25,7 +25,7 @@ void ScopedResource::Allocate(const gfx::Size& size,
set_id(resource_provider_->CreateResource(
size, GL_CLAMP_TO_EDGE, hint, format));
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
allocate_thread_id_ = base::PlatformThread::CurrentId();
#endif
}
@@ -38,20 +38,17 @@ void ScopedResource::AllocateManaged(const gfx::Size& size,
set_dimensions(size, format);
set_id(resource_provider_->CreateManagedResource(
- size,
- target,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ size, target, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
format));
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
allocate_thread_id_ = base::PlatformThread::CurrentId();
#endif
}
void ScopedResource::Free() {
if (id()) {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
DCHECK(allocate_thread_id_ == base::PlatformThread::CurrentId());
#endif
resource_provider_->DeleteResource(id());
diff --git a/chromium/cc/resources/scoped_resource.h b/chromium/cc/resources/scoped_resource.h
index 4241b38eae6..6f8c1cd8c54 100644
--- a/chromium/cc/resources/scoped_resource.h
+++ b/chromium/cc/resources/scoped_resource.h
@@ -11,7 +11,7 @@
#include "cc/base/cc_export.h"
#include "cc/resources/resource.h"
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
#include "base/threading/platform_thread.h"
#endif
@@ -39,7 +39,7 @@ class CC_EXPORT ScopedResource : public Resource {
private:
ResourceProvider* resource_provider_;
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
base::PlatformThreadId allocate_thread_id_;
#endif
diff --git a/chromium/cc/resources/scoped_resource_unittest.cc b/chromium/cc/resources/scoped_resource_unittest.cc
index a141218a053..b95d814914e 100644
--- a/chromium/cc/resources/scoped_resource_unittest.cc
+++ b/chromium/cc/resources/scoped_resource_unittest.cc
@@ -57,8 +57,8 @@ TEST(ScopedResourceTest, CreateScopedResource) {
1));
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
- texture->Allocate(
- gfx::Size(30, 30), ResourceProvider::TextureHintImmutable, RGBA_8888);
+ texture->Allocate(gfx::Size(30, 30), ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
// The texture has an allocated byte-size now.
size_t expected_bytes = 30 * 30 * 4;
@@ -89,8 +89,8 @@ TEST(ScopedResourceTest, ScopedResourceIsDeleted) {
ScopedResource::Create(resource_provider.get());
EXPECT_EQ(0u, resource_provider->num_resources());
- texture->Allocate(
- gfx::Size(30, 30), ResourceProvider::TextureHintImmutable, RGBA_8888);
+ texture->Allocate(gfx::Size(30, 30),
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
EXPECT_LT(0u, texture->id());
EXPECT_EQ(1u, resource_provider->num_resources());
}
@@ -100,8 +100,8 @@ TEST(ScopedResourceTest, ScopedResourceIsDeleted) {
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
EXPECT_EQ(0u, resource_provider->num_resources());
- texture->Allocate(
- gfx::Size(30, 30), ResourceProvider::TextureHintImmutable, RGBA_8888);
+ texture->Allocate(gfx::Size(30, 30),
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
EXPECT_LT(0u, texture->id());
EXPECT_EQ(1u, resource_provider->num_resources());
texture->Free();
diff --git a/chromium/cc/resources/shared_bitmap.cc b/chromium/cc/resources/shared_bitmap.cc
index 31cf245151c..1ac03233dfb 100644
--- a/chromium/cc/resources/shared_bitmap.cc
+++ b/chromium/cc/resources/shared_bitmap.cc
@@ -10,25 +10,13 @@
namespace cc {
-SharedBitmap::SharedBitmap(
- base::SharedMemory* memory,
- const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap* bitmap)>& free_callback)
- : memory_(memory),
- pixels_(static_cast<uint8*>(memory_->memory())),
- id_(id),
- free_callback_(free_callback) {
+SharedBitmap::SharedBitmap(uint8* pixels, const SharedBitmapId& id)
+ : pixels_(pixels), id_(id) {
}
-SharedBitmap::SharedBitmap(
- uint8* pixels,
- const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap* bitmap)>& free_callback)
- : memory_(NULL), pixels_(pixels), id_(id), free_callback_(free_callback) {
+SharedBitmap::~SharedBitmap() {
}
-SharedBitmap::~SharedBitmap() { free_callback_.Run(this); }
-
// static
bool SharedBitmap::SizeInBytes(const gfx::Size& size, size_t* size_in_bytes) {
if (size.IsEmpty())
diff --git a/chromium/cc/resources/shared_bitmap.h b/chromium/cc/resources/shared_bitmap.h
index ca1271061f0..6980afbc112 100644
--- a/chromium/cc/resources/shared_bitmap.h
+++ b/chromium/cc/resources/shared_bitmap.h
@@ -6,42 +6,22 @@
#define CC_RESOURCES_SHARED_BITMAP_H_
#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/shared_memory.h"
#include "cc/base/cc_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "ui/gfx/geometry/size.h"
-namespace base { class SharedMemory; }
-
namespace cc {
typedef gpu::Mailbox SharedBitmapId;
class CC_EXPORT SharedBitmap {
public:
- SharedBitmap(base::SharedMemory* memory,
- const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap* bitmap)>& free_callback);
-
- SharedBitmap(uint8* pixels,
- const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap* bitmap)>& free_callback);
+ SharedBitmap(uint8* pixels, const SharedBitmapId& id);
- ~SharedBitmap();
-
- bool operator<(const SharedBitmap& right) const {
- if (memory_ < right.memory_)
- return true;
- if (memory_ > right.memory_)
- return false;
- return id_ < right.id_;
- }
+ virtual ~SharedBitmap();
uint8* pixels() { return pixels_; }
- base::SharedMemory* memory() { return memory_; }
-
- SharedBitmapId id() { return id_; }
+ const SharedBitmapId& id() { return id_; }
// Returns true if the size is valid and false otherwise.
static bool SizeInBytes(const gfx::Size& size, size_t* size_in_bytes);
@@ -57,10 +37,8 @@ class CC_EXPORT SharedBitmap {
static SharedBitmapId GenerateId();
private:
- base::SharedMemory* memory_;
uint8* pixels_;
SharedBitmapId id_;
- base::Callback<void(SharedBitmap* bitmap)> free_callback_;
DISALLOW_COPY_AND_ASSIGN(SharedBitmap);
};
diff --git a/chromium/cc/resources/shared_bitmap_manager.h b/chromium/cc/resources/shared_bitmap_manager.h
index fe61b0998b8..d5239e4b88d 100644
--- a/chromium/cc/resources/shared_bitmap_manager.h
+++ b/chromium/cc/resources/shared_bitmap_manager.h
@@ -6,6 +6,7 @@
#define CC_RESOURCES_SHARED_BITMAP_MANAGER_H_
#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "cc/resources/shared_bitmap.h"
#include "ui/gfx/geometry/size.h"
@@ -21,8 +22,6 @@ class CC_EXPORT SharedBitmapManager {
virtual scoped_ptr<SharedBitmap> GetSharedBitmapFromId(
const gfx::Size&,
const SharedBitmapId&) = 0;
- virtual scoped_ptr<SharedBitmap> GetBitmapForSharedMemory(
- base::SharedMemory*) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(SharedBitmapManager);
diff --git a/chromium/cc/resources/single_release_callback.cc b/chromium/cc/resources/single_release_callback.cc
index 4565963a59f..ff9422302bd 100644
--- a/chromium/cc/resources/single_release_callback.cc
+++ b/chromium/cc/resources/single_release_callback.cc
@@ -10,20 +10,19 @@
namespace cc {
SingleReleaseCallback::SingleReleaseCallback(const ReleaseCallback& callback)
- : has_been_run_(false), callback_(callback) {
+ : callback_(callback) {
DCHECK(!callback_.is_null())
<< "Use a NULL SingleReleaseCallback for an empty callback.";
}
SingleReleaseCallback::~SingleReleaseCallback() {
- DCHECK(callback_.is_null() || has_been_run_)
- << "SingleReleaseCallback was never run.";
+ DCHECK(callback_.is_null()) << "SingleReleaseCallback was never run.";
}
void SingleReleaseCallback::Run(uint32 sync_point, bool is_lost) {
- DCHECK(!has_been_run_) << "SingleReleaseCallback was run more than once.";
- has_been_run_ = true;
- callback_.Run(sync_point, is_lost);
+ DCHECK(!callback_.is_null())
+ << "SingleReleaseCallback was run more than once.";
+ base::ResetAndReturn(&callback_).Run(sync_point, is_lost);
}
} // namespace cc
diff --git a/chromium/cc/resources/single_release_callback.h b/chromium/cc/resources/single_release_callback.h
index 6f64df629e7..b51c4e608c9 100644
--- a/chromium/cc/resources/single_release_callback.h
+++ b/chromium/cc/resources/single_release_callback.h
@@ -24,7 +24,6 @@ class CC_EXPORT SingleReleaseCallback {
private:
explicit SingleReleaseCallback(const ReleaseCallback& callback);
- bool has_been_run_;
ReleaseCallback callback_;
};
diff --git a/chromium/cc/resources/single_release_callback_impl.cc b/chromium/cc/resources/single_release_callback_impl.cc
index 6f3c5353819..c19e14e58a2 100644
--- a/chromium/cc/resources/single_release_callback_impl.cc
+++ b/chromium/cc/resources/single_release_callback_impl.cc
@@ -12,23 +12,23 @@ namespace cc {
SingleReleaseCallbackImpl::SingleReleaseCallbackImpl(
const ReleaseCallbackImpl& callback)
- : has_been_run_(false), callback_(callback) {
+ : callback_(callback) {
DCHECK(!callback_.is_null())
<< "Use a NULL SingleReleaseCallbackImpl for an empty callback.";
}
SingleReleaseCallbackImpl::~SingleReleaseCallbackImpl() {
- DCHECK(callback_.is_null() || has_been_run_)
- << "SingleReleaseCallbackImpl was never run.";
+ DCHECK(callback_.is_null()) << "SingleReleaseCallbackImpl was never run.";
}
void SingleReleaseCallbackImpl::Run(
uint32 sync_point,
bool is_lost,
BlockingTaskRunner* main_thread_task_runner) {
- DCHECK(!has_been_run_) << "SingleReleaseCallbackImpl was run more than once.";
- has_been_run_ = true;
- callback_.Run(sync_point, is_lost, main_thread_task_runner);
+ DCHECK(!callback_.is_null())
+ << "SingleReleaseCallbackImpl was run more than once.";
+ base::ResetAndReturn(&callback_)
+ .Run(sync_point, is_lost, main_thread_task_runner);
}
} // namespace cc
diff --git a/chromium/cc/resources/single_release_callback_impl.h b/chromium/cc/resources/single_release_callback_impl.h
index 41220dc29e8..e9d4293f67b 100644
--- a/chromium/cc/resources/single_release_callback_impl.h
+++ b/chromium/cc/resources/single_release_callback_impl.h
@@ -27,7 +27,6 @@ class CC_EXPORT SingleReleaseCallbackImpl {
private:
explicit SingleReleaseCallbackImpl(const ReleaseCallbackImpl& callback);
- bool has_been_run_;
ReleaseCallbackImpl callback_;
};
diff --git a/chromium/cc/resources/skpicture_content_layer_updater.cc b/chromium/cc/resources/skpicture_content_layer_updater.cc
index bd524f235f1..c54f5dcaa7c 100644
--- a/chromium/cc/resources/skpicture_content_layer_updater.cc
+++ b/chromium/cc/resources/skpicture_content_layer_updater.cc
@@ -4,7 +4,7 @@
#include "cc/resources/skpicture_content_layer_updater.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/resources/layer_painter.h"
#include "cc/resources/prioritized_resource.h"
@@ -16,9 +16,9 @@ namespace cc {
SkPictureContentLayerUpdater::SkPictureContentLayerUpdater(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
int layer_id)
- : ContentLayerUpdater(painter.Pass(), stats_instrumentation, layer_id) {}
+ : ContentLayerUpdater(painter.Pass(), layer_id) {
+}
SkPictureContentLayerUpdater::~SkPictureContentLayerUpdater() {}
@@ -33,18 +33,12 @@ void SkPictureContentLayerUpdater::PrepareToUpdate(
recorder.beginRecording(paint_rect.width(), paint_rect.height(), NULL, 0);
DCHECK_EQ(paint_rect.width(), canvas->getBaseLayerSize().width());
DCHECK_EQ(paint_rect.height(), canvas->getBaseLayerSize().height());
- base::TimeTicks start_time =
- rendering_stats_instrumentation_->StartRecording();
PaintContents(canvas,
content_size,
paint_rect,
contents_width_scale,
contents_height_scale);
- base::TimeDelta duration =
- rendering_stats_instrumentation_->EndRecording(start_time);
- rendering_stats_instrumentation_->AddRecord(
- duration, paint_rect.width() * paint_rect.height());
- picture_ = skia::AdoptRef(recorder.endRecording());
+ picture_ = skia::AdoptRef(recorder.endRecordingAsPicture());
}
void SkPictureContentLayerUpdater::DrawPicture(SkCanvas* canvas) {
diff --git a/chromium/cc/resources/skpicture_content_layer_updater.h b/chromium/cc/resources/skpicture_content_layer_updater.h
index ec49aaecdbb..33480a873c8 100644
--- a/chromium/cc/resources/skpicture_content_layer_updater.h
+++ b/chromium/cc/resources/skpicture_content_layer_updater.h
@@ -21,7 +21,6 @@ class SkPictureContentLayerUpdater : public ContentLayerUpdater {
protected:
SkPictureContentLayerUpdater(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
int layer_id);
~SkPictureContentLayerUpdater() override;
diff --git a/chromium/cc/resources/texture_mailbox.cc b/chromium/cc/resources/texture_mailbox.cc
index 92736f41fe7..9bf242e1d7c 100644
--- a/chromium/cc/resources/texture_mailbox.cc
+++ b/chromium/cc/resources/texture_mailbox.cc
@@ -9,25 +9,31 @@
namespace cc {
-TextureMailbox::TextureMailbox() : shared_memory_(NULL) {}
+TextureMailbox::TextureMailbox() : shared_bitmap_(NULL) {
+}
TextureMailbox::TextureMailbox(const gpu::MailboxHolder& mailbox_holder)
: mailbox_holder_(mailbox_holder),
- shared_memory_(NULL),
- allow_overlay_(false) {}
+ shared_bitmap_(NULL),
+ allow_overlay_(false),
+ nearest_neighbor_(false) {
+}
TextureMailbox::TextureMailbox(const gpu::Mailbox& mailbox,
uint32 target,
uint32 sync_point)
: mailbox_holder_(mailbox, target, sync_point),
- shared_memory_(NULL),
- allow_overlay_(false) {}
+ shared_bitmap_(NULL),
+ allow_overlay_(false),
+ nearest_neighbor_(false) {
+}
-TextureMailbox::TextureMailbox(base::SharedMemory* shared_memory,
+TextureMailbox::TextureMailbox(SharedBitmap* shared_bitmap,
const gfx::Size& size)
- : shared_memory_(shared_memory),
+ : shared_bitmap_(shared_bitmap),
shared_memory_size_(size),
- allow_overlay_(false) {
+ allow_overlay_(false),
+ nearest_neighbor_(false) {
// If an embedder of cc gives an invalid TextureMailbox, we should crash
// here to identify the offender.
CHECK(SharedBitmap::VerifySizeInBytes(shared_memory_size_));
@@ -41,8 +47,7 @@ bool TextureMailbox::Equals(const TextureMailbox& other) const {
other.mailbox_holder_.mailbox.name,
sizeof(mailbox_holder_.mailbox.name));
} else if (other.IsSharedMemory()) {
- return IsSharedMemory() &&
- shared_memory_->handle() == other.shared_memory_->handle();
+ return IsSharedMemory() && (shared_bitmap_ == other.shared_bitmap_);
}
DCHECK(!other.IsValid());
diff --git a/chromium/cc/resources/texture_mailbox.h b/chromium/cc/resources/texture_mailbox.h
index 4a0b76afea0..cec60cedaca 100644
--- a/chromium/cc/resources/texture_mailbox.h
+++ b/chromium/cc/resources/texture_mailbox.h
@@ -13,6 +13,7 @@
#include "ui/gfx/geometry/size.h"
namespace cc {
+class SharedBitmap;
// TODO(skaslev, danakj) Rename this class more apropriately since now it
// can hold a shared memory resource as well as a texture mailbox.
@@ -21,13 +22,13 @@ class CC_EXPORT TextureMailbox {
TextureMailbox();
explicit TextureMailbox(const gpu::MailboxHolder& mailbox_holder);
TextureMailbox(const gpu::Mailbox& mailbox, uint32 target, uint32 sync_point);
- TextureMailbox(base::SharedMemory* shared_memory, const gfx::Size& size);
+ TextureMailbox(SharedBitmap* shared_bitmap, const gfx::Size& size);
~TextureMailbox();
bool IsValid() const { return IsTexture() || IsSharedMemory(); }
bool IsTexture() const { return !mailbox_holder_.mailbox.IsZero(); }
- bool IsSharedMemory() const { return shared_memory_ != NULL; }
+ bool IsSharedMemory() const { return shared_bitmap_ != NULL; }
bool Equals(const TextureMailbox&) const;
@@ -41,16 +42,21 @@ class CC_EXPORT TextureMailbox {
bool allow_overlay() const { return allow_overlay_; }
void set_allow_overlay(bool allow_overlay) { allow_overlay_ = allow_overlay; }
+ bool nearest_neighbor() const { return nearest_neighbor_; }
+ void set_nearest_neighbor(bool nearest_neighbor) {
+ nearest_neighbor_ = nearest_neighbor;
+ }
- base::SharedMemory* shared_memory() const { return shared_memory_; }
+ SharedBitmap* shared_bitmap() const { return shared_bitmap_; }
gfx::Size shared_memory_size() const { return shared_memory_size_; }
size_t SharedMemorySizeInBytes() const;
private:
gpu::MailboxHolder mailbox_holder_;
- base::SharedMemory* shared_memory_;
+ SharedBitmap* shared_bitmap_;
gfx::Size shared_memory_size_;
bool allow_overlay_;
+ bool nearest_neighbor_;
};
} // namespace cc
diff --git a/chromium/cc/resources/texture_uploader.cc b/chromium/cc/resources/texture_uploader.cc
index 9526fcb9238..89271bdcb54 100644
--- a/chromium/cc/resources/texture_uploader.cc
+++ b/chromium/cc/resources/texture_uploader.cc
@@ -7,8 +7,8 @@
#include <algorithm>
#include <vector>
-#include "base/debug/trace_event.h"
#include "base/metrics/histogram.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/util.h"
#include "cc/resources/resource.h"
#include "gpu/GLES2/gl2extchromium.h"
@@ -136,7 +136,7 @@ void TextureUploader::EndQuery() {
void TextureUploader::Upload(const uint8* image,
const gfx::Rect& image_rect,
const gfx::Rect& source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Vector2d& dest_offset,
ResourceFormat format,
const gfx::Size& size) {
CHECK(image_rect.Contains(source_rect));
@@ -146,14 +146,7 @@ void TextureUploader::Upload(const uint8* image,
if (is_full_upload)
BeginQuery();
- if (format == ETC1) {
- // ETC1 does not support subimage uploads.
- DCHECK(is_full_upload);
- UploadWithTexImageETC1(image, size);
- } else {
- UploadWithMapTexSubImage(
- image, image_rect, source_rect, dest_offset, format);
- }
+ UploadWithMapTexSubImage(image, image_rect, source_rect, dest_offset, format);
if (is_full_upload)
EndQuery();
@@ -180,7 +173,7 @@ void TextureUploader::ReleaseCachedQueries() {
void TextureUploader::UploadWithTexSubImage(const uint8* image,
const gfx::Rect& image_rect,
const gfx::Rect& source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Vector2d& dest_offset,
ResourceFormat format) {
TRACE_EVENT0("cc", "TextureUploader::UploadWithTexSubImage");
@@ -234,7 +227,7 @@ void TextureUploader::UploadWithTexSubImage(const uint8* image,
void TextureUploader::UploadWithMapTexSubImage(const uint8* image,
const gfx::Rect& image_rect,
const gfx::Rect& source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Vector2d& dest_offset,
ResourceFormat format) {
TRACE_EVENT0("cc", "TextureUploader::UploadWithMapTexSubImage");
@@ -291,22 +284,6 @@ void TextureUploader::UploadWithMapTexSubImage(const uint8* image,
gl_->UnmapTexSubImage2DCHROMIUM(pixel_dest);
}
-void TextureUploader::UploadWithTexImageETC1(const uint8* image,
- const gfx::Size& size) {
- TRACE_EVENT0("cc", "TextureUploader::UploadWithTexImageETC1");
- DCHECK_EQ(0, size.width() % 4);
- DCHECK_EQ(0, size.height() % 4);
-
- gl_->CompressedTexImage2D(GL_TEXTURE_2D,
- 0,
- GLInternalFormat(ETC1),
- size.width(),
- size.height(),
- 0,
- Resource::MemorySizeBytes(size, ETC1),
- image);
-}
-
void TextureUploader::ProcessQueries() {
while (!pending_queries_.empty()) {
if (pending_queries_.front()->IsPending())
diff --git a/chromium/cc/resources/texture_uploader.h b/chromium/cc/resources/texture_uploader.h
index 72c46e7ffb5..ae834083e72 100644
--- a/chromium/cc/resources/texture_uploader.h
+++ b/chromium/cc/resources/texture_uploader.h
@@ -45,7 +45,7 @@ class CC_EXPORT TextureUploader {
void Upload(const uint8* image,
const gfx::Rect& content_rect,
const gfx::Rect& source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Vector2d& dest_offset,
ResourceFormat format,
const gfx::Size& size);
@@ -90,12 +90,12 @@ class CC_EXPORT TextureUploader {
void UploadWithTexSubImage(const uint8* image,
const gfx::Rect& image_rect,
const gfx::Rect& source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Vector2d& dest_offset,
ResourceFormat format);
void UploadWithMapTexSubImage(const uint8* image,
const gfx::Rect& image_rect,
const gfx::Rect& source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Vector2d& dest_offset,
ResourceFormat format);
void UploadWithTexImageETC1(const uint8* image, const gfx::Size& size);
diff --git a/chromium/cc/resources/texture_uploader_unittest.cc b/chromium/cc/resources/texture_uploader_unittest.cc
index 72491727291..b1689627d1f 100644
--- a/chromium/cc/resources/texture_uploader_unittest.cc
+++ b/chromium/cc/resources/texture_uploader_unittest.cc
@@ -111,6 +111,14 @@ class TextureUploadTestContext : public gpu::gles2::GLES2InterfaceStub {
EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
bytes_per_pixel = 2;
break;
+ case GL_RED_EXT:
+ EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+ bytes_per_pixel = 1;
+ break;
+ case GL_RG_EXT:
+ EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+ bytes_per_pixel = 2;
+ break;
}
// If NULL, we aren't checking texture contents.
@@ -232,6 +240,15 @@ TEST(TextureUploaderTest, UploadContentsTest) {
buffer[(i + 1) * 82 - 1] = 0x2;
}
UploadTexture(uploader.get(), LUMINANCE_8, gfx::Size(82, 86), buffer);
+
+ // Upload a tightly packed 82x86 RED texture.
+ memset(buffer, 0, sizeof(buffer));
+ for (int i = 0; i < 86; ++i) {
+ // Mark the beginning and end of each row, for the test.
+ buffer[i * 1 * 82] = 0x1;
+ buffer[(i + 1) * 82 - 1] = 0x2;
+ }
+ UploadTexture(uploader.get(), RED_8, gfx::Size(82, 86), buffer);
}
} // namespace
diff --git a/chromium/cc/resources/tile.cc b/chromium/cc/resources/tile.cc
deleted file mode 100644
index d6bd3c4b583..00000000000
--- a/chromium/cc/resources/tile.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2012 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/tile.h"
-
-#include <algorithm>
-
-#include "base/debug/trace_event_argument.h"
-#include "cc/base/math_util.h"
-#include "cc/debug/traced_value.h"
-#include "cc/resources/tile_manager.h"
-#include "third_party/khronos/GLES2/gl2.h"
-
-namespace cc {
-
-Tile::Id Tile::s_next_id_ = 0;
-
-Tile::Tile(TileManager* tile_manager,
- RasterSource* raster_source,
- const gfx::Size& tile_size,
- const gfx::Rect& content_rect,
- float contents_scale,
- int layer_id,
- int source_frame_number,
- int flags)
- : RefCountedManaged<Tile>(tile_manager),
- tile_manager_(tile_manager),
- size_(tile_size),
- content_rect_(content_rect),
- contents_scale_(contents_scale),
- layer_id_(layer_id),
- source_frame_number_(source_frame_number),
- flags_(flags),
- is_shared_(false),
- tiling_i_index_(-1),
- tiling_j_index_(-1),
- required_for_activation_(false),
- id_(s_next_id_++) {
- set_raster_source(raster_source);
- for (int i = 0; i < NUM_TREES; i++)
- is_occluded_[i] = false;
-}
-
-Tile::~Tile() {
- TRACE_EVENT_OBJECT_DELETED_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "cc::Tile", this);
-}
-
-void Tile::AsValueInto(base::debug::TracedValue* res) const {
- TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
- TRACE_DISABLED_BY_DEFAULT("cc.debug"), res, "cc::Tile", this);
- TracedValue::SetIDRef(raster_source_.get(), res, "picture_pile");
- res->SetDouble("contents_scale", contents_scale_);
-
- res->BeginArray("content_rect");
- MathUtil::AddToTracedValue(content_rect_, res);
- res->EndArray();
-
- res->SetInteger("layer_id", layer_id_);
-
- res->BeginDictionary("active_priority");
- priority_[ACTIVE_TREE].AsValueInto(res);
- res->EndDictionary();
-
- res->BeginDictionary("pending_priority");
- priority_[PENDING_TREE].AsValueInto(res);
- res->EndDictionary();
-
- res->BeginDictionary("managed_state");
- managed_state_.AsValueInto(res);
- res->EndDictionary();
-
- res->SetBoolean("use_picture_analysis", use_picture_analysis());
-
- res->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes());
-}
-
-size_t Tile::GPUMemoryUsageInBytes() const {
- if (managed_state_.draw_info.resource_)
- return managed_state_.draw_info.resource_->bytes();
- return 0;
-}
-
-bool Tile::HasRasterTask() const {
- return !!managed_state_.raster_task.get();
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/tile.h b/chromium/cc/resources/tile.h
deleted file mode 100644
index c6413677eb9..00000000000
--- a/chromium/cc/resources/tile.h
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2012 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_TILE_H_
-#define CC_RESOURCES_TILE_H_
-
-#include "base/memory/ref_counted.h"
-#include "cc/base/ref_counted_managed.h"
-#include "cc/resources/managed_tile_state.h"
-#include "cc/resources/raster_source.h"
-#include "cc/resources/tile_priority.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace cc {
-
-class CC_EXPORT Tile : public RefCountedManaged<Tile> {
- public:
- enum TileRasterFlags { USE_PICTURE_ANALYSIS = 1 << 0 };
-
- typedef uint64 Id;
-
- Id id() const {
- return id_;
- }
-
- RasterSource* raster_source() { return raster_source_.get(); }
-
- const RasterSource* raster_source() const { return raster_source_.get(); }
-
- const TilePriority& priority(WhichTree tree) const {
- return priority_[tree];
- }
-
- TilePriority priority_for_tree_priority(TreePriority tree_priority) const {
- switch (tree_priority) {
- case SMOOTHNESS_TAKES_PRIORITY:
- return priority_[ACTIVE_TREE];
- case NEW_CONTENT_TAKES_PRIORITY:
- return priority_[PENDING_TREE];
- case SAME_PRIORITY_FOR_BOTH_TREES:
- return combined_priority();
- default:
- NOTREACHED();
- return TilePriority();
- }
- }
-
- TilePriority combined_priority() const {
- return TilePriority(priority_[ACTIVE_TREE],
- priority_[PENDING_TREE]);
- }
-
- void SetPriority(WhichTree tree, const TilePriority& priority) {
- priority_[tree] = priority;
- }
-
- // TODO(vmpstr): Move this to the iterators.
- void set_is_occluded(WhichTree tree, bool is_occluded) {
- is_occluded_[tree] = is_occluded;
- }
-
- bool is_occluded(WhichTree tree) const { return is_occluded_[tree]; }
-
- void set_shared(bool is_shared) { is_shared_ = is_shared; }
- bool is_shared() const { return is_shared_; }
-
- bool is_occluded_for_tree_priority(TreePriority tree_priority) const {
- switch (tree_priority) {
- case SMOOTHNESS_TAKES_PRIORITY:
- return is_occluded_[ACTIVE_TREE];
- case NEW_CONTENT_TAKES_PRIORITY:
- return is_occluded_[PENDING_TREE];
- case SAME_PRIORITY_FOR_BOTH_TREES:
- return is_occluded_[ACTIVE_TREE] && is_occluded_[PENDING_TREE];
- default:
- NOTREACHED();
- return false;
- }
- }
-
- // TODO(vmpstr): Move this to the iterators.
- bool required_for_activation() const { return required_for_activation_; }
- void set_required_for_activation(bool is_required) {
- required_for_activation_ = is_required;
- }
-
- bool use_picture_analysis() const {
- return !!(flags_ & USE_PICTURE_ANALYSIS);
- }
-
- bool HasResources() const { return managed_state_.draw_info.has_resource(); }
- bool NeedsRaster() const {
- return managed_state_.draw_info.mode() ==
- ManagedTileState::DrawInfo::PICTURE_PILE_MODE ||
- !managed_state_.draw_info.IsReadyToDraw();
- }
-
- void AsValueInto(base::debug::TracedValue* dict) const;
-
- inline bool IsReadyToDraw() const {
- return managed_state_.draw_info.IsReadyToDraw();
- }
-
- const ManagedTileState::DrawInfo& draw_info() const {
- return managed_state_.draw_info;
- }
-
- ManagedTileState::DrawInfo& draw_info() { return managed_state_.draw_info; }
-
- float contents_scale() const { return contents_scale_; }
- gfx::Rect content_rect() const { return content_rect_; }
-
- int layer_id() const { return layer_id_; }
-
- int source_frame_number() const { return source_frame_number_; }
-
- void set_raster_source(scoped_refptr<RasterSource> raster_source) {
- DCHECK(raster_source->CoversRect(content_rect_, contents_scale_))
- << "Recording rect: "
- << gfx::ScaleToEnclosingRect(content_rect_, 1.f / contents_scale_)
- .ToString();
- raster_source_ = raster_source;
- }
-
- size_t GPUMemoryUsageInBytes() const;
-
- gfx::Size size() const { return size_; }
-
- void set_tiling_index(int i, int j) {
- tiling_i_index_ = i;
- tiling_j_index_ = j;
- }
- int tiling_i_index() const { return tiling_i_index_; }
- int tiling_j_index() const { return tiling_j_index_; }
-
- private:
- friend class TileManager;
- friend class PrioritizedTileSet;
- friend class FakeTileManager;
- friend class BinComparator;
- friend class FakePictureLayerImpl;
-
- // Methods called by by tile manager.
- Tile(TileManager* tile_manager,
- RasterSource* raster_source,
- const gfx::Size& tile_size,
- const gfx::Rect& content_rect,
- float contents_scale,
- int layer_id,
- int source_frame_number,
- int flags);
- ~Tile();
-
- ManagedTileState& managed_state() { return managed_state_; }
- const ManagedTileState& managed_state() const { return managed_state_; }
-
- bool HasRasterTask() const;
-
- TileManager* tile_manager_;
- scoped_refptr<RasterSource> raster_source_;
- gfx::Size size_;
- gfx::Rect content_rect_;
- float contents_scale_;
- bool is_occluded_[NUM_TREES];
-
- TilePriority priority_[NUM_TREES];
- ManagedTileState managed_state_;
- int layer_id_;
- int source_frame_number_;
- int flags_;
- bool is_shared_;
- int tiling_i_index_;
- int tiling_j_index_;
- bool required_for_activation_;
-
- Id id_;
- static Id s_next_id_;
-
- DISALLOW_COPY_AND_ASSIGN(Tile);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_TILE_H_
diff --git a/chromium/cc/resources/tile_manager_unittest.cc b/chromium/cc/resources/tile_manager_unittest.cc
deleted file mode 100644
index 2f0735c33d3..00000000000
--- a/chromium/cc/resources/tile_manager_unittest.cc
+++ /dev/null
@@ -1,769 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/eviction_tile_priority_queue.h"
-#include "cc/resources/raster_tile_priority_queue.h"
-#include "cc/resources/tile.h"
-#include "cc/resources/tile_priority.h"
-#include "cc/test/fake_impl_proxy.h"
-#include "cc/test/fake_layer_tree_host_impl.h"
-#include "cc/test/fake_output_surface.h"
-#include "cc/test/fake_output_surface_client.h"
-#include "cc/test/fake_picture_layer_impl.h"
-#include "cc/test/fake_picture_pile_impl.h"
-#include "cc/test/fake_tile_manager.h"
-#include "cc/test/impl_side_painting_settings.h"
-#include "cc/test/test_shared_bitmap_manager.h"
-#include "cc/test/test_tile_priorities.h"
-#include "cc/trees/layer_tree_impl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-namespace {
-
-class LowResTilingsSettings : public ImplSidePaintingSettings {
- public:
- LowResTilingsSettings() { create_low_res_tiling = true; }
-};
-
-class TileManagerTilePriorityQueueTest : public testing::Test {
- public:
- TileManagerTilePriorityQueueTest()
- : memory_limit_policy_(ALLOW_ANYTHING),
- max_tiles_(10000),
- ready_to_activate_(false),
- id_(7),
- proxy_(base::MessageLoopProxy::current()),
- host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_) {}
-
- void SetTreePriority(TreePriority tree_priority) {
- GlobalStateThatImpactsTilePriority state;
- gfx::Size tile_size(256, 256);
-
- state.soft_memory_limit_in_bytes = 100 * 1000 * 1000;
- state.num_resources_limit = max_tiles_;
- state.hard_memory_limit_in_bytes = state.soft_memory_limit_in_bytes * 2;
- state.memory_limit_policy = memory_limit_policy_;
- state.tree_priority = tree_priority;
-
- global_state_ = state;
- host_impl_.resource_pool()->SetResourceUsageLimits(
- state.soft_memory_limit_in_bytes,
- state.soft_memory_limit_in_bytes,
- state.num_resources_limit);
- host_impl_.tile_manager()->SetGlobalStateForTesting(state);
- }
-
- virtual void SetUp() override {
- InitializeRenderer();
- SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
- }
-
- virtual void InitializeRenderer() {
- host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
- }
-
- void SetupDefaultTrees(const gfx::Size& layer_bounds) {
- gfx::Size tile_size(100, 100);
-
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
- SetupTrees(pending_pile, active_pile);
- }
-
- void ActivateTree() {
- host_impl_.ActivateSyncTree();
- CHECK(!host_impl_.pending_tree());
- pending_layer_ = NULL;
- active_layer_ = static_cast<FakePictureLayerImpl*>(
- host_impl_.active_tree()->LayerById(id_));
- }
-
- void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds,
- const gfx::Size& tile_size) {
- SetupDefaultTrees(layer_bounds);
- pending_layer_->set_fixed_tile_size(tile_size);
- active_layer_->set_fixed_tile_size(tile_size);
- }
-
- void SetupTrees(scoped_refptr<PicturePileImpl> pending_pile,
- scoped_refptr<PicturePileImpl> active_pile) {
- SetupPendingTree(active_pile);
- ActivateTree();
- SetupPendingTree(pending_pile);
- }
-
- void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
- host_impl_.CreatePendingTree();
- LayerTreeImpl* pending_tree = host_impl_.pending_tree();
-
- // Steal from the recycled tree.
- scoped_ptr<LayerImpl> old_pending_root = pending_tree->DetachLayerTree();
- DCHECK_IMPLIES(old_pending_root, old_pending_root->id() == id_);
-
- scoped_ptr<FakePictureLayerImpl> pending_layer;
- if (old_pending_root) {
- pending_layer.reset(
- static_cast<FakePictureLayerImpl*>(old_pending_root.release()));
- pending_layer->SetPile(pile);
- } else {
- pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
- pending_layer->SetDrawsContent(true);
- }
- // The bounds() just mirror the pile size.
- pending_layer->SetBounds(pending_layer->pile()->tiling_size());
- pending_tree->SetRootLayer(pending_layer.Pass());
-
- pending_layer_ = static_cast<FakePictureLayerImpl*>(
- host_impl_.pending_tree()->LayerById(id_));
- pending_layer_->DoPostCommitInitializationIfNeeded();
- }
-
- void CreateHighLowResAndSetAllTilesVisible() {
- // Active layer must get updated first so pending layer can share from it.
- active_layer_->CreateDefaultTilingsAndTiles();
- active_layer_->SetAllTilesVisible();
- pending_layer_->CreateDefaultTilingsAndTiles();
- pending_layer_->SetAllTilesVisible();
- }
-
- TileManager* tile_manager() { return host_impl_.tile_manager(); }
-
- protected:
- GlobalStateThatImpactsTilePriority global_state_;
-
- TestSharedBitmapManager shared_bitmap_manager_;
- TileMemoryLimitPolicy memory_limit_policy_;
- int max_tiles_;
- bool ready_to_activate_;
- int id_;
- FakeImplProxy proxy_;
- FakeLayerTreeHostImpl host_impl_;
- FakePictureLayerImpl* pending_layer_;
- FakePictureLayerImpl* active_layer_;
-};
-
-TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueue) {
- SetupDefaultTrees(gfx::Size(1000, 1000));
-
- active_layer_->CreateDefaultTilingsAndTiles();
- pending_layer_->CreateDefaultTilingsAndTiles();
-
- RasterTilePriorityQueue queue;
- host_impl_.BuildRasterQueue(&queue, SAME_PRIORITY_FOR_BOTH_TREES);
- EXPECT_FALSE(queue.IsEmpty());
-
- size_t tile_count = 0;
- std::set<Tile*> all_tiles;
- while (!queue.IsEmpty()) {
- EXPECT_TRUE(queue.Top());
- all_tiles.insert(queue.Top());
- ++tile_count;
- queue.Pop();
- }
-
- EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(16u, tile_count);
-
- // Sanity check, all tiles should be visible.
- std::set<Tile*> smoothness_tiles;
- queue.Reset();
- host_impl_.BuildRasterQueue(&queue, SMOOTHNESS_TAKES_PRIORITY);
- bool had_low_res = false;
- while (!queue.IsEmpty()) {
- Tile* tile = queue.Top();
- EXPECT_TRUE(tile);
- EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin);
- EXPECT_EQ(TilePriority::NOW, tile->priority(PENDING_TREE).priority_bin);
- if (tile->priority(ACTIVE_TREE).resolution == LOW_RESOLUTION)
- had_low_res = true;
- else
- smoothness_tiles.insert(tile);
- queue.Pop();
- }
- EXPECT_EQ(all_tiles, smoothness_tiles);
- EXPECT_TRUE(had_low_res);
-
- Region invalidation(gfx::Rect(0, 0, 500, 500));
-
- // Invalidate the pending tree.
- pending_layer_->set_invalidation(invalidation);
- pending_layer_->HighResTiling()->UpdateTilesToCurrentPile(
- invalidation, gfx::Size(1000, 1000));
- pending_layer_->LowResTiling()->UpdateTilesToCurrentPile(
- invalidation, gfx::Size(1000, 1000));
-
- active_layer_->ResetAllTilesPriorities();
- pending_layer_->ResetAllTilesPriorities();
-
- // Renew all of the tile priorities.
- gfx::Rect viewport(50, 50, 100, 100);
- pending_layer_->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- pending_layer_->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- active_layer_->HighResTiling()->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
- active_layer_->LowResTiling()->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
-
- // Populate all tiles directly from the tilings.
- all_tiles.clear();
- std::set<Tile*> high_res_tiles;
- std::vector<Tile*> pending_high_res_tiles =
- pending_layer_->HighResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < pending_high_res_tiles.size(); ++i) {
- all_tiles.insert(pending_high_res_tiles[i]);
- high_res_tiles.insert(pending_high_res_tiles[i]);
- }
-
- std::vector<Tile*> pending_low_res_tiles =
- pending_layer_->LowResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < pending_low_res_tiles.size(); ++i)
- all_tiles.insert(pending_low_res_tiles[i]);
-
- std::vector<Tile*> active_high_res_tiles =
- active_layer_->HighResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < active_high_res_tiles.size(); ++i) {
- all_tiles.insert(active_high_res_tiles[i]);
- high_res_tiles.insert(active_high_res_tiles[i]);
- }
-
- std::vector<Tile*> active_low_res_tiles =
- active_layer_->LowResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < active_low_res_tiles.size(); ++i)
- all_tiles.insert(active_low_res_tiles[i]);
-
- Tile* last_tile = NULL;
- smoothness_tiles.clear();
- tile_count = 0;
- size_t correct_order_tiles = 0u;
- // Here we expect to get increasing ACTIVE_TREE priority_bin.
- queue.Reset();
- host_impl_.BuildRasterQueue(&queue, SMOOTHNESS_TAKES_PRIORITY);
- while (!queue.IsEmpty()) {
- Tile* tile = queue.Top();
- EXPECT_TRUE(tile);
-
- if (!last_tile)
- last_tile = tile;
-
- EXPECT_LE(last_tile->priority(ACTIVE_TREE).priority_bin,
- tile->priority(ACTIVE_TREE).priority_bin);
- bool skip_updating_last_tile = false;
- if (last_tile->priority(ACTIVE_TREE).priority_bin ==
- tile->priority(ACTIVE_TREE).priority_bin) {
- correct_order_tiles +=
- last_tile->priority(ACTIVE_TREE).distance_to_visible <=
- tile->priority(ACTIVE_TREE).distance_to_visible;
- } else if (tile->priority(ACTIVE_TREE).priority_bin ==
- TilePriority::EVENTUALLY &&
- tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW) {
- // Since we'd return pending tree now tiles before the eventually tiles on
- // the active tree, update the value.
- ++correct_order_tiles;
- skip_updating_last_tile = true;
- }
-
- if (tile->priority(ACTIVE_TREE).priority_bin == TilePriority::NOW &&
- last_tile->priority(ACTIVE_TREE).resolution !=
- tile->priority(ACTIVE_TREE).resolution) {
- // Low resolution should come first.
- EXPECT_EQ(LOW_RESOLUTION, last_tile->priority(ACTIVE_TREE).resolution);
- }
-
- if (!skip_updating_last_tile)
- last_tile = tile;
- ++tile_count;
- smoothness_tiles.insert(tile);
- queue.Pop();
- }
-
- EXPECT_EQ(tile_count, smoothness_tiles.size());
- EXPECT_EQ(all_tiles, smoothness_tiles);
- // Since we don't guarantee increasing distance due to spiral iterator, we
- // should check that we're _mostly_ right.
- EXPECT_GT(correct_order_tiles, 3 * tile_count / 4);
-
- std::set<Tile*> new_content_tiles;
- last_tile = NULL;
- size_t increasing_distance_tiles = 0u;
- // Here we expect to get increasing PENDING_TREE priority_bin.
- queue.Reset();
- host_impl_.BuildRasterQueue(&queue, NEW_CONTENT_TAKES_PRIORITY);
- tile_count = 0;
- while (!queue.IsEmpty()) {
- Tile* tile = queue.Top();
- EXPECT_TRUE(tile);
-
- if (!last_tile)
- last_tile = tile;
-
- EXPECT_LE(last_tile->priority(PENDING_TREE).priority_bin,
- tile->priority(PENDING_TREE).priority_bin);
- if (last_tile->priority(PENDING_TREE).priority_bin ==
- tile->priority(PENDING_TREE).priority_bin) {
- increasing_distance_tiles +=
- last_tile->priority(PENDING_TREE).distance_to_visible <=
- tile->priority(PENDING_TREE).distance_to_visible;
- }
-
- if (tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW &&
- last_tile->priority(PENDING_TREE).resolution !=
- tile->priority(PENDING_TREE).resolution) {
- // High resolution should come first.
- EXPECT_EQ(HIGH_RESOLUTION, last_tile->priority(PENDING_TREE).resolution);
- }
-
- last_tile = tile;
- new_content_tiles.insert(tile);
- ++tile_count;
- queue.Pop();
- }
-
- EXPECT_EQ(tile_count, new_content_tiles.size());
- EXPECT_EQ(high_res_tiles, new_content_tiles);
- // Since we don't guarantee increasing distance due to spiral iterator, we
- // should check that we're _mostly_ right.
- EXPECT_GE(increasing_distance_tiles, 3 * tile_count / 4);
-}
-
-TEST_F(TileManagerTilePriorityQueueTest, ActivationComesBeforeEventually) {
- SetupDefaultTrees(gfx::Size(1000, 1000));
-
- active_layer_->CreateDefaultTilingsAndTiles();
- pending_layer_->CreateDefaultTilingsAndTiles();
-
- // Create a pending child layer.
- gfx::Size tile_size(256, 256);
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
- scoped_ptr<FakePictureLayerImpl> pending_child =
- FakePictureLayerImpl::CreateWithPile(
- host_impl_.pending_tree(), id_ + 1, pending_pile);
- pending_layer_->AddChild(pending_child.Pass());
- FakePictureLayerImpl* pending_child_raw = static_cast<FakePictureLayerImpl*>(
- host_impl_.pending_tree()->LayerById(id_ + 1));
- ASSERT_TRUE(pending_child_raw);
-
- pending_child_raw->SetDrawsContent(true);
- pending_child_raw->DoPostCommitInitializationIfNeeded();
- pending_child_raw->CreateDefaultTilingsAndTiles();
- ASSERT_TRUE(pending_child_raw->HighResTiling());
-
- // Set a small viewport, so we have soon and eventually tiles.
- gfx::Rect viewport(200, 200);
- active_layer_->draw_properties().visible_content_rect = viewport;
- active_layer_->UpdateTiles(Occlusion(), false);
- pending_layer_->draw_properties().visible_content_rect = viewport;
- pending_layer_->UpdateTiles(Occlusion(), false);
- pending_child_raw->draw_properties().visible_content_rect = viewport;
- pending_child_raw->UpdateTiles(Occlusion(), false);
-
- RasterTilePriorityQueue queue;
- host_impl_.SetRequiresHighResToDraw();
- host_impl_.BuildRasterQueue(&queue, SMOOTHNESS_TAKES_PRIORITY);
- EXPECT_FALSE(queue.IsEmpty());
-
- // Get all the tiles that are NOW or SOON and make sure they are ready to
- // draw.
- std::vector<Tile*> all_tiles;
- while (!queue.IsEmpty()) {
- Tile* tile = queue.Top();
- if (tile->combined_priority().priority_bin >= TilePriority::EVENTUALLY)
- break;
-
- all_tiles.push_back(tile);
- queue.Pop();
- }
-
- tile_manager()->InitializeTilesWithResourcesForTesting(
- std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
-
- // Ensure we can activate.
- EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
- EXPECT_TRUE(pending_child_raw->AllTilesRequiredForActivationAreReadyToDraw());
-}
-
-TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) {
- SetupDefaultTrees(gfx::Size(1000, 1000));
-
- active_layer_->CreateDefaultTilingsAndTiles();
- pending_layer_->CreateDefaultTilingsAndTiles();
-
- EvictionTilePriorityQueue empty_queue;
- host_impl_.BuildEvictionQueue(&empty_queue, SAME_PRIORITY_FOR_BOTH_TREES);
- EXPECT_TRUE(empty_queue.IsEmpty());
- std::set<Tile*> all_tiles;
- size_t tile_count = 0;
-
- RasterTilePriorityQueue raster_queue;
- host_impl_.BuildRasterQueue(&raster_queue, SAME_PRIORITY_FOR_BOTH_TREES);
- while (!raster_queue.IsEmpty()) {
- ++tile_count;
- EXPECT_TRUE(raster_queue.Top());
- all_tiles.insert(raster_queue.Top());
- raster_queue.Pop();
- }
-
- EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(16u, tile_count);
-
- tile_manager()->InitializeTilesWithResourcesForTesting(
- std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
-
- EvictionTilePriorityQueue queue;
- host_impl_.BuildEvictionQueue(&queue, SMOOTHNESS_TAKES_PRIORITY);
- EXPECT_FALSE(queue.IsEmpty());
-
- // Sanity check, all tiles should be visible.
- std::set<Tile*> smoothness_tiles;
- while (!queue.IsEmpty()) {
- Tile* tile = queue.Top();
- EXPECT_TRUE(tile);
- EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin);
- EXPECT_EQ(TilePriority::NOW, tile->priority(PENDING_TREE).priority_bin);
- EXPECT_TRUE(tile->HasResources());
- smoothness_tiles.insert(tile);
- queue.Pop();
- }
- EXPECT_EQ(all_tiles, smoothness_tiles);
-
- tile_manager()->ReleaseTileResourcesForTesting(
- std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
-
- Region invalidation(gfx::Rect(0, 0, 500, 500));
-
- // Invalidate the pending tree.
- pending_layer_->set_invalidation(invalidation);
- pending_layer_->HighResTiling()->UpdateTilesToCurrentPile(
- invalidation, gfx::Size(1000, 1000));
- pending_layer_->LowResTiling()->UpdateTilesToCurrentPile(
- invalidation, gfx::Size(1000, 1000));
-
- active_layer_->ResetAllTilesPriorities();
- pending_layer_->ResetAllTilesPriorities();
-
- // Renew all of the tile priorities.
- gfx::Rect viewport(50, 50, 100, 100);
- pending_layer_->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- pending_layer_->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- active_layer_->HighResTiling()->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
- active_layer_->LowResTiling()->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
-
- // Populate all tiles directly from the tilings.
- all_tiles.clear();
- std::vector<Tile*> pending_high_res_tiles =
- pending_layer_->HighResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < pending_high_res_tiles.size(); ++i)
- all_tiles.insert(pending_high_res_tiles[i]);
-
- std::vector<Tile*> pending_low_res_tiles =
- pending_layer_->LowResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < pending_low_res_tiles.size(); ++i)
- all_tiles.insert(pending_low_res_tiles[i]);
-
- std::vector<Tile*> active_high_res_tiles =
- active_layer_->HighResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < active_high_res_tiles.size(); ++i)
- all_tiles.insert(active_high_res_tiles[i]);
-
- std::vector<Tile*> active_low_res_tiles =
- active_layer_->LowResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < active_low_res_tiles.size(); ++i)
- all_tiles.insert(active_low_res_tiles[i]);
-
- tile_manager()->InitializeTilesWithResourcesForTesting(
- std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
-
- Tile* last_tile = NULL;
- smoothness_tiles.clear();
- tile_count = 0;
- // Here we expect to get increasing ACTIVE_TREE priority_bin.
- queue.Reset();
- host_impl_.BuildEvictionQueue(&queue, SMOOTHNESS_TAKES_PRIORITY);
- while (!queue.IsEmpty()) {
- Tile* tile = queue.Top();
- EXPECT_TRUE(tile);
- EXPECT_TRUE(tile->HasResources());
-
- if (!last_tile)
- last_tile = tile;
-
- EXPECT_GE(last_tile->priority(ACTIVE_TREE).priority_bin,
- tile->priority(ACTIVE_TREE).priority_bin);
- if (last_tile->priority(ACTIVE_TREE).priority_bin ==
- tile->priority(ACTIVE_TREE).priority_bin) {
- EXPECT_LE(last_tile->required_for_activation(),
- tile->required_for_activation());
- if (last_tile->required_for_activation() ==
- tile->required_for_activation()) {
- EXPECT_GE(last_tile->priority(ACTIVE_TREE).distance_to_visible,
- tile->priority(ACTIVE_TREE).distance_to_visible);
- }
- }
-
- last_tile = tile;
- ++tile_count;
- smoothness_tiles.insert(tile);
- queue.Pop();
- }
-
- EXPECT_EQ(tile_count, smoothness_tiles.size());
- EXPECT_EQ(all_tiles, smoothness_tiles);
-
- std::set<Tile*> new_content_tiles;
- last_tile = NULL;
- // Here we expect to get increasing PENDING_TREE priority_bin.
- queue.Reset();
- host_impl_.BuildEvictionQueue(&queue, NEW_CONTENT_TAKES_PRIORITY);
- while (!queue.IsEmpty()) {
- Tile* tile = queue.Top();
- EXPECT_TRUE(tile);
-
- if (!last_tile)
- last_tile = tile;
-
- EXPECT_GE(last_tile->priority(PENDING_TREE).priority_bin,
- tile->priority(PENDING_TREE).priority_bin);
- if (last_tile->priority(PENDING_TREE).priority_bin ==
- tile->priority(PENDING_TREE).priority_bin) {
- EXPECT_LE(last_tile->required_for_activation(),
- tile->required_for_activation());
- if (last_tile->required_for_activation() ==
- tile->required_for_activation()) {
- EXPECT_GE(last_tile->priority(PENDING_TREE).distance_to_visible,
- tile->priority(PENDING_TREE).distance_to_visible);
- }
- }
-
- last_tile = tile;
- new_content_tiles.insert(tile);
- queue.Pop();
- }
-
- EXPECT_EQ(tile_count, new_content_tiles.size());
- EXPECT_EQ(all_tiles, new_content_tiles);
-}
-
-TEST_F(TileManagerTilePriorityQueueTest,
- EvictionTilePriorityQueueWithOcclusion) {
- gfx::Size tile_size(102, 102);
- gfx::Size layer_bounds(1000, 1000);
-
- scoped_refptr<FakePicturePileImpl> pending_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SetupPendingTree(pending_pile);
- pending_layer_->CreateDefaultTilingsAndTiles();
-
- scoped_ptr<FakePictureLayerImpl> pending_child =
- FakePictureLayerImpl::CreateWithPile(
- host_impl_.pending_tree(), 2, pending_pile);
- pending_layer_->AddChild(pending_child.Pass());
-
- FakePictureLayerImpl* pending_child_layer =
- static_cast<FakePictureLayerImpl*>(pending_layer_->children()[0]);
- pending_child_layer->SetDrawsContent(true);
- pending_child_layer->DoPostCommitInitializationIfNeeded();
- pending_child_layer->CreateDefaultTilingsAndTiles();
-
- std::set<Tile*> all_tiles;
- size_t tile_count = 0;
- RasterTilePriorityQueue raster_queue;
- host_impl_.BuildRasterQueue(&raster_queue, SAME_PRIORITY_FOR_BOTH_TREES);
- while (!raster_queue.IsEmpty()) {
- ++tile_count;
- EXPECT_TRUE(raster_queue.Top());
- all_tiles.insert(raster_queue.Top());
- raster_queue.Pop();
- }
- EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(32u, tile_count);
-
- pending_layer_->ResetAllTilesPriorities();
-
- // Renew all of the tile priorities.
- gfx::Rect viewport(layer_bounds);
- pending_layer_->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- pending_layer_->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- pending_child_layer->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- pending_child_layer->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
-
- // Populate all tiles directly from the tilings.
- all_tiles.clear();
- std::vector<Tile*> pending_high_res_tiles =
- pending_layer_->HighResTiling()->AllTilesForTesting();
- all_tiles.insert(pending_high_res_tiles.begin(),
- pending_high_res_tiles.end());
-
- std::vector<Tile*> pending_low_res_tiles =
- pending_layer_->LowResTiling()->AllTilesForTesting();
- all_tiles.insert(pending_low_res_tiles.begin(), pending_low_res_tiles.end());
-
- // Set all tiles on the pending_child_layer as occluded on the pending tree.
- std::vector<Tile*> pending_child_high_res_tiles =
- pending_child_layer->HighResTiling()->AllTilesForTesting();
- pending_child_layer->HighResTiling()->SetAllTilesOccludedForTesting();
- all_tiles.insert(pending_child_high_res_tiles.begin(),
- pending_child_high_res_tiles.end());
-
- std::vector<Tile*> pending_child_low_res_tiles =
- pending_child_layer->LowResTiling()->AllTilesForTesting();
- pending_child_layer->LowResTiling()->SetAllTilesOccludedForTesting();
- all_tiles.insert(pending_child_low_res_tiles.begin(),
- pending_child_low_res_tiles.end());
-
- tile_manager()->InitializeTilesWithResourcesForTesting(
- std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
-
- // Verify occlusion is considered by EvictionTilePriorityQueue.
- TreePriority tree_priority = NEW_CONTENT_TAKES_PRIORITY;
- size_t occluded_count = 0u;
- Tile* last_tile = NULL;
- EvictionTilePriorityQueue queue;
- host_impl_.BuildEvictionQueue(&queue, tree_priority);
- while (!queue.IsEmpty()) {
- Tile* tile = queue.Top();
- if (!last_tile)
- last_tile = tile;
-
- bool tile_is_occluded = tile->is_occluded_for_tree_priority(tree_priority);
-
- // The only way we will encounter an occluded tile after an unoccluded
- // tile is if the priorty bin decreased, the tile is required for
- // activation, or the scale changed.
- if (tile_is_occluded) {
- occluded_count++;
-
- bool last_tile_is_occluded =
- last_tile->is_occluded_for_tree_priority(tree_priority);
- if (!last_tile_is_occluded) {
- TilePriority::PriorityBin tile_priority_bin =
- tile->priority_for_tree_priority(tree_priority).priority_bin;
- TilePriority::PriorityBin last_tile_priority_bin =
- last_tile->priority_for_tree_priority(tree_priority).priority_bin;
-
- EXPECT_TRUE((tile_priority_bin < last_tile_priority_bin) ||
- tile->required_for_activation() ||
- (tile->contents_scale() != last_tile->contents_scale()));
- }
- }
- last_tile = tile;
- queue.Pop();
- }
- size_t expected_occluded_count =
- pending_child_high_res_tiles.size() + pending_child_low_res_tiles.size();
- EXPECT_EQ(expected_occluded_count, occluded_count);
-}
-
-TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueEmptyLayers) {
- SetupDefaultTrees(gfx::Size(1000, 1000));
-
- active_layer_->CreateDefaultTilingsAndTiles();
- pending_layer_->CreateDefaultTilingsAndTiles();
-
- RasterTilePriorityQueue queue;
- host_impl_.BuildRasterQueue(&queue, SAME_PRIORITY_FOR_BOTH_TREES);
- EXPECT_FALSE(queue.IsEmpty());
-
- size_t tile_count = 0;
- std::set<Tile*> all_tiles;
- while (!queue.IsEmpty()) {
- EXPECT_TRUE(queue.Top());
- all_tiles.insert(queue.Top());
- ++tile_count;
- queue.Pop();
- }
-
- EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(16u, tile_count);
-
- queue.Reset();
- for (int i = 1; i < 10; ++i) {
- scoped_ptr<FakePictureLayerImpl> pending_layer =
- FakePictureLayerImpl::Create(host_impl_.pending_tree(), id_ + i);
- pending_layer->SetDrawsContent(true);
- pending_layer->DoPostCommitInitializationIfNeeded();
- pending_layer->set_has_valid_tile_priorities(true);
- pending_layer_->AddChild(pending_layer.Pass());
- }
-
- host_impl_.BuildRasterQueue(&queue, SAME_PRIORITY_FOR_BOTH_TREES);
- EXPECT_FALSE(queue.IsEmpty());
-
- tile_count = 0;
- all_tiles.clear();
- while (!queue.IsEmpty()) {
- EXPECT_TRUE(queue.Top());
- all_tiles.insert(queue.Top());
- ++tile_count;
- queue.Pop();
- }
- EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(16u, tile_count);
-}
-
-TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueueEmptyLayers) {
- SetupDefaultTrees(gfx::Size(1000, 1000));
-
- active_layer_->CreateDefaultTilingsAndTiles();
- pending_layer_->CreateDefaultTilingsAndTiles();
-
- RasterTilePriorityQueue raster_queue;
- host_impl_.BuildRasterQueue(&raster_queue, SAME_PRIORITY_FOR_BOTH_TREES);
- EXPECT_FALSE(raster_queue.IsEmpty());
-
- size_t tile_count = 0;
- std::set<Tile*> all_tiles;
- while (!raster_queue.IsEmpty()) {
- EXPECT_TRUE(raster_queue.Top());
- all_tiles.insert(raster_queue.Top());
- ++tile_count;
- raster_queue.Pop();
- }
- EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(16u, tile_count);
-
- std::vector<Tile*> tiles(all_tiles.begin(), all_tiles.end());
- host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
-
- EvictionTilePriorityQueue queue;
- for (int i = 1; i < 10; ++i) {
- scoped_ptr<FakePictureLayerImpl> pending_layer =
- FakePictureLayerImpl::Create(host_impl_.pending_tree(), id_ + i);
- pending_layer->SetDrawsContent(true);
- pending_layer->DoPostCommitInitializationIfNeeded();
- pending_layer->set_has_valid_tile_priorities(true);
- pending_layer_->AddChild(pending_layer.Pass());
- }
-
- host_impl_.BuildEvictionQueue(&queue, SAME_PRIORITY_FOR_BOTH_TREES);
- EXPECT_FALSE(queue.IsEmpty());
-
- tile_count = 0;
- all_tiles.clear();
- while (!queue.IsEmpty()) {
- EXPECT_TRUE(queue.Top());
- all_tiles.insert(queue.Top());
- ++tile_count;
- queue.Pop();
- }
- EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(16u, tile_count);
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/resources/ui_resource_request.h b/chromium/cc/resources/ui_resource_request.h
index 6d89761d44b..b89e567ce45 100644
--- a/chromium/cc/resources/ui_resource_request.h
+++ b/chromium/cc/resources/ui_resource_request.h
@@ -16,9 +16,9 @@ namespace cc {
class CC_EXPORT UIResourceRequest {
public:
enum UIResourceRequestType {
- UIResourceCreate,
- UIResourceDelete,
- UIResourceInvalidRequest
+ UI_RESOURCE_CREATE,
+ UI_RESOURCE_DELETE,
+ UI_RESOURCE_INVALID_REQUEST
};
UIResourceRequest(UIResourceRequestType type, UIResourceId id);
diff --git a/chromium/cc/resources/video_resource_updater.cc b/chromium/cc/resources/video_resource_updater.cc
index 01a6042ef3e..06fb6929c95 100644
--- a/chromium/cc/resources/video_resource_updater.cc
+++ b/chromium/cc/resources/video_resource_updater.cc
@@ -4,14 +4,17 @@
#include "cc/resources/video_resource_updater.h"
+#include <algorithm>
+
#include "base/bind.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/base/util.h"
#include "cc/output/gl_renderer.h"
#include "cc/resources/resource_provider.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "media/base/video_frame.h"
-#include "media/filters/skcanvas_video_renderer.h"
+#include "media/blink/skcanvas_video_renderer.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -20,26 +23,68 @@ namespace cc {
namespace {
-const ResourceFormat kYUVResourceFormat = LUMINANCE_8;
const ResourceFormat kRGBResourceFormat = RGBA_8888;
class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
public:
- explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
+ explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl,
+ uint32 sync_point)
+ : gl_(gl), sync_point_(sync_point) {}
~SyncPointClientImpl() override {}
uint32 InsertSyncPoint() override {
- return GLC(gl_, gl_->InsertSyncPointCHROMIUM());
+ if (sync_point_)
+ return sync_point_;
+ return gl_->InsertSyncPointCHROMIUM();
}
void WaitSyncPoint(uint32 sync_point) override {
- GLC(gl_, gl_->WaitSyncPointCHROMIUM(sync_point));
+ if (!sync_point)
+ return;
+ gl_->WaitSyncPointCHROMIUM(sync_point);
+ if (sync_point_) {
+ gl_->WaitSyncPointCHROMIUM(sync_point_);
+ sync_point_ = 0;
+ }
}
private:
gpu::gles2::GLES2Interface* gl_;
+ uint32 sync_point_;
};
} // namespace
+VideoResourceUpdater::PlaneResource::PlaneResource(
+ unsigned int resource_id,
+ const gfx::Size& resource_size,
+ ResourceFormat resource_format,
+ gpu::Mailbox mailbox)
+ : resource_id(resource_id),
+ resource_size(resource_size),
+ resource_format(resource_format),
+ mailbox(mailbox),
+ ref_count(0),
+ frame_ptr(nullptr),
+ plane_index(0) {
+}
+
+bool VideoResourceUpdater::PlaneResourceMatchesUniqueID(
+ const PlaneResource& plane_resource,
+ const media::VideoFrame* video_frame,
+ int plane_index) {
+ return plane_resource.frame_ptr == video_frame &&
+ plane_resource.plane_index == plane_index &&
+ plane_resource.timestamp == video_frame->timestamp();
+}
+
+void VideoResourceUpdater::SetPlaneResourceUniqueId(
+ const media::VideoFrame* video_frame,
+ int plane_index,
+ PlaneResource* plane_resource) {
+ plane_resource->frame_ptr = video_frame;
+ plane_resource->plane_index = plane_index;
+ plane_resource->timestamp = video_frame->timestamp();
+}
+
VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {}
VideoFrameExternalResources::~VideoFrameExternalResources() {}
@@ -51,17 +96,43 @@ VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider,
}
VideoResourceUpdater::~VideoResourceUpdater() {
- while (!all_resources_.empty()) {
- resource_provider_->DeleteResource(all_resources_.back());
- all_resources_.pop_back();
+ for (const PlaneResource& plane_resource : all_resources_)
+ resource_provider_->DeleteResource(plane_resource.resource_id);
+}
+
+VideoResourceUpdater::ResourceList::iterator
+VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size,
+ ResourceFormat format,
+ bool has_mailbox) {
+ // TODO(danakj): Abstract out hw/sw resource create/delete from
+ // ResourceProvider and stop using ResourceProvider in this class.
+ const ResourceProvider::ResourceId resource_id =
+ resource_provider_->CreateResource(
+ plane_size, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
+ if (resource_id == 0)
+ return all_resources_.end();
+
+ gpu::Mailbox mailbox;
+ if (has_mailbox) {
+ DCHECK(context_provider_);
+
+ gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+
+ gl->GenMailboxCHROMIUM(mailbox.name);
+ ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id);
+ gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D,
+ mailbox.name);
}
+ all_resources_.push_front(
+ PlaneResource(resource_id, plane_size, format, mailbox));
+ return all_resources_.begin();
}
-void VideoResourceUpdater::DeleteResource(unsigned resource_id) {
- resource_provider_->DeleteResource(resource_id);
- all_resources_.erase(std::remove(all_resources_.begin(),
- all_resources_.end(),
- resource_id));
+void VideoResourceUpdater::DeleteResource(ResourceList::iterator resource_it) {
+ DCHECK_EQ(resource_it->ref_count, 0);
+ resource_provider_->DeleteResource(resource_it->resource_id);
+ all_resources_.erase(resource_it);
}
VideoFrameExternalResources VideoResourceUpdater::
@@ -85,11 +156,13 @@ bool VideoResourceUpdater::VerifyFrame(
case media::VideoFrame::YV12A:
case media::VideoFrame::YV16:
case media::VideoFrame::YV12J:
+ case media::VideoFrame::YV12HD:
case media::VideoFrame::YV24:
case media::VideoFrame::NATIVE_TEXTURE:
#if defined(VIDEO_HOLE)
case media::VideoFrame::HOLE:
#endif // defined(VIDEO_HOLE)
+ case media::VideoFrame::ARGB:
return true;
// Unacceptable inputs. ¯\(°_o)/¯
@@ -104,14 +177,12 @@ bool VideoResourceUpdater::VerifyFrame(
// each plane in the frame.
static gfx::Size SoftwarePlaneDimension(
const scoped_refptr<media::VideoFrame>& input_frame,
- ResourceFormat output_resource_format,
+ bool software_compositor,
size_t plane_index) {
- if (output_resource_format == kYUVResourceFormat) {
+ if (!software_compositor) {
return media::VideoFrame::PlaneSize(
input_frame->format(), plane_index, input_frame->coded_size());
}
-
- DCHECK_EQ(output_resource_format, kRGBResourceFormat);
return input_frame->coded_size();
}
@@ -129,23 +200,21 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
#endif // defined(VIDEO_HOLE)
// Only YUV software video frames are supported.
- DCHECK(input_frame_format == media::VideoFrame::YV12 ||
- input_frame_format == media::VideoFrame::I420 ||
- input_frame_format == media::VideoFrame::YV12A ||
- input_frame_format == media::VideoFrame::YV12J ||
- input_frame_format == media::VideoFrame::YV16 ||
- input_frame_format == media::VideoFrame::YV24);
if (input_frame_format != media::VideoFrame::YV12 &&
input_frame_format != media::VideoFrame::I420 &&
input_frame_format != media::VideoFrame::YV12A &&
input_frame_format != media::VideoFrame::YV12J &&
+ input_frame_format != media::VideoFrame::YV12HD &&
input_frame_format != media::VideoFrame::YV16 &&
- input_frame_format != media::VideoFrame::YV24)
+ input_frame_format != media::VideoFrame::YV24) {
+ NOTREACHED() << input_frame_format;
return VideoFrameExternalResources();
+ }
bool software_compositor = context_provider_ == NULL;
- ResourceFormat output_resource_format = kYUVResourceFormat;
+ ResourceFormat output_resource_format =
+ resource_provider_->yuv_resource_format();
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
@@ -157,82 +226,69 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
output_plane_count = 1;
}
- int max_resource_size = resource_provider_->max_texture_size();
- std::vector<PlaneResource> plane_resources;
- bool allocation_success = true;
+ // Drop recycled resources that are the wrong format.
+ for (auto it = all_resources_.begin(); it != all_resources_.end();) {
+ if (it->ref_count == 0 && it->resource_format != output_resource_format)
+ DeleteResource(it++);
+ else
+ ++it;
+ }
+ 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, output_resource_format, i);
+ SoftwarePlaneDimension(video_frame, 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) {
- allocation_success = false;
break;
}
- ResourceProvider::ResourceId resource_id = 0;
- gpu::Mailbox mailbox;
-
// Try recycle a previously-allocated resource.
- for (size_t i = 0; i < recycled_resources_.size(); ++i) {
- bool resource_matches =
- recycled_resources_[i].resource_format == output_resource_format &&
- recycled_resources_[i].resource_size == output_plane_resource_size;
- bool not_in_use =
- !software_compositor || !resource_provider_->InUseByConsumer(
- recycled_resources_[i].resource_id);
- if (resource_matches && not_in_use) {
- resource_id = recycled_resources_[i].resource_id;
- mailbox = recycled_resources_[i].mailbox;
- recycled_resources_.erase(recycled_resources_.begin() + i);
- break;
+ ResourceList::iterator resource_it = all_resources_.end();
+ for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) {
+ if (it->resource_size == output_plane_resource_size &&
+ it->resource_format == output_resource_format) {
+ if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i)) {
+ // Bingo, we found a resource that already contains the data we are
+ // planning to put in it. It's safe to reuse it even if
+ // resource_provider_ holds some references to it, because those
+ // references are read-only.
+ resource_it = it;
+ break;
+ }
+
+ // This extra check is needed because resources backed by SharedMemory
+ // are not ref-counted, unlike mailboxes. Full discussion in
+ // codereview.chromium.org/145273021.
+ const bool in_use =
+ software_compositor &&
+ resource_provider_->InUseByConsumer(it->resource_id);
+ if (it->ref_count == 0 && !in_use) {
+ // We found a resource with the correct size that we can overwrite.
+ resource_it = it;
+ }
}
}
- if (resource_id == 0) {
- // TODO(danakj): Abstract out hw/sw resource create/delete from
- // ResourceProvider and stop using ResourceProvider in this class.
- resource_id = resource_provider_->CreateResource(
- output_plane_resource_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- output_resource_format);
-
- DCHECK(mailbox.IsZero());
-
- if (!software_compositor) {
- DCHECK(context_provider_);
-
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
-
- GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
- ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
- resource_id);
- GLC(gl,
- gl->ProduceTextureDirectCHROMIUM(
- lock.texture_id(), GL_TEXTURE_2D, mailbox.name));
- }
-
- if (resource_id)
- all_resources_.push_back(resource_id);
+ // Check if we need to allocate a new resource.
+ if (resource_it == all_resources_.end()) {
+ resource_it =
+ AllocateResource(output_plane_resource_size, output_resource_format,
+ !software_compositor);
}
-
- if (resource_id == 0) {
- allocation_success = false;
+ if (resource_it == all_resources_.end())
break;
- }
- DCHECK(software_compositor || !mailbox.IsZero());
- plane_resources.push_back(PlaneResource(resource_id,
- output_plane_resource_size,
- output_resource_format,
- mailbox));
+ ++resource_it->ref_count;
+ plane_resources.push_back(resource_it);
}
- if (!allocation_success) {
- for (size_t i = 0; i < plane_resources.size(); ++i)
- DeleteResource(plane_resources[i].resource_id);
+ if (plane_resources.size() != output_plane_count) {
+ // Allocation failed, nothing will be returned so restore reference counts.
+ for (ResourceList::iterator resource_it : plane_resources)
+ --resource_it->ref_count;
return VideoFrameExternalResources();
}
@@ -240,61 +296,81 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
if (software_compositor) {
DCHECK_EQ(plane_resources.size(), 1u);
- DCHECK_EQ(plane_resources[0].resource_format, kRGBResourceFormat);
- DCHECK(plane_resources[0].mailbox.IsZero());
+ PlaneResource& plane_resource = *plane_resources[0];
+ DCHECK_EQ(plane_resource.resource_format, kRGBResourceFormat);
+ DCHECK(plane_resource.mailbox.IsZero());
- if (!video_renderer_)
- video_renderer_.reset(new media::SkCanvasVideoRenderer);
+ if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), 0)) {
+ // We need to transfer data from |video_frame| to the plane resource.
+ if (!video_renderer_)
+ video_renderer_.reset(new media::SkCanvasVideoRenderer);
- {
ResourceProvider::ScopedWriteLockSoftware lock(
- resource_provider_, plane_resources[0].resource_id);
- video_renderer_->Copy(video_frame, lock.sk_canvas());
+ resource_provider_, plane_resource.resource_id);
+ SkCanvas 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());
+ SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resource);
}
- RecycleResourceData recycle_data = {
- plane_resources[0].resource_id,
- plane_resources[0].resource_size,
- plane_resources[0].resource_format,
- gpu::Mailbox()
- };
- external_resources.software_resources.push_back(
- plane_resources[0].resource_id);
+ external_resources.software_resources.push_back(plane_resource.resource_id);
external_resources.software_release_callback =
- base::Bind(&RecycleResource, AsWeakPtr(), recycle_data);
+ base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id);
external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
-
return external_resources;
}
for (size_t i = 0; i < plane_resources.size(); ++i) {
+ PlaneResource& plane_resource = *plane_resources[i];
// Update each plane's resource id with its content.
- DCHECK_EQ(plane_resources[i].resource_format, kYUVResourceFormat);
-
- const uint8_t* input_plane_pixels = video_frame->data(i);
-
- gfx::Rect image_rect(0,
- 0,
- video_frame->stride(i),
- plane_resources[i].resource_size.height());
- gfx::Rect source_rect(plane_resources[i].resource_size);
- resource_provider_->SetPixels(plane_resources[i].resource_id,
- input_plane_pixels,
- image_rect,
- source_rect,
- gfx::Vector2d());
-
- RecycleResourceData recycle_data = {
- plane_resources[i].resource_id,
- plane_resources[i].resource_size,
- plane_resources[i].resource_format,
- plane_resources[i].mailbox
- };
+ DCHECK_EQ(plane_resource.resource_format,
+ resource_provider_->yuv_resource_format());
+
+ if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), i)) {
+ // We need to transfer data from |video_frame| to the plane resource.
+ // TODO(reveman): Can use GpuMemoryBuffers here to improve performance.
+
+ // The |resource_size_pixels| is the size of the resource we want to
+ // upload to.
+ gfx::Size resource_size_pixels = plane_resource.resource_size;
+ // The |video_stride_pixels| is the width of the video frame we are
+ // uploading (including non-frame data to fill in the stride).
+ size_t video_stride_pixels = video_frame->stride(i);
+
+ size_t bytes_per_pixel = BitsPerPixel(plane_resource.resource_format) / 8;
+ // Use 4-byte row alignment (OpenGL default) for upload performance.
+ // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
+ size_t upload_image_stride =
+ RoundUp<size_t>(bytes_per_pixel * resource_size_pixels.width(), 4u);
+
+ const uint8_t* pixels;
+ if (upload_image_stride == video_stride_pixels * bytes_per_pixel) {
+ pixels = video_frame->data(i);
+ } else {
+ // Avoid malloc for each frame/plane if possible.
+ size_t needed_size =
+ upload_image_stride * resource_size_pixels.height();
+ if (upload_pixels_.size() < needed_size)
+ upload_pixels_.resize(needed_size);
+ for (int row = 0; row < resource_size_pixels.height(); ++row) {
+ uint8_t* dst = &upload_pixels_[upload_image_stride * row];
+ const uint8_t* src = video_frame->data(i) +
+ bytes_per_pixel * video_stride_pixels * row;
+ memcpy(dst, src, resource_size_pixels.width() * bytes_per_pixel);
+ }
+ pixels = &upload_pixels_[0];
+ }
+
+ resource_provider_->CopyToResource(plane_resource.resource_id, pixels,
+ resource_size_pixels);
+ SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resource);
+ }
external_resources.mailboxes.push_back(
- TextureMailbox(plane_resources[i].mailbox, GL_TEXTURE_2D, 0));
+ TextureMailbox(plane_resource.mailbox, GL_TEXTURE_2D, 0));
external_resources.release_callbacks.push_back(
- base::Bind(&RecycleResource, AsWeakPtr(), recycle_data));
+ base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id));
}
external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
@@ -312,10 +388,11 @@ void VideoResourceUpdater::ReturnTexture(
// resource.
if (lost_resource || !updater.get())
return;
- // VideoFrame::UpdateReleaseSyncPoint() creates new sync point using the same
- // GL context which created the given |sync_point|, so discard the
- // |sync_point|.
- SyncPointClientImpl client(updater->context_provider_->ContextGL());
+ // Update the release sync point in |video_frame| with |sync_point|
+ // returned by the compositor and emit a WaitSyncPointCHROMIUM on
+ // |video_frame|'s previous sync point using the current GL context.
+ SyncPointClientImpl client(updater->context_provider_->ContextGL(),
+ sync_point);
video_frame->UpdateReleaseSyncPoint(&client);
}
@@ -325,43 +402,60 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
media::VideoFrame::Format frame_format = video_frame->format();
DCHECK_EQ(frame_format, media::VideoFrame::NATIVE_TEXTURE);
- if (frame_format != media::VideoFrame::NATIVE_TEXTURE)
- return VideoFrameExternalResources();
-
if (!context_provider_)
return VideoFrameExternalResources();
- const gpu::MailboxHolder* mailbox_holder = video_frame->mailbox_holder();
+ size_t textures =
+ media::VideoFrame::NumTextures(video_frame->texture_format());
+ DCHECK_GE(textures, 1u);
VideoFrameExternalResources external_resources;
- switch (mailbox_holder->texture_target) {
- case GL_TEXTURE_2D:
- external_resources.type = VideoFrameExternalResources::RGB_RESOURCE;
- break;
- case GL_TEXTURE_EXTERNAL_OES:
- external_resources.type =
- VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
+ switch (video_frame->texture_format()) {
+ case media::VideoFrame::TEXTURE_RGBA:
+ case media::VideoFrame::TEXTURE_RGB:
+ DCHECK_EQ(1u, textures);
+ switch (video_frame->mailbox_holder(0).texture_target) {
+ case GL_TEXTURE_2D:
+ if (video_frame->texture_format() == media::VideoFrame::TEXTURE_RGB)
+ external_resources.type = VideoFrameExternalResources::RGB_RESOURCE;
+ else
+ external_resources.type =
+ VideoFrameExternalResources::RGBA_RESOURCE;
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ external_resources.type =
+ VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ external_resources.type = VideoFrameExternalResources::IO_SURFACE;
+ break;
+ default:
+ NOTREACHED();
+ return VideoFrameExternalResources();
+ }
break;
- case GL_TEXTURE_RECTANGLE_ARB:
- external_resources.type = VideoFrameExternalResources::IO_SURFACE;
+ case media::VideoFrame::TEXTURE_YUV_420:
+ external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
break;
- default:
- NOTREACHED();
- return VideoFrameExternalResources();
}
+ DCHECK_NE(VideoFrameExternalResources::NONE, external_resources.type);
- external_resources.mailboxes.push_back(
- TextureMailbox(mailbox_holder->mailbox,
- mailbox_holder->texture_target,
- mailbox_holder->sync_point));
- external_resources.release_callbacks.push_back(
- base::Bind(&ReturnTexture, AsWeakPtr(), video_frame));
+ for (size_t i = 0; i < textures; ++i) {
+ const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i);
+ external_resources.mailboxes.push_back(
+ TextureMailbox(mailbox_holder.mailbox, mailbox_holder.texture_target,
+ mailbox_holder.sync_point));
+ external_resources.mailboxes.back().set_allow_overlay(
+ video_frame->allow_overlay());
+ external_resources.release_callbacks.push_back(
+ base::Bind(&ReturnTexture, AsWeakPtr(), video_frame));
+ }
return external_resources;
}
// static
void VideoResourceUpdater::RecycleResource(
base::WeakPtr<VideoResourceUpdater> updater,
- RecycleResourceData data,
+ ResourceProvider::ResourceId resource_id,
uint32 sync_point,
bool lost_resource,
BlockingTaskRunner* main_thread_task_runner) {
@@ -370,30 +464,27 @@ void VideoResourceUpdater::RecycleResource(
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())
+ return;
+
ContextProvider* context_provider = updater->context_provider_;
if (context_provider && sync_point) {
- GLC(context_provider->ContextGL(),
- context_provider->ContextGL()->WaitSyncPointCHROMIUM(sync_point));
+ context_provider->ContextGL()->WaitSyncPointCHROMIUM(sync_point);
}
if (lost_resource) {
- updater->DeleteResource(data.resource_id);
+ resource_it->ref_count = 0;
+ updater->DeleteResource(resource_it);
return;
}
- // Drop recycled resources that are the wrong format.
- while (!updater->recycled_resources_.empty() &&
- updater->recycled_resources_.back().resource_format !=
- data.resource_format) {
- updater->DeleteResource(updater->recycled_resources_.back().resource_id);
- updater->recycled_resources_.pop_back();
- }
-
- PlaneResource recycled_resource(data.resource_id,
- data.resource_size,
- data.resource_format,
- data.mailbox);
- updater->recycled_resources_.push_back(recycled_resource);
+ --resource_it->ref_count;
+ DCHECK_GE(resource_it->ref_count, 0);
}
} // namespace cc
diff --git a/chromium/cc/resources/video_resource_updater.h b/chromium/cc/resources/video_resource_updater.h
index 99800b4c878..13f81b8f06e 100644
--- a/chromium/cc/resources/video_resource_updater.h
+++ b/chromium/cc/resources/video_resource_updater.h
@@ -5,11 +5,13 @@
#ifndef CC_RESOURCES_VIDEO_RESOURCE_UPDATER_H_
#define CC_RESOURCES_VIDEO_RESOURCE_UPDATER_H_
+#include <list>
#include <vector>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/resources/release_callback_impl.h"
#include "cc/resources/resource_format.h"
@@ -33,6 +35,7 @@ class CC_EXPORT VideoFrameExternalResources {
NONE,
YUV_RESOURCE,
RGB_RESOURCE,
+ RGBA_RESOURCE,
STREAM_TEXTURE_RESOURCE,
IO_SURFACE,
@@ -59,13 +62,13 @@ class CC_EXPORT VideoFrameExternalResources {
~VideoFrameExternalResources();
};
-// VideoResourceUpdater is by the video system to produce frame content as
+// VideoResourceUpdater is used by the video system to produce frame content as
// resources consumable by the compositor.
class CC_EXPORT VideoResourceUpdater
: public base::SupportsWeakPtr<VideoResourceUpdater> {
public:
- explicit VideoResourceUpdater(ContextProvider* context_provider,
- ResourceProvider* resource_provider);
+ VideoResourceUpdater(ContextProvider* context_provider,
+ ResourceProvider* resource_provider);
~VideoResourceUpdater();
VideoFrameExternalResources CreateExternalResourcesFromVideoFrame(
@@ -77,32 +80,46 @@ class CC_EXPORT VideoResourceUpdater
gfx::Size resource_size;
ResourceFormat resource_format;
gpu::Mailbox mailbox;
+ // The balance between the number of times this resource has been returned
+ // from CreateForSoftwarePlanes vs released in RecycleResource.
+ int ref_count;
+ // These last three members will be used for identifying the data stored in
+ // this resource, and uniquely identifies a media::VideoFrame plane. The
+ // frame pointer will only be used for pointer comparison, i.e. the
+ // underlying data will not be accessed.
+ const void* frame_ptr;
+ int plane_index;
+ base::TimeDelta timestamp;
PlaneResource(unsigned resource_id,
const gfx::Size& resource_size,
ResourceFormat resource_format,
- gpu::Mailbox mailbox)
- : resource_id(resource_id),
- resource_size(resource_size),
- resource_format(resource_format),
- mailbox(mailbox) {}
+ gpu::Mailbox mailbox);
};
- void DeleteResource(unsigned resource_id);
+ static bool PlaneResourceMatchesUniqueID(const PlaneResource& plane_resource,
+ const media::VideoFrame* video_frame,
+ int plane_index);
+
+ static void SetPlaneResourceUniqueId(const media::VideoFrame* video_frame,
+ int plane_index,
+ PlaneResource* plane_resource);
+
+ // This needs to be a container where iterators can be erased without
+ // invalidating other iterators.
+ typedef std::list<PlaneResource> ResourceList;
+ ResourceList::iterator AllocateResource(const gfx::Size& plane_size,
+ ResourceFormat format,
+ bool has_mailbox);
+ void DeleteResource(ResourceList::iterator resource_it);
bool VerifyFrame(const scoped_refptr<media::VideoFrame>& video_frame);
VideoFrameExternalResources CreateForHardwarePlanes(
const scoped_refptr<media::VideoFrame>& video_frame);
VideoFrameExternalResources CreateForSoftwarePlanes(
const scoped_refptr<media::VideoFrame>& video_frame);
- struct RecycleResourceData {
- unsigned resource_id;
- gfx::Size resource_size;
- ResourceFormat resource_format;
- gpu::Mailbox mailbox;
- };
static void RecycleResource(base::WeakPtr<VideoResourceUpdater> updater,
- RecycleResourceData data,
+ unsigned resource_id,
uint32 sync_point,
bool lost_resource,
BlockingTaskRunner* main_thread_task_runner);
@@ -115,9 +132,11 @@ class CC_EXPORT VideoResourceUpdater
ContextProvider* context_provider_;
ResourceProvider* resource_provider_;
scoped_ptr<media::SkCanvasVideoRenderer> video_renderer_;
+ std::vector<uint8_t> upload_pixels_;
- std::vector<unsigned> all_resources_;
- std::vector<PlaneResource> recycled_resources_;
+ // Recycle resources so that we can reduce the number of allocations and
+ // data transfers.
+ ResourceList all_resources_;
DISALLOW_COPY_AND_ASSIGN(VideoResourceUpdater);
};
diff --git a/chromium/cc/resources/video_resource_updater_unittest.cc b/chromium/cc/resources/video_resource_updater_unittest.cc
index c0a4af402c4..10f7fbdbbcf 100644
--- a/chromium/cc/resources/video_resource_updater_unittest.cc
+++ b/chromium/cc/resources/video_resource_updater_unittest.cc
@@ -11,23 +11,66 @@
#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/blocking_task_runner.h"
+#include "gpu/GLES2/gl2extchromium.h"
#include "media/base/video_frame.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
+class WebGraphicsContext3DUploadCounter : public TestWebGraphicsContext3D {
+ public:
+ void texSubImage2D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void* pixels) override {
+ ++upload_count_;
+ }
+
+ int UploadCount() { return upload_count_; }
+ void ResetUploadCount() { upload_count_ = 0; }
+
+ private:
+ int upload_count_;
+};
+
+class SharedBitmapManagerAllocationCounter : public TestSharedBitmapManager {
+ public:
+ scoped_ptr<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() {
- scoped_ptr<TestWebGraphicsContext3D> context3d =
- TestWebGraphicsContext3D::Create();
+ scoped_ptr<WebGraphicsContext3DUploadCounter> context3d(
+ new WebGraphicsContext3DUploadCounter());
+
context3d_ = context3d.get();
output_surface3d_ =
FakeOutputSurface::Create3d(context3d.Pass());
CHECK(output_surface3d_->BindToClient(&client_));
- shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+
+ output_surface_software_ = FakeOutputSurface::CreateSoftware(
+ make_scoped_ptr(new SoftwareOutputDevice));
+ CHECK(output_surface_software_->BindToClient(&client_));
+
+ shared_bitmap_manager_.reset(new SharedBitmapManagerAllocationCounter());
resource_provider3d_ =
ResourceProvider::Create(output_surface3d_.get(),
shared_bitmap_manager_.get(),
@@ -36,6 +79,10 @@ class VideoResourceUpdaterTest : public testing::Test {
0,
false,
1);
+
+ resource_provider_software_ = ResourceProvider::Create(
+ output_surface_software_.get(), shared_bitmap_manager_.get(), NULL,
+ NULL, 0, false, 1);
}
scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() {
@@ -60,11 +107,61 @@ class VideoResourceUpdaterTest : public testing::Test {
base::Closure()); // no_longer_needed_cb
}
- TestWebGraphicsContext3D* context3d_;
+ static void ReleaseMailboxCB(unsigned sync_point) {}
+
+ scoped_refptr<media::VideoFrame> CreateTestRGBAHardwareVideoFrame() {
+ const int kDimension = 10;
+ gfx::Size size(kDimension, kDimension);
+
+ gpu::Mailbox mailbox;
+ mailbox.name[0] = 51;
+
+ const unsigned sync_point = 7;
+ const unsigned target = GL_TEXTURE_2D;
+ return media::VideoFrame::WrapNativeTexture(
+ gpu::MailboxHolder(mailbox, target, sync_point),
+ base::Bind(&ReleaseMailboxCB),
+ size, // coded_size
+ gfx::Rect(size), // visible_rect
+ size, // natural_size
+ base::TimeDelta(), // timestamp
+ false, // allow_overlay
+ true); // has_alpha
+ }
+
+ scoped_refptr<media::VideoFrame> CreateTestYUVHardareVideoFrame() {
+ const int kDimension = 10;
+ gfx::Size size(kDimension, kDimension);
+
+ const int kPlanesNum = 3;
+ gpu::Mailbox mailbox[kPlanesNum];
+ for (int i = 0; i < kPlanesNum; ++i) {
+ mailbox[i].name[0] = 50 + 1;
+ }
+ const unsigned sync_point = 7;
+ const unsigned target = GL_TEXTURE_RECTANGLE_ARB;
+ return media::VideoFrame::WrapYUV420NativeTextures(
+ gpu::MailboxHolder(mailbox[media::VideoFrame::kYPlane], target,
+ sync_point),
+ gpu::MailboxHolder(mailbox[media::VideoFrame::kUPlane], target,
+ sync_point),
+ gpu::MailboxHolder(mailbox[media::VideoFrame::kVPlane], target,
+ sync_point),
+ base::Bind(&ReleaseMailboxCB),
+ size, // coded_size
+ gfx::Rect(size), // visible_rect
+ size, // natural_size
+ base::TimeDelta(), // timestamp
+ false); // allow_overlay
+ }
+
+ WebGraphicsContext3DUploadCounter* context3d_;
FakeOutputSurfaceClient client_;
scoped_ptr<FakeOutputSurface> output_surface3d_;
- scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<FakeOutputSurface> output_surface_software_;
+ scoped_ptr<SharedBitmapManagerAllocationCounter> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider3d_;
+ scoped_ptr<ResourceProvider> resource_provider_software_;
};
TEST_F(VideoResourceUpdaterTest, SoftwareFrame) {
@@ -77,5 +174,153 @@ TEST_F(VideoResourceUpdaterTest, SoftwareFrame) {
EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
}
+TEST_F(VideoResourceUpdaterTest, ReuseResource) {
+ VideoResourceUpdater updater(output_surface3d_->context_provider(),
+ resource_provider3d_.get());
+ 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);
+ EXPECT_EQ(size_t(3), resources.mailboxes.size());
+ EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(0), resources.software_resources.size());
+ // Expect exactly three texture uploads, one for each plane.
+ EXPECT_EQ(3, context3d_->UploadCount());
+
+ // Simulate the ResourceProvider releasing the resources back to the video
+ // updater.
+ for (ReleaseCallbackImpl& release_callback : resources.release_callbacks)
+ release_callback.Run(0, false, nullptr);
+
+ // Allocate resources for the same frame.
+ context3d_->ResetUploadCount();
+ resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ EXPECT_EQ(size_t(3), resources.mailboxes.size());
+ EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+ // The data should be reused so expect no texture uploads.
+ EXPECT_EQ(0, context3d_->UploadCount());
+}
+
+TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDelete) {
+ VideoResourceUpdater updater(output_surface3d_->context_provider(),
+ resource_provider3d_.get());
+ 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);
+ EXPECT_EQ(size_t(3), resources.mailboxes.size());
+ EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(0), resources.software_resources.size());
+ // 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);
+ EXPECT_EQ(size_t(3), resources.mailboxes.size());
+ EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+ // The data should be reused so expect no texture uploads.
+ EXPECT_EQ(0, context3d_->UploadCount());
+}
+
+TEST_F(VideoResourceUpdaterTest, SoftwareFrameSoftwareCompositor) {
+ VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
+ scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
+
+ VideoFrameExternalResources resources =
+ updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+}
+
+TEST_F(VideoResourceUpdaterTest, ReuseResourceSoftwareCompositor) {
+ VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
+ 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(size_t(0), resources.mailboxes.size());
+ EXPECT_EQ(size_t(0), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(1), resources.software_resources.size());
+ // Expect exactly one allocated shared bitmap.
+ EXPECT_EQ(1, shared_bitmap_manager_->AllocationCount());
+
+ // Simulate the ResourceProvider releasing the resource back to the video
+ // updater.
+ resources.software_release_callback.Run(0, false, nullptr);
+
+ // Allocate resources for the same frame.
+ shared_bitmap_manager_->ResetAllocationCount();
+ resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+ EXPECT_EQ(size_t(0), resources.mailboxes.size());
+ EXPECT_EQ(size_t(0), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(1), resources.software_resources.size());
+ // The data should be reused so expect no new allocations.
+ EXPECT_EQ(0, shared_bitmap_manager_->AllocationCount());
+}
+
+TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDeleteSoftwareCompositor) {
+ VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
+ 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(size_t(0), resources.mailboxes.size());
+ EXPECT_EQ(size_t(0), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(1), resources.software_resources.size());
+ // Expect exactly one allocated shared bitmap.
+ EXPECT_EQ(1, shared_bitmap_manager_->AllocationCount());
+
+ // Allocate resources for the same frame.
+ shared_bitmap_manager_->ResetAllocationCount();
+ resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+ EXPECT_EQ(size_t(0), resources.mailboxes.size());
+ EXPECT_EQ(size_t(0), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(1), resources.software_resources.size());
+ // The data should be reused so expect no new allocations.
+ EXPECT_EQ(0, shared_bitmap_manager_->AllocationCount());
+}
+
+TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes) {
+ VideoResourceUpdater updater(output_surface3d_->context_provider(),
+ resource_provider3d_.get());
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ CreateTestRGBAHardwareVideoFrame();
+
+ VideoFrameExternalResources resources =
+ updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::RGBA_RESOURCE, resources.type);
+ EXPECT_EQ(1u, resources.mailboxes.size());
+ EXPECT_EQ(1u, resources.release_callbacks.size());
+ EXPECT_EQ(0u, resources.software_resources.size());
+
+ video_frame = CreateTestYUVHardareVideoFrame();
+
+ resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ EXPECT_EQ(3u, resources.mailboxes.size());
+ EXPECT_EQ(3u, resources.release_callbacks.size());
+ EXPECT_EQ(0u, resources.software_resources.size());
+}
} // namespace
} // namespace cc
diff --git a/chromium/cc/resources/zero_copy_raster_worker_pool.cc b/chromium/cc/resources/zero_copy_raster_worker_pool.cc
deleted file mode 100644
index ca2bc9b01e1..00000000000
--- a/chromium/cc/resources/zero_copy_raster_worker_pool.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/zero_copy_raster_worker_pool.h"
-
-#include <algorithm>
-
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
-#include "base/strings/stringprintf.h"
-#include "cc/debug/traced_value.h"
-#include "cc/resources/raster_buffer.h"
-#include "cc/resources/resource.h"
-#include "ui/gfx/gpu_memory_buffer.h"
-
-namespace cc {
-namespace {
-
-class RasterBufferImpl : public RasterBuffer {
- public:
- RasterBufferImpl(ResourceProvider* resource_provider,
- const Resource* resource)
- : lock_(resource_provider, resource->id()), resource_(resource) {}
-
- // Overridden from RasterBuffer:
- void Playback(const RasterSource* raster_source,
- const gfx::Rect& rect,
- float scale) override {
- gfx::GpuMemoryBuffer* gpu_memory_buffer = lock_.GetGpuMemoryBuffer();
- if (!gpu_memory_buffer)
- return;
-
- RasterWorkerPool::PlaybackToMemory(
- gpu_memory_buffer->Map(), resource_->format(), resource_->size(),
- gpu_memory_buffer->GetStride(), raster_source, rect, scale);
- gpu_memory_buffer->Unmap();
- }
-
- private:
- ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock_;
- const Resource* resource_;
-
- DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
-};
-
-} // namespace
-
-// static
-scoped_ptr<RasterWorkerPool> ZeroCopyRasterWorkerPool::Create(
- base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ResourceProvider* resource_provider) {
- return make_scoped_ptr<RasterWorkerPool>(new ZeroCopyRasterWorkerPool(
- task_runner, task_graph_runner, resource_provider));
-}
-
-ZeroCopyRasterWorkerPool::ZeroCopyRasterWorkerPool(
- base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ResourceProvider* resource_provider)
- : task_runner_(task_runner),
- task_graph_runner_(task_graph_runner),
- namespace_token_(task_graph_runner->GetNamespaceToken()),
- resource_provider_(resource_provider),
- raster_finished_weak_ptr_factory_(this) {
-}
-
-ZeroCopyRasterWorkerPool::~ZeroCopyRasterWorkerPool() {
-}
-
-Rasterizer* ZeroCopyRasterWorkerPool::AsRasterizer() {
- return this;
-}
-
-void ZeroCopyRasterWorkerPool::SetClient(RasterizerClient* client) {
- client_ = client;
-}
-
-void ZeroCopyRasterWorkerPool::Shutdown() {
- TRACE_EVENT0("cc", "ZeroCopyRasterWorkerPool::Shutdown");
-
- TaskGraph empty;
- task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
- task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
-}
-
-void ZeroCopyRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
- TRACE_EVENT0("cc", "ZeroCopyRasterWorkerPool::ScheduleTasks");
-
- if (raster_pending_.none())
- TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
-
- // Mark all task sets as pending.
- raster_pending_.set();
-
- unsigned priority = kRasterTaskPriorityBase;
-
- graph_.Reset();
-
- // Cancel existing OnRasterFinished callbacks.
- raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
-
- scoped_refptr<RasterizerTask> new_raster_finished_tasks[kNumberOfTaskSets];
-
- size_t task_count[kNumberOfTaskSets] = {0};
-
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- new_raster_finished_tasks[task_set] = CreateRasterFinishedTask(
- task_runner_.get(),
- base::Bind(&ZeroCopyRasterWorkerPool::OnRasterFinished,
- raster_finished_weak_ptr_factory_.GetWeakPtr(),
- task_set));
- }
-
- for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
- it != queue->items.end();
- ++it) {
- const RasterTaskQueue::Item& item = *it;
- RasterTask* task = item.task;
- DCHECK(!task->HasCompleted());
-
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- if (!item.task_sets[task_set])
- continue;
-
- ++task_count[task_set];
-
- graph_.edges.push_back(
- TaskGraph::Edge(task, new_raster_finished_tasks[task_set].get()));
- }
-
- InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
- }
-
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) {
- InsertNodeForTask(&graph_,
- new_raster_finished_tasks[task_set].get(),
- kRasterFinishedTaskPriority,
- task_count[task_set]);
- }
-
- ScheduleTasksOnOriginThread(this, &graph_);
- task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
-
- std::copy(new_raster_finished_tasks,
- new_raster_finished_tasks + kNumberOfTaskSets,
- raster_finished_tasks_);
-
- TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue());
-}
-
-void ZeroCopyRasterWorkerPool::CheckForCompletedTasks() {
- TRACE_EVENT0("cc", "ZeroCopyRasterWorkerPool::CheckForCompletedTasks");
-
- task_graph_runner_->CollectCompletedTasks(namespace_token_,
- &completed_tasks_);
- for (Task::Vector::const_iterator it = completed_tasks_.begin();
- it != completed_tasks_.end();
- ++it) {
- RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
-
- task->WillComplete();
- task->CompleteOnOriginThread(this);
- task->DidComplete();
-
- task->RunReplyOnOriginThread();
- }
- completed_tasks_.clear();
-}
-
-scoped_ptr<RasterBuffer> ZeroCopyRasterWorkerPool::AcquireBufferForRaster(
- const Resource* resource) {
- return make_scoped_ptr<RasterBuffer>(
- new RasterBufferImpl(resource_provider_, resource));
-}
-
-void ZeroCopyRasterWorkerPool::ReleaseBufferForRaster(
- scoped_ptr<RasterBuffer> buffer) {
- // Nothing to do here. RasterBufferImpl destructor cleans up after itself.
-}
-
-void ZeroCopyRasterWorkerPool::OnRasterFinished(TaskSet task_set) {
- TRACE_EVENT1(
- "cc", "ZeroCopyRasterWorkerPool::OnRasterFinished", "task_set", task_set);
-
- DCHECK(raster_pending_[task_set]);
- raster_pending_[task_set] = false;
- if (raster_pending_.any()) {
- TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, "rasterizing", "state", StateAsValue());
- } else {
- TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
- }
- client_->DidFinishRunningTasks(task_set);
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-ZeroCopyRasterWorkerPool::StateAsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
-
- state->BeginArray("tasks_pending");
- for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
- state->AppendBoolean(raster_pending_[task_set]);
- state->EndArray();
- return state;
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/zero_copy_raster_worker_pool.h b/chromium/cc/resources/zero_copy_raster_worker_pool.h
deleted file mode 100644
index d1f583ee164..00000000000
--- a/chromium/cc/resources/zero_copy_raster_worker_pool.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_ZERO_COPY_RASTER_WORKER_POOL_H_
-#define CC_RESOURCES_ZERO_COPY_RASTER_WORKER_POOL_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/values.h"
-#include "cc/resources/raster_worker_pool.h"
-#include "cc/resources/rasterizer.h"
-
-namespace base {
-namespace debug {
-class ConvertableToTraceFormat;
-}
-}
-
-namespace cc {
-class ResourceProvider;
-
-class CC_EXPORT ZeroCopyRasterWorkerPool : public RasterWorkerPool,
- public Rasterizer,
- public RasterizerTaskClient {
- public:
- ~ZeroCopyRasterWorkerPool() override;
-
- static scoped_ptr<RasterWorkerPool> Create(
- base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ResourceProvider* resource_provider);
-
- // Overridden from RasterWorkerPool:
- Rasterizer* AsRasterizer() override;
-
- // Overridden from Rasterizer:
- void SetClient(RasterizerClient* client) override;
- void Shutdown() override;
- void ScheduleTasks(RasterTaskQueue* queue) override;
- void CheckForCompletedTasks() override;
-
- // Overridden from RasterizerTaskClient:
- scoped_ptr<RasterBuffer> AcquireBufferForRaster(
- const Resource* resource) override;
- void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override;
-
- protected:
- ZeroCopyRasterWorkerPool(base::SequencedTaskRunner* task_runner,
- TaskGraphRunner* task_graph_runner,
- ResourceProvider* resource_provider);
-
- private:
- void OnRasterFinished(TaskSet task_set);
- scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
-
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
- TaskGraphRunner* task_graph_runner_;
- const NamespaceToken namespace_token_;
- RasterizerClient* client_;
- ResourceProvider* resource_provider_;
-
- TaskSetCollection raster_pending_;
-
- scoped_refptr<RasterizerTask> raster_finished_tasks_[kNumberOfTaskSets];
-
- // Task graph used when scheduling tasks and vector used to gather
- // completed tasks.
- TaskGraph graph_;
- Task::Vector completed_tasks_;
-
- base::WeakPtrFactory<ZeroCopyRasterWorkerPool>
- raster_finished_weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ZeroCopyRasterWorkerPool);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_ZERO_COPY_RASTER_WORKER_POOL_H_
diff --git a/chromium/cc/scheduler/begin_frame_source.cc b/chromium/cc/scheduler/begin_frame_source.cc
index 4a9f1844083..48d834359f4 100644
--- a/chromium/cc/scheduler/begin_frame_source.cc
+++ b/chromium/cc/scheduler/begin_frame_source.cc
@@ -5,10 +5,11 @@
#include "cc/scheduler/begin_frame_source.h"
#include "base/auto_reset.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/location.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/scheduler/delay_based_time_source.h"
#include "cc/scheduler/scheduler.h"
#include "ui/gfx/frame_time.h"
@@ -52,7 +53,7 @@ void BeginFrameObserverMixIn::OnBeginFrame(const BeginFrameArgs& args) {
}
void BeginFrameObserverMixIn::AsValueInto(
- base::debug::TracedValue* dict) const {
+ base::trace_event::TracedValue* dict) const {
dict->BeginDictionary("last_begin_frame_args_");
last_begin_frame_args_.AsValueInto(dict);
dict->EndDictionary();
@@ -79,9 +80,9 @@ void BeginFrameSourceMixIn::SetNeedsBeginFrames(bool needs_begin_frames) {
"new state",
needs_begin_frames);
if (needs_begin_frames_ != needs_begin_frames) {
+ needs_begin_frames_ = needs_begin_frames;
OnNeedsBeginFramesChange(needs_begin_frames);
}
- needs_begin_frames_ = needs_begin_frames;
}
void BeginFrameSourceMixIn::AddObserver(BeginFrameObserver* obs) {
@@ -116,7 +117,8 @@ void BeginFrameSourceMixIn::CallOnBeginFrame(const BeginFrameArgs& args) {
}
// Tracing support
-void BeginFrameSourceMixIn::AsValueInto(base::debug::TracedValue* dict) const {
+void BeginFrameSourceMixIn::AsValueInto(
+ base::trace_event::TracedValue* dict) const {
// As the observer might try to trace the source, prevent an infinte loop
// from occuring.
if (inside_as_value_into_) {
@@ -145,9 +147,9 @@ scoped_ptr<BackToBackBeginFrameSource> BackToBackBeginFrameSource::Create(
BackToBackBeginFrameSource::BackToBackBeginFrameSource(
base::SingleThreadTaskRunner* task_runner)
: BeginFrameSourceMixIn(),
- weak_factory_(this),
task_runner_(task_runner),
- send_begin_frame_posted_(false) {
+ send_begin_frame_posted_(false),
+ weak_factory_(this) {
DCHECK(task_runner);
DCHECK_EQ(needs_begin_frames_, false);
DCHECK_EQ(send_begin_frame_posted_, false);
@@ -181,10 +183,9 @@ void BackToBackBeginFrameSource::BeginFrame() {
return;
base::TimeTicks now = Now();
- BeginFrameArgs args =
- BeginFrameArgs::Create(now,
- now + BeginFrameArgs::DefaultInterval(),
- BeginFrameArgs::DefaultInterval());
+ BeginFrameArgs args = BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, now, now + BeginFrameArgs::DefaultInterval(),
+ BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
CallOnBeginFrame(args);
}
@@ -198,7 +199,7 @@ void BackToBackBeginFrameSource::DidFinishFrame(size_t remaining_frames) {
// Tracing support
void BackToBackBeginFrameSource::AsValueInto(
- base::debug::TracedValue* dict) const {
+ base::trace_event::TracedValue* dict) const {
dict->SetString("type", "BackToBackBeginFrameSource");
BeginFrameSourceMixIn::AsValueInto(dict);
dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
@@ -243,8 +244,8 @@ BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs(
base::TimeTicks frame_time,
BeginFrameArgs::BeginFrameArgsType type) {
base::TimeTicks deadline = time_source_->NextTickTime();
- return BeginFrameArgs::CreateTyped(
- frame_time, deadline, time_source_->Interval(), type);
+ return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
+ time_source_->Interval(), type);
}
// TimeSourceClient support
@@ -264,13 +265,9 @@ void SyntheticBeginFrameSource::OnNeedsBeginFramesChange(
}
}
-bool SyntheticBeginFrameSource::NeedsBeginFrames() const {
- return time_source_->Active();
-}
-
// Tracing support
void SyntheticBeginFrameSource::AsValueInto(
- base::debug::TracedValue* dict) const {
+ base::trace_event::TracedValue* dict) const {
dict->SetString("type", "SyntheticBeginFrameSource");
BeginFrameSourceMixIn::AsValueInto(dict);
@@ -300,6 +297,10 @@ BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
}
BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
+ if (active_source_) {
+ active_source_->SetNeedsBeginFrames(false);
+ active_source_->RemoveObserver(this);
+ }
}
void BeginFrameSourceMultiplexer::SetMinimumInterval(
@@ -314,11 +315,8 @@ void BeginFrameSourceMultiplexer::SetMinimumInterval(
}
void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
- DEBUG_FRAMES("BeginFrameSourceMultiplexer::AddSource",
- "current active",
- active_source_,
- "source to remove",
- new_source);
+ DEBUG_FRAMES("BeginFrameSourceMultiplexer::AddSource", "current active",
+ active_source_, "source to be added", new_source);
DCHECK(new_source);
DCHECK(!HasSource(new_source));
@@ -331,11 +329,8 @@ void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
void BeginFrameSourceMultiplexer::RemoveSource(
BeginFrameSource* existing_source) {
- DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource",
- "current active",
- active_source_,
- "source to remove",
- existing_source);
+ DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource", "current active",
+ active_source_, "source to be removed", existing_source);
DCHECK(existing_source);
DCHECK(HasSource(existing_source));
DCHECK_NE(existing_source, active_source_);
@@ -406,19 +401,10 @@ const BeginFrameArgs BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs()
}
// BeginFrameSource support
-bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const {
- if (active_source_) {
- return active_source_->NeedsBeginFrames();
- } else {
- return false;
- }
-}
-
-void BeginFrameSourceMultiplexer::SetNeedsBeginFrames(bool needs_begin_frames) {
- DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetNeedsBeginFrames",
- "active_source",
- active_source_,
- "needs_begin_frames",
+void BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange(
+ bool needs_begin_frames) {
+ DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange",
+ "active_source", active_source_, "needs_begin_frames",
needs_begin_frames);
if (active_source_) {
active_source_->SetNeedsBeginFrames(needs_begin_frames);
@@ -440,7 +426,7 @@ void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames) {
// Tracing support
void BeginFrameSourceMultiplexer::AsValueInto(
- base::debug::TracedValue* dict) const {
+ base::trace_event::TracedValue* dict) const {
dict->SetString("type", "BeginFrameSourceMultiplexer");
dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
diff --git a/chromium/cc/scheduler/begin_frame_source.h b/chromium/cc/scheduler/begin_frame_source.h
index 3d849a40d63..d845dacd8e4 100644
--- a/chromium/cc/scheduler/begin_frame_source.h
+++ b/chromium/cc/scheduler/begin_frame_source.h
@@ -8,8 +8,8 @@
#include <set>
#include <string>
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "cc/output/begin_frame_args.h"
#include "cc/output/vsync_parameter_observer.h"
#include "cc/scheduler/delay_based_time_source.h"
@@ -50,7 +50,7 @@ class CC_EXPORT BeginFrameObserver {
virtual const BeginFrameArgs LastUsedBeginFrameArgs() const = 0;
// Tracing support
- virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const = 0;
};
// Simple mix in which implements a BeginFrameObserver which checks the
@@ -75,7 +75,7 @@ class CC_EXPORT BeginFrameObserverMixIn : public BeginFrameObserver {
const BeginFrameArgs LastUsedBeginFrameArgs() const override;
// Outputs last_begin_frame_args_
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
protected:
// Subclasses should override this method!
@@ -117,9 +117,12 @@ class CC_EXPORT BeginFrameSource {
virtual void AddObserver(BeginFrameObserver* obs) = 0;
virtual void RemoveObserver(BeginFrameObserver* obs) = 0;
+ // Tells the Source that client is ready to handle BeginFrames messages.
+ virtual void SetClientReady() = 0;
+
// Tracing support - Recommend (but not required) to call this implementation
// in any override.
- virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const = 0;
};
// Simple mix in which implements a BeginFrameSource.
@@ -134,15 +137,16 @@ class CC_EXPORT BeginFrameSourceMixIn : public BeginFrameSource {
~BeginFrameSourceMixIn() override {}
// BeginFrameSource
- bool NeedsBeginFrames() const override;
- void SetNeedsBeginFrames(bool needs_begin_frames) override;
+ bool NeedsBeginFrames() const final;
+ void SetNeedsBeginFrames(bool needs_begin_frames) final;
void DidFinishFrame(size_t remaining_frames) override {}
- void AddObserver(BeginFrameObserver* obs) override;
- void RemoveObserver(BeginFrameObserver* obs) override;
+ void AddObserver(BeginFrameObserver* obs) final;
+ void RemoveObserver(BeginFrameObserver* obs) final;
+ void SetClientReady() override {}
// Tracing support - Recommend (but not required) to call this implementation
// in any override.
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
protected:
BeginFrameSourceMixIn();
@@ -174,14 +178,13 @@ class CC_EXPORT BackToBackBeginFrameSource : public BeginFrameSourceMixIn {
void DidFinishFrame(size_t remaining_frames) override;
// Tracing
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
protected:
explicit BackToBackBeginFrameSource(
base::SingleThreadTaskRunner* task_runner);
virtual base::TimeTicks Now(); // Now overridable for testing
- base::WeakPtrFactory<BackToBackBeginFrameSource> weak_factory_;
base::SingleThreadTaskRunner* task_runner_;
bool send_begin_frame_posted_;
@@ -190,6 +193,9 @@ class CC_EXPORT BackToBackBeginFrameSource : public BeginFrameSourceMixIn {
void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
void BeginFrame();
+
+ private:
+ base::WeakPtrFactory<BackToBackBeginFrameSource> weak_factory_;
};
// A frame source which is locked to an external parameters provides from a
@@ -204,11 +210,8 @@ class CC_EXPORT SyntheticBeginFrameSource : public BeginFrameSourceMixIn,
base::TimeDelta initial_vsync_interval);
~SyntheticBeginFrameSource() override;
- // BeginFrameSource
- bool NeedsBeginFrames() const override;
-
// Tracing
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
// VSyncParameterObserver
void OnUpdateVSyncParameters(base::TimeTicks new_vsync_timebase,
@@ -254,12 +257,13 @@ class CC_EXPORT BeginFrameSourceMultiplexer : public BeginFrameSourceMixIn,
const BeginFrameArgs LastUsedBeginFrameArgs() const override;
// BeginFrameSource
- bool NeedsBeginFrames() const override;
- void SetNeedsBeginFrames(bool needs_begin_frames) override;
void DidFinishFrame(size_t remaining_frames) override;
+ // BeginFrameSourceMixIn
+ void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
+
// Tracing
- void AsValueInto(base::debug::TracedValue* dict) const override;
+ void AsValueInto(base::trace_event::TracedValue* dict) const override;
protected:
BeginFrameSourceMultiplexer();
diff --git a/chromium/cc/scheduler/begin_frame_source_unittest.cc b/chromium/cc/scheduler/begin_frame_source_unittest.cc
index b741e3581a9..22126bead45 100644
--- a/chromium/cc/scheduler/begin_frame_source_unittest.cc
+++ b/chromium/cc/scheduler/begin_frame_source_unittest.cc
@@ -15,19 +15,18 @@
#include "testing/gtest/include/gtest/gtest.h"
// Macros to help set up expected calls on the MockBeginFrameObserver.
-#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval) \
- { \
- ::testing::Expectation exp = \
- EXPECT_CALL((obs), \
- OnBeginFrame(CreateBeginFrameArgsForTesting( \
- frame_time, deadline, interval))) \
- .InSequence((obs).sequence); \
+#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval) \
+ { \
+ ::testing::Expectation exp = \
+ EXPECT_CALL((obs), OnBeginFrame(CreateBeginFrameArgsForTesting( \
+ BEGINFRAME_FROM_HERE, frame_time, deadline, \
+ interval))).InSequence((obs).sequence); \
}
#define EXPECT_BEGIN_FRAME_USED(obs, frame_time, deadline, interval) \
{ \
- BeginFrameArgs args = \
- CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting( \
+ BEGINFRAME_FROM_HERE, frame_time, deadline, interval); \
::testing::Expectation exp = \
EXPECT_CALL((obs), OnBeginFrame(args)).InSequence((obs).sequence); \
EXPECT_CALL((obs), LastUsedBeginFrameArgs()) \
@@ -38,15 +37,15 @@
// Macros to send BeginFrameArgs on a FakeBeginFrameSink (and verify resulting
// observer behaviour).
-#define SEND_BEGIN_FRAME( \
- args_equal_to, source, frame_time, deadline, interval) \
- { \
- BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs(); \
- BeginFrameArgs new_args = \
- CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \
- ASSERT_TRUE(!(old_args == new_args)); \
- (source).TestOnBeginFrame(new_args); \
- EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs()); \
+#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \
+ interval) \
+ { \
+ BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs(); \
+ BeginFrameArgs new_args = CreateBeginFrameArgsForTesting( \
+ BEGINFRAME_FROM_HERE, frame_time, deadline, interval); \
+ ASSERT_FALSE(old_args == new_args); \
+ (source).TestOnBeginFrame(new_args); \
+ EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs()); \
}
// When dropping LastUsedBeginFrameArgs **shouldn't** change.
@@ -65,7 +64,7 @@ class MockBeginFrameObserver : public BeginFrameObserver {
MOCK_METHOD1(OnBeginFrame, void(const BeginFrameArgs&));
MOCK_CONST_METHOD0(LastUsedBeginFrameArgs, const BeginFrameArgs());
- virtual void AsValueInto(base::debug::TracedValue* dict) const {
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const {
dict->SetString("type", "MockBeginFrameObserver");
dict->BeginDictionary("last_begin_frame_args");
LastUsedBeginFrameArgs().AsValueInto(dict);
@@ -99,19 +98,25 @@ TEST(MockBeginFrameObserverTest, ExpectOnBeginFrame) {
MockBeginFrameObserver::kDefaultBeginFrameArgs);
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
- 100, 200, 300)); // One call to LastUsedBeginFrameArgs
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ BEGINFRAME_FROM_HERE, 100, 200,
+ 300)); // One call to LastUsedBeginFrameArgs
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
- 400, 600, 300)); // Multiple calls to LastUsedBeginFrameArgs
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(400, 600, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(400, 600, 300));
+ BEGINFRAME_FROM_HERE, 400, 600,
+ 300)); // Multiple calls to LastUsedBeginFrameArgs
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
- 700, 900, 300)); // No calls to LastUsedBeginFrameArgs
+ BEGINFRAME_FROM_HERE, 700, 900,
+ 300)); // No calls to LastUsedBeginFrameArgs
}
TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) {
@@ -125,28 +130,45 @@ TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) {
MockBeginFrameObserver::kDefaultBeginFrameArgs);
// Used
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(100, 200, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
// Dropped
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(400, 600, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
// Dropped
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(450, 650, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(100, 200, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 450, 650, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
// Used
- obs.OnBeginFrame(CreateBeginFrameArgsForTesting(700, 900, 300));
- EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
- CreateBeginFrameArgsForTesting(700, 900, 300));
+ obs.OnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
+ EXPECT_EQ(
+ obs.LastUsedBeginFrameArgs(),
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
}
const BeginFrameArgs MockBeginFrameObserver::kDefaultBeginFrameArgs =
- CreateBeginFrameArgsForTesting(-1, -1, -1);
+ CreateBeginFrameArgsForTesting(
+#ifdef NDEBUG
+ nullptr,
+#else
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "MockBeginFrameObserver::kDefaultBeginFrameArgs"),
+#endif
+ -1,
+ -1,
+ -1);
// BeginFrameObserverMixIn testing ---------------------------------------
class MockMinimalBeginFrameObserverMixIn : public BeginFrameObserverMixIn {
@@ -168,25 +190,31 @@ TEST(BeginFrameObserverMixInTest, OnBeginFrameImplementation) {
EXPECT_DEATH({ obs.OnBeginFrame(BeginFrameArgs()); }, "");
#endif
- BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(100, 200, 300);
+ BeginFrameArgs args1 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300);
EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args1)).WillOnce(Return(true));
obs.OnBeginFrame(args1);
EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
EXPECT_EQ(0, obs.dropped_begin_frame_args());
#ifndef NDEBUG
- EXPECT_DEATH(
- { obs.OnBeginFrame(CreateBeginFrameArgsForTesting(50, 200, 300)); }, "");
+ EXPECT_DEATH({
+ obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 50, 200, 300));
+ },
+ "");
#endif
// Returning false shouldn't update the LastUsedBeginFrameArgs value.
- BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(200, 300, 400);
+ BeginFrameArgs args2 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 200, 300, 400);
EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args2)).WillOnce(Return(false));
obs.OnBeginFrame(args2);
EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
EXPECT_EQ(1, obs.dropped_begin_frame_args());
- BeginFrameArgs args3 = CreateBeginFrameArgsForTesting(150, 300, 400);
+ BeginFrameArgs args3 =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 150, 300, 400);
EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args3)).WillOnce(Return(true));
obs.OnBeginFrame(args3);
EXPECT_EQ(args3, obs.LastUsedBeginFrameArgs());
@@ -256,7 +284,7 @@ class LoopingBeginFrameObserver : public BeginFrameObserverMixIn {
public:
BeginFrameSource* source_;
- void AsValueInto(base::debug::TracedValue* dict) const override {
+ void AsValueInto(base::trace_event::TracedValue* dict) const override {
dict->SetString("type", "LoopingBeginFrameObserver");
dict->BeginDictionary("source");
source_->AsValueInto(dict);
@@ -277,8 +305,8 @@ TEST(BeginFrameSourceMixInTest, DetectAsValueIntoLoop) {
obs.source_ = &source;
source.AddObserver(&obs);
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
source.AsValueInto(state.get());
}
@@ -312,7 +340,7 @@ class BackToBackBeginFrameSourceTest : public ::testing::Test {
scoped_ptr<TestBackToBackBeginFrameSource> source_;
scoped_ptr<MockBeginFrameObserver> obs_;
- virtual void SetUp() override {
+ void SetUp() override {
now_src_ = TestNowSource::Create(1000);
task_runner_ =
make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false));
@@ -323,7 +351,7 @@ class BackToBackBeginFrameSourceTest : public ::testing::Test {
source_->AddObserver(obs_.get());
}
- virtual void TearDown() override { obs_.reset(); }
+ void TearDown() override { obs_.reset(); }
};
const int64_t BackToBackBeginFrameSourceTest::kDeadline =
@@ -478,7 +506,7 @@ class SyntheticBeginFrameSourceTest : public ::testing::Test {
scoped_ptr<TestSyntheticBeginFrameSource> source_;
scoped_ptr<MockBeginFrameObserver> obs_;
- virtual void SetUp() override {
+ void SetUp() override {
now_src_ = TestNowSource::Create(1000);
task_runner_ =
make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false));
@@ -488,15 +516,15 @@ class SyntheticBeginFrameSourceTest : public ::testing::Test {
source_->AddObserver(obs_.get());
}
- virtual void TearDown() override { obs_.reset(); }
+ void TearDown() override { obs_.reset(); }
};
TEST_F(SyntheticBeginFrameSourceTest,
SetNeedsBeginFramesCallsOnBeginFrameWithMissedTick) {
now_src_->SetNowMicroseconds(10010);
- EXPECT_CALL((*obs_),
- OnBeginFrame(CreateTypedBeginFrameArgsForTesting(
- 10000, 20000, 10000, BeginFrameArgs::MISSED)));
+ EXPECT_CALL((*obs_), OnBeginFrame(CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 10000, 20000, 10000,
+ BeginFrameArgs::MISSED)));
source_->SetNeedsBeginFrames(true); // Should cause the last tick to be sent
// No tasks should need to be run for this to occur.
}
@@ -547,7 +575,7 @@ TEST_F(SyntheticBeginFrameSourceTest, VSyncChanges) {
// BeginFrameSourceMultiplexer testing -----------------------------------
class BeginFrameSourceMultiplexerTest : public ::testing::Test {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
mux_ = BeginFrameSourceMultiplexer::Create();
source1_store_ = make_scoped_ptr(new FakeBeginFrameSource());
@@ -559,7 +587,7 @@ class BeginFrameSourceMultiplexerTest : public ::testing::Test {
source3_ = source3_store_.get();
}
- virtual void TearDown() override {
+ void TearDown() override {
// Make sure the mux is torn down before the sources.
mux_.reset();
}
diff --git a/chromium/cc/scheduler/commit_earlyout_reason.h b/chromium/cc/scheduler/commit_earlyout_reason.h
new file mode 100644
index 00000000000..14aaeb3b7d9
--- /dev/null
+++ b/chromium/cc/scheduler/commit_earlyout_reason.h
@@ -0,0 +1,40 @@
+// Copyright 2014 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_SCHEDULER_COMMIT_EARLYOUT_REASON_H_
+#define CC_SCHEDULER_COMMIT_EARLYOUT_REASON_H_
+
+#include "base/logging.h"
+
+namespace cc {
+
+enum class CommitEarlyOutReason {
+ ABORTED_OUTPUT_SURFACE_LOST,
+ ABORTED_NOT_VISIBLE,
+ ABORTED_DEFERRED_COMMIT,
+ FINISHED_NO_UPDATES,
+};
+
+inline const char* CommitEarlyOutReasonToString(CommitEarlyOutReason reason) {
+ switch (reason) {
+ case CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST:
+ return "CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST";
+ case CommitEarlyOutReason::ABORTED_NOT_VISIBLE:
+ return "CommitEarlyOutReason::ABORTED_NOT_VISIBLE";
+ case CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT:
+ return "CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT";
+ case CommitEarlyOutReason::FINISHED_NO_UPDATES:
+ return "CommitEarlyOutReason::FINISHED_NO_UPDATES";
+ }
+ NOTREACHED();
+ return "???";
+}
+
+inline bool CommitEarlyOutHandledCommit(CommitEarlyOutReason reason) {
+ return reason == CommitEarlyOutReason::FINISHED_NO_UPDATES;
+}
+
+} // namespace cc
+
+#endif // CC_SCHEDULER_COMMIT_EARLYOUT_REASON_H_
diff --git a/chromium/cc/scheduler/delay_based_time_source.cc b/chromium/cc/scheduler/delay_based_time_source.cc
index cd214fd98d7..ef43524a878 100644
--- a/chromium/cc/scheduler/delay_based_time_source.cc
+++ b/chromium/cc/scheduler/delay_based_time_source.cc
@@ -9,11 +9,11 @@
#include <string>
#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
namespace cc {
@@ -36,7 +36,7 @@ static const double kPhaseChangeThreshold = 0.25;
} // namespace
// The following methods correspond to the DelayBasedTimeSource that uses
-// the base::TimeTicks::HighResNow as the timebase.
+// the base::TimeTicks::Now as the timebase.
scoped_refptr<DelayBasedTimeSourceHighRes> DelayBasedTimeSourceHighRes::Create(
base::TimeDelta interval,
base::SingleThreadTaskRunner* task_runner) {
@@ -53,7 +53,7 @@ DelayBasedTimeSourceHighRes::DelayBasedTimeSourceHighRes(
DelayBasedTimeSourceHighRes::~DelayBasedTimeSourceHighRes() {}
base::TimeTicks DelayBasedTimeSourceHighRes::Now() const {
- return base::TimeTicks::HighResNow();
+ return base::TimeTicks::Now();
}
// The following methods correspond to the DelayBasedTimeSource that uses
@@ -234,34 +234,20 @@ base::TimeTicks DelayBasedTimeSource::Now() const {
// now=37 tick_target=16.667 new_target=50.000 -->
// tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13)
base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) {
- base::TimeDelta new_interval = next_parameters_.interval;
-
- // |interval_offset| is the offset from |now| to the next multiple of
- // |interval| after |tick_target|, possibly negative if in the past.
- base::TimeDelta interval_offset = base::TimeDelta::FromInternalValue(
- (next_parameters_.tick_target - now).ToInternalValue() %
- new_interval.ToInternalValue());
- // If |now| is exactly on the interval (i.e. offset==0), don't adjust.
- // Otherwise, if |tick_target| was in the past, adjust forward to the next
- // tick after |now|.
- if (interval_offset.ToInternalValue() != 0 &&
- next_parameters_.tick_target < now) {
- interval_offset += new_interval;
- }
-
- base::TimeTicks new_tick_target = now + interval_offset;
+ base::TimeTicks new_tick_target = now.SnappedToNextTick(
+ next_parameters_.tick_target, next_parameters_.interval);
DCHECK(now <= new_tick_target)
<< "now = " << now.ToInternalValue()
<< "; new_tick_target = " << new_tick_target.ToInternalValue()
- << "; new_interval = " << new_interval.InMicroseconds()
- << "; tick_target = " << next_parameters_.tick_target.ToInternalValue()
- << "; interval_offset = " << interval_offset.ToInternalValue();
+ << "; new_interval = " << next_parameters_.interval.InMicroseconds()
+ << "; tick_target = " << next_parameters_.tick_target.ToInternalValue();
// Avoid double ticks when:
// 1) Turning off the timer and turning it right back on.
// 2) Jittery data is passed to SetTimebaseAndInterval().
- if (new_tick_target - last_tick_time_ <= new_interval / kDoubleTickDivisor)
- new_tick_target += new_interval;
+ if (new_tick_target - last_tick_time_ <=
+ next_parameters_.interval / kDoubleTickDivisor)
+ new_tick_target += next_parameters_.interval;
return new_tick_target;
}
@@ -290,7 +276,8 @@ std::string DelayBasedTimeSourceHighRes::TypeString() const {
return "DelayBasedTimeSourceHighRes";
}
-void DelayBasedTimeSource::AsValueInto(base::debug::TracedValue* state) const {
+void DelayBasedTimeSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
state->SetString("type", TypeString());
state->SetDouble("last_tick_time_us", LastTickTime().ToInternalValue());
state->SetDouble("next_tick_time_us", NextTickTime().ToInternalValue());
diff --git a/chromium/cc/scheduler/delay_based_time_source.h b/chromium/cc/scheduler/delay_based_time_source.h
index 9f670d1f8ff..4d7276c97c8 100644
--- a/chromium/cc/scheduler/delay_based_time_source.h
+++ b/chromium/cc/scheduler/delay_based_time_source.h
@@ -12,7 +12,7 @@
#include "cc/base/cc_export.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
class SingleThreadTaskRunner;
@@ -55,7 +55,7 @@ class CC_EXPORT DelayBasedTimeSource
// Virtual for testing.
virtual base::TimeTicks Now() const;
- virtual void AsValueInto(base::debug::TracedValue* dict) const;
+ virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
protected:
DelayBasedTimeSource(base::TimeDelta interval,
@@ -95,7 +95,9 @@ class CC_EXPORT DelayBasedTimeSource
DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSource);
};
-// DelayBasedTimeSource uses base::TimeTicks::HighResNow as its timebase.
+// DelayBasedTimeSource that once used base::TimeTicks::HighResNow as its time
+// source, but is now a no-op.
+// TODO(brianderson): Remove along with gfx::/FrameTime.http://crbug.com/447329
class DelayBasedTimeSourceHighRes : public DelayBasedTimeSource {
public:
static scoped_refptr<DelayBasedTimeSourceHighRes> Create(
diff --git a/chromium/cc/scheduler/delay_based_time_source_unittest.cc b/chromium/cc/scheduler/delay_based_time_source_unittest.cc
index 0af8b02f4b9..f721b11ff7f 100644
--- a/chromium/cc/scheduler/delay_based_time_source_unittest.cc
+++ b/chromium/cc/scheduler/delay_based_time_source_unittest.cc
@@ -508,23 +508,6 @@ TEST(DelayBasedTimeSourceTest, TestDeactivateAndReactivateAfterNextTickTime) {
EXPECT_EQ(13, task_runner->NextPendingTaskDelay().InMilliseconds());
}
-TEST(DelayBasedTimeSourceTest, TestOverflow) {
- // int(big_now / interval) < 0, so this causes a crash if the number of
- // intervals elapsed is attempted to be stored in an int.
- base::TimeDelta interval = base::TimeDelta::FromInternalValue(4000);
- base::TimeTicks big_now = base::TimeTicks::FromInternalValue(8635916564000);
-
- scoped_refptr<base::TestSimpleTaskRunner> task_runner =
- new base::TestSimpleTaskRunner;
- FakeTimeSourceClient client;
- scoped_refptr<FakeDelayBasedTimeSource> timer =
- FakeDelayBasedTimeSource::Create(interval, task_runner.get());
- timer->SetClient(&client);
- timer->SetNow(big_now);
- timer->SetActive(true);
- EXPECT_EQ(0, task_runner->NextPendingTaskDelay().InMilliseconds());
-}
-
TEST(DelayBasedTimeSourceTest, TestReturnValueWhenTimerIsDeActivated) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index 88c27c103e3..d2520335c0c 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -5,11 +5,13 @@
#include "cc/scheduler/scheduler.h"
#include <algorithm>
+
#include "base/auto_reset.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/logging.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/traced_value.h"
#include "cc/scheduler/delay_based_time_source.h"
@@ -19,21 +21,14 @@ namespace cc {
BeginFrameSource* SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource(
Scheduler* scheduler) {
- if (!scheduler->settings_.throttle_frame_production) {
+ if (scheduler->settings_.use_external_begin_frame_source) {
TRACE_EVENT1("cc",
"Scheduler::Scheduler()",
"PrimaryFrameSource",
- "BackToBackBeginFrameSource");
- DCHECK(!scheduler->primary_frame_source_internal_);
- scheduler->primary_frame_source_internal_ =
- BackToBackBeginFrameSource::Create(scheduler->task_runner_.get());
+ "ExternalBeginFrameSource");
+ DCHECK(scheduler->primary_frame_source_internal_)
+ << "Need external BeginFrameSource";
return scheduler->primary_frame_source_internal_.get();
- } else if (scheduler->settings_.begin_frame_scheduling_enabled) {
- TRACE_EVENT1("cc",
- "Scheduler::Scheduler()",
- "PrimaryFrameSource",
- "SchedulerClient");
- return scheduler->client_->ExternalBeginFrameSource();
} else {
TRACE_EVENT1("cc",
"Scheduler::Scheduler()",
@@ -54,18 +49,14 @@ BeginFrameSource* SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource(
}
BeginFrameSource*
-SchedulerFrameSourcesConstructor::ConstructBackgroundFrameSource(
+SchedulerFrameSourcesConstructor::ConstructUnthrottledFrameSource(
Scheduler* scheduler) {
- TRACE_EVENT1("cc",
- "Scheduler::Scheduler()",
- "BackgroundFrameSource",
- "SyntheticBeginFrameSource");
- DCHECK(!(scheduler->background_frame_source_internal_));
- scheduler->background_frame_source_internal_ =
- SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(),
- scheduler->Now(),
- base::TimeDelta::FromSeconds(1));
- return scheduler->background_frame_source_internal_.get();
+ TRACE_EVENT1("cc", "Scheduler::Scheduler()", "UnthrottledFrameSource",
+ "BackToBackBeginFrameSource");
+ DCHECK(!scheduler->unthrottled_frame_source_internal_);
+ scheduler->unthrottled_frame_source_internal_ =
+ BackToBackBeginFrameSource::Create(scheduler->task_runner_.get());
+ return scheduler->unthrottled_frame_source_internal_.get();
}
Scheduler::Scheduler(
@@ -73,20 +64,21 @@ Scheduler::Scheduler(
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- base::PowerMonitor* power_monitor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source,
SchedulerFrameSourcesConstructor* frame_sources_constructor)
: frame_source_(),
primary_frame_source_(NULL),
- background_frame_source_(NULL),
- primary_frame_source_internal_(),
- background_frame_source_internal_(),
+ primary_frame_source_internal_(external_begin_frame_source.Pass()),
vsync_observer_(NULL),
+ authoritative_vsync_interval_(base::TimeDelta()),
+ last_vsync_timebase_(base::TimeTicks()),
+ throttle_frame_production_(false),
settings_(scheduler_settings),
client_(client),
layer_tree_host_id_(layer_tree_host_id),
task_runner_(task_runner),
- power_monitor_(power_monitor),
- begin_retro_frame_posted_(false),
+ begin_impl_frame_deadline_mode_(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE),
state_machine_(scheduler_settings),
inside_process_scheduled_actions_(false),
inside_action_(SchedulerStateMachine::ACTION_NONE),
@@ -102,8 +94,6 @@ Scheduler::Scheduler(
base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
begin_impl_frame_deadline_closure_ = base::Bind(
&Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
- poll_for_draw_triggers_closure_ = base::Bind(
- &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr());
advance_commit_state_closure_ = base::Bind(
&Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
@@ -114,17 +104,20 @@ Scheduler::Scheduler(
primary_frame_source_ =
frame_sources_constructor->ConstructPrimaryFrameSource(this);
frame_source_->AddSource(primary_frame_source_);
+ primary_frame_source_->SetClientReady();
- // Background ticking frame source
- background_frame_source_ =
- frame_sources_constructor->ConstructBackgroundFrameSource(this);
- frame_source_->AddSource(background_frame_source_);
+ // Unthrottled frame source
+ unthrottled_frame_source_ =
+ frame_sources_constructor->ConstructUnthrottledFrameSource(this);
+ frame_source_->AddSource(unthrottled_frame_source_);
- SetupPowerMonitoring();
+ SetThrottleFrameProduction(scheduler_settings.throttle_frame_production);
}
Scheduler::~Scheduler() {
- TeardownPowerMonitoring();
+ if (frame_source_->NeedsBeginFrames())
+ frame_source_->SetNeedsBeginFrames(false);
+ frame_source_->SetActiveSource(nullptr);
}
base::TimeTicks Scheduler::Now() const {
@@ -136,32 +129,16 @@ base::TimeTicks Scheduler::Now() const {
return now;
}
-void Scheduler::SetupPowerMonitoring() {
- if (settings_.disable_hi_res_timer_tasks_on_battery) {
- DCHECK(power_monitor_);
- power_monitor_->AddObserver(this);
- state_machine_.SetImplLatencyTakesPriorityOnBattery(
- power_monitor_->IsOnBatteryPower());
- }
-}
-
-void Scheduler::TeardownPowerMonitoring() {
- if (settings_.disable_hi_res_timer_tasks_on_battery) {
- DCHECK(power_monitor_);
- power_monitor_->RemoveObserver(this);
- }
-}
-
-void Scheduler::OnPowerStateChange(bool on_battery_power) {
- DCHECK(settings_.disable_hi_res_timer_tasks_on_battery);
- state_machine_.SetImplLatencyTakesPriorityOnBattery(on_battery_power);
-}
-
void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) {
- // TODO(brianderson): We should not be receiving 0 intervals.
- if (interval == base::TimeDelta())
+ if (authoritative_vsync_interval_ != base::TimeDelta()) {
+ interval = authoritative_vsync_interval_;
+ } else if (interval == base::TimeDelta()) {
+ // TODO(brianderson): We should not be receiving 0 intervals.
interval = BeginFrameArgs::DefaultInterval();
+ }
+
+ last_vsync_timebase_ = timebase;
if (vsync_observer_)
vsync_observer_->OnUpdateVSyncParameters(timebase, interval);
@@ -179,11 +156,6 @@ void Scheduler::SetCanStart() {
void Scheduler::SetVisible(bool visible) {
state_machine_.SetVisible(visible);
- if (visible) {
- frame_source_->SetActiveSource(primary_frame_source_);
- } else {
- frame_source_->SetActiveSource(background_frame_source_);
- }
ProcessScheduledActions();
}
@@ -197,6 +169,22 @@ void Scheduler::NotifyReadyToActivate() {
ProcessScheduledActions();
}
+void Scheduler::NotifyReadyToDraw() {
+ // Future work might still needed for crbug.com/352894.
+ state_machine_.NotifyReadyToDraw();
+ ProcessScheduledActions();
+}
+
+void Scheduler::SetThrottleFrameProduction(bool throttle) {
+ throttle_frame_production_ = throttle;
+ if (throttle) {
+ frame_source_->SetActiveSource(primary_frame_source_);
+ } else {
+ frame_source_->SetActiveSource(unthrottled_frame_source_);
+ }
+ ProcessScheduledActions();
+}
+
void Scheduler::SetNeedsCommit() {
state_machine_.SetNeedsCommit();
ProcessScheduledActions();
@@ -212,9 +200,14 @@ void Scheduler::SetNeedsAnimate() {
ProcessScheduledActions();
}
-void Scheduler::SetNeedsManageTiles() {
- DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES));
- state_machine_.SetNeedsManageTiles();
+void Scheduler::SetNeedsPrepareTiles() {
+ DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_PREPARE_TILES));
+ state_machine_.SetNeedsPrepareTiles();
+ ProcessScheduledActions();
+}
+
+void Scheduler::SetWaitForReadyToDraw() {
+ state_machine_.SetWaitForReadyToDraw();
ProcessScheduledActions();
}
@@ -232,11 +225,6 @@ void Scheduler::DidSwapBuffers() {
}
}
-void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
- state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
- ProcessScheduledActions();
-}
-
void Scheduler::DidSwapBuffersComplete() {
state_machine_.DidSwapBuffersComplete();
ProcessScheduledActions();
@@ -253,22 +241,22 @@ void Scheduler::NotifyReadyToCommit() {
ProcessScheduledActions();
}
-void Scheduler::BeginMainFrameAborted(bool did_handle) {
- TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted");
- state_machine_.BeginMainFrameAborted(did_handle);
+void Scheduler::BeginMainFrameAborted(CommitEarlyOutReason reason) {
+ TRACE_EVENT1("cc", "Scheduler::BeginMainFrameAborted", "reason",
+ CommitEarlyOutReasonToString(reason));
+ state_machine_.BeginMainFrameAborted(reason);
ProcessScheduledActions();
}
-void Scheduler::DidManageTiles() {
- state_machine_.DidManageTiles();
+void Scheduler::DidPrepareTiles() {
+ state_machine_.DidPrepareTiles();
}
void Scheduler::DidLoseOutputSurface() {
TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
- state_machine_.DidLoseOutputSurface();
- if (frame_source_->NeedsBeginFrames())
- frame_source_->SetNeedsBeginFrames(false);
begin_retro_frame_args_.clear();
+ begin_retro_frame_task_.Cancel();
+ state_machine_.DidLoseOutputSurface();
ProcessScheduledActions();
}
@@ -302,69 +290,35 @@ base::TimeTicks Scheduler::LastBeginImplFrameTime() {
}
void Scheduler::SetupNextBeginFrameIfNeeded() {
- if (!task_runner_.get())
- return;
-
- bool needs_begin_frame = state_machine_.BeginFrameNeeded();
-
- bool at_end_of_deadline =
- (state_machine_.begin_impl_frame_state() ==
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
-
- bool should_call_set_needs_begin_frame =
- // Always request the BeginFrame immediately if it wasn't needed before.
- (needs_begin_frame && !frame_source_->NeedsBeginFrames()) ||
- // Only stop requesting BeginFrames after a deadline.
- (!needs_begin_frame && frame_source_->NeedsBeginFrames() &&
- at_end_of_deadline);
-
- if (should_call_set_needs_begin_frame) {
- frame_source_->SetNeedsBeginFrames(needs_begin_frame);
- }
-
- if (at_end_of_deadline) {
- frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
+ // Never call SetNeedsBeginFrames if the frame source already has the right
+ // value.
+ if (frame_source_->NeedsBeginFrames() != state_machine_.BeginFrameNeeded()) {
+ if (state_machine_.BeginFrameNeeded()) {
+ // Call SetNeedsBeginFrames(true) as soon as possible.
+ frame_source_->SetNeedsBeginFrames(true);
+ } else if (state_machine_.begin_impl_frame_state() ==
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) {
+ // Call SetNeedsBeginFrames(false) in between frames only.
+ frame_source_->SetNeedsBeginFrames(false);
+ client_->SendBeginMainFrameNotExpectedSoon();
+ }
}
PostBeginRetroFrameIfNeeded();
- SetupPollingMechanisms(needs_begin_frame);
}
// We may need to poll when we can't rely on BeginFrame to advance certain
// state or to avoid deadlock.
-void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
- bool needs_advance_commit_state_timer = false;
- // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
- // aren't expecting any more BeginFrames. This should only be needed by
- // the synchronous compositor when BeginFrameNeeded is false.
- if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
- DCHECK(!state_machine_.SupportsProactiveBeginFrame());
- DCHECK(!needs_begin_frame);
- if (poll_for_draw_triggers_task_.IsCancelled()) {
- poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
- base::TimeDelta delay = begin_impl_frame_args_.IsValid()
- ? begin_impl_frame_args_.interval
- : BeginFrameArgs::DefaultInterval();
- task_runner_->PostDelayedTask(
- FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
- }
- } else {
- poll_for_draw_triggers_task_.Cancel();
-
- // At this point we'd prefer to advance through the commit flow by
- // drawing a frame, however it's possible that the frame rate controller
- // will not give us a BeginFrame until the commit completes. See
- // crbug.com/317430 for an example of a swap ack being held on commit. Thus
- // we set a repeating timer to poll on ProcessScheduledActions until we
- // successfully reach BeginFrame. Synchronous compositor does not use
- // frame rate controller or have the circular wait in the bug.
- if (IsBeginMainFrameSentOrStarted() &&
- !settings_.using_synchronous_renderer_compositor) {
- needs_advance_commit_state_timer = true;
- }
- }
-
- if (needs_advance_commit_state_timer) {
+void Scheduler::SetupPollingMechanisms() {
+ // At this point we'd prefer to advance through the commit flow by
+ // drawing a frame, however it's possible that the frame rate controller
+ // will not give us a BeginFrame until the commit completes. See
+ // crbug.com/317430 for an example of a swap ack being held on commit. Thus
+ // we set a repeating timer to poll on ProcessScheduledActions until we
+ // successfully reach BeginFrame. Synchronous compositor does not use
+ // frame rate controller or have the circular wait in the bug.
+ if (IsBeginMainFrameSentOrStarted() &&
+ !settings_.using_synchronous_renderer_compositor) {
if (advance_commit_state_task_.IsCancelled() &&
begin_impl_frame_args_.IsValid()) {
// Since we'd rather get a BeginImplFrame by the normal mechanism, we
@@ -384,31 +338,38 @@ void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
// If the scheduler is busy, we queue the BeginFrame to be handled later as
// a BeginRetroFrame.
bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) {
- TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue());
+ TRACE_EVENT1("cc,benchmark", "Scheduler::BeginFrame", "args", args.AsValue());
+
+ // TODO(brianderson): Adjust deadline in the DisplayScheduler.
+ BeginFrameArgs adjusted_args(args);
+ adjusted_args.deadline -= EstimatedParentDrawTime();
+
+ // Deliver BeginFrames to children.
+ // TODO(brianderson): Move this responsibility to the DisplayScheduler.
+ if (state_machine_.children_need_begin_frames())
+ client_->SendBeginFramesToChildren(adjusted_args);
+
+ if (settings_.using_synchronous_renderer_compositor) {
+ BeginImplFrameSynchronous(adjusted_args);
+ return true;
+ }
// We have just called SetNeedsBeginFrame(true) and the BeginFrameSource has
// sent us the last BeginFrame we have missed. As we might not be able to
// actually make rendering for this call, handle it like a "retro frame".
// TODO(brainderson): Add a test for this functionality ASAP!
- if (args.type == BeginFrameArgs::MISSED) {
- begin_retro_frame_args_.push_back(args);
+ if (adjusted_args.type == BeginFrameArgs::MISSED) {
+ begin_retro_frame_args_.push_back(adjusted_args);
PostBeginRetroFrameIfNeeded();
return true;
}
- BeginFrameArgs adjusted_args(args);
- adjusted_args.deadline -= EstimatedParentDrawTime();
-
- bool should_defer_begin_frame;
- if (settings_.using_synchronous_renderer_compositor) {
- should_defer_begin_frame = false;
- } else {
- should_defer_begin_frame =
- !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ ||
- !frame_source_->NeedsBeginFrames() ||
- (state_machine_.begin_impl_frame_state() !=
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
- }
+ bool should_defer_begin_frame =
+ !begin_retro_frame_args_.empty() ||
+ !begin_retro_frame_task_.IsCancelled() ||
+ !frame_source_->NeedsBeginFrames() ||
+ (state_machine_.begin_impl_frame_state() !=
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
if (should_defer_begin_frame) {
begin_retro_frame_args_.push_back(adjusted_args);
@@ -416,23 +377,51 @@ bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) {
"cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
// Queuing the frame counts as "using it", so we need to return true.
} else {
- BeginImplFrame(adjusted_args);
+ BeginImplFrameWithDeadline(adjusted_args);
}
return true;
}
+void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) {
+ state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames);
+ ProcessScheduledActions();
+}
+
+void Scheduler::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) {
+ authoritative_vsync_interval_ = interval;
+ if (vsync_observer_)
+ vsync_observer_->OnUpdateVSyncParameters(last_vsync_timebase_, interval);
+}
+
+void Scheduler::SetVideoNeedsBeginFrames(bool video_needs_begin_frames) {
+ state_machine_.SetVideoNeedsBeginFrames(video_needs_begin_frames);
+ ProcessScheduledActions();
+}
+
+void Scheduler::OnDrawForOutputSurface() {
+ DCHECK(settings_.using_synchronous_renderer_compositor);
+ DCHECK_EQ(state_machine_.begin_impl_frame_state(),
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ DCHECK(!BeginImplFrameDeadlinePending());
+
+ state_machine_.OnBeginImplFrameDeadline();
+ ProcessScheduledActions();
+
+ state_machine_.OnBeginImplFrameIdle();
+ ProcessScheduledActions();
+}
+
// BeginRetroFrame is called for BeginFrames that we've deferred because
// the scheduler was in the middle of processing a previous BeginFrame.
void Scheduler::BeginRetroFrame() {
- TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame");
+ TRACE_EVENT0("cc,benchmark", "Scheduler::BeginRetroFrame");
DCHECK(!settings_.using_synchronous_renderer_compositor);
- DCHECK(begin_retro_frame_posted_);
- begin_retro_frame_posted_ = false;
+ DCHECK(!begin_retro_frame_args_.empty());
+ DCHECK(!begin_retro_frame_task_.IsCancelled());
+ DCHECK_EQ(state_machine_.begin_impl_frame_state(),
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
- // If there aren't any retroactive BeginFrames, then we've lost the
- // OutputSurface and should abort.
- if (begin_retro_frame_args_.empty())
- return;
+ begin_retro_frame_task_.Cancel();
// Discard expired BeginRetroFrames
// Today, we should always end up with at most one un-expired BeginRetroFrame
@@ -442,20 +431,16 @@ void Scheduler::BeginRetroFrame() {
// draining the queue if we don't catch up. If we consistently can't catch
// up, our fallback should be to lower our frame rate.
base::TimeTicks now = Now();
- base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
+
while (!begin_retro_frame_args_.empty()) {
- base::TimeTicks adjusted_deadline = AdjustedBeginImplFrameDeadline(
- begin_retro_frame_args_.front(), draw_duration_estimate);
- if (now <= adjusted_deadline)
+ const BeginFrameArgs& args = begin_retro_frame_args_.front();
+ base::TimeTicks expiration_time = args.frame_time + args.interval;
+ if (now <= expiration_time)
break;
-
- TRACE_EVENT_INSTANT2("cc",
- "Scheduler::BeginRetroFrame discarding",
- TRACE_EVENT_SCOPE_THREAD,
- "deadline - now",
- (adjusted_deadline - now).InMicroseconds(),
- "BeginFrameArgs",
- begin_retro_frame_args_.front().AsValue());
+ TRACE_EVENT_INSTANT2(
+ "cc", "Scheduler::BeginRetroFrame discarding", TRACE_EVENT_SCOPE_THREAD,
+ "expiration_time - now", (expiration_time - now).InMillisecondsF(),
+ "BeginFrameArgs", begin_retro_frame_args_.front().AsValue());
begin_retro_frame_args_.pop_front();
frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
}
@@ -465,8 +450,9 @@ void Scheduler::BeginRetroFrame() {
"Scheduler::BeginRetroFrames all expired",
TRACE_EVENT_SCOPE_THREAD);
} else {
- BeginImplFrame(begin_retro_frame_args_.front());
+ BeginFrameArgs front = begin_retro_frame_args_.front();
begin_retro_frame_args_.pop_front();
+ BeginImplFrameWithDeadline(front);
}
}
@@ -482,7 +468,7 @@ void Scheduler::PostBeginRetroFrameIfNeeded() {
if (!frame_source_->NeedsBeginFrames())
return;
- if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
+ if (begin_retro_frame_args_.empty() || !begin_retro_frame_task_.IsCancelled())
return;
// begin_retro_frame_args_ should always be empty for the
@@ -493,34 +479,24 @@ void Scheduler::PostBeginRetroFrameIfNeeded() {
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)
return;
- begin_retro_frame_posted_ = true;
- task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
+ begin_retro_frame_task_.Reset(begin_retro_frame_closure_);
+
+ task_runner_->PostTask(FROM_HERE, begin_retro_frame_task_.callback());
}
-// BeginImplFrame starts a compositor frame that will wait up until a deadline
-// for a BeginMainFrame+activation to complete before it times out and draws
-// any asynchronous animation and scroll/pinch updates.
-void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
+void Scheduler::BeginImplFrameWithDeadline(const BeginFrameArgs& args) {
bool main_thread_is_in_high_latency_mode =
state_machine_.MainThreadIsInHighLatencyMode();
- TRACE_EVENT2("cc",
- "Scheduler::BeginImplFrame",
- "args",
- args.AsValue(),
- "main_thread_is_high_latency",
+ TRACE_EVENT2("cc,benchmark", "Scheduler::BeginImplFrame", "args",
+ args.AsValue(), "main_thread_is_high_latency",
main_thread_is_in_high_latency_mode);
TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
- "MainThreadLatency",
- main_thread_is_in_high_latency_mode);
- DCHECK_EQ(state_machine_.begin_impl_frame_state(),
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
- DCHECK(state_machine_.HasInitializedOutputSurface());
+ "MainThreadLatency", main_thread_is_in_high_latency_mode);
advance_commit_state_task_.Cancel();
- base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
begin_impl_frame_args_ = args;
- begin_impl_frame_args_.deadline -= draw_duration_estimate;
+ begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate();
if (!state_machine_.impl_latency_takes_priority() &&
main_thread_is_in_high_latency_mode &&
@@ -528,68 +504,115 @@ void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
}
- client_->WillBeginImplFrame(begin_impl_frame_args_);
- state_machine_.OnBeginImplFrame(begin_impl_frame_args_);
- devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
+ BeginImplFrame();
+ // The deadline will be scheduled in ProcessScheduledActions.
+ state_machine_.OnBeginImplFrameDeadlinePending();
ProcessScheduledActions();
+}
- state_machine_.OnBeginImplFrameDeadlinePending();
- ScheduleBeginImplFrameDeadline(
- AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
+void Scheduler::BeginImplFrameSynchronous(const BeginFrameArgs& args) {
+ TRACE_EVENT1("cc,benchmark", "Scheduler::BeginImplFrame", "args",
+ args.AsValue());
+ begin_impl_frame_args_ = args;
+ BeginImplFrame();
+ FinishImplFrame();
}
-base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
- const BeginFrameArgs& args,
- base::TimeDelta draw_duration_estimate) const {
- if (settings_.using_synchronous_renderer_compositor) {
- // The synchronous compositor needs to draw right away.
- return base::TimeTicks();
- } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
- // We are ready to draw a new active tree immediately.
- return base::TimeTicks();
- } else if (state_machine_.needs_redraw()) {
- // We have an animation or fast input path on the impl thread that wants
- // to draw, so don't wait too long for a new active tree.
- return args.deadline - draw_duration_estimate;
- } else {
- // The impl thread doesn't have anything it wants to draw and we are just
- // waiting for a new active tree, so post the deadline for the next
- // expected BeginImplFrame start. This allows us to draw immediately when
- // there is a new active tree, instead of waiting for the next
- // BeginImplFrame.
- // TODO(brianderson): Handle long deadlines (that are past the next frame's
- // frame time) properly instead of using this hack.
- return args.frame_time + args.interval;
- }
+void Scheduler::FinishImplFrame() {
+ state_machine_.OnBeginImplFrameIdle();
+ ProcessScheduledActions();
+
+ client_->DidFinishImplFrame();
+ frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
}
-void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
- TRACE_EVENT1(
- "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline);
- if (settings_.using_synchronous_renderer_compositor) {
- // The synchronous renderer compositor has to make its GL calls
- // within this call.
- // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
- // so the sychronous renderer compositor can take advantage of splitting
- // up the BeginImplFrame and deadline as well.
- OnBeginImplFrameDeadline();
- return;
- }
+// BeginImplFrame starts a compositor frame that will wait up until a deadline
+// for a BeginMainFrame+activation to complete before it times out and draws
+// any asynchronous animation and scroll/pinch updates.
+void Scheduler::BeginImplFrame() {
+ DCHECK_EQ(state_machine_.begin_impl_frame_state(),
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ DCHECK(!BeginImplFrameDeadlinePending());
+ DCHECK(state_machine_.HasInitializedOutputSurface());
+ DCHECK(advance_commit_state_task_.IsCancelled());
+
+ state_machine_.OnBeginImplFrame();
+ devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
+ client_->WillBeginImplFrame(begin_impl_frame_args_);
+
+ ProcessScheduledActions();
+}
+
+void Scheduler::ScheduleBeginImplFrameDeadline() {
+ // The synchronous compositor does not post a deadline task.
+ DCHECK(!settings_.using_synchronous_renderer_compositor);
+
begin_impl_frame_deadline_task_.Cancel();
begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
- base::TimeDelta delta = deadline - Now();
- if (delta <= base::TimeDelta())
- delta = base::TimeDelta();
+ begin_impl_frame_deadline_mode_ =
+ state_machine_.CurrentBeginImplFrameDeadlineMode();
+
+ base::TimeTicks deadline;
+ switch (begin_impl_frame_deadline_mode_) {
+ case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE:
+ // No deadline.
+ return;
+ case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE:
+ // We are ready to draw a new active tree immediately.
+ // We don't use Now() here because it's somewhat expensive to call.
+ deadline = base::TimeTicks();
+ break;
+ case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR:
+ // We are animating on the impl thread but we can wait for some time.
+ deadline = begin_impl_frame_args_.deadline;
+ break;
+ case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE:
+ // We are blocked for one reason or another and we should wait.
+ // TODO(brianderson): Handle long deadlines (that are past the next
+ // frame's frame time) properly instead of using this hack.
+ deadline =
+ begin_impl_frame_args_.frame_time + begin_impl_frame_args_.interval;
+ break;
+ case SchedulerStateMachine::
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW:
+ // We are blocked because we are waiting for ReadyToDraw signal. We would
+ // post deadline after we received ReadyToDraw singal.
+ TRACE_EVENT1("cc", "Scheduler::ScheduleBeginImplFrameDeadline",
+ "deadline_mode", "blocked_on_ready_to_draw");
+ return;
+ }
+
+ TRACE_EVENT2("cc", "Scheduler::ScheduleBeginImplFrameDeadline", "mode",
+ SchedulerStateMachine::BeginImplFrameDeadlineModeToString(
+ begin_impl_frame_deadline_mode_),
+ "deadline", deadline);
+
+ base::TimeDelta delta = std::max(deadline - Now(), base::TimeDelta());
task_runner_->PostDelayedTask(
FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
}
+void Scheduler::ScheduleBeginImplFrameDeadlineIfNeeded() {
+ if (settings_.using_synchronous_renderer_compositor)
+ return;
+
+ if (state_machine_.begin_impl_frame_state() !=
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
+ return;
+
+ if (begin_impl_frame_deadline_mode_ ==
+ state_machine_.CurrentBeginImplFrameDeadlineMode() &&
+ BeginImplFrameDeadlinePending())
+ return;
+
+ ScheduleBeginImplFrameDeadline();
+}
+
void Scheduler::OnBeginImplFrameDeadline() {
- TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
+ TRACE_EVENT0("cc,benchmark", "Scheduler::OnBeginImplFrameDeadline");
begin_impl_frame_deadline_task_.Cancel();
-
// We split the deadline actions up into two phases so the state machine
// has a chance to trigger actions that should occur durring and after
// the deadline separately. For example:
@@ -597,21 +620,16 @@ void Scheduler::OnBeginImplFrameDeadline() {
// order to wait for more user-input before starting the next commit.
// * Creating a new OuputSurface will not occur during the deadline in
// order to allow the state machine to "settle" first.
+
+ // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 Scheduler::OnBeginImplFrameDeadline1"));
state_machine_.OnBeginImplFrameDeadline();
ProcessScheduledActions();
- state_machine_.OnBeginImplFrameIdle();
- ProcessScheduledActions();
-
- client_->DidBeginImplFrameDeadline();
+ FinishImplFrame();
}
-void Scheduler::PollForAnticipatedDrawTriggers() {
- TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
- poll_for_draw_triggers_task_.Cancel();
- state_machine_.DidEnterPollForAnticipatedDrawTriggers();
- ProcessScheduledActions();
- state_machine_.DidLeavePollForAnticipatedDrawTriggers();
-}
void Scheduler::PollToAdvanceCommitState() {
TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
@@ -624,6 +642,14 @@ void Scheduler::DrawAndSwapIfPossible() {
state_machine_.DidDrawIfPossibleCompleted(result);
}
+void Scheduler::SetDeferCommits(bool defer_commits) {
+ TRACE_EVENT1("cc", "Scheduler::SetDeferCommits",
+ "defer_commits",
+ defer_commits);
+ state_machine_.SetDeferCommits(defer_commits);
+ ProcessScheduledActions();
+}
+
void Scheduler::ProcessScheduledActions() {
// We do not allow ProcessScheduledActions to be recursive.
// The top-level call will iteratively execute the next action for us anyway.
@@ -654,18 +680,27 @@ void Scheduler::ProcessScheduledActions() {
case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
client_->ScheduledActionSendBeginMainFrame();
break;
- case SchedulerStateMachine::ACTION_COMMIT:
+ case SchedulerStateMachine::ACTION_COMMIT: {
+ // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 Scheduler::ProcessScheduledActions4"));
client_->ScheduledActionCommit();
break;
- case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
- client_->ScheduledActionUpdateVisibleTiles();
- break;
+ }
case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE:
client_->ScheduledActionActivateSyncTree();
break;
- case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
+ case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
+ // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile6(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 Scheduler::ProcessScheduledActions6"));
DrawAndSwapIfPossible();
break;
+ }
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
client_->ScheduledActionDrawAndSwapForced();
break;
@@ -676,36 +711,36 @@ void Scheduler::ProcessScheduledActions() {
case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
client_->ScheduledActionBeginOutputSurfaceCreation();
break;
- case SchedulerStateMachine::ACTION_MANAGE_TILES:
- client_->ScheduledActionManageTiles();
+ case SchedulerStateMachine::ACTION_PREPARE_TILES:
+ client_->ScheduledActionPrepareTiles();
+ break;
+ case SchedulerStateMachine::ACTION_INVALIDATE_OUTPUT_SURFACE: {
+ client_->ScheduledActionInvalidateOutputSurface();
break;
+ }
}
} while (action != SchedulerStateMachine::ACTION_NONE);
- SetupNextBeginFrameIfNeeded();
+ SetupPollingMechanisms();
+
client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
- if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
- DCHECK(!settings_.using_synchronous_renderer_compositor);
- ScheduleBeginImplFrameDeadline(base::TimeTicks());
- }
-}
+ ScheduleBeginImplFrameDeadlineIfNeeded();
-bool Scheduler::WillDrawIfNeeded() const {
- return !state_machine_.PendingDrawsShouldBeAborted();
+ SetupNextBeginFrameIfNeeded();
}
-scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue()
+scoped_refptr<base::trace_event::ConvertableToTraceFormat> Scheduler::AsValue()
const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
AsValueInto(state.get());
return state;
}
-void Scheduler::AsValueInto(base::debug::TracedValue* state) const {
+void Scheduler::AsValueInto(base::trace_event::TracedValue* state) const {
state->BeginDictionary("state_machine");
- state_machine_.AsValueInto(state, Now());
+ state_machine_.AsValueInto(state);
state->EndDictionary();
// Only trace frame sources when explicitly enabled - http://crbug.com/420607
@@ -726,18 +761,34 @@ void Scheduler::AsValueInto(base::debug::TracedValue* state) const {
estimated_parent_draw_time_.InMillisecondsF());
state->SetBoolean("last_set_needs_begin_frame_",
frame_source_->NeedsBeginFrames());
- state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_);
state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size());
+ state->SetBoolean("begin_retro_frame_task_",
+ !begin_retro_frame_task_.IsCancelled());
state->SetBoolean("begin_impl_frame_deadline_task_",
!begin_impl_frame_deadline_task_.IsCancelled());
- state->SetBoolean("poll_for_draw_triggers_task_",
- !poll_for_draw_triggers_task_.IsCancelled());
state->SetBoolean("advance_commit_state_task_",
!advance_commit_state_task_.IsCancelled());
state->BeginDictionary("begin_impl_frame_args");
begin_impl_frame_args_.AsValueInto(state);
state->EndDictionary();
+ base::TimeTicks now = Now();
+ base::TimeTicks frame_time = begin_impl_frame_args_.frame_time;
+ base::TimeTicks deadline = begin_impl_frame_args_.deadline;
+ base::TimeDelta interval = begin_impl_frame_args_.interval;
+ state->BeginDictionary("major_timestamps_in_ms");
+ state->SetDouble("0_interval", interval.InMillisecondsF());
+ state->SetDouble("1_now_to_deadline", (deadline - now).InMillisecondsF());
+ state->SetDouble("2_frame_time_to_now", (now - frame_time).InMillisecondsF());
+ state->SetDouble("3_frame_time_to_deadline",
+ (deadline - frame_time).InMillisecondsF());
+ state->SetDouble("4_now", (now - base::TimeTicks()).InMillisecondsF());
+ state->SetDouble("5_frame_time",
+ (frame_time - base::TimeTicks()).InMillisecondsF());
+ state->SetDouble("6_deadline",
+ (deadline - base::TimeTicks()).InMillisecondsF());
+ state->EndDictionary();
+
state->EndDictionary();
state->BeginDictionary("client_state");
diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h
index f470d17a9e7..13daf008cc3 100644
--- a/chromium/cc/scheduler/scheduler.h
+++ b/chromium/cc/scheduler/scheduler.h
@@ -11,8 +11,6 @@
#include "base/basictypes.h"
#include "base/cancelable_callback.h"
#include "base/memory/scoped_ptr.h"
-#include "base/power_monitor/power_monitor.h"
-#include "base/power_monitor/power_observer.h"
#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/output/begin_frame_args.h"
@@ -24,7 +22,7 @@
#include "cc/scheduler/scheduler_state_machine.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
}
class SingleThreadTaskRunner;
@@ -34,22 +32,23 @@ namespace cc {
class SchedulerClient {
public:
- virtual BeginFrameSource* ExternalBeginFrameSource() = 0;
virtual void WillBeginImplFrame(const BeginFrameArgs& args) = 0;
virtual void ScheduledActionSendBeginMainFrame() = 0;
virtual DrawResult ScheduledActionDrawAndSwapIfPossible() = 0;
virtual DrawResult ScheduledActionDrawAndSwapForced() = 0;
virtual void ScheduledActionAnimate() = 0;
virtual void ScheduledActionCommit() = 0;
- virtual void ScheduledActionUpdateVisibleTiles() = 0;
virtual void ScheduledActionActivateSyncTree() = 0;
virtual void ScheduledActionBeginOutputSurfaceCreation() = 0;
- virtual void ScheduledActionManageTiles() = 0;
+ virtual void ScheduledActionPrepareTiles() = 0;
+ virtual void ScheduledActionInvalidateOutputSurface() = 0;
virtual void DidAnticipatedDrawTimeChange(base::TimeTicks time) = 0;
virtual base::TimeDelta DrawDurationEstimate() = 0;
virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() = 0;
virtual base::TimeDelta CommitToActivateDurationEstimate() = 0;
- virtual void DidBeginImplFrameDeadline() = 0;
+ virtual void DidFinishImplFrame() = 0;
+ virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) = 0;
+ virtual void SendBeginMainFrameNotExpectedSoon() = 0;
protected:
virtual ~SchedulerClient() {}
@@ -64,7 +63,7 @@ class CC_EXPORT SchedulerFrameSourcesConstructor {
public:
virtual ~SchedulerFrameSourcesConstructor() {}
virtual BeginFrameSource* ConstructPrimaryFrameSource(Scheduler* scheduler);
- virtual BeginFrameSource* ConstructBackgroundFrameSource(
+ virtual BeginFrameSource* ConstructUnthrottledFrameSource(
Scheduler* scheduler);
protected:
@@ -73,28 +72,29 @@ class CC_EXPORT SchedulerFrameSourcesConstructor {
friend class Scheduler;
};
-class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
- public base::PowerObserver {
+class CC_EXPORT Scheduler : public BeginFrameObserverMixIn {
public:
static scoped_ptr<Scheduler> Create(
SchedulerClient* client,
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- base::PowerMonitor* power_monitor) {
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
SchedulerFrameSourcesConstructor frame_sources_constructor;
return make_scoped_ptr(new Scheduler(client,
scheduler_settings,
layer_tree_host_id,
task_runner,
- power_monitor,
+ external_begin_frame_source.Pass(),
&frame_sources_constructor));
}
~Scheduler() override;
- // base::PowerObserver method.
- void OnPowerStateChange(bool on_battery_power) override;
+ // BeginFrameObserverMixin
+ bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) override;
+
+ void OnDrawForOutputSurface();
const SchedulerSettings& settings() const { return settings_; }
@@ -107,6 +107,8 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
void SetVisible(bool visible);
void SetCanDraw(bool can_draw);
void NotifyReadyToActivate();
+ void NotifyReadyToDraw();
+ void SetThrottleFrameProduction(bool throttle);
void SetNeedsCommit();
@@ -114,19 +116,20 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
void SetNeedsAnimate();
- void SetNeedsManageTiles();
+ void SetNeedsPrepareTiles();
+
+ void SetWaitForReadyToDraw();
void SetMaxSwapsPending(int max);
void DidSwapBuffers();
- void SetSwapUsedIncompleteTile(bool used_incomplete_tile);
void DidSwapBuffersComplete();
void SetImplLatencyTakesPriority(bool impl_latency_takes_priority);
void NotifyReadyToCommit();
- void BeginMainFrameAborted(bool did_handle);
+ void BeginMainFrameAborted(CommitEarlyOutReason reason);
- void DidManageTiles();
+ void DidPrepareTiles();
void DidLoseOutputSurface();
void DidCreateAndInitializeOutputSurface();
@@ -139,8 +142,8 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
bool CommitPending() const { return state_machine_.CommitPending(); }
bool RedrawPending() const { return state_machine_.RedrawPending(); }
- bool ManageTilesPending() const {
- return state_machine_.ManageTilesPending();
+ bool PrepareTilesPending() const {
+ return state_machine_.PrepareTilesPending();
}
bool MainThreadIsInHighLatencyMode() const {
return state_machine_.MainThreadIsInHighLatencyMode();
@@ -149,30 +152,32 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
return !begin_impl_frame_deadline_task_.IsCancelled();
}
- bool WillDrawIfNeeded() const;
-
base::TimeTicks AnticipatedDrawTime() const;
void NotifyBeginMainFrameStarted();
base::TimeTicks LastBeginImplFrameTime();
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
- void AsValueInto(base::debug::TracedValue* value) const override;
+ void SetDeferCommits(bool defer_commits);
+
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+ void AsValueInto(base::trace_event::TracedValue* value) const override;
void SetContinuousPainting(bool continuous_painting) {
state_machine_.SetContinuousPainting(continuous_painting);
}
- // BeginFrameObserverMixin
- bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) override;
+ void SetChildrenNeedBeginFrames(bool children_need_begin_frames);
+ void SetVideoNeedsBeginFrames(bool video_needs_begin_frames);
+
+ void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval);
protected:
Scheduler(SchedulerClient* client,
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- base::PowerMonitor* power_monitor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source,
SchedulerFrameSourcesConstructor* frame_sources_constructor);
// virtual for testing - Don't call these in the constructor or
@@ -181,35 +186,35 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
scoped_ptr<BeginFrameSourceMultiplexer> frame_source_;
BeginFrameSource* primary_frame_source_;
- BeginFrameSource* background_frame_source_;
+ BeginFrameSource* unthrottled_frame_source_;
// Storage when frame sources are internal
scoped_ptr<BeginFrameSource> primary_frame_source_internal_;
- scoped_ptr<SyntheticBeginFrameSource> background_frame_source_internal_;
+ scoped_ptr<BeginFrameSource> unthrottled_frame_source_internal_;
VSyncParameterObserver* vsync_observer_;
+ base::TimeDelta authoritative_vsync_interval_;
+ base::TimeTicks last_vsync_timebase_;
+
+ bool throttle_frame_production_;
const SchedulerSettings settings_;
SchedulerClient* client_;
int layer_tree_host_id_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- base::PowerMonitor* power_monitor_;
-
base::TimeDelta estimated_parent_draw_time_;
- bool begin_retro_frame_posted_;
std::deque<BeginFrameArgs> begin_retro_frame_args_;
BeginFrameArgs begin_impl_frame_args_;
+ SchedulerStateMachine::BeginImplFrameDeadlineMode
+ begin_impl_frame_deadline_mode_;
base::Closure begin_retro_frame_closure_;
- base::Closure begin_unthrottled_frame_closure_;
-
base::Closure begin_impl_frame_deadline_closure_;
- base::Closure poll_for_draw_triggers_closure_;
base::Closure advance_commit_state_closure_;
+ base::CancelableClosure begin_retro_frame_task_;
base::CancelableClosure begin_impl_frame_deadline_task_;
- base::CancelableClosure poll_for_draw_triggers_task_;
base::CancelableClosure advance_commit_state_task_;
SchedulerStateMachine state_machine_;
@@ -217,25 +222,23 @@ class CC_EXPORT Scheduler : public BeginFrameObserverMixIn,
SchedulerStateMachine::Action inside_action_;
private:
- base::TimeTicks AdjustedBeginImplFrameDeadline(
- const BeginFrameArgs& args,
- base::TimeDelta draw_duration_estimate) const;
- void ScheduleBeginImplFrameDeadline(base::TimeTicks deadline);
+ void ScheduleBeginImplFrameDeadline();
+ void ScheduleBeginImplFrameDeadlineIfNeeded();
void SetupNextBeginFrameIfNeeded();
void PostBeginRetroFrameIfNeeded();
- void SetupPollingMechanisms(bool needs_begin_frame);
+ void SetupPollingMechanisms();
void DrawAndSwapIfPossible();
void ProcessScheduledActions();
bool CanCommitAndActivateBeforeDeadline() const;
void AdvanceCommitStateIfPossible();
bool IsBeginMainFrameSentOrStarted() const;
void BeginRetroFrame();
- void BeginImplFrame(const BeginFrameArgs& args);
+ void BeginImplFrameWithDeadline(const BeginFrameArgs& args);
+ void BeginImplFrameSynchronous(const BeginFrameArgs& args);
+ void BeginImplFrame();
+ void FinishImplFrame();
void OnBeginImplFrameDeadline();
- void PollForAnticipatedDrawTriggers();
void PollToAdvanceCommitState();
- void SetupPowerMonitoring();
- void TeardownPowerMonitoring();
base::TimeDelta EstimatedParentDrawTime() {
return estimated_parent_draw_time_;
diff --git a/chromium/cc/scheduler/scheduler_settings.cc b/chromium/cc/scheduler/scheduler_settings.cc
index ab9add087bd..c6c8e8eb2db 100644
--- a/chromium/cc/scheduler/scheduler_settings.cc
+++ b/chromium/cc/scheduler/scheduler_settings.cc
@@ -4,46 +4,30 @@
#include "cc/scheduler/scheduler_settings.h"
-#include "base/debug/trace_event_argument.h"
-#include "cc/trees/layer_tree_settings.h"
+#include "base/trace_event/trace_event_argument.h"
namespace cc {
SchedulerSettings::SchedulerSettings()
- : begin_frame_scheduling_enabled(true),
+ : use_external_begin_frame_source(false),
main_frame_before_activation_enabled(false),
impl_side_painting(false),
timeout_and_draw_when_animation_checkerboards(true),
maximum_number_of_failed_draws_before_draw_is_forced_(3),
using_synchronous_renderer_compositor(false),
throttle_frame_production(true),
- disable_hi_res_timer_tasks_on_battery(false) {
-}
-
-SchedulerSettings::SchedulerSettings(const LayerTreeSettings& settings)
- : begin_frame_scheduling_enabled(settings.begin_frame_scheduling_enabled),
- main_frame_before_activation_enabled(
- settings.main_frame_before_activation_enabled),
- impl_side_painting(settings.impl_side_painting),
- timeout_and_draw_when_animation_checkerboards(
- settings.timeout_and_draw_when_animation_checkerboards),
- maximum_number_of_failed_draws_before_draw_is_forced_(
- settings.maximum_number_of_failed_draws_before_draw_is_forced_),
- using_synchronous_renderer_compositor(
- settings.using_synchronous_renderer_compositor),
- throttle_frame_production(settings.throttle_frame_production),
- disable_hi_res_timer_tasks_on_battery(
- settings.disable_hi_res_timer_tasks_on_battery) {
+ main_thread_should_always_be_low_latency(false),
+ background_frame_interval(base::TimeDelta::FromSeconds(1)) {
}
SchedulerSettings::~SchedulerSettings() {}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
SchedulerSettings::AsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
- state->SetBoolean("begin_frame_scheduling_enabled",
- begin_frame_scheduling_enabled);
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
+ state->SetBoolean("use_external_begin_frame_source",
+ use_external_begin_frame_source);
state->SetBoolean("main_frame_before_activation_enabled",
main_frame_before_activation_enabled);
state->SetBoolean("impl_side_painting", impl_side_painting);
@@ -54,8 +38,10 @@ SchedulerSettings::AsValue() const {
state->SetBoolean("using_synchronous_renderer_compositor",
using_synchronous_renderer_compositor);
state->SetBoolean("throttle_frame_production", throttle_frame_production);
- state->SetBoolean("disable_hi_res_timer_tasks_on_battery",
- disable_hi_res_timer_tasks_on_battery);
+ state->SetBoolean("main_thread_should_always_be_low_latency",
+ main_thread_should_always_be_low_latency);
+ state->SetInteger("background_frame_interval",
+ background_frame_interval.InMicroseconds());
return state;
}
diff --git a/chromium/cc/scheduler/scheduler_settings.h b/chromium/cc/scheduler/scheduler_settings.h
index 8607991914e..421409ab4dc 100644
--- a/chromium/cc/scheduler/scheduler_settings.h
+++ b/chromium/cc/scheduler/scheduler_settings.h
@@ -6,34 +6,40 @@
#define CC_SCHEDULER_SCHEDULER_SETTINGS_H_
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "cc/base/cc_export.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
}
}
namespace cc {
-class LayerTreeSettings;
class CC_EXPORT SchedulerSettings {
public:
SchedulerSettings();
- explicit SchedulerSettings(const LayerTreeSettings& settings);
~SchedulerSettings();
- bool begin_frame_scheduling_enabled;
+ bool use_external_begin_frame_source;
bool main_frame_before_activation_enabled;
bool impl_side_painting;
bool timeout_and_draw_when_animation_checkerboards;
int maximum_number_of_failed_draws_before_draw_is_forced_;
bool using_synchronous_renderer_compositor;
bool throttle_frame_production;
- bool disable_hi_res_timer_tasks_on_battery;
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
+ // In main thread low latency mode the entire
+ // BeginMainFrame->Commit->Activation->Draw cycle should complete before
+ // starting the next cycle. Additionally, BeginMainFrame and Commit are
+ // completed atomically with no other tasks or actions occuring between them.
+ bool main_thread_should_always_be_low_latency;
+
+ base::TimeDelta background_frame_interval;
+
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
};
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc
index 2b8210d2d2f..e303d3ab48a 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine.cc
@@ -4,11 +4,11 @@
#include "cc/scheduler/scheduler_state_machine.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "ui/gfx/frame_time.h"
@@ -26,30 +26,37 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
last_frame_number_swap_performed_(-1),
last_frame_number_swap_requested_(-1),
last_frame_number_begin_main_frame_sent_(-1),
- last_frame_number_update_visible_tiles_was_called_(-1),
- manage_tiles_funnel_(0),
+ last_frame_number_invalidate_output_surface_performed_(-1),
+ animate_funnel_(false),
+ request_swap_funnel_(false),
+ send_begin_main_frame_funnel_(false),
+ invalidate_output_surface_funnel_(false),
+ prepare_tiles_funnel_(0),
consecutive_checkerboard_animations_(0),
max_pending_swaps_(1),
pending_swaps_(0),
needs_redraw_(false),
needs_animate_(false),
- needs_manage_tiles_(false),
- swap_used_incomplete_tile_(false),
+ needs_prepare_tiles_(false),
needs_commit_(false),
- inside_poll_for_anticipated_draw_triggers_(false),
visible_(false),
can_start_(false),
can_draw_(false),
has_pending_tree_(false),
pending_tree_is_ready_for_activation_(false),
active_tree_needs_first_draw_(false),
- did_commit_after_animating_(false),
did_create_and_initialize_first_output_surface_(false),
impl_latency_takes_priority_(false),
skip_next_begin_main_frame_to_reduce_latency_(false),
skip_begin_main_frame_to_reduce_latency_(false),
continuous_painting_(false),
- impl_latency_takes_priority_on_battery_(false) {
+ children_need_begin_frames_(false),
+ defer_commits_(false),
+ video_needs_begin_frames_(false),
+ last_commit_had_no_updates_(false),
+ wait_for_active_tree_ready_to_draw_(false),
+ did_request_swap_in_last_frame_(false),
+ did_perform_swap_in_last_draw_(false) {
}
const char* SchedulerStateMachine::OutputSurfaceStateToString(
@@ -86,6 +93,24 @@ const char* SchedulerStateMachine::BeginImplFrameStateToString(
return "???";
}
+const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString(
+ BeginImplFrameDeadlineMode mode) {
+ switch (mode) {
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE";
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE";
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR";
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE";
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW:
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW";
+ }
+ NOTREACHED();
+ return "???";
+}
+
const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
switch (state) {
case COMMIT_STATE_IDLE:
@@ -98,6 +123,8 @@ const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
return "COMMIT_STATE_READY_TO_COMMIT";
case COMMIT_STATE_WAITING_FOR_ACTIVATION:
return "COMMIT_STATE_WAITING_FOR_ACTIVATION";
+ case COMMIT_STATE_WAITING_FOR_DRAW:
+ return "COMMIT_STATE_WAITING_FOR_DRAW";
}
NOTREACHED();
return "???";
@@ -129,8 +156,6 @@ const char* SchedulerStateMachine::ActionToString(Action action) {
return "ACTION_SEND_BEGIN_MAIN_FRAME";
case ACTION_COMMIT:
return "ACTION_COMMIT";
- case ACTION_UPDATE_VISIBLE_TILES:
- return "ACTION_UPDATE_VISIBLE_TILES";
case ACTION_ACTIVATE_SYNC_TREE:
return "ACTION_ACTIVATE_SYNC_TREE";
case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
@@ -141,23 +166,25 @@ const char* SchedulerStateMachine::ActionToString(Action action) {
return "ACTION_DRAW_AND_SWAP_ABORT";
case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION";
- case ACTION_MANAGE_TILES:
- return "ACTION_MANAGE_TILES";
+ case ACTION_PREPARE_TILES:
+ return "ACTION_PREPARE_TILES";
+ case ACTION_INVALIDATE_OUTPUT_SURFACE:
+ return "ACTION_INVALIDATE_OUTPUT_SURFACE";
}
NOTREACHED();
return "???";
}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
SchedulerStateMachine::AsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
- AsValueInto(state.get(), gfx::FrameTime::Now());
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
+ AsValueInto(state.get());
return state;
}
-void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
- base::TimeTicks now) const {
+void SchedulerStateMachine::AsValueInto(
+ base::trace_event::TracedValue* state) const {
state->BeginDictionary("major_state");
state->SetString("next_action", ActionToString(NextAction()));
state->SetString("begin_impl_frame_state",
@@ -169,35 +196,9 @@ void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
state->EndDictionary();
- state->BeginDictionary("major_timestamps_in_ms");
- state->SetDouble("0_interval",
- begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L);
- state->SetDouble(
- "1_now_to_deadline",
- (begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
- state->SetDouble(
- "2_frame_time_to_now",
- (now - begin_impl_frame_args_.frame_time).InMicroseconds() / 1000.0L);
- state->SetDouble("3_frame_time_to_deadline",
- (begin_impl_frame_args_.deadline -
- begin_impl_frame_args_.frame_time).InMicroseconds() /
- 1000.0L);
- state->SetDouble("4_now",
- (now - base::TimeTicks()).InMicroseconds() / 1000.0L);
- state->SetDouble(
- "5_frame_time",
- (begin_impl_frame_args_.frame_time - base::TimeTicks()).InMicroseconds() /
- 1000.0L);
- state->SetDouble(
- "6_deadline",
- (begin_impl_frame_args_.deadline - base::TimeTicks()).InMicroseconds() /
- 1000.0L);
- state->EndDictionary();
-
state->BeginDictionary("minor_state");
state->SetInteger("commit_count", commit_count_);
state->SetInteger("current_frame_number", current_frame_number_);
-
state->SetInteger("last_frame_number_animate_performed",
last_frame_number_animate_performed_);
state->SetInteger("last_frame_number_swap_performed",
@@ -206,18 +207,20 @@ void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
last_frame_number_swap_requested_);
state->SetInteger("last_frame_number_begin_main_frame_sent",
last_frame_number_begin_main_frame_sent_);
- state->SetInteger("last_frame_number_update_visible_tiles_was_called",
- last_frame_number_update_visible_tiles_was_called_);
-
- state->SetInteger("manage_tiles_funnel", manage_tiles_funnel_);
+ state->SetBoolean("funnel: animate_funnel", animate_funnel_);
+ state->SetBoolean("funnel: request_swap_funnel", request_swap_funnel_);
+ state->SetBoolean("funnel: send_begin_main_frame_funnel",
+ send_begin_main_frame_funnel_);
+ state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_);
+ state->SetBoolean("funnel: invalidate_output_surface_funnel",
+ invalidate_output_surface_funnel_);
state->SetInteger("consecutive_checkerboard_animations",
consecutive_checkerboard_animations_);
state->SetInteger("max_pending_swaps_", max_pending_swaps_);
state->SetInteger("pending_swaps_", pending_swaps_);
state->SetBoolean("needs_redraw", needs_redraw_);
state->SetBoolean("needs_animate_", needs_animate_);
- state->SetBoolean("needs_manage_tiles", needs_manage_tiles_);
- state->SetBoolean("swap_used_incomplete_tile", swap_used_incomplete_tile_);
+ state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_);
state->SetBoolean("needs_commit", needs_commit_);
state->SetBoolean("visible", visible_);
state->SetBoolean("can_start", can_start_);
@@ -227,7 +230,8 @@ void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
pending_tree_is_ready_for_activation_);
state->SetBoolean("active_tree_needs_first_draw",
active_tree_needs_first_draw_);
- state->SetBoolean("did_commit_after_animating", did_commit_after_animating_);
+ state->SetBoolean("wait_for_active_tree_ready_to_draw",
+ wait_for_active_tree_ready_to_draw_);
state->SetBoolean("did_create_and_initialize_first_output_surface",
did_create_and_initialize_first_output_surface_);
state->SetBoolean("impl_latency_takes_priority",
@@ -239,45 +243,17 @@ void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency",
skip_next_begin_main_frame_to_reduce_latency_);
state->SetBoolean("continuous_painting", continuous_painting_);
- state->SetBoolean("impl_latency_takes_priority_on_battery",
- impl_latency_takes_priority_on_battery_);
+ state->SetBoolean("children_need_begin_frames", children_need_begin_frames_);
+ state->SetBoolean("video_needs_begin_frames", video_needs_begin_frames_);
+ state->SetBoolean("defer_commits", defer_commits_);
+ state->SetBoolean("last_commit_had_no_updates", last_commit_had_no_updates_);
+ state->SetBoolean("did_request_swap_in_last_frame",
+ did_request_swap_in_last_frame_);
+ state->SetBoolean("did_perform_swap_in_last_draw",
+ did_perform_swap_in_last_draw_);
state->EndDictionary();
}
-void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
- current_frame_number_++;
-
- // "Drain" the ManageTiles funnel.
- if (manage_tiles_funnel_ > 0)
- manage_tiles_funnel_--;
-
- skip_begin_main_frame_to_reduce_latency_ =
- skip_next_begin_main_frame_to_reduce_latency_;
- skip_next_begin_main_frame_to_reduce_latency_ = false;
-}
-
-bool SchedulerStateMachine::HasAnimatedThisFrame() const {
- return last_frame_number_animate_performed_ == current_frame_number_;
-}
-
-bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const {
- return current_frame_number_ ==
- last_frame_number_begin_main_frame_sent_;
-}
-
-bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
- return current_frame_number_ ==
- last_frame_number_update_visible_tiles_was_called_;
-}
-
-bool SchedulerStateMachine::HasSwappedThisFrame() const {
- return current_frame_number_ == last_frame_number_swap_performed_;
-}
-
-bool SchedulerStateMachine::HasRequestedSwapThisFrame() const {
- return current_frame_number_ == last_frame_number_swap_requested_;
-}
-
bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
// These are all the cases where we normally cannot or do not want to draw
// but, if needs_redraw_ is true and we do not draw to make forward progress,
@@ -329,7 +305,7 @@ bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE)
return false;
- // We want to clear the pipline of any pending draws and activations
+ // We want to clear the pipeline of any pending draws and activations
// before starting output surface initialization. This allows us to avoid
// weird corner cases where we abort draws or force activation while we
// are initializing the output surface.
@@ -344,19 +320,20 @@ bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
bool SchedulerStateMachine::ShouldDraw() const {
// If we need to abort draws, we should do so ASAP since the draw could
// be blocking other important actions (like output surface initialization),
- // from occuring. If we are waiting for the first draw, then perfom the
+ // from occurring. If we are waiting for the first draw, then perform the
// aborted draw to keep things moving. If we are not waiting for the first
// draw however, we don't want to abort for no reason.
if (PendingDrawsShouldBeAborted())
return active_tree_needs_first_draw_;
- // If a commit has occurred after the animate call, we need to call animate
- // again before we should draw.
- if (did_commit_after_animating_)
+ // Do not draw too many times in a single frame. It's okay that we don't check
+ // this before checking for aborted draws because aborted draws do not request
+ // a swap.
+ if (request_swap_funnel_)
return false;
- // After this line, we only want to send a swap request once per frame.
- if (HasRequestedSwapThisFrame())
+ // Don't draw if we are waiting on the first commit after a surface.
+ if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
return false;
// Do not queue too many swaps.
@@ -394,40 +371,13 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const {
return pending_tree_is_ready_for_activation_;
}
-bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
- if (!settings_.impl_side_painting)
- return false;
- if (HasUpdatedVisibleTilesThisFrame())
- return false;
-
- // We don't want to update visible tiles right after drawing.
- if (HasRequestedSwapThisFrame())
- return false;
-
- // There's no reason to check for tiles if we don't have an output surface.
- if (!HasInitializedOutputSurface())
- return false;
-
- // We should not check for visible tiles until we've entered the deadline so
- // we check as late as possible and give the tiles more time to initialize.
- if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
- return false;
-
- // If the last swap drew with checkerboard or missing tiles, we should
- // poll for any new visible tiles so we can be notified to draw again
- // when there are.
- if (swap_used_incomplete_tile_)
- return true;
-
- return false;
-}
-
bool SchedulerStateMachine::ShouldAnimate() const {
- if (!can_draw_)
+ // Do not animate too many times in a single frame.
+ if (animate_funnel_)
return false;
- // If a commit occurred after our last call, we need to do animation again.
- if (HasAnimatedThisFrame() && !did_commit_after_animating_)
+ // Don't animate if we are waiting on the first commit after a surface.
+ if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
return false;
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING &&
@@ -445,6 +395,10 @@ bool SchedulerStateMachine::CouldSendBeginMainFrame() const {
if (!visible_)
return false;
+ // Do not make a new commits when it is deferred.
+ if (defer_commits_)
+ return false;
+
return true;
}
@@ -452,6 +406,10 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (!CouldSendBeginMainFrame())
return false;
+ // Do not send begin main frame too many times in a single frame.
+ if (send_begin_main_frame_funnel_)
+ return false;
+
// Only send BeginMainFrame when there isn't another commit pending already.
if (commit_state_ != COMMIT_STATE_IDLE)
return false;
@@ -463,10 +421,6 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
return false;
}
- // We want to start the first commit after we get a new output surface ASAP.
- if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT)
- return true;
-
// We should not send BeginMainFrame while we are in
// BEGIN_IMPL_FRAME_STATE_IDLE since we might have new
// user input arriving soon.
@@ -481,10 +435,6 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
return true;
- // After this point, we only start a commit once per frame.
- if (HasSentBeginMainFrameThisFrame())
- return false;
-
// We shouldn't normally accept commits if there isn't an OutputSurface.
if (!HasInitializedOutputSurface())
return false;
@@ -493,7 +443,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
// TODO(brianderson): Remove this restriction to improve throughput.
bool just_swapped_in_deadline =
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
- HasSwappedThisFrame();
+ did_perform_swap_in_last_draw_;
if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline)
return false;
@@ -520,25 +470,41 @@ bool SchedulerStateMachine::ShouldCommit() const {
return true;
}
-bool SchedulerStateMachine::ShouldManageTiles() const {
- // ManageTiles only really needs to be called immediately after commit
+bool SchedulerStateMachine::ShouldPrepareTiles() const {
+ // PrepareTiles only really needs to be called immediately after commit
// and then periodically after that. Use a funnel to make sure we average
- // one ManageTiles per BeginImplFrame in the long run.
- if (manage_tiles_funnel_ > 0)
+ // one PrepareTiles per BeginImplFrame in the long run.
+ if (prepare_tiles_funnel_ > 0)
return false;
// Limiting to once per-frame is not enough, since we only want to
- // manage tiles _after_ draws. Polling for draw triggers and
- // begin-frame are mutually exclusive, so we limit to these two cases.
- if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
- !inside_poll_for_anticipated_draw_triggers_)
+ // prepare tiles _after_ draws.
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
return false;
- return needs_manage_tiles_;
+
+ return needs_prepare_tiles_;
+}
+
+bool SchedulerStateMachine::ShouldInvalidateOutputSurface() const {
+ // Do not invalidate too many times in a frame.
+ if (invalidate_output_surface_funnel_)
+ return false;
+
+ // Only the synchronous compositor requires invalidations.
+ if (!settings_.using_synchronous_renderer_compositor)
+ return false;
+
+ // Invalidations are only performed inside a BeginFrame.
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
+ return false;
+
+ // TODO(sunnyps): needs_prepare_tiles_ is needed here because PrepareTiles is
+ // called only inside the deadline / draw phase. We could remove this if we
+ // allowed PrepareTiles to happen in OnBeginImplFrame.
+ return needs_redraw_ || needs_prepare_tiles_;
}
SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
- if (ShouldUpdateVisibleTiles())
- return ACTION_UPDATE_VISIBLE_TILES;
if (ShouldActivatePendingTree())
return ACTION_ACTIVATE_SYNC_TREE;
if (ShouldCommit())
@@ -553,10 +519,12 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
else
return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
}
- if (ShouldManageTiles())
- return ACTION_MANAGE_TILES;
+ if (ShouldPrepareTiles())
+ return ACTION_PREPARE_TILES;
if (ShouldSendBeginMainFrame())
return ACTION_SEND_BEGIN_MAIN_FRAME;
+ if (ShouldInvalidateOutputSurface())
+ return ACTION_INVALIDATE_OUTPUT_SURFACE;
if (ShouldBeginOutputSurfaceCreation())
return ACTION_BEGIN_OUTPUT_SURFACE_CREATION;
return ACTION_NONE;
@@ -567,37 +535,21 @@ void SchedulerStateMachine::UpdateState(Action action) {
case ACTION_NONE:
return;
- case ACTION_UPDATE_VISIBLE_TILES:
- last_frame_number_update_visible_tiles_was_called_ =
- current_frame_number_;
- return;
-
case ACTION_ACTIVATE_SYNC_TREE:
UpdateStateOnActivation();
return;
case ACTION_ANIMATE:
- last_frame_number_animate_performed_ = current_frame_number_;
- needs_animate_ = false;
- did_commit_after_animating_ = false;
- // TODO(skyostil): Instead of assuming this, require the client to tell
- // us.
- SetNeedsRedraw();
+ UpdateStateOnAnimate();
return;
case ACTION_SEND_BEGIN_MAIN_FRAME:
- DCHECK(!has_pending_tree_ ||
- settings_.main_frame_before_activation_enabled);
- DCHECK(visible_);
- commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
- needs_commit_ = false;
- last_frame_number_begin_main_frame_sent_ =
- current_frame_number_;
+ UpdateStateOnSendBeginMainFrame();
return;
case ACTION_COMMIT: {
- bool commit_was_aborted = false;
- UpdateStateOnCommit(commit_was_aborted);
+ bool commit_has_no_updates = false;
+ UpdateStateOnCommit(commit_has_no_updates);
return;
}
@@ -615,40 +567,58 @@ void SchedulerStateMachine::UpdateState(Action action) {
}
case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
- DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
- output_surface_state_ = OUTPUT_SURFACE_CREATING;
-
- // The following DCHECKs make sure we are in the proper quiescent state.
- // The pipeline should be flushed entirely before we start output
- // surface creation to avoid complicated corner cases.
- DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
- DCHECK(!has_pending_tree_);
- DCHECK(!active_tree_needs_first_draw_);
+ UpdateStateOnBeginOutputSurfaceCreation();
+ return;
+
+ case ACTION_PREPARE_TILES:
+ UpdateStateOnPrepareTiles();
return;
- case ACTION_MANAGE_TILES:
- UpdateStateOnManageTiles();
+ case ACTION_INVALIDATE_OUTPUT_SURFACE:
+ UpdateStateOnInvalidateOutputSurface();
return;
}
}
-void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
+void SchedulerStateMachine::UpdateStateOnAnimate() {
+ DCHECK(!animate_funnel_);
+ last_frame_number_animate_performed_ = current_frame_number_;
+ animate_funnel_ = true;
+ needs_animate_ = false;
+ // TODO(skyostil): Instead of assuming this, require the client to tell us.
+ SetNeedsRedraw();
+}
+
+void SchedulerStateMachine::UpdateStateOnSendBeginMainFrame() {
+ DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled);
+ DCHECK(visible_);
+ DCHECK(!send_begin_main_frame_funnel_);
+ commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
+ needs_commit_ = false;
+ send_begin_main_frame_funnel_ = true;
+ last_frame_number_begin_main_frame_sent_ = current_frame_number_;
+}
+
+void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) {
commit_count_++;
- if (!commit_was_aborted && HasAnimatedThisFrame())
- did_commit_after_animating_ = true;
+ // Animate after commit even if we've already animated.
+ if (!commit_has_no_updates)
+ animate_funnel_ = false;
- if (commit_was_aborted || settings_.main_frame_before_activation_enabled) {
+ if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) {
commit_state_ = COMMIT_STATE_IDLE;
+ } else if (settings_.impl_side_painting) {
+ commit_state_ = COMMIT_STATE_WAITING_FOR_ACTIVATION;
} else {
- commit_state_ = settings_.impl_side_painting
- ? COMMIT_STATE_WAITING_FOR_ACTIVATION
+ commit_state_ = settings_.main_thread_should_always_be_low_latency
+ ? COMMIT_STATE_WAITING_FOR_DRAW
: COMMIT_STATE_IDLE;
}
// If we are impl-side-painting but the commit was aborted, then we behave
// mostly as if we are not impl-side-painting since there is no pending tree.
- has_pending_tree_ = settings_.impl_side_painting && !commit_was_aborted;
+ has_pending_tree_ = settings_.impl_side_painting && !commit_has_no_updates;
// Update state related to forced draws.
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
@@ -671,7 +641,7 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
// Update state if we have a new active tree to draw, or if the active tree
// was unchanged but we need to do a forced draw.
if (!has_pending_tree_ &&
- (!commit_was_aborted ||
+ (!commit_has_no_updates ||
forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) {
needs_redraw_ = true;
active_tree_needs_first_draw_ = true;
@@ -682,11 +652,15 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
if (continuous_painting_)
needs_commit_ = true;
+ last_commit_had_no_updates_ = commit_has_no_updates;
}
void SchedulerStateMachine::UpdateStateOnActivation() {
- if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION)
- commit_state_ = COMMIT_STATE_IDLE;
+ if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION) {
+ commit_state_ = settings_.main_thread_should_always_be_low_latency
+ ? COMMIT_STATE_WAITING_FOR_DRAW
+ : COMMIT_STATE_IDLE;
+ }
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
@@ -704,15 +678,46 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) {
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
+ if (commit_state_ == COMMIT_STATE_WAITING_FOR_DRAW)
+ commit_state_ = COMMIT_STATE_IDLE;
+
needs_redraw_ = false;
active_tree_needs_first_draw_ = false;
- if (did_request_swap)
+ if (did_request_swap) {
+ DCHECK(!request_swap_funnel_);
+ request_swap_funnel_ = true;
+ did_request_swap_in_last_frame_ = true;
last_frame_number_swap_requested_ = current_frame_number_;
+ }
+}
+
+void SchedulerStateMachine::UpdateStateOnPrepareTiles() {
+ needs_prepare_tiles_ = false;
+}
+
+void SchedulerStateMachine::UpdateStateOnBeginOutputSurfaceCreation() {
+ DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
+ output_surface_state_ = OUTPUT_SURFACE_CREATING;
+
+ // The following DCHECKs make sure we are in the proper quiescent state.
+ // The pipeline should be flushed entirely before we start output
+ // surface creation to avoid complicated corner cases.
+ DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
+ DCHECK(!has_pending_tree_);
+ DCHECK(!active_tree_needs_first_draw_);
}
-void SchedulerStateMachine::UpdateStateOnManageTiles() {
- needs_manage_tiles_ = false;
+void SchedulerStateMachine::UpdateStateOnInvalidateOutputSurface() {
+ DCHECK(!invalidate_output_surface_funnel_);
+ invalidate_output_surface_funnel_ = true;
+ last_frame_number_invalidate_output_surface_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() {
@@ -722,91 +727,69 @@ void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() {
skip_next_begin_main_frame_to_reduce_latency_ = true;
}
-bool SchedulerStateMachine::BeginFrameNeeded() const {
- // Proactive BeginFrames are bad for the synchronous compositor because we
- // have to draw when we get the BeginFrame and could end up drawing many
- // duplicate frames if our new frame isn't ready in time.
- // To poll for state with the synchronous compositor without having to draw,
- // we rely on ShouldPollForAnticipatedDrawTriggers instead.
- if (!SupportsProactiveBeginFrame())
- return BeginFrameNeededToAnimateOrDraw();
-
- return BeginFrameNeededToAnimateOrDraw() || ProactiveBeginFrameWanted();
-}
-
-bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const {
- // ShouldPollForAnticipatedDrawTriggers is what we use in place of
- // ProactiveBeginFrameWanted when we are using the synchronous
- // compositor.
- if (!SupportsProactiveBeginFrame()) {
- return !BeginFrameNeededToAnimateOrDraw() && ProactiveBeginFrameWanted();
- }
-
- // Non synchronous compositors should rely on
- // ProactiveBeginFrameWanted to poll for state instead.
- return false;
+bool SchedulerStateMachine::BeginFrameRequiredForChildren() const {
+ return children_need_begin_frames_;
}
-
-// Note: If SupportsProactiveBeginFrame is false, the scheduler should poll
-// for changes in it's draw state so it can request a BeginFrame when it's
-// actually ready.
-bool SchedulerStateMachine::SupportsProactiveBeginFrame() const {
- // It is undesirable to proactively request BeginFrames if we are
- // using a synchronous compositor because we *must* draw for every
- // BeginFrame, which could cause duplicate draws.
- return !settings_.using_synchronous_renderer_compositor;
+bool SchedulerStateMachine::BeginFrameNeededForVideo() const {
+ return video_needs_begin_frames_;
}
-// These are the cases where we definitely (or almost definitely) have a
-// new frame to animate and/or draw and can draw.
-bool SchedulerStateMachine::BeginFrameNeededToAnimateOrDraw() const {
- // The output surface is the provider of BeginImplFrames, so we are not going
- // to get them even if we ask for them.
+bool SchedulerStateMachine::BeginFrameNeeded() const {
+ // We can't handle BeginFrames when output surface isn't initialized.
+ // TODO(brianderson): Support output surface creation inside a BeginFrame.
if (!HasInitializedOutputSurface())
return false;
- // If we can't draw, don't tick until we are notified that we can draw again.
- if (!can_draw_)
+ // If we are not visible, we don't need BeginFrame messages.
+ if (!visible_)
return false;
- // The forced draw respects our normal draw scheduling, so we need to
- // request a BeginImplFrame for it.
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
- return true;
+ return (BeginFrameRequiredForAction() || BeginFrameRequiredForChildren() ||
+ BeginFrameNeededForVideo() || ProactiveBeginFrameWanted());
+}
- // There's no need to produce frames if we are not visible.
- if (!visible_)
- return false;
+void SchedulerStateMachine::SetChildrenNeedBeginFrames(
+ bool children_need_begin_frames) {
+ children_need_begin_frames_ = children_need_begin_frames;
+}
- // We need to draw a more complete frame than we did the last BeginImplFrame,
- // so request another BeginImplFrame in anticipation that we will have
- // additional visible tiles.
- if (swap_used_incomplete_tile_)
- return true;
+void SchedulerStateMachine::SetVideoNeedsBeginFrames(
+ bool video_needs_begin_frames) {
+ video_needs_begin_frames_ = video_needs_begin_frames;
+}
+
+void SchedulerStateMachine::SetDeferCommits(bool defer_commits) {
+ defer_commits_ = defer_commits;
+}
- if (needs_animate_)
+// These are the cases where we require a BeginFrame message to make progress
+// on requested actions.
+bool SchedulerStateMachine::BeginFrameRequiredForAction() const {
+ // The forced draw respects our normal draw scheduling, so we need to
+ // request a BeginImplFrame for it.
+ if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
return true;
- return needs_redraw_;
+ return needs_animate_ || needs_redraw_ || (needs_commit_ && !defer_commits_);
}
-// These are cases where we are very likely to draw soon, but might not
-// actually have a new frame to draw when we receive the next BeginImplFrame.
-// Proactively requesting the BeginImplFrame helps hide the round trip latency
-// of the SetNeedsBeginFrame request that has to go to the Browser.
+// These are cases where we are very likely want a BeginFrame message in the
+// near future. Proactively requesting the BeginImplFrame helps hide the round
+// trip latency of the SetNeedsBeginFrame request that has to go to the
+// Browser.
+// This includes things like drawing soon, but might not actually have a new
+// frame to draw when we receive the next BeginImplFrame.
bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
- // The output surface is the provider of BeginImplFrames,
- // so we are not going to get them even if we ask for them.
- if (!HasInitializedOutputSurface())
- return false;
-
// Do not be proactive when invisible.
if (!visible_)
return false;
// We should proactively request a BeginImplFrame if a commit is pending
- // because we will want to draw if the commit completes quickly.
- if (needs_commit_ || commit_state_ != COMMIT_STATE_IDLE)
+ // because we will want to draw if the commit completes quickly. Do not
+ // request frames when commits are disabled, because the frame requests will
+ // not provide the needed commit (and will wake up the process when it could
+ // stay idle).
+ if ((commit_state_ != COMMIT_STATE_IDLE) && !defer_commits_)
return true;
// If the pending tree activates quickly, we'll want a BeginImplFrame soon
@@ -816,7 +799,7 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
// Changing priorities may allow us to activate (given the new priorities),
// which may result in a new frame.
- if (needs_manage_tiles_)
+ if (needs_prepare_tiles_)
return true;
// If we just sent a swap request, it's likely that we are going to produce
@@ -824,48 +807,93 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
// SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame
// provider and get sampled at an inopportune time, delaying the next
// BeginImplFrame.
- if (HasRequestedSwapThisFrame())
+ if (did_request_swap_in_last_frame_)
+ return true;
+
+ // If the last commit was aborted because of early out (no updates), we should
+ // still want a begin frame in case there is a commit coming again.
+ if (last_commit_had_no_updates_)
return true;
return false;
}
-void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) {
- AdvanceCurrentFrameNumber();
- begin_impl_frame_args_ = args;
- DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE)
- << AsValue()->ToString();
+void SchedulerStateMachine::OnBeginImplFrame() {
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
+ current_frame_number_++;
+
+ last_commit_had_no_updates_ = false;
+ did_request_swap_in_last_frame_ = false;
+
+ // Clear funnels for any actions we perform during the frame.
+ animate_funnel_ = false;
+ send_begin_main_frame_funnel_ = false;
+ invalidate_output_surface_funnel_ = false;
+
+ // "Drain" the PrepareTiles funnel.
+ if (prepare_tiles_funnel_ > 0)
+ prepare_tiles_funnel_--;
+
+ skip_begin_main_frame_to_reduce_latency_ =
+ skip_next_begin_main_frame_to_reduce_latency_;
+ skip_next_begin_main_frame_to_reduce_latency_ = false;
}
void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() {
- DCHECK_EQ(begin_impl_frame_state_,
- BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
- << AsValue()->ToString();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME;
}
void SchedulerStateMachine::OnBeginImplFrameDeadline() {
- DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
- << AsValue()->ToString();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
+
+ did_perform_swap_in_last_draw_ = false;
+
+ // Clear funnels for any actions we perform during the deadline.
+ request_swap_funnel_ = false;
+
+ // Allow one PrepareTiles per draw for synchronous compositor.
+ if (settings_.using_synchronous_renderer_compositor) {
+ if (prepare_tiles_funnel_ > 0)
+ prepare_tiles_funnel_--;
+ }
}
void SchedulerStateMachine::OnBeginImplFrameIdle() {
- DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
- << AsValue()->ToString();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
}
-bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
- // TODO(brianderson): This should take into account multiple commit sources.
+SchedulerStateMachine::BeginImplFrameDeadlineMode
+SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const {
+ if (settings_.using_synchronous_renderer_compositor) {
+ // No deadline for synchronous compositor.
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE;
+ } else if (wait_for_active_tree_ready_to_draw_) {
+ // When we are waiting for ready to draw signal, we do not wait to post a
+ // deadline yet.
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW;
+ } else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) {
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE;
+ } else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) {
+ // We have an animation or fast input path on the impl thread that wants
+ // to draw, so don't wait too long for a new active tree.
+ // If we are swap throttled we should wait until we are unblocked.
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR;
+ } else {
+ // The impl thread doesn't have anything it wants to draw and we are just
+ // waiting for a new active tree or we are swap throttled. In short we are
+ // blocked.
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE;
+ }
+}
+bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately()
+ const {
+ // TODO(brianderson): This should take into account multiple commit sources.
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
return false;
- // If we've lost the output surface, end the current BeginImplFrame ASAP
- // so we can start creating the next output surface.
- if (output_surface_state_ == OUTPUT_SURFACE_LOST)
+ // If we just forced activation, we should end the deadline right now.
+ if (PendingActivationsShouldBeForced() && !has_pending_tree_)
return true;
// SwapAck throttle the deadline since we wont draw and swap anyway.
@@ -890,11 +918,6 @@ bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
if (impl_latency_takes_priority_)
return true;
- // If we are on battery power and want to prioritize impl latency because
- // we don't trust deadline tasks to execute at the right time.
- if (impl_latency_takes_priority_on_battery_)
- return true;
-
return false;
}
@@ -906,7 +929,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
// If we just sent a BeginMainFrame and haven't hit the deadline yet, the main
// thread is in a low latency mode.
- if (HasSentBeginMainFrameThisFrame() &&
+ if (send_begin_main_frame_funnel_ &&
(begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING ||
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
return false;
@@ -930,8 +953,8 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
// Even if there's a new active tree to draw at the deadline or we've just
// swapped it, it may have been triggered by a previous BeginImplFrame, in
// which case the main thread is in a high latency mode.
- return (active_tree_needs_first_draw_ || HasSwappedThisFrame()) &&
- !HasSentBeginMainFrameThisFrame();
+ return (active_tree_needs_first_draw_ || did_perform_swap_in_last_draw_) &&
+ !send_begin_main_frame_funnel_;
}
// If the active tree needs its first draw in any other state, we know the
@@ -939,15 +962,6 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
return active_tree_needs_first_draw_;
}
-void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() {
- AdvanceCurrentFrameNumber();
- inside_poll_for_anticipated_draw_triggers_ = true;
-}
-
-void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() {
- inside_poll_for_anticipated_draw_triggers_ = false;
-}
-
void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
@@ -958,11 +972,15 @@ void SchedulerStateMachine::SetNeedsAnimate() {
needs_animate_ = true;
}
-void SchedulerStateMachine::SetNeedsManageTiles() {
- if (!needs_manage_tiles_) {
- TRACE_EVENT0("cc",
- "SchedulerStateMachine::SetNeedsManageTiles");
- needs_manage_tiles_ = true;
+void SchedulerStateMachine::SetWaitForReadyToDraw() {
+ DCHECK(settings_.impl_side_painting);
+ wait_for_active_tree_ready_to_draw_ = true;
+}
+
+void SchedulerStateMachine::SetNeedsPrepareTiles() {
+ if (!needs_prepare_tiles_) {
+ TRACE_EVENT0("cc", "SchedulerStateMachine::SetNeedsPrepareTiles");
+ needs_prepare_tiles_ = true;
}
}
@@ -974,14 +992,10 @@ void SchedulerStateMachine::DidSwapBuffers() {
pending_swaps_++;
DCHECK_LE(pending_swaps_, max_pending_swaps_);
+ did_perform_swap_in_last_draw_ = true;
last_frame_number_swap_performed_ = current_frame_number_;
}
-void SchedulerStateMachine::SetSwapUsedIncompleteTile(
- bool used_incomplete_tile) {
- swap_used_incomplete_tile_ = used_incomplete_tile;
-}
-
void SchedulerStateMachine::DidSwapBuffersComplete() {
DCHECK_GT(pending_swaps_, 0);
pending_swaps_--;
@@ -1043,23 +1057,33 @@ void SchedulerStateMachine::NotifyReadyToCommit() {
DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED)
<< AsValue()->ToString();
commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
+ // In main thread low latency mode, commit should happen right after
+ // BeginFrame, meaning when this function is called, next action should be
+ // commit.
+ if (settings_.main_thread_should_always_be_low_latency)
+ DCHECK(ShouldCommit());
}
-void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
+void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) {
DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
- if (did_handle) {
- bool commit_was_aborted = true;
- UpdateStateOnCommit(commit_was_aborted);
- } else {
- commit_state_ = COMMIT_STATE_IDLE;
- SetNeedsCommit();
+ switch (reason) {
+ case CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST:
+ case CommitEarlyOutReason::ABORTED_NOT_VISIBLE:
+ case CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT:
+ commit_state_ = COMMIT_STATE_IDLE;
+ SetNeedsCommit();
+ return;
+ case CommitEarlyOutReason::FINISHED_NO_UPDATES:
+ bool commit_has_no_updates = true;
+ UpdateStateOnCommit(commit_has_no_updates);
+ return;
}
}
-void SchedulerStateMachine::DidManageTiles() {
- needs_manage_tiles_ = false;
- // "Fill" the ManageTiles funnel.
- manage_tiles_funnel_++;
+void SchedulerStateMachine::DidPrepareTiles() {
+ needs_prepare_tiles_ = false;
+ // "Fill" the PrepareTiles funnel.
+ prepare_tiles_funnel_++;
}
void SchedulerStateMachine::DidLoseOutputSurface() {
@@ -1068,6 +1092,7 @@ void SchedulerStateMachine::DidLoseOutputSurface() {
return;
output_surface_state_ = OUTPUT_SURFACE_LOST;
needs_redraw_ = false;
+ wait_for_active_tree_ready_to_draw_ = false;
}
void SchedulerStateMachine::NotifyReadyToActivate() {
@@ -1075,6 +1100,10 @@ void SchedulerStateMachine::NotifyReadyToActivate() {
pending_tree_is_ready_for_activation_ = true;
}
+void SchedulerStateMachine::NotifyReadyToDraw() {
+ wait_for_active_tree_ready_to_draw_ = false;
+}
+
void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT;
diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h
index a63a683e907..cf29ca9b6a5 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.h
+++ b/chromium/cc/scheduler/scheduler_state_machine.h
@@ -9,14 +9,14 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/output/begin_frame_args.h"
+#include "cc/scheduler/commit_earlyout_reason.h"
#include "cc/scheduler/draw_result.h"
#include "cc/scheduler/scheduler_settings.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
class TracedValue;
}
@@ -50,10 +50,10 @@ class CC_EXPORT SchedulerStateMachine {
};
static const char* OutputSurfaceStateToString(OutputSurfaceState state);
- // Note: BeginImplFrameState will always cycle through all the states in
- // order. Whether or not it actually waits or draws, it will at least try to
- // wait in BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME and try to draw in
- // BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE
+ // Note: BeginImplFrameState does not cycle through these states in a fixed
+ // order on all platforms. It's up to the scheduler to set these correctly.
+ // TODO(sunnyps): Rename the states to IDLE, ANIMATE, WAITING_FOR_DEADLINE and
+ // DRAW.
enum BeginImplFrameState {
BEGIN_IMPL_FRAME_STATE_IDLE,
BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
@@ -62,12 +62,23 @@ class CC_EXPORT SchedulerStateMachine {
};
static const char* BeginImplFrameStateToString(BeginImplFrameState state);
+ enum BeginImplFrameDeadlineMode {
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE,
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE,
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR,
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE,
+ BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW,
+ };
+ static const char* BeginImplFrameDeadlineModeToString(
+ BeginImplFrameDeadlineMode mode);
+
enum CommitState {
COMMIT_STATE_IDLE,
COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
COMMIT_STATE_READY_TO_COMMIT,
COMMIT_STATE_WAITING_FOR_ACTIVATION,
+ COMMIT_STATE_WAITING_FOR_DRAW,
};
static const char* CommitStateToString(CommitState state);
@@ -88,25 +99,25 @@ class CC_EXPORT SchedulerStateMachine {
CommitState commit_state() const { return commit_state_; }
bool RedrawPending() const { return needs_redraw_; }
- bool ManageTilesPending() const { return needs_manage_tiles_; }
+ bool PrepareTilesPending() const { return needs_prepare_tiles_; }
enum Action {
ACTION_NONE,
ACTION_ANIMATE,
ACTION_SEND_BEGIN_MAIN_FRAME,
ACTION_COMMIT,
- ACTION_UPDATE_VISIBLE_TILES,
ACTION_ACTIVATE_SYNC_TREE,
ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
ACTION_DRAW_AND_SWAP_FORCED,
ACTION_DRAW_AND_SWAP_ABORT,
ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- ACTION_MANAGE_TILES,
+ ACTION_PREPARE_TILES,
+ ACTION_INVALIDATE_OUTPUT_SURFACE,
};
static const char* ActionToString(Action action);
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
- void AsValueInto(base::debug::TracedValue* dict, base::TimeTicks now) const;
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
Action NextAction() const;
void UpdateState(Action action);
@@ -115,39 +126,28 @@ class CC_EXPORT SchedulerStateMachine {
// to make progress.
bool BeginFrameNeeded() const;
- // Indicates that we need to independently poll for new state and actions
- // because we can't expect a BeginImplFrame. This is mostly used to avoid
- // drawing repeat frames with the synchronous compositor without dropping
- // necessary actions on the floor.
- bool ShouldPollForAnticipatedDrawTriggers() const;
-
// Indicates that the system has entered and left a BeginImplFrame callback.
// The scheduler will not draw more than once in a given BeginImplFrame
// callback nor send more than one BeginMainFrame message.
- void OnBeginImplFrame(const BeginFrameArgs& args);
+ void OnBeginImplFrame();
void OnBeginImplFrameDeadlinePending();
+ // Indicates that the scheduler has entered the draw phase. The scheduler
+ // will not draw more than once in a single draw phase.
+ // TODO(sunnyps): Rename OnBeginImplFrameDeadline to OnDraw or similar.
void OnBeginImplFrameDeadline();
void OnBeginImplFrameIdle();
- bool ShouldTriggerBeginImplFrameDeadlineEarly() const;
BeginImplFrameState begin_impl_frame_state() const {
return begin_impl_frame_state_;
}
+ BeginImplFrameDeadlineMode CurrentBeginImplFrameDeadlineMode() const;
// If the main thread didn't manage to produce a new frame in time for the
// impl thread to draw, it is in a high latency mode.
bool MainThreadIsInHighLatencyMode() const;
- // PollForAnticipatedDrawTriggers is used by the synchronous compositor to
- // avoid requesting BeginImplFrames when we won't actually draw but still
- // need to advance our state at vsync intervals.
- void DidEnterPollForAnticipatedDrawTriggers();
- void DidLeavePollForAnticipatedDrawTriggers();
- bool inside_poll_for_anticipated_draw_triggers() const {
- return inside_poll_for_anticipated_draw_triggers_;
- }
-
// Indicates whether the LayerTreeHostImpl is visible.
void SetVisible(bool visible);
+ bool visible() const { return visible_; }
// Indicates that a redraw is required, either due to the impl tree changing
// or the screen being damaged and simply needing redisplay.
@@ -157,9 +157,12 @@ class CC_EXPORT SchedulerStateMachine {
void SetNeedsAnimate();
bool needs_animate() const { return needs_animate_; }
- // Indicates that manage-tiles is required. This guarantees another
- // ManageTiles will occur shortly (even if no redraw is required).
- void SetNeedsManageTiles();
+ // Indicates that prepare-tiles is required. This guarantees another
+ // PrepareTiles will occur shortly (even if no redraw is required).
+ void SetNeedsPrepareTiles();
+
+ // Make deadline wait for ReadyToDraw signal.
+ void SetWaitForReadyToDraw();
// Sets how many swaps can be pending to the OutputSurface.
void SetMaxSwapsPending(int max);
@@ -198,11 +201,12 @@ class CC_EXPORT SchedulerStateMachine {
// Call this only in response to receiving an ACTION_SEND_BEGIN_MAIN_FRAME
// from NextAction if the client rejects the BeginMainFrame message.
- // If did_handle is false, then another commit will be retried soon.
- void BeginMainFrameAborted(bool did_handle);
+ void BeginMainFrameAborted(CommitEarlyOutReason reason);
// Set that we can create the first OutputSurface and start the scheduler.
void SetCanStart() { can_start_ = true; }
+ // Allow access of the can_start_ state in tests.
+ bool CanStartForTesting() const { return can_start_; }
void SetSkipNextBeginMainFrameToReduceLatency();
@@ -217,12 +221,15 @@ class CC_EXPORT SchedulerStateMachine {
// Indicates that the pending tree is ready for activation.
void NotifyReadyToActivate();
+ // Indicates the active tree's visible tiles are ready to be drawn.
+ void NotifyReadyToDraw();
+
bool has_pending_tree() const { return has_pending_tree_; }
bool active_tree_needs_first_draw() const {
return active_tree_needs_first_draw_;
}
- void DidManageTiles();
+ void DidPrepareTiles();
void DidLoseOutputSurface();
void DidCreateAndInitializeOutputSurface();
bool HasInitializedOutputSurface() const;
@@ -230,52 +237,54 @@ class CC_EXPORT SchedulerStateMachine {
// True if we need to abort draws to make forward progress.
bool PendingDrawsShouldBeAborted() const;
- bool SupportsProactiveBeginFrame() const;
-
void SetContinuousPainting(bool continuous_painting) {
continuous_painting_ = continuous_painting;
}
bool CouldSendBeginMainFrame() const;
- void SetImplLatencyTakesPriorityOnBattery(
- bool impl_latency_takes_priority_on_battery) {
- impl_latency_takes_priority_on_battery_ =
- impl_latency_takes_priority_on_battery;
- }
+ void SetDeferCommits(bool defer_commits);
// TODO(zmo): This is temporary for debugging crbug.com/393331.
// We should remove it afterwards.
std::string GetStatesForDebugging() const;
+ void SetChildrenNeedBeginFrames(bool children_need_begin_frames);
+ bool children_need_begin_frames() const {
+ return children_need_begin_frames_;
+ }
+
+ void SetVideoNeedsBeginFrames(bool video_needs_begin_frames);
+ bool video_needs_begin_frames() const { return video_needs_begin_frames_; }
+
protected:
- bool BeginFrameNeededToAnimateOrDraw() const;
+ bool BeginFrameRequiredForAction() const;
+ bool BeginFrameRequiredForChildren() const;
+ bool BeginFrameNeededForVideo() const;
bool ProactiveBeginFrameWanted() const;
+ bool ShouldTriggerBeginImplFrameDeadlineImmediately() const;
+
// True if we need to force activations to make forward progress.
bool PendingActivationsShouldBeForced() const;
bool ShouldAnimate() const;
bool ShouldBeginOutputSurfaceCreation() const;
- bool ShouldDrawForced() const;
bool ShouldDraw() const;
bool ShouldActivatePendingTree() const;
- bool ShouldUpdateVisibleTiles() const;
bool ShouldSendBeginMainFrame() const;
bool ShouldCommit() const;
- bool ShouldManageTiles() const;
+ bool ShouldPrepareTiles() const;
+ bool ShouldInvalidateOutputSurface() const;
- void AdvanceCurrentFrameNumber();
- bool HasAnimatedThisFrame() const;
- bool HasSentBeginMainFrameThisFrame() const;
- bool HasUpdatedVisibleTilesThisFrame() const;
- bool HasRequestedSwapThisFrame() const;
- bool HasSwappedThisFrame() const;
-
- void UpdateStateOnCommit(bool commit_was_aborted);
+ void UpdateStateOnAnimate();
+ void UpdateStateOnSendBeginMainFrame();
+ void UpdateStateOnCommit(bool commit_had_no_updates);
void UpdateStateOnActivation();
void UpdateStateOnDraw(bool did_request_swap);
- void UpdateStateOnManageTiles();
+ void UpdateStateOnBeginOutputSurfaceCreation();
+ void UpdateStateOnPrepareTiles();
+ void UpdateStateOnInvalidateOutputSurface();
const SchedulerSettings settings_;
@@ -284,43 +293,52 @@ class CC_EXPORT SchedulerStateMachine {
CommitState commit_state_;
ForcedRedrawOnTimeoutState forced_redraw_state_;
- BeginFrameArgs begin_impl_frame_args_;
-
+ // These are used for tracing only.
int commit_count_;
int current_frame_number_;
int last_frame_number_animate_performed_;
int last_frame_number_swap_performed_;
int last_frame_number_swap_requested_;
int last_frame_number_begin_main_frame_sent_;
- int last_frame_number_update_visible_tiles_was_called_;
-
- // manage_tiles_funnel_ is "filled" each time ManageTiles is called
+ int last_frame_number_invalidate_output_surface_performed_;
+
+ // These are used to ensure that an action only happens once per frame,
+ // deadline, etc.
+ bool animate_funnel_;
+ bool request_swap_funnel_;
+ bool send_begin_main_frame_funnel_;
+ bool invalidate_output_surface_funnel_;
+ // prepare_tiles_funnel_ is "filled" each time PrepareTiles is called
// and "drained" on each BeginImplFrame. If the funnel gets too full,
- // we start throttling ACTION_MANAGE_TILES such that we average one
- // ManageTile per BeginImplFrame.
- int manage_tiles_funnel_;
+ // we start throttling ACTION_PREPARE_TILES such that we average one
+ // PrepareTiles per BeginImplFrame.
+ int prepare_tiles_funnel_;
+
int consecutive_checkerboard_animations_;
int max_pending_swaps_;
int pending_swaps_;
bool needs_redraw_;
bool needs_animate_;
- bool needs_manage_tiles_;
- bool swap_used_incomplete_tile_;
+ bool needs_prepare_tiles_;
bool needs_commit_;
- bool inside_poll_for_anticipated_draw_triggers_;
bool visible_;
bool can_start_;
bool can_draw_;
bool has_pending_tree_;
bool pending_tree_is_ready_for_activation_;
bool active_tree_needs_first_draw_;
- bool did_commit_after_animating_;
bool did_create_and_initialize_first_output_surface_;
bool impl_latency_takes_priority_;
bool skip_next_begin_main_frame_to_reduce_latency_;
bool skip_begin_main_frame_to_reduce_latency_;
bool continuous_painting_;
- bool impl_latency_takes_priority_on_battery_;
+ bool children_need_begin_frames_;
+ bool defer_commits_;
+ bool video_needs_begin_frames_;
+ bool last_commit_had_no_updates_;
+ bool wait_for_active_tree_ready_to_draw_;
+ bool did_request_swap_in_last_frame_;
+ bool did_perform_swap_in_last_draw_;
private:
DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine);
diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
index e3530c877f4..7b332a3fbf3 100644
--- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -4,31 +4,58 @@
#include "cc/scheduler/scheduler_state_machine.h"
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/scheduler/scheduler.h"
#include "cc/test/begin_frame_args_test.h"
#include "testing/gtest/include/gtest/gtest.h"
-#define EXPECT_ACTION_UPDATE_STATE(action) \
- EXPECT_STREQ(SchedulerStateMachine::ActionToString(action), \
- SchedulerStateMachine::ActionToString(state.NextAction())) \
- << state.AsValue()->ToString(); \
- if (action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE || \
- action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED) { \
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, \
- state.begin_impl_frame_state()) \
- << state.AsValue()->ToString(); \
- } \
- state.UpdateState(action); \
- if (action == SchedulerStateMachine::ACTION_NONE) { \
- if (state.begin_impl_frame_state() == \
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) \
- state.OnBeginImplFrameDeadlinePending(); \
- if (state.begin_impl_frame_state() == \
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) \
- state.OnBeginImplFrameIdle(); \
+// Macro to compare two enum values and get nice output.
+// Without:
+// Value of: actual() Actual: 7
+// Expected: expected() Which is: 0
+// With:
+// Value of: actual() Actual: "ACTION_ANIMATE"
+// Expected: expected() Which is: "ACTION_NONE"
+#define EXPECT_ENUM_EQ(enum_tostring, expected, actual) \
+ EXPECT_STREQ(SchedulerStateMachine::enum_tostring(expected), \
+ SchedulerStateMachine::enum_tostring(actual))
+
+#define EXPECT_IMPL_FRAME_STATE(expected) \
+ EXPECT_ENUM_EQ(BeginImplFrameStateToString, expected, \
+ state.begin_impl_frame_state()) \
+ << state.AsValue()->ToString()
+
+#define EXPECT_COMMIT_STATE(expected) \
+ EXPECT_ENUM_EQ(CommitStateToString, expected, state.CommitState())
+
+#define EXPECT_ACTION(expected) \
+ EXPECT_ENUM_EQ(ActionToString, expected, state.NextAction()) \
+ << state.AsValue()->ToString()
+
+#define EXPECT_ACTION_UPDATE_STATE(action) \
+ EXPECT_ACTION(action); \
+ if (action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE || \
+ action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED) { \
+ EXPECT_IMPL_FRAME_STATE( \
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); \
+ } \
+ state.UpdateState(action); \
+ if (action == SchedulerStateMachine::ACTION_NONE) { \
+ if (state.begin_impl_frame_state() == \
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) \
+ state.OnBeginImplFrameDeadlinePending(); \
+ if (state.begin_impl_frame_state() == \
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) \
+ state.OnBeginImplFrameIdle(); \
}
+#define SET_UP_STATE(state) \
+ state.SetCanStart(); \
+ state.UpdateState(state.NextAction()); \
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); \
+ state.SetVisible(true); \
+ state.SetCanDraw(true);
+
namespace cc {
namespace {
@@ -44,7 +71,8 @@ const SchedulerStateMachine::CommitState all_commit_states[] = {
SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION};
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW};
// Exposes the protected state fields of the SchedulerStateMachine for testing
class StateMachine : public SchedulerStateMachine {
@@ -76,9 +104,17 @@ class StateMachine : public SchedulerStateMachine {
return output_surface_state_;
}
+ void SetNeedsCommitForTest(bool needs_commit) {
+ needs_commit_ = needs_commit;
+ }
+
bool NeedsCommit() const { return needs_commit_; }
- void SetNeedsRedraw(bool b) { needs_redraw_ = b; }
+ void SetNeedsAnimateForTest(bool needs_animate) {
+ needs_animate_ = needs_animate;
+ }
+
+ void SetNeedsRedraw(bool needs_redraw) { needs_redraw_ = needs_redraw; }
void SetNeedsForcedRedrawForTimeout(bool b) {
forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
@@ -102,8 +138,56 @@ class StateMachine : public SchedulerStateMachine {
void SetHasPendingTree(bool has_pending_tree) {
has_pending_tree_ = has_pending_tree;
}
+
+ using SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately;
+ using SchedulerStateMachine::ProactiveBeginFrameWanted;
+ using SchedulerStateMachine::UpdateStateOnCommit;
};
+TEST(SchedulerStateMachineTest, BeginFrameNeeded) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION)
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
+
+ // Don't request BeginFrames if we are idle.
+ state.SetVisible(true);
+ state.SetNeedsRedraw(false);
+ state.SetNeedsAnimateForTest(false);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+
+ // Request BeginFrames if we are ready to draw.
+ state.SetVisible(true);
+ state.SetNeedsRedraw(true);
+ state.SetNeedsAnimateForTest(false);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ // Don't background tick for needs_redraw.
+ state.SetVisible(false);
+ state.SetNeedsRedraw(true);
+ state.SetNeedsAnimateForTest(false);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+
+ // Proactively request BeginFrames when commit is pending.
+ state.SetVisible(true);
+ state.SetNeedsRedraw(false);
+ state.SetNeedsAnimateForTest(false);
+ state.SetNeedsCommitForTest(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ // Don't request BeginFrames when commit is pending if
+ // we are currently deferring commits.
+ state.SetVisible(true);
+ state.SetNeedsRedraw(false);
+ state.SetNeedsAnimateForTest(false);
+ state.SetNeedsCommitForTest(true);
+ state.SetDeferCommits(true);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+}
+
TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
SchedulerSettings default_scheduler_settings;
@@ -122,7 +206,7 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -140,7 +224,7 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
}
@@ -158,7 +242,36 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ // Expect nothing to happen until after OnBeginImplFrame.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ }
+
+ // If commit requested and can't draw, still begin a main frame.
+ {
+ StateMachine state(default_scheduler_settings);
+ state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetNeedsRedraw(false);
+ state.SetVisible(true);
+ state.SetNeedsCommit();
+ state.SetCanDraw(false);
+
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ // Expect nothing to happen until after OnBeginImplFrame.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -171,8 +284,8 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(true);
state.UpdateState(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
}
}
@@ -184,18 +297,14 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
scheduler_settings.main_frame_before_activation_enabled = true;
StateMachine state(scheduler_settings);
state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ SET_UP_STATE(state)
state.SetNeedsRedraw(false);
- state.SetVisible(true);
- state.SetCanDraw(true);
state.SetNeedsCommit();
EXPECT_TRUE(state.BeginFrameNeeded());
// Commit to the pending tree.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -204,14 +313,14 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Verify that the next commit starts while there is still a pending tree.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -228,7 +337,7 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
@@ -237,22 +346,18 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
}
TEST(SchedulerStateMachineTest,
TestFailedDrawForAnimationCheckerboardSetsNeedsCommitAndDoesNotDrawAgain) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -269,7 +374,7 @@ TEST(SchedulerStateMachineTest,
// Failing the draw makes us require a commit.
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -280,16 +385,12 @@ TEST(SchedulerStateMachineTest,
TEST(SchedulerStateMachineTest, TestFailedDrawForMissingHighResNeedsCommit) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -303,7 +404,7 @@ TEST(SchedulerStateMachineTest, TestFailedDrawForMissingHighResNeedsCommit) {
// Missing high res content requires a commit (but not a redraw)
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_FALSE(state.RedrawPending());
@@ -314,16 +415,11 @@ TEST(SchedulerStateMachineTest,
TestsetNeedsRedrawDuringFailedDrawDoesNotRemoveNeedsRedraw) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
-
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -344,7 +440,7 @@ TEST(SchedulerStateMachineTest,
// Failing the draw for animation checkerboards makes us require a commit.
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -356,16 +452,12 @@ TEST(SchedulerStateMachineTest,
SchedulerSettings scheduler_settings;
scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start a commit.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -395,7 +487,7 @@ TEST(SchedulerStateMachineTest,
EXPECT_TRUE(state.RedrawPending());
// The redraw should be forced at the end of the next BeginImplFrame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -414,16 +506,12 @@ TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) {
draw_limit;
scheduler_settings.impl_side_painting = true;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start a commit.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -471,16 +559,12 @@ TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) {
TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start a draw.
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -497,7 +581,7 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
// We should not be trying to draw again now, but we have a commit pending.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -514,16 +598,12 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
// Draw the first frame.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -542,7 +622,7 @@ TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) {
// Move to another frame. This should now draw.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -615,19 +695,16 @@ TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginImplFrame) {
expected_action = SchedulerStateMachine::ACTION_COMMIT;
} else {
expected_action = SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
- EXPECT_EQ(state.NextAction(), SchedulerStateMachine::ACTION_ANIMATE)
- << state.AsValue()->ToString();
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_ANIMATE);
state.UpdateState(state.NextAction());
}
// Case 1: needs_commit=false.
- EXPECT_EQ(state.NextAction(), expected_action)
- << state.AsValue()->ToString();
+ EXPECT_ACTION(expected_action);
// Case 2: needs_commit=true.
state.SetNeedsCommit();
- EXPECT_EQ(state.NextAction(), expected_action)
- << state.AsValue()->ToString();
+ EXPECT_ACTION(expected_action);
}
}
@@ -680,7 +757,7 @@ TEST(SchedulerStateMachineTest, TestCanRedraw_StopsDraw) {
state.SetVisible(false);
state.SetNeedsRedraw(true);
if (j == 1)
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
state.SetCanDraw(false);
EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
@@ -702,7 +779,8 @@ TEST(SchedulerStateMachineTest,
state.SetNeedsRedraw(true);
state.SetVisible(true);
state.SetCanDraw(false);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -711,6 +789,7 @@ TEST(SchedulerStateMachineTest,
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
@@ -718,21 +797,17 @@ TEST(SchedulerStateMachineTest,
TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost) {
SchedulerSettings scheduler_settings;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ SET_UP_STATE(state)
state.SetNeedsCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
// Now, while the frame is in progress, set another commit.
state.SetNeedsCommit();
@@ -741,33 +816,31 @@ TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost) {
// Let the frame finish.
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
// Expect to commit regardless of BeginImplFrame state.
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameDeadlinePending();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameIdle();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ state.OnBeginImplFrame();
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
// Finish the commit, then make sure we start the next commit immediately
// and draw on the next BeginImplFrame.
@@ -791,29 +864,24 @@ TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost) {
TEST(SchedulerStateMachineTest, TestFullCycle) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start clean and set commit.
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Tell the scheduler the frame finished.
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
// Commit.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
@@ -834,28 +902,166 @@ TEST(SchedulerStateMachineTest, TestFullCycle) {
// Should be synchronized, no draw needed, no action needed.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
EXPECT_FALSE(state.needs_redraw());
}
+TEST(SchedulerStateMachineTest, TestFullCycleWithMainThreadLowLatencyMode) {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.main_thread_should_always_be_low_latency = true;
+ StateMachine state(scheduler_settings);
+ SET_UP_STATE(state)
+
+ // Start clean and set commit.
+ state.SetNeedsCommit();
+
+ // Begin the frame.
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Tell the scheduler the frame finished.
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
+
+ // Commit.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
+ EXPECT_TRUE(state.needs_redraw());
+
+ // Now commit should wait for draw.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW);
+
+ // Swap throttled. Do not draw.
+ state.DidSwapBuffers();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.DidSwapBuffersComplete();
+
+ // Haven't draw since last commit, do not begin new main frame.
+ state.SetNeedsCommit();
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // At BeginImplFrame deadline, draw.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
+
+ // Now will be able to start main frame.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_FALSE(state.needs_redraw());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
+TEST(SchedulerStateMachineTest,
+ TestFullCycleWithMainThreadLowLatencyMode_ImplSidePaint) {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.main_thread_should_always_be_low_latency = true;
+ scheduler_settings.impl_side_painting = true;
+ StateMachine state(scheduler_settings);
+ SET_UP_STATE(state)
+
+ // Start clean and set commit.
+ state.SetNeedsCommit();
+
+ // Begin the frame.
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Tell the scheduler the frame finished.
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
+
+ // Commit.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+
+ // Now commit should wait for activation.
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION);
+
+ // No activation yet, so this commit is not drawn yet. Force to draw this
+ // frame, and still block BeginMainFrame.
+ state.SetNeedsRedraw(true);
+ state.SetNeedsCommit();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Cannot BeginMainFrame yet since last commit is not yet activated and drawn.
+ state.OnBeginImplFrame();
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Now activate sync tree.
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
+ EXPECT_TRUE(state.needs_redraw());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW);
+
+ // Swap throttled. Do not draw.
+ state.DidSwapBuffers();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.DidSwapBuffersComplete();
+
+ // Haven't draw since last commit, do not begin new main frame.
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // At BeginImplFrame deadline, draw. This draws unblocks BeginMainFrame.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
+
+ // Now will be able to start main frame.
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_FALSE(state.needs_redraw());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start clean and set commit.
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -866,8 +1072,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
// Tell the scheduler the frame finished.
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
// First commit.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
@@ -888,11 +1093,11 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
// Should be synchronized, no draw needed, no action needed.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
EXPECT_FALSE(state.needs_redraw());
// Next BeginImplFrame should initiate second commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -907,33 +1112,35 @@ TEST(SchedulerStateMachineTest, TestRequestCommitInvisible) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
-TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) {
+// See ThreadProxy::BeginMainFrame "EarlyOut_NotVisible" /
+// "EarlyOut_OutputSurfaceLost" cases.
+TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Start clean and set commit.
state.SetNeedsCommit();
// Begin the frame while visible.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Become invisible and abort BeginMainFrame.
state.SetVisible(false);
- state.BeginMainFrameAborted(false);
+ state.BeginMainFrameAborted(CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
+
+ // NeedsCommit should now be true again because we never actually did a
+ // commit.
+ EXPECT_TRUE(state.NeedsCommit());
// We should now be back in the idle state as if we never started the frame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// We shouldn't do anything on the BeginImplFrame deadline.
@@ -945,22 +1152,23 @@ TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) {
// Although we have aborted on this frame and haven't cancelled the commit
// (i.e. need another), don't send another BeginMainFrame yet.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.NeedsCommit());
// Start a new frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
// We should be starting the commit now.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
-TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) {
+// See ThreadProxy::BeginMainFrame "EarlyOut_NoUpdates" case.
+TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetCanStart();
@@ -971,25 +1179,22 @@ TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) {
// Get into a begin frame / commit state.
state.SetNeedsCommit();
-
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
EXPECT_FALSE(state.NeedsCommit());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
- // Abort the commit, cancelling future commits.
- state.BeginMainFrameAborted(true);
+ // Abort the commit, true means that the BeginMainFrame was sent but there
+ // was no work to do on the main thread.
+ state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
- // Verify that another commit doesn't start on the same frame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ // NeedsCommit should now be false because the commit was actually handled.
EXPECT_FALSE(state.NeedsCommit());
- // Start a new frame; draw because this is the first frame since output
- // surface init'd.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ // Even though the commit was aborted, we still expect to draw the new frame.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -997,163 +1202,22 @@ TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) {
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
state.DidSwapBuffers();
state.DidSwapBuffersComplete();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Verify another commit doesn't start on another frame either.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_FALSE(state.NeedsCommit());
-
- // Verify another commit can start if requested, though.
- state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
-}
-
-TEST(SchedulerStateMachineTest,
- AbortBeginMainFrameAndCancelCommitWhenInvisible) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.DidCreateAndInitializeOutputSurface();
- state.SetVisible(true);
- state.SetCanDraw(true);
-
- // Get into a begin frame / commit state.
- state.SetNeedsCommit();
-
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
- EXPECT_FALSE(state.NeedsCommit());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
-
- // Become invisible and abort BeginMainFrame.
- state.SetVisible(false);
- state.BeginMainFrameAborted(true);
-
- // Verify that another commit doesn't start on the same frame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
- // Become visible and start a new frame.
- state.SetVisible(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-
- // Draw because this is the first frame since output surface init'd.
state.OnBeginImplFrameDeadline();
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
- state.DidSwapBuffers();
- state.DidSwapBuffersComplete();
-
- // Verify another commit doesn't start on another frame either.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Verify another commit can start if requested, though.
state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
-}
-
-TEST(SchedulerStateMachineTest,
- AbortBeginMainFrameAndRequestCommitWhenInvisible) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.DidCreateAndInitializeOutputSurface();
- state.SetVisible(true);
- state.SetCanDraw(true);
-
- // Get into a begin frame / commit state.
- state.SetNeedsCommit();
-
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
- EXPECT_FALSE(state.NeedsCommit());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
-
- // Become invisible and abort BeginMainFrame.
- state.SetVisible(false);
- state.BeginMainFrameAborted(true);
-
- // Verify that another commit doesn't start on the same frame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_FALSE(state.NeedsCommit());
-
- // Asking for a commit while not visible won't make it happen.
- state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_TRUE(state.NeedsCommit());
-
- // Become visible but nothing happens until the next frame.
- state.SetVisible(true);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_TRUE(state.NeedsCommit());
-
- // We should get that commit when we begin the next frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-}
-
-TEST(SchedulerStateMachineTest,
- AbortBeginMainFrameAndRequestCommitAndBeginImplFrameWhenInvisible) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.DidCreateAndInitializeOutputSurface();
- state.SetVisible(true);
- state.SetCanDraw(true);
-
- // Get into a begin frame / commit state.
- state.SetNeedsCommit();
-
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
- EXPECT_FALSE(state.NeedsCommit());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
-
- // Become invisible and abort BeginMainFrame.
- state.SetVisible(false);
- state.BeginMainFrameAborted(true);
-
- // Asking for a commit while not visible won't make it happen.
- state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_TRUE(state.NeedsCommit());
-
- // Begin a frame when not visible, the scheduler animates but does not commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_TRUE(state.NeedsCommit());
-
- // Become visible and the requested commit happens immediately.
- state.SetVisible(true);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ state.OnBeginImplFrame();
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
@@ -1169,14 +1233,14 @@ TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that the first init does not SetNeedsCommit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that a needs commit initiates a BeginMainFrame.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1184,19 +1248,13 @@ TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
-
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
EXPECT_NE(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
state.NextAction());
state.DidLoseOutputSurface();
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
state.UpdateState(state.NextAction());
// Once context recreation begins, nothing should happen.
@@ -1206,7 +1264,7 @@ TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) {
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
// When the context is recreated, we should begin a commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1214,84 +1272,140 @@ TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) {
TEST(SchedulerStateMachineTest,
TestContextLostWhenIdleAndCommitRequestedWhileRecreating) {
SchedulerSettings default_scheduler_settings;
+ // We use impl side painting because it's the more complicated version.
+ default_scheduler_settings.impl_side_painting = true;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
EXPECT_NE(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
state.NextAction());
state.DidLoseOutputSurface();
+ EXPECT_EQ(state.output_surface_state(),
+ SchedulerStateMachine::OUTPUT_SURFACE_LOST);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Once context recreation begins, nothing should happen.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// While context is recreating, commits shouldn't begin.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Recreate the context
state.DidCreateAndInitializeOutputSurface();
+ EXPECT_EQ(state.output_surface_state(),
+ SchedulerStateMachine::OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT);
EXPECT_FALSE(state.RedrawPending());
- // When the context is recreated, we should begin a commit
+ // When the context is recreated, we wait until the next BeginImplFrame
+ // before starting.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // When the BeginFrame comes in we should begin a commit
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
- state.CommitState());
+ EXPECT_COMMIT_STATE(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
+
+ // Until that commit finishes, we shouldn't be drawing or animate.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ // Finish the commit, which should make the surface active.
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_EQ(state.output_surface_state(),
+ SchedulerStateMachine::OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.output_surface_state(),
+ SchedulerStateMachine::OUTPUT_SURFACE_ACTIVE);
+
// Finishing the first commit after initializing an output surface should
// automatically cause a redraw.
EXPECT_TRUE(state.RedrawPending());
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.RedrawPending());
+
+ // Next frame as no work to do.
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Once the context is recreated, whether we draw should be based on
- // SetCanDraw.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ // SetCanDraw if waiting on first draw after activate.
+ state.SetNeedsRedraw(true);
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
- state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
state.SetCanDraw(false);
- EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT,
- state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.SetCanDraw(true);
- EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
- state.NextAction());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Once the context is recreated, whether we draw should be based on
+ // SetCanDraw if waiting on first draw after activate.
+ state.SetNeedsRedraw(true);
+ state.SetNeedsCommit();
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ // Activate so we need the first draw
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
+ EXPECT_TRUE(state.needs_redraw());
+
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.SetCanDraw(false);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
+ state.SetCanDraw(true);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
}
TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
SchedulerSettings scheduler_settings;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Get a commit in flight.
state.SetNeedsCommit();
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1308,7 +1422,7 @@ TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
// Ask for another draw. Expect nothing happens.
state.SetNeedsRedraw(true);
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
// Finish the frame, and commit.
state.NotifyBeginMainFrameStarted();
@@ -1321,36 +1435,30 @@ TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
// Expect to begin context recreation only in BEGIN_IMPL_FRAME_STATE_IDLE
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ state.OnBeginImplFrame();
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadlinePending();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
}
TEST(SchedulerStateMachineTest,
TestContextLostWhileCommitInProgressAndAnotherCommitRequested) {
SchedulerSettings scheduler_settings;
StateMachine state(scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Get a commit in flight.
state.SetNeedsCommit();
@@ -1358,7 +1466,7 @@ TEST(SchedulerStateMachineTest,
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1388,25 +1496,23 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
// Expect to begin context recreation only in BEGIN_IMPL_FRAME_STATE_IDLE
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ state.OnBeginImplFrame();
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadlinePending();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
- state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_IMPL_FRAME_STATE(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(
@@ -1414,7 +1520,7 @@ TEST(SchedulerStateMachineTest,
// After we get a new output surface, the commit flow should start.
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1434,25 +1540,19 @@ TEST(SchedulerStateMachineTest,
TEST(SchedulerStateMachineTest, DontDrawBeforeCommitAfterLostOutputSurface) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsRedraw(true);
// Cause a lost output surface, and restore it.
state.DidLoseOutputSurface();
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
state.UpdateState(state.NextAction());
state.DidCreateAndInitializeOutputSurface();
EXPECT_FALSE(state.RedrawPending());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
- EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
+ state.OnBeginImplFrame();
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest,
@@ -1460,11 +1560,7 @@ TEST(SchedulerStateMachineTest,
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetCommitState(
SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
@@ -1483,6 +1579,25 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
}
+TEST(SchedulerStateMachineTest, TestNoBeginFrameNeededWhenInvisible) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetVisible(true);
+
+ EXPECT_FALSE(state.BeginFrameNeeded());
+ state.SetNeedsRedraw(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ state.SetVisible(false);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+
+ state.SetVisible(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+}
+
TEST(SchedulerStateMachineTest, TestNoBeginMainFrameWhenInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
@@ -1491,7 +1606,15 @@ TEST(SchedulerStateMachineTest, TestNoBeginMainFrameWhenInvisible) {
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(false);
state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.BeginFrameNeeded());
+
+ // When become visible again, the needs commit should still be pending.
+ state.SetVisible(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
@@ -1507,7 +1630,7 @@ TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
state.NotifyBeginMainFrameStarted();
state.NotifyReadyToCommit();
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
state.UpdateState(state.NextAction());
EXPECT_TRUE(state.active_tree_needs_first_draw());
@@ -1517,11 +1640,7 @@ TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsCommit();
state.DidLoseOutputSurface();
@@ -1538,19 +1657,13 @@ TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) {
// lost the output surface and are trying to get the first commit, since the
// main thread will just abort anyway.
state.SetVisible(false);
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction())
- << state.AsValue()->ToString();
+ EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
}
TEST(SchedulerStateMachineTest, ReportIfNotDrawing) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
-
- state.SetCanDraw(true);
- state.SetVisible(true);
+ SET_UP_STATE(state)
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
state.SetCanDraw(false);
@@ -1570,19 +1683,16 @@ TEST(SchedulerStateMachineTest, ReportIfNotDrawing) {
EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
}
-TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyAfterAbortedCommit) {
+TEST(SchedulerStateMachineTest,
+ TestTriggerDeadlineImmediatelyAfterAbortedCommit) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// This test mirrors what happens during the first frame of a scroll gesture.
// First we get the input event and a BeginFrame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
// As a response the compositor requests a redraw and a commit to tell the
// main thread about the new scroll offset.
@@ -1597,11 +1707,11 @@ TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyAfterAbortedCommit) {
// Since only the scroll offset changed, the main thread will abort the
// commit.
- state.BeginMainFrameAborted(true);
+ state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
// Since the commit was aborted, we should draw right away instead of waiting
// for the deadline.
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
}
void FinishPreviousCommitAndDrawWithoutExitingDeadline(
@@ -1617,11 +1727,11 @@ void FinishPreviousCommitAndDrawWithoutExitingDeadline(
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
@@ -1632,17 +1742,13 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// This test ensures that impl-draws are prioritized over main thread updates
// in prefer impl latency mode.
state.SetNeedsRedraw(true);
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1650,9 +1756,9 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) {
// Verify the deadline is not triggered early until we enter
// prefer impl latency mode.
- EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.SetImplLatencyTakesPriority(true);
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
// Trigger the deadline.
state.OnBeginImplFrameDeadline();
@@ -1679,52 +1785,64 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) {
// and did not just swap.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
-TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyOnLostOutputSurface) {
+TEST(SchedulerStateMachineTest,
+ TestTriggerDeadlineImmediatelyOnLostOutputSurface) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.DidLoseOutputSurface();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// The deadline should be triggered immediately when output surface is lost.
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
+}
+
+TEST(SchedulerStateMachineTest, TestTriggerDeadlineImmediatelyWhenInvisible) {
+ SchedulerSettings settings;
+ settings.impl_side_painting = true;
+ StateMachine state(settings);
+ SET_UP_STATE(state)
+
+ state.SetNeedsCommit();
+
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
+
+ state.SetVisible(false);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
}
TEST(SchedulerStateMachineTest, TestSetNeedsAnimate) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Test requesting an animation that, when run, causes us to draw.
state.SetNeedsAnimate();
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
state.OnBeginImplFrameDeadlinePending();
@@ -1737,11 +1855,7 @@ TEST(SchedulerStateMachineTest, TestAnimateBeforeCommit) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Check that animations are updated before we start a commit.
state.SetNeedsAnimate();
@@ -1750,7 +1864,7 @@ TEST(SchedulerStateMachineTest, TestAnimateBeforeCommit) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1765,11 +1879,7 @@ TEST(SchedulerStateMachineTest, TestAnimateAfterCommitBeforeDraw) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Check that animations are updated before we start a commit.
state.SetNeedsAnimate();
@@ -1778,7 +1888,7 @@ TEST(SchedulerStateMachineTest, TestAnimateAfterCommitBeforeDraw) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1798,11 +1908,7 @@ TEST(SchedulerStateMachineTest, TestSetNeedsAnimateAfterAnimate) {
SchedulerSettings settings;
settings.impl_side_painting = true;
StateMachine state(settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
+ SET_UP_STATE(state)
// Test requesting an animation after we have already animated during this
// frame.
@@ -1810,7 +1916,7 @@ TEST(SchedulerStateMachineTest, TestSetNeedsAnimateAfterAnimate) {
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
state.SetNeedsAnimate();
@@ -1821,5 +1927,51 @@ TEST(SchedulerStateMachineTest, TestSetNeedsAnimateAfterAnimate) {
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
}
+TEST(SchedulerStateMachineTest, TestForwardBeginFramesToChildren) {
+ SchedulerSettings settings;
+ StateMachine state(settings);
+ SET_UP_STATE(state)
+
+ EXPECT_FALSE(state.BeginFrameNeeded());
+ state.SetChildrenNeedBeginFrames(true);
+ EXPECT_TRUE(state.BeginFrameNeeded());
+}
+
+TEST(SchedulerStateMachineTest, TestDeferCommit) {
+ SchedulerSettings settings;
+ StateMachine state(settings);
+ SET_UP_STATE(state)
+
+ state.SetDeferCommits(true);
+
+ state.SetNeedsCommit();
+ EXPECT_FALSE(state.BeginFrameNeeded());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.SetDeferCommits(false);
+ state.OnBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
+TEST(SchedulerStateMachineTest, EarlyOutCommitWantsProactiveBeginFrame) {
+ SchedulerSettings settings;
+ StateMachine state(settings);
+ SET_UP_STATE(state);
+
+ EXPECT_FALSE(state.ProactiveBeginFrameWanted());
+ bool commit_has_no_updates = true;
+ state.UpdateStateOnCommit(commit_has_no_updates);
+ EXPECT_TRUE(state.ProactiveBeginFrameWanted());
+ state.OnBeginImplFrame();
+ EXPECT_FALSE(state.ProactiveBeginFrameWanted());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc
index 7da62676c6c..d2b12d768a5 100644
--- a/chromium/cc/scheduler/scheduler_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_unittest.cc
@@ -1,35 +1,34 @@
// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+
#include "cc/scheduler/scheduler.h"
#include <string>
#include <vector>
-#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
-#include "base/power_monitor/power_monitor.h"
-#include "base/power_monitor/power_monitor_source.h"
#include "base/run_loop.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "cc/test/begin_frame_args_test.h"
#include "cc/test/ordered_simple_task_runner.h"
#include "cc/test/scheduler_test_common.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
- do { \
- EXPECT_EQ(expected_num_actions, client.num_actions_()); \
- if (action_index >= 0) { \
- ASSERT_LT(action_index, client.num_actions_()) << scheduler; \
- EXPECT_STREQ(action, client.Action(action_index)); \
- } \
- for (int i = expected_num_actions; i < client.num_actions_(); ++i) \
- ADD_FAILURE() << "Unexpected action: " << client.Action(i) \
- << " with state:\n" << client.StateForAction(i); \
+#define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
+ do { \
+ EXPECT_EQ(expected_num_actions, client->num_actions_()); \
+ if (action_index >= 0) { \
+ ASSERT_LT(action_index, client->num_actions_()) << scheduler_.get(); \
+ EXPECT_STREQ(action, client->Action(action_index)); \
+ } \
+ for (int i = expected_num_actions; i < client->num_actions_(); ++i) \
+ ADD_FAILURE() << "Unexpected action: " << client->Action(i) \
+ << " with state:\n" << client->StateForAction(i); \
} while (false)
#define EXPECT_NO_ACTION(client) EXPECT_ACTION("", client, -1, 0)
@@ -37,64 +36,20 @@
#define EXPECT_SINGLE_ACTION(action, client) \
EXPECT_ACTION(action, client, 0, 1)
+#define EXPECT_SCOPED(statements) \
+ { \
+ SCOPED_TRACE(""); \
+ statements; \
+ }
+
namespace cc {
namespace {
-class FakeSchedulerClient;
-
-void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
- FakeSchedulerClient* client);
-
class FakeSchedulerClient : public SchedulerClient {
public:
- struct FakeBeginFrameSourceForFakeSchedulerClient
- : public FakeBeginFrameSource {
- FakeSchedulerClient* client_;
-
- explicit FakeBeginFrameSourceForFakeSchedulerClient(
- FakeSchedulerClient* client)
- : client_(client) {}
-
- void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
- if (needs_begin_frames) {
- client_->actions_.push_back("SetNeedsBeginFrames(true)");
- } else {
- client_->actions_.push_back("SetNeedsBeginFrames(false)");
- }
- client_->states_.push_back(client_->scheduler_->AsValue());
- }
- };
-
- class FakePowerMonitorSource : public base::PowerMonitorSource {
- public:
- FakePowerMonitorSource() {}
- ~FakePowerMonitorSource() override {}
- void GeneratePowerStateEvent(bool on_battery_power) {
- on_battery_power_impl_ = on_battery_power;
- ProcessPowerEvent(POWER_STATE_EVENT);
- base::MessageLoop::current()->RunUntilIdle();
- }
- bool IsOnBatteryPowerImpl() override { return on_battery_power_impl_; }
-
- private:
- bool on_battery_power_impl_;
- };
-
FakeSchedulerClient()
: automatic_swap_ack_(true),
- swap_contains_incomplete_tile_(false),
- redraw_will_happen_if_update_visible_tiles_happens_(false),
- now_src_(TestNowSource::Create()),
- task_runner_(new OrderedSimpleTaskRunner(now_src_, true)),
- fake_frame_source_(this),
- fake_power_monitor_source_(new FakePowerMonitorSource),
- power_monitor_(make_scoped_ptr<base::PowerMonitorSource>(
- fake_power_monitor_source_)),
scheduler_(nullptr) {
- // A bunch of tests require Now() to be > BeginFrameArgs::DefaultInterval()
- now_src_->AdvanceNow(base::TimeDelta::FromMilliseconds(100));
- // Fail if we need to run 100 tasks in a row.
- task_runner_->SetRunTaskLimit(100);
Reset();
}
@@ -105,21 +60,19 @@ class FakeSchedulerClient : public SchedulerClient {
swap_will_happen_if_draw_happens_ = true;
num_draws_ = 0;
log_anticipated_draw_time_change_ = false;
+ begin_frame_args_sent_to_children_ = BeginFrameArgs();
}
- TestScheduler* CreateScheduler(const SchedulerSettings& settings) {
- scheduler_ = TestScheduler::Create(
- now_src_, this, settings, 0, task_runner_, &power_monitor_);
- DCHECK(scheduler_);
- return scheduler_.get();
- }
+ void set_scheduler(TestScheduler* scheduler) { scheduler_ = scheduler; }
// Most tests don't care about DidAnticipatedDrawTimeChange, so only record it
// for tests that do.
void set_log_anticipated_draw_time_change(bool log) {
log_anticipated_draw_time_change_ = log;
}
- bool needs_begin_frames() { return fake_frame_source_.NeedsBeginFrames(); }
+ bool needs_begin_frames() {
+ return scheduler_->frame_source().NeedsBeginFrames();
+ }
int num_draws() const { return num_draws_; }
int num_actions_() const { return static_cast<int>(actions_.size()); }
const char* Action(int i) const { return actions_[i]; }
@@ -128,40 +81,6 @@ class FakeSchedulerClient : public SchedulerClient {
return posted_begin_impl_frame_deadline_;
}
- bool ExternalBeginFrame() {
- return scheduler_->settings().begin_frame_scheduling_enabled &&
- scheduler_->settings().throttle_frame_production;
- }
- FakeBeginFrameSource* ExternalBeginFrameSource() override {
- return &fake_frame_source_;
- }
-
- base::PowerMonitor* PowerMonitor() { return &power_monitor_; }
-
- FakePowerMonitorSource* PowerMonitorSource() {
- return fake_power_monitor_source_;
- }
-
- void AdvanceFrame() {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
- "FakeSchedulerClient::AdvanceFrame");
- // EXPECT_TRUE(needs_begin_frames());
- if (ExternalBeginFrame()) {
- // Creep the time forward so that any BeginFrameArgs is not equal to the
- // last one otherwise we violate the BeginFrameSource contract.
- now_src_->AdvanceNowMicroseconds(1);
- fake_frame_source_.TestOnBeginFrame(
- CreateBeginFrameArgsForTesting(now_src_));
- EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- }
-
- EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(false)));
- EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- }
-
- OrderedSimpleTaskRunner& task_runner() { return *task_runner_; }
- TestNowSource* now_src() { return now_src_.get(); }
-
int ActionIndex(const char* action) const {
for (size_t i = 0; i < actions_.size(); i++)
if (!strcmp(actions_[i], action))
@@ -169,10 +88,6 @@ class FakeSchedulerClient : public SchedulerClient {
return -1;
}
- void SetSwapContainsIncompleteTile(bool contain) {
- swap_contains_incomplete_tile_ = contain;
- }
-
bool HasAction(const char* action) const {
return ActionIndex(action) >= 0;
}
@@ -186,25 +101,20 @@ class FakeSchedulerClient : public SchedulerClient {
void SetAutomaticSwapAck(bool automatic_swap_ack) {
automatic_swap_ack_ = automatic_swap_ack;
}
- void SetRedrawWillHappenIfUpdateVisibleTilesHappens(bool redraw) {
- redraw_will_happen_if_update_visible_tiles_happens_ = redraw;
- }
// SchedulerClient implementation.
void WillBeginImplFrame(const BeginFrameArgs& args) override {
- actions_.push_back("WillBeginImplFrame");
- states_.push_back(scheduler_->AsValue());
+ PushAction("WillBeginImplFrame");
}
+ void DidFinishImplFrame() override {}
+
void ScheduledActionSendBeginMainFrame() override {
- actions_.push_back("ScheduledActionSendBeginMainFrame");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionSendBeginMainFrame");
}
void ScheduledActionAnimate() override {
- actions_.push_back("ScheduledActionAnimate");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionAnimate");
}
DrawResult ScheduledActionDrawAndSwapIfPossible() override {
- actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionDrawAndSwapIfPossible");
num_draws_++;
DrawResult result =
draw_will_happen_ ? DRAW_SUCCESS : DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
@@ -212,12 +122,6 @@ class FakeSchedulerClient : public SchedulerClient {
draw_will_happen_ && swap_will_happen_if_draw_happens_;
if (swap_will_happen) {
scheduler_->DidSwapBuffers();
- if (swap_contains_incomplete_tile_) {
- scheduler_->SetSwapUsedIncompleteTile(true);
- swap_contains_incomplete_tile_ = false;
- } else {
- scheduler_->SetSwapUsedIncompleteTile(false);
- }
if (automatic_swap_ack_)
scheduler_->DidSwapBuffersComplete();
@@ -225,35 +129,26 @@ class FakeSchedulerClient : public SchedulerClient {
return result;
}
DrawResult ScheduledActionDrawAndSwapForced() override {
- actions_.push_back("ScheduledActionDrawAndSwapForced");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionDrawAndSwapForced");
return DRAW_SUCCESS;
}
- void ScheduledActionCommit() override {
- actions_.push_back("ScheduledActionCommit");
- states_.push_back(scheduler_->AsValue());
- }
- void ScheduledActionUpdateVisibleTiles() override {
- actions_.push_back("ScheduledActionUpdateVisibleTiles");
- states_.push_back(scheduler_->AsValue());
- if (redraw_will_happen_if_update_visible_tiles_happens_)
- scheduler_->SetNeedsRedraw();
- }
+ void ScheduledActionCommit() override { PushAction("ScheduledActionCommit"); }
void ScheduledActionActivateSyncTree() override {
- actions_.push_back("ScheduledActionActivateSyncTree");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionActivateSyncTree");
}
void ScheduledActionBeginOutputSurfaceCreation() override {
- actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
- states_.push_back(scheduler_->AsValue());
+ PushAction("ScheduledActionBeginOutputSurfaceCreation");
+ }
+ void ScheduledActionPrepareTiles() override {
+ PushAction("ScheduledActionPrepareTiles");
}
- void ScheduledActionManageTiles() override {
- actions_.push_back("ScheduledActionManageTiles");
+ void ScheduledActionInvalidateOutputSurface() override {
+ actions_.push_back("ScheduledActionInvalidateOutputSurface");
states_.push_back(scheduler_->AsValue());
}
void DidAnticipatedDrawTimeChange(base::TimeTicks) override {
if (log_anticipated_draw_time_change_)
- actions_.push_back("DidAnticipatedDrawTimeChange");
+ PushAction("DidAnticipatedDrawTimeChange");
}
base::TimeDelta DrawDurationEstimate() override { return base::TimeDelta(); }
base::TimeDelta BeginMainFrameToCommitDurationEstimate() override {
@@ -263,7 +158,13 @@ class FakeSchedulerClient : public SchedulerClient {
return base::TimeDelta();
}
- void DidBeginImplFrameDeadline() override {}
+ void SendBeginFramesToChildren(const BeginFrameArgs& args) override {
+ begin_frame_args_sent_to_children_ = args;
+ }
+
+ void SendBeginMainFrameNotExpectedSoon() override {
+ PushAction("SendBeginMainFrameNotExpectedSoon");
+ }
base::Callback<bool(void)> ImplFrameDeadlinePending(bool state) {
return base::Bind(&FakeSchedulerClient::ImplFrameDeadlinePendingCallback,
@@ -271,6 +172,19 @@ class FakeSchedulerClient : public SchedulerClient {
state);
}
+ bool begin_frame_is_sent_to_children() const {
+ return begin_frame_args_sent_to_children_.IsValid();
+ }
+
+ const BeginFrameArgs& begin_frame_args_sent_to_children() const {
+ return begin_frame_args_sent_to_children_;
+ }
+
+ void PushAction(const char* description) {
+ actions_.push_back(description);
+ states_.push_back(scheduler_->AsValue());
+ }
+
protected:
bool ImplFrameDeadlinePendingCallback(bool state) {
return scheduler_->BeginImplFrameDeadlinePending() == state;
@@ -281,217 +195,548 @@ class FakeSchedulerClient : public SchedulerClient {
bool automatic_swap_ack_;
int num_draws_;
bool log_anticipated_draw_time_change_;
- bool swap_contains_incomplete_tile_;
- bool redraw_will_happen_if_update_visible_tiles_happens_;
+ BeginFrameArgs begin_frame_args_sent_to_children_;
base::TimeTicks posted_begin_impl_frame_deadline_;
std::vector<const char*> actions_;
- std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat>> states_;
+ std::vector<scoped_refptr<base::trace_event::ConvertableToTraceFormat>>
+ states_;
+ TestScheduler* scheduler_;
+};
+
+class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
+ public:
+ SchedulerClientWithFixedEstimates(
+ base::TimeDelta draw_duration,
+ base::TimeDelta begin_main_frame_to_commit_duration,
+ base::TimeDelta commit_to_activate_duration)
+ : draw_duration_(draw_duration),
+ begin_main_frame_to_commit_duration_(
+ begin_main_frame_to_commit_duration),
+ commit_to_activate_duration_(commit_to_activate_duration) {}
+
+ base::TimeDelta DrawDurationEstimate() override { return draw_duration_; }
+ base::TimeDelta BeginMainFrameToCommitDurationEstimate() override {
+ return begin_main_frame_to_commit_duration_;
+ }
+ base::TimeDelta CommitToActivateDurationEstimate() override {
+ return commit_to_activate_duration_;
+ }
+
+ private:
+ base::TimeDelta draw_duration_;
+ base::TimeDelta begin_main_frame_to_commit_duration_;
+ base::TimeDelta commit_to_activate_duration_;
+};
+
+class FakeExternalBeginFrameSource : public BeginFrameSourceMixIn {
+ public:
+ explicit FakeExternalBeginFrameSource(FakeSchedulerClient* client)
+ : client_(client) {}
+ ~FakeExternalBeginFrameSource() override {}
+
+ void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
+ if (needs_begin_frames) {
+ client_->PushAction("SetNeedsBeginFrames(true)");
+ } else {
+ client_->PushAction("SetNeedsBeginFrames(false)");
+ }
+ }
+
+ void TestOnBeginFrame(const BeginFrameArgs& args) {
+ return CallOnBeginFrame(args);
+ }
+
+ private:
+ FakeSchedulerClient* client_;
+};
+
+class SchedulerTest : public testing::Test {
+ public:
+ SchedulerTest()
+ : now_src_(TestNowSource::Create()),
+ task_runner_(new OrderedSimpleTaskRunner(now_src_, true)),
+ fake_external_begin_frame_source_(nullptr) {
+ // A bunch of tests require Now() to be > BeginFrameArgs::DefaultInterval()
+ now_src_->AdvanceNow(base::TimeDelta::FromMilliseconds(100));
+ // Fail if we need to run 100 tasks in a row.
+ task_runner_->SetRunTaskLimit(100);
+ }
+
+ ~SchedulerTest() override {}
+
+ protected:
+ TestScheduler* CreateScheduler() {
+ scoped_ptr<FakeExternalBeginFrameSource> fake_external_begin_frame_source;
+ if (scheduler_settings_.use_external_begin_frame_source) {
+ fake_external_begin_frame_source.reset(
+ new FakeExternalBeginFrameSource(client_.get()));
+ fake_external_begin_frame_source_ =
+ fake_external_begin_frame_source.get();
+ }
+ scheduler_ = TestScheduler::Create(now_src_, client_.get(),
+ scheduler_settings_, 0, task_runner_,
+ fake_external_begin_frame_source.Pass());
+ DCHECK(scheduler_);
+ client_->set_scheduler(scheduler_.get());
+ return scheduler_.get();
+ }
+
+ void CreateSchedulerAndInitSurface() {
+ CreateScheduler();
+ EXPECT_SCOPED(InitializeOutputSurfaceAndFirstCommit());
+ }
+
+ void SetUpScheduler(bool initSurface) {
+ SetUpScheduler(make_scoped_ptr(new FakeSchedulerClient), initSurface);
+ }
+
+ void SetUpScheduler(scoped_ptr<FakeSchedulerClient> client,
+ bool initSurface) {
+ client_ = client.Pass();
+ if (initSurface)
+ CreateSchedulerAndInitSurface();
+ else
+ CreateScheduler();
+ }
+
+ OrderedSimpleTaskRunner& task_runner() { return *task_runner_; }
+ TestNowSource* now_src() { return now_src_.get(); }
+
+ // As this function contains EXPECT macros, to allow debugging it should be
+ // called inside EXPECT_SCOPED like so;
+ // EXPECT_SCOPED(client.InitializeOutputSurfaceAndFirstCommit(scheduler));
+ void InitializeOutputSurfaceAndFirstCommit() {
+ TRACE_EVENT0("cc",
+ "SchedulerUnitTest::InitializeOutputSurfaceAndFirstCommit");
+ DCHECK(scheduler_);
+
+ // Check the client doesn't have any actions queued when calling this
+ // function.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(client_->needs_begin_frames());
+
+ // Start the initial output surface creation.
+ EXPECT_FALSE(scheduler_->CanStart());
+ scheduler_->SetCanStart();
+ scheduler_->SetVisible(true);
+ scheduler_->SetCanDraw(true);
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+
+ client_->Reset();
+
+ // We don't see anything happening until the first impl frame.
+ scheduler_->DidCreateAndInitializeOutputSurface();
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ {
+ SCOPED_TRACE("Do first frame to commit after initialize.");
+ AdvanceFrame();
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommitThenActivateIfNeeded();
+
+ EXPECT_FALSE(scheduler_->CommitPending());
+
+ if (scheduler_settings_.using_synchronous_renderer_compositor) {
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ } else {
+ // Run the posted deadline task.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ }
+
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ }
+
+ client_->Reset();
+
+ {
+ SCOPED_TRACE(
+ "Run second frame so Scheduler calls SetNeedsBeginFrame(false).");
+ AdvanceFrame();
+
+ if (!scheduler_settings_.using_synchronous_renderer_compositor) {
+ // Run the posted deadline task.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ }
+
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ }
+
+ EXPECT_FALSE(client_->needs_begin_frames());
+ client_->Reset();
+ }
+
+ // As this function contains EXPECT macros, to allow debugging it should be
+ // called inside EXPECT_SCOPED like so;
+ // EXPECT_SCOPED(client.AdvanceFrame());
+ void AdvanceFrame() {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
+ "FakeSchedulerClient::AdvanceFrame");
+ // Consume any previous deadline first, if no deadline is currently
+ // pending, ImplFrameDeadlinePending will return false straight away and we
+ // will run no tasks.
+ task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Send the next BeginFrame message if using an external source, otherwise
+ // it will be already in the task queue.
+ if (scheduler_->settings().use_external_begin_frame_source &&
+ scheduler_->FrameProductionThrottled()) {
+ EXPECT_TRUE(client_->needs_begin_frames());
+ SendNextBeginFrame();
+ }
+
+ if (!scheduler_->settings().using_synchronous_renderer_compositor) {
+ // Then run tasks until new deadline is scheduled.
+ EXPECT_TRUE(task_runner_->RunTasksWhile(
+ client_->ImplFrameDeadlinePending(false)));
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ }
+ }
+
+ void SendNextBeginFrame() {
+ DCHECK(scheduler_->settings().use_external_begin_frame_source);
+ // Creep the time forward so that any BeginFrameArgs is not equal to the
+ // last one otherwise we violate the BeginFrameSource contract.
+ now_src_->AdvanceNow(BeginFrameArgs::DefaultInterval());
+ fake_external_begin_frame_source_->TestOnBeginFrame(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src()));
+ }
+
+ FakeExternalBeginFrameSource* fake_external_begin_frame_source() const {
+ return fake_external_begin_frame_source_;
+ }
+
+ void MainFrameInHighLatencyMode(
+ int64 begin_main_frame_to_commit_estimate_in_ms,
+ int64 commit_to_activate_estimate_in_ms,
+ bool impl_latency_takes_priority,
+ bool should_send_begin_main_frame);
+ void BeginFramesNotFromClient(bool use_external_begin_frame_source,
+ bool throttle_frame_production);
+ void BeginFramesNotFromClient_SwapThrottled(
+ bool use_external_begin_frame_source,
+ bool throttle_frame_production);
+ void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
+ bool impl_side_painting);
+ void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting);
+
scoped_refptr<TestNowSource> now_src_;
scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
- FakeBeginFrameSourceForFakeSchedulerClient fake_frame_source_;
- FakePowerMonitorSource* fake_power_monitor_source_;
- base::PowerMonitor power_monitor_;
+ FakeExternalBeginFrameSource* fake_external_begin_frame_source_;
+ SchedulerSettings scheduler_settings_;
+ scoped_ptr<FakeSchedulerClient> client_;
scoped_ptr<TestScheduler> scheduler_;
};
-void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
- FakeSchedulerClient* client) {
- TRACE_EVENT0("cc",
- "SchedulerUnitTest::InitializeOutputSurfaceAndFirstCommit");
-
- scheduler->DidCreateAndInitializeOutputSurface();
- scheduler->SetNeedsCommit();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- if (scheduler->settings().impl_side_painting)
- scheduler->NotifyReadyToActivate();
-
- {
- SCOPED_TRACE("Go through the motions to draw the commit");
- client->AdvanceFrame();
- }
+TEST_F(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(false);
+ scheduler_->SetCanStart();
+ scheduler_->SetVisible(true);
+ scheduler_->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+ client_->Reset();
+ scheduler_->DidCreateAndInitializeOutputSurface();
+ EXPECT_NO_ACTION(client_);
+}
- // Run the posted deadline task.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+TEST_F(SchedulerTest, SendBeginFramesToChildren) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- {
- SCOPED_TRACE(
- "We need another BeginImplFrame so Scheduler calls "
- "SetNeedsBeginFrame(false).");
- client->AdvanceFrame();
- }
+ EXPECT_FALSE(client_->begin_frame_is_sent_to_children());
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ scheduler_->SetChildrenNeedBeginFrames(true);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(client_->needs_begin_frames());
+}
- // Run the posted deadline task.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+TEST_F(SchedulerTest, SendBeginFramesToChildrenWithoutCommit) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- // EXPECT_FALSE(client->needs_begin_frames());
+ EXPECT_FALSE(client_->needs_begin_frames());
+ scheduler_->SetChildrenNeedBeginFrames(true);
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
}
-TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
- FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- client.Reset();
- scheduler->DidCreateAndInitializeOutputSurface();
- EXPECT_NO_ACTION(client);
+TEST_F(SchedulerTest, SendBeginFramesToChildrenDeadlineNotAdjusted) {
+ // Set up client with specified estimates.
+ SchedulerClientWithFixedEstimates* client =
+ new SchedulerClientWithFixedEstimates(
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMilliseconds(2),
+ base::TimeDelta::FromMilliseconds(4));
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ EXPECT_FALSE(client_->needs_begin_frames());
+ scheduler_->SetChildrenNeedBeginFrames(true);
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+
+ BeginFrameArgs frame_args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
+ fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
+
+ EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
+ EXPECT_EQ(client_->begin_frame_args_sent_to_children().deadline,
+ frame_args.deadline);
}
-TEST(SchedulerTest, RequestCommit) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+TEST_F(SchedulerTest, VideoNeedsBeginFrames) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetVideoNeedsBeginFrames(true);
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ // WillBeginImplFrame is responsible for sending BeginFrames to video.
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+
+ client_->Reset();
+ scheduler_->SetVideoNeedsBeginFrames(false);
+ EXPECT_NO_ACTION(client_);
+
+ client_->Reset();
+ task_runner_->RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_FALSE(client_->needs_begin_frames());
+}
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, RequestCommit) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// If we don't swap on the deadline, we wait for the next BeginFrame.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// NotifyReadyToCommit should trigger the commit.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// BeginImplFrame should prepare the draw.
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// BeginImplFrame deadline should draw.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// to avoid excessive toggles.
- client.AdvanceFrame();
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ client_->Reset();
+}
+
+TEST_F(SchedulerTest, RequestCommitAfterSetDeferCommit) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetDeferCommits(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_NO_ACTION(client_);
+
+ client_->Reset();
+ task_runner().RunPendingTasks();
+ // There are no pending tasks or actions.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(client_->needs_begin_frames());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
- client.Reset();
+ client_->Reset();
+ scheduler_->SetDeferCommits(false);
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ // Start new BeginMainFrame after defer commit is off.
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
}
-TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+TEST_F(SchedulerTest, DeferCommitWithRedraw) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetDeferCommits(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_NO_ACTION(client_);
+
+ // The SetNeedsRedraw will override the SetDeferCommits(true), to allow a
+ // begin frame to be needed.
+ client_->Reset();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ AdvanceFrame();
+ // BeginMainFrame is not sent during the defer commit is on.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ AdvanceFrame();
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+}
+
+TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame.
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Now SetNeedsCommit again. Calling here means we need a second commit.
- scheduler->SetNeedsCommit();
- EXPECT_EQ(client.num_actions_(), 0);
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_EQ(client_->num_actions_(), 0);
+ client_->Reset();
// Finish the first commit.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
// Because we just swapped, the Scheduler should also request the next
// BeginImplFrame from the OutputSurface.
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Since another commit is needed, the next BeginImplFrame should initiate
// the second commit.
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// Finishing the commit before the deadline should post a new deadline task
// to trigger the deadline early.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// On the next BeginImplFrame, verify we go back to a quiescent state and
// no longer request BeginImplFrames.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_FALSE(client_->needs_begin_frames());
+ client_->Reset();
}
class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
public:
+ SchedulerClientThatsetNeedsDrawInsideDraw()
+ : FakeSchedulerClient(), request_redraws_(false) {}
+
void ScheduledActionSendBeginMainFrame() override {}
+
+ void SetRequestRedrawsInsideDraw(bool enable) { request_redraws_ = enable; }
+
DrawResult ScheduledActionDrawAndSwapIfPossible() override {
// Only SetNeedsRedraw the first time this is called
- if (!num_draws_)
+ if (request_redraws_) {
scheduler_->SetNeedsRedraw();
+ }
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
}
@@ -501,95 +746,95 @@ class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
}
void ScheduledActionCommit() override {}
- void ScheduledActionBeginOutputSurfaceCreation() override {}
void DidAnticipatedDrawTimeChange(base::TimeTicks) override {}
+
+ private:
+ bool request_redraws_;
};
// Tests for two different situations:
// 1. the scheduler dropping SetNeedsRedraw requests that happen inside
// a ScheduledActionDrawAndSwap
// 2. the scheduler drawing twice inside a single tick
-TEST(SchedulerTest, RequestRedrawInsideDraw) {
- SchedulerClientThatsetNeedsDrawInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
-
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
-
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+TEST_F(SchedulerTest, RequestRedrawInsideDraw) {
+ SchedulerClientThatsetNeedsDrawInsideDraw* client =
+ new SchedulerClientThatsetNeedsDrawInsideDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+ client->SetRequestRedrawsInsideDraw(true);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
+
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+
+ client->SetRequestRedrawsInsideDraw(false);
+
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client_->num_draws());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(client.needs_begin_frames());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(client->needs_begin_frames());
}
// Test that requesting redraw inside a failed draw doesn't lose the request.
-TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
- SchedulerClientThatsetNeedsDrawInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- client.SetDrawWillHappen(false);
-
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
+TEST_F(SchedulerTest, RequestRedrawInsideFailedDraw) {
+ SchedulerClientThatsetNeedsDrawInsideDraw* client =
+ new SchedulerClientThatsetNeedsDrawInsideDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ client->SetRequestRedrawsInsideDraw(true);
+ client->SetDrawWillHappen(false);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
// Fail the draw.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
// We have a commit pending and the draw failed, and we didn't lose the redraw
// request.
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+
+ client->SetRequestRedrawsInsideDraw(false);
// Fail the draw again.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// Draw successfully.
- client.SetDrawWillHappen(true);
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(3, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ client->SetDrawWillHappen(true);
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(3, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
}
class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
@@ -613,7 +858,6 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
}
void ScheduledActionCommit() override {}
- void ScheduledActionBeginOutputSurfaceCreation() override {}
void DidAnticipatedDrawTimeChange(base::TimeTicks) override {}
void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; }
@@ -624,1521 +868,1844 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
// Tests for the scheduler infinite-looping on SetNeedsCommit requests that
// happen inside a ScheduledActionDrawAndSwap
-TEST(SchedulerTest, RequestCommitInsideDraw) {
- SchedulerClientThatSetNeedsCommitInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- EXPECT_FALSE(client.needs_begin_frames());
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_EQ(0, client.num_draws());
- EXPECT_TRUE(client.needs_begin_frames());
-
- client.SetNeedsCommitOnNextDraw();
- client.AdvanceFrame();
- client.SetNeedsCommitOnNextDraw();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(client.needs_begin_frames());
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
-
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
-
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->CommitPending());
- EXPECT_TRUE(client.needs_begin_frames());
+TEST_F(SchedulerTest, RequestCommitInsideDraw) {
+ SchedulerClientThatSetNeedsCommitInsideDraw* client =
+ new SchedulerClientThatSetNeedsCommitInsideDraw;
+
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ EXPECT_FALSE(client->needs_begin_frames());
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_EQ(0, client->num_draws());
+ EXPECT_TRUE(client->needs_begin_frames());
+
+ client->SetNeedsCommitOnNextDraw();
+ EXPECT_SCOPED(AdvanceFrame());
+ client->SetNeedsCommitOnNextDraw();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->CommitPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->CommitPending());
- EXPECT_FALSE(client.needs_begin_frames());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->CommitPending());
+ EXPECT_FALSE(client->needs_begin_frames());
}
// Tests that when a draw fails then the pending commit should not be dropped.
-TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
- SchedulerClientThatsetNeedsDrawInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- client.SetDrawWillHappen(false);
-
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
+TEST_F(SchedulerTest, RequestCommitInsideFailedDraw) {
+ SchedulerClientThatsetNeedsDrawInsideDraw* client =
+ new SchedulerClientThatsetNeedsDrawInsideDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ client->SetDrawWillHappen(false);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
// Fail the draw.
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
// We have a commit pending and the draw failed, and we didn't lose the commit
// request.
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// Fail the draw again.
- client.AdvanceFrame();
+ EXPECT_SCOPED(AdvanceFrame());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// Draw successfully.
- client.SetDrawWillHappen(true);
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(3, client.num_draws());
- EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ client->SetDrawWillHappen(true);
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(3, client->num_draws());
+ EXPECT_TRUE(scheduler_->CommitPending());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
}
-TEST(SchedulerTest, NoSwapWhenDrawFails) {
- SchedulerClientThatSetNeedsCommitInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- client.Reset();
-
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
+TEST_F(SchedulerTest, NoSwapWhenDrawFails) {
+ SchedulerClientThatSetNeedsCommitInsideDraw* client =
+ new SchedulerClientThatSetNeedsCommitInsideDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
// Draw successfully, this starts a new frame.
- client.SetNeedsCommitOnNextDraw();
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
+ client->SetNeedsCommitOnNextDraw();
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_frames());
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(client->needs_begin_frames());
// Fail to draw, this should not start a frame.
- client.SetDrawWillHappen(false);
- client.SetNeedsCommitOnNextDraw();
- client.AdvanceFrame();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client.num_draws());
+ client->SetDrawWillHappen(false);
+ client->SetNeedsCommitOnNextDraw();
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(2, client->num_draws());
}
-class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
+class SchedulerClientNeedsPrepareTilesInDraw : public FakeSchedulerClient {
public:
DrawResult ScheduledActionDrawAndSwapIfPossible() override {
- scheduler_->SetNeedsManageTiles();
+ scheduler_->SetNeedsPrepareTiles();
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
}
};
-// Test manage tiles is independant of draws.
-TEST(SchedulerTest, ManageTiles) {
- SchedulerClientNeedsManageTilesInDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- // Request both draw and manage tiles. ManageTiles shouldn't
+// Test prepare tiles is independant of draws.
+TEST_F(SchedulerTest, PrepareTiles) {
+ SchedulerClientNeedsPrepareTilesInDraw* client =
+ new SchedulerClientNeedsPrepareTilesInDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ // Request both draw and prepare tiles. PrepareTiles shouldn't
// be trigged until BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(scheduler->ManageTilesPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
- EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ client->Reset();
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
+ EXPECT_FALSE(client->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
// We have no immediate actions to perform, so the BeginImplFrame should post
// the deadline task.
- client.Reset();
- client.AdvanceFrame();
+ client->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
// On the deadline, he actions should have occured in the right order.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
- client.ActionIndex("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->ManageTilesPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- // Request a draw. We don't need a ManageTiles yet.
- client.Reset();
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->ManageTilesPending());
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_EQ(0, client.num_draws());
+ client->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
+ EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_LT(client->ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
+ client->ActionIndex("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Request a draw. We don't need a PrepareTiles yet.
+ client->Reset();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_TRUE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_EQ(0, client->num_draws());
// We have no immediate actions to perform, so the BeginImplFrame should post
// the deadline task.
- client.Reset();
- client.AdvanceFrame();
+ client->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- // Draw. The draw will trigger SetNeedsManageTiles, and
- // then the ManageTiles action will be triggered after the Draw.
- // Afterwards, neither a draw nor ManageTiles are pending.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
- client.ActionIndex("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->ManageTilesPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Draw. The draw will trigger SetNeedsPrepareTiles, and
+ // then the PrepareTiles action will be triggered after the Draw.
+ // Afterwards, neither a draw nor PrepareTiles are pending.
+ client->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client->num_draws());
+ EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_LT(client->ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
+ client->ActionIndex("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
// We need a BeginImplFrame where we don't swap to go idle.
- client.Reset();
- client.AdvanceFrame();
+ client->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_EQ(0, client.num_draws());
-
- // Now trigger a ManageTiles outside of a draw. We will then need
- // a begin-frame for the ManageTiles, but we don't need a draw.
- client.Reset();
- EXPECT_FALSE(client.needs_begin_frames());
- scheduler->SetNeedsManageTiles();
- EXPECT_TRUE(client.needs_begin_frames());
- EXPECT_TRUE(scheduler->ManageTilesPending());
- EXPECT_FALSE(scheduler->RedrawPending());
-
- // BeginImplFrame. There will be no draw, only ManageTiles.
- client.Reset();
- client.AdvanceFrame();
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_EQ(0, client->num_draws());
+
+ // Now trigger a PrepareTiles outside of a draw. We will then need
+ // a begin-frame for the PrepareTiles, but we don't need a draw.
+ client->Reset();
+ EXPECT_FALSE(client->needs_begin_frames());
+ scheduler_->SetNeedsPrepareTiles();
+ EXPECT_TRUE(client->needs_begin_frames());
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->RedrawPending());
+
+ // BeginImplFrame. There will be no draw, only PrepareTiles.
+ client->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(0, client.num_draws());
- EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(0, client->num_draws());
+ EXPECT_FALSE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
}
-// Test that ManageTiles only happens once per frame. If an external caller
-// initiates it, then the state machine should not ManageTiles on that frame.
-TEST(SchedulerTest, ManageTilesOncePerFrame) {
- FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- // If DidManageTiles during a frame, then ManageTiles should not occur again.
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- EXPECT_TRUE(scheduler->ManageTilesPending());
- scheduler->DidManageTiles(); // An explicit ManageTiles.
- EXPECT_FALSE(scheduler->ManageTilesPending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->ManageTilesPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- // Next frame without DidManageTiles should ManageTiles with draw.
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
- client.ActionIndex("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->ManageTilesPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
-
- // If we get another DidManageTiles within the same frame, we should
- // not ManageTiles on the next frame.
- scheduler->DidManageTiles(); // An explicit ManageTiles.
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- EXPECT_TRUE(scheduler->ManageTilesPending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- // If we get another DidManageTiles, we should not ManageTiles on the next
- // frame. This verifies we don't alternate calling ManageTiles once and twice.
- EXPECT_TRUE(scheduler->ManageTilesPending());
- scheduler->DidManageTiles(); // An explicit ManageTiles.
- EXPECT_FALSE(scheduler->ManageTilesPending());
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- EXPECT_TRUE(scheduler->ManageTilesPending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- // Next frame without DidManageTiles should ManageTiles with draw.
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client.num_draws());
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
- EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
- EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
- client.ActionIndex("ScheduledActionManageTiles"));
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(scheduler->ManageTilesPending());
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
+// Test that PrepareTiles only happens once per frame. If an external caller
+// initiates it, then the state machine should not PrepareTiles on that frame.
+TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ // If DidPrepareTiles during a frame, then PrepareTiles should not occur
+ // again.
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+ scheduler_->DidPrepareTiles(); // An explicit PrepareTiles.
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Next frame without DidPrepareTiles should PrepareTiles with draw.
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_LT(client_->ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
+ client_->ActionIndex("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ scheduler_->DidPrepareTiles(); // Corresponds to ScheduledActionPrepareTiles
+
+ // If we get another DidPrepareTiles within the same frame, we should
+ // not PrepareTiles on the next frame.
+ scheduler_->DidPrepareTiles(); // An explicit PrepareTiles.
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // If we get another DidPrepareTiles, we should not PrepareTiles on the next
+ // frame. This verifies we don't alternate calling PrepareTiles once and
+ // twice.
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+ scheduler_->DidPrepareTiles(); // An explicit PrepareTiles.
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ EXPECT_TRUE(scheduler_->PrepareTilesPending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // Next frame without DidPrepareTiles should PrepareTiles with draw.
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
+ EXPECT_LT(client_->ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
+ client_->ActionIndex("ScheduledActionPrepareTiles"));
+ EXPECT_FALSE(scheduler_->RedrawPending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ scheduler_->DidPrepareTiles(); // Corresponds to ScheduledActionPrepareTiles
}
-TEST(SchedulerTest, ShouldUpdateVisibleTiles) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.impl_side_painting = true;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- client.SetRedrawWillHappenIfUpdateVisibleTilesHappens(true);
+TEST_F(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
+ SchedulerClientNeedsPrepareTilesInDraw* client =
+ new SchedulerClientNeedsPrepareTilesInDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
- // SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SCOPED(AdvanceFrame());
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
-
- client.Reset();
- scheduler->NotifyReadyToActivate();
- EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
-
- client.Reset();
- client.SetSwapContainsIncompleteTile(true);
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->RedrawPending());
-
- client.Reset();
- client.AdvanceFrame();
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionUpdateVisibleTiles", client, 0, 3);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 3);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3);
+ // The deadline should be zero since there is no work other than drawing
+ // pending.
+ EXPECT_EQ(base::TimeTicks(), client->posted_begin_impl_frame_deadline());
+}
- client.Reset();
- client.AdvanceFrame();
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+TEST_F(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) {
+ SchedulerClientNeedsPrepareTilesInDraw* client =
+ new SchedulerClientNeedsPrepareTilesInDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
- // No more UpdateVisibleTiles().
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Begin new frame.
+ EXPECT_SCOPED(AdvanceFrame());
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+
+ client_->Reset();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ scheduler_->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
+
+ // Set scheduler to wait for ready to draw. Schedule won't post deadline in
+ // the mode.
+ scheduler_->SetWaitForReadyToDraw();
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Try to run posted deadline.
+ // There is no posted deadline.
+ EXPECT_NO_ACTION(client_);
+
+ // Scheduler received ready to draw signal, and posted deadline.
+ scheduler_->NotifyReadyToDraw();
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client_->num_draws());
+ EXPECT_TRUE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
}
-TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
- SchedulerClientNeedsManageTilesInDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- client.Reset();
- scheduler->SetNeedsRedraw();
- client.AdvanceFrame();
+TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostOutputSurface) {
+ SchedulerClientNeedsPrepareTilesInDraw* client =
+ new SchedulerClientNeedsPrepareTilesInDraw;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
- // The deadline should be zero since there is no work other than drawing
- // pending.
- EXPECT_EQ(base::TimeTicks(), client.posted_begin_impl_frame_deadline());
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Begin new frame.
+ EXPECT_SCOPED(AdvanceFrame());
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+
+ client_->Reset();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ scheduler_->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
+
+ // Set scheduler to wait for ready to draw. Schedule won't post deadline in
+ // the mode.
+ scheduler_->SetWaitForReadyToDraw();
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Try to run posted deadline.
+ // There is no posted deadline.
+ EXPECT_NO_ACTION(client_);
+
+ // Scheduler loses output surface, and stops waiting for ready to draw signal.
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
-class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
- public:
- SchedulerClientWithFixedEstimates(
- base::TimeDelta draw_duration,
- base::TimeDelta begin_main_frame_to_commit_duration,
- base::TimeDelta commit_to_activate_duration)
- : draw_duration_(draw_duration),
- begin_main_frame_to_commit_duration_(
- begin_main_frame_to_commit_duration),
- commit_to_activate_duration_(commit_to_activate_duration) {}
-
- base::TimeDelta DrawDurationEstimate() override { return draw_duration_; }
- base::TimeDelta BeginMainFrameToCommitDurationEstimate() override {
- return begin_main_frame_to_commit_duration_;
- }
- base::TimeDelta CommitToActivateDurationEstimate() override {
- return commit_to_activate_duration_;
- }
+void SchedulerTest::MainFrameInHighLatencyMode(
+ int64 begin_main_frame_to_commit_estimate_in_ms,
+ int64 commit_to_activate_estimate_in_ms,
+ bool impl_latency_takes_priority,
+ bool should_send_begin_main_frame) {
+ // Set up client with specified estimates (draw duration is set to 1).
+ SchedulerClientWithFixedEstimates* client =
+ new SchedulerClientWithFixedEstimates(
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMilliseconds(
+ begin_main_frame_to_commit_estimate_in_ms),
+ base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
- private:
- base::TimeDelta draw_duration_;
- base::TimeDelta begin_main_frame_to_commit_duration_;
- base::TimeDelta commit_to_activate_duration_;
-};
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
-void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
- int64 commit_to_activate_estimate_in_ms,
- bool impl_latency_takes_priority,
- bool should_send_begin_main_frame) {
- // Set up client with specified estimates (draw duration is set to 1).
- SchedulerClientWithFixedEstimates client(
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMilliseconds(
- begin_main_frame_to_commit_estimate_in_ms),
- base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- scheduler->SetImplLatencyTakesPriority(impl_latency_takes_priority);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ scheduler_->SetImplLatencyTakesPriority(impl_latency_takes_priority);
// Impl thread hits deadline before commit finishes.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
- client.AdvanceFrame();
- EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
-
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- client.AdvanceFrame();
- EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(),
+ scheduler_->SetNeedsCommit();
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
+ EXPECT_TRUE(client->HasAction("ScheduledActionSendBeginMainFrame"));
+
+ client->Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(scheduler_->MainThreadIsInHighLatencyMode(),
should_send_begin_main_frame);
- EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"),
+ EXPECT_EQ(client->HasAction("ScheduledActionSendBeginMainFrame"),
should_send_begin_main_frame);
}
-TEST(SchedulerTest,
- SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
+TEST_F(SchedulerTest,
+ SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
// Set up client so that estimates indicate that we can commit and activate
// before the deadline (~8ms by default).
- MainFrameInHighLatencyMode(1, 1, false, false);
+ EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 1, false, false));
}
-TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
+TEST_F(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
// Set up client so that estimates indicate that the commit cannot finish
// before the deadline (~8ms by default).
- MainFrameInHighLatencyMode(10, 1, false, true);
+ EXPECT_SCOPED(MainFrameInHighLatencyMode(10, 1, false, true));
}
-TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
+TEST_F(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
// Set up client so that estimates indicate that the activate cannot finish
// before the deadline (~8ms by default).
- MainFrameInHighLatencyMode(1, 10, false, true);
+ EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 10, false, true));
}
-TEST(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) {
+TEST_F(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) {
// Set up client so that estimates indicate that we can commit and activate
// before the deadline (~8ms by default), but also enable impl latency takes
// priority mode.
- MainFrameInHighLatencyMode(1, 1, true, true);
+ EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 1, true, true));
}
-TEST(SchedulerTest, PollForCommitCompletion) {
+TEST_F(SchedulerTest, PollForCommitCompletion) {
// Since we are simulating a long commit, set up a client with draw duration
// estimates that prevent skipping main frames to get to low latency mode.
- SchedulerClientWithFixedEstimates client(
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMilliseconds(32),
- base::TimeDelta::FromMilliseconds(32));
- client.set_log_anticipated_draw_time_change(true);
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
-
- scheduler->SetCanDraw(true);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->DidCreateAndInitializeOutputSurface();
-
- scheduler->SetNeedsCommit();
- EXPECT_TRUE(scheduler->CommitPending());
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- scheduler->SetNeedsRedraw();
-
- BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src());
+ SchedulerClientWithFixedEstimates* client =
+ new SchedulerClientWithFixedEstimates(
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMilliseconds(32),
+ base::TimeDelta::FromMilliseconds(32));
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(make_scoped_ptr(client).Pass(), true);
+
+ client->set_log_anticipated_draw_time_change(true);
+
+ BeginFrameArgs frame_args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(frame_args);
-
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- scheduler->DidSwapBuffers();
- scheduler->DidSwapBuffersComplete();
// At this point, we've drawn a frame. Start another commit, but hold off on
// the NotifyReadyToCommit for now.
- EXPECT_FALSE(scheduler->CommitPending());
- scheduler->SetNeedsCommit();
- client.ExternalBeginFrameSource()->TestOnBeginFrame(frame_args);
- EXPECT_TRUE(scheduler->CommitPending());
+ EXPECT_FALSE(scheduler_->CommitPending());
+ scheduler_->SetNeedsCommit();
+ fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
+ EXPECT_TRUE(scheduler_->CommitPending());
// Draw and swap the frame, but don't ack the swap to simulate the Browser
// blocking on the renderer.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- scheduler->DidSwapBuffers();
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ scheduler_->DidSwapBuffers();
// Spin the event loop a few times and make sure we get more
// DidAnticipateDrawTimeChange calls every time.
- int actions_so_far = client.num_actions_();
+ int actions_so_far = client->num_actions_();
// Does three iterations to make sure that the timer is properly repeating.
for (int i = 0; i < 3; ++i) {
EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
- client.task_runner().DelayToNextTaskTime().InMicroseconds())
- << scheduler->AsValue()->ToString();
- client.task_runner().RunPendingTasks();
- EXPECT_GT(client.num_actions_(), actions_so_far);
- EXPECT_STREQ(client.Action(client.num_actions_() - 1),
+ task_runner().DelayToNextTaskTime().InMicroseconds())
+ << scheduler_->AsValue()->ToString();
+ task_runner().RunPendingTasks();
+ EXPECT_GT(client->num_actions_(), actions_so_far);
+ EXPECT_STREQ(client->Action(client->num_actions_() - 1),
"DidAnticipatedDrawTimeChange");
- actions_so_far = client.num_actions_();
+ actions_so_far = client->num_actions_();
}
// Do the same thing after BeginMainFrame starts but still before activation.
- scheduler->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyBeginMainFrameStarted();
for (int i = 0; i < 3; ++i) {
EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
- client.task_runner().DelayToNextTaskTime().InMicroseconds())
- << scheduler->AsValue()->ToString();
- client.task_runner().RunPendingTasks();
- EXPECT_GT(client.num_actions_(), actions_so_far);
- EXPECT_STREQ(client.Action(client.num_actions_() - 1),
+ task_runner().DelayToNextTaskTime().InMicroseconds())
+ << scheduler_->AsValue()->ToString();
+ task_runner().RunPendingTasks();
+ EXPECT_GT(client->num_actions_(), actions_so_far);
+ EXPECT_STREQ(client->Action(client->num_actions_() - 1),
"DidAnticipatedDrawTimeChange");
- actions_so_far = client.num_actions_();
+ actions_so_far = client->num_actions_();
}
}
-TEST(SchedulerTest, BeginRetroFrame) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, BeginRetroFrame) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Queue BeginFrames while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// NotifyReadyToCommit should trigger the commit.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// BeginImplFrame should prepare the draw.
- client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// BeginImplFrame deadline should draw.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// to avoid excessive toggles.
- client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
-
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ client_->Reset();
}
-TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, BeginRetroFrame_SwapThrottled) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetEstimatedParentDrawTime(base::TimeDelta::FromMicroseconds(1));
// To test swap ack throttling, this test disables automatic swap acks.
- scheduler->SetMaxSwapsPending(1);
- client.SetAutomaticSwapAck(false);
+ scheduler_->SetMaxSwapsPending(1);
+ client_->SetAutomaticSwapAck(false);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
- client.Reset();
-
- // Create a BeginFrame with a long deadline to avoid race conditions.
- // This is the first BeginFrame, which will be handled immediately.
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
- args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ client_->Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Queue BeginFrame while we are still handling the previous BeginFrame.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_NO_ACTION(client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
+ SendNextBeginFrame();
+ EXPECT_NO_ACTION(client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// NotifyReadyToCommit should trigger the pending commit and draw.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// Swapping will put us into a swap throttled state.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ // Run posted deadline.
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
// While swap throttled, BeginRetroFrames should trigger BeginImplFrames
// but not a BeginMainFrame or draw.
- scheduler->SetNeedsCommit();
- client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
-
- // Queue BeginFrame while we are still handling the previous BeginFrame.
- args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_NO_ACTION(client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ scheduler_->SetNeedsRedraw();
+ // Run posted BeginRetroFrame.
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(false));
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+
+ // Let time pass sufficiently beyond the regular deadline but not beyond the
+ // late deadline.
+ now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() -
+ base::TimeDelta::FromMicroseconds(1));
+ task_runner().RunUntilTime(now_src()->Now());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
// Take us out of a swap throttled state.
- scheduler->DidSwapBuffersComplete();
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
-
- // BeginImplFrame deadline should draw.
- scheduler->SetNeedsRedraw();
+ scheduler_->DidSwapBuffersComplete();
+ EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+
+ // Verify that the deadline was rescheduled.
+ task_runner().RunUntilTime(now_src()->Now());
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+}
- EXPECT_TRUE(client.task_runner().RunTasksWhile(
- client.ImplFrameDeadlinePending(true)));
+TEST_F(SchedulerTest, RetroFrameDoesNotExpireTooEarly) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+
+ client_->Reset();
+ SendNextBeginFrame();
+ // This BeginFrame is queued up as a retro frame.
+ EXPECT_NO_ACTION(client_);
+ // The previous deadline is still pending.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ // This commit should schedule the (previous) deadline to trigger immediately.
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ // The deadline task should trigger causing a draw.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+
+ // Keep animating.
+ client_->Reset();
+ scheduler_->SetNeedsAnimate();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_NO_ACTION(client_);
+
+ // Let's advance sufficiently past the next frame's deadline.
+ now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() -
+ BeginFrameArgs::DefaultEstimatedParentDrawTime() +
+ base::TimeDelta::FromMicroseconds(1));
+
+ // The retro frame hasn't expired yet.
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(false));
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ // This is an immediate deadline case.
+ client_->Reset();
+ task_runner().RunPendingTasks();
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+}
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
- client.Reset();
+TEST_F(SchedulerTest, RetroFrameDoesNotExpireTooLate) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(client_->needs_begin_frames());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+
+ client_->Reset();
+ SendNextBeginFrame();
+ // This BeginFrame is queued up as a retro frame.
+ EXPECT_NO_ACTION(client_);
+ // The previous deadline is still pending.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ // This commit should schedule the (previous) deadline to trigger immediately.
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ // The deadline task should trigger causing a draw.
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+
+ // Keep animating.
+ client_->Reset();
+ scheduler_->SetNeedsAnimate();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_NO_ACTION(client_);
+
+ // Let's advance sufficiently past the next frame's deadline.
+ now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() +
+ base::TimeDelta::FromMicroseconds(1));
+
+ // The retro frame should've expired.
+ EXPECT_NO_ACTION(client_);
}
-void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled,
- bool throttle_frame_production) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.begin_frame_scheduling_enabled =
- begin_frame_scheduling_enabled;
- scheduler_settings.throttle_frame_production = throttle_frame_production;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+void SchedulerTest::BeginFramesNotFromClient(
+ bool use_external_begin_frame_source,
+ bool throttle_frame_production) {
+ scheduler_settings_.use_external_begin_frame_source =
+ use_external_begin_frame_source;
+ scheduler_settings_.throttle_frame_production = throttle_frame_production;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame
// without calling SetNeedsBeginFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_FALSE(client.needs_begin_frames());
- EXPECT_NO_ACTION(client);
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_NO_ACTION(client_);
+ client_->Reset();
// When the client-driven BeginFrame are disabled, the scheduler posts it's
// own BeginFrame tasks.
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// If we don't swap on the deadline, we wait for the next BeginFrame.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// NotifyReadyToCommit should trigger the commit.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
// BeginImplFrame should prepare the draw.
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// BeginImplFrame deadline should draw.
- client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// to avoid excessive toggles.
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// Make sure SetNeedsBeginFrame isn't called on the client
// when the BeginFrame is no longer needed.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("SendBeginMainFrameNotExpectedSoon", client_);
+ client_->Reset();
}
-TEST(SchedulerTest, SyntheticBeginFrames) {
- bool begin_frame_scheduling_enabled = false;
+TEST_F(SchedulerTest, SyntheticBeginFrames) {
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = true;
- BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest, VSyncThrottlingDisabled) {
- bool begin_frame_scheduling_enabled = true;
+TEST_F(SchedulerTest, VSyncThrottlingDisabled) {
+ bool use_external_begin_frame_source = true;
bool throttle_frame_production = false;
- BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) {
- bool begin_frame_scheduling_enabled = false;
+TEST_F(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) {
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = false;
- BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient(use_external_begin_frame_source,
throttle_frame_production);
}
-void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled,
- bool throttle_frame_production) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.begin_frame_scheduling_enabled =
- begin_frame_scheduling_enabled;
- scheduler_settings.throttle_frame_production = throttle_frame_production;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+void SchedulerTest::BeginFramesNotFromClient_SwapThrottled(
+ bool use_external_begin_frame_source,
+ bool throttle_frame_production) {
+ scheduler_settings_.use_external_begin_frame_source =
+ use_external_begin_frame_source;
+ scheduler_settings_.throttle_frame_production = throttle_frame_production;
+ SetUpScheduler(true);
+
+ scheduler_->SetEstimatedParentDrawTime(base::TimeDelta::FromMicroseconds(1));
// To test swap ack throttling, this test disables automatic swap acks.
- scheduler->SetMaxSwapsPending(1);
- client.SetAutomaticSwapAck(false);
+ scheduler_->SetMaxSwapsPending(1);
+ client_->SetAutomaticSwapAck(false);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_FALSE(client.needs_begin_frames());
- EXPECT_NO_ACTION(client);
- client.Reset();
+ client_->Reset();
+ scheduler_->SetNeedsCommit();
+ EXPECT_NO_ACTION(client_);
+ client_->Reset();
// Trigger the first BeginImplFrame and BeginMainFrame
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// NotifyReadyToCommit should trigger the pending commit and draw.
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
// Swapping will put us into a swap throttled state.
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ // Run posted deadline.
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
// While swap throttled, BeginFrames should trigger BeginImplFrames,
// but not a BeginMainFrame or draw.
- scheduler->SetNeedsCommit();
- client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->SetNeedsCommit();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SCOPED(AdvanceFrame()); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Let time pass sufficiently beyond the regular deadline but not beyond the
+ // late deadline.
+ now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() -
+ base::TimeDelta::FromMicroseconds(1));
+ task_runner().RunUntilTime(now_src()->Now());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
// Take us out of a swap throttled state.
- scheduler->DidSwapBuffersComplete();
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
-
- // BeginImplFrame deadline should draw.
- scheduler->SetNeedsRedraw();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
- client.Reset();
+ scheduler_->DidSwapBuffersComplete();
+ EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Verify that the deadline was rescheduled.
+ // We can't use RunUntilTime(now) here because the next frame is also
+ // scheduled if throttle_frame_production = false.
+ base::TimeTicks before_deadline = now_src()->Now();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ base::TimeTicks after_deadline = now_src()->Now();
+ EXPECT_EQ(after_deadline, before_deadline);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
}
-TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) {
- bool begin_frame_scheduling_enabled = false;
+TEST_F(SchedulerTest, SyntheticBeginFrames_SwapThrottled) {
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = true;
- BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) {
- bool begin_frame_scheduling_enabled = true;
+TEST_F(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) {
+ bool use_external_begin_frame_source = true;
bool throttle_frame_production = false;
- BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest,
- SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) {
- bool begin_frame_scheduling_enabled = false;
+TEST_F(SchedulerTest,
+ SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) {
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = false;
- BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
throttle_frame_production);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- client.Reset();
- scheduler->DidCreateAndInitializeOutputSurface();
- EXPECT_NO_ACTION(client);
-
- scheduler->DidLoseOutputSurface();
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
-}
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(false);
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+ scheduler_->SetCanStart();
+ scheduler_->SetVisible(true);
+ scheduler_->SetCanDraw(true);
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
- // SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+ client_->Reset();
+ scheduler_->DidCreateAndInitializeOutputSurface();
+ EXPECT_NO_ACTION(client_);
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->DidLoseOutputSurface();
- // Do nothing when impl frame is in deadine pending state.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+}
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 1);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ // SetNeedsCommit should begin the frame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
+ EXPECT_NO_ACTION(client_);
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_ACTION("ScheduledActionCommit", client_, 0, 1);
+
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
-void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
+void SchedulerTest::DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
bool impl_side_painting) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.impl_side_painting = impl_side_painting;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ scheduler_settings_.impl_side_painting = impl_side_painting;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- client.Reset();
- scheduler->DidLoseOutputSurface();
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
// Do nothing when impl frame is in deadine pending state.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
+ EXPECT_NO_ACTION(client_);
- client.Reset();
+ client_->Reset();
// Run posted deadline.
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
- // OnBeginImplFrameDeadline didn't schedule any actions because main frame is
- // not yet completed.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ // OnBeginImplFrameDeadline didn't schedule output surface creation because
+ // main frame is not yet completed.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
// BeginImplFrame is not started.
- client.task_runner().RunUntilTime(client.now_src()->Now() +
- base::TimeDelta::FromMilliseconds(10));
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
+ client_->Reset();
+ task_runner().RunUntilTime(now_src()->Now() +
+ base::TimeDelta::FromMilliseconds(10));
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
if (impl_side_painting) {
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 3);
- EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 3);
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 2, 3);
+ EXPECT_ACTION("ScheduledActionCommit", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 2, 3);
} else {
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+ EXPECT_ACTION("ScheduledActionCommit", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 1, 2);
}
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency) {
+TEST_F(SchedulerTest,
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency) {
bool impl_side_painting = false;
DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
}
-TEST(SchedulerTest,
- DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatencyWithImplPaint) {
+TEST_F(SchedulerTest,
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatencyWithImplPaint) {
bool impl_side_painting = true;
DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
}
-void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.impl_side_painting = impl_side_painting;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+void SchedulerTest::DidLoseOutputSurfaceAfterReadyToCommit(
+ bool impl_side_painting) {
+ scheduler_settings_.impl_side_painting = impl_side_painting;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
-
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
-
- client.Reset();
- scheduler->DidLoseOutputSurface();
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
if (impl_side_painting) {
// Sync tree should be forced to activate.
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client, 0, 2);
- EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 2);
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
} else {
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
+ EXPECT_NO_ACTION(client_);
}
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) {
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) {
DidLoseOutputSurfaceAfterReadyToCommit(false);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommitWithImplPainting) {
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommitWithImplPainting) {
DidLoseOutputSurfaceAfterReadyToCommit(true);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- client.Reset();
- scheduler->SetNeedsManageTiles();
- scheduler->SetNeedsRedraw();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
-
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->DidLoseOutputSurface();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionManageTiles", client, 0, 2);
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsPrepareTiles) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsPrepareTiles();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
+ EXPECT_NO_ACTION(client_);
+
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 0, 4);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 1, 4);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 2, 4);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- client.Reset();
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ client_->Reset();
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
// Queue BeginFrames while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
// NotifyReadyToCommit should trigger the commit.
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
-
- client.Reset();
- EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
- scheduler->DidLoseOutputSurface();
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client, 0, 2);
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
- EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ EXPECT_FALSE(scheduler_->IsBeginRetroFrameArgsEmpty());
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_TRUE(scheduler_->IsBeginRetroFrameArgsEmpty());
// Posted BeginRetroFrame is aborted.
- client.Reset();
- client.task_runner().RunPendingTasks();
- EXPECT_NO_ACTION(client);
+ client_->Reset();
+ task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client_);
}
-TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
// Create a BeginFrame with a long deadline to avoid race conditions.
// This is the first BeginFrame, which will be handled immediately.
- client.Reset();
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+ client_->Reset();
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
// Queue BeginFrames while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ fake_external_begin_frame_source()->TestOnBeginFrame(args);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
// NotifyReadyToCommit should trigger the commit.
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_frames());
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(client_->needs_begin_frames());
// BeginImplFrame should prepare the draw.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_frames());
-
- client.Reset();
- EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
- scheduler->DidLoseOutputSurface();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
- EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+
+ client_->Reset();
+ EXPECT_FALSE(scheduler_->IsBeginRetroFrameArgsEmpty());
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_NO_ACTION(client_);
+ EXPECT_TRUE(scheduler_->IsBeginRetroFrameArgsEmpty());
// BeginImplFrame deadline should abort drawing.
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client_->needs_begin_frames());
// No more BeginRetroFrame because BeginRetroFrame queue is cleared.
- client.Reset();
- client.task_runner().RunPendingTasks();
- EXPECT_NO_ACTION(client);
+ client_->Reset();
+ task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client_);
}
-TEST(SchedulerTest,
- StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.begin_frame_scheduling_enabled = false;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
- client.Reset();
- EXPECT_FALSE(scheduler->frame_source().NeedsBeginFrames());
- scheduler->SetNeedsCommit();
- EXPECT_TRUE(scheduler->frame_source().NeedsBeginFrames());
+ EXPECT_FALSE(scheduler_->frame_source().NeedsBeginFrames());
+ scheduler_->SetNeedsCommit();
+ EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted Tick.
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(scheduler->frame_source().NeedsBeginFrames());
+ client_->Reset();
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
// NotifyReadyToCommit should trigger the commit.
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(scheduler->frame_source().NeedsBeginFrames());
-
- client.Reset();
- scheduler->DidLoseOutputSurface();
- EXPECT_NO_ACTION(client);
- EXPECT_FALSE(scheduler->frame_source().NeedsBeginFrames());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- EXPECT_FALSE(scheduler->frame_source().NeedsBeginFrames());
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
+
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
+
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->frame_source().NeedsBeginFrames());
}
-TEST(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.impl_side_painting = true;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+TEST_F(SchedulerTest, DidLoseOutputSurfaceWhenIdle) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ // SetNeedsCommit should begin the frame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+
+ // Idle time between BeginFrames.
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+}
+
+TEST_F(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
+ scheduler_settings_.impl_side_painting = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
// SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->SetVisible(false);
+ task_runner().RunPendingTasks(); // Run posted deadline.
- client.Reset();
- scheduler->SetVisible(false);
// Sync tree should be forced to activate.
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client, 0, 2);
- EXPECT_ACTION("ScheduledActionActivateSyncTree", client, 1, 2);
+ EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
-TEST(SchedulerTest, SchedulerPowerMonitoring) {
- FakeSchedulerClient client;
- SchedulerSettings settings;
- settings.disable_hi_res_timer_tasks_on_battery = true;
- TestScheduler* scheduler = client.CreateScheduler(settings);
-
- base::TimeTicks before_deadline, after_deadline;
+// Tests to ensure frame sources can be successfully changed while drawing.
+TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottled) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ // SetNeedsRedraw should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ scheduler_->SetNeedsRedraw();
+
+ // Switch to an unthrottled frame source.
+ scheduler_->SetThrottleFrameProduction(false);
+ client_->Reset();
+
+ // Unthrottled frame source will immediately begin a new frame.
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
+ // If we don't swap on the deadline, we wait for the next BeginFrame.
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+// Tests to ensure frame sources can be successfully changed while a frame
+// deadline is pending.
+TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottledBeforeDeadline) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ // SetNeedsRedraw should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+
+ // Switch to an unthrottled frame source before the frame deadline is hit.
+ scheduler_->SetThrottleFrameProduction(false);
+ client_->Reset();
+
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline and BeginFrame.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 2);
+ // Unthrottled frame source will immediately begin a new frame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 1, 2);
+ scheduler_->SetNeedsRedraw();
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
+// Tests to ensure that the active frame source can successfully be changed from
+// unthrottled to throttled.
+TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) {
+ scheduler_settings_.throttle_frame_production = false;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_NO_ACTION(client_);
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Switch to a throttled frame source.
+ scheduler_->SetThrottleFrameProduction(true);
+ client_->Reset();
+
+ // SetNeedsRedraw should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsRedraw();
+ task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client_);
+ client_->Reset();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client_->needs_begin_frames());
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
+}
- // On non-battery power
- EXPECT_FALSE(client.PowerMonitor()->IsOnBatteryPower());
+// Tests to ensure that we send a BeginMainFrameNotExpectedSoon when expected.
+TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
- client.AdvanceFrame();
- client.Reset();
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Trigger a frame draw.
+ EXPECT_SCOPED(AdvanceFrame());
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ task_runner().RunPendingTasks();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 5);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 5);
+ EXPECT_ACTION("ScheduledActionCommit", client_, 2, 5);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 3, 5);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 5);
+ client_->Reset();
- before_deadline = client.now_src()->Now();
- EXPECT_TRUE(client.task_runner().RunTasksWhile(
- client.ImplFrameDeadlinePending(true)));
- after_deadline = client.now_src()->Now();
+ // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
+ // and send a SendBeginMainFrameNotExpectedSoon.
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ client_->Reset();
+}
- // We post a non-zero deadline task when not on battery
- EXPECT_LT(before_deadline, after_deadline);
+TEST_F(SchedulerTest, SynchronousCompositorAnimation) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsAnimate();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Continue with animation.
+ scheduler_->SetNeedsAnimate();
+ EXPECT_NO_ACTION(client_);
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Idle on next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- // Switch to battery power
- client.PowerMonitorSource()->GeneratePowerStateEvent(true);
- EXPECT_TRUE(client.PowerMonitor()->IsOnBatteryPower());
+TEST_F(SchedulerTest, SynchronousCompositorOnDrawDuringIdle) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Idle on next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- client.AdvanceFrame();
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
+TEST_F(SchedulerTest, SynchronousCompositorCommit) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_NO_ACTION(client_);
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
+
+ scheduler_->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ // Idle on next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+}
- before_deadline = client.now_src()->Now();
- EXPECT_TRUE(client.task_runner().RunTasksWhile(
- client.ImplFrameDeadlinePending(true)));
- after_deadline = client.now_src()->Now();
+TEST_F(SchedulerTest, SynchronousCompositorDoubleCommitWithoutDraw) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+ SetUpScheduler(true);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Next vsync.
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_NO_ACTION(client_);
+
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
+
+ scheduler_->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
+ client_->Reset();
+
+ // Ask for another commit.
+ scheduler_->SetNeedsCommit();
+
+ AdvanceFrame();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 4);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 4);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 3, 4);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ EXPECT_NO_ACTION(client_);
+
+ // Allow new commit even though previous commit hasn't been drawn.
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ client_->Reset();
+}
- // We post a zero deadline task when on battery
- EXPECT_EQ(before_deadline, after_deadline);
+class SchedulerClientSetNeedsPrepareTilesOnDraw : public FakeSchedulerClient {
+ public:
+ SchedulerClientSetNeedsPrepareTilesOnDraw() : FakeSchedulerClient() {}
- // Switch to non-battery power
- client.PowerMonitorSource()->GeneratePowerStateEvent(false);
- EXPECT_FALSE(client.PowerMonitor()->IsOnBatteryPower());
+ protected:
+ DrawResult ScheduledActionDrawAndSwapIfPossible() override {
+ scheduler_->SetNeedsPrepareTiles();
+ return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
+ }
- client.AdvanceFrame();
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
+ void ScheduledActionPrepareTiles() override {
+ FakeSchedulerClient::ScheduledActionPrepareTiles();
+ scheduler_->DidPrepareTiles();
+ }
+};
- // Same as before
- before_deadline = client.now_src()->Now();
- EXPECT_TRUE(client.task_runner().RunTasksWhile(
- client.ImplFrameDeadlinePending(true)));
- after_deadline = client.now_src()->Now();
+TEST_F(SchedulerTest, SynchronousCompositorPrepareTilesOnDraw) {
+ scheduler_settings_.using_synchronous_renderer_compositor = true;
+ scheduler_settings_.use_external_begin_frame_source = true;
+ scheduler_settings_.impl_side_painting = true;
+
+ scoped_ptr<FakeSchedulerClient> client =
+ make_scoped_ptr(new SchedulerClientSetNeedsPrepareTilesOnDraw);
+ SetUpScheduler(client.Pass(), true);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Next vsync.
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateOutputSurface", client_, 2, 3);
+ client_->Reset();
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ client_->Reset();
+
+ // Android onDraw.
+ scheduler_->SetNeedsRedraw();
+ scheduler_->OnDrawForOutputSurface();
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 1, 2);
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ client_->Reset();
+
+ // Next vsync.
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_FALSE(scheduler_->PrepareTilesPending());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_FALSE(client_->needs_begin_frames());
+ client_->Reset();
}
-TEST(SchedulerTest,
- SimulateWindowsLowResolutionTimerOnBattery_PrioritizeImplLatencyOff) {
- FakeSchedulerClient client;
- SchedulerSettings settings;
- TestScheduler* scheduler = client.CreateScheduler(settings);
-
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- // Set needs commit so that the scheduler tries to wait for the main thread
- scheduler->SetNeedsCommit();
- // Set needs redraw so that the scheduler doesn't wait too long
- scheduler->SetNeedsRedraw();
- client.Reset();
-
- // Switch to battery power
- client.PowerMonitorSource()->GeneratePowerStateEvent(true);
- EXPECT_TRUE(client.PowerMonitor()->IsOnBatteryPower());
-
- client.AdvanceFrame();
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
-
- // Disable auto-advancing of now_src
- client.task_runner().SetAutoAdvanceNowToPendingTasks(false);
-
- // Deadline task is pending
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks();
- // Deadline task is still pending
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- // Advance now by 15 ms - same as windows low res timer
- client.now_src()->AdvanceNowMicroseconds(15000);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks();
- // Deadline task finally completes
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-}
+TEST_F(SchedulerTest, AuthoritativeVSyncInterval) {
+ SetUpScheduler(true);
+
+ base::TimeDelta initial_interval =
+ scheduler_->begin_impl_frame_args().interval;
+ base::TimeDelta authoritative_interval =
+ base::TimeDelta::FromMilliseconds(33);
+
+ scheduler_->SetNeedsCommit();
+ EXPECT_SCOPED(AdvanceFrame());
+
+ EXPECT_EQ(initial_interval, scheduler_->begin_impl_frame_args().interval);
+
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+
+ scheduler_->SetAuthoritativeVSyncInterval(authoritative_interval);
+
+ EXPECT_SCOPED(AdvanceFrame());
-TEST(SchedulerTest,
- SimulateWindowsLowResolutionTimerOnBattery_PrioritizeImplLatencyOn) {
- FakeSchedulerClient client;
- SchedulerSettings settings;
- settings.disable_hi_res_timer_tasks_on_battery = true;
- TestScheduler* scheduler = client.CreateScheduler(settings);
-
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- // Set needs commit so that the scheduler tries to wait for the main thread
- scheduler->SetNeedsCommit();
- // Set needs redraw so that the scheduler doesn't wait too long
- scheduler->SetNeedsRedraw();
- client.Reset();
-
- // Switch to battery power
- client.PowerMonitorSource()->GeneratePowerStateEvent(true);
- EXPECT_TRUE(client.PowerMonitor()->IsOnBatteryPower());
-
- client.AdvanceFrame();
- scheduler->SetNeedsCommit();
- scheduler->SetNeedsRedraw();
- client.Reset();
-
- // Disable auto-advancing of now_src
- client.task_runner().SetAutoAdvanceNowToPendingTasks(false);
-
- // Deadline task is pending
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- client.task_runner().RunPendingTasks();
- // Deadline task runs immediately
- EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ // At the next BeginFrame, authoritative interval is used instead of previous
+ // interval.
+ EXPECT_NE(initial_interval, scheduler_->begin_impl_frame_args().interval);
+ EXPECT_EQ(authoritative_interval,
+ scheduler_->begin_impl_frame_args().interval);
}
} // namespace
diff --git a/chromium/cc/scheduler/video_frame_controller.h b/chromium/cc/scheduler/video_frame_controller.h
new file mode 100644
index 00000000000..0307cd5e402
--- /dev/null
+++ b/chromium/cc/scheduler/video_frame_controller.h
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_SCHEDULER_VIDEO_FRAME_CONTROLLER_H_
+#define CC_SCHEDULER_VIDEO_FRAME_CONTROLLER_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/output/begin_frame_args.h"
+
+namespace cc {
+
+class VideoFrameController;
+
+class CC_EXPORT VideoFrameControllerClient {
+ public:
+ virtual void AddVideoFrameController(VideoFrameController* controller) = 0;
+ virtual void RemoveVideoFrameController(VideoFrameController* controller) = 0;
+
+ protected:
+ virtual ~VideoFrameControllerClient() {}
+};
+
+// TODO(sunnyps): Consider making this a BeginFrameObserver some day.
+class CC_EXPORT VideoFrameController {
+ public:
+ virtual void OnBeginFrame(const BeginFrameArgs& args) = 0;
+
+ // Called upon completion of LayerTreeHostImpl::DidDrawAllLayers(), regardless
+ // of whether the controller issued a SetNeedsRedraw(). May be used to
+ // determine when SetNeedsRedraw() is called but the draw is aborted.
+ virtual void DidDrawFrame() = 0;
+
+ protected:
+ virtual ~VideoFrameController() {}
+};
+
+} // namespace cc
+
+#endif // CC_SCHEDULER_VIDEO_FRAME_CONTROLLER_H_
diff --git a/chromium/cc/surfaces/BUILD.gn b/chromium/cc/surfaces/BUILD.gn
index a45e786e17c..e43d4e5741f 100644
--- a/chromium/cc/surfaces/BUILD.gn
+++ b/chromium/cc/surfaces/BUILD.gn
@@ -2,20 +2,33 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+source_set("surface_id") {
+ sources = [
+ "surface_id.h",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
+
component("surfaces") {
output_name = "cc_surfaces"
sources = [
"display.cc",
"display.h",
"display_client.h",
+ "onscreen_display_client.cc",
+ "onscreen_display_client.h",
"surface.cc",
"surface.h",
"surface_aggregator.cc",
"surface_aggregator.h",
+ "surface_display_output_surface.cc",
+ "surface_display_output_surface.h",
"surface_factory.cc",
"surface_factory.h",
"surface_factory_client.h",
- "surface_id.h",
"surface_id_allocator.cc",
"surface_id_allocator.h",
"surface_manager.cc",
@@ -28,6 +41,7 @@ component("surfaces") {
defines = [ "CC_SURFACES_IMPLEMENTATION=1" ]
deps = [
+ ":surface_id",
"//base",
"//base/third_party/dynamic_annotations",
"//cc",
@@ -42,4 +56,3 @@ component("surfaces") {
configs += [ "//build/config/compiler:optimize_max" ]
}
}
-
diff --git a/chromium/cc/surfaces/display.cc b/chromium/cc/surfaces/display.cc
index 129a11615d3..e2b81728393 100644
--- a/chromium/cc/surfaces/display.cc
+++ b/chromium/cc/surfaces/display.cc
@@ -4,15 +4,16 @@
#include "cc/surfaces/display.h"
-#include "base/debug/trace_event.h"
-#include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
#include "cc/debug/benchmark_instrumentation.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_ack.h"
#include "cc/output/direct_renderer.h"
#include "cc/output/gl_renderer.h"
+#include "cc/output/renderer_settings.h"
#include "cc/output/software_renderer.h"
-#include "cc/resources/texture_mailbox_deleter.h"
+#include "cc/output/texture_mailbox_deleter.h"
#include "cc/surfaces/display_client.h"
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_aggregator.h"
@@ -24,21 +25,30 @@ namespace cc {
Display::Display(DisplayClient* client,
SurfaceManager* manager,
SharedBitmapManager* bitmap_manager,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager)
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ const RendererSettings& settings)
: client_(client),
manager_(manager),
bitmap_manager_(bitmap_manager),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+ settings_(settings),
device_scale_factor_(1.f),
blocking_main_thread_task_runner_(
- BlockingTaskRunner::Create(base::MessageLoopProxy::current())),
+ BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get())),
texture_mailbox_deleter_(
- new TextureMailboxDeleter(base::MessageLoopProxy::current())) {
+ new TextureMailboxDeleter(base::ThreadTaskRunnerHandle::Get())) {
manager_->AddObserver(this);
}
Display::~Display() {
manager_->RemoveObserver(this);
+ if (aggregator_) {
+ for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
+ Surface* surface = manager_->GetSurfaceForId(id_entry.first);
+ if (surface)
+ surface->RunDrawCallbacks(SurfaceDrawStatus::DRAW_SKIPPED);
+ }
+ }
}
bool Display::Initialize(scoped_ptr<OutputSurface> output_surface) {
@@ -46,41 +56,39 @@ bool Display::Initialize(scoped_ptr<OutputSurface> output_surface) {
return output_surface_->BindToClient(this);
}
-void Display::Resize(SurfaceId id,
- const gfx::Size& size,
- float device_scale_factor) {
+void Display::SetSurfaceId(SurfaceId id, float device_scale_factor) {
current_surface_id_ = id;
- current_surface_size_ = size;
device_scale_factor_ = device_scale_factor;
client_->DisplayDamaged();
}
+void Display::Resize(const gfx::Size& size) {
+ if (size == current_surface_size_)
+ return;
+ // Need to ensure all pending swaps have executed before the window is
+ // resized, or D3D11 will scale the swap output.
+ if (renderer_ && settings_.finish_rendering_on_resize)
+ renderer_->Finish();
+ current_surface_size_ = size;
+ client_->DisplayDamaged();
+}
+
void Display::InitializeRenderer() {
if (resource_provider_)
return;
- int highp_threshold_min = 0;
- bool use_rgba_4444_texture_format = false;
- size_t id_allocation_chunk_size = 1;
- scoped_ptr<ResourceProvider> resource_provider =
- ResourceProvider::Create(output_surface_.get(),
- bitmap_manager_,
- gpu_memory_buffer_manager_,
- blocking_main_thread_task_runner_.get(),
- highp_threshold_min,
- use_rgba_4444_texture_format,
- id_allocation_chunk_size);
+ scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create(
+ output_surface_.get(), bitmap_manager_, gpu_memory_buffer_manager_,
+ blocking_main_thread_task_runner_.get(), settings_.highp_threshold_min,
+ settings_.use_rgba_4444_textures,
+ settings_.texture_id_allocation_chunk_size);
if (!resource_provider)
return;
if (output_surface_->context_provider()) {
- scoped_ptr<GLRenderer> renderer =
- GLRenderer::Create(this,
- &settings_,
- output_surface_.get(),
- resource_provider.get(),
- texture_mailbox_deleter_.get(),
- highp_threshold_min);
+ scoped_ptr<GLRenderer> renderer = GLRenderer::Create(
+ this, &settings_, output_surface_.get(), resource_provider.get(),
+ texture_mailbox_deleter_.get(), settings_.highp_threshold_min);
if (!renderer)
return;
renderer_ = renderer.Pass();
@@ -117,27 +125,57 @@ bool Display::Draw() {
TRACE_EVENT0("cc", "Display::Draw");
benchmark_instrumentation::IssueDisplayRenderingStatsEvent();
- DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
- gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_);
- gfx::Rect device_clip_rect = device_viewport_rect;
- bool disable_picture_quad_image_filtering = false;
-
- renderer_->DecideRenderPassAllocationsForFrame(frame_data->render_pass_list);
- renderer_->DrawFrame(&frame_data->render_pass_list,
- device_scale_factor_,
- device_viewport_rect,
- device_clip_rect,
- disable_picture_quad_image_filtering);
- renderer_->SwapBuffers(frame->metadata);
- for (SurfaceAggregator::SurfaceIndexMap::iterator it =
- aggregator_->previous_contained_surfaces().begin();
- it != aggregator_->previous_contained_surfaces().end();
- ++it) {
- Surface* surface = manager_->GetSurfaceForId(it->first);
+ // Run callbacks early to allow pipelining.
+ for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
+ Surface* surface = manager_->GetSurfaceForId(id_entry.first);
if (surface)
- surface->RunDrawCallbacks();
+ surface->RunDrawCallbacks(SurfaceDrawStatus::DRAWN);
+ }
+ DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
+
+ frame->metadata.latency_info.insert(frame->metadata.latency_info.end(),
+ stored_latency_info_.begin(),
+ stored_latency_info_.end());
+ stored_latency_info_.clear();
+ bool have_copy_requests = false;
+ for (const auto* pass : frame_data->render_pass_list) {
+ have_copy_requests |= !pass->copy_requests.empty();
}
+
+ gfx::Size surface_size;
+ bool have_damage = false;
+ if (!frame_data->render_pass_list.empty()) {
+ surface_size = frame_data->render_pass_list.back()->output_rect.size();
+ have_damage =
+ !frame_data->render_pass_list.back()->damage_rect.size().IsEmpty();
+ }
+ bool avoid_swap = surface_size != current_surface_size_;
+ bool should_draw = !frame->metadata.latency_info.empty() ||
+ have_copy_requests || (have_damage && !avoid_swap);
+
+ if (should_draw) {
+ gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_);
+ gfx::Rect device_clip_rect = device_viewport_rect;
+ bool disable_picture_quad_image_filtering = false;
+
+ renderer_->DecideRenderPassAllocationsForFrame(
+ frame_data->render_pass_list);
+ renderer_->DrawFrame(&frame_data->render_pass_list, device_scale_factor_,
+ device_viewport_rect, device_clip_rect,
+ disable_picture_quad_image_filtering);
+ }
+
+ if (should_draw && !avoid_swap) {
+ renderer_->SwapBuffers(frame->metadata);
+ } else {
+ stored_latency_info_.insert(stored_latency_info_.end(),
+ frame->metadata.latency_info.begin(),
+ frame->metadata.latency_info.end());
+ DidSwapBuffers();
+ DidSwapBuffersComplete();
+ }
+
return true;
}
@@ -158,9 +196,53 @@ void Display::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
client_->SetMemoryPolicy(policy);
}
-void Display::OnSurfaceDamaged(SurfaceId surface) {
- if (aggregator_ && aggregator_->previous_contained_surfaces().count(surface))
+void Display::OnDraw() {
+ NOTREACHED();
+}
+
+void Display::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
+ NOTREACHED();
+}
+
+void Display::ReclaimResources(const CompositorFrameAck* ack) {
+ NOTREACHED();
+}
+
+void Display::SetExternalDrawConstraints(
+ const gfx::Transform& transform,
+ const gfx::Rect& viewport,
+ const gfx::Rect& clip,
+ const gfx::Rect& viewport_rect_for_tile_priority,
+ const gfx::Transform& transform_for_tile_priority,
+ bool resourceless_software_draw) {
+ NOTREACHED();
+}
+
+void Display::SetTreeActivationCallback(const base::Closure& callback) {
+ NOTREACHED();
+}
+
+void Display::SetFullRootLayerDamage() {
+ if (aggregator_ && !current_surface_id_.is_null())
+ aggregator_->SetFullDamageForSurface(current_surface_id_);
+}
+
+void Display::OnSurfaceDamaged(SurfaceId surface_id, bool* changed) {
+ if (aggregator_ &&
+ aggregator_->previous_contained_surfaces().count(surface_id)) {
+ Surface* surface = manager_->GetSurfaceForId(surface_id);
+ if (surface) {
+ const CompositorFrame* current_frame = surface->GetEligibleFrame();
+ if (!current_frame || !current_frame->delegated_frame_data ||
+ !current_frame->delegated_frame_data->resource_list.size())
+ aggregator_->ReleaseResources(surface_id);
+ }
+ client_->DisplayDamaged();
+ *changed = true;
+ } else if (surface_id == current_surface_id_) {
client_->DisplayDamaged();
+ *changed = true;
+ }
}
SurfaceId Display::CurrentSurfaceId() {
@@ -168,9 +250,11 @@ SurfaceId Display::CurrentSurfaceId() {
}
int Display::GetMaxFramesPending() {
- if (!output_surface_)
- return OutputSurface::DEFAULT_MAX_FRAMES_PENDING;
- return output_surface_->capabilities().max_frames_pending;
+ int max_frames_pending =
+ output_surface_ ? output_surface_->capabilities().max_frames_pending : 0;
+ if (max_frames_pending <= 0)
+ max_frames_pending = OutputSurface::DEFAULT_MAX_FRAMES_PENDING;
+ return max_frames_pending;
}
} // namespace cc
diff --git a/chromium/cc/surfaces/display.h b/chromium/cc/surfaces/display.h
index 5f80d64371d..22874a02c01 100644
--- a/chromium/cc/surfaces/display.h
+++ b/chromium/cc/surfaces/display.h
@@ -5,6 +5,8 @@
#ifndef CC_SURFACES_DISPLAY_H_
#define CC_SURFACES_DISPLAY_H_
+#include <vector>
+
#include "base/memory/scoped_ptr.h"
#include "cc/output/output_surface_client.h"
#include "cc/output/renderer.h"
@@ -13,6 +15,11 @@
#include "cc/surfaces/surface_id.h"
#include "cc/surfaces/surface_manager.h"
#include "cc/surfaces/surfaces_export.h"
+#include "ui/events/latency_info.h"
+
+namespace gpu {
+class GpuMemoryBufferManager;
+}
namespace gfx {
class Size;
@@ -24,6 +31,7 @@ class BlockingTaskRunner;
class DirectRenderer;
class DisplayClient;
class OutputSurface;
+class RendererSettings;
class ResourceProvider;
class SharedBitmapManager;
class Surface;
@@ -42,31 +50,28 @@ class CC_SURFACES_EXPORT Display : public OutputSurfaceClient,
Display(DisplayClient* client,
SurfaceManager* manager,
SharedBitmapManager* bitmap_manager,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager);
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ const RendererSettings& settings);
~Display() override;
bool Initialize(scoped_ptr<OutputSurface> output_surface);
// device_scale_factor is used to communicate to the external window system
// what scale this was rendered at.
- void Resize(SurfaceId id,
- const gfx::Size& new_size,
- float device_scale_factor);
+ void SetSurfaceId(SurfaceId id, float device_scale_factor);
+ void Resize(const gfx::Size& new_size);
bool Draw();
SurfaceId CurrentSurfaceId();
int GetMaxFramesPending();
// OutputSurfaceClient implementation.
- void DeferredInitialize() override {}
- void ReleaseGL() override {}
void CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) override;
- void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override {}
- void BeginFrame(const BeginFrameArgs& args) override {}
+ void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override;
void DidSwapBuffers() override;
void DidSwapBuffersComplete() override;
- void ReclaimResources(const CompositorFrameAck* ack) override {}
+ void ReclaimResources(const CompositorFrameAck* ack) override;
void DidLoseOutputSurface() override;
void SetExternalDrawConstraints(
const gfx::Transform& transform,
@@ -74,15 +79,16 @@ class CC_SURFACES_EXPORT Display : public OutputSurfaceClient,
const gfx::Rect& clip,
const gfx::Rect& viewport_rect_for_tile_priority,
const gfx::Transform& transform_for_tile_priority,
- bool resourceless_software_draw) override {}
+ bool resourceless_software_draw) override;
void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
- void SetTreeActivationCallback(const base::Closure& callback) override {}
+ void SetTreeActivationCallback(const base::Closure& callback) override;
+ void OnDraw() override;
// RendererClient implementation.
- void SetFullRootLayerDamage() override {}
+ void SetFullRootLayerDamage() override;
// SurfaceDamageObserver implementation.
- void OnSurfaceDamaged(SurfaceId surface) override;
+ void OnSurfaceDamaged(SurfaceId surface, bool* changed) override;
private:
void InitializeRenderer();
@@ -91,16 +97,17 @@ class CC_SURFACES_EXPORT Display : public OutputSurfaceClient,
SurfaceManager* manager_;
SharedBitmapManager* bitmap_manager_;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ RendererSettings settings_;
SurfaceId current_surface_id_;
gfx::Size current_surface_size_;
float device_scale_factor_;
- LayerTreeSettings settings_;
scoped_ptr<OutputSurface> output_surface_;
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<SurfaceAggregator> aggregator_;
scoped_ptr<DirectRenderer> renderer_;
scoped_ptr<BlockingTaskRunner> blocking_main_thread_task_runner_;
scoped_ptr<TextureMailboxDeleter> texture_mailbox_deleter_;
+ std::vector<ui::LatencyInfo> stored_latency_info_;
DISALLOW_COPY_AND_ASSIGN(Display);
};
diff --git a/chromium/cc/surfaces/display_client.h b/chromium/cc/surfaces/display_client.h
index b0f8f794614..71ee43439d0 100644
--- a/chromium/cc/surfaces/display_client.h
+++ b/chromium/cc/surfaces/display_client.h
@@ -25,6 +25,7 @@ class DisplayClient {
protected:
virtual ~DisplayClient() {}
};
-}
+
+} // namespace cc
#endif // CC_SURFACES_DISPLAY_CLIENT_H_
diff --git a/chromium/cc/surfaces/display_unittest.cc b/chromium/cc/surfaces/display_unittest.cc
new file mode 100644
index 00000000000..7b012440907
--- /dev/null
+++ b/chromium/cc/surfaces/display_unittest.cc
@@ -0,0 +1,239 @@
+// 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.
+
+#include "cc/output/compositor_frame.h"
+#include "cc/output/copy_output_result.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/render_pass.h"
+#include "cc/resources/shared_bitmap_manager.h"
+#include "cc/surfaces/display.h"
+#include "cc/surfaces/display_client.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "cc/surfaces/surface_manager.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
+ public:
+ void ReturnResources(const ReturnedResourceArray& resources) override {}
+};
+
+class DisplayTest : public testing::Test {
+ public:
+ DisplayTest() : factory_(&manager_, &empty_client_) {}
+
+ void SetUp() override {
+ output_surface_ = FakeOutputSurface::CreateSoftware(
+ make_scoped_ptr(new SoftwareOutputDevice));
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager);
+ output_surface_ptr_ = output_surface_.get();
+ }
+
+ protected:
+ void SubmitFrame(RenderPassList* pass_list, SurfaceId surface_id) {
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+ pass_list->swap(frame_data->render_pass_list);
+
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = frame_data.Pass();
+
+ factory_.SubmitFrame(surface_id, frame.Pass(),
+ SurfaceFactory::DrawCallback());
+ }
+
+ SurfaceManager manager_;
+ EmptySurfaceFactoryClient empty_client_;
+ SurfaceFactory factory_;
+ scoped_ptr<FakeOutputSurface> output_surface_;
+ FakeOutputSurface* output_surface_ptr_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+};
+
+class TestDisplayClient : public DisplayClient {
+ public:
+ TestDisplayClient() : damaged(false), swapped(false) {}
+ ~TestDisplayClient() override {}
+
+ void DisplayDamaged() override { damaged = true; }
+ void DidSwapBuffers() override { swapped = true; }
+ void DidSwapBuffersComplete() override {}
+ void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override {}
+ void OutputSurfaceLost() override {}
+ void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override {}
+
+ bool damaged;
+ bool swapped;
+};
+
+void CopyCallback(bool* called, scoped_ptr<CopyOutputResult> result) {
+ *called = true;
+}
+
+// Check that frame is damaged and swapped only under correct conditions.
+TEST_F(DisplayTest, DisplayDamaged) {
+ TestDisplayClient client;
+ RendererSettings settings;
+ settings.partial_swap_enabled = true;
+ Display display(&client, &manager_, shared_bitmap_manager_.get(), nullptr,
+ settings);
+
+ display.Initialize(output_surface_.Pass());
+
+ SurfaceId surface_id(7u);
+ EXPECT_FALSE(client.damaged);
+ display.SetSurfaceId(surface_id, 1.f);
+ EXPECT_TRUE(client.damaged);
+
+ client.damaged = false;
+ display.Resize(gfx::Size(100, 100));
+ EXPECT_TRUE(client.damaged);
+
+ factory_.Create(surface_id);
+
+ // First draw from surface should have full damage.
+ RenderPassList pass_list;
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 1, 1);
+ pass->id = RenderPassId(1, 1);
+ pass_list.push_back(pass.Pass());
+
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ EXPECT_FALSE(client.swapped);
+ EXPECT_EQ(0u, output_surface_ptr_->num_sent_frames());
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(1u, output_surface_ptr_->num_sent_frames());
+ SoftwareFrameData* software_data =
+ output_surface_ptr_->last_sent_frame().software_frame_data.get();
+ ASSERT_NE(nullptr, software_data);
+ EXPECT_EQ(gfx::Size(100, 100).ToString(), software_data->size.ToString());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
+ software_data->damage_rect.ToString());
+
+ {
+ // Only damaged portion should be swapped.
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 1, 1);
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(2u, output_surface_ptr_->num_sent_frames());
+ software_data =
+ output_surface_ptr_->last_sent_frame().software_frame_data.get();
+ ASSERT_NE(nullptr, software_data);
+ EXPECT_EQ(gfx::Size(100, 100).ToString(), software_data->size.ToString());
+ EXPECT_EQ(gfx::Rect(10, 10, 1, 1).ToString(),
+ software_data->damage_rect.ToString());
+ }
+
+ {
+ // Pass has no damage so shouldn't be swapped.
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(2u, output_surface_ptr_->num_sent_frames());
+ }
+
+ {
+ // Pass is wrong size so shouldn't be swapped.
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 99, 99);
+ pass->damage_rect = gfx::Rect(10, 10, 10, 10);
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(2u, output_surface_ptr_->num_sent_frames());
+ }
+
+ {
+ // Pass has copy output request so should be swapped.
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ bool copy_called = false;
+ pass->copy_requests.push_back(CopyOutputRequest::CreateRequest(
+ base::Bind(&CopyCallback, &copy_called)));
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(3u, output_surface_ptr_->num_sent_frames());
+ EXPECT_TRUE(copy_called);
+ }
+
+ // Pass has latency info so should be swapped.
+ {
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+ pass_list.swap(frame_data->render_pass_list);
+
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = frame_data.Pass();
+ frame->metadata.latency_info.push_back(ui::LatencyInfo());
+
+ factory_.SubmitFrame(surface_id, frame.Pass(),
+ SurfaceFactory::DrawCallback());
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(4u, output_surface_ptr_->num_sent_frames());
+ }
+
+ factory_.Destroy(surface_id);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/surfaces/onscreen_display_client.cc b/chromium/cc/surfaces/onscreen_display_client.cc
new file mode 100644
index 00000000000..c9f1f7f4a3e
--- /dev/null
+++ b/chromium/cc/surfaces/onscreen_display_client.cc
@@ -0,0 +1,96 @@
+// Copyright 2014 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/surfaces/onscreen_display_client.h"
+
+#include "base/trace_event/trace_event.h"
+#include "cc/output/output_surface.h"
+#include "cc/surfaces/surface_display_output_surface.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_manager.h"
+
+namespace cc {
+
+OnscreenDisplayClient::OnscreenDisplayClient(
+ scoped_ptr<OutputSurface> output_surface,
+ SurfaceManager* manager,
+ SharedBitmapManager* bitmap_manager,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ const RendererSettings& settings,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : output_surface_(output_surface.Pass()),
+ display_(new Display(this,
+ manager,
+ bitmap_manager,
+ gpu_memory_buffer_manager,
+ settings)),
+ task_runner_(task_runner),
+ scheduled_draw_(false),
+ output_surface_lost_(false),
+ deferred_draw_(false),
+ pending_frames_(0),
+ weak_ptr_factory_(this) {
+}
+
+OnscreenDisplayClient::~OnscreenDisplayClient() {
+}
+
+bool OnscreenDisplayClient::Initialize() {
+ return display_->Initialize(output_surface_.Pass());
+}
+
+void OnscreenDisplayClient::CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ surface_display_output_surface_->ReceivedVSyncParameters(timebase, interval);
+}
+
+void OnscreenDisplayClient::DisplayDamaged() {
+ if (scheduled_draw_ || deferred_draw_)
+ return;
+ TRACE_EVENT0("content", "OnscreenDisplayClient::DisplayDamaged");
+ if (pending_frames_ >= display_->GetMaxFramesPending()) {
+ deferred_draw_ = true;
+ } else {
+ ScheduleDraw();
+ }
+}
+
+void OnscreenDisplayClient::ScheduleDraw() {
+ DCHECK(!deferred_draw_);
+ DCHECK(!scheduled_draw_);
+ scheduled_draw_ = true;
+ task_runner_->PostTask(FROM_HERE, base::Bind(&OnscreenDisplayClient::Draw,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void OnscreenDisplayClient::OutputSurfaceLost() {
+ output_surface_lost_ = true;
+ surface_display_output_surface_->DidLoseOutputSurface();
+}
+
+void OnscreenDisplayClient::Draw() {
+ TRACE_EVENT0("content", "OnscreenDisplayClient::Draw");
+ if (output_surface_lost_)
+ return;
+ scheduled_draw_ = false;
+ display_->Draw();
+}
+
+void OnscreenDisplayClient::DidSwapBuffers() {
+ pending_frames_++;
+}
+
+void OnscreenDisplayClient::DidSwapBuffersComplete() {
+ pending_frames_--;
+ if ((pending_frames_ < display_->GetMaxFramesPending()) && deferred_draw_) {
+ deferred_draw_ = false;
+ ScheduleDraw();
+ }
+}
+
+void OnscreenDisplayClient::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
+ surface_display_output_surface_->SetMemoryPolicy(policy);
+}
+
+} // namespace cc
diff --git a/chromium/cc/surfaces/onscreen_display_client.h b/chromium/cc/surfaces/onscreen_display_client.h
new file mode 100644
index 00000000000..c699d99e197
--- /dev/null
+++ b/chromium/cc/surfaces/onscreen_display_client.h
@@ -0,0 +1,76 @@
+// Copyright 2014 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_SURFACES_ONSCREEN_DISPLAY_CLIENT_H_
+#define CC_SURFACES_ONSCREEN_DISPLAY_CLIENT_H_
+
+#include "cc/surfaces/display_client.h"
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "cc/surfaces/display.h"
+#include "cc/surfaces/surfaces_export.h"
+
+namespace cc {
+class ContextProvider;
+class SurfaceManager;
+class SurfaceDisplayOutputSurface;
+
+// This class provides a DisplayClient implementation for drawing directly to an
+// onscreen context.
+class CC_SURFACES_EXPORT OnscreenDisplayClient
+ : NON_EXPORTED_BASE(DisplayClient) {
+ public:
+ OnscreenDisplayClient(
+ scoped_ptr<OutputSurface> output_surface,
+ SurfaceManager* manager,
+ SharedBitmapManager* bitmap_manager,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ const RendererSettings& settings,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+ ~OnscreenDisplayClient() override;
+
+ bool Initialize();
+ Display* display() { return display_.get(); }
+ void set_surface_output_surface(SurfaceDisplayOutputSurface* surface) {
+ surface_display_output_surface_ = surface;
+ }
+
+ // DisplayClient implementation.
+ void DisplayDamaged() override;
+ void DidSwapBuffers() override;
+ void DidSwapBuffersComplete() override;
+ void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override;
+ void OutputSurfaceLost() override;
+ void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
+
+ bool output_surface_lost() { return output_surface_lost_; }
+
+ private:
+ void ScheduleDraw();
+ void Draw();
+
+ protected:
+ scoped_ptr<OutputSurface> output_surface_;
+ scoped_ptr<Display> display_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ SurfaceDisplayOutputSurface* surface_display_output_surface_;
+ bool scheduled_draw_;
+ bool output_surface_lost_;
+ // True if a draw should be scheduled, but it's hit the limit on max frames
+ // pending.
+ bool deferred_draw_;
+ int pending_frames_;
+
+ base::WeakPtrFactory<OnscreenDisplayClient> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(OnscreenDisplayClient);
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_ONSCREEN_DISPLAY_CLIENT_H_
diff --git a/chromium/cc/surfaces/surface.cc b/chromium/cc/surfaces/surface.cc
index 600455f1261..97575813f48 100644
--- a/chromium/cc/surfaces/surface.cc
+++ b/chromium/cc/surfaces/surface.cc
@@ -18,9 +18,8 @@ namespace cc {
// completely damaged the first time they're drawn from.
static const int kFrameIndexStart = 2;
-Surface::Surface(SurfaceId id, const gfx::Size& size, SurfaceFactory* factory)
+Surface::Surface(SurfaceId id, SurfaceFactory* factory)
: surface_id_(id),
- size_(size),
factory_(factory->AsWeakPtr()),
frame_index_(kFrameIndexStart) {
}
@@ -34,18 +33,32 @@ Surface::~Surface() {
&current_resources);
factory_->UnrefResources(current_resources);
}
+ if (!draw_callback_.is_null())
+ draw_callback_.Run(SurfaceDrawStatus::DRAW_SKIPPED);
}
void Surface::QueueFrame(scoped_ptr<CompositorFrame> frame,
- const base::Closure& callback) {
+ const DrawCallback& callback) {
DCHECK(factory_);
ClearCopyRequests();
- TakeLatencyInfo(&frame->metadata.latency_info);
+
+ if (frame) {
+ TakeLatencyInfo(&frame->metadata.latency_info);
+ }
+
scoped_ptr<CompositorFrame> previous_frame = current_frame_.Pass();
current_frame_ = frame.Pass();
- factory_->ReceiveFromChild(
- current_frame_->delegated_frame_data->resource_list);
- ++frame_index_;
+
+ if (current_frame_) {
+ factory_->ReceiveFromChild(
+ current_frame_->delegated_frame_data->resource_list);
+ }
+
+ // Empty frames shouldn't be drawn and shouldn't contribute damage, so don't
+ // increment frame index for them.
+ if (current_frame_ &&
+ !current_frame_->delegated_frame_data->render_pass_list.empty())
+ ++frame_index_;
if (previous_frame) {
ReturnedResourceArray previous_resources;
@@ -55,11 +68,14 @@ void Surface::QueueFrame(scoped_ptr<CompositorFrame> frame,
factory_->UnrefResources(previous_resources);
}
if (!draw_callback_.is_null())
- draw_callback_.Run();
+ draw_callback_.Run(SurfaceDrawStatus::DRAW_SKIPPED);
draw_callback_ = callback;
- factory_->manager()->DidSatisfySequences(
- SurfaceIdAllocator::NamespaceForId(surface_id_),
- &current_frame_->metadata.satisfies_sequences);
+
+ if (current_frame_) {
+ factory_->manager()->DidSatisfySequences(
+ SurfaceIdAllocator::NamespaceForId(surface_id_),
+ &current_frame_->metadata.satisfies_sequences);
+ }
}
void Surface::RequestCopyOfOutput(scoped_ptr<CopyOutputRequest> copy_request) {
@@ -105,11 +121,11 @@ void Surface::TakeLatencyInfo(std::vector<ui::LatencyInfo>* latency_info) {
current_frame_->metadata.latency_info.clear();
}
-void Surface::RunDrawCallbacks() {
+void Surface::RunDrawCallbacks(SurfaceDrawStatus drawn) {
if (!draw_callback_.is_null()) {
- base::Closure callback = draw_callback_;
- draw_callback_ = base::Closure();
- callback.Run();
+ DrawCallback callback = draw_callback_;
+ draw_callback_ = DrawCallback();
+ callback.Run(drawn);
}
}
diff --git a/chromium/cc/surfaces/surface.h b/chromium/cc/surfaces/surface.h
index 7b3fbc125b2..8e6d7a46cbf 100644
--- a/chromium/cc/surfaces/surface.h
+++ b/chromium/cc/surfaces/surface.h
@@ -16,6 +16,7 @@
#include "cc/base/scoped_ptr_vector.h"
#include "cc/output/copy_output_request.h"
#include "cc/quads/render_pass_id.h"
+#include "cc/surfaces/surface_factory.h"
#include "cc/surfaces/surface_id.h"
#include "cc/surfaces/surface_sequence.h"
#include "cc/surfaces/surfaces_export.h"
@@ -34,14 +35,15 @@ class SurfaceResourceHolder;
class CC_SURFACES_EXPORT Surface {
public:
- Surface(SurfaceId id, const gfx::Size& size, SurfaceFactory* factory);
+ using DrawCallback = SurfaceFactory::DrawCallback;
+
+ Surface(SurfaceId id, SurfaceFactory* factory);
~Surface();
- const gfx::Size& size() const { return size_; }
SurfaceId surface_id() const { return surface_id_; }
void QueueFrame(scoped_ptr<CompositorFrame> frame,
- const base::Closure& draw_callback);
+ const DrawCallback& draw_callback);
void RequestCopyOfOutput(scoped_ptr<CopyOutputRequest> copy_request);
// Adds each CopyOutputRequest in the current frame to copy_requests. The
// caller takes ownership of them.
@@ -54,7 +56,7 @@ class CC_SURFACES_EXPORT Surface {
int frame_index() const { return frame_index_; }
void TakeLatencyInfo(std::vector<ui::LatencyInfo>* latency_info);
- void RunDrawCallbacks();
+ void RunDrawCallbacks(SurfaceDrawStatus drawn);
base::WeakPtr<SurfaceFactory> factory() { return factory_; }
@@ -74,14 +76,13 @@ class CC_SURFACES_EXPORT Surface {
void ClearCopyRequests();
SurfaceId surface_id_;
- gfx::Size size_;
base::WeakPtr<SurfaceFactory> factory_;
// TODO(jamesr): Support multiple frames in flight.
scoped_ptr<CompositorFrame> current_frame_;
int frame_index_;
std::vector<SurfaceSequence> destruction_dependencies_;
- base::Closure draw_callback_;
+ DrawCallback draw_callback_;
DISALLOW_COPY_AND_ASSIGN(Surface);
};
diff --git a/chromium/cc/surfaces/surface_aggregator.cc b/chromium/cc/surfaces/surface_aggregator.cc
index 44afaffd669..941e2d89fab 100644
--- a/chromium/cc/surfaces/surface_aggregator.cc
+++ b/chromium/cc/surfaces/surface_aggregator.cc
@@ -8,8 +8,8 @@
#include "base/bind.h"
#include "base/containers/hash_tables.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/delegated_frame_data.h"
@@ -48,6 +48,31 @@ SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager,
SurfaceAggregator::~SurfaceAggregator() {}
+// Create a clip rect for an aggregated quad from the original clip rect and
+// the clip rect from the surface it's on.
+SurfaceAggregator::ClipData SurfaceAggregator::CalculateClipRect(
+ const ClipData& surface_clip,
+ const ClipData& quad_clip,
+ const gfx::Transform& target_transform) {
+ ClipData out_clip;
+ if (surface_clip.is_clipped)
+ out_clip = surface_clip;
+
+ if (quad_clip.is_clipped) {
+ // TODO(jamesr): This only works if target_transform maps integer
+ // rects to integer rects.
+ gfx::Rect final_clip =
+ MathUtil::MapEnclosingClippedRect(target_transform, quad_clip.rect);
+ if (out_clip.is_clipped)
+ out_clip.rect.Intersect(final_clip);
+ else
+ out_clip.rect = final_clip;
+ out_clip.is_clipped = true;
+ }
+
+ return out_clip;
+}
+
class SurfaceAggregator::RenderPassIdAllocator {
public:
explicit RenderPassIdAllocator(int* next_index) : next_index_(next_index) {}
@@ -95,6 +120,10 @@ int SurfaceAggregator::ChildIdForSurface(Surface* surface) {
if (it == surface_id_to_resource_child_id_.end()) {
int child_id =
provider_->CreateChild(base::Bind(&UnrefHelper, surface->factory()));
+ if (surface->factory()) {
+ provider_->SetChildNeedsSyncPoints(
+ child_id, surface->factory()->needs_sync_points());
+ }
surface_id_to_resource_child_id_[surface->surface_id()] = child_id;
return child_id;
} else {
@@ -103,45 +132,62 @@ int SurfaceAggregator::ChildIdForSurface(Surface* surface) {
}
static ResourceProvider::ResourceId ResourceRemapHelper(
- bool* invalid_frame,
const ResourceProvider::ResourceIdMap& child_to_parent_map,
- ResourceProvider::ResourceIdArray* resources_in_frame,
ResourceProvider::ResourceId id) {
ResourceProvider::ResourceIdMap::const_iterator it =
child_to_parent_map.find(id);
- if (it == child_to_parent_map.end()) {
- *invalid_frame = true;
- return 0;
- }
+ DCHECK(it != child_to_parent_map.end());
DCHECK_EQ(it->first, id);
ResourceProvider::ResourceId remapped_id = it->second;
- resources_in_frame->push_back(id);
return remapped_id;
}
-bool SurfaceAggregator::TakeResources(Surface* surface,
- const DelegatedFrameData* frame_data,
- RenderPassList* render_pass_list) {
- RenderPass::CopyAll(frame_data->render_pass_list, render_pass_list);
+static ResourceProvider::ResourceId ValidateResourceHelper(
+ bool* invalid_frame,
+ const ResourceProvider::ResourceIdMap& child_to_parent_map,
+ ResourceProvider::ResourceIdSet* resources_in_frame,
+ ResourceProvider::ResourceId id) {
+ ResourceProvider::ResourceIdMap::const_iterator it =
+ child_to_parent_map.find(id);
+ if (it == child_to_parent_map.end()) {
+ *invalid_frame = true;
+ return id;
+ }
+ resources_in_frame->insert(id);
+ return id;
+}
+
+bool SurfaceAggregator::ValidateResources(
+ Surface* surface,
+ const DelegatedFrameData* frame_data) {
if (!provider_) // TODO(jamesr): hack for unit tests that don't set up rp
return false;
int child_id = ChildIdForSurface(surface);
- provider_->ReceiveFromChild(child_id, frame_data->resource_list);
if (surface->factory())
surface->factory()->RefResources(frame_data->resource_list);
+ provider_->ReceiveFromChild(child_id, frame_data->resource_list);
- typedef ResourceProvider::ResourceIdArray IdArray;
- IdArray referenced_resources;
+ ResourceProvider::ResourceIdSet referenced_resources;
+ size_t reserve_size = frame_data->resource_list.size();
+#if defined(COMPILER_MSVC)
+ referenced_resources.reserve(reserve_size);
+#elif defined(COMPILER_GCC)
+ // Pre-standard hash-tables only implement resize, which behaves similarly
+ // to reserve for these keys. Resizing to 0 may also be broken (particularly
+ // on stlport).
+ // TODO(jbauman): Replace with reserve when C++11 is supported everywhere.
+ if (reserve_size)
+ referenced_resources.resize(reserve_size);
+#endif
bool invalid_frame = false;
DrawQuad::ResourceIteratorCallback remap =
- base::Bind(&ResourceRemapHelper,
- &invalid_frame,
- provider_->GetChildToParentMap(child_id),
+ base::Bind(&ValidateResourceHelper, &invalid_frame,
+ base::ConstRef(provider_->GetChildToParentMap(child_id)),
&referenced_resources);
- for (const auto& render_pass : *render_pass_list) {
+ for (const auto& render_pass : frame_data->render_pass_list) {
for (const auto& quad : render_pass->quad_list)
quad->IterateResources(remap);
}
@@ -153,17 +199,21 @@ bool SurfaceAggregator::TakeResources(Surface* surface,
}
gfx::Rect SurfaceAggregator::DamageRectForSurface(const Surface* surface,
- const RenderPass& source) {
+ const RenderPass& source,
+ const gfx::Rect& full_rect) {
int previous_index = previous_contained_surfaces_[surface->surface_id()];
if (previous_index == surface->frame_index())
return gfx::Rect();
else if (previous_index == surface->frame_index() - 1)
return source.damage_rect;
- return gfx::Rect(surface->size());
+ return full_rect;
}
-void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
- RenderPass* dest_pass) {
+void SurfaceAggregator::HandleSurfaceQuad(
+ const SurfaceDrawQuad* surface_quad,
+ const gfx::Transform& target_transform,
+ const ClipData& clip_rect,
+ RenderPass* dest_pass) {
SurfaceId surface_id = surface_quad->surface_id;
// If this surface's id is already in our referenced set then it creates
// a cycle in the graph and should be dropped.
@@ -185,8 +235,8 @@ void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
std::multimap<RenderPassId, CopyOutputRequest*> copy_requests;
surface->TakeCopyOutputRequests(&copy_requests);
- RenderPassList render_pass_list;
- bool invalid_frame = TakeResources(surface, frame_data, &render_pass_list);
+ const RenderPassList& render_pass_list = frame_data->render_pass_list;
+ bool invalid_frame = ValidateResources(surface, frame_data);
if (invalid_frame) {
for (auto& request : copy_requests) {
request.second->SendEmptyResult();
@@ -196,9 +246,18 @@ void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
}
SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first;
+ DrawQuad::ResourceIteratorCallback remap;
+ if (provider_) {
+ int child_id = ChildIdForSurface(surface);
+ remap =
+ base::Bind(&ResourceRemapHelper,
+ base::ConstRef(provider_->GetChildToParentMap(child_id)));
+ }
- bool merge_pass = copy_requests.empty();
+ bool merge_pass = surface_quad->opacity() == 1.f && copy_requests.empty();
+ gfx::Rect surface_damage = DamageRectForSurface(
+ surface, *render_pass_list.back(), surface_quad->visible_rect);
const RenderPassList& referenced_passes = render_pass_list;
size_t passes_to_copy =
merge_pass ? referenced_passes.size() - 1 : referenced_passes.size();
@@ -211,9 +270,7 @@ void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
RenderPassId remapped_pass_id = RemapPassId(source.id, surface_id);
- copy_pass->SetAll(remapped_pass_id,
- source.output_rect,
- source.damage_rect,
+ copy_pass->SetAll(remapped_pass_id, source.output_rect, gfx::Rect(),
source.transform_to_root_target,
source.has_transparent_background);
@@ -222,16 +279,17 @@ void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
// Contributing passes aggregated in to the pass list need to take the
// transform of the surface quad into account to update their transform to
// the root surface.
- // TODO(jamesr): Make sure this is sufficient for surfaces nested several
- // levels deep and add tests.
copy_pass->transform_to_root_target.ConcatTransform(
surface_quad->quadTransform());
+ copy_pass->transform_to_root_target.ConcatTransform(target_transform);
+ copy_pass->transform_to_root_target.ConcatTransform(
+ dest_pass->transform_to_root_target);
+
+ CopyQuadsToPass(source.quad_list, source.shared_quad_state_list, remap,
+ gfx::Transform(), ClipData(), copy_pass.get(), surface_id);
- CopyQuadsToPass(source.quad_list,
- source.shared_quad_state_list,
- gfx::Transform(),
- copy_pass.get(),
- surface_id);
+ if (j == referenced_passes.size() - 1)
+ surface_damage = gfx::UnionRects(surface_damage, copy_pass->damage_rect);
dest_pass_list_->push_back(copy_pass.Pass());
}
@@ -241,18 +299,30 @@ void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
// TODO(jamesr): Clean up last pass special casing.
const QuadList& quads = last_pass.quad_list;
- // TODO(jamesr): Make sure clipping is enforced.
- CopyQuadsToPass(quads,
- last_pass.shared_quad_state_list,
- surface_quad->quadTransform(),
- dest_pass,
- surface_id);
+ gfx::Transform surface_transform = surface_quad->quadTransform();
+ surface_transform.ConcatTransform(target_transform);
+
+ // Intersect the transformed visible rect and the clip rect to create a
+ // smaller cliprect for the quad.
+ ClipData surface_quad_clip_rect(
+ true, MathUtil::MapEnclosingClippedRect(surface_quad->quadTransform(),
+ surface_quad->visible_rect));
+ if (surface_quad->isClipped())
+ surface_quad_clip_rect.rect.Intersect(surface_quad->clipRect());
+
+ ClipData quads_clip =
+ CalculateClipRect(clip_rect, surface_quad_clip_rect, target_transform);
+
+ CopyQuadsToPass(quads, last_pass.shared_quad_state_list, remap,
+ surface_transform, quads_clip, dest_pass, surface_id);
} else {
RenderPassId remapped_pass_id = RemapPassId(last_pass.id, surface_id);
+ CopySharedQuadState(surface_quad->shared_quad_state, target_transform,
+ clip_rect, dest_pass);
+
SharedQuadState* shared_quad_state =
- dest_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->CopyFrom(surface_quad->shared_quad_state);
+ dest_pass->shared_quad_state_list.back();
RenderPassDrawQuad* quad =
dest_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
quad->SetNew(shared_quad_state,
@@ -269,37 +339,41 @@ void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
dest_pass->damage_rect =
gfx::UnionRects(dest_pass->damage_rect,
MathUtil::MapEnclosingClippedRect(
- surface_quad->quadTransform(),
- DamageRectForSurface(surface, last_pass)));
+ surface_quad->quadTransform(), surface_damage));
referenced_surfaces_.erase(it);
}
void SurfaceAggregator::CopySharedQuadState(
const SharedQuadState* source_sqs,
- const gfx::Transform& content_to_target_transform,
+ const gfx::Transform& target_transform,
+ const ClipData& clip_rect,
RenderPass* dest_render_pass) {
SharedQuadState* copy_shared_quad_state =
dest_render_pass->CreateAndAppendSharedQuadState();
copy_shared_quad_state->CopyFrom(source_sqs);
- // content_to_target_transform contains any transformation that may exist
+ // target_transform contains any transformation that may exist
// between the context that these quads are being copied from (i.e. the
// surface's draw transform when aggregated from within a surface) to the
// target space of the pass. This will be identity except when copying the
// root draw pass from a surface into a pass when the surface draw quad's
// transform is not identity.
copy_shared_quad_state->content_to_target_transform.ConcatTransform(
- content_to_target_transform);
- if (copy_shared_quad_state->is_clipped) {
- copy_shared_quad_state->clip_rect = MathUtil::MapEnclosingClippedRect(
- content_to_target_transform, copy_shared_quad_state->clip_rect);
- }
+ target_transform);
+
+ ClipData new_clip_rect = CalculateClipRect(
+ clip_rect, ClipData(source_sqs->is_clipped, source_sqs->clip_rect),
+ target_transform);
+ copy_shared_quad_state->is_clipped = new_clip_rect.is_clipped;
+ copy_shared_quad_state->clip_rect = new_clip_rect.rect;
}
void SurfaceAggregator::CopyQuadsToPass(
const QuadList& source_quad_list,
const SharedQuadStateList& source_shared_quad_state_list,
- const gfx::Transform& content_to_target_transform,
+ const DrawQuad::ResourceIteratorCallback& remap,
+ const gfx::Transform& target_transform,
+ const ClipData& clip_rect,
RenderPass* dest_pass,
SurfaceId surface_id) {
const SharedQuadState* last_copied_source_shared_quad_state = NULL;
@@ -315,13 +389,14 @@ void SurfaceAggregator::CopyQuadsToPass(
if (quad->material == DrawQuad::SURFACE_CONTENT) {
const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
- HandleSurfaceQuad(surface_quad, dest_pass);
+ HandleSurfaceQuad(surface_quad, target_transform, clip_rect, dest_pass);
} else {
if (quad->shared_quad_state != last_copied_source_shared_quad_state) {
- CopySharedQuadState(
- quad->shared_quad_state, content_to_target_transform, dest_pass);
+ CopySharedQuadState(quad->shared_quad_state, target_transform,
+ clip_rect, dest_pass);
last_copied_source_shared_quad_state = quad->shared_quad_state;
}
+ DrawQuad* dest_quad;
if (quad->material == DrawQuad::RENDER_PASS) {
const RenderPassDrawQuad* pass_quad =
RenderPassDrawQuad::MaterialCast(quad);
@@ -329,29 +404,51 @@ void SurfaceAggregator::CopyQuadsToPass(
RenderPassId remapped_pass_id =
RemapPassId(original_pass_id, surface_id);
- dest_pass->CopyFromAndAppendRenderPassDrawQuad(
- pass_quad,
- dest_pass->shared_quad_state_list.back(),
+ gfx::Rect pass_damage;
+ for (const auto* pass : *dest_pass_list_) {
+ if (pass->id == remapped_pass_id) {
+ pass_damage = pass->damage_rect;
+ break;
+ }
+ }
+
+ dest_quad = dest_pass->CopyFromAndAppendRenderPassDrawQuad(
+ pass_quad, dest_pass->shared_quad_state_list.back(),
remapped_pass_id);
+ dest_pass->damage_rect =
+ gfx::UnionRects(dest_pass->damage_rect,
+ MathUtil::MapEnclosingClippedRect(
+ dest_quad->quadTransform(), pass_damage));
} else {
- dest_pass->CopyFromAndAppendDrawQuad(
+ dest_quad = dest_pass->CopyFromAndAppendDrawQuad(
quad, dest_pass->shared_quad_state_list.back());
}
+ if (!remap.is_null())
+ dest_quad->IterateResources(remap);
}
}
}
void SurfaceAggregator::CopyPasses(const DelegatedFrameData* frame_data,
Surface* surface) {
- RenderPassList source_pass_list;
-
// The root surface is allowed to have copy output requests, so grab them
// off its render passes.
std::multimap<RenderPassId, CopyOutputRequest*> copy_requests;
surface->TakeCopyOutputRequests(&copy_requests);
- bool invalid_frame = TakeResources(surface, frame_data, &source_pass_list);
+ const RenderPassList& source_pass_list = frame_data->render_pass_list;
+ bool invalid_frame = ValidateResources(surface, frame_data);
DCHECK(!invalid_frame);
+ if (invalid_frame)
+ return;
+
+ DrawQuad::ResourceIteratorCallback remap;
+ if (provider_) {
+ int child_id = ChildIdForSurface(surface);
+ remap =
+ base::Bind(&ResourceRemapHelper,
+ base::ConstRef(provider_->GetChildToParentMap(child_id)));
+ }
for (size_t i = 0; i < source_pass_list.size(); ++i) {
const RenderPass& source = *source_pass_list[i];
@@ -365,22 +462,39 @@ void SurfaceAggregator::CopyPasses(const DelegatedFrameData* frame_data,
RenderPassId remapped_pass_id =
RemapPassId(source.id, surface->surface_id());
- copy_pass->SetAll(remapped_pass_id,
- source.output_rect,
- DamageRectForSurface(surface, source),
+ gfx::Rect damage_rect =
+ (i < source_pass_list.size() - 1)
+ ? gfx::Rect()
+ : DamageRectForSurface(surface, source, source.output_rect);
+ copy_pass->SetAll(remapped_pass_id, source.output_rect, damage_rect,
source.transform_to_root_target,
source.has_transparent_background);
- CopyQuadsToPass(source.quad_list,
- source.shared_quad_state_list,
- gfx::Transform(),
- copy_pass.get(),
+ CopyQuadsToPass(source.quad_list, source.shared_quad_state_list, remap,
+ gfx::Transform(), ClipData(), copy_pass.get(),
surface->surface_id());
dest_pass_list_->push_back(copy_pass.Pass());
}
}
+void SurfaceAggregator::RemoveUnreferencedChildren() {
+ for (const auto& surface : previous_contained_surfaces_) {
+ if (!contained_surfaces_.count(surface.first)) {
+ SurfaceToResourceChildIdMap::iterator it =
+ surface_id_to_resource_child_id_.find(surface.first);
+ if (it != surface_id_to_resource_child_id_.end()) {
+ provider_->DestroyChild(it->second);
+ surface_id_to_resource_child_id_.erase(it);
+ }
+
+ Surface* surface_ptr = manager_->GetSurfaceForId(surface.first);
+ if (surface_ptr)
+ surface_ptr->RunDrawCallbacks(SurfaceDrawStatus::DRAW_SKIPPED);
+ }
+ }
+}
+
scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) {
Surface* surface = manager_->GetSurfaceForId(surface_id);
DCHECK(surface);
@@ -405,7 +519,11 @@ scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) {
referenced_surfaces_.erase(it);
DCHECK(referenced_surfaces_.empty());
+ if (dest_pass_list_->empty())
+ return nullptr;
+
dest_pass_list_ = NULL;
+ RemoveUnreferencedChildren();
contained_surfaces_.swap(previous_contained_surfaces_);
contained_surfaces_.clear();
@@ -423,4 +541,21 @@ scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) {
return frame.Pass();
}
+void SurfaceAggregator::ReleaseResources(SurfaceId surface_id) {
+ SurfaceToResourceChildIdMap::iterator it =
+ surface_id_to_resource_child_id_.find(surface_id);
+ if (it != surface_id_to_resource_child_id_.end()) {
+ provider_->DestroyChild(it->second);
+ surface_id_to_resource_child_id_.erase(it);
+ }
+}
+
+void SurfaceAggregator::SetFullDamageForSurface(SurfaceId surface_id) {
+ auto it = previous_contained_surfaces_.find(surface_id);
+ if (it == previous_contained_surfaces_.end())
+ return;
+ // Set the last drawn index as 0 to ensure full damage next time it's drawn.
+ it->second = 0;
+}
+
} // namespace cc
diff --git a/chromium/cc/surfaces/surface_aggregator.h b/chromium/cc/surfaces/surface_aggregator.h
index 31d35ddc7f4..8ceb4eb471e 100644
--- a/chromium/cc/surfaces/surface_aggregator.h
+++ b/chromium/cc/surfaces/surface_aggregator.h
@@ -10,6 +10,7 @@
#include "base/containers/hash_tables.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/scoped_ptr.h"
+#include "cc/quads/draw_quad.h"
#include "cc/quads/render_pass.h"
#include "cc/resources/transferable_resource.h"
#include "cc/surfaces/surface_id.h"
@@ -32,38 +33,62 @@ class CC_SURFACES_EXPORT SurfaceAggregator {
~SurfaceAggregator();
scoped_ptr<CompositorFrame> Aggregate(SurfaceId surface_id);
+ void ReleaseResources(SurfaceId surface_id);
SurfaceIndexMap& previous_contained_surfaces() {
return previous_contained_surfaces_;
}
+ void SetFullDamageForSurface(SurfaceId surface_id);
private:
+ struct ClipData {
+ ClipData() : is_clipped(false) {}
+ ClipData(bool is_clipped, const gfx::Rect& rect)
+ : is_clipped(is_clipped), rect(rect) {}
+
+ bool is_clipped;
+ gfx::Rect rect;
+ };
+
+ ClipData CalculateClipRect(const ClipData& surface_clip,
+ const ClipData& quad_clip,
+ const gfx::Transform& target_transform);
+
RenderPassId RemapPassId(RenderPassId surface_local_pass_id,
SurfaceId surface_id);
void HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
+ const gfx::Transform& target_transform,
+ const ClipData& clip_rect,
RenderPass* dest_pass);
void CopySharedQuadState(const SharedQuadState* source_sqs,
- const gfx::Transform& content_to_target_transform,
+ const gfx::Transform& target_transform,
+ const ClipData& clip_rect,
RenderPass* dest_render_pass);
void CopyQuadsToPass(const QuadList& source_quad_list,
const SharedQuadStateList& source_shared_quad_state_list,
- const gfx::Transform& content_to_target_transform,
+ const DrawQuad::ResourceIteratorCallback& remap,
+ const gfx::Transform& target_transform,
+ const ClipData& clip_rect,
RenderPass* dest_pass,
SurfaceId surface_id);
void CopyPasses(const DelegatedFrameData* frame_data, Surface* surface);
- bool TakeResources(Surface* surface,
- const DelegatedFrameData* frame_data,
- RenderPassList* render_pass_list);
+ // Remove Surfaces that were referenced before but aren't currently
+ // referenced from the ResourceProvider.
+ void RemoveUnreferencedChildren();
+
+ bool ValidateResources(Surface* surface,
+ const DelegatedFrameData* frame_data);
int ChildIdForSurface(Surface* surface);
gfx::Rect DamageRectForSurface(const Surface* surface,
- const RenderPass& source);
+ const RenderPass& source,
+ const gfx::Rect& full_rect);
SurfaceManager* manager_;
ResourceProvider* provider_;
class RenderPassIdAllocator;
- typedef base::ScopedPtrHashMap<SurfaceId, RenderPassIdAllocator>
+ typedef base::ScopedPtrHashMap<SurfaceId, scoped_ptr<RenderPassIdAllocator>>
RenderPassIdAllocatorMap;
RenderPassIdAllocatorMap render_pass_allocator_map_;
int next_render_pass_id_;
diff --git a/chromium/cc/surfaces/surface_aggregator_perftest.cc b/chromium/cc/surfaces/surface_aggregator_perftest.cc
new file mode 100644
index 00000000000..87a8932132c
--- /dev/null
+++ b/chromium/cc/surfaces/surface_aggregator_perftest.cc
@@ -0,0 +1,132 @@
+// 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.
+
+#include "cc/debug/lap_timer.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/surfaces/surface_aggregator.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/surface_manager.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+namespace {
+
+class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
+ public:
+ void ReturnResources(const ReturnedResourceArray& resources) override {}
+};
+
+class SurfaceAggregatorPerfTest : public testing::Test {
+ public:
+ SurfaceAggregatorPerfTest() : factory_(&manager_, &empty_client_) {
+ output_surface_ = FakeOutputSurface::CreateSoftware(
+ make_scoped_ptr(new SoftwareOutputDevice));
+ output_surface_->BindToClient(&output_surface_client_);
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager);
+
+ resource_provider_ = ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), nullptr, nullptr,
+ 0, false, 1);
+ aggregator_.reset(
+ new SurfaceAggregator(&manager_, resource_provider_.get()));
+ }
+
+ void RunTest(int num_surfaces,
+ int num_textures,
+ float opacity,
+ const std::string& name) {
+ for (int i = 1; i <= num_surfaces; i++) {
+ factory_.Create(SurfaceId(i));
+ scoped_ptr<RenderPass> pass(RenderPass::Create());
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+
+ SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
+ for (int j = 0; j < num_textures; j++) {
+ TransferableResource resource;
+ resource.id = j;
+ resource.is_software = true;
+ frame_data->resource_list.push_back(resource);
+
+ TextureDrawQuad* quad =
+ pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
+ const gfx::Rect rect(0, 0, 1, 1);
+ const gfx::Rect opaque_rect;
+ const gfx::Rect visible_rect(0, 0, 1, 1);
+ bool needs_blending = false;
+ bool premultiplied_alpha = false;
+ const gfx::PointF uv_top_left;
+ const gfx::PointF uv_bottom_right;
+ SkColor background_color = SK_ColorGREEN;
+ const float vertex_opacity[4] = {0.f, 0.f, 1.f, 1.f};
+ bool flipped = false;
+ bool nearest_neighbor = false;
+ quad->SetAll(sqs, rect, opaque_rect, visible_rect, needs_blending, j,
+ premultiplied_alpha, uv_top_left, uv_bottom_right,
+ background_color, vertex_opacity, flipped,
+ nearest_neighbor);
+ }
+ sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->opacity = opacity;
+ if (i > 1) {
+ SurfaceDrawQuad* surface_quad =
+ pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
+ surface_quad->SetNew(sqs, gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1),
+ SurfaceId(i - 1));
+ }
+
+ frame_data->render_pass_list.push_back(pass.Pass());
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = frame_data.Pass();
+ factory_.SubmitFrame(SurfaceId(i), frame.Pass(),
+ SurfaceFactory::DrawCallback());
+ }
+
+ timer_.Reset();
+ do {
+ scoped_ptr<CompositorFrame> aggregated =
+ aggregator_->Aggregate(SurfaceId(num_surfaces));
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("aggregator_speed", "", name, timer_.LapsPerSecond(),
+ "runs/s", true);
+
+ for (int i = 1; i <= num_surfaces; i++)
+ factory_.Destroy(SurfaceId(i));
+ }
+
+ protected:
+ SurfaceManager manager_;
+ EmptySurfaceFactoryClient empty_client_;
+ SurfaceFactory factory_;
+ FakeOutputSurfaceClient output_surface_client_;
+ scoped_ptr<OutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<SurfaceAggregator> aggregator_;
+ LapTimer timer_;
+};
+
+TEST_F(SurfaceAggregatorPerfTest, ManySurfacesOpaque) {
+ RunTest(20, 100, 1.f, "many_surfaces_opaque");
+}
+
+TEST_F(SurfaceAggregatorPerfTest, ManySurfacesTransparent) {
+ RunTest(20, 100, .5f, "many_surfaces_transparent");
+}
+
+TEST_F(SurfaceAggregatorPerfTest, FewSurfaces) {
+ RunTest(3, 1000, 1.f, "few_surfaces");
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/surfaces/surface_aggregator_test_helpers.cc b/chromium/cc/surfaces/surface_aggregator_test_helpers.cc
index 6b527c0bd2e..b21b37e28d6 100644
--- a/chromium/cc/surfaces/surface_aggregator_test_helpers.cc
+++ b/chromium/cc/surfaces/surface_aggregator_test_helpers.cc
@@ -24,13 +24,13 @@ namespace test {
void AddTestSurfaceQuad(TestRenderPass* pass,
const gfx::Size& surface_size,
+ float opacity,
SurfaceId surface_id) {
gfx::Transform content_to_target_transform;
gfx::Size content_bounds = surface_size;
gfx::Rect visible_content_rect = gfx::Rect(surface_size);
gfx::Rect clip_rect = gfx::Rect(surface_size);
bool is_clipped = false;
- float opacity = 1.0;
SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
SharedQuadState* shared_quad_state = pass->CreateAndAppendSharedQuadState();
@@ -82,7 +82,7 @@ void AddQuadInPass(TestRenderPass* pass, Quad desc) {
AddQuad(pass, gfx::Rect(0, 0, 5, 5), desc.color);
break;
case DrawQuad::SURFACE_CONTENT:
- AddTestSurfaceQuad(pass, gfx::Size(5, 5), desc.surface_id);
+ AddTestSurfaceQuad(pass, gfx::Size(5, 5), desc.opacity, desc.surface_id);
break;
case DrawQuad::RENDER_PASS:
AddTestRenderPassQuad(pass, desc.render_pass_id);
diff --git a/chromium/cc/surfaces/surface_aggregator_test_helpers.h b/chromium/cc/surfaces/surface_aggregator_test_helpers.h
index 6f3a342193f..05c83440616 100644
--- a/chromium/cc/surfaces/surface_aggregator_test_helpers.h
+++ b/chromium/cc/surfaces/surface_aggregator_test_helpers.h
@@ -30,9 +30,10 @@ struct Quad {
return quad;
}
- static Quad SurfaceQuad(SurfaceId surface_id) {
+ static Quad SurfaceQuad(SurfaceId surface_id, float opacity) {
Quad quad;
quad.material = DrawQuad::SURFACE_CONTENT;
+ quad.opacity = opacity;
quad.surface_id = surface_id;
return quad;
}
@@ -47,6 +48,7 @@ struct Quad {
DrawQuad::Material material;
// Set when material==DrawQuad::SURFACE_CONTENT.
SurfaceId surface_id;
+ float opacity;
// Set when material==DrawQuad::SOLID_COLOR.
SkColor color;
// Set when material==DrawQuad::RENDER_PASS.
@@ -55,6 +57,7 @@ struct Quad {
private:
Quad()
: material(DrawQuad::INVALID),
+ opacity(1.f),
color(SK_ColorWHITE),
render_pass_id(-1, -1) {}
};
diff --git a/chromium/cc/surfaces/surface_aggregator_unittest.cc b/chromium/cc/surfaces/surface_aggregator_unittest.cc
index 4771c823b29..40a3d572bda 100644
--- a/chromium/cc/surfaces/surface_aggregator_unittest.cc
+++ b/chromium/cc/surfaces/surface_aggregator_unittest.cc
@@ -59,7 +59,7 @@ class SurfaceAggregatorTest : public testing::Test {
TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) {
SurfaceId one_id(7);
- factory_.Create(one_id, SurfaceSize());
+ factory_.Create(one_id);
scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(one_id);
EXPECT_FALSE(frame);
factory_.Destroy(one_id);
@@ -69,13 +69,13 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
public:
SurfaceAggregatorValidSurfaceTest() : allocator_(1u), child_allocator_(2u) {}
- virtual void SetUp() {
+ void SetUp() override {
SurfaceAggregatorTest::SetUp();
root_surface_id_ = allocator_.GenerateId();
- factory_.Create(root_surface_id_, SurfaceSize());
+ factory_.Create(root_surface_id_);
}
- virtual void TearDown() {
+ void TearDown() override {
factory_.Destroy(root_surface_id_);
SurfaceAggregatorTest::TearDown();
}
@@ -123,7 +123,8 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
scoped_ptr<CompositorFrame> frame(new CompositorFrame);
frame->delegated_frame_data = frame_data.Pass();
- factory_.SubmitFrame(surface_id, frame.Pass(), base::Closure());
+ factory_.SubmitFrame(surface_id, frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
void QueuePassAsFrame(scoped_ptr<RenderPass> pass, SurfaceId surface_id) {
@@ -133,7 +134,8 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
child_frame->delegated_frame_data = delegated_frame_data.Pass();
- factory_.SubmitFrame(surface_id, child_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(surface_id, child_frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
protected:
@@ -155,6 +157,46 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleFrame) {
AggregateAndVerify(passes, arraysize(passes), ids, arraysize(ids));
}
+TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
+ SurfaceId embedded_surface_id = allocator_.GenerateId();
+ factory_.Create(embedded_surface_id);
+
+ test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass embedded_passes[] = {
+ test::Pass(embedded_quads, arraysize(embedded_quads))};
+
+ SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id);
+
+ test::Quad quads[] = {test::Quad::SurfaceQuad(embedded_surface_id, .5f)};
+ test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
+
+ SubmitFrame(passes, arraysize(passes), root_surface_id_);
+
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_id_);
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
+
+ RenderPassList& render_pass_list(frame_data->render_pass_list);
+ ASSERT_EQ(2u, render_pass_list.size());
+ SharedQuadStateList& shared_quad_state_list(
+ render_pass_list[0]->shared_quad_state_list);
+ ASSERT_EQ(2u, shared_quad_state_list.size());
+ EXPECT_EQ(1.f, shared_quad_state_list.ElementAt(0)->opacity);
+ EXPECT_EQ(1.f, shared_quad_state_list.ElementAt(1)->opacity);
+
+ SharedQuadStateList& shared_quad_state_list2(
+ render_pass_list[1]->shared_quad_state_list);
+ ASSERT_EQ(1u, shared_quad_state_list2.size());
+ EXPECT_EQ(.5f, shared_quad_state_list2.ElementAt(0)->opacity);
+
+ factory_.Destroy(embedded_surface_id);
+}
+
TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) {
test::Quad quads[][2] = {{test::Quad::SolidColorQuad(SK_ColorWHITE),
test::Quad::SolidColorQuad(SK_ColorLTGRAY)},
@@ -176,7 +218,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) {
// color quad should be aggregated into the final frame.
TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
SurfaceId embedded_surface_id = allocator_.GenerateId();
- factory_.Create(embedded_surface_id, SurfaceSize());
+ factory_.Create(embedded_surface_id);
test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
test::Pass embedded_passes[] = {
@@ -185,7 +227,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id);
test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
- test::Quad::SurfaceQuad(embedded_surface_id),
+ test::Quad::SurfaceQuad(embedded_surface_id, 1.f),
test::Quad::SolidColorQuad(SK_ColorBLACK)};
test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
@@ -205,7 +247,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
SurfaceId embedded_surface_id = allocator_.GenerateId();
- factory_.Create(embedded_surface_id, SurfaceSize());
+ factory_.Create(embedded_surface_id);
test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
test::Pass embedded_passes[] = {
@@ -218,7 +260,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
factory_.RequestCopyOfSurface(embedded_surface_id, copy_request.Pass());
test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
- test::Quad::SurfaceQuad(embedded_surface_id),
+ test::Quad::SurfaceQuad(embedded_surface_id, 1.f),
test::Quad::SolidColorQuad(SK_ColorBLACK)};
test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
@@ -262,7 +304,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
// Root surface may contain copy requests.
TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
SurfaceId embedded_surface_id = allocator_.GenerateId();
- factory_.Create(embedded_surface_id, SurfaceSize());
+ factory_.Create(embedded_surface_id);
test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
test::Pass embedded_passes[] = {
@@ -277,7 +319,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
CopyOutputRequest* copy_request2_ptr = copy_request2.get();
test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
- test::Quad::SurfaceQuad(embedded_surface_id),
+ test::Quad::SurfaceQuad(embedded_surface_id, 1.f),
test::Quad::SolidColorQuad(SK_ColorBLACK)};
test::Quad root_quads2[] = {test::Quad::SolidColorQuad(SK_ColorRED)};
test::Pass root_passes[] = {
@@ -298,7 +340,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
scoped_ptr<CompositorFrame> frame(new CompositorFrame);
frame->delegated_frame_data = frame_data.Pass();
- factory_.SubmitFrame(root_surface_id_, frame.Pass(), base::Closure());
+ factory_.SubmitFrame(root_surface_id_, frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
scoped_ptr<CompositorFrame> aggregated_frame =
@@ -350,7 +393,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
// This tests referencing a surface that has multiple render passes.
TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
SurfaceId embedded_surface_id = child_allocator_.GenerateId();
- factory_.Create(embedded_surface_id, SurfaceSize());
+ factory_.Create(embedded_surface_id);
RenderPassId pass_ids[] = {RenderPassId(1, 1), RenderPassId(1, 2),
RenderPassId(1, 3)};
@@ -368,7 +411,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
test::Quad root_quads[][2] = {
{test::Quad::SolidColorQuad(5), test::Quad::SolidColorQuad(6)},
- {test::Quad::SurfaceQuad(embedded_surface_id),
+ {test::Quad::SurfaceQuad(embedded_surface_id, 1.f),
test::Quad::RenderPassQuad(pass_ids[0])},
{test::Quad::SolidColorQuad(7), test::Quad::RenderPassQuad(pass_ids[1])}};
test::Pass root_passes[] = {
@@ -489,7 +532,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
// be dropped.
TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) {
test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
- test::Quad::SurfaceQuad(InvalidSurfaceId()),
+ test::Quad::SurfaceQuad(InvalidSurfaceId(), 1.f),
test::Quad::SolidColorQuad(SK_ColorBLUE)};
test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
@@ -508,9 +551,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) {
// should also just be dropped.
TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) {
SurfaceId surface_with_no_frame_id = allocator_.GenerateId();
- factory_.Create(surface_with_no_frame_id, gfx::Size(5, 5));
+ factory_.Create(surface_with_no_frame_id);
test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
- test::Quad::SurfaceQuad(surface_with_no_frame_id),
+ test::Quad::SurfaceQuad(surface_with_no_frame_id, 1.f),
test::Quad::SolidColorQuad(SK_ColorBLUE)};
test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
@@ -529,7 +572,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) {
// Tests a surface quad referencing itself, generating a trivial cycle.
// The quad creating the cycle should be dropped from the final frame.
TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) {
- test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_id_),
+ test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_id_, 1.f),
test::Quad::SolidColorQuad(SK_ColorYELLOW)};
test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
@@ -546,10 +589,10 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) {
// Tests a more complex cycle with one intermediate surface.
TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) {
SurfaceId child_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, SurfaceSize());
+ factory_.Create(child_surface_id);
test::Quad parent_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE),
- test::Quad::SurfaceQuad(child_surface_id),
+ test::Quad::SurfaceQuad(child_surface_id, 1.f),
test::Quad::SolidColorQuad(SK_ColorCYAN)};
test::Pass parent_passes[] = {
test::Pass(parent_quads, arraysize(parent_quads))};
@@ -557,7 +600,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) {
SubmitFrame(parent_passes, arraysize(parent_passes), root_surface_id_);
test::Quad child_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
- test::Quad::SurfaceQuad(root_surface_id_),
+ test::Quad::SurfaceQuad(root_surface_id_, 1.f),
test::Quad::SolidColorQuad(SK_ColorMAGENTA)};
test::Pass child_passes[] = {test::Pass(child_quads, arraysize(child_quads))};
@@ -585,7 +628,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) {
// namespace and update RenderPassDrawQuad's id references to match.
TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) {
SurfaceId child_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, SurfaceSize());
+ factory_.Create(child_surface_id);
RenderPassId child_pass_id[] = {RenderPassId(1, 1), RenderPassId(1, 2)};
test::Quad child_quad[][1] = {{test::Quad::SolidColorQuad(SK_ColorGREEN)},
@@ -599,7 +642,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) {
// Pass IDs from the parent surface may collide with ones from the child.
RenderPassId parent_pass_id[] = {RenderPassId(2, 1), RenderPassId(1, 2)};
test::Quad parent_quad[][1] = {
- {test::Quad::SurfaceQuad(child_surface_id)},
+ {test::Quad::SurfaceQuad(child_surface_id, 1.f)},
{test::Quad::RenderPassQuad(parent_pass_id[0])}};
test::Pass parent_passes[] = {
test::Pass(parent_quad[0], arraysize(parent_quad[0]), parent_pass_id[0]),
@@ -713,7 +756,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
RenderPassId pass_id(1, 1);
SurfaceId grandchild_surface_id = allocator_.GenerateId();
- factory_.Create(grandchild_surface_id, SurfaceSize());
+ factory_.Create(grandchild_surface_id);
scoped_ptr<RenderPass> grandchild_pass = RenderPass::Create();
gfx::Rect output_rect(SurfaceSize());
gfx::Rect damage_rect(SurfaceSize());
@@ -725,7 +768,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
QueuePassAsFrame(grandchild_pass.Pass(), grandchild_surface_id);
SurfaceId child_one_surface_id = allocator_.GenerateId();
- factory_.Create(child_one_surface_id, SurfaceSize());
+ factory_.Create(child_one_surface_id);
scoped_ptr<RenderPass> child_one_pass = RenderPass::Create();
child_one_pass->SetNew(
@@ -743,7 +786,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
QueuePassAsFrame(child_one_pass.Pass(), child_one_surface_id);
SurfaceId child_two_surface_id = allocator_.GenerateId();
- factory_.Create(child_two_surface_id, SurfaceSize());
+ factory_.Create(child_two_surface_id);
scoped_ptr<RenderPass> child_two_pass = RenderPass::Create();
child_two_pass->SetNew(
@@ -811,55 +854,98 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
// The root surface has one pass with a surface quad transformed by +10 in the y
// direction.
//
+// The middle surface has one pass with a surface quad scaled by 2 in the x
+// and 3 in the y directions.
+//
// The child surface has two passes. The first pass has a quad with a transform
// of +5 in the x direction. The second pass has a reference to the first pass'
// pass id and a transform of +8 in the x direction.
//
-// After aggregation, the child surface's root pass quad should have both
-// transforms concatenated for a total transform of +8 x, +10 y. The
+// After aggregation, the child surface's root pass quad should have all
+// transforms concatenated for a total transform of +23 x, +10 y. The
// contributing render pass' transform in the aggregate frame should not be
// affected.
TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
+ // Innermost child surface.
SurfaceId child_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, SurfaceSize());
- RenderPassId child_pass_id[] = {RenderPassId(1, 1), RenderPassId(1, 2)};
- test::Quad child_quads[][1] = {
- {test::Quad::SolidColorQuad(SK_ColorGREEN)},
- {test::Quad::RenderPassQuad(child_pass_id[0])}};
- test::Pass child_passes[] = {
- test::Pass(child_quads[0], arraysize(child_quads[0]), child_pass_id[0]),
- test::Pass(child_quads[1], arraysize(child_quads[1]), child_pass_id[1])};
+ {
+ factory_.Create(child_surface_id);
+ RenderPassId child_pass_id[] = {RenderPassId(1, 1), RenderPassId(1, 2)};
+ test::Quad child_quads[][1] = {
+ {test::Quad::SolidColorQuad(SK_ColorGREEN)},
+ {test::Quad::RenderPassQuad(child_pass_id[0])},
+ };
+ test::Pass child_passes[] = {
+ test::Pass(child_quads[0], arraysize(child_quads[0]), child_pass_id[0]),
+ test::Pass(child_quads[1], arraysize(child_quads[1]),
+ child_pass_id[1])};
+
+ RenderPassList child_pass_list;
+ AddPasses(&child_pass_list, gfx::Rect(SurfaceSize()), child_passes,
+ arraysize(child_passes));
- RenderPassList child_pass_list;
- AddPasses(&child_pass_list,
- gfx::Rect(SurfaceSize()),
- child_passes,
- arraysize(child_passes));
+ RenderPass* child_nonroot_pass = child_pass_list.at(0u);
+ child_nonroot_pass->transform_to_root_target.Translate(8, 0);
+ SharedQuadState* child_nonroot_pass_sqs =
+ child_nonroot_pass->shared_quad_state_list.front();
+ child_nonroot_pass_sqs->content_to_target_transform.Translate(5, 0);
- RenderPass* child_nonroot_pass = child_pass_list.at(0u);
- child_nonroot_pass->transform_to_root_target.Translate(8, 0);
- SharedQuadState* child_nonroot_pass_sqs =
- child_nonroot_pass->shared_quad_state_list.front();
- child_nonroot_pass_sqs->content_to_target_transform.Translate(5, 0);
+ RenderPass* child_root_pass = child_pass_list.at(1u);
+ SharedQuadState* child_root_pass_sqs =
+ child_root_pass->shared_quad_state_list.front();
+ child_root_pass_sqs->content_to_target_transform.Translate(8, 0);
+ child_root_pass_sqs->is_clipped = true;
+ child_root_pass_sqs->clip_rect = gfx::Rect(0, 0, 5, 5);
- RenderPass* child_root_pass = child_pass_list.at(1u);
- SharedQuadState* child_root_pass_sqs =
- child_root_pass->shared_quad_state_list.front();
- child_root_pass_sqs->content_to_target_transform.Translate(8, 0);
- child_root_pass_sqs->is_clipped = true;
- child_root_pass_sqs->clip_rect = gfx::Rect(0, 0, 5, 5);
+ scoped_ptr<DelegatedFrameData> child_frame_data(new DelegatedFrameData);
+ child_pass_list.swap(child_frame_data->render_pass_list);
- scoped_ptr<DelegatedFrameData> child_frame_data(new DelegatedFrameData);
- child_pass_list.swap(child_frame_data->render_pass_list);
+ scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
+ child_frame->delegated_frame_data = child_frame_data.Pass();
- scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
- child_frame->delegated_frame_data = child_frame_data.Pass();
+ factory_.SubmitFrame(child_surface_id, child_frame.Pass(),
+ SurfaceFactory::DrawCallback());
+ }
- factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
+ // Middle child surface.
+ SurfaceId middle_surface_id = allocator_.GenerateId();
+ {
+ factory_.Create(middle_surface_id);
+ test::Quad middle_quads[] = {
+ test::Quad::SurfaceQuad(child_surface_id, 1.f)};
+ test::Pass middle_passes[] = {
+ test::Pass(middle_quads, arraysize(middle_quads)),
+ };
+
+ RenderPassList middle_pass_list;
+ AddPasses(&middle_pass_list, gfx::Rect(SurfaceSize()), middle_passes,
+ arraysize(middle_passes));
+
+ RenderPass* middle_root_pass = middle_pass_list.at(0u);
+ middle_root_pass->quad_list.ElementAt(0)->visible_rect =
+ gfx::Rect(0, 1, 100, 7);
+ SharedQuadState* middle_root_pass_sqs =
+ middle_root_pass->shared_quad_state_list.front();
+ middle_root_pass_sqs->content_to_target_transform.Scale(2, 3);
+
+ scoped_ptr<DelegatedFrameData> middle_frame_data(new DelegatedFrameData);
+ middle_pass_list.swap(middle_frame_data->render_pass_list);
+
+ scoped_ptr<CompositorFrame> middle_frame(new CompositorFrame);
+ middle_frame->delegated_frame_data = middle_frame_data.Pass();
+
+ factory_.SubmitFrame(middle_surface_id, middle_frame.Pass(),
+ SurfaceFactory::DrawCallback());
+ }
- test::Quad root_quads[] = {test::Quad::SolidColorQuad(1),
- test::Quad::SurfaceQuad(child_surface_id)};
- test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
+ // Root surface.
+ test::Quad secondary_quads[] = {
+ test::Quad::SolidColorQuad(1),
+ test::Quad::SurfaceQuad(middle_surface_id, 1.f)};
+ test::Quad root_quads[] = {test::Quad::SolidColorQuad(1)};
+ test::Pass root_passes[] = {
+ test::Pass(secondary_quads, arraysize(secondary_quads)),
+ test::Pass(root_quads, arraysize(root_quads))};
RenderPassList root_pass_list;
AddPasses(&root_pass_list,
@@ -873,6 +959,10 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
root_pass_list.at(0)
->shared_quad_state_list.ElementAt(1)
->content_to_target_transform.Translate(0, 10);
+ root_pass_list.at(0)->quad_list.ElementAt(1)->visible_rect =
+ gfx::Rect(0, 0, 8, 100);
+
+ root_pass_list[0]->transform_to_root_target.Translate(10, 5);
scoped_ptr<DelegatedFrameData> root_frame_data(new DelegatedFrameData);
root_pass_list.swap(root_frame_data->render_pass_list);
@@ -880,7 +970,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
root_frame->delegated_frame_data = root_frame_data.Pass();
- factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(root_surface_id_, root_frame.Pass(),
+ SurfaceFactory::DrawCallback());
scoped_ptr<CompositorFrame> aggregated_frame =
aggregator_.Aggregate(root_surface_id_);
@@ -892,17 +983,19 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
- ASSERT_EQ(2u, aggregated_pass_list.size());
+ ASSERT_EQ(3u, aggregated_pass_list.size());
ASSERT_EQ(1u, aggregated_pass_list[0]->shared_quad_state_list.size());
// The first pass should have one shared quad state for the one solid color
// quad.
EXPECT_EQ(1u, aggregated_pass_list[0]->shared_quad_state_list.size());
- // The second (root) pass should have just two shared quad states. We'll
+ // The second pass should have just two shared quad states. We'll
// verify the properties through the quads.
EXPECT_EQ(2u, aggregated_pass_list[1]->shared_quad_state_list.size());
+ EXPECT_EQ(1u, aggregated_pass_list[2]->shared_quad_state_list.size());
+
SharedQuadState* aggregated_first_pass_sqs =
aggregated_pass_list[0]->shared_quad_state_list.front();
@@ -914,9 +1007,12 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
aggregated_first_pass_sqs->content_to_target_transform.ToString());
// The first pass's transform to the root target should include the aggregated
- // transform.
+ // transform, including the transform from the child pass to the root.
gfx::Transform expected_first_pass_transform_to_root_target;
- expected_first_pass_transform_to_root_target.Translate(8, 10);
+ expected_first_pass_transform_to_root_target.Translate(10, 5);
+ expected_first_pass_transform_to_root_target.Translate(0, 10);
+ expected_first_pass_transform_to_root_target.Scale(2, 3);
+ expected_first_pass_transform_to_root_target.Translate(8, 0);
EXPECT_EQ(expected_first_pass_transform_to_root_target.ToString(),
aggregated_pass_list[0]->transform_to_root_target.ToString());
@@ -928,9 +1024,12 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
// still be +7 in the y direction.
expected_root_pass_quad_transforms[0].Translate(0, 7);
// The second quad in the root pass is aggregated from the child surface so
- // its transform should be the combination of its original translation (0, 10)
- // and the child surface draw quad's translation (8, 0).
- expected_root_pass_quad_transforms[1].Translate(8, 10);
+ // its transform should be the combination of its original translation
+ // (0, 10), the middle surface draw quad's scale of (2, 3), and the
+ // child surface draw quad's translation (8, 0).
+ expected_root_pass_quad_transforms[1].Translate(0, 10);
+ expected_root_pass_quad_transforms[1].Scale(2, 3);
+ expected_root_pass_quad_transforms[1].Translate(8, 0);
for (auto iter = aggregated_pass_list[1]->quad_list.cbegin();
iter != aggregated_pass_list[1]->quad_list.cend();
@@ -944,19 +1043,21 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
aggregated_pass_list[1]->shared_quad_state_list.ElementAt(1)->is_clipped);
// The second quad in the root pass is aggregated from the child, so its
- // clip rect must be transformed by the child's translation.
- EXPECT_EQ(gfx::Rect(0, 10, 5, 5).ToString(),
+ // clip rect must be transformed by the child's translation/scale and
+ // clipped be the visible_rects for both children.
+ EXPECT_EQ(gfx::Rect(0, 13, 8, 12).ToString(),
aggregated_pass_list[1]
->shared_quad_state_list.ElementAt(1)
->clip_rect.ToString());
+ factory_.Destroy(middle_surface_id);
factory_.Destroy(child_surface_id);
}
// Tests that damage rects are aggregated correctly when surfaces change.
TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
SurfaceId child_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, SurfaceSize());
+ factory_.Create(child_surface_id);
RenderPassId child_pass_id = RenderPassId(1, 1);
test::Quad child_quads[] = {test::Quad::RenderPassQuad(child_pass_id)};
test::Pass child_passes[] = {
@@ -979,10 +1080,16 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
child_frame->delegated_frame_data = child_frame_data.Pass();
- factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(child_surface_id, child_frame.Pass(),
+ SurfaceFactory::DrawCallback());
- test::Quad root_quads[] = {test::Quad::SurfaceQuad(child_surface_id)};
- test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
+ RenderPassId pass_id(5, 10);
+ test::Quad first_quads[] = {test::Quad::SurfaceQuad(child_surface_id, 1.f)};
+ test::Quad root_quads[] = {test::Quad::RenderPassQuad(pass_id)};
+
+ test::Pass root_passes[] = {
+ test::Pass(first_quads, arraysize(first_quads), pass_id),
+ test::Pass(root_quads, arraysize(root_quads))};
RenderPassList root_pass_list;
AddPasses(&root_pass_list,
@@ -994,6 +1101,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
->shared_quad_state_list.front()
->content_to_target_transform.Translate(0, 10);
root_pass_list.at(0)->damage_rect = gfx::Rect(5, 5, 10, 10);
+ root_pass_list.at(1)->damage_rect = gfx::Rect(5, 5, 100, 100);
scoped_ptr<DelegatedFrameData> root_frame_data(new DelegatedFrameData);
root_pass_list.swap(root_frame_data->render_pass_list);
@@ -1001,7 +1109,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
root_frame->delegated_frame_data = root_frame_data.Pass();
- factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(root_surface_id_, root_frame.Pass(),
+ SurfaceFactory::DrawCallback());
scoped_ptr<CompositorFrame> aggregated_frame =
aggregator_.Aggregate(root_surface_id_);
@@ -1013,11 +1122,11 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
- ASSERT_EQ(1u, aggregated_pass_list.size());
+ ASSERT_EQ(2u, aggregated_pass_list.size());
// Damage rect for first aggregation should contain entire root surface.
EXPECT_TRUE(
- aggregated_pass_list[0]->damage_rect.Contains(gfx::Rect(SurfaceSize())));
+ aggregated_pass_list[1]->damage_rect.Contains(gfx::Rect(SurfaceSize())));
{
AddPasses(&child_pass_list,
@@ -1037,7 +1146,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
child_frame->delegated_frame_data = child_frame_data.Pass();
- factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(child_surface_id, child_frame.Pass(),
+ SurfaceFactory::DrawCallback());
scoped_ptr<CompositorFrame> aggregated_frame =
aggregator_.Aggregate(root_surface_id_);
@@ -1050,12 +1160,12 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
- ASSERT_EQ(1u, aggregated_pass_list.size());
+ ASSERT_EQ(2u, aggregated_pass_list.size());
// Outer surface didn't change, so transformed inner damage rect should be
// used.
EXPECT_EQ(gfx::Rect(10, 20, 10, 10).ToString(),
- aggregated_pass_list[0]->damage_rect.ToString());
+ aggregated_pass_list[1]->damage_rect.ToString());
}
{
@@ -1076,7 +1186,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
root_frame->delegated_frame_data = root_frame_data.Pass();
- factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(root_surface_id_, root_frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
{
@@ -1097,7 +1208,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
root_frame->delegated_frame_data = root_frame_data.Pass();
- factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(root_surface_id_, root_frame.Pass(),
+ SurfaceFactory::DrawCallback());
scoped_ptr<CompositorFrame> aggregated_frame =
aggregator_.Aggregate(root_surface_id_);
@@ -1110,11 +1222,50 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
- ASSERT_EQ(1u, aggregated_pass_list.size());
+ ASSERT_EQ(2u, aggregated_pass_list.size());
// The root surface was enqueued without being aggregated once, so it should
// be treated as completely damaged.
- EXPECT_TRUE(aggregated_pass_list[0]->damage_rect.Contains(
+ EXPECT_TRUE(aggregated_pass_list[1]->damage_rect.Contains(
+ gfx::Rect(SurfaceSize())));
+ }
+
+ // No Surface changed, so no damage should be given.
+ {
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_id_);
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data =
+ aggregated_frame->delegated_frame_data.get();
+
+ const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
+
+ ASSERT_EQ(2u, aggregated_pass_list.size());
+
+ EXPECT_TRUE(aggregated_pass_list[1]->damage_rect.IsEmpty());
+ }
+
+ // SetFullDamageRectForSurface should cause the entire output to be
+ // marked as damaged.
+ {
+ aggregator_.SetFullDamageForSurface(root_surface_id_);
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_id_);
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data =
+ aggregated_frame->delegated_frame_data.get();
+
+ const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
+
+ ASSERT_EQ(2u, aggregated_pass_list.size());
+
+ EXPECT_TRUE(aggregated_pass_list[1]->damage_rect.Contains(
gfx::Rect(SurfaceSize())));
}
@@ -1123,7 +1274,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
class SurfaceAggregatorWithResourcesTest : public testing::Test {
public:
- virtual void SetUp() {
+ void SetUp() override {
output_surface_ = FakeOutputSurface::CreateSoftware(
make_scoped_ptr(new SoftwareOutputDevice));
output_surface_->BindToClient(&output_surface_client_);
@@ -1171,16 +1322,27 @@ class ResourceTrackingSurfaceFactoryClient : public SurfaceFactoryClient {
void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids,
size_t num_resource_ids,
+ bool valid,
+ SurfaceId child_id,
SurfaceFactory* factory,
SurfaceId surface_id) {
scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
scoped_ptr<RenderPass> pass = RenderPass::Create();
pass->id = RenderPassId(1, 1);
SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->opacity = 1.f;
+ if (!child_id.is_null()) {
+ SurfaceDrawQuad* surface_quad =
+ pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
+ surface_quad->SetNew(sqs, gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1),
+ child_id);
+ }
+
for (size_t i = 0u; i < num_resource_ids; ++i) {
TransferableResource resource;
resource.id = resource_ids[i];
- resource.is_software = true;
+ // ResourceProvider is software, so only software resources are valid.
+ resource.is_software = valid;
frame_data->resource_list.push_back(resource);
TextureDrawQuad* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
const gfx::Rect rect;
@@ -1193,6 +1355,7 @@ void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids,
SkColor background_color = SK_ColorGREEN;
const float vertex_opacity[4] = {0.f, 0.f, 1.f, 1.f};
bool flipped = false;
+ bool nearest_neighbor = false;
quad->SetAll(sqs,
rect,
opaque_rect,
@@ -1204,31 +1367,32 @@ void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids,
uv_bottom_right,
background_color,
vertex_opacity,
- flipped);
-
- quad->shared_quad_state = sqs;
+ flipped,
+ nearest_neighbor);
}
frame_data->render_pass_list.push_back(pass.Pass());
scoped_ptr<CompositorFrame> frame(new CompositorFrame);
frame->delegated_frame_data = frame_data.Pass();
- factory->SubmitFrame(surface_id, frame.Pass(), base::Closure());
+ factory->SubmitFrame(surface_id, frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) {
ResourceTrackingSurfaceFactoryClient client;
SurfaceFactory factory(&manager_, &client);
SurfaceId surface_id(7u);
- factory.Create(surface_id, SurfaceSize());
+ factory.Create(surface_id);
ResourceProvider::ResourceId ids[] = {11, 12, 13};
- SubmitFrameWithResources(ids, arraysize(ids), &factory, surface_id);
+ SubmitFrameWithResources(ids, arraysize(ids), true, SurfaceId(), &factory,
+ surface_id);
scoped_ptr<CompositorFrame> frame = aggregator_->Aggregate(surface_id);
// Nothing should be available to be returned yet.
EXPECT_TRUE(client.returned_resources().empty());
- SubmitFrameWithResources(NULL, 0u, &factory, surface_id);
+ SubmitFrameWithResources(NULL, 0u, true, SurfaceId(), &factory, surface_id);
frame = aggregator_->Aggregate(surface_id);
@@ -1242,6 +1406,123 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) {
factory.Destroy(surface_id);
}
+TEST_F(SurfaceAggregatorWithResourcesTest, TakeInvalidResources) {
+ ResourceTrackingSurfaceFactoryClient client;
+ SurfaceFactory factory(&manager_, &client);
+ SurfaceId surface_id(7u);
+ factory.Create(surface_id);
+
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->id = RenderPassId(1, 1);
+ TransferableResource resource;
+ resource.id = 11;
+ // ResourceProvider is software but resource is not, so it should be
+ // ignored.
+ resource.is_software = false;
+ frame_data->resource_list.push_back(resource);
+ frame_data->render_pass_list.push_back(pass.Pass());
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = frame_data.Pass();
+ factory.SubmitFrame(surface_id, frame.Pass(), SurfaceFactory::DrawCallback());
+
+ scoped_ptr<CompositorFrame> returned_frame =
+ aggregator_->Aggregate(surface_id);
+
+ // Nothing should be available to be returned yet.
+ EXPECT_TRUE(client.returned_resources().empty());
+
+ SubmitFrameWithResources(NULL, 0, true, SurfaceId(), &factory, surface_id);
+ ASSERT_EQ(1u, client.returned_resources().size());
+ EXPECT_EQ(11u, client.returned_resources()[0].id);
+
+ factory.Destroy(surface_id);
+}
+
+TEST_F(SurfaceAggregatorWithResourcesTest, TwoSurfaces) {
+ ResourceTrackingSurfaceFactoryClient client;
+ SurfaceFactory factory(&manager_, &client);
+ SurfaceId surface_id(7u);
+ factory.Create(surface_id);
+ SurfaceId surface_id2(8u);
+ factory.Create(surface_id2);
+
+ ResourceProvider::ResourceId ids[] = {11, 12, 13};
+ SubmitFrameWithResources(ids, arraysize(ids), true, SurfaceId(), &factory,
+ surface_id);
+ ResourceProvider::ResourceId ids2[] = {14, 15, 16};
+ SubmitFrameWithResources(ids2, arraysize(ids2), true, SurfaceId(), &factory,
+ surface_id2);
+
+ scoped_ptr<CompositorFrame> frame = aggregator_->Aggregate(surface_id);
+
+ SubmitFrameWithResources(NULL, 0, true, SurfaceId(), &factory, surface_id);
+
+ // Nothing should be available to be returned yet.
+ EXPECT_TRUE(client.returned_resources().empty());
+
+ frame = aggregator_->Aggregate(surface_id2);
+
+ // surface_id wasn't referenced, so its resources should be returned.
+ ASSERT_EQ(3u, client.returned_resources().size());
+ ResourceProvider::ResourceId returned_ids[3];
+ for (size_t i = 0; i < 3; ++i) {
+ returned_ids[i] = client.returned_resources()[i].id;
+ }
+ EXPECT_THAT(returned_ids,
+ testing::WhenSorted(testing::ElementsAreArray(ids)));
+ EXPECT_EQ(3u, resource_provider_->num_resources());
+ factory.Destroy(surface_id);
+ factory.Destroy(surface_id2);
+}
+
+// Ensure that aggregator completely ignores Surfaces that reference invalid
+// resources.
+TEST_F(SurfaceAggregatorWithResourcesTest, InvalidChildSurface) {
+ ResourceTrackingSurfaceFactoryClient client;
+ SurfaceFactory factory(&manager_, &client);
+ SurfaceId root_surface_id(7u);
+ factory.Create(root_surface_id);
+ SurfaceId middle_surface_id(8u);
+ factory.Create(middle_surface_id);
+ SurfaceId child_surface_id(9u);
+ factory.Create(child_surface_id);
+
+ ResourceProvider::ResourceId ids[] = {14, 15, 16};
+ SubmitFrameWithResources(ids, arraysize(ids), true, SurfaceId(), &factory,
+ child_surface_id);
+
+ ResourceProvider::ResourceId ids2[] = {17, 18, 19};
+ SubmitFrameWithResources(ids2, arraysize(ids2), false, child_surface_id,
+ &factory, middle_surface_id);
+
+ ResourceProvider::ResourceId ids3[] = {20, 21, 22};
+ SubmitFrameWithResources(ids3, arraysize(ids3), true, middle_surface_id,
+ &factory, root_surface_id);
+
+ scoped_ptr<CompositorFrame> frame;
+ frame = aggregator_->Aggregate(root_surface_id);
+
+ RenderPassList* pass_list = &frame->delegated_frame_data->render_pass_list;
+ ASSERT_EQ(1u, pass_list->size());
+ EXPECT_EQ(1u, pass_list->back()->shared_quad_state_list.size());
+ EXPECT_EQ(3u, pass_list->back()->quad_list.size());
+
+ SubmitFrameWithResources(ids2, arraysize(ids), true, child_surface_id,
+ &factory, middle_surface_id);
+
+ frame = aggregator_->Aggregate(root_surface_id);
+
+ pass_list = &frame->delegated_frame_data->render_pass_list;
+ ASSERT_EQ(1u, pass_list->size());
+ EXPECT_EQ(3u, pass_list->back()->shared_quad_state_list.size());
+ EXPECT_EQ(9u, pass_list->back()->quad_list.size());
+
+ factory.Destroy(root_surface_id);
+ factory.Destroy(child_surface_id);
+ factory.Destroy(middle_surface_id);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/surfaces/surface_damage_observer.h b/chromium/cc/surfaces/surface_damage_observer.h
index 379c9f75ee4..62ee0126e66 100644
--- a/chromium/cc/surfaces/surface_damage_observer.h
+++ b/chromium/cc/surfaces/surface_damage_observer.h
@@ -11,7 +11,9 @@ namespace cc {
class SurfaceDamageObserver {
public:
- virtual void OnSurfaceDamaged(SurfaceId surface_id) = 0;
+ // Runs when a Surface is damaged. *changed should be set to true if this
+ // causes a Display to be damaged.
+ virtual void OnSurfaceDamaged(SurfaceId surface_id, bool* changed) = 0;
};
} // namespace cc
diff --git a/chromium/cc/surfaces/surface_display_output_surface.cc b/chromium/cc/surfaces/surface_display_output_surface.cc
new file mode 100644
index 00000000000..e1f90da7614
--- /dev/null
+++ b/chromium/cc/surfaces/surface_display_output_surface.cc
@@ -0,0 +1,99 @@
+// Copyright 2014 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/surfaces/surface_display_output_surface.h"
+
+#include "base/bind.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/compositor_frame_ack.h"
+#include "cc/surfaces/display.h"
+#include "cc/surfaces/onscreen_display_client.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_manager.h"
+
+namespace cc {
+
+SurfaceDisplayOutputSurface::SurfaceDisplayOutputSurface(
+ SurfaceManager* surface_manager,
+ SurfaceIdAllocator* allocator,
+ const scoped_refptr<ContextProvider>& context_provider)
+ : OutputSurface(context_provider),
+ display_client_(NULL),
+ factory_(surface_manager, this),
+ allocator_(allocator) {
+ factory_.set_needs_sync_points(false);
+ capabilities_.delegated_rendering = true;
+ capabilities_.max_frames_pending = 1;
+ capabilities_.adjust_deadline_for_parent = true;
+ capabilities_.can_force_reclaim_resources = true;
+ // Display and SurfaceDisplayOutputSurface share a GL context, so sync
+ // points aren't needed when passing resources between them.
+ capabilities_.delegated_sync_points_required = false;
+}
+
+SurfaceDisplayOutputSurface::~SurfaceDisplayOutputSurface() {
+ client_ = NULL;
+ if (!surface_id_.is_null()) {
+ factory_.Destroy(surface_id_);
+ }
+}
+
+void SurfaceDisplayOutputSurface::ReceivedVSyncParameters(
+ base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ CommitVSyncParameters(timebase, interval);
+}
+
+void SurfaceDisplayOutputSurface::SwapBuffers(CompositorFrame* frame) {
+ gfx::Size frame_size =
+ frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
+ if (frame_size.IsEmpty() || frame_size != display_size_) {
+ if (!surface_id_.is_null()) {
+ factory_.Destroy(surface_id_);
+ }
+ surface_id_ = allocator_->GenerateId();
+ factory_.Create(surface_id_);
+ display_size_ = frame_size;
+ }
+ display_client_->display()->SetSurfaceId(surface_id_,
+ frame->metadata.device_scale_factor);
+
+ scoped_ptr<CompositorFrame> frame_copy(new CompositorFrame());
+ frame->AssignTo(frame_copy.get());
+ factory_.SubmitFrame(
+ surface_id_, frame_copy.Pass(),
+ base::Bind(&SurfaceDisplayOutputSurface::SwapBuffersComplete,
+ base::Unretained(this)));
+
+ client_->DidSwapBuffers();
+}
+
+bool SurfaceDisplayOutputSurface::BindToClient(OutputSurfaceClient* client) {
+ DCHECK(client);
+ DCHECK(display_client_);
+ client_ = client;
+ // Avoid initializing GL context here, as this should be sharing the
+ // Display's context.
+ return display_client_->Initialize();
+}
+
+void SurfaceDisplayOutputSurface::ForceReclaimResources() {
+ if (!surface_id_.is_null())
+ factory_.SubmitFrame(surface_id_, nullptr, SurfaceFactory::DrawCallback());
+}
+
+void SurfaceDisplayOutputSurface::ReturnResources(
+ const ReturnedResourceArray& resources) {
+ CompositorFrameAck ack;
+ ack.resources = resources;
+ if (client_)
+ client_->ReclaimResources(&ack);
+}
+
+void SurfaceDisplayOutputSurface::SwapBuffersComplete(SurfaceDrawStatus drawn) {
+ if (client_ && !display_client_->output_surface_lost())
+ client_->DidSwapBuffersComplete();
+}
+
+} // namespace cc
diff --git a/chromium/cc/surfaces/surface_display_output_surface.h b/chromium/cc/surfaces/surface_display_output_surface.h
new file mode 100644
index 00000000000..c11bb86075d
--- /dev/null
+++ b/chromium/cc/surfaces/surface_display_output_surface.h
@@ -0,0 +1,62 @@
+// Copyright 2014 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_SURFACES_SURFACE_DISPLAY_OUTPUT_SURFACE_H_
+#define CC_SURFACES_SURFACE_DISPLAY_OUTPUT_SURFACE_H_
+
+#include "cc/output/output_surface.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "cc/surfaces/surfaces_export.h"
+
+namespace cc {
+class Display;
+class OnscreenDisplayClient;
+class SurfaceManager;
+
+// This class is maps a compositor OutputSurface to the surface system's Display
+// concept, allowing a compositor client to submit frames for a native root
+// window or physical display.
+class CC_SURFACES_EXPORT SurfaceDisplayOutputSurface
+ : public OutputSurface,
+ public SurfaceFactoryClient {
+ public:
+ // The underlying Display and SurfaceManager must outlive this class.
+ SurfaceDisplayOutputSurface(
+ SurfaceManager* surface_manager,
+ SurfaceIdAllocator* allocator,
+ const scoped_refptr<ContextProvider>& context_provider);
+ ~SurfaceDisplayOutputSurface() override;
+
+ void set_display_client(OnscreenDisplayClient* display_client) {
+ display_client_ = display_client;
+ }
+ SurfaceFactory* factory() { return &factory_; }
+ void ReceivedVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval);
+
+ // OutputSurface implementation.
+ void SwapBuffers(CompositorFrame* frame) override;
+ bool BindToClient(OutputSurfaceClient* client) override;
+ void ForceReclaimResources() override;
+
+ // SurfaceFactoryClient implementation.
+ void ReturnResources(const ReturnedResourceArray& resources) override;
+
+ private:
+ void SwapBuffersComplete(SurfaceDrawStatus drawn);
+
+ OnscreenDisplayClient* display_client_;
+ SurfaceFactory factory_;
+ gfx::Size display_size_;
+ SurfaceId surface_id_;
+ SurfaceIdAllocator* allocator_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceDisplayOutputSurface);
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_SURFACE_DISPLAY_OUTPUT_SURFACE_H_
diff --git a/chromium/cc/surfaces/surface_display_output_surface_unittest.cc b/chromium/cc/surfaces/surface_display_output_surface_unittest.cc
new file mode 100644
index 00000000000..ed801e91474
--- /dev/null
+++ b/chromium/cc/surfaces/surface_display_output_surface_unittest.cc
@@ -0,0 +1,147 @@
+// 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.
+
+#include "cc/surfaces/surface_display_output_surface.h"
+
+#include "cc/surfaces/onscreen_display_client.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "cc/surfaces/surface_manager.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/ordered_simple_task_runner.h"
+#include "cc/test/test_context_provider.h"
+#include "cc/test/test_gpu_memory_buffer_manager.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class FakeOnscreenDisplayClient : public OnscreenDisplayClient {
+ public:
+ FakeOnscreenDisplayClient(
+ SurfaceManager* manager,
+ SharedBitmapManager* bitmap_manager,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ const RendererSettings& settings,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : OnscreenDisplayClient(FakeOutputSurface::Create3d(),
+ manager,
+ bitmap_manager,
+ gpu_memory_buffer_manager,
+ settings,
+ task_runner) {
+ // Ownership is passed to another object later, store a pointer
+ // to it now for future reference.
+ fake_output_surface_ =
+ static_cast<FakeOutputSurface*>(output_surface_.get());
+ }
+
+ FakeOutputSurface* output_surface() { return fake_output_surface_; }
+
+ protected:
+ FakeOutputSurface* fake_output_surface_;
+};
+
+class SurfaceDisplayOutputSurfaceTest : public testing::Test {
+ public:
+ SurfaceDisplayOutputSurfaceTest()
+ : task_runner_(new OrderedSimpleTaskRunner()),
+ allocator_(0),
+ display_size_(1920, 1080),
+ display_rect_(display_size_),
+ display_client_(&surface_manager_,
+ &bitmap_manager_,
+ &gpu_memory_buffer_manager_,
+ renderer_settings_,
+ task_runner_),
+ context_provider_(TestContextProvider::Create()),
+ surface_display_output_surface_(&surface_manager_,
+ &allocator_,
+ context_provider_) {
+ output_surface_ = display_client_.output_surface();
+ display_client_.set_surface_output_surface(
+ &surface_display_output_surface_);
+ surface_display_output_surface_.set_display_client(&display_client_);
+ surface_display_output_surface_.BindToClient(
+ &surface_display_output_surface_client_);
+ display_client_.display()->Resize(display_size_);
+
+ EXPECT_FALSE(surface_display_output_surface_client_
+ .did_lose_output_surface_called());
+ }
+
+ ~SurfaceDisplayOutputSurfaceTest() override {}
+
+ void SwapBuffersWithDamage(const gfx::Rect& damage_rect_) {
+ scoped_ptr<RenderPass> render_pass(RenderPass::Create());
+ render_pass->SetNew(RenderPassId(1, 1), display_rect_, damage_rect_,
+ gfx::Transform());
+
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+ frame_data->render_pass_list.push_back(render_pass.Pass());
+
+ CompositorFrame frame;
+ frame.delegated_frame_data = frame_data.Pass();
+
+ surface_display_output_surface_.SwapBuffers(&frame);
+ }
+
+ void SetUp() override {
+ // Draw the first frame to start in an "unlocked" state.
+ SwapBuffersWithDamage(display_rect_);
+
+ EXPECT_EQ(0u, output_surface_->num_sent_frames());
+ task_runner_->RunUntilIdle();
+ EXPECT_EQ(1u, output_surface_->num_sent_frames());
+ }
+
+ protected:
+ scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
+ SurfaceIdAllocator allocator_;
+
+ const gfx::Size display_size_;
+ const gfx::Rect display_rect_;
+ FakeOutputSurface* output_surface_;
+ SurfaceManager surface_manager_;
+ TestSharedBitmapManager bitmap_manager_;
+ TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
+ RendererSettings renderer_settings_;
+ FakeOnscreenDisplayClient display_client_;
+
+ scoped_refptr<TestContextProvider> context_provider_;
+
+ FakeOutputSurfaceClient surface_display_output_surface_client_;
+ SurfaceDisplayOutputSurface surface_display_output_surface_;
+};
+
+TEST_F(SurfaceDisplayOutputSurfaceTest, DamageTriggersSwapBuffers) {
+ SwapBuffersWithDamage(display_rect_);
+ EXPECT_EQ(1u, output_surface_->num_sent_frames());
+ task_runner_->RunUntilIdle();
+ EXPECT_EQ(2u, output_surface_->num_sent_frames());
+}
+
+TEST_F(SurfaceDisplayOutputSurfaceTest, NoDamageDoesNotTriggerSwapBuffers) {
+ SwapBuffersWithDamage(gfx::Rect());
+ EXPECT_EQ(1u, output_surface_->num_sent_frames());
+ task_runner_->RunUntilIdle();
+ EXPECT_EQ(1u, output_surface_->num_sent_frames());
+}
+
+TEST_F(SurfaceDisplayOutputSurfaceTest,
+ LockingResourcesDoesNotIndirectlyCauseDamage) {
+ surface_display_output_surface_.ForceReclaimResources();
+ EXPECT_EQ(1u, output_surface_->num_sent_frames());
+ task_runner_->RunPendingTasks();
+ EXPECT_EQ(1u, output_surface_->num_sent_frames());
+
+ SwapBuffersWithDamage(gfx::Rect());
+ EXPECT_EQ(1u, output_surface_->num_sent_frames());
+ task_runner_->RunUntilIdle();
+ EXPECT_EQ(1u, output_surface_->num_sent_frames());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/surfaces/surface_factory.cc b/chromium/cc/surfaces/surface_factory.cc
index 574f5d1faea..9bb50ace4c2 100644
--- a/chromium/cc/surfaces/surface_factory.cc
+++ b/chromium/cc/surfaces/surface_factory.cc
@@ -13,7 +13,10 @@
namespace cc {
SurfaceFactory::SurfaceFactory(SurfaceManager* manager,
SurfaceFactoryClient* client)
- : manager_(manager), client_(client), holder_(client) {
+ : manager_(manager),
+ client_(client),
+ holder_(client),
+ needs_sync_points_(true) {
}
SurfaceFactory::~SurfaceFactory() {
@@ -30,8 +33,8 @@ void SurfaceFactory::DestroyAll() {
surface_map_.clear();
}
-void SurfaceFactory::Create(SurfaceId surface_id, const gfx::Size& size) {
- scoped_ptr<Surface> surface(new Surface(surface_id, size, this));
+void SurfaceFactory::Create(SurfaceId surface_id) {
+ scoped_ptr<Surface> surface(new Surface(surface_id, this));
manager_->RegisterSurface(surface.get());
DCHECK(!surface_map_.count(surface_id));
surface_map_.add(surface_id, surface.Pass());
@@ -46,12 +49,13 @@ void SurfaceFactory::Destroy(SurfaceId surface_id) {
void SurfaceFactory::SubmitFrame(SurfaceId surface_id,
scoped_ptr<CompositorFrame> frame,
- const base::Closure& callback) {
+ const DrawCallback& callback) {
OwningSurfaceMap::iterator it = surface_map_.find(surface_id);
DCHECK(it != surface_map_.end());
DCHECK(it->second->factory().get() == this);
it->second->QueueFrame(frame.Pass(), callback);
- manager_->SurfaceModified(surface_id);
+ if (!manager_->SurfaceModified(surface_id))
+ it->second->RunDrawCallbacks(SurfaceDrawStatus::DRAW_SKIPPED);
}
void SurfaceFactory::RequestCopyOfSurface(
diff --git a/chromium/cc/surfaces/surface_factory.h b/chromium/cc/surfaces/surface_factory.h
index 8e9211c57b3..0e812de5e23 100644
--- a/chromium/cc/surfaces/surface_factory.h
+++ b/chromium/cc/surfaces/surface_factory.h
@@ -27,6 +27,8 @@ class Surface;
class SurfaceFactoryClient;
class SurfaceManager;
+enum class SurfaceDrawStatus { DRAW_SKIPPED, DRAWN };
+
// A SurfaceFactory is used to create surfaces that may share resources and
// receive returned resources for frames submitted to those surfaces. Resources
// submitted to frames created by a particular factory will be returned to that
@@ -35,18 +37,21 @@ class SurfaceManager;
class CC_SURFACES_EXPORT SurfaceFactory
: public base::SupportsWeakPtr<SurfaceFactory> {
public:
+ using DrawCallback = base::Callback<void(SurfaceDrawStatus)>;
+
SurfaceFactory(SurfaceManager* manager, SurfaceFactoryClient* client);
~SurfaceFactory();
- void Create(SurfaceId surface_id, const gfx::Size& size);
+ void Create(SurfaceId surface_id);
void Destroy(SurfaceId surface_id);
void DestroyAll();
// A frame can only be submitted to a surface created by this factory,
// although the frame may reference surfaces created by other factories.
- // The callback is called the first time this frame is used to draw.
+ // The callback is called the first time this frame is used to draw, or if
+ // the frame is discarded.
void SubmitFrame(SurfaceId surface_id,
scoped_ptr<CompositorFrame> frame,
- const base::Closure& callback);
+ const DrawCallback& callback);
void RequestCopyOfSurface(SurfaceId surface_id,
scoped_ptr<CopyOutputRequest> copy_request);
@@ -58,13 +63,22 @@ class CC_SURFACES_EXPORT SurfaceFactory
SurfaceManager* manager() { return manager_; }
+ // This can be set to false if resources from this SurfaceFactory don't need
+ // to have sync points set on them when returned from the Display, for
+ // example if the Display shares a context with the creator.
+ bool needs_sync_points() const { return needs_sync_points_; }
+ void set_needs_sync_points(bool needs) { needs_sync_points_ = needs; }
+
private:
SurfaceManager* manager_;
SurfaceFactoryClient* client_;
SurfaceResourceHolder holder_;
- typedef base::ScopedPtrHashMap<SurfaceId, Surface> OwningSurfaceMap;
- base::ScopedPtrHashMap<SurfaceId, Surface> surface_map_;
+ bool needs_sync_points_;
+
+ typedef base::ScopedPtrHashMap<SurfaceId, scoped_ptr<Surface>>
+ OwningSurfaceMap;
+ OwningSurfaceMap surface_map_;
DISALLOW_COPY_AND_ASSIGN(SurfaceFactory);
};
diff --git a/chromium/cc/surfaces/surface_factory_unittest.cc b/chromium/cc/surfaces/surface_factory_unittest.cc
index 14a25fdf71a..b9c6bf5c207 100644
--- a/chromium/cc/surfaces/surface_factory_unittest.cc
+++ b/chromium/cc/surfaces/surface_factory_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/bind.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/delegated_frame_data.h"
#include "cc/surfaces/surface.h"
@@ -39,10 +40,10 @@ class TestSurfaceFactoryClient : public SurfaceFactoryClient {
class SurfaceFactoryTest : public testing::Test {
public:
SurfaceFactoryTest() : factory_(&manager_, &client_), surface_id_(3) {
- factory_.Create(surface_id_, gfx::Size(5, 5));
+ factory_.Create(surface_id_);
}
- virtual ~SurfaceFactoryTest() {
+ ~SurfaceFactoryTest() override {
if (!surface_id_.is_null())
factory_.Destroy(surface_id_);
}
@@ -58,7 +59,8 @@ class SurfaceFactoryTest : public testing::Test {
}
scoped_ptr<CompositorFrame> frame(new CompositorFrame);
frame->delegated_frame_data = frame_data.Pass();
- factory_.SubmitFrame(surface_id_, frame.Pass(), base::Closure());
+ factory_.SubmitFrame(surface_id_, frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
void UnrefResources(ResourceProvider::ResourceId* ids_to_unref,
@@ -358,10 +360,32 @@ TEST_F(SurfaceFactoryTest, ResourceLifetime) {
}
}
+TEST_F(SurfaceFactoryTest, BlankNoIndexIncrement) {
+ SurfaceId surface_id(6);
+ factory_.Create(surface_id);
+ Surface* surface = manager_.GetSurfaceForId(surface_id);
+ ASSERT_NE(nullptr, surface);
+ EXPECT_EQ(2, surface->frame_index());
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data.reset(new DelegatedFrameData);
+
+ factory_.SubmitFrame(surface_id, frame.Pass(),
+ SurfaceFactory::DrawCallback());
+ EXPECT_EQ(2, surface->frame_index());
+ factory_.Destroy(surface_id);
+}
+
+void DrawCallback(uint32* execute_count,
+ SurfaceDrawStatus* result,
+ SurfaceDrawStatus drawn) {
+ *execute_count += 1;
+ *result = drawn;
+}
+
// Tests doing a DestroyAll before shutting down the factory;
TEST_F(SurfaceFactoryTest, DestroyAll) {
SurfaceId id(7);
- factory_.Create(id, gfx::Size(1, 1));
+ factory_.Create(id);
scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
TransferableResource resource;
@@ -370,15 +394,21 @@ TEST_F(SurfaceFactoryTest, DestroyAll) {
frame_data->resource_list.push_back(resource);
scoped_ptr<CompositorFrame> frame(new CompositorFrame);
frame->delegated_frame_data = frame_data.Pass();
- factory_.SubmitFrame(id, frame.Pass(), base::Closure());
+ uint32 execute_count = 0;
+ SurfaceDrawStatus drawn = SurfaceDrawStatus::DRAW_SKIPPED;
+
+ factory_.SubmitFrame(id, frame.Pass(),
+ base::Bind(&DrawCallback, &execute_count, &drawn));
surface_id_ = SurfaceId();
factory_.DestroyAll();
+ EXPECT_EQ(1u, execute_count);
+ EXPECT_EQ(SurfaceDrawStatus::DRAW_SKIPPED, drawn);
}
TEST_F(SurfaceFactoryTest, DestroySequence) {
SurfaceId id2(5);
- factory_.Create(id2, gfx::Size(5, 5));
+ factory_.Create(id2);
// Check that waiting before the sequence is satisfied works.
manager_.GetSurfaceForId(id2)
@@ -391,11 +421,12 @@ TEST_F(SurfaceFactoryTest, DestroySequence) {
frame->metadata.satisfies_sequences.push_back(4);
frame->delegated_frame_data = frame_data.Pass();
DCHECK(manager_.GetSurfaceForId(id2));
- factory_.SubmitFrame(surface_id_, frame.Pass(), base::Closure());
+ factory_.SubmitFrame(surface_id_, frame.Pass(),
+ SurfaceFactory::DrawCallback());
DCHECK(!manager_.GetSurfaceForId(id2));
// Check that waiting after the sequence is satisfied works.
- factory_.Create(id2, gfx::Size(5, 5));
+ factory_.Create(id2);
DCHECK(manager_.GetSurfaceForId(id2));
manager_.GetSurfaceForId(id2)
->AddDestructionDependency(SurfaceSequence(0, 6));
diff --git a/chromium/cc/surfaces/surface_manager.cc b/chromium/cc/surfaces/surface_manager.cc
index 050f04b062a..117d82ab659 100644
--- a/chromium/cc/surfaces/surface_manager.cc
+++ b/chromium/cc/surfaces/surface_manager.cc
@@ -78,10 +78,12 @@ Surface* SurfaceManager::GetSurfaceForId(SurfaceId surface_id) {
return it->second;
}
-void SurfaceManager::SurfaceModified(SurfaceId surface_id) {
+bool SurfaceManager::SurfaceModified(SurfaceId surface_id) {
DCHECK(thread_checker_.CalledOnValidThread());
- FOR_EACH_OBSERVER(
- SurfaceDamageObserver, observer_list_, OnSurfaceDamaged(surface_id));
+ bool changed = false;
+ FOR_EACH_OBSERVER(SurfaceDamageObserver, observer_list_,
+ OnSurfaceDamaged(surface_id, &changed));
+ return changed;
}
} // namespace cc
diff --git a/chromium/cc/surfaces/surface_manager.h b/chromium/cc/surfaces/surface_manager.h
index d6303523b48..d7d78c42e28 100644
--- a/chromium/cc/surfaces/surface_manager.h
+++ b/chromium/cc/surfaces/surface_manager.h
@@ -42,7 +42,7 @@ class CC_SURFACES_EXPORT SurfaceManager {
observer_list_.RemoveObserver(obs);
}
- void SurfaceModified(SurfaceId surface_id);
+ bool SurfaceModified(SurfaceId surface_id);
// A frame for a surface satisfies a set of sequence numbers in a particular
// id namespace.
diff --git a/chromium/cc/surfaces/surface_unittest.cc b/chromium/cc/surfaces/surface_unittest.cc
index b8990c5590c..42fd55f4a03 100644
--- a/chromium/cc/surfaces/surface_unittest.cc
+++ b/chromium/cc/surfaces/surface_unittest.cc
@@ -17,8 +17,8 @@ TEST(SurfaceTest, SurfaceLifetime) {
SurfaceId surface_id(6);
{
- factory.Create(surface_id, gfx::Size(5, 5));
- EXPECT_TRUE(!!manager.GetSurfaceForId(surface_id));
+ factory.Create(surface_id);
+ EXPECT_TRUE(manager.GetSurfaceForId(surface_id));
factory.Destroy(surface_id);
}
diff --git a/chromium/cc/surfaces/surfaces_pixeltest.cc b/chromium/cc/surfaces/surfaces_pixeltest.cc
index c70028b7281..528684b2c85 100644
--- a/chromium/cc/surfaces/surfaces_pixeltest.cc
+++ b/chromium/cc/surfaces/surfaces_pixeltest.cc
@@ -85,8 +85,9 @@ TEST_F(SurfacesPixelTest, DrawSimpleFrame) {
root_frame->delegated_frame_data = delegated_frame_data.Pass();
SurfaceId root_surface_id = allocator_.GenerateId();
- factory_.Create(root_surface_id, device_viewport_size_);
- factory_.SubmitFrame(root_surface_id, root_frame.Pass(), base::Closure());
+ factory_.Create(root_surface_id);
+ factory_.SubmitFrame(root_surface_id, root_frame.Pass(),
+ SurfaceFactory::DrawCallback());
SurfaceAggregator aggregator(&manager_, resource_provider_.get());
scoped_ptr<CompositorFrame> aggregated_frame =
@@ -107,8 +108,8 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) {
gfx::Size child_size(200, 100);
SurfaceId child_surface_id = allocator_.GenerateId();
SurfaceId root_surface_id = allocator_.GenerateId();
- factory_.Create(child_surface_id, child_size);
- factory_.Create(root_surface_id, device_viewport_size_);
+ factory_.Create(child_surface_id);
+ factory_.Create(root_surface_id);
{
gfx::Rect rect(device_viewport_size_);
RenderPassId id(1, 1);
@@ -140,7 +141,8 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) {
scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
root_frame->delegated_frame_data = delegated_frame_data.Pass();
- factory_.SubmitFrame(root_surface_id, root_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(root_surface_id, root_frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
{
@@ -167,7 +169,8 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) {
scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
child_frame->delegated_frame_data = delegated_frame_data.Pass();
- factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(child_surface_id, child_frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
SurfaceAggregator aggregator(&manager_, resource_provider_.get());
@@ -199,9 +202,9 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
SurfaceId left_child_id = allocator_.GenerateId();
SurfaceId right_child_id = allocator_.GenerateId();
SurfaceId root_surface_id = allocator_.GenerateId();
- factory_.Create(left_child_id, child_size);
- factory_.Create(right_child_id, child_size);
- factory_.Create(root_surface_id, device_viewport_size_);
+ factory_.Create(left_child_id);
+ factory_.Create(right_child_id);
+ factory_.Create(root_surface_id);
{
gfx::Rect rect(device_viewport_size_);
@@ -237,7 +240,8 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
root_frame->delegated_frame_data = delegated_frame_data.Pass();
- factory_.SubmitFrame(root_surface_id, root_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(root_surface_id, root_frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
{
@@ -272,7 +276,8 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
child_frame->delegated_frame_data = delegated_frame_data.Pass();
- factory_.SubmitFrame(left_child_id, child_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(left_child_id, child_frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
{
@@ -307,7 +312,8 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
child_frame->delegated_frame_data = delegated_frame_data.Pass();
- factory_.SubmitFrame(right_child_id, child_frame.Pass(), base::Closure());
+ factory_.SubmitFrame(right_child_id, child_frame.Pass(),
+ SurfaceFactory::DrawCallback());
}
SurfaceAggregator aggregator(&manager_, resource_provider_.get());
diff --git a/chromium/cc/tiles/eviction_tile_priority_queue.cc b/chromium/cc/tiles/eviction_tile_priority_queue.cc
new file mode 100644
index 00000000000..fb27448c2be
--- /dev/null
+++ b/chromium/cc/tiles/eviction_tile_priority_queue.cc
@@ -0,0 +1,161 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/tiles/eviction_tile_priority_queue.h"
+
+namespace cc {
+
+namespace {
+
+class EvictionOrderComparator {
+ public:
+ explicit EvictionOrderComparator(TreePriority tree_priority)
+ : tree_priority_(tree_priority) {}
+
+ bool operator()(const TilingSetEvictionQueue* a_queue,
+ const TilingSetEvictionQueue* b_queue) const {
+ // Note that in this function, we have to return true if and only if
+ // b is strictly lower priority than a.
+ const PrioritizedTile& a_tile = a_queue->Top();
+ const PrioritizedTile& b_tile = b_queue->Top();
+
+ const TilePriority& a_priority = a_tile.priority();
+ const TilePriority& b_priority = b_tile.priority();
+ bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY;
+
+ // If the priority bin differs, b is lower priority if it has the higher
+ // priority bin.
+ if (a_priority.priority_bin != b_priority.priority_bin)
+ return b_priority.priority_bin > a_priority.priority_bin;
+
+ // Otherwise if the resolution differs, then the order will be determined by
+ // whether we prioritize low res or not.
+ // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile
+ // class but instead produced by the iterators.
+ if (b_priority.resolution != a_priority.resolution) {
+ // Non ideal resolution should be sorted higher than other resolutions.
+ if (a_priority.resolution == NON_IDEAL_RESOLUTION)
+ return false;
+
+ if (b_priority.resolution == NON_IDEAL_RESOLUTION)
+ return true;
+
+ if (prioritize_low_res)
+ return a_priority.resolution == LOW_RESOLUTION;
+ return a_priority.resolution == HIGH_RESOLUTION;
+ }
+
+ // Otherwise if the occlusion differs, b is lower priority if it is
+ // occluded.
+ bool a_is_occluded = a_tile.is_occluded();
+ bool b_is_occluded = b_tile.is_occluded();
+ if (a_is_occluded != b_is_occluded)
+ return b_is_occluded;
+
+ // b is lower priorty if it is farther from visible.
+ return b_priority.distance_to_visible > a_priority.distance_to_visible;
+ }
+
+ private:
+ TreePriority tree_priority_;
+};
+
+void CreateTilingSetEvictionQueues(
+ const std::vector<PictureLayerImpl*>& layers,
+ TreePriority tree_priority,
+ ScopedPtrVector<TilingSetEvictionQueue>* queues) {
+ DCHECK(queues->empty());
+
+ for (auto* layer : layers) {
+ scoped_ptr<TilingSetEvictionQueue> tiling_set_queue = make_scoped_ptr(
+ new TilingSetEvictionQueue(layer->picture_layer_tiling_set()));
+ // Queues will only contain non empty tiling sets.
+ if (!tiling_set_queue->IsEmpty())
+ queues->push_back(tiling_set_queue.Pass());
+ }
+ queues->make_heap(EvictionOrderComparator(tree_priority));
+}
+
+} // namespace
+
+EvictionTilePriorityQueue::EvictionTilePriorityQueue() {
+}
+
+EvictionTilePriorityQueue::~EvictionTilePriorityQueue() {
+}
+
+void EvictionTilePriorityQueue::Build(
+ const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers,
+ TreePriority tree_priority) {
+ tree_priority_ = tree_priority;
+
+ CreateTilingSetEvictionQueues(active_layers, tree_priority, &active_queues_);
+ CreateTilingSetEvictionQueues(pending_layers, tree_priority,
+ &pending_queues_);
+}
+
+bool EvictionTilePriorityQueue::IsEmpty() const {
+ return active_queues_.empty() && pending_queues_.empty();
+}
+
+const PrioritizedTile& EvictionTilePriorityQueue::Top() const {
+ DCHECK(!IsEmpty());
+ const ScopedPtrVector<TilingSetEvictionQueue>& next_queues = GetNextQueues();
+ return next_queues.front()->Top();
+}
+
+void EvictionTilePriorityQueue::Pop() {
+ DCHECK(!IsEmpty());
+
+ ScopedPtrVector<TilingSetEvictionQueue>& next_queues = GetNextQueues();
+ next_queues.pop_heap(EvictionOrderComparator(tree_priority_));
+ TilingSetEvictionQueue* queue = next_queues.back();
+ queue->Pop();
+
+ // Remove empty queues.
+ if (queue->IsEmpty())
+ next_queues.pop_back();
+ else
+ next_queues.push_heap(EvictionOrderComparator(tree_priority_));
+}
+
+ScopedPtrVector<TilingSetEvictionQueue>&
+EvictionTilePriorityQueue::GetNextQueues() {
+ return const_cast<ScopedPtrVector<TilingSetEvictionQueue>&>(
+ static_cast<const EvictionTilePriorityQueue*>(this)->GetNextQueues());
+}
+
+const ScopedPtrVector<TilingSetEvictionQueue>&
+EvictionTilePriorityQueue::GetNextQueues() const {
+ DCHECK(!IsEmpty());
+
+ // If we only have one queue with tiles, return it.
+ if (active_queues_.empty())
+ return pending_queues_;
+ if (pending_queues_.empty())
+ return active_queues_;
+
+ const PrioritizedTile& active_tile = active_queues_.front()->Top();
+ const PrioritizedTile& pending_tile = pending_queues_.front()->Top();
+
+ const TilePriority& active_priority = active_tile.priority();
+ const TilePriority& pending_priority = pending_tile.priority();
+
+ // If the bins are the same and activation differs, then return the tree of
+ // the tile not required for activation.
+ if (active_priority.priority_bin == pending_priority.priority_bin &&
+ active_tile.tile()->required_for_activation() !=
+ pending_tile.tile()->required_for_activation()) {
+ return active_tile.tile()->required_for_activation() ? pending_queues_
+ : active_queues_;
+ }
+
+ // Return tile with a lower priority.
+ if (pending_priority.IsHigherPriorityThan(active_priority))
+ return active_queues_;
+ return pending_queues_;
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/eviction_tile_priority_queue.h b/chromium/cc/tiles/eviction_tile_priority_queue.h
new file mode 100644
index 00000000000..e7610260508
--- /dev/null
+++ b/chromium/cc/tiles/eviction_tile_priority_queue.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TILES_EVICTION_TILE_PRIORITY_QUEUE_H_
+#define CC_TILES_EVICTION_TILE_PRIORITY_QUEUE_H_
+
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "cc/base/cc_export.h"
+#include "cc/layers/picture_layer_impl.h"
+#include "cc/tiles/tile_priority.h"
+#include "cc/tiles/tiling_set_eviction_queue.h"
+
+namespace cc {
+class PrioritizedTile;
+
+class CC_EXPORT EvictionTilePriorityQueue {
+ public:
+ EvictionTilePriorityQueue();
+ ~EvictionTilePriorityQueue();
+
+ void Build(const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers,
+ TreePriority tree_priority);
+
+ bool IsEmpty() const;
+ const PrioritizedTile& Top() const;
+ void Pop();
+
+ private:
+ ScopedPtrVector<TilingSetEvictionQueue>& GetNextQueues();
+ const ScopedPtrVector<TilingSetEvictionQueue>& GetNextQueues() const;
+
+ ScopedPtrVector<TilingSetEvictionQueue> active_queues_;
+ ScopedPtrVector<TilingSetEvictionQueue> pending_queues_;
+ TreePriority tree_priority_;
+
+ DISALLOW_COPY_AND_ASSIGN(EvictionTilePriorityQueue);
+};
+
+} // namespace cc
+
+#endif // CC_TILES_EVICTION_TILE_PRIORITY_QUEUE_H_
diff --git a/chromium/cc/resources/layer_tiling_data.cc b/chromium/cc/tiles/layer_tiling_data.cc
index 63b003628c3..494ded8456d 100644
--- a/chromium/cc/resources/layer_tiling_data.cc
+++ b/chromium/cc/tiles/layer_tiling_data.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/layer_tiling_data.h"
+#include "cc/tiles/layer_tiling_data.h"
#include <vector>
diff --git a/chromium/cc/resources/layer_tiling_data.h b/chromium/cc/tiles/layer_tiling_data.h
index 51681184bbd..5e944a569bf 100644
--- a/chromium/cc/resources/layer_tiling_data.h
+++ b/chromium/cc/tiles/layer_tiling_data.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_LAYER_TILING_DATA_H_
-#define CC_RESOURCES_LAYER_TILING_DATA_H_
+#ifndef CC_TILES_LAYER_TILING_DATA_H_
+#define CC_TILES_LAYER_TILING_DATA_H_
#include <utility>
@@ -69,7 +69,7 @@ class CC_EXPORT LayerTilingData {
DISALLOW_COPY_AND_ASSIGN(Tile);
};
typedef std::pair<int, int> TileMapKey;
- typedef base::ScopedPtrHashMap<TileMapKey, Tile> TileMap;
+ typedef base::ScopedPtrHashMap<TileMapKey, scoped_ptr<Tile>> TileMap;
void AddTile(scoped_ptr<Tile> tile, int i, int j);
scoped_ptr<Tile> TakeTile(int i, int j);
@@ -99,4 +99,4 @@ class CC_EXPORT LayerTilingData {
} // namespace cc
-#endif // CC_RESOURCES_LAYER_TILING_DATA_H_
+#endif // CC_TILES_LAYER_TILING_DATA_H_
diff --git a/chromium/cc/tiles/picture_layer_tiling.cc b/chromium/cc/tiles/picture_layer_tiling.cc
new file mode 100644
index 00000000000..58b048bcd28
--- /dev/null
+++ b/chromium/cc/tiles/picture_layer_tiling.cc
@@ -0,0 +1,1087 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/tiles/picture_layer_tiling.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <set>
+
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/base/math_util.h"
+#include "cc/playback/raster_source.h"
+#include "cc/tiles/prioritized_tile.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_priority.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
+
+namespace cc {
+namespace {
+
+const float kSoonBorderDistanceViewportPercentage = 0.15f;
+const float kMaxSoonBorderDistanceInScreenPixels = 312.f;
+
+} // namespace
+
+scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
+ WhichTree tree,
+ float contents_scale,
+ scoped_refptr<RasterSource> raster_source,
+ PictureLayerTilingClient* client,
+ float tiling_interest_area_viewport_multiplier,
+ float skewport_target_time_in_seconds,
+ int skewport_extrapolation_limit_in_content_pixels) {
+ return make_scoped_ptr(new PictureLayerTiling(
+ tree, contents_scale, raster_source, client,
+ tiling_interest_area_viewport_multiplier, skewport_target_time_in_seconds,
+ skewport_extrapolation_limit_in_content_pixels));
+}
+
+PictureLayerTiling::PictureLayerTiling(
+ WhichTree tree,
+ float contents_scale,
+ scoped_refptr<RasterSource> raster_source,
+ PictureLayerTilingClient* client,
+ float tiling_interest_area_viewport_multiplier,
+ float skewport_target_time_in_seconds,
+ int skewport_extrapolation_limit_in_content_pixels)
+ : tiling_interest_area_viewport_multiplier_(
+ tiling_interest_area_viewport_multiplier),
+ skewport_target_time_in_seconds_(skewport_target_time_in_seconds),
+ skewport_extrapolation_limit_in_content_pixels_(
+ skewport_extrapolation_limit_in_content_pixels),
+ contents_scale_(contents_scale),
+ client_(client),
+ tree_(tree),
+ raster_source_(raster_source),
+ resolution_(NON_IDEAL_RESOLUTION),
+ tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels),
+ can_require_tiles_for_activation_(false),
+ current_content_to_screen_scale_(0.f),
+ has_visible_rect_tiles_(false),
+ has_skewport_rect_tiles_(false),
+ has_soon_border_rect_tiles_(false),
+ has_eventually_rect_tiles_(false) {
+ DCHECK(!raster_source->IsSolidColor());
+ gfx::Size content_bounds = gfx::ToCeiledSize(
+ gfx::ScaleSize(raster_source_->GetSize(), contents_scale));
+ gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
+
+ DCHECK(!gfx::ToFlooredSize(gfx::ScaleSize(raster_source_->GetSize(),
+ contents_scale)).IsEmpty())
+ << "Tiling created with scale too small as contents become empty."
+ << " Layer bounds: " << raster_source_->GetSize().ToString()
+ << " Contents scale: " << contents_scale;
+
+ tiling_data_.SetTilingSize(content_bounds);
+ tiling_data_.SetMaxTextureSize(tile_size);
+}
+
+PictureLayerTiling::~PictureLayerTiling() {
+}
+
+// static
+float PictureLayerTiling::CalculateSoonBorderDistance(
+ const gfx::Rect& visible_rect_in_content_space,
+ float content_to_screen_scale) {
+ float max_dimension = std::max(visible_rect_in_content_space.width(),
+ visible_rect_in_content_space.height());
+ return std::min(
+ kMaxSoonBorderDistanceInScreenPixels / content_to_screen_scale,
+ max_dimension * kSoonBorderDistanceViewportPercentage);
+}
+
+Tile* PictureLayerTiling::CreateTile(int i, int j) {
+ TileMapKey key(i, j);
+ DCHECK(tiles_.find(key) == tiles_.end());
+
+ gfx::Rect paint_rect = tiling_data_.TileBoundsWithBorder(i, j);
+ gfx::Rect tile_rect = paint_rect;
+ tile_rect.set_size(tiling_data_.max_texture_size());
+
+ if (!raster_source_->CoversRect(tile_rect, contents_scale_))
+ return nullptr;
+
+ ScopedTilePtr tile = client_->CreateTile(contents_scale_, tile_rect);
+ Tile* raw_ptr = tile.get();
+ tile->set_tiling_index(i, j);
+ tiles_.add(key, tile.Pass());
+ return raw_ptr;
+}
+
+void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
+ bool include_borders = false;
+ for (TilingData::Iterator iter(&tiling_data_, live_tiles_rect_,
+ include_borders);
+ iter; ++iter) {
+ TileMapKey key = iter.index();
+ TileMap::iterator find = tiles_.find(key);
+ if (find != tiles_.end())
+ continue;
+
+ if (ShouldCreateTileAt(key.first, key.second))
+ CreateTile(key.first, key.second);
+ }
+ VerifyLiveTilesRect(false);
+}
+
+void PictureLayerTiling::TakeTilesAndPropertiesFrom(
+ PictureLayerTiling* pending_twin,
+ const Region& layer_invalidation) {
+ TRACE_EVENT0("cc", "TakeTilesAndPropertiesFrom");
+ SetRasterSourceAndResize(pending_twin->raster_source_);
+
+ RemoveTilesInRegion(layer_invalidation, false /* recreate tiles */);
+
+ resolution_ = pending_twin->resolution_;
+ bool create_missing_tiles = false;
+ if (live_tiles_rect_.IsEmpty()) {
+ live_tiles_rect_ = pending_twin->live_tiles_rect();
+ create_missing_tiles = true;
+ } else {
+ SetLiveTilesRect(pending_twin->live_tiles_rect());
+ }
+
+ if (tiles_.empty()) {
+ tiles_.swap(pending_twin->tiles_);
+ } else {
+ while (!pending_twin->tiles_.empty()) {
+ TileMapKey key = pending_twin->tiles_.begin()->first;
+ tiles_.set(key, pending_twin->tiles_.take_and_erase(key));
+ }
+ }
+ DCHECK(pending_twin->tiles_.empty());
+
+ if (create_missing_tiles)
+ CreateMissingTilesInLiveTilesRect();
+
+ VerifyLiveTilesRect(false);
+
+ SetTilePriorityRects(pending_twin->current_content_to_screen_scale_,
+ pending_twin->current_visible_rect_,
+ pending_twin->current_skewport_rect_,
+ pending_twin->current_soon_border_rect_,
+ pending_twin->current_eventually_rect_,
+ pending_twin->current_occlusion_in_layer_space_);
+}
+
+void PictureLayerTiling::SetRasterSourceAndResize(
+ scoped_refptr<RasterSource> raster_source) {
+ DCHECK(!raster_source->IsSolidColor());
+ gfx::Size old_layer_bounds = raster_source_->GetSize();
+ raster_source_.swap(raster_source);
+ gfx::Size new_layer_bounds = raster_source_->GetSize();
+ gfx::Size content_bounds =
+ gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
+ gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
+
+ if (tile_size != tiling_data_.max_texture_size()) {
+ tiling_data_.SetTilingSize(content_bounds);
+ tiling_data_.SetMaxTextureSize(tile_size);
+ // When the tile size changes, the TilingData positions no longer work
+ // as valid keys to the TileMap, so just drop all tiles and clear the live
+ // tiles rect.
+ Reset();
+ return;
+ }
+
+ if (old_layer_bounds == new_layer_bounds)
+ return;
+
+ // The SetLiveTilesRect() method would drop tiles outside the new bounds,
+ // but may do so incorrectly if resizing the tiling causes the number of
+ // tiles in the tiling_data_ to change.
+ gfx::Rect content_rect(content_bounds);
+ int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x());
+ int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y());
+ int before_right =
+ tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+ int before_bottom =
+ tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+
+ // The live_tiles_rect_ is clamped to stay within the tiling size as we
+ // change it.
+ live_tiles_rect_.Intersect(content_rect);
+ tiling_data_.SetTilingSize(content_bounds);
+
+ int after_right = -1;
+ int after_bottom = -1;
+ if (!live_tiles_rect_.IsEmpty()) {
+ after_right =
+ tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+ after_bottom =
+ tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+ }
+
+ // There is no recycled twin since this is run on the pending tiling
+ // during commit, and on the active tree during activate.
+ // Drop tiles outside the new layer bounds if the layer shrank.
+ for (int i = after_right + 1; i <= before_right; ++i) {
+ for (int j = before_top; j <= before_bottom; ++j)
+ RemoveTileAt(i, j);
+ }
+ for (int i = before_left; i <= after_right; ++i) {
+ for (int j = after_bottom + 1; j <= before_bottom; ++j)
+ RemoveTileAt(i, j);
+ }
+
+ if (after_right > before_right) {
+ DCHECK_EQ(after_right, before_right + 1);
+ for (int j = before_top; j <= after_bottom; ++j) {
+ if (ShouldCreateTileAt(after_right, j))
+ CreateTile(after_right, j);
+ }
+ }
+ if (after_bottom > before_bottom) {
+ DCHECK_EQ(after_bottom, before_bottom + 1);
+ for (int i = before_left; i <= before_right; ++i) {
+ if (ShouldCreateTileAt(i, after_bottom))
+ CreateTile(i, after_bottom);
+ }
+ }
+}
+
+void PictureLayerTiling::Invalidate(const Region& layer_invalidation) {
+ DCHECK_IMPLIES(tree_ == ACTIVE_TREE,
+ !client_->GetPendingOrActiveTwinTiling(this));
+ RemoveTilesInRegion(layer_invalidation, true /* recreate tiles */);
+}
+
+void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_invalidation,
+ bool recreate_tiles) {
+ // We only invalidate the active tiling when it's orphaned: it has no pending
+ // twin, so it's slated for removal in the future.
+ if (live_tiles_rect_.IsEmpty())
+ return;
+ std::vector<TileMapKey> new_tile_keys;
+ gfx::Rect expanded_live_tiles_rect =
+ tiling_data_.ExpandRectIgnoringBordersToTileBounds(live_tiles_rect_);
+ for (Region::Iterator iter(layer_invalidation); iter.has_rect();
+ iter.next()) {
+ gfx::Rect layer_rect = iter.rect();
+ gfx::Rect content_rect =
+ gfx::ScaleToEnclosingRect(layer_rect, contents_scale_);
+ // Consider tiles inside the live tiles rect even if only their border
+ // pixels intersect the invalidation. But don't consider tiles outside
+ // the live tiles rect with the same conditions, as they won't exist.
+ int border_pixels = tiling_data_.border_texels();
+ content_rect.Inset(-border_pixels, -border_pixels);
+ // Avoid needless work by not bothering to invalidate where there aren't
+ // tiles.
+ content_rect.Intersect(expanded_live_tiles_rect);
+ if (content_rect.IsEmpty())
+ continue;
+ // Since the content_rect includes border pixels already, don't include
+ // borders when iterating to avoid double counting them.
+ bool include_borders = false;
+ for (
+ TilingData::Iterator iter(&tiling_data_, content_rect, include_borders);
+ iter; ++iter) {
+ if (RemoveTileAt(iter.index_x(), iter.index_y())) {
+ if (recreate_tiles)
+ new_tile_keys.push_back(iter.index());
+ }
+ }
+ }
+
+ for (const auto& key : new_tile_keys)
+ CreateTile(key.first, key.second);
+}
+
+bool PictureLayerTiling::ShouldCreateTileAt(int i, int j) const {
+ // Active tree should always create a tile. The reason for this is that active
+ // tree represents content that we draw on screen, which means that whenever
+ // we check whether a tile should exist somewhere, the answer is yes. This
+ // doesn't mean it will actually be created (if raster source doesn't cover
+ // the tile for instance). Pending tree, on the other hand, should only be
+ // creating tiles that are different from the current active tree, which is
+ // represented by the logic in the rest of the function.
+ if (tree_ == ACTIVE_TREE)
+ return true;
+
+ // If the pending tree has no active twin, then it needs to create all tiles.
+ const PictureLayerTiling* active_twin =
+ client_->GetPendingOrActiveTwinTiling(this);
+ if (!active_twin)
+ return true;
+
+ // Pending tree will override the entire active tree if indices don't match.
+ if (!TilingMatchesTileIndices(active_twin))
+ return true;
+
+ gfx::Rect paint_rect = tiling_data_.TileBoundsWithBorder(i, j);
+ gfx::Rect tile_rect = paint_rect;
+ tile_rect.set_size(tiling_data_.max_texture_size());
+
+ // If the active tree can't create a tile, because of its raster source, then
+ // the pending tree should create one.
+ if (!active_twin->raster_source()->CoversRect(tile_rect, contents_scale()))
+ return true;
+
+ const Region* layer_invalidation = client_->GetPendingInvalidation();
+ gfx::Rect layer_rect =
+ gfx::ScaleToEnclosingRect(tile_rect, 1.f / contents_scale());
+
+ // If this tile is invalidated, then the pending tree should create one.
+ if (layer_invalidation && layer_invalidation->Intersects(layer_rect))
+ return true;
+
+ // If the active tree doesn't have a tile here, but it's in the pending tree's
+ // visible rect, then the pending tree should create a tile. This can happen
+ // if the pending visible rect is outside of the active tree's live tiles
+ // rect. In those situations, we need to block activation until we're ready to
+ // display content, which will have to come from the pending tree.
+ if (!active_twin->TileAt(i, j) && current_visible_rect_.Intersects(tile_rect))
+ return true;
+
+ // In all other cases, the pending tree doesn't need to create a tile.
+ return false;
+}
+
+bool PictureLayerTiling::TilingMatchesTileIndices(
+ const PictureLayerTiling* twin) const {
+ return tiling_data_.max_texture_size() ==
+ twin->tiling_data_.max_texture_size();
+}
+
+PictureLayerTiling::CoverageIterator::CoverageIterator()
+ : tiling_(NULL),
+ current_tile_(NULL),
+ tile_i_(0),
+ tile_j_(0),
+ left_(0),
+ top_(0),
+ right_(-1),
+ bottom_(-1) {
+}
+
+PictureLayerTiling::CoverageIterator::CoverageIterator(
+ const PictureLayerTiling* tiling,
+ float dest_scale,
+ const gfx::Rect& dest_rect)
+ : tiling_(tiling),
+ dest_rect_(dest_rect),
+ dest_to_content_scale_(0),
+ current_tile_(NULL),
+ tile_i_(0),
+ tile_j_(0),
+ left_(0),
+ top_(0),
+ right_(-1),
+ bottom_(-1) {
+ DCHECK(tiling_);
+ if (dest_rect_.IsEmpty())
+ return;
+
+ dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale;
+
+ gfx::Rect content_rect =
+ gfx::ScaleToEnclosingRect(dest_rect_,
+ dest_to_content_scale_,
+ dest_to_content_scale_);
+ // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to
+ // check for non-intersection first.
+ content_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
+ if (content_rect.IsEmpty())
+ return;
+
+ left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x());
+ top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y());
+ right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(
+ content_rect.right() - 1);
+ bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(
+ content_rect.bottom() - 1);
+
+ tile_i_ = left_ - 1;
+ tile_j_ = top_;
+ ++(*this);
+}
+
+PictureLayerTiling::CoverageIterator::~CoverageIterator() {
+}
+
+PictureLayerTiling::CoverageIterator&
+PictureLayerTiling::CoverageIterator::operator++() {
+ if (tile_j_ > bottom_)
+ return *this;
+
+ bool first_time = tile_i_ < left_;
+ bool new_row = false;
+ tile_i_++;
+ if (tile_i_ > right_) {
+ tile_i_ = left_;
+ tile_j_++;
+ new_row = true;
+ if (tile_j_ > bottom_) {
+ current_tile_ = NULL;
+ return *this;
+ }
+ }
+
+ current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
+
+ // Calculate the current geometry rect. Due to floating point rounding
+ // and ToEnclosingRect, tiles might overlap in destination space on the
+ // edges.
+ gfx::Rect last_geometry_rect = current_geometry_rect_;
+
+ gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_);
+
+ current_geometry_rect_ =
+ gfx::ScaleToEnclosingRect(content_rect,
+ 1 / dest_to_content_scale_,
+ 1 / dest_to_content_scale_);
+
+ current_geometry_rect_.Intersect(dest_rect_);
+
+ if (first_time)
+ return *this;
+
+ // Iteration happens left->right, top->bottom. Running off the bottom-right
+ // edge is handled by the intersection above with dest_rect_. Here we make
+ // sure that the new current geometry rect doesn't overlap with the last.
+ int min_left;
+ int min_top;
+ if (new_row) {
+ min_left = dest_rect_.x();
+ min_top = last_geometry_rect.bottom();
+ } else {
+ min_left = last_geometry_rect.right();
+ min_top = last_geometry_rect.y();
+ }
+
+ int inset_left = std::max(0, min_left - current_geometry_rect_.x());
+ int inset_top = std::max(0, min_top - current_geometry_rect_.y());
+ current_geometry_rect_.Inset(inset_left, inset_top, 0, 0);
+
+ if (!new_row) {
+ DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
+ DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom());
+ DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y());
+ }
+
+ return *this;
+}
+
+gfx::Rect PictureLayerTiling::CoverageIterator::geometry_rect() const {
+ return current_geometry_rect_;
+}
+
+gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const {
+ gfx::PointF tex_origin =
+ tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_).origin();
+
+ // Convert from dest space => content space => texture space.
+ gfx::RectF texture_rect(current_geometry_rect_);
+ texture_rect.Scale(dest_to_content_scale_,
+ dest_to_content_scale_);
+ texture_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
+ if (texture_rect.IsEmpty())
+ return texture_rect;
+ texture_rect.Offset(-tex_origin.OffsetFromOrigin());
+
+ return texture_rect;
+}
+
+bool PictureLayerTiling::RemoveTileAt(int i, int j) {
+ TileMap::iterator found = tiles_.find(TileMapKey(i, j));
+ if (found == tiles_.end())
+ return false;
+ tiles_.erase(found);
+ return true;
+}
+
+void PictureLayerTiling::Reset() {
+ live_tiles_rect_ = gfx::Rect();
+ tiles_.clear();
+}
+
+gfx::Rect PictureLayerTiling::ComputeSkewport(
+ double current_frame_time_in_seconds,
+ const gfx::Rect& visible_rect_in_content_space) const {
+ gfx::Rect skewport = visible_rect_in_content_space;
+ if (skewport.IsEmpty())
+ return skewport;
+
+ if (visible_rect_history_[1].frame_time_in_seconds == 0.0)
+ return skewport;
+
+ double time_delta = current_frame_time_in_seconds -
+ visible_rect_history_[1].frame_time_in_seconds;
+ if (time_delta == 0.0)
+ return skewport;
+
+ double extrapolation_multiplier =
+ skewport_target_time_in_seconds_ / time_delta;
+
+ int old_x = visible_rect_history_[1].visible_rect_in_content_space.x();
+ int old_y = visible_rect_history_[1].visible_rect_in_content_space.y();
+ int old_right =
+ visible_rect_history_[1].visible_rect_in_content_space.right();
+ int old_bottom =
+ visible_rect_history_[1].visible_rect_in_content_space.bottom();
+
+ int new_x = visible_rect_in_content_space.x();
+ int new_y = visible_rect_in_content_space.y();
+ int new_right = visible_rect_in_content_space.right();
+ int new_bottom = visible_rect_in_content_space.bottom();
+
+ // Compute the maximum skewport based on
+ // |skewport_extrapolation_limit_in_content_pixels_|.
+ gfx::Rect max_skewport = skewport;
+ max_skewport.Inset(-skewport_extrapolation_limit_in_content_pixels_,
+ -skewport_extrapolation_limit_in_content_pixels_);
+
+ // Inset the skewport by the needed adjustment.
+ skewport.Inset(extrapolation_multiplier * (new_x - old_x),
+ extrapolation_multiplier * (new_y - old_y),
+ extrapolation_multiplier * (old_right - new_right),
+ extrapolation_multiplier * (old_bottom - new_bottom));
+
+ // Ensure that visible rect is contained in the skewport.
+ skewport.Union(visible_rect_in_content_space);
+
+ // Clip the skewport to |max_skewport|. This needs to happen after the
+ // union in case intersecting would have left the empty rect.
+ skewport.Intersect(max_skewport);
+
+ // Due to limits in int's representation, it is possible that the two
+ // operations above (union and intersect) result in an empty skewport. To
+ // avoid any unpleasant situations like that, union the visible rect again to
+ // ensure that skewport.Contains(visible_rect_in_content_space) is always
+ // true.
+ skewport.Union(visible_rect_in_content_space);
+
+ return skewport;
+}
+
+bool PictureLayerTiling::ComputeTilePriorityRects(
+ const gfx::Rect& viewport_in_layer_space,
+ float ideal_contents_scale,
+ double current_frame_time_in_seconds,
+ const Occlusion& occlusion_in_layer_space) {
+ if (!NeedsUpdateForFrameAtTimeAndViewport(current_frame_time_in_seconds,
+ viewport_in_layer_space)) {
+ // This should never be zero for the purposes of has_ever_been_updated().
+ DCHECK_NE(current_frame_time_in_seconds, 0.0);
+ return false;
+ }
+ gfx::Rect visible_rect_in_content_space =
+ gfx::ScaleToEnclosingRect(viewport_in_layer_space, contents_scale_);
+
+ if (tiling_size().IsEmpty()) {
+ UpdateVisibleRectHistory(current_frame_time_in_seconds,
+ visible_rect_in_content_space);
+ last_viewport_in_layer_space_ = viewport_in_layer_space;
+ return false;
+ }
+
+ // Calculate the skewport.
+ gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds,
+ visible_rect_in_content_space);
+ DCHECK(skewport.Contains(visible_rect_in_content_space));
+
+ // Calculate the eventually/live tiles rect.
+ int64 eventually_rect_area = tiling_interest_area_viewport_multiplier_ *
+ visible_rect_in_content_space.width() *
+ visible_rect_in_content_space.height();
+
+ gfx::Rect eventually_rect =
+ ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space,
+ eventually_rect_area,
+ gfx::Rect(tiling_size()),
+ &expansion_cache_);
+
+ DCHECK(eventually_rect.IsEmpty() ||
+ gfx::Rect(tiling_size()).Contains(eventually_rect))
+ << "tiling_size: " << tiling_size().ToString()
+ << " eventually_rect: " << eventually_rect.ToString();
+
+ // Calculate the soon border rect.
+ float content_to_screen_scale = ideal_contents_scale / contents_scale_;
+ gfx::Rect soon_border_rect = visible_rect_in_content_space;
+ float border = CalculateSoonBorderDistance(visible_rect_in_content_space,
+ content_to_screen_scale);
+ soon_border_rect.Inset(-border, -border, -border, -border);
+
+ UpdateVisibleRectHistory(current_frame_time_in_seconds,
+ visible_rect_in_content_space);
+ last_viewport_in_layer_space_ = viewport_in_layer_space;
+
+ SetTilePriorityRects(content_to_screen_scale, visible_rect_in_content_space,
+ skewport, soon_border_rect, eventually_rect,
+ occlusion_in_layer_space);
+ SetLiveTilesRect(eventually_rect);
+ return true;
+}
+
+void PictureLayerTiling::SetTilePriorityRects(
+ float content_to_screen_scale,
+ const gfx::Rect& visible_rect_in_content_space,
+ const gfx::Rect& skewport,
+ const gfx::Rect& soon_border_rect,
+ const gfx::Rect& eventually_rect,
+ const Occlusion& occlusion_in_layer_space) {
+ current_visible_rect_ = visible_rect_in_content_space;
+ current_skewport_rect_ = skewport;
+ current_soon_border_rect_ = soon_border_rect;
+ current_eventually_rect_ = eventually_rect;
+ current_occlusion_in_layer_space_ = occlusion_in_layer_space;
+ current_content_to_screen_scale_ = content_to_screen_scale;
+
+ gfx::Rect tiling_rect(tiling_size());
+ has_visible_rect_tiles_ = tiling_rect.Intersects(current_visible_rect_);
+ has_skewport_rect_tiles_ = tiling_rect.Intersects(current_skewport_rect_);
+ has_soon_border_rect_tiles_ =
+ tiling_rect.Intersects(current_soon_border_rect_);
+ has_eventually_rect_tiles_ = tiling_rect.Intersects(current_eventually_rect_);
+}
+
+void PictureLayerTiling::SetLiveTilesRect(
+ const gfx::Rect& new_live_tiles_rect) {
+ DCHECK(new_live_tiles_rect.IsEmpty() ||
+ gfx::Rect(tiling_size()).Contains(new_live_tiles_rect))
+ << "tiling_size: " << tiling_size().ToString()
+ << " new_live_tiles_rect: " << new_live_tiles_rect.ToString();
+ if (live_tiles_rect_ == new_live_tiles_rect)
+ return;
+
+ // Iterate to delete all tiles outside of our new live_tiles rect.
+ for (TilingData::DifferenceIterator iter(&tiling_data_, live_tiles_rect_,
+ new_live_tiles_rect);
+ iter; ++iter) {
+ RemoveTileAt(iter.index_x(), iter.index_y());
+ }
+
+ // Iterate to allocate new tiles for all regions with newly exposed area.
+ for (TilingData::DifferenceIterator iter(&tiling_data_, new_live_tiles_rect,
+ live_tiles_rect_);
+ iter; ++iter) {
+ TileMapKey key(iter.index());
+ if (ShouldCreateTileAt(key.first, key.second))
+ CreateTile(key.first, key.second);
+ }
+
+ live_tiles_rect_ = new_live_tiles_rect;
+ VerifyLiveTilesRect(false);
+}
+
+void PictureLayerTiling::VerifyLiveTilesRect(bool is_on_recycle_tree) const {
+#if DCHECK_IS_ON()
+ for (auto it = tiles_.begin(); it != tiles_.end(); ++it) {
+ if (!it->second)
+ continue;
+ DCHECK(it->first.first < tiling_data_.num_tiles_x())
+ << this << " " << it->first.first << "," << it->first.second
+ << " num_tiles_x " << tiling_data_.num_tiles_x() << " live_tiles_rect "
+ << live_tiles_rect_.ToString();
+ DCHECK(it->first.second < tiling_data_.num_tiles_y())
+ << this << " " << it->first.first << "," << it->first.second
+ << " num_tiles_y " << tiling_data_.num_tiles_y() << " live_tiles_rect "
+ << live_tiles_rect_.ToString();
+ DCHECK(tiling_data_.TileBounds(it->first.first, it->first.second)
+ .Intersects(live_tiles_rect_))
+ << this << " " << it->first.first << "," << it->first.second
+ << " tile bounds "
+ << tiling_data_.TileBounds(it->first.first, it->first.second).ToString()
+ << " live_tiles_rect " << live_tiles_rect_.ToString();
+ }
+#endif
+}
+
+bool PictureLayerTiling::IsTileOccluded(const Tile* tile) const {
+ // If this tile is not occluded on this tree, then it is not occluded.
+ if (!IsTileOccludedOnCurrentTree(tile))
+ return false;
+
+ // Otherwise, if this is the pending tree, we're done and the tile is
+ // occluded.
+ if (tree_ == PENDING_TREE)
+ return true;
+
+ // On the active tree however, we need to check if this tile will be
+ // unoccluded upon activation, in which case it has to be considered
+ // unoccluded.
+ const PictureLayerTiling* pending_twin =
+ client_->GetPendingOrActiveTwinTiling(this);
+ if (pending_twin) {
+ // If there's a pending tile in the same position. Or if the pending twin
+ // would have to be creating all tiles, then we don't need to worry about
+ // occlusion on the twin.
+ if (!TilingMatchesTileIndices(pending_twin) ||
+ pending_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index())) {
+ return true;
+ }
+ return pending_twin->IsTileOccludedOnCurrentTree(tile);
+ }
+ return true;
+}
+
+bool PictureLayerTiling::IsTileOccludedOnCurrentTree(const Tile* tile) const {
+ if (!current_occlusion_in_layer_space_.HasOcclusion())
+ return false;
+ gfx::Rect tile_query_rect =
+ gfx::IntersectRects(tile->content_rect(), current_visible_rect_);
+ // Explicitly check if the tile is outside the viewport. If so, we need to
+ // return false, since occlusion for this tile is unknown.
+ if (tile_query_rect.IsEmpty())
+ return false;
+
+ if (contents_scale_ != 1.f) {
+ tile_query_rect =
+ gfx::ScaleToEnclosingRect(tile_query_rect, 1.f / contents_scale_);
+ }
+ return current_occlusion_in_layer_space_.IsOccluded(tile_query_rect);
+}
+
+bool PictureLayerTiling::IsTileRequiredForActivation(const Tile* tile) const {
+ if (tree_ == PENDING_TREE) {
+ if (!can_require_tiles_for_activation_)
+ return false;
+
+ if (resolution_ != HIGH_RESOLUTION)
+ return false;
+
+ if (IsTileOccluded(tile))
+ return false;
+
+ bool tile_is_visible =
+ tile->content_rect().Intersects(current_visible_rect_);
+ if (!tile_is_visible)
+ return false;
+
+ if (client_->RequiresHighResToDraw())
+ return true;
+
+ const PictureLayerTiling* active_twin =
+ client_->GetPendingOrActiveTwinTiling(this);
+ if (!active_twin || !TilingMatchesTileIndices(active_twin))
+ return true;
+
+ if (active_twin->raster_source()->GetSize() != raster_source()->GetSize())
+ return true;
+
+ if (active_twin->current_visible_rect_ != current_visible_rect_)
+ return true;
+
+ Tile* twin_tile =
+ active_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index());
+ if (!twin_tile)
+ return false;
+ return true;
+ }
+
+ DCHECK_EQ(tree_, ACTIVE_TREE);
+ const PictureLayerTiling* pending_twin =
+ client_->GetPendingOrActiveTwinTiling(this);
+ // If we don't have a pending tree, or the pending tree will overwrite the
+ // given tile, then it is not required for activation.
+ if (!pending_twin || !TilingMatchesTileIndices(pending_twin) ||
+ pending_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index())) {
+ return false;
+ }
+ // Otherwise, ask the pending twin if this tile is required for activation.
+ return pending_twin->IsTileRequiredForActivation(tile);
+}
+
+bool PictureLayerTiling::IsTileRequiredForDraw(const Tile* tile) const {
+ if (tree_ == PENDING_TREE)
+ return false;
+
+ if (resolution_ != HIGH_RESOLUTION)
+ return false;
+
+ bool tile_is_visible = current_visible_rect_.Intersects(tile->content_rect());
+ if (!tile_is_visible)
+ return false;
+
+ if (IsTileOccludedOnCurrentTree(tile))
+ return false;
+ return true;
+}
+
+void PictureLayerTiling::UpdateRequiredStatesOnTile(Tile* tile) const {
+ DCHECK(tile);
+ tile->set_required_for_activation(IsTileRequiredForActivation(tile));
+ tile->set_required_for_draw(IsTileRequiredForDraw(tile));
+}
+
+PrioritizedTile PictureLayerTiling::MakePrioritizedTile(
+ Tile* tile,
+ PriorityRectType priority_rect_type) const {
+ DCHECK(tile);
+ DCHECK(
+ raster_source()->CoversRect(tile->content_rect(), tile->contents_scale()))
+ << "Recording rect: "
+ << gfx::ScaleToEnclosingRect(tile->content_rect(),
+ 1.f / tile->contents_scale()).ToString();
+
+ return PrioritizedTile(tile, raster_source(),
+ ComputePriorityForTile(tile, priority_rect_type),
+ IsTileOccluded(tile));
+}
+
+std::map<const Tile*, PrioritizedTile>
+PictureLayerTiling::UpdateAndGetAllPrioritizedTilesForTesting() const {
+ std::map<const Tile*, PrioritizedTile> result;
+ for (const auto& key_tile_pair : tiles_) {
+ Tile* tile = key_tile_pair.second;
+ UpdateRequiredStatesOnTile(tile);
+ PrioritizedTile prioritized_tile =
+ MakePrioritizedTile(tile, ComputePriorityRectTypeForTile(tile));
+ result.insert(std::make_pair(prioritized_tile.tile(), prioritized_tile));
+ }
+ return result;
+}
+
+TilePriority PictureLayerTiling::ComputePriorityForTile(
+ const Tile* tile,
+ PriorityRectType priority_rect_type) const {
+ // TODO(vmpstr): See if this can be moved to iterators.
+ TilePriority::PriorityBin max_tile_priority_bin =
+ client_->GetMaxTilePriorityBin();
+
+ DCHECK_EQ(ComputePriorityRectTypeForTile(tile), priority_rect_type);
+ DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile);
+
+ TilePriority::PriorityBin priority_bin = max_tile_priority_bin;
+
+ switch (priority_rect_type) {
+ case VISIBLE_RECT:
+ return TilePriority(resolution_, priority_bin, 0);
+ case PENDING_VISIBLE_RECT:
+ if (max_tile_priority_bin <= TilePriority::SOON)
+ return TilePriority(resolution_, TilePriority::SOON, 0);
+ priority_bin = TilePriority::EVENTUALLY;
+ break;
+ case SKEWPORT_RECT:
+ case SOON_BORDER_RECT:
+ if (max_tile_priority_bin <= TilePriority::SOON)
+ priority_bin = TilePriority::SOON;
+ break;
+ case EVENTUALLY_RECT:
+ priority_bin = TilePriority::EVENTUALLY;
+ break;
+ }
+
+ gfx::Rect tile_bounds =
+ tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
+ DCHECK_GT(current_content_to_screen_scale_, 0.f);
+ float distance_to_visible =
+ current_visible_rect_.ManhattanInternalDistance(tile_bounds) *
+ current_content_to_screen_scale_;
+
+ return TilePriority(resolution_, priority_bin, distance_to_visible);
+}
+
+PictureLayerTiling::PriorityRectType
+PictureLayerTiling::ComputePriorityRectTypeForTile(const Tile* tile) const {
+ DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile);
+ gfx::Rect tile_bounds =
+ tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
+
+ if (current_visible_rect_.Intersects(tile_bounds))
+ return VISIBLE_RECT;
+
+ if (pending_visible_rect().Intersects(tile_bounds))
+ return PENDING_VISIBLE_RECT;
+
+ if (current_skewport_rect_.Intersects(tile_bounds))
+ return SKEWPORT_RECT;
+
+ if (current_soon_border_rect_.Intersects(tile_bounds))
+ return SOON_BORDER_RECT;
+
+ DCHECK(current_eventually_rect_.Intersects(tile_bounds));
+ return EVENTUALLY_RECT;
+}
+
+void PictureLayerTiling::GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const {
+ for (const auto& tile_pair : tiles_) {
+ Tile* tile = tile_pair.second;
+ prioritized_tiles->push_back(
+ MakePrioritizedTile(tile, ComputePriorityRectTypeForTile(tile)));
+ }
+}
+
+void PictureLayerTiling::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetInteger("num_tiles", tiles_.size());
+ state->SetDouble("content_scale", contents_scale_);
+ MathUtil::AddToTracedValue("visible_rect", current_visible_rect_, state);
+ MathUtil::AddToTracedValue("skewport_rect", current_skewport_rect_, state);
+ MathUtil::AddToTracedValue("soon_rect", current_soon_border_rect_, state);
+ MathUtil::AddToTracedValue("eventually_rect", current_eventually_rect_,
+ state);
+ MathUtil::AddToTracedValue("tiling_size", tiling_size(), state);
+}
+
+size_t PictureLayerTiling::GPUMemoryUsageInBytes() const {
+ size_t amount = 0;
+ for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+ const Tile* tile = it->second;
+ amount += tile->GPUMemoryUsageInBytes();
+ }
+ return amount;
+}
+
+PictureLayerTiling::RectExpansionCache::RectExpansionCache()
+ : previous_target(0) {
+}
+
+namespace {
+
+// This struct represents an event at which the expending rect intersects
+// one of its boundaries. 4 intersection events will occur during expansion.
+struct EdgeEvent {
+ enum { BOTTOM, TOP, LEFT, RIGHT } edge;
+ int* num_edges;
+ int distance;
+};
+
+// Compute the delta to expand from edges to cover target_area.
+int ComputeExpansionDelta(int num_x_edges, int num_y_edges,
+ int width, int height,
+ int64 target_area) {
+ // Compute coefficients for the quadratic equation:
+ // a*x^2 + b*x + c = 0
+ int a = num_y_edges * num_x_edges;
+ int b = num_y_edges * width + num_x_edges * height;
+ int64 c = static_cast<int64>(width) * height - target_area;
+
+ // Compute the delta for our edges using the quadratic equation.
+ int delta =
+ (a == 0) ? -c / b : (-b + static_cast<int>(std::sqrt(
+ static_cast<int64>(b) * b - 4.0 * a * c))) /
+ (2 * a);
+ return std::max(0, delta);
+}
+
+} // namespace
+
+gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy(
+ const gfx::Rect& starting_rect,
+ int64 target_area,
+ const gfx::Rect& bounding_rect,
+ RectExpansionCache* cache) {
+ if (starting_rect.IsEmpty())
+ return starting_rect;
+
+ if (cache &&
+ cache->previous_start == starting_rect &&
+ cache->previous_bounds == bounding_rect &&
+ cache->previous_target == target_area)
+ return cache->previous_result;
+
+ if (cache) {
+ cache->previous_start = starting_rect;
+ cache->previous_bounds = bounding_rect;
+ cache->previous_target = target_area;
+ }
+
+ DCHECK(!bounding_rect.IsEmpty());
+ DCHECK_GT(target_area, 0);
+
+ // Expand the starting rect to cover target_area, if it is smaller than it.
+ int delta = ComputeExpansionDelta(
+ 2, 2, starting_rect.width(), starting_rect.height(), target_area);
+ gfx::Rect expanded_starting_rect = starting_rect;
+ if (delta > 0)
+ expanded_starting_rect.Inset(-delta, -delta);
+
+ gfx::Rect rect = IntersectRects(expanded_starting_rect, bounding_rect);
+ if (rect.IsEmpty()) {
+ // The starting_rect and bounding_rect are far away.
+ if (cache)
+ cache->previous_result = rect;
+ return rect;
+ }
+ if (delta >= 0 && rect == expanded_starting_rect) {
+ // The starting rect already covers the entire bounding_rect and isn't too
+ // large for the target_area.
+ if (cache)
+ cache->previous_result = rect;
+ return rect;
+ }
+
+ // Continue to expand/shrink rect to let it cover target_area.
+
+ // These values will be updated by the loop and uses as the output.
+ int origin_x = rect.x();
+ int origin_y = rect.y();
+ int width = rect.width();
+ int height = rect.height();
+
+ // In the beginning we will consider 2 edges in each dimension.
+ int num_y_edges = 2;
+ int num_x_edges = 2;
+
+ // Create an event list.
+ EdgeEvent events[] = {
+ { EdgeEvent::BOTTOM, &num_y_edges, rect.y() - bounding_rect.y() },
+ { EdgeEvent::TOP, &num_y_edges, bounding_rect.bottom() - rect.bottom() },
+ { EdgeEvent::LEFT, &num_x_edges, rect.x() - bounding_rect.x() },
+ { EdgeEvent::RIGHT, &num_x_edges, bounding_rect.right() - rect.right() }
+ };
+
+ // Sort the events by distance (closest first).
+ if (events[0].distance > events[1].distance) std::swap(events[0], events[1]);
+ if (events[2].distance > events[3].distance) std::swap(events[2], events[3]);
+ if (events[0].distance > events[2].distance) std::swap(events[0], events[2]);
+ if (events[1].distance > events[3].distance) std::swap(events[1], events[3]);
+ if (events[1].distance > events[2].distance) std::swap(events[1], events[2]);
+
+ for (int event_index = 0; event_index < 4; event_index++) {
+ const EdgeEvent& event = events[event_index];
+
+ int delta = ComputeExpansionDelta(
+ num_x_edges, num_y_edges, width, height, target_area);
+
+ // Clamp delta to our event distance.
+ if (delta > event.distance)
+ delta = event.distance;
+
+ // Adjust the edge count for this kind of edge.
+ --*event.num_edges;
+
+ // Apply the delta to the edges and edge events.
+ for (int i = event_index; i < 4; i++) {
+ switch (events[i].edge) {
+ case EdgeEvent::BOTTOM:
+ origin_y -= delta;
+ height += delta;
+ break;
+ case EdgeEvent::TOP:
+ height += delta;
+ break;
+ case EdgeEvent::LEFT:
+ origin_x -= delta;
+ width += delta;
+ break;
+ case EdgeEvent::RIGHT:
+ width += delta;
+ break;
+ }
+ events[i].distance -= delta;
+ }
+
+ // If our delta is less then our event distance, we're done.
+ if (delta < event.distance)
+ break;
+ }
+
+ gfx::Rect result(origin_x, origin_y, width, height);
+ if (cache)
+ cache->previous_result = result;
+ return result;
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/picture_layer_tiling.h b/chromium/cc/tiles/picture_layer_tiling.h
index 17da548c916..8af4c4c9b30 100644
--- a/chromium/cc/resources/picture_layer_tiling.h
+++ b/chromium/cc/tiles/picture_layer_tiling.h
@@ -2,26 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_PICTURE_LAYER_TILING_H_
-#define CC_RESOURCES_PICTURE_LAYER_TILING_H_
+#ifndef CC_TILES_PICTURE_LAYER_TILING_H_
+#define CC_TILES_PICTURE_LAYER_TILING_H_
-#include <set>
+#include <map>
#include <utility>
#include <vector>
#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
+#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "cc/base/region.h"
#include "cc/base/tiling_data.h"
-#include "cc/resources/tile.h"
-#include "cc/resources/tile_priority.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_priority.h"
#include "cc/trees/occlusion.h"
#include "ui/gfx/geometry/rect.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
}
@@ -29,16 +29,15 @@ class TracedValue;
namespace cc {
class PictureLayerTiling;
-class PicturePileImpl;
+class PrioritizedTile;
+class RasterSource;
class CC_EXPORT PictureLayerTilingClient {
public:
// Create a tile at the given content_rect (in the contents scale of the
// tiling) This might return null if the client cannot create such a tile.
- virtual scoped_refptr<Tile> CreateTile(
- PictureLayerTiling* tiling,
- const gfx::Rect& content_rect) = 0;
- virtual RasterSource* GetRasterSource() = 0;
+ virtual ScopedTilePtr CreateTile(float contents_scale,
+ const gfx::Rect& content_rect) = 0;
virtual gfx::Size CalculateTileSize(
const gfx::Size& content_bounds) const = 0;
// This invalidation region defines the area (if any, it can by null) that
@@ -46,12 +45,7 @@ class CC_EXPORT PictureLayerTilingClient {
virtual const Region* GetPendingInvalidation() = 0;
virtual const PictureLayerTiling* GetPendingOrActiveTwinTiling(
const PictureLayerTiling* tiling) const = 0;
- virtual PictureLayerTiling* GetRecycledTwinTiling(
- const PictureLayerTiling* tiling) = 0;
- virtual size_t GetMaxTilesForInterestArea() const = 0;
- virtual float GetSkewportTargetTimeInSeconds() const = 0;
- virtual int GetSkewportExtrapolationLimitInContentPixels() const = 0;
- virtual WhichTree GetTree() const = 0;
+ virtual TilePriority::PriorityBin GetMaxTilePriorityBin() const = 0;
virtual bool RequiresHighResToDraw() const = 0;
protected:
@@ -62,134 +56,70 @@ class CC_EXPORT PictureLayerTiling {
public:
static const int kBorderTexels = 1;
- enum EvictionCategory {
- EVENTUALLY,
- EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION,
- SOON,
- SOON_AND_REQUIRED_FOR_ACTIVATION,
- NOW,
- NOW_AND_REQUIRED_FOR_ACTIVATION
- };
-
- class CC_EXPORT TilingRasterTileIterator {
- public:
- TilingRasterTileIterator();
- explicit TilingRasterTileIterator(PictureLayerTiling* tiling);
- ~TilingRasterTileIterator();
-
- operator bool() const { return !!current_tile_; }
- const Tile* operator*() const { return current_tile_; }
- Tile* operator*() { return current_tile_; }
- TilePriority::PriorityBin get_type() const {
- switch (phase_) {
- case VISIBLE_RECT:
- return TilePriority::NOW;
- case SKEWPORT_RECT:
- case SOON_BORDER_RECT:
- return TilePriority::SOON;
- case EVENTUALLY_RECT:
- return TilePriority::EVENTUALLY;
- }
- NOTREACHED();
- return TilePriority::EVENTUALLY;
- }
-
- TilingRasterTileIterator& operator++();
-
- private:
- enum Phase {
- VISIBLE_RECT,
- SKEWPORT_RECT,
- SOON_BORDER_RECT,
- EVENTUALLY_RECT
- };
-
- void AdvancePhase();
- bool TileNeedsRaster(Tile* tile) const {
- return tile->NeedsRaster() && !tiling_->IsTileOccluded(tile);
- }
-
- PictureLayerTiling* tiling_;
-
- Phase phase_;
-
- Tile* current_tile_;
- TilingData::Iterator visible_iterator_;
- TilingData::SpiralDifferenceIterator spiral_iterator_;
- };
-
- class CC_EXPORT TilingEvictionTileIterator {
- public:
- TilingEvictionTileIterator();
- TilingEvictionTileIterator(PictureLayerTiling* tiling,
- TreePriority tree_priority,
- EvictionCategory category);
- ~TilingEvictionTileIterator();
-
- operator bool() const;
- const Tile* operator*() const;
- Tile* operator*();
- TilingEvictionTileIterator& operator++();
-
- private:
- const std::vector<Tile*>* eviction_tiles_;
- size_t current_eviction_tiles_index_;
- };
-
+ PictureLayerTilingClient* client() const { return client_; }
~PictureLayerTiling();
- // Create a tiling with no tiles. CreateTiles must be called to add some.
+ static float CalculateSoonBorderDistance(
+ const gfx::Rect& visible_rect_in_content_space,
+ float content_to_screen_scale);
+
+ // Create a tiling with no tiles. CreateTile() must be called to add some.
static scoped_ptr<PictureLayerTiling> Create(
+ WhichTree tree,
float contents_scale,
- const gfx::Size& layer_bounds,
- PictureLayerTilingClient* client);
- gfx::Size layer_bounds() const { return layer_bounds_; }
- void UpdateTilesToCurrentPile(const Region& layer_invalidation,
- const gfx::Size& new_layer_bounds);
+ scoped_refptr<RasterSource> raster_source,
+ PictureLayerTilingClient* client,
+ float tiling_interest_area_viewport_multiplier,
+ float skewport_target_time_in_seconds,
+ int skewport_extrapolation_limit_in_content_pixels);
+
+ void SetRasterSourceAndResize(scoped_refptr<RasterSource> raster_source);
+ void Invalidate(const Region& layer_invalidation);
void CreateMissingTilesInLiveTilesRect();
- void RemoveTilesInRegion(const Region& layer_region);
+ void TakeTilesAndPropertiesFrom(PictureLayerTiling* pending_twin,
+ const Region& layer_invalidation);
+
+ bool IsTileRequiredForActivation(const Tile* tile) const;
+ bool IsTileRequiredForDraw(const Tile* tile) const;
- void SetClient(PictureLayerTilingClient* client);
void set_resolution(TileResolution resolution) { resolution_ = resolution; }
TileResolution resolution() const { return resolution_; }
void set_can_require_tiles_for_activation(bool can_require_tiles) {
can_require_tiles_for_activation_ = can_require_tiles;
}
+ RasterSource* raster_source() const { return raster_source_.get(); }
gfx::Size tiling_size() const { return tiling_data_.tiling_size(); }
gfx::Rect live_tiles_rect() const { return live_tiles_rect_; }
gfx::Size tile_size() const { return tiling_data_.max_texture_size(); }
float contents_scale() const { return contents_scale_; }
+ const TilingData* tiling_data() const { return &tiling_data_; }
Tile* TileAt(int i, int j) const {
TileMap::const_iterator iter = tiles_.find(TileMapKey(i, j));
- return (iter == tiles_.end()) ? NULL : iter->second.get();
+ return iter == tiles_.end() ? nullptr : iter->second;
}
+ bool has_tiles() const { return !tiles_.empty(); }
+
+ // For testing functionality.
void CreateAllTilesForTesting() {
SetLiveTilesRect(gfx::Rect(tiling_data_.tiling_size()));
}
-
const TilingData& TilingDataForTesting() const { return tiling_data_; }
-
std::vector<Tile*> AllTilesForTesting() const {
std::vector<Tile*> all_tiles;
for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
- all_tiles.push_back(it->second.get());
+ all_tiles.push_back(it->second);
return all_tiles;
}
- void UpdateAllTilePrioritiesForTesting() {
- for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
- UpdateTileAndTwinPriority(it->second.get());
- }
-
- std::vector<scoped_refptr<Tile>> AllRefTilesForTesting() const {
- std::vector<scoped_refptr<Tile>> all_tiles;
- for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
- all_tiles.push_back(it->second);
- return all_tiles;
+ void UpdateAllRequiredStateForTesting() {
+ for (const auto& key_tile_pair : tiles_)
+ UpdateRequiredStatesOnTile(key_tile_pair.second);
}
+ std::map<const Tile*, PrioritizedTile>
+ UpdateAndGetAllPrioritizedTilesForTesting() const;
void SetAllTilesOccludedForTesting() {
gfx::Rect viewport_in_layer_space =
@@ -199,14 +129,10 @@ class CC_EXPORT PictureLayerTiling {
SimpleEnclosedRegion(viewport_in_layer_space),
SimpleEnclosedRegion(viewport_in_layer_space));
}
-
const gfx::Rect& GetCurrentVisibleRectForTesting() const {
return current_visible_rect_;
}
- bool IsTileOccluded(const Tile* tile) const;
- bool IsTileRequiredForActivation(const Tile* tile) const;
-
// Iterate over all tiles to fill content_rect. Even if tiles are invalid
// (i.e. no valid resource) this tiling should still iterate over them.
// The union of all geometry_rect calls for each element iterated over should
@@ -224,11 +150,6 @@ class CC_EXPORT PictureLayerTiling {
gfx::Rect geometry_rect() const;
// Texture rect (in texels) for geometry_rect
gfx::RectF texture_rect() const;
- gfx::Size texture_size() const;
-
- // Full rect (including borders) of the current tile, always in the space
- // of content_rect, regardless of the contents scale of the tiling.
- gfx::Rect full_tile_geometry_rect() const;
Tile* operator->() const { return current_tile_; }
Tile* operator*() const { return current_tile_; }
@@ -258,21 +179,14 @@ class CC_EXPORT PictureLayerTiling {
void Reset();
- void ComputeTilePriorityRects(WhichTree tree,
- const gfx::Rect& viewport_in_layer_space,
+ bool ComputeTilePriorityRects(const gfx::Rect& viewport_in_layer_space,
float ideal_contents_scale,
double current_frame_time_in_seconds,
const Occlusion& occlusion_in_layer_space);
- bool NeedsUpdateForFrameAtTimeAndViewport(
- double frame_time_in_seconds,
- const gfx::Rect& viewport_in_layer_space) {
- return frame_time_in_seconds != last_impl_frame_time_in_seconds_ ||
- viewport_in_layer_space != last_viewport_in_layer_space_;
- }
-
- void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
- void AsValueInto(base::debug::TracedValue* array) const;
+ void GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const;
+ void AsValueInto(base::trace_event::TracedValue* array) const;
size_t GPUMemoryUsageInBytes() const;
struct RectExpansionCache {
@@ -291,26 +205,47 @@ class CC_EXPORT PictureLayerTiling {
const gfx::Rect& bounding_rect,
RectExpansionCache* cache);
- bool has_ever_been_updated() const {
- return last_impl_frame_time_in_seconds_ != 0.0;
- }
-
protected:
friend class CoverageIterator;
- friend class TilingRasterTileIterator;
- friend class TilingEvictionTileIterator;
+ friend class PrioritizedTile;
+ friend class TilingSetRasterQueueAll;
+ friend class TilingSetRasterQueueRequired;
+ friend class TilingSetEvictionQueue;
+
+ // PENDING VISIBLE RECT refers to the visible rect that will become current
+ // upon activation (ie, the pending tree's visible rect). Tiles in this
+ // region that are not part of the current visible rect are all handled
+ // here. Note that when processing a pending tree, this rect is the same as
+ // the visible rect so no tiles are processed in this case.
+ enum PriorityRectType {
+ VISIBLE_RECT,
+ PENDING_VISIBLE_RECT,
+ SKEWPORT_RECT,
+ SOON_BORDER_RECT,
+ EVENTUALLY_RECT
+ };
+
+ using TileMapKey = std::pair<int, int>;
+ using TileMap = base::ScopedPtrHashMap<TileMapKey, ScopedTilePtr>;
- typedef std::pair<int, int> TileMapKey;
- typedef base::hash_map<TileMapKey, scoped_refptr<Tile>> TileMap;
+ struct FrameVisibleRect {
+ gfx::Rect visible_rect_in_content_space;
+ double frame_time_in_seconds = 0.0;
+ };
- PictureLayerTiling(float contents_scale,
- const gfx::Size& layer_bounds,
- PictureLayerTilingClient* client);
+ PictureLayerTiling(WhichTree tree,
+ float contents_scale,
+ scoped_refptr<RasterSource> raster_source,
+ PictureLayerTilingClient* client,
+ float tiling_interest_area_viewport_multiplier,
+ float skewport_target_time_in_seconds,
+ int skewport_extrapolation_limit_in_content_pixels);
void SetLiveTilesRect(const gfx::Rect& live_tiles_rect);
- void VerifyLiveTilesRect();
- Tile* CreateTile(int i, int j, const PictureLayerTiling* twin_tiling);
+ void VerifyLiveTilesRect(bool is_on_recycle_tree) const;
+ Tile* CreateTile(int i, int j);
// Returns true if the Tile existed and was removed from the tiling.
- bool RemoveTileAt(int i, int j, PictureLayerTiling* recycled_twin);
+ bool RemoveTileAt(int i, int j);
+ bool TilingMatchesTileIndices(const PictureLayerTiling* twin) const;
// Computes a skewport. The calculation extrapolates the last visible
// rect and the current visible rect to expand the skewport to where it
@@ -320,63 +255,111 @@ class CC_EXPORT PictureLayerTiling {
const gfx::Rect& visible_rect_in_content_space)
const;
- void UpdateEvictionCacheIfNeeded(TreePriority tree_priority);
- const std::vector<Tile*>* GetEvictionTiles(TreePriority tree_priority,
- EvictionCategory category);
+ // Save the required data for computing tile priorities later.
+ void SetTilePriorityRects(float content_to_screen_scale_,
+ const gfx::Rect& visible_rect_in_content_space,
+ const gfx::Rect& skewport,
+ const gfx::Rect& soon_border_rect,
+ const gfx::Rect& eventually_rect,
+ const Occlusion& occlusion_in_layer_space);
- void Invalidate(const Region& layer_region);
+ bool NeedsUpdateForFrameAtTimeAndViewport(
+ double frame_time_in_seconds,
+ const gfx::Rect& viewport_in_layer_space) {
+ return frame_time_in_seconds !=
+ visible_rect_history_[0].frame_time_in_seconds ||
+ viewport_in_layer_space != last_viewport_in_layer_space_;
+ }
+ void UpdateVisibleRectHistory(
+ double frame_time_in_seconds,
+ const gfx::Rect& visible_rect_in_content_space) {
+ visible_rect_history_[1] = visible_rect_history_[0];
+ visible_rect_history_[0].frame_time_in_seconds = frame_time_in_seconds;
+ visible_rect_history_[0].visible_rect_in_content_space =
+ visible_rect_in_content_space;
+ // If we don't have a second history item, set it to the most recent one.
+ if (visible_rect_history_[1].frame_time_in_seconds == 0.0)
+ visible_rect_history_[1] = visible_rect_history_[0];
+ }
+ bool IsTileOccludedOnCurrentTree(const Tile* tile) const;
+ bool ShouldCreateTileAt(int i, int j) const;
+ bool IsTileOccluded(const Tile* tile) const;
+ void UpdateRequiredStatesOnTile(Tile* tile) const;
+ PrioritizedTile MakePrioritizedTile(
+ Tile* tile,
+ PriorityRectType priority_rect_type) const;
+ TilePriority ComputePriorityForTile(
+ const Tile* tile,
+ PriorityRectType priority_rect_type) const;
+ PriorityRectType ComputePriorityRectTypeForTile(const Tile* tile) const;
+ bool has_visible_rect_tiles() const { return has_visible_rect_tiles_; }
+ bool has_skewport_rect_tiles() const { return has_skewport_rect_tiles_; }
+ bool has_soon_border_rect_tiles() const {
+ return has_soon_border_rect_tiles_;
+ }
+ bool has_eventually_rect_tiles() const { return has_eventually_rect_tiles_; }
- void DoInvalidate(const Region& layer_region,
- bool recreate_invalidated_tiles);
+ const gfx::Rect& current_visible_rect() const {
+ return current_visible_rect_;
+ }
+ gfx::Rect pending_visible_rect() const {
+ const PictureLayerTiling* pending_tiling =
+ tree_ == ACTIVE_TREE ? client_->GetPendingOrActiveTwinTiling(this)
+ : this;
+ if (pending_tiling)
+ return pending_tiling->current_visible_rect();
+ return gfx::Rect();
+ }
+ const gfx::Rect& current_skewport_rect() const {
+ return current_skewport_rect_;
+ }
+ const gfx::Rect& current_soon_border_rect() const {
+ return current_soon_border_rect_;
+ }
+ const gfx::Rect& current_eventually_rect() const {
+ return current_eventually_rect_;
+ }
+ bool has_ever_been_updated() const {
+ return visible_rect_history_[0].frame_time_in_seconds != 0.0;
+ }
+ void RemoveTilesInRegion(const Region& layer_region, bool recreate_tiles);
- void UpdateTileAndTwinPriority(Tile* tile) const;
- void UpdateTilePriority(Tile* tile) const;
+ const float tiling_interest_area_viewport_multiplier_;
+ const float skewport_target_time_in_seconds_;
+ const int skewport_extrapolation_limit_in_content_pixels_;
// Given properties.
- float contents_scale_;
- gfx::Size layer_bounds_;
+ const float contents_scale_;
+ PictureLayerTilingClient* const client_;
+ const WhichTree tree_;
+ scoped_refptr<RasterSource> raster_source_;
TileResolution resolution_;
- PictureLayerTilingClient* client_;
// Internal data.
TilingData tiling_data_;
TileMap tiles_; // It is not legal to have a NULL tile in the tiles_ map.
gfx::Rect live_tiles_rect_;
- // State saved for computing velocities based upon finite differences.
- double last_impl_frame_time_in_seconds_;
gfx::Rect last_viewport_in_layer_space_;
- gfx::Rect last_visible_rect_in_content_space_;
- float content_to_screen_scale_;
+ // State saved for computing velocities based upon finite differences.
+ FrameVisibleRect visible_rect_history_[2];
bool can_require_tiles_for_activation_;
- // Iteration rects in content space
+ // Iteration rects in content space.
gfx::Rect current_visible_rect_;
gfx::Rect current_skewport_rect_;
gfx::Rect current_soon_border_rect_;
gfx::Rect current_eventually_rect_;
+ // Other properties used for tile iteration and prioritization.
+ float current_content_to_screen_scale_;
+ Occlusion current_occlusion_in_layer_space_;
bool has_visible_rect_tiles_;
bool has_skewport_rect_tiles_;
bool has_soon_border_rect_tiles_;
bool has_eventually_rect_tiles_;
- Occlusion current_occlusion_in_layer_space_;
-
- // TODO(reveman): Remove this in favour of an array of eviction_tiles_ when we
- // change all enums to have a consistent way of getting the count/last
- // element.
- std::vector<Tile*> eviction_tiles_now_;
- std::vector<Tile*> eviction_tiles_now_and_required_for_activation_;
- std::vector<Tile*> eviction_tiles_soon_;
- std::vector<Tile*> eviction_tiles_soon_and_required_for_activation_;
- std::vector<Tile*> eviction_tiles_eventually_;
- std::vector<Tile*> eviction_tiles_eventually_and_required_for_activation_;
-
- bool eviction_tiles_cache_valid_;
- TreePriority eviction_cache_tree_priority_;
-
private:
DISALLOW_ASSIGN(PictureLayerTiling);
@@ -385,4 +368,4 @@ class CC_EXPORT PictureLayerTiling {
} // namespace cc
-#endif // CC_RESOURCES_PICTURE_LAYER_TILING_H_
+#endif // CC_TILES_PICTURE_LAYER_TILING_H_
diff --git a/chromium/cc/tiles/picture_layer_tiling_perftest.cc b/chromium/cc/tiles/picture_layer_tiling_perftest.cc
new file mode 100644
index 00000000000..3567ecb71f6
--- /dev/null
+++ b/chromium/cc/tiles/picture_layer_tiling_perftest.cc
@@ -0,0 +1,174 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/debug/lap_timer.h"
+#include "cc/resources/resource_provider.h"
+#include "cc/resources/scoped_resource.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/fake_picture_layer_tiling_client.h"
+#include "cc/test/fake_picture_pile_impl.h"
+#include "cc/test/test_context_provider.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/tiles/picture_layer_tiling.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+
+namespace {
+
+static const int kTimeLimitMillis = 2000;
+static const int kWarmupRuns = 5;
+static const int kTimeCheckInterval = 10;
+
+class PictureLayerTilingPerfTest : public testing::Test {
+ public:
+ PictureLayerTilingPerfTest()
+ : timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval),
+ context_provider_(TestContextProvider::Create()) {
+ output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
+ CHECK(output_surface_->BindToClient(&output_surface_client_));
+
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ = ResourceProvider::Create(output_surface_.get(),
+ shared_bitmap_manager_.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1).Pass();
+ }
+
+ void SetUp() override {
+ LayerTreeSettings defaults;
+ picture_layer_tiling_client_.SetTileSize(gfx::Size(256, 256));
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ gfx::Size(256 * 50, 256 * 50));
+ picture_layer_tiling_ = PictureLayerTiling::Create(
+ PENDING_TREE, 1.f, pile, &picture_layer_tiling_client_,
+ defaults.tiling_interest_area_viewport_multiplier,
+ defaults.skewport_target_time_in_seconds,
+ defaults.skewport_extrapolation_limit_in_content_pixels);
+ picture_layer_tiling_->CreateAllTilesForTesting();
+ }
+
+ void TearDown() override { picture_layer_tiling_.reset(NULL); }
+
+ void RunInvalidateTest(const std::string& test_name, const Region& region) {
+ timer_.Reset();
+ do {
+ picture_layer_tiling_->Invalidate(region);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult(
+ "invalidation", "", test_name, timer_.LapsPerSecond(), "runs/s", true);
+ }
+
+ void RunComputeTilePriorityRectsStationaryTest(
+ const std::string& test_name,
+ const gfx::Transform& transform) {
+ gfx::Rect viewport_rect(0, 0, 1024, 768);
+
+ timer_.Reset();
+ do {
+ picture_layer_tiling_->ComputeTilePriorityRects(
+ viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion());
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("compute_tile_priority_rects_stationary",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ void RunComputeTilePriorityRectsScrollingTest(
+ const std::string& test_name,
+ const gfx::Transform& transform) {
+ gfx::Size viewport_size(1024, 768);
+ gfx::Rect viewport_rect(viewport_size);
+ int xoffsets[] = {10, 0, -10, 0};
+ int yoffsets[] = {0, 10, 0, -10};
+ int offset_index = 0;
+ int offset_count = 0;
+ const int max_offset_count = 1000;
+
+ timer_.Reset();
+ do {
+ picture_layer_tiling_->ComputeTilePriorityRects(
+ viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion());
+
+ viewport_rect = gfx::Rect(viewport_rect.x() + xoffsets[offset_index],
+ viewport_rect.y() + yoffsets[offset_index],
+ viewport_rect.width(), viewport_rect.height());
+
+ if (++offset_count > max_offset_count) {
+ offset_count = 0;
+ offset_index = (offset_index + 1) % 4;
+ }
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("compute_tile_priority_rects_scrolling",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ private:
+ FakePictureLayerTilingClient picture_layer_tiling_client_;
+ scoped_ptr<PictureLayerTiling> picture_layer_tiling_;
+
+ LapTimer timer_;
+
+ scoped_refptr<ContextProvider> context_provider_;
+ FakeOutputSurfaceClient output_surface_client_;
+ scoped_ptr<FakeOutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+};
+
+TEST_F(PictureLayerTilingPerfTest, Invalidate) {
+ Region one_tile(gfx::Rect(256, 256));
+ RunInvalidateTest("1x1", one_tile);
+
+ Region half_region(gfx::Rect(25 * 256, 50 * 256));
+ RunInvalidateTest("25x50", half_region);
+
+ Region full_region(gfx::Rect(50 * 256, 50 * 256));
+ RunInvalidateTest("50x50", full_region);
+}
+
+#if defined(OS_ANDROID)
+// TODO(vmpstr): Investigate why this is noisy (crbug.com/310220).
+TEST_F(PictureLayerTilingPerfTest, DISABLED_ComputeTilePriorityRects) {
+#else
+TEST_F(PictureLayerTilingPerfTest, ComputeTilePriorityRects) {
+#endif // defined(OS_ANDROID)
+ gfx::Transform transform;
+
+ RunComputeTilePriorityRectsStationaryTest("no_transform", transform);
+ RunComputeTilePriorityRectsScrollingTest("no_transform", transform);
+
+ transform.Rotate(10);
+ RunComputeTilePriorityRectsStationaryTest("rotation", transform);
+ RunComputeTilePriorityRectsScrollingTest("rotation", transform);
+
+ transform.ApplyPerspectiveDepth(10);
+ RunComputeTilePriorityRectsStationaryTest("perspective", transform);
+ RunComputeTilePriorityRectsScrollingTest("perspective", transform);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/tiles/picture_layer_tiling_set.cc b/chromium/cc/tiles/picture_layer_tiling_set.cc
new file mode 100644
index 00000000000..1831539a793
--- /dev/null
+++ b/chromium/cc/tiles/picture_layer_tiling_set.cc
@@ -0,0 +1,605 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/tiles/picture_layer_tiling_set.h"
+
+#include <limits>
+#include <set>
+#include <vector>
+
+#include "cc/playback/raster_source.h"
+
+namespace cc {
+
+namespace {
+
+class LargestToSmallestScaleFunctor {
+ public:
+ bool operator() (PictureLayerTiling* left, PictureLayerTiling* right) {
+ return left->contents_scale() > right->contents_scale();
+ }
+};
+
+inline float LargerRatio(float float1, float float2) {
+ DCHECK_GT(float1, 0.f);
+ DCHECK_GT(float2, 0.f);
+ return float1 > float2 ? float1 / float2 : float2 / float1;
+}
+
+} // namespace
+
+// static
+scoped_ptr<PictureLayerTilingSet> PictureLayerTilingSet::Create(
+ WhichTree tree,
+ PictureLayerTilingClient* client,
+ float tiling_interest_area_viewport_multiplier,
+ float skewport_target_time_in_seconds,
+ int skewport_extrapolation_limit_in_content_pixels) {
+ return make_scoped_ptr(new PictureLayerTilingSet(
+ tree, client, tiling_interest_area_viewport_multiplier,
+ skewport_target_time_in_seconds,
+ skewport_extrapolation_limit_in_content_pixels));
+}
+
+PictureLayerTilingSet::PictureLayerTilingSet(
+ WhichTree tree,
+ PictureLayerTilingClient* client,
+ float tiling_interest_area_viewport_multiplier,
+ float skewport_target_time_in_seconds,
+ int skewport_extrapolation_limit_in_content_pixels)
+ : tiling_interest_area_viewport_multiplier_(
+ tiling_interest_area_viewport_multiplier),
+ skewport_target_time_in_seconds_(skewport_target_time_in_seconds),
+ skewport_extrapolation_limit_in_content_pixels_(
+ skewport_extrapolation_limit_in_content_pixels),
+ tree_(tree),
+ client_(client) {
+}
+
+PictureLayerTilingSet::~PictureLayerTilingSet() {
+}
+
+void PictureLayerTilingSet::CopyTilingsAndPropertiesFromPendingTwin(
+ const PictureLayerTilingSet* pending_twin_set,
+ const scoped_refptr<RasterSource>& raster_source,
+ const Region& layer_invalidation) {
+ if (pending_twin_set->tilings_.empty()) {
+ // If the twin (pending) tiling set is empty, it was not updated for the
+ // current frame. So we drop tilings from our set as well, instead of
+ // leaving behind unshared tilings that are all non-ideal.
+ RemoveAllTilings();
+ return;
+ }
+
+ bool tiling_sort_required = false;
+ for (PictureLayerTiling* pending_twin_tiling : pending_twin_set->tilings_) {
+ float contents_scale = pending_twin_tiling->contents_scale();
+ PictureLayerTiling* this_tiling = FindTilingWithScale(contents_scale);
+ if (!this_tiling) {
+ scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
+ tree_, contents_scale, raster_source, client_,
+ tiling_interest_area_viewport_multiplier_,
+ skewport_target_time_in_seconds_,
+ skewport_extrapolation_limit_in_content_pixels_);
+ tilings_.push_back(new_tiling.Pass());
+ this_tiling = tilings_.back();
+ tiling_sort_required = true;
+ }
+ this_tiling->TakeTilesAndPropertiesFrom(pending_twin_tiling,
+ layer_invalidation);
+ }
+
+ if (tiling_sort_required)
+ tilings_.sort(LargestToSmallestScaleFunctor());
+}
+
+void PictureLayerTilingSet::UpdateTilingsToCurrentRasterSourceForActivation(
+ scoped_refptr<RasterSource> raster_source,
+ const PictureLayerTilingSet* pending_twin_set,
+ const Region& layer_invalidation,
+ float minimum_contents_scale,
+ float maximum_contents_scale) {
+ RemoveTilingsBelowScale(minimum_contents_scale);
+ RemoveTilingsAboveScale(maximum_contents_scale);
+
+ // Copy over tilings that are shared with the |pending_twin_set| tiling set.
+ // Also, copy all of the properties from twin tilings.
+ CopyTilingsAndPropertiesFromPendingTwin(pending_twin_set, raster_source,
+ layer_invalidation);
+
+ // If the tiling is not shared (FindTilingWithScale returns nullptr), then
+ // invalidate tiles and update them to the new raster source.
+ for (PictureLayerTiling* tiling : tilings_) {
+ if (pending_twin_set->FindTilingWithScale(tiling->contents_scale()))
+ continue;
+
+ tiling->SetRasterSourceAndResize(raster_source);
+ tiling->Invalidate(layer_invalidation);
+ // This is needed for cases where the live tiles rect didn't change but
+ // recordings exist in the raster source that did not exist on the last
+ // raster source.
+ tiling->CreateMissingTilesInLiveTilesRect();
+
+ // |this| is active set and |tiling| is not in the pending set, which means
+ // it is now NON_IDEAL_RESOLUTION.
+ tiling->set_resolution(NON_IDEAL_RESOLUTION);
+ }
+
+ VerifyTilings(pending_twin_set);
+}
+
+void PictureLayerTilingSet::UpdateTilingsToCurrentRasterSourceForCommit(
+ scoped_refptr<RasterSource> raster_source,
+ const Region& layer_invalidation,
+ float minimum_contents_scale,
+ float maximum_contents_scale) {
+ RemoveTilingsBelowScale(minimum_contents_scale);
+ RemoveTilingsAboveScale(maximum_contents_scale);
+
+ // Invalidate tiles and update them to the new raster source.
+ for (PictureLayerTiling* tiling : tilings_) {
+ tiling->SetRasterSourceAndResize(raster_source);
+ tiling->Invalidate(layer_invalidation);
+ // This is needed for cases where the live tiles rect didn't change but
+ // recordings exist in the raster source that did not exist on the last
+ // raster source.
+ tiling->CreateMissingTilesInLiveTilesRect();
+ }
+ VerifyTilings(nullptr /* pending_twin_set */);
+}
+
+void PictureLayerTilingSet::UpdateRasterSourceDueToLCDChange(
+ const scoped_refptr<RasterSource>& raster_source,
+ const Region& layer_invalidation) {
+ for (PictureLayerTiling* tiling : tilings_) {
+ tiling->SetRasterSourceAndResize(raster_source);
+ tiling->Invalidate(layer_invalidation);
+ // Since the invalidation changed, we need to create any missing tiles in
+ // the live tiles rect again.
+ tiling->CreateMissingTilesInLiveTilesRect();
+ }
+}
+
+void PictureLayerTilingSet::VerifyTilings(
+ const PictureLayerTilingSet* pending_twin_set) const {
+#if DCHECK_IS_ON()
+ for (PictureLayerTiling* tiling : tilings_) {
+ DCHECK(tiling->tile_size() ==
+ client_->CalculateTileSize(tiling->tiling_size()))
+ << "tile_size: " << tiling->tile_size().ToString()
+ << " tiling_size: " << tiling->tiling_size().ToString()
+ << " CalculateTileSize: "
+ << client_->CalculateTileSize(tiling->tiling_size()).ToString();
+ }
+
+ if (!tilings_.empty()) {
+ DCHECK_LE(NumHighResTilings(), 1);
+ // When commiting from the main thread the high res tiling may get dropped,
+ // but when cloning to the active tree, there should always be one.
+ if (pending_twin_set) {
+ DCHECK_EQ(1, NumHighResTilings())
+ << " num tilings on active: " << tilings_.size()
+ << " num tilings on pending: " << pending_twin_set->tilings_.size()
+ << " num high res on pending: "
+ << pending_twin_set->NumHighResTilings()
+ << " are on active tree: " << (tree_ == ACTIVE_TREE);
+ }
+ }
+#endif
+}
+
+void PictureLayerTilingSet::CleanUpTilings(
+ float min_acceptable_high_res_scale,
+ float max_acceptable_high_res_scale,
+ const std::vector<PictureLayerTiling*>& needed_tilings,
+ bool should_have_low_res,
+ PictureLayerTilingSet* twin_set,
+ PictureLayerTilingSet* recycled_twin_set) {
+ float twin_low_res_scale = 0.f;
+ if (twin_set) {
+ PictureLayerTiling* tiling =
+ twin_set->FindTilingWithResolution(LOW_RESOLUTION);
+ if (tiling)
+ twin_low_res_scale = tiling->contents_scale();
+ }
+
+ std::vector<PictureLayerTiling*> to_remove;
+ for (auto* tiling : tilings_) {
+ // Keep all tilings within the min/max scales.
+ if (tiling->contents_scale() >= min_acceptable_high_res_scale &&
+ tiling->contents_scale() <= max_acceptable_high_res_scale) {
+ continue;
+ }
+
+ // Keep low resolution tilings, if the tiling set should have them.
+ if (should_have_low_res &&
+ (tiling->resolution() == LOW_RESOLUTION ||
+ tiling->contents_scale() == twin_low_res_scale)) {
+ continue;
+ }
+
+ // Don't remove tilings that are required.
+ if (std::find(needed_tilings.begin(), needed_tilings.end(), tiling) !=
+ needed_tilings.end()) {
+ continue;
+ }
+
+ to_remove.push_back(tiling);
+ }
+
+ for (auto* tiling : to_remove) {
+ PictureLayerTiling* recycled_twin_tiling =
+ recycled_twin_set
+ ? recycled_twin_set->FindTilingWithScale(tiling->contents_scale())
+ : nullptr;
+ // Remove the tiling from the recycle tree. Note that we ignore resolution,
+ // since we don't need to maintain high/low res on the recycle set.
+ if (recycled_twin_tiling)
+ recycled_twin_set->Remove(recycled_twin_tiling);
+
+ DCHECK_NE(HIGH_RESOLUTION, tiling->resolution());
+ Remove(tiling);
+ }
+}
+
+void PictureLayerTilingSet::RemoveNonIdealTilings() {
+ auto to_remove = tilings_.remove_if([](PictureLayerTiling* t) {
+ return t->resolution() == NON_IDEAL_RESOLUTION;
+ });
+ tilings_.erase(to_remove, tilings_.end());
+}
+
+void PictureLayerTilingSet::MarkAllTilingsNonIdeal() {
+ for (auto* tiling : tilings_)
+ tiling->set_resolution(NON_IDEAL_RESOLUTION);
+}
+
+PictureLayerTiling* PictureLayerTilingSet::AddTiling(
+ float contents_scale,
+ scoped_refptr<RasterSource> raster_source) {
+ for (size_t i = 0; i < tilings_.size(); ++i) {
+ DCHECK_NE(tilings_[i]->contents_scale(), contents_scale);
+ DCHECK_EQ(tilings_[i]->raster_source(), raster_source.get());
+ }
+
+ tilings_.push_back(PictureLayerTiling::Create(
+ tree_, contents_scale, raster_source, client_,
+ tiling_interest_area_viewport_multiplier_,
+ skewport_target_time_in_seconds_,
+ skewport_extrapolation_limit_in_content_pixels_));
+ PictureLayerTiling* appended = tilings_.back();
+
+ tilings_.sort(LargestToSmallestScaleFunctor());
+ return appended;
+}
+
+int PictureLayerTilingSet::NumHighResTilings() const {
+ return std::count_if(tilings_.begin(), tilings_.end(),
+ [](PictureLayerTiling* tiling) {
+ return tiling->resolution() == HIGH_RESOLUTION;
+ });
+}
+
+PictureLayerTiling* PictureLayerTilingSet::FindTilingWithScale(
+ float scale) const {
+ for (size_t i = 0; i < tilings_.size(); ++i) {
+ if (tilings_[i]->contents_scale() == scale)
+ return tilings_[i];
+ }
+ return NULL;
+}
+
+PictureLayerTiling* PictureLayerTilingSet::FindTilingWithResolution(
+ TileResolution resolution) const {
+ auto iter = std::find_if(tilings_.begin(), tilings_.end(),
+ [resolution](const PictureLayerTiling* tiling) {
+ return tiling->resolution() == resolution;
+ });
+ if (iter == tilings_.end())
+ return NULL;
+ return *iter;
+}
+
+void PictureLayerTilingSet::RemoveTilingsBelowScale(float minimum_scale) {
+ auto to_remove =
+ tilings_.remove_if([minimum_scale](PictureLayerTiling* tiling) {
+ return tiling->contents_scale() < minimum_scale;
+ });
+ tilings_.erase(to_remove, tilings_.end());
+}
+
+void PictureLayerTilingSet::RemoveTilingsAboveScale(float maximum_scale) {
+ auto to_remove =
+ tilings_.remove_if([maximum_scale](PictureLayerTiling* tiling) {
+ return tiling->contents_scale() > maximum_scale;
+ });
+ tilings_.erase(to_remove, tilings_.end());
+}
+
+void PictureLayerTilingSet::RemoveAllTilings() {
+ tilings_.clear();
+}
+
+void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) {
+ ScopedPtrVector<PictureLayerTiling>::iterator iter =
+ std::find(tilings_.begin(), tilings_.end(), tiling);
+ if (iter == tilings_.end())
+ return;
+ tilings_.erase(iter);
+}
+
+void PictureLayerTilingSet::RemoveAllTiles() {
+ for (size_t i = 0; i < tilings_.size(); ++i)
+ tilings_[i]->Reset();
+}
+
+float PictureLayerTilingSet::GetSnappedContentsScale(
+ float start_scale,
+ float snap_to_existing_tiling_ratio) const {
+ // If a tiling exists within the max snapping ratio, snap to its scale.
+ float snapped_contents_scale = start_scale;
+ float snapped_ratio = snap_to_existing_tiling_ratio;
+ for (const auto* tiling : tilings_) {
+ float tiling_contents_scale = tiling->contents_scale();
+ float ratio = LargerRatio(tiling_contents_scale, start_scale);
+ if (ratio < snapped_ratio) {
+ snapped_contents_scale = tiling_contents_scale;
+ snapped_ratio = ratio;
+ }
+ }
+ return snapped_contents_scale;
+}
+
+float PictureLayerTilingSet::GetMaximumContentsScale() const {
+ if (tilings_.empty())
+ return 0.f;
+ // The first tiling has the largest contents scale.
+ return tilings_[0]->contents_scale();
+}
+
+bool PictureLayerTilingSet::UpdateTilePriorities(
+ const gfx::Rect& required_rect_in_layer_space,
+ float ideal_contents_scale,
+ double current_frame_time_in_seconds,
+ const Occlusion& occlusion_in_layer_space,
+ bool can_require_tiles_for_activation) {
+ bool updated = false;
+ for (auto* tiling : tilings_) {
+ tiling->set_can_require_tiles_for_activation(
+ can_require_tiles_for_activation);
+ updated |= tiling->ComputeTilePriorityRects(
+ required_rect_in_layer_space, ideal_contents_scale,
+ current_frame_time_in_seconds, occlusion_in_layer_space);
+ }
+ return updated;
+}
+
+void PictureLayerTilingSet::GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const {
+ for (auto* tiling : tilings_)
+ tiling->GetAllPrioritizedTilesForTracing(prioritized_tiles);
+}
+
+PictureLayerTilingSet::CoverageIterator::CoverageIterator(
+ const PictureLayerTilingSet* set,
+ float contents_scale,
+ const gfx::Rect& content_rect,
+ float ideal_contents_scale)
+ : set_(set),
+ contents_scale_(contents_scale),
+ ideal_contents_scale_(ideal_contents_scale),
+ current_tiling_(-1) {
+ missing_region_.Union(content_rect);
+
+ for (ideal_tiling_ = 0;
+ static_cast<size_t>(ideal_tiling_) < set_->tilings_.size();
+ ++ideal_tiling_) {
+ PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_];
+ if (tiling->contents_scale() < ideal_contents_scale_) {
+ if (ideal_tiling_ > 0)
+ ideal_tiling_--;
+ break;
+ }
+ }
+
+ DCHECK_LE(set_->tilings_.size(),
+ static_cast<size_t>(std::numeric_limits<int>::max()));
+
+ int num_tilings = set_->tilings_.size();
+ if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0)
+ ideal_tiling_--;
+
+ ++(*this);
+}
+
+PictureLayerTilingSet::CoverageIterator::~CoverageIterator() {
+}
+
+gfx::Rect PictureLayerTilingSet::CoverageIterator::geometry_rect() const {
+ if (!tiling_iter_) {
+ if (!region_iter_.has_rect())
+ return gfx::Rect();
+ return region_iter_.rect();
+ }
+ return tiling_iter_.geometry_rect();
+}
+
+gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const {
+ if (!tiling_iter_)
+ return gfx::RectF();
+ return tiling_iter_.texture_rect();
+}
+
+Tile* PictureLayerTilingSet::CoverageIterator::operator->() const {
+ if (!tiling_iter_)
+ return NULL;
+ return *tiling_iter_;
+}
+
+Tile* PictureLayerTilingSet::CoverageIterator::operator*() const {
+ if (!tiling_iter_)
+ return NULL;
+ return *tiling_iter_;
+}
+
+TileResolution PictureLayerTilingSet::CoverageIterator::resolution() const {
+ const PictureLayerTiling* tiling = CurrentTiling();
+ DCHECK(tiling);
+ return tiling->resolution();
+}
+
+PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling()
+ const {
+ if (current_tiling_ < 0)
+ return NULL;
+ if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size())
+ return NULL;
+ return set_->tilings_[current_tiling_];
+}
+
+int PictureLayerTilingSet::CoverageIterator::NextTiling() const {
+ // Order returned by this method is:
+ // 1. Ideal tiling index
+ // 2. Tiling index < Ideal in decreasing order (higher res than ideal)
+ // 3. Tiling index > Ideal in increasing order (lower res than ideal)
+ // 4. Tiling index > tilings.size() (invalid index)
+ if (current_tiling_ < 0)
+ return ideal_tiling_;
+ else if (current_tiling_ > ideal_tiling_)
+ return current_tiling_ + 1;
+ else if (current_tiling_)
+ return current_tiling_ - 1;
+ else
+ return ideal_tiling_ + 1;
+}
+
+PictureLayerTilingSet::CoverageIterator&
+PictureLayerTilingSet::CoverageIterator::operator++() {
+ bool first_time = current_tiling_ < 0;
+
+ if (!*this && !first_time)
+ return *this;
+
+ if (tiling_iter_)
+ ++tiling_iter_;
+
+ // Loop until we find a valid place to stop.
+ while (true) {
+ while (tiling_iter_ &&
+ (!*tiling_iter_ || !tiling_iter_->draw_info().IsReadyToDraw())) {
+ missing_region_.Union(tiling_iter_.geometry_rect());
+ ++tiling_iter_;
+ }
+ if (tiling_iter_)
+ return *this;
+
+ // If the set of current rects for this tiling is done, go to the next
+ // tiling and set up to iterate through all of the remaining holes.
+ // This will also happen the first time through the loop.
+ if (!region_iter_.has_rect()) {
+ current_tiling_ = NextTiling();
+ current_region_.Swap(&missing_region_);
+ missing_region_.Clear();
+ region_iter_ = Region::Iterator(current_region_);
+
+ // All done and all filled.
+ if (!region_iter_.has_rect()) {
+ current_tiling_ = set_->tilings_.size();
+ return *this;
+ }
+
+ // No more valid tiles, return this checkerboard rect.
+ if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
+ return *this;
+ }
+
+ // Pop a rect off. If there are no more tilings, then these will be
+ // treated as geometry with null tiles that the caller can checkerboard.
+ gfx::Rect last_rect = region_iter_.rect();
+ region_iter_.next();
+
+ // Done, found next checkerboard rect to return.
+ if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
+ return *this;
+
+ // Construct a new iterator for the next tiling, but we need to loop
+ // again until we get to a valid one.
+ tiling_iter_ = PictureLayerTiling::CoverageIterator(
+ set_->tilings_[current_tiling_],
+ contents_scale_,
+ last_rect);
+ }
+
+ return *this;
+}
+
+PictureLayerTilingSet::CoverageIterator::operator bool() const {
+ return current_tiling_ < static_cast<int>(set_->tilings_.size()) ||
+ region_iter_.has_rect();
+}
+
+void PictureLayerTilingSet::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ for (size_t i = 0; i < tilings_.size(); ++i) {
+ state->BeginDictionary();
+ tilings_[i]->AsValueInto(state);
+ state->EndDictionary();
+ }
+}
+
+size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const {
+ size_t amount = 0;
+ for (size_t i = 0; i < tilings_.size(); ++i)
+ amount += tilings_[i]->GPUMemoryUsageInBytes();
+ return amount;
+}
+
+PictureLayerTilingSet::TilingRange PictureLayerTilingSet::GetTilingRange(
+ TilingRangeType type) const {
+ // Doesn't seem to be the case right now but if it ever becomes a performance
+ // problem to compute these ranges each time this function is called, we can
+ // compute them only when the tiling set has changed instead.
+ TilingRange high_res_range(0, 0);
+ TilingRange low_res_range(tilings_.size(), tilings_.size());
+ for (size_t i = 0; i < tilings_.size(); ++i) {
+ const PictureLayerTiling* tiling = tilings_[i];
+ if (tiling->resolution() == HIGH_RESOLUTION)
+ high_res_range = TilingRange(i, i + 1);
+ if (tiling->resolution() == LOW_RESOLUTION)
+ low_res_range = TilingRange(i, i + 1);
+ }
+
+ TilingRange range(0, 0);
+ switch (type) {
+ case HIGHER_THAN_HIGH_RES:
+ range = TilingRange(0, high_res_range.start);
+ break;
+ case HIGH_RES:
+ range = high_res_range;
+ break;
+ case BETWEEN_HIGH_AND_LOW_RES:
+ // TODO(vmpstr): This code assumes that high res tiling will come before
+ // low res tiling, however there are cases where this assumption is
+ // violated. As a result, it's better to be safe in these situations,
+ // since otherwise we can end up accessing a tiling that doesn't exist.
+ // See crbug.com/429397 for high res tiling appearing after low res
+ // tiling discussion/fixes.
+ if (high_res_range.start <= low_res_range.start)
+ range = TilingRange(high_res_range.end, low_res_range.start);
+ else
+ range = TilingRange(low_res_range.end, high_res_range.start);
+ break;
+ case LOW_RES:
+ range = low_res_range;
+ break;
+ case LOWER_THAN_LOW_RES:
+ range = TilingRange(low_res_range.end, tilings_.size());
+ break;
+ }
+
+ DCHECK_LE(range.start, range.end);
+ return range;
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/picture_layer_tiling_set.h b/chromium/cc/tiles/picture_layer_tiling_set.h
new file mode 100644
index 00000000000..d1367f8a614
--- /dev/null
+++ b/chromium/cc/tiles/picture_layer_tiling_set.h
@@ -0,0 +1,206 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TILES_PICTURE_LAYER_TILING_SET_H_
+#define CC_TILES_PICTURE_LAYER_TILING_SET_H_
+
+#include <set>
+#include <vector>
+
+#include "cc/base/region.h"
+#include "cc/base/scoped_ptr_vector.h"
+#include "cc/tiles/picture_layer_tiling.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace base {
+namespace trace_event {
+class TracedValue;
+}
+}
+
+namespace cc {
+
+class CC_EXPORT PictureLayerTilingSet {
+ public:
+ enum TilingRangeType {
+ HIGHER_THAN_HIGH_RES,
+ HIGH_RES,
+ BETWEEN_HIGH_AND_LOW_RES,
+ LOW_RES,
+ LOWER_THAN_LOW_RES
+ };
+ struct TilingRange {
+ TilingRange(int start, int end) : start(start), end(end) {}
+
+ int start;
+ int end;
+ };
+
+ static scoped_ptr<PictureLayerTilingSet> Create(
+ WhichTree tree,
+ PictureLayerTilingClient* client,
+ float tiling_interest_area_viewport_multiplier,
+ float skewport_target_time_in_seconds,
+ int skewport_extrapolation_limit_in_content);
+
+ ~PictureLayerTilingSet();
+
+ const PictureLayerTilingClient* client() const { return client_; }
+
+ void CleanUpTilings(float min_acceptable_high_res_scale,
+ float max_acceptable_high_res_scale,
+ const std::vector<PictureLayerTiling*>& needed_tilings,
+ bool should_have_low_res,
+ PictureLayerTilingSet* twin_set,
+ PictureLayerTilingSet* recycled_twin_set);
+ void RemoveNonIdealTilings();
+
+ // This function is called on the active tree during activation.
+ void UpdateTilingsToCurrentRasterSourceForActivation(
+ scoped_refptr<RasterSource> raster_source,
+ const PictureLayerTilingSet* pending_twin_set,
+ const Region& layer_invalidation,
+ float minimum_contents_scale,
+ float maximum_contents_scale);
+
+ // This function is called on the sync tree during commit.
+ void UpdateTilingsToCurrentRasterSourceForCommit(
+ scoped_refptr<RasterSource> raster_source,
+ const Region& layer_invalidation,
+ float minimum_contents_scale,
+ float maximum_contents_scale);
+
+ // This function is called on the sync tree right after commit.
+ void UpdateRasterSourceDueToLCDChange(
+ const scoped_refptr<RasterSource>& raster_source,
+ const Region& layer_invalidation);
+
+ PictureLayerTiling* AddTiling(float contents_scale,
+ scoped_refptr<RasterSource> raster_source);
+ size_t num_tilings() const { return tilings_.size(); }
+ int NumHighResTilings() const;
+ PictureLayerTiling* tiling_at(size_t idx) { return tilings_[idx]; }
+ const PictureLayerTiling* tiling_at(size_t idx) const {
+ return tilings_[idx];
+ }
+ WhichTree tree() const { return tree_; }
+
+ PictureLayerTiling* FindTilingWithScale(float scale) const;
+ PictureLayerTiling* FindTilingWithResolution(TileResolution resolution) const;
+
+ void MarkAllTilingsNonIdeal();
+
+ // If a tiling exists whose scale is within |snap_to_existing_tiling_ratio|
+ // ratio of |start_scale|, then return that tiling's scale. Otherwise, return
+ // |start_scale|. If multiple tilings match the criteria, return the one with
+ // the least ratio to |start_scale|.
+ float GetSnappedContentsScale(float start_scale,
+ float snap_to_existing_tiling_ratio) const;
+
+ // Returns the maximum contents scale of all tilings, or 0 if no tilings
+ // exist.
+ float GetMaximumContentsScale() const;
+
+ // Removes all tilings with a contents scale < |minimum_scale|.
+ void RemoveTilingsBelowScale(float minimum_scale);
+
+ // Removes all tilings with a contents scale > |maximum_scale|.
+ void RemoveTilingsAboveScale(float maximum_scale);
+
+ // Remove all tilings.
+ void RemoveAllTilings();
+
+ // Remove all tiles; keep all tilings.
+ void RemoveAllTiles();
+
+ // Update the rects and priorities for tiles based on the given information.
+ bool UpdateTilePriorities(const gfx::Rect& required_rect_in_layer_space,
+ float ideal_contents_scale,
+ double current_frame_time_in_seconds,
+ const Occlusion& occlusion_in_layer_space,
+ bool can_require_tiles_for_activation);
+
+ void GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const;
+
+ // For a given rect, iterates through tiles that can fill it. If no
+ // set of tiles with resources can fill the rect, then it will iterate
+ // through null tiles with valid geometry_rect() until the rect is full.
+ // If all tiles have resources, the union of all geometry_rects will
+ // exactly fill rect with no overlap.
+ class CC_EXPORT CoverageIterator {
+ public:
+ CoverageIterator(const PictureLayerTilingSet* set,
+ float contents_scale,
+ const gfx::Rect& content_rect,
+ float ideal_contents_scale);
+ ~CoverageIterator();
+
+ // Visible rect (no borders), always in the space of rect,
+ // regardless of the relative contents scale of the tiling.
+ gfx::Rect geometry_rect() const;
+ // Texture rect (in texels) for geometry_rect
+ gfx::RectF texture_rect() const;
+
+ Tile* operator->() const;
+ Tile* operator*() const;
+
+ CoverageIterator& operator++();
+ operator bool() const;
+
+ TileResolution resolution() const;
+ PictureLayerTiling* CurrentTiling() const;
+
+ private:
+ int NextTiling() const;
+
+ const PictureLayerTilingSet* set_;
+ float contents_scale_;
+ float ideal_contents_scale_;
+ PictureLayerTiling::CoverageIterator tiling_iter_;
+ int current_tiling_;
+ int ideal_tiling_;
+
+ Region current_region_;
+ Region missing_region_;
+ Region::Iterator region_iter_;
+ };
+
+ void AsValueInto(base::trace_event::TracedValue* array) const;
+ size_t GPUMemoryUsageInBytes() const;
+
+ TilingRange GetTilingRange(TilingRangeType type) const;
+
+ private:
+ explicit PictureLayerTilingSet(
+ WhichTree tree,
+ PictureLayerTilingClient* client,
+ float tiling_interest_area_viewport_multiplier,
+ float skewport_target_time_in_seconds,
+ int skewport_extrapolation_limit_in_content_pixels);
+
+ void CopyTilingsAndPropertiesFromPendingTwin(
+ const PictureLayerTilingSet* pending_twin_set,
+ const scoped_refptr<RasterSource>& raster_source,
+ const Region& layer_invalidation);
+
+ // Remove one tiling.
+ void Remove(PictureLayerTiling* tiling);
+ void VerifyTilings(const PictureLayerTilingSet* pending_twin_set) const;
+
+ ScopedPtrVector<PictureLayerTiling> tilings_;
+
+ const float tiling_interest_area_viewport_multiplier_;
+ const float skewport_target_time_in_seconds_;
+ const int skewport_extrapolation_limit_in_content_pixels_;
+ WhichTree tree_;
+ PictureLayerTilingClient* client_;
+
+ friend class Iterator;
+ DISALLOW_COPY_AND_ASSIGN(PictureLayerTilingSet);
+};
+
+} // namespace cc
+
+#endif // CC_TILES_PICTURE_LAYER_TILING_SET_H_
diff --git a/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
new file mode 100644
index 00000000000..2d0a1b2d08a
--- /dev/null
+++ b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
@@ -0,0 +1,454 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/tiles/picture_layer_tiling_set.h"
+
+#include <map>
+#include <vector>
+
+#include "cc/resources/resource_provider.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/fake_picture_layer_tiling_client.h"
+#include "cc/test/fake_picture_pile_impl.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size_conversions.h"
+
+namespace cc {
+namespace {
+
+scoped_ptr<PictureLayerTilingSet> CreateTilingSet(
+ PictureLayerTilingClient* client) {
+ LayerTreeSettings defaults;
+ return PictureLayerTilingSet::Create(
+ ACTIVE_TREE, client, defaults.tiling_interest_area_viewport_multiplier,
+ defaults.skewport_target_time_in_seconds,
+ defaults.skewport_extrapolation_limit_in_content_pixels);
+}
+
+TEST(PictureLayerTilingSetTest, NoResources) {
+ FakePictureLayerTilingClient client;
+ gfx::Size layer_bounds(1000, 800);
+ scoped_ptr<PictureLayerTilingSet> set = CreateTilingSet(&client);
+ client.SetTileSize(gfx::Size(256, 256));
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateEmptyPileWithDefaultTileSize(layer_bounds);
+
+ set->AddTiling(1.0, pile);
+ set->AddTiling(1.5, pile);
+ set->AddTiling(2.0, pile);
+
+ float contents_scale = 2.0;
+ gfx::Size content_bounds(
+ gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)));
+ gfx::Rect content_rect(content_bounds);
+
+ Region remaining(content_rect);
+ PictureLayerTilingSet::CoverageIterator iter(set.get(), contents_scale,
+ content_rect, contents_scale);
+ for (; iter; ++iter) {
+ gfx::Rect geometry_rect = iter.geometry_rect();
+ EXPECT_TRUE(content_rect.Contains(geometry_rect));
+ ASSERT_TRUE(remaining.Contains(geometry_rect));
+ remaining.Subtract(geometry_rect);
+
+ // No tiles have resources, so no iter represents a real tile.
+ EXPECT_FALSE(*iter);
+ }
+ EXPECT_TRUE(remaining.IsEmpty());
+}
+
+TEST(PictureLayerTilingSetTest, TilingRange) {
+ FakePictureLayerTilingClient client;
+ gfx::Size layer_bounds(10, 10);
+ PictureLayerTilingSet::TilingRange higher_than_high_res_range(0, 0);
+ PictureLayerTilingSet::TilingRange high_res_range(0, 0);
+ PictureLayerTilingSet::TilingRange between_high_and_low_res_range(0, 0);
+ PictureLayerTilingSet::TilingRange low_res_range(0, 0);
+ PictureLayerTilingSet::TilingRange lower_than_low_res_range(0, 0);
+ PictureLayerTiling* high_res_tiling;
+ PictureLayerTiling* low_res_tiling;
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+
+ scoped_ptr<PictureLayerTilingSet> set = CreateTilingSet(&client);
+ set->AddTiling(2.0, pile);
+ high_res_tiling = set->AddTiling(1.0, pile);
+ high_res_tiling->set_resolution(HIGH_RESOLUTION);
+ set->AddTiling(0.5, pile);
+ low_res_tiling = set->AddTiling(0.25, pile);
+ low_res_tiling->set_resolution(LOW_RESOLUTION);
+ set->AddTiling(0.125, pile);
+
+ higher_than_high_res_range =
+ set->GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
+ EXPECT_EQ(0, higher_than_high_res_range.start);
+ EXPECT_EQ(1, higher_than_high_res_range.end);
+
+ high_res_range = set->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
+ EXPECT_EQ(1, high_res_range.start);
+ EXPECT_EQ(2, high_res_range.end);
+
+ between_high_and_low_res_range =
+ set->GetTilingRange(PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
+ EXPECT_EQ(2, between_high_and_low_res_range.start);
+ EXPECT_EQ(3, between_high_and_low_res_range.end);
+
+ low_res_range = set->GetTilingRange(PictureLayerTilingSet::LOW_RES);
+ EXPECT_EQ(3, low_res_range.start);
+ EXPECT_EQ(4, low_res_range.end);
+
+ lower_than_low_res_range =
+ set->GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES);
+ EXPECT_EQ(4, lower_than_low_res_range.start);
+ EXPECT_EQ(5, lower_than_low_res_range.end);
+
+ scoped_ptr<PictureLayerTilingSet> set_without_low_res =
+ CreateTilingSet(&client);
+ set_without_low_res->AddTiling(2.0, pile);
+ high_res_tiling = set_without_low_res->AddTiling(1.0, pile);
+ high_res_tiling->set_resolution(HIGH_RESOLUTION);
+ set_without_low_res->AddTiling(0.5, pile);
+ set_without_low_res->AddTiling(0.25, pile);
+
+ higher_than_high_res_range = set_without_low_res->GetTilingRange(
+ PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
+ EXPECT_EQ(0, higher_than_high_res_range.start);
+ EXPECT_EQ(1, higher_than_high_res_range.end);
+
+ high_res_range =
+ set_without_low_res->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
+ EXPECT_EQ(1, high_res_range.start);
+ EXPECT_EQ(2, high_res_range.end);
+
+ between_high_and_low_res_range = set_without_low_res->GetTilingRange(
+ PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
+ EXPECT_EQ(2, between_high_and_low_res_range.start);
+ EXPECT_EQ(4, between_high_and_low_res_range.end);
+
+ low_res_range =
+ set_without_low_res->GetTilingRange(PictureLayerTilingSet::LOW_RES);
+ EXPECT_EQ(0, low_res_range.end - low_res_range.start);
+
+ lower_than_low_res_range = set_without_low_res->GetTilingRange(
+ PictureLayerTilingSet::LOWER_THAN_LOW_RES);
+ EXPECT_EQ(0, lower_than_low_res_range.end - lower_than_low_res_range.start);
+
+ scoped_ptr<PictureLayerTilingSet> set_with_only_high_and_low_res =
+ CreateTilingSet(&client);
+ high_res_tiling = set_with_only_high_and_low_res->AddTiling(1.0, pile);
+ high_res_tiling->set_resolution(HIGH_RESOLUTION);
+ low_res_tiling = set_with_only_high_and_low_res->AddTiling(0.5, pile);
+ low_res_tiling->set_resolution(LOW_RESOLUTION);
+
+ higher_than_high_res_range = set_with_only_high_and_low_res->GetTilingRange(
+ PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
+ EXPECT_EQ(0,
+ higher_than_high_res_range.end - higher_than_high_res_range.start);
+
+ high_res_range = set_with_only_high_and_low_res->GetTilingRange(
+ PictureLayerTilingSet::HIGH_RES);
+ EXPECT_EQ(0, high_res_range.start);
+ EXPECT_EQ(1, high_res_range.end);
+
+ between_high_and_low_res_range =
+ set_with_only_high_and_low_res->GetTilingRange(
+ PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
+ EXPECT_EQ(0, between_high_and_low_res_range.end -
+ between_high_and_low_res_range.start);
+
+ low_res_range = set_with_only_high_and_low_res->GetTilingRange(
+ PictureLayerTilingSet::LOW_RES);
+ EXPECT_EQ(1, low_res_range.start);
+ EXPECT_EQ(2, low_res_range.end);
+
+ lower_than_low_res_range = set_with_only_high_and_low_res->GetTilingRange(
+ PictureLayerTilingSet::LOWER_THAN_LOW_RES);
+ EXPECT_EQ(0, lower_than_low_res_range.end - lower_than_low_res_range.start);
+
+ scoped_ptr<PictureLayerTilingSet> set_with_only_high_res =
+ CreateTilingSet(&client);
+ high_res_tiling = set_with_only_high_res->AddTiling(1.0, pile);
+ high_res_tiling->set_resolution(HIGH_RESOLUTION);
+
+ higher_than_high_res_range = set_with_only_high_res->GetTilingRange(
+ PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
+ EXPECT_EQ(0,
+ higher_than_high_res_range.end - higher_than_high_res_range.start);
+
+ high_res_range =
+ set_with_only_high_res->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
+ EXPECT_EQ(0, high_res_range.start);
+ EXPECT_EQ(1, high_res_range.end);
+
+ between_high_and_low_res_range = set_with_only_high_res->GetTilingRange(
+ PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
+ EXPECT_EQ(0, between_high_and_low_res_range.end -
+ between_high_and_low_res_range.start);
+
+ low_res_range =
+ set_with_only_high_res->GetTilingRange(PictureLayerTilingSet::LOW_RES);
+ EXPECT_EQ(0, low_res_range.end - low_res_range.start);
+
+ lower_than_low_res_range = set_with_only_high_res->GetTilingRange(
+ PictureLayerTilingSet::LOWER_THAN_LOW_RES);
+ EXPECT_EQ(0, lower_than_low_res_range.end - lower_than_low_res_range.start);
+}
+
+class PictureLayerTilingSetTestWithResources : public testing::Test {
+ public:
+ void RunTest(int num_tilings,
+ float min_scale,
+ float scale_increment,
+ float ideal_contents_scale,
+ float expected_scale) {
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<FakeOutputSurface> output_surface =
+ FakeOutputSurface::Create3d();
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider =
+ ResourceProvider::Create(output_surface.get(),
+ shared_bitmap_manager.get(),
+ NULL,
+ NULL,
+ 0,
+ false,
+ 1);
+
+ FakePictureLayerTilingClient client(resource_provider.get());
+ client.SetTileSize(gfx::Size(256, 256));
+ gfx::Size layer_bounds(1000, 800);
+ scoped_ptr<PictureLayerTilingSet> set = CreateTilingSet(&client);
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+
+ float scale = min_scale;
+ for (int i = 0; i < num_tilings; ++i, scale += scale_increment) {
+ PictureLayerTiling* tiling = set->AddTiling(scale, pile);
+ tiling->CreateAllTilesForTesting();
+ std::vector<Tile*> tiles = tiling->AllTilesForTesting();
+ client.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
+ }
+
+ float max_contents_scale = scale;
+ gfx::Size content_bounds(
+ gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, max_contents_scale)));
+ gfx::Rect content_rect(content_bounds);
+
+ Region remaining(content_rect);
+ PictureLayerTilingSet::CoverageIterator iter(
+ set.get(), max_contents_scale, content_rect, ideal_contents_scale);
+ for (; iter; ++iter) {
+ gfx::Rect geometry_rect = iter.geometry_rect();
+ EXPECT_TRUE(content_rect.Contains(geometry_rect));
+ ASSERT_TRUE(remaining.Contains(geometry_rect));
+ remaining.Subtract(geometry_rect);
+
+ float scale = iter.CurrentTiling()->contents_scale();
+ EXPECT_EQ(expected_scale, scale);
+
+ if (num_tilings)
+ EXPECT_TRUE(*iter);
+ else
+ EXPECT_FALSE(*iter);
+ }
+ EXPECT_TRUE(remaining.IsEmpty());
+ }
+};
+
+TEST_F(PictureLayerTilingSetTestWithResources, NoTilings) {
+ RunTest(0, 0.f, 0.f, 2.f, 0.f);
+}
+TEST_F(PictureLayerTilingSetTestWithResources, OneTiling_Smaller) {
+ RunTest(1, 1.f, 0.f, 2.f, 1.f);
+}
+TEST_F(PictureLayerTilingSetTestWithResources, OneTiling_Larger) {
+ RunTest(1, 3.f, 0.f, 2.f, 3.f);
+}
+TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_Smaller) {
+ RunTest(2, 1.f, 1.f, 3.f, 2.f);
+}
+
+TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_SmallerEqual) {
+ RunTest(2, 1.f, 1.f, 2.f, 2.f);
+}
+
+TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_LargerEqual) {
+ RunTest(2, 1.f, 1.f, 1.f, 1.f);
+}
+
+TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_Larger) {
+ RunTest(2, 2.f, 8.f, 1.f, 2.f);
+}
+
+TEST_F(PictureLayerTilingSetTestWithResources, ManyTilings_Equal) {
+ RunTest(10, 1.f, 1.f, 5.f, 5.f);
+}
+
+TEST_F(PictureLayerTilingSetTestWithResources, ManyTilings_NotEqual) {
+ RunTest(10, 1.f, 1.f, 4.5f, 5.f);
+}
+
+TEST(PictureLayerTilingSetTest, TileSizeChange) {
+ FakePictureLayerTilingClient pending_client;
+ FakePictureLayerTilingClient active_client;
+ scoped_ptr<PictureLayerTilingSet> pending_set = PictureLayerTilingSet::Create(
+ PENDING_TREE, &pending_client, 1000, 1.f, 1000);
+ scoped_ptr<PictureLayerTilingSet> active_set = PictureLayerTilingSet::Create(
+ ACTIVE_TREE, &active_client, 1000, 1.f, 1000);
+
+ gfx::Size layer_bounds(100, 100);
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+
+ gfx::Size tile_size1(10, 10);
+ gfx::Size tile_size2(30, 30);
+ gfx::Size tile_size3(20, 20);
+
+ pending_client.SetTileSize(tile_size1);
+ pending_set->AddTiling(1.f, pile);
+ // New tilings get the correct tile size.
+ EXPECT_EQ(tile_size1, pending_set->tiling_at(0)->tile_size());
+
+ // Set some expected things for the tiling set to function.
+ pending_set->tiling_at(0)->set_resolution(HIGH_RESOLUTION);
+ active_client.set_twin_tiling_set(pending_set.get());
+
+ // Set a priority rect so we get tiles.
+ pending_set->UpdateTilePriorities(gfx::Rect(layer_bounds), 1.f, 1.0,
+ Occlusion(), false);
+ EXPECT_EQ(tile_size1, pending_set->tiling_at(0)->tile_size());
+
+ // The tiles should get the correct size.
+ std::vector<Tile*> pending_tiles =
+ pending_set->tiling_at(0)->AllTilesForTesting();
+ EXPECT_GT(pending_tiles.size(), 0u);
+ for (const auto& tile : pending_tiles)
+ EXPECT_EQ(tile_size1, tile->content_rect().size());
+
+ // Update to a new source frame with a new tile size.
+ pending_client.SetTileSize(tile_size2);
+ pending_set->UpdateTilingsToCurrentRasterSourceForCommit(pile.get(), Region(),
+ 1.f, 1.f);
+ // The tiling should get the correct tile size.
+ EXPECT_EQ(tile_size2, pending_set->tiling_at(0)->tile_size());
+
+ // Set a priority rect so we get tiles.
+ pending_set->UpdateTilePriorities(gfx::Rect(layer_bounds), 1.f, 2.0,
+ Occlusion(), false);
+ EXPECT_EQ(tile_size2, pending_set->tiling_at(0)->tile_size());
+
+ // Tiles should have the new correct size.
+ pending_tiles = pending_set->tiling_at(0)->AllTilesForTesting();
+ EXPECT_GT(pending_tiles.size(), 0u);
+ for (const auto& tile : pending_tiles)
+ EXPECT_EQ(tile_size2, tile->content_rect().size());
+
+ // Clone from the pending to the active tree.
+ active_client.SetTileSize(tile_size2);
+ active_set->UpdateTilingsToCurrentRasterSourceForActivation(
+ pile.get(), pending_set.get(), Region(), 1.f, 1.f);
+ // The active tiling should get the right tile size.
+ EXPECT_EQ(tile_size2, active_set->tiling_at(0)->tile_size());
+
+ // Cloned tiles should have the right size.
+ std::vector<Tile*> active_tiles =
+ active_set->tiling_at(0)->AllTilesForTesting();
+ EXPECT_GT(active_tiles.size(), 0u);
+ for (const auto& tile : active_tiles)
+ EXPECT_EQ(tile_size2, tile->content_rect().size());
+
+ // A new source frame with a new tile size.
+ pending_client.SetTileSize(tile_size3);
+ pending_set->UpdateTilingsToCurrentRasterSourceForCommit(pile.get(), Region(),
+ 1.f, 1.f);
+ // The tiling gets the new size correctly.
+ EXPECT_EQ(tile_size3, pending_set->tiling_at(0)->tile_size());
+
+ // Set a priority rect so we get tiles.
+ pending_set->UpdateTilePriorities(gfx::Rect(layer_bounds), 1.f, 3.0,
+ Occlusion(), false);
+ EXPECT_EQ(tile_size3, pending_set->tiling_at(0)->tile_size());
+
+ // Tiles are resized for the new size.
+ pending_tiles = pending_set->tiling_at(0)->AllTilesForTesting();
+ EXPECT_GT(pending_tiles.size(), 0u);
+ for (const auto& tile : pending_tiles)
+ EXPECT_EQ(tile_size3, tile->content_rect().size());
+
+ // Now we activate with a different tile size for the active tiling.
+ active_client.SetTileSize(tile_size3);
+ active_set->UpdateTilingsToCurrentRasterSourceForActivation(
+ pile.get(), pending_set.get(), Region(), 1.f, 1.f);
+ // The active tiling changes its tile size.
+ EXPECT_EQ(tile_size3, active_set->tiling_at(0)->tile_size());
+
+ // And its tiles are resized.
+ active_tiles = active_set->tiling_at(0)->AllTilesForTesting();
+ EXPECT_GT(active_tiles.size(), 0u);
+ for (const auto& tile : active_tiles)
+ EXPECT_EQ(tile_size3, tile->content_rect().size());
+}
+
+TEST(PictureLayerTilingSetTest, MaxContentScale) {
+ FakePictureLayerTilingClient pending_client;
+ FakePictureLayerTilingClient active_client;
+ scoped_ptr<PictureLayerTilingSet> pending_set = PictureLayerTilingSet::Create(
+ PENDING_TREE, &pending_client, 1000, 1.f, 1000);
+ scoped_ptr<PictureLayerTilingSet> active_set = PictureLayerTilingSet::Create(
+ ACTIVE_TREE, &active_client, 1000, 1.f, 1000);
+
+ gfx::Size layer_bounds(100, 105);
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateEmptyPileWithDefaultTileSize(layer_bounds);
+
+ // Tilings can be added of any scale, the tiling client can controls this.
+ pending_set->AddTiling(1.f, pile);
+ pending_set->AddTiling(2.f, pile);
+ pending_set->AddTiling(3.f, pile);
+
+ // Set some expected things for the tiling set to function.
+ pending_set->tiling_at(0)->set_resolution(HIGH_RESOLUTION);
+ active_client.set_twin_tiling_set(pending_set.get());
+
+ // Update to a new source frame with a max content scale that is larger than
+ // everything.
+ float max_content_scale = 3.f;
+ pending_set->UpdateTilingsToCurrentRasterSourceForCommit(
+ pile.get(), Region(), 1.f, max_content_scale);
+
+ // All the tilings are there still.
+ EXPECT_EQ(3u, pending_set->num_tilings());
+
+ // Clone from the pending to the active tree with the same max content size.
+ active_set->UpdateTilingsToCurrentRasterSourceForActivation(
+ pile.get(), pending_set.get(), Region(), 1.f, max_content_scale);
+ // All the tilings are on the active tree.
+ EXPECT_EQ(3u, active_set->num_tilings());
+
+ // Update to a new source frame with a max content scale that will drop one
+ // tiling.
+ max_content_scale = 2.9f;
+ pending_set->UpdateTilingsToCurrentRasterSourceForCommit(
+ pile.get(), Region(), 1.f, max_content_scale);
+ // All the tilings are there still.
+ EXPECT_EQ(2u, pending_set->num_tilings());
+
+ pending_set->tiling_at(0)->set_resolution(HIGH_RESOLUTION);
+
+ // Clone from the pending to the active tree with the same max content size.
+ active_set->UpdateTilingsToCurrentRasterSourceForActivation(
+ pile.get(), pending_set.get(), Region(), 1.f, max_content_scale);
+ // All the tilings are on the active tree.
+ EXPECT_EQ(2u, active_set->num_tilings());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/resources/picture_layer_tiling_unittest.cc b/chromium/cc/tiles/picture_layer_tiling_unittest.cc
index f793097b7f4..31caf461d2a 100644
--- a/chromium/cc/resources/picture_layer_tiling_unittest.cc
+++ b/chromium/cc/tiles/picture_layer_tiling_unittest.cc
@@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/picture_layer_tiling.h"
-
#include <limits>
#include <set>
#include "cc/base/math_util.h"
-#include "cc/resources/picture_layer_tiling_set.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_picture_layer_tiling_client.h"
+#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/test_context_provider.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/tiles/picture_layer_tiling.h"
+#include "cc/tiles/picture_layer_tiling_set.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/quad_f.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -35,63 +35,69 @@ static gfx::Rect ViewportInLayerSpace(
return ToEnclosingRect(viewport_in_layer_space);
}
-static void UpdateAllTilePriorities(PictureLayerTilingSet* set,
- WhichTree tree,
- const gfx::Rect& visible_layer_rect,
- float layer_contents_scale,
- double current_frame_time_in_seconds) {
- for (size_t i = 0; i < set->num_tilings(); ++i) {
- set->tiling_at(i)->ComputeTilePriorityRects(tree,
- visible_layer_rect,
- layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
- }
-}
-
class TestablePictureLayerTiling : public PictureLayerTiling {
public:
using PictureLayerTiling::SetLiveTilesRect;
using PictureLayerTiling::TileAt;
static scoped_ptr<TestablePictureLayerTiling> Create(
+ WhichTree tree,
float contents_scale,
- const gfx::Size& layer_bounds,
- PictureLayerTilingClient* client) {
+ scoped_refptr<RasterSource> raster_source,
+ PictureLayerTilingClient* client,
+ const LayerTreeSettings& settings) {
return make_scoped_ptr(new TestablePictureLayerTiling(
- contents_scale,
- layer_bounds,
- client));
+ tree, contents_scale, raster_source, client,
+ settings.tiling_interest_area_viewport_multiplier,
+ settings.skewport_target_time_in_seconds,
+ settings.skewport_extrapolation_limit_in_content_pixels));
}
gfx::Rect live_tiles_rect() const { return live_tiles_rect_; }
- bool eviction_tiles_cache_valid() const {
- return eviction_tiles_cache_valid_;
- }
using PictureLayerTiling::ComputeSkewport;
using PictureLayerTiling::RemoveTileAt;
protected:
- TestablePictureLayerTiling(float contents_scale,
- const gfx::Size& layer_bounds,
- PictureLayerTilingClient* client)
- : PictureLayerTiling(contents_scale, layer_bounds, client) { }
+ TestablePictureLayerTiling(WhichTree tree,
+ float contents_scale,
+ scoped_refptr<RasterSource> raster_source,
+ PictureLayerTilingClient* client,
+ float tiling_interest_area_viewport_multiplier,
+ float skewport_target_time,
+ int skewport_extrapolation_limit)
+ : PictureLayerTiling(tree,
+ contents_scale,
+ raster_source,
+ client,
+ tiling_interest_area_viewport_multiplier,
+ skewport_target_time,
+ skewport_extrapolation_limit) {}
};
class PictureLayerTilingIteratorTest : public testing::Test {
public:
PictureLayerTilingIteratorTest() {}
- virtual ~PictureLayerTilingIteratorTest() {}
+ ~PictureLayerTilingIteratorTest() override {}
void Initialize(const gfx::Size& tile_size,
float contents_scale,
const gfx::Size& layer_bounds) {
client_.SetTileSize(tile_size);
- client_.set_tree(PENDING_TREE);
- tiling_ = TestablePictureLayerTiling::Create(contents_scale,
- layer_bounds,
- &client_);
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ tiling_ = TestablePictureLayerTiling::Create(
+ PENDING_TREE, contents_scale, pile, &client_, LayerTreeSettings());
+ }
+
+ void InitializeActive(const gfx::Size& tile_size,
+ float contents_scale,
+ const gfx::Size& layer_bounds) {
+ client_.SetTileSize(tile_size);
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ tiling_ = TestablePictureLayerTiling::Create(
+ ACTIVE_TREE, contents_scale, pile, &client_, LayerTreeSettings());
}
void SetLiveRectAndVerifyTiles(const gfx::Rect& live_tiles_rect) {
@@ -135,8 +141,6 @@ class PictureLayerTilingIteratorTest : public testing::Test {
EXPECT_GE(texture_rect.y(), 0);
EXPECT_LE(texture_rect.right(), client_.TileSize().width());
EXPECT_LE(texture_rect.bottom(), client_.TileSize().height());
-
- EXPECT_EQ(iter.texture_size(), client_.TileSize());
}
// The entire rect must be filled by geometry from the tiling.
@@ -183,10 +187,6 @@ class PictureLayerTilingIteratorTest : public testing::Test {
VerifyTilesExactlyCoverRect(rect_scale, dest_rect, clamped_rect);
}
- void set_max_tiles_for_interest_area(size_t area) {
- client_.set_max_tiles_for_interest_area(area);
- }
-
protected:
FakePictureLayerTilingClient client_;
scoped_ptr<TestablePictureLayerTiling> tiling_;
@@ -200,24 +200,28 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeDeletesTiles) {
// deletes tiles that intersect that invalidation.
gfx::Size tile_size(100, 100);
gfx::Size original_layer_size(10, 10);
- Initialize(tile_size, 1.f, original_layer_size);
+ InitializeActive(tile_size, 1.f, original_layer_size);
SetLiveRectAndVerifyTiles(gfx::Rect(original_layer_size));
// Tiling only has one tile, since its total size is less than one.
EXPECT_TRUE(tiling_->TileAt(0, 0));
// Stop creating tiles so that any invalidations are left as holes.
- client_.set_allow_create_tile(false);
+ gfx::Size new_layer_size(200, 200);
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateEmptyPileWithDefaultTileSize(new_layer_size);
Region invalidation =
SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
- tiling_->UpdateTilesToCurrentPile(invalidation, gfx::Size(200, 200));
+ tiling_->SetRasterSourceAndResize(pile);
+ EXPECT_TRUE(tiling_->TileAt(0, 0));
+ tiling_->Invalidate(invalidation);
EXPECT_FALSE(tiling_->TileAt(0, 0));
}
TEST_F(PictureLayerTilingIteratorTest, CreateMissingTilesStaysInsideLiveRect) {
// The tiling has three rows and columns.
- Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 250));
+ Initialize(gfx::Size(100, 100), 1.f, gfx::Size(250, 250));
EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y());
@@ -245,7 +249,7 @@ TEST_F(PictureLayerTilingIteratorTest, CreateMissingTilesStaysInsideLiveRect) {
TEST_F(PictureLayerTilingIteratorTest, ResizeTilingOverTileBorders) {
// The tiling has four rows and three columns.
- Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350));
+ Initialize(gfx::Size(100, 100), 1.f, gfx::Size(250, 350));
EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
@@ -265,9 +269,10 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeTilingOverTileBorders) {
// Shrink the tiling so that the last tile row/column is entirely in the
// border pixels of the interior tiles. That row/column is removed.
- Region invalidation;
- tiling_->UpdateTilesToCurrentPile(invalidation,
- gfx::Size(right + 1, bottom + 1));
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ gfx::Size(right + 1, bottom + 1));
+ tiling_->SetRasterSourceAndResize(pile);
EXPECT_EQ(2, tiling_->TilingDataForTesting().num_tiles_x());
EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y());
@@ -284,8 +289,9 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeTilingOverTileBorders) {
// Growing outside the current right/bottom tiles border pixels should create
// the tiles again, even though the live rect has not changed size.
- tiling_->UpdateTilesToCurrentPile(invalidation,
- gfx::Size(right + 2, bottom + 2));
+ pile = FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ gfx::Size(right + 2, bottom + 2));
+ tiling_->SetRasterSourceAndResize(pile);
EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
@@ -308,7 +314,7 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeTilingOverTileBorders) {
TEST_F(PictureLayerTilingIteratorTest, ResizeLiveTileRectOverTileBorders) {
// The tiling has three rows and columns.
- Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350));
+ Initialize(gfx::Size(100, 100), 1.f, gfx::Size(250, 350));
EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
@@ -373,7 +379,7 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeLiveTileRectOverTileBorders) {
TEST_F(PictureLayerTilingIteratorTest, ResizeLiveTileRectOverSameTiles) {
// The tiling has four rows and three columns.
- Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350));
+ Initialize(gfx::Size(100, 100), 1.f, gfx::Size(250, 350));
EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
@@ -410,18 +416,22 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeOverBorderPixelsDeletesTiles) {
// deletes tiles that intersect that invalidation.
gfx::Size tile_size(100, 100);
gfx::Size original_layer_size(99, 99);
- Initialize(tile_size, 1.f, original_layer_size);
+ InitializeActive(tile_size, 1.f, original_layer_size);
SetLiveRectAndVerifyTiles(gfx::Rect(original_layer_size));
// Tiling only has one tile, since its total size is less than one.
EXPECT_TRUE(tiling_->TileAt(0, 0));
// Stop creating tiles so that any invalidations are left as holes.
- client_.set_allow_create_tile(false);
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateEmptyPileWithDefaultTileSize(
+ gfx::Size(200, 200));
+ tiling_->SetRasterSourceAndResize(pile);
Region invalidation =
SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
- tiling_->UpdateTilesToCurrentPile(invalidation, gfx::Size(200, 200));
+ EXPECT_TRUE(tiling_->TileAt(0, 0));
+ tiling_->Invalidate(invalidation);
EXPECT_FALSE(tiling_->TileAt(0, 0));
// The original tile was the same size after resize, but it would include new
@@ -431,7 +441,7 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeOverBorderPixelsDeletesTiles) {
}
TEST_F(PictureLayerTilingIteratorTest, LiveTilesExactlyCoverLiveTileRect) {
- Initialize(gfx::Size(100, 100), 1, gfx::Size(1099, 801));
+ Initialize(gfx::Size(100, 100), 1.f, gfx::Size(1099, 801));
SetLiveRectAndVerifyTiles(gfx::Rect(100, 100));
SetLiveRectAndVerifyTiles(gfx::Rect(101, 99));
SetLiveRectAndVerifyTiles(gfx::Rect(1099, 1));
@@ -441,13 +451,13 @@ TEST_F(PictureLayerTilingIteratorTest, LiveTilesExactlyCoverLiveTileRect) {
}
TEST_F(PictureLayerTilingIteratorTest, IteratorCoversLayerBoundsNoScale) {
- Initialize(gfx::Size(100, 100), 1, gfx::Size(1099, 801));
+ Initialize(gfx::Size(100, 100), 1.f, gfx::Size(1099, 801));
VerifyTilesExactlyCoverRect(1, gfx::Rect());
VerifyTilesExactlyCoverRect(1, gfx::Rect(0, 0, 1099, 801));
VerifyTilesExactlyCoverRect(1, gfx::Rect(52, 83, 789, 412));
// With borders, a size of 3x3 = 1 pixel of content.
- Initialize(gfx::Size(3, 3), 1, gfx::Size(10, 10));
+ Initialize(gfx::Size(3, 3), 1.f, gfx::Size(10, 10));
VerifyTilesExactlyCoverRect(1, gfx::Rect(0, 0, 1, 1));
VerifyTilesExactlyCoverRect(1, gfx::Rect(0, 0, 2, 2));
VerifyTilesExactlyCoverRect(1, gfx::Rect(1, 1, 2, 2));
@@ -533,18 +543,21 @@ TEST_F(PictureLayerTilingIteratorTest, NonContainedDestRect) {
TEST(PictureLayerTilingTest, SkewportLimits) {
FakePictureLayerTilingClient client;
- client.set_skewport_extrapolation_limit_in_content_pixels(75);
- client.set_tree(ACTIVE_TREE);
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Rect viewport(0, 0, 100, 100);
gfx::Size layer_bounds(200, 200);
client.SetTileSize(gfx::Size(100, 100));
- tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
+ LayerTreeSettings settings;
+ settings.skewport_extrapolation_limit_in_content_pixels = 75;
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.f, 1.0, Occlusion());
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ settings);
+
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
// Move viewport down 50 pixels in 0.5 seconds.
gfx::Rect down_skewport =
@@ -588,7 +601,7 @@ TEST(PictureLayerTilingTest, SkewportLimits) {
EXPECT_EQ(350, expand_skewport.height());
EXPECT_TRUE(expand_skewport.Contains(gfx::Rect(-50, -50, 200, 200)));
- // Expand the viewport past the limit.
+ // Expand the viewport past the limit in all directions.
gfx::Rect big_expand_skewport =
tiling->ComputeSkewport(1.5, gfx::Rect(-500, -500, 1500, 1500));
@@ -597,21 +610,64 @@ TEST(PictureLayerTilingTest, SkewportLimits) {
EXPECT_EQ(1650, big_expand_skewport.width());
EXPECT_EQ(1650, big_expand_skewport.height());
EXPECT_TRUE(big_expand_skewport.Contains(gfx::Rect(-500, -500, 1500, 1500)));
+
+ // Shrink the skewport in all directions.
+ gfx::Rect shrink_viewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(0, 0, 100, 100));
+ EXPECT_EQ(0, shrink_viewport.x());
+ EXPECT_EQ(0, shrink_viewport.y());
+ EXPECT_EQ(100, shrink_viewport.width());
+ EXPECT_EQ(100, shrink_viewport.height());
+
+ // Move the skewport really far in one direction.
+ gfx::Rect move_skewport_far =
+ tiling->ComputeSkewport(1.5, gfx::Rect(0, 5000, 100, 100));
+ EXPECT_EQ(0, move_skewport_far.x());
+ EXPECT_EQ(5000, move_skewport_far.y());
+ EXPECT_EQ(100, move_skewport_far.width());
+ EXPECT_EQ(175, move_skewport_far.height());
+ EXPECT_TRUE(move_skewport_far.Contains(gfx::Rect(0, 5000, 100, 100)));
+}
+
+TEST(PictureLayerTilingTest, ComputeSkewportExtremeCases) {
+ FakePictureLayerTilingClient client;
+
+ gfx::Size layer_bounds(200, 200);
+ client.SetTileSize(gfx::Size(100, 100));
+ LayerTreeSettings settings;
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ settings);
+
+ gfx::Rect viewport1(-1918, 255860, 4010, 2356);
+ gfx::Rect viewport2(-7088, -91738, 14212, 8350);
+ gfx::Rect viewport3(-12730024, -158883296, 24607540, 14454512);
+ double time = 1.0;
+ tiling->ComputeTilePriorityRects(viewport1, 1.f, time, Occlusion());
+ time += 0.016;
+ EXPECT_TRUE(tiling->ComputeSkewport(time, viewport2).Contains(viewport2));
+ tiling->ComputeTilePriorityRects(viewport2, 1.f, time, Occlusion());
+ time += 0.016;
+ EXPECT_TRUE(tiling->ComputeSkewport(time, viewport3).Contains(viewport3));
}
TEST(PictureLayerTilingTest, ComputeSkewport) {
FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Rect viewport(0, 0, 100, 100);
gfx::Size layer_bounds(200, 200);
client.SetTileSize(gfx::Size(100, 100));
- client.set_tree(ACTIVE_TREE);
- tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.f, 1.0, Occlusion());
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ LayerTreeSettings());
+
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
// Move viewport down 50 pixels in 0.5 seconds.
gfx::Rect down_skewport =
@@ -659,33 +715,105 @@ TEST(PictureLayerTilingTest, ComputeSkewport) {
EXPECT_EQ(160, expanded_skewport.height());
}
+TEST(PictureLayerTilingTest, SkewportThroughUpdateTilePriorities) {
+ FakePictureLayerTilingClient client;
+
+ gfx::Rect viewport(0, 0, 100, 100);
+ gfx::Size layer_bounds(200, 200);
+
+ client.SetTileSize(gfx::Size(100, 100));
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ LayerTreeSettings());
+
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
+
+ // Move viewport down 50 pixels in 0.5 seconds.
+ gfx::Rect viewport_50 = gfx::Rect(0, 50, 100, 100);
+ gfx::Rect skewport_50 = tiling->ComputeSkewport(1.5, viewport_50);
+
+ EXPECT_EQ(gfx::Rect(0, 50, 100, 200), skewport_50);
+ tiling->ComputeTilePriorityRects(viewport_50, 1.f, 1.5, Occlusion());
+
+ gfx::Rect viewport_100 = gfx::Rect(0, 100, 100, 100);
+ gfx::Rect skewport_100 = tiling->ComputeSkewport(2.0, viewport_100);
+
+ EXPECT_EQ(gfx::Rect(0, 100, 100, 200), skewport_100);
+ tiling->ComputeTilePriorityRects(viewport_100, 1.f, 2.0, Occlusion());
+
+ // Advance time, but not the viewport.
+ gfx::Rect result = tiling->ComputeSkewport(2.5, viewport_100);
+ // Since the history did advance, we should still get a skewport but a smaller
+ // one.
+ EXPECT_EQ(gfx::Rect(0, 100, 100, 150), result);
+ tiling->ComputeTilePriorityRects(viewport_100, 1.f, 2.5, Occlusion());
+
+ // Advance time again.
+ result = tiling->ComputeSkewport(3.0, viewport_100);
+ EXPECT_EQ(viewport_100, result);
+ tiling->ComputeTilePriorityRects(viewport_100, 1.f, 3.0, Occlusion());
+
+ // Ensure we have a skewport.
+ gfx::Rect viewport_150 = gfx::Rect(0, 150, 100, 100);
+ gfx::Rect skewport_150 = tiling->ComputeSkewport(3.5, viewport_150);
+ EXPECT_EQ(gfx::Rect(0, 150, 100, 150), skewport_150);
+ tiling->ComputeTilePriorityRects(viewport_150, 1.f, 3.5, Occlusion());
+
+ // Advance the viewport, but not the time.
+ gfx::Rect viewport_200 = gfx::Rect(0, 200, 100, 100);
+ gfx::Rect skewport_200 = tiling->ComputeSkewport(3.5, viewport_200);
+ EXPECT_EQ(gfx::Rect(0, 200, 100, 300), skewport_200);
+
+ // Ensure that continued calls with the same value, produce the same skewport.
+ tiling->ComputeTilePriorityRects(viewport_150, 1.f, 3.5, Occlusion());
+ EXPECT_EQ(gfx::Rect(0, 200, 100, 300), skewport_200);
+ tiling->ComputeTilePriorityRects(viewport_150, 1.f, 3.5, Occlusion());
+ EXPECT_EQ(gfx::Rect(0, 200, 100, 300), skewport_200);
+
+ tiling->ComputeTilePriorityRects(viewport_200, 1.f, 3.5, Occlusion());
+
+ // This should never happen, but advance the viewport yet again keeping the
+ // time the same.
+ gfx::Rect viewport_250 = gfx::Rect(0, 250, 100, 100);
+ gfx::Rect skewport_250 = tiling->ComputeSkewport(3.5, viewport_250);
+ EXPECT_EQ(viewport_250, skewport_250);
+ tiling->ComputeTilePriorityRects(viewport_250, 1.f, 3.5, Occlusion());
+}
+
TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Rect viewport(0, 0, 100, 100);
gfx::Size layer_bounds(1500, 1500);
client.SetTileSize(gfx::Size(10, 10));
- client.set_tree(ACTIVE_TREE);
+ LayerTreeSettings settings;
+ settings.tiling_interest_area_viewport_multiplier = 10000;
// Tiling at 0.25 scale: this should create 47x47 tiles of size 10x10.
// The reason is that each tile has a one pixel border, so tile at (1, 2)
// for instance begins at (8, 16) pixels. So tile at (46, 46) will begin at
// (368, 368) and extend to the end of 1500 * 0.25 = 375 edge of the
// tiling.
- tiling = TestablePictureLayerTiling::Create(0.25f, layer_bounds, &client);
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 0.25f, pile, &client,
+ settings);
gfx::Rect viewport_in_content_space =
gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f));
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.f, 1.0, Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
+ auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
- gfx::Rect soon_rect = viewport;
- soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
- gfx::Rect soon_rect_in_content_space =
- gfx::ToEnclosedRect(gfx::ScaleRect(soon_rect, 0.25f));
+ // Compute the soon border.
+ float inset = PictureLayerTiling::CalculateSoonBorderDistance(
+ viewport_in_content_space, 1.0f / 0.25f);
+ gfx::Rect soon_rect_in_content_space = viewport_in_content_space;
+ soon_rect_in_content_space.Inset(-inset, -inset);
// Sanity checks.
for (int i = 0; i < 47; ++i) {
@@ -707,7 +835,8 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
for (int i = 0; i < 47; ++i) {
for (int j = 0; j < 47; ++j) {
Tile* tile = tiling->TileAt(i, j);
- TilePriority priority = tile->priority(ACTIVE_TREE);
+ PrioritizedTile prioritized_tile = prioritized_tiles[tile];
+ TilePriority priority = prioritized_tile.priority();
gfx::Rect tile_rect = tiling->TilingDataForTesting().TileBounds(i, j);
if (viewport_in_content_space.Intersects(tile_rect)) {
@@ -739,13 +868,13 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
// 41,9 8x8 on all sides.
EXPECT_EQ(tiling->TileAt(5, 1)->content_rect().ToString(), "40,8 10x10");
- TilePriority priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(68.f, priority.distance_to_visible);
- priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(68.f, priority.distance_to_visible);
- priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(40.f, priority.distance_to_visible);
// Move the viewport down 40 pixels.
@@ -754,19 +883,19 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f));
gfx::Rect skewport = tiling->ComputeSkewport(2.0, viewport_in_content_space);
- soon_rect = viewport;
- soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
- soon_rect_in_content_space =
- gfx::ToEnclosedRect(gfx::ScaleRect(soon_rect, 0.25f));
+ // Compute the soon border.
+ inset = PictureLayerTiling::CalculateSoonBorderDistance(
+ viewport_in_content_space, 1.0f / 0.25f);
+ soon_rect_in_content_space = viewport_in_content_space;
+ soon_rect_in_content_space.Inset(-inset, -inset);
EXPECT_EQ(0, skewport.x());
EXPECT_EQ(10, skewport.y());
EXPECT_EQ(25, skewport.width());
EXPECT_EQ(35, skewport.height());
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.f, 2.0, Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 2.0, Occlusion());
+ prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
have_now = false;
have_eventually = false;
@@ -777,7 +906,7 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
for (int i = 0; i < 47; ++i) {
for (int j = 0; j < 47; ++j) {
Tile* tile = tiling->TileAt(i, j);
- TilePriority priority = tile->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tile].priority();
gfx::Rect tile_rect = tiling->TilingDataForTesting().TileBounds(i, j);
if (viewport_in_content_space.Intersects(tile_rect)) {
@@ -807,55 +936,53 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
EXPECT_TRUE(have_soon);
EXPECT_TRUE(have_eventually);
- priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(68.f, priority.distance_to_visible);
- priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(28.f, priority.distance_to_visible);
- priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(4.f, priority.distance_to_visible);
// Change the underlying layer scale.
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 2.0f, 3.0, Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ tiling->ComputeTilePriorityRects(viewport, 2.0f, 3.0, Occlusion());
+ prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
- priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(136.f, priority.distance_to_visible);
- priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(56.f, priority.distance_to_visible);
- priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(8.f, priority.distance_to_visible);
// Test additional scales.
- tiling = TestablePictureLayerTiling::Create(0.2f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 4.0, Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ tiling = TestablePictureLayerTiling::Create(ACTIVE_TREE, 0.2f, pile, &client,
+ LayerTreeSettings());
+ tiling->ComputeTilePriorityRects(viewport, 1.0f, 4.0, Occlusion());
+ prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
- priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(110.f, priority.distance_to_visible);
- priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(70.f, priority.distance_to_visible);
- priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(60.f, priority.distance_to_visible);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 0.5f, 5.0, Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ tiling->ComputeTilePriorityRects(viewport, 0.5f, 5.0, Occlusion());
+ prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
- priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(55.f, priority.distance_to_visible);
- priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(35.f, priority.distance_to_visible);
- priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(30.f, priority.distance_to_visible);
}
@@ -1081,289 +1208,18 @@ TEST(PictureLayerTilingTest, EmptyStartingRect) {
EXPECT_TRUE(out.IsEmpty());
}
-TEST(PictureLayerTilingTest, TilingRasterTileIteratorStaticViewport) {
- FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
-
- gfx::Rect viewport(50, 50, 100, 100);
- gfx::Size layer_bounds(800, 800);
-
- gfx::Rect soon_rect = viewport;
- soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
-
- client.SetTileSize(gfx::Size(30, 30));
- client.set_tree(ACTIVE_TREE);
-
- tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
-
- PictureLayerTiling::TilingRasterTileIterator empty_iterator;
- EXPECT_FALSE(empty_iterator);
-
- std::vector<Tile*> all_tiles = tiling->AllTilesForTesting();
-
- // Sanity check.
- EXPECT_EQ(841u, all_tiles.size());
-
- // The explanation of each iteration is as follows:
- // 1. First iteration tests that we can get all of the tiles correctly.
- // 2. Second iteration ensures that we can get all of the tiles again (first
- // iteration didn't change any tiles), as well set all tiles to be ready to
- // draw.
- // 3. Third iteration ensures that no tiles are returned, since they were all
- // marked as ready to draw.
- for (int i = 0; i < 3; ++i) {
- PictureLayerTiling::TilingRasterTileIterator it(tiling.get());
-
- // There are 3 bins in TilePriority.
- bool have_tiles[3] = {};
-
- // On the third iteration, we should get no tiles since everything was
- // marked as ready to draw.
- if (i == 2) {
- EXPECT_FALSE(it);
- continue;
- }
-
- EXPECT_TRUE(it);
- std::set<Tile*> unique_tiles;
- unique_tiles.insert(*it);
- Tile* last_tile = *it;
- have_tiles[last_tile->priority(ACTIVE_TREE).priority_bin] = true;
-
- // On the second iteration, mark everything as ready to draw (solid color).
- if (i == 1) {
- ManagedTileState::DrawInfo& draw_info = last_tile->draw_info();
- draw_info.SetSolidColorForTesting(SK_ColorRED);
- }
- ++it;
- int eventually_bin_order_correct_count = 0;
- int eventually_bin_order_incorrect_count = 0;
- while (it) {
- Tile* new_tile = *it;
- ++it;
- unique_tiles.insert(new_tile);
-
- TilePriority last_priority = last_tile->priority(ACTIVE_TREE);
- TilePriority new_priority = new_tile->priority(ACTIVE_TREE);
- EXPECT_LE(last_priority.priority_bin, new_priority.priority_bin);
- if (last_priority.priority_bin == new_priority.priority_bin) {
- if (last_priority.priority_bin == TilePriority::EVENTUALLY) {
- bool order_correct = last_priority.distance_to_visible <=
- new_priority.distance_to_visible;
- eventually_bin_order_correct_count += order_correct;
- eventually_bin_order_incorrect_count += !order_correct;
- } else if (!soon_rect.Intersects(new_tile->content_rect()) &&
- !soon_rect.Intersects(last_tile->content_rect())) {
- EXPECT_LE(last_priority.distance_to_visible,
- new_priority.distance_to_visible);
- EXPECT_EQ(TilePriority::NOW, new_priority.priority_bin);
- } else if (new_priority.distance_to_visible > 0.f) {
- EXPECT_EQ(TilePriority::SOON, new_priority.priority_bin);
- }
- }
- have_tiles[new_priority.priority_bin] = true;
-
- last_tile = new_tile;
-
- // On the second iteration, mark everything as ready to draw (solid
- // color).
- if (i == 1) {
- ManagedTileState::DrawInfo& draw_info = last_tile->draw_info();
- draw_info.SetSolidColorForTesting(SK_ColorRED);
- }
- }
-
- EXPECT_GT(eventually_bin_order_correct_count,
- eventually_bin_order_incorrect_count);
-
- // We should have now and eventually tiles, as well as soon tiles from
- // the border region.
- EXPECT_TRUE(have_tiles[TilePriority::NOW]);
- EXPECT_TRUE(have_tiles[TilePriority::SOON]);
- EXPECT_TRUE(have_tiles[TilePriority::EVENTUALLY]);
-
- EXPECT_EQ(unique_tiles.size(), all_tiles.size());
- }
-}
-
-TEST(PictureLayerTilingTest, TilingRasterTileIteratorMovingViewport) {
- FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
-
- gfx::Rect viewport(50, 0, 100, 100);
- gfx::Rect moved_viewport(50, 0, 100, 500);
- gfx::Size layer_bounds(1000, 1000);
-
- client.SetTileSize(gfx::Size(30, 30));
- client.set_tree(ACTIVE_TREE);
-
- tiling = TestablePictureLayerTiling::Create(1.f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, moved_viewport, 1.0f, 2.0, Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
-
- gfx::Rect soon_rect = moved_viewport;
- soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
-
- // There are 3 bins in TilePriority.
- bool have_tiles[3] = {};
- Tile* last_tile = NULL;
- int eventually_bin_order_correct_count = 0;
- int eventually_bin_order_incorrect_count = 0;
- for (PictureLayerTiling::TilingRasterTileIterator it(tiling.get()); it;
- ++it) {
- if (!last_tile)
- last_tile = *it;
-
- Tile* new_tile = *it;
-
- TilePriority last_priority = last_tile->priority(ACTIVE_TREE);
- TilePriority new_priority = new_tile->priority(ACTIVE_TREE);
-
- have_tiles[new_priority.priority_bin] = true;
-
- EXPECT_LE(last_priority.priority_bin, new_priority.priority_bin);
- if (last_priority.priority_bin == new_priority.priority_bin) {
- if (last_priority.priority_bin == TilePriority::EVENTUALLY) {
- bool order_correct = last_priority.distance_to_visible <=
- new_priority.distance_to_visible;
- eventually_bin_order_correct_count += order_correct;
- eventually_bin_order_incorrect_count += !order_correct;
- } else if (!soon_rect.Intersects(new_tile->content_rect()) &&
- !soon_rect.Intersects(last_tile->content_rect())) {
- EXPECT_LE(last_priority.distance_to_visible,
- new_priority.distance_to_visible);
- } else if (new_priority.distance_to_visible > 0.f) {
- EXPECT_EQ(TilePriority::SOON, new_priority.priority_bin);
- }
- }
- last_tile = new_tile;
- }
-
- EXPECT_GT(eventually_bin_order_correct_count,
- eventually_bin_order_incorrect_count);
-
- EXPECT_TRUE(have_tiles[TilePriority::NOW]);
- EXPECT_TRUE(have_tiles[TilePriority::SOON]);
- EXPECT_TRUE(have_tiles[TilePriority::EVENTUALLY]);
-}
-
static void TileExists(bool exists, Tile* tile,
const gfx::Rect& geometry_rect) {
EXPECT_EQ(exists, tile != NULL) << geometry_rect.ToString();
}
-TEST(PictureLayerTilingTest, TilingEvictionTileIteratorStaticViewport) {
- FakeOutputSurfaceClient output_surface_client;
- scoped_ptr<FakeOutputSurface> output_surface = FakeOutputSurface::Create3d();
- CHECK(output_surface->BindToClient(&output_surface_client));
- TestSharedBitmapManager shared_bitmap_manager;
- scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create(
- output_surface.get(), &shared_bitmap_manager, NULL, NULL, 0, false, 1);
-
- FakePictureLayerTilingClient client(resource_provider.get());
- scoped_ptr<TestablePictureLayerTiling> tiling;
-
- gfx::Rect viewport(50, 50, 100, 100);
- gfx::Size layer_bounds(2000, 2000);
-
- client.SetTileSize(gfx::Size(30, 30));
- client.set_tree(ACTIVE_TREE);
-
- tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
-
- PictureLayerTiling::TilingRasterTileIterator empty_iterator;
- EXPECT_FALSE(empty_iterator);
-
- std::vector<Tile*> all_tiles = tiling->AllTilesForTesting();
-
- PictureLayerTiling::TilingEvictionTileIterator it(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::NOW);
-
- // Tiles don't have resources to evict.
- EXPECT_FALSE(it);
-
- // Sanity check.
- EXPECT_EQ(5184u, all_tiles.size());
-
- client.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
-
- std::set<Tile*> all_tiles_set(all_tiles.begin(), all_tiles.end());
-
- std::set<Tile*> eviction_tiles;
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::EVENTUALLY);
- EXPECT_TRUE(it);
- for (; it; ++it) {
- Tile* tile = *it;
- EXPECT_TRUE(tile);
- EXPECT_EQ(TilePriority::EVENTUALLY,
- tile->priority(ACTIVE_TREE).priority_bin);
- EXPECT_FALSE(tile->required_for_activation());
- eviction_tiles.insert(tile);
- }
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::SOON);
- EXPECT_TRUE(it);
- for (; it; ++it) {
- Tile* tile = *it;
- EXPECT_TRUE(tile);
- EXPECT_EQ(TilePriority::SOON, tile->priority(ACTIVE_TREE).priority_bin);
- EXPECT_FALSE(tile->required_for_activation());
- eviction_tiles.insert(tile);
- }
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::NOW);
- EXPECT_TRUE(it);
- for (; it; ++it) {
- Tile* tile = *it;
- EXPECT_TRUE(tile);
- EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin);
- EXPECT_FALSE(tile->required_for_activation());
- eviction_tiles.insert(tile);
- }
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(),
- SMOOTHNESS_TAKES_PRIORITY,
- PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION);
- EXPECT_FALSE(it);
-
- EXPECT_GT(all_tiles_set.size(), 0u);
- EXPECT_EQ(all_tiles_set, eviction_tiles);
-
- EXPECT_TRUE(tiling->eviction_tiles_cache_valid());
- tiling->RemoveTileAt(0, 0, nullptr);
- EXPECT_FALSE(tiling->eviction_tiles_cache_valid());
-
- it = PictureLayerTiling::TilingEvictionTileIterator(
- tiling.get(), SMOOTHNESS_TAKES_PRIORITY,
- PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION);
- EXPECT_TRUE(tiling->eviction_tiles_cache_valid());
- tiling->Reset();
- EXPECT_FALSE(tiling->eviction_tiles_cache_valid());
-}
-
TEST_F(PictureLayerTilingIteratorTest, TilesExist) {
gfx::Size layer_bounds(1099, 801);
Initialize(gfx::Size(100, 100), 1.f, layer_bounds);
VerifyTilesExactlyCoverRect(1.f, gfx::Rect(layer_bounds));
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, false));
- client_.set_tree(ACTIVE_TREE);
tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE,
gfx::Rect(layer_bounds), // visible content rect
1.f, // current contents scale
1.0, // current frame time
@@ -1371,8 +1227,7 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExist) {
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true));
// Make the viewport rect empty. All tiles are killed and become zombies.
- tiling_->ComputeTilePriorityRects(ACTIVE_TREE,
- gfx::Rect(), // visible content rect
+ tiling_->ComputeTilePriorityRects(gfx::Rect(), // visible content rect
1.f, // current contents scale
2.0, // current frame time
Occlusion());
@@ -1387,9 +1242,7 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExistGiantViewport) {
gfx::Rect giant_rect(-10000000, -10000000, 1000000000, 1000000000);
- client_.set_tree(ACTIVE_TREE);
tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE,
gfx::Rect(layer_bounds), // visible content rect
1.f, // current contents scale
1.0, // current frame time
@@ -1397,8 +1250,7 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExistGiantViewport) {
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true));
// If the visible content rect is empty, it should still have live tiles.
- tiling_->ComputeTilePriorityRects(ACTIVE_TREE,
- giant_rect, // visible content rect
+ tiling_->ComputeTilePriorityRects(giant_rect, // visible content rect
1.f, // current contents scale
2.0, // current frame time
Occlusion());
@@ -1416,9 +1268,7 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExistOutsideViewport) {
gfx::Rect viewport_rect(1100, 0, 1000, 1000);
EXPECT_FALSE(viewport_rect.Intersects(gfx::Rect(layer_bounds)));
- client_.set_tree(ACTIVE_TREE);
- tiling_->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_rect, // visible content rect
+ tiling_->ComputeTilePriorityRects(viewport_rect, // visible content rect
1.f, // current contents scale
1.0, // current frame time
Occlusion());
@@ -1439,16 +1289,20 @@ static void TilesIntersectingRectExist(const gfx::Rect& rect,
TEST_F(PictureLayerTilingIteratorTest,
TilesExistLargeViewportAndLayerWithSmallVisibleArea) {
gfx::Size layer_bounds(10000, 10000);
- Initialize(gfx::Size(100, 100), 1.f, layer_bounds);
+ client_.SetTileSize(gfx::Size(100, 100));
+ LayerTreeSettings settings;
+ settings.tiling_interest_area_viewport_multiplier = 1;
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ tiling_ = TestablePictureLayerTiling::Create(PENDING_TREE, 1.f, pile,
+ &client_, settings);
VerifyTilesExactlyCoverRect(1.f, gfx::Rect(layer_bounds));
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, false));
gfx::Rect visible_rect(8000, 8000, 50, 50);
- client_.set_tree(ACTIVE_TREE);
- set_max_tiles_for_interest_area(1);
- tiling_->ComputeTilePriorityRects(ACTIVE_TREE,
- visible_rect, // visible content rect
+ tiling_->ComputeTilePriorityRects(visible_rect, // visible content rect
1.f, // current contents scale
1.0, // current frame time
Occlusion());
@@ -1457,65 +1311,10 @@ TEST_F(PictureLayerTilingIteratorTest,
base::Bind(&TilesIntersectingRectExist, visible_rect, true));
}
-TEST_F(PictureLayerTilingIteratorTest, AddTilingsToMatchScale) {
- gfx::Size layer_bounds(1099, 801);
- gfx::Size tile_size(100, 100);
-
- client_.SetTileSize(tile_size);
- client_.set_tree(PENDING_TREE);
-
- PictureLayerTilingSet active_set(&client_);
-
- active_set.AddTiling(1.f, layer_bounds);
-
- VerifyTiles(active_set.tiling_at(0),
- 1.f,
- gfx::Rect(layer_bounds),
- base::Bind(&TileExists, false));
-
- UpdateAllTilePriorities(&active_set,
- PENDING_TREE,
- gfx::Rect(layer_bounds), // visible content rect
- 1.f, // current contents scale
- 1.0); // current frame time
-
- // The active tiling has tiles now.
- VerifyTiles(active_set.tiling_at(0),
- 1.f,
- gfx::Rect(layer_bounds),
- base::Bind(&TileExists, true));
-
- // Add the same tilings to the pending set.
- PictureLayerTilingSet pending_set(&client_);
- Region invalidation;
- pending_set.SyncTilings(active_set, layer_bounds, invalidation, 0.f);
-
- // The pending tiling starts with no tiles.
- VerifyTiles(pending_set.tiling_at(0),
- 1.f,
- gfx::Rect(layer_bounds),
- base::Bind(&TileExists, false));
-
- // ComputeTilePriorityRects on the pending tiling at the same frame time. The
- // pending tiling should get tiles.
- UpdateAllTilePriorities(&pending_set,
- PENDING_TREE,
- gfx::Rect(layer_bounds), // visible content rect
- 1.f, // current contents scale
- 1.0); // current frame time
-
- VerifyTiles(pending_set.tiling_at(0),
- 1.f,
- gfx::Rect(layer_bounds),
- base::Bind(&TileExists, true));
-}
-
TEST(ComputeTilePriorityRectsTest, VisibleTiles) {
// The TilePriority of visible tiles should have zero distance_to_visible
// and time_to_visible.
-
FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
gfx::Size last_layer_bounds(200, 200);
@@ -1528,36 +1327,37 @@ TEST(ComputeTilePriorityRectsTest, VisibleTiles) {
current_screen_transform, device_viewport);
client.SetTileSize(gfx::Size(100, 100));
- client.set_tree(ACTIVE_TREE);
- tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- current_layer_bounds,
- &client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ current_layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ LayerTreeSettings());
+
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ current_frame_time_in_seconds, Occlusion());
+ auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
ASSERT_TRUE(tiling->TileAt(1, 0));
ASSERT_TRUE(tiling->TileAt(1, 1));
- TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tiling->TileAt(0, 0)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(0, 1)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 0)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
}
@@ -1565,9 +1365,7 @@ TEST(ComputeTilePriorityRectsTest, VisibleTiles) {
TEST(ComputeTilePriorityRectsTest, OffscreenTiles) {
// The TilePriority of offscreen tiles (without movement) should have nonzero
// distance_to_visible and infinite time_to_visible.
-
FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
gfx::Size last_layer_bounds(200, 200);
@@ -1584,56 +1382,55 @@ TEST(ComputeTilePriorityRectsTest, OffscreenTiles) {
current_screen_transform, device_viewport);
client.SetTileSize(gfx::Size(100, 100));
- client.set_tree(ACTIVE_TREE);
- tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- current_layer_bounds,
- &client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ current_layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ LayerTreeSettings());
+
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ current_frame_time_in_seconds, Occlusion());
+ auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
ASSERT_TRUE(tiling->TileAt(1, 0));
ASSERT_TRUE(tiling->TileAt(1, 1));
- TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tiling->TileAt(0, 0)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(0, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 0)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// Furthermore, in this scenario tiles on the right hand side should have a
// larger distance to visible.
- TilePriority left = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- TilePriority right = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+ TilePriority left = prioritized_tiles[tiling->TileAt(0, 0)].priority();
+ TilePriority right = prioritized_tiles[tiling->TileAt(1, 0)].priority();
EXPECT_GT(right.distance_to_visible, left.distance_to_visible);
- left = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- right = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ left = prioritized_tiles[tiling->TileAt(0, 1)].priority();
+ right = prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_GT(right.distance_to_visible, left.distance_to_visible);
}
TEST(ComputeTilePriorityRectsTest, PartiallyOffscreenLayer) {
// Sanity check that a layer with some tiles visible and others offscreen has
// correct TilePriorities for each tile.
-
FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
gfx::Size last_layer_bounds(200, 200);
@@ -1650,36 +1447,37 @@ TEST(ComputeTilePriorityRectsTest, PartiallyOffscreenLayer) {
current_screen_transform, device_viewport);
client.SetTileSize(gfx::Size(100, 100));
- client.set_tree(ACTIVE_TREE);
- tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- current_layer_bounds,
- &client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ current_layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ LayerTreeSettings());
+
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ current_frame_time_in_seconds, Occlusion());
+ auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
ASSERT_TRUE(tiling->TileAt(1, 0));
ASSERT_TRUE(tiling->TileAt(1, 1));
- TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tiling->TileAt(0, 0)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(0, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 0)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
}
@@ -1688,9 +1486,7 @@ TEST(ComputeTilePriorityRectsTest, PartiallyOffscreenRotatedLayer) {
// Each tile of a layer may be affected differently by a transform; Check
// that ComputeTilePriorityRects correctly accounts for the transform between
// layer space and screen space.
-
FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
gfx::Size last_layer_bounds(200, 200);
@@ -1710,44 +1506,46 @@ TEST(ComputeTilePriorityRectsTest, PartiallyOffscreenRotatedLayer) {
current_screen_transform, device_viewport);
client.SetTileSize(gfx::Size(100, 100));
- client.set_tree(ACTIVE_TREE);
- tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- current_layer_bounds,
- &client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ current_layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ LayerTreeSettings());
+
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ current_frame_time_in_seconds, Occlusion());
+ auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
ASSERT_TRUE(tiling->TileAt(1, 0));
ASSERT_TRUE(tiling->TileAt(1, 1));
- TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tiling->TileAt(0, 0)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(0, 1)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 0)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// Furthermore, in this scenario the bottom-right tile should have the larger
// distance to visible.
- TilePriority top_left = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- TilePriority top_right = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- TilePriority bottom_right = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ TilePriority top_left = prioritized_tiles[tiling->TileAt(0, 0)].priority();
+ TilePriority top_right = prioritized_tiles[tiling->TileAt(1, 0)].priority();
+ TilePriority bottom_right =
+ prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_GT(top_right.distance_to_visible, top_left.distance_to_visible);
EXPECT_EQ(bottom_right.distance_to_visible, top_right.distance_to_visible);
@@ -1756,9 +1554,7 @@ TEST(ComputeTilePriorityRectsTest, PartiallyOffscreenRotatedLayer) {
TEST(ComputeTilePriorityRectsTest, PerspectiveLayer) {
// Perspective transforms need to take a different code path.
// This test checks tile priorities of a perspective layer.
-
FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
gfx::Rect visible_layer_rect(0, 0, 0, 0); // offscreen.
@@ -1794,17 +1590,18 @@ TEST(ComputeTilePriorityRectsTest, PerspectiveLayer) {
current_screen_transform, device_viewport);
client.SetTileSize(gfx::Size(100, 100));
- client.set_tree(ACTIVE_TREE);
- tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- current_layer_bounds,
- &client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ current_layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ LayerTreeSettings());
+
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ current_frame_time_in_seconds, Occlusion());
+ auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -1813,29 +1610,30 @@ TEST(ComputeTilePriorityRectsTest, PerspectiveLayer) {
// All tiles will have a positive distance_to_visible
// and an infinite time_to_visible.
- TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tiling->TileAt(0, 0)].priority();
EXPECT_FLOAT_EQ(priority.distance_to_visible, 0.f);
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(0, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 0)].priority();
EXPECT_FLOAT_EQ(priority.distance_to_visible, 0.f);
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// Furthermore, in this scenario the top-left distance_to_visible
// will be smallest, followed by top-right. The bottom layers
// will of course be further than the top layers.
- TilePriority top_left = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- TilePriority top_right = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- TilePriority bottom_left = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- TilePriority bottom_right = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ TilePriority top_left = prioritized_tiles[tiling->TileAt(0, 0)].priority();
+ TilePriority top_right = prioritized_tiles[tiling->TileAt(1, 0)].priority();
+ TilePriority bottom_left = prioritized_tiles[tiling->TileAt(0, 1)].priority();
+ TilePriority bottom_right =
+ prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_GT(bottom_right.distance_to_visible, top_right.distance_to_visible);
@@ -1845,9 +1643,7 @@ TEST(ComputeTilePriorityRectsTest, PerspectiveLayer) {
TEST(ComputeTilePriorityRectsTest, PerspectiveLayerClippedByW) {
// Perspective transforms need to take a different code path.
// This test checks tile priorities of a perspective layer.
-
FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
gfx::Size last_layer_bounds(200, 200);
@@ -1888,17 +1684,18 @@ TEST(ComputeTilePriorityRectsTest, PerspectiveLayerClippedByW) {
current_screen_transform, device_viewport);
client.SetTileSize(gfx::Size(100, 100));
- client.set_tree(ACTIVE_TREE);
- tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- current_layer_bounds,
- &client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ current_layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ LayerTreeSettings());
+
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ current_frame_time_in_seconds, Occlusion());
+ auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -1907,21 +1704,21 @@ TEST(ComputeTilePriorityRectsTest, PerspectiveLayerClippedByW) {
// Left-side tiles will be clipped by the transform, so we have to assume
// they are visible just in case.
- TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tiling->TileAt(0, 0)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(0, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// Right-side tiles will have a positive distance_to_visible
// and an infinite time_to_visible.
- priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 0)].priority();
EXPECT_FLOAT_EQ(priority.distance_to_visible, 0.f);
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
}
@@ -1929,9 +1726,7 @@ TEST(ComputeTilePriorityRectsTest, PerspectiveLayerClippedByW) {
TEST(ComputeTilePriorityRectsTest, BasicMotion) {
// Test that time_to_visible is computed correctly when
// there is some motion.
-
FakePictureLayerTilingClient client;
- scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
gfx::Rect visible_layer_rect(0, 0, 0, 0);
@@ -1952,46 +1747,47 @@ TEST(ComputeTilePriorityRectsTest, BasicMotion) {
current_screen_transform, device_viewport);
client.SetTileSize(gfx::Size(100, 100));
- client.set_tree(ACTIVE_TREE);
- tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- current_layer_bounds,
- &client);
+ LayerTreeSettings settings;
+ settings.tiling_interest_area_viewport_multiplier = 10000;
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ current_layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ settings);
// previous ("last") frame
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
last_layer_contents_scale,
- last_frame_time_in_seconds,
- Occlusion());
+ last_frame_time_in_seconds, Occlusion());
// current frame
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ current_frame_time_in_seconds, Occlusion());
+ auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
ASSERT_TRUE(tiling->TileAt(1, 0));
ASSERT_TRUE(tiling->TileAt(1, 1));
- TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tiling->TileAt(0, 0)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(0, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// time_to_visible for the right hand side layers needs an extra 0.099
// seconds because this tile is 99 pixels further away.
- priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 0)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 1)].priority();
EXPECT_GT(priority.distance_to_visible, 0.f);
EXPECT_NE(TilePriority::NOW, priority.priority_bin);
}
@@ -2031,40 +1827,38 @@ TEST(ComputeTilePriorityRectsTest, RotationMotion) {
current_screen_transform, device_viewport);
client.SetTileSize(gfx::Size(100, 100));
- client.set_tree(ACTIVE_TREE);
- tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- current_layer_bounds,
- &client);
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ current_layer_bounds);
+ tiling = TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client,
+ LayerTreeSettings());
// previous ("last") frame
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
last_layer_contents_scale,
- last_frame_time_in_seconds,
- Occlusion());
+ last_frame_time_in_seconds, Occlusion());
// current frame
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
- tiling->UpdateAllTilePrioritiesForTesting();
+ current_frame_time_in_seconds, Occlusion());
+ auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
ASSERT_TRUE(tiling->TileAt(1, 0));
ASSERT_TRUE(tiling->TileAt(1, 1));
- TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+ TilePriority priority = prioritized_tiles[tiling->TileAt(0, 0)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(0, 1)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
- priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+ priority = prioritized_tiles[tiling->TileAt(1, 0)].priority();
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
}
@@ -2081,96 +1875,93 @@ TEST(PictureLayerTilingTest, RecycledTilesCleared) {
// will be shared next time a pending tiling is created).
FakePictureLayerTilingClient active_client;
- scoped_ptr<TestablePictureLayerTiling> active_tiling;
active_client.SetTileSize(gfx::Size(100, 100));
- active_client.set_tree(ACTIVE_TREE);
- active_client.set_max_tiles_for_interest_area(10);
- active_tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- gfx::Size(10000, 10000),
- &active_client);
+ LayerTreeSettings settings;
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ gfx::Size(10000, 10000));
+ scoped_ptr<TestablePictureLayerTiling> active_tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile,
+ &active_client, settings);
// Create all tiles on this tiling.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion());
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f,
+ Occlusion());
FakePictureLayerTilingClient recycle_client;
recycle_client.SetTileSize(gfx::Size(100, 100));
- recycle_client.set_tree(PENDING_TREE);
recycle_client.set_twin_tiling(active_tiling.get());
- recycle_client.set_max_tiles_for_interest_area(10);
- scoped_ptr<TestablePictureLayerTiling> recycle_tiling;
- recycle_tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- gfx::Size(10000, 10000),
- &recycle_client);
+ pile = FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ gfx::Size(10000, 10000));
+ scoped_ptr<TestablePictureLayerTiling> recycle_tiling =
+ TestablePictureLayerTiling::Create(PENDING_TREE, 1.0f, pile,
+ &recycle_client, settings);
// Create all tiles on the second tiling. All tiles should be shared.
- recycle_tiling->ComputeTilePriorityRects(
- PENDING_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion());
+ recycle_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f,
+ 1.0f, Occlusion());
// Set the second tiling as recycled.
active_client.set_twin_tiling(NULL);
- active_client.set_recycled_twin_tiling(recycle_tiling.get());
recycle_client.set_twin_tiling(NULL);
- // Verify that tiles exist and are shared.
EXPECT_TRUE(active_tiling->TileAt(0, 0));
- EXPECT_TRUE(recycle_tiling->TileAt(0, 0));
- EXPECT_EQ(active_tiling->TileAt(0, 0), recycle_tiling->TileAt(0, 0));
+ EXPECT_FALSE(recycle_tiling->TileAt(0, 0));
// Move the viewport far away from the (0, 0) tile.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(9000, 9000, 100, 100), 1.0f, 2.0, Occlusion());
- // Ensure the tile was deleted on both tilings.
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(9000, 9000, 100, 100), 1.0f,
+ 2.0, Occlusion());
+ // Ensure the tile was deleted.
EXPECT_FALSE(active_tiling->TileAt(0, 0));
EXPECT_FALSE(recycle_tiling->TileAt(0, 0));
// Move the viewport back to (0, 0) tile.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 3.0, Occlusion());
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 3.0,
+ Occlusion());
- // Ensure that we now have a tile here, but the recycle tiling does not.
+ // Ensure that we now have a tile here on both active.
EXPECT_TRUE(active_tiling->TileAt(0, 0));
EXPECT_FALSE(recycle_tiling->TileAt(0, 0));
}
TEST(PictureLayerTilingTest, RecycledTilesClearedOnReset) {
FakePictureLayerTilingClient active_client;
- scoped_ptr<TestablePictureLayerTiling> active_tiling;
-
active_client.SetTileSize(gfx::Size(100, 100));
- active_client.set_tree(ACTIVE_TREE);
- active_tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- gfx::Size(100, 100),
- &active_client);
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ gfx::Size(100, 100));
+ scoped_ptr<TestablePictureLayerTiling> active_tiling =
+ TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile,
+ &active_client, LayerTreeSettings());
// Create all tiles on this tiling.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion());
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f,
+ Occlusion());
FakePictureLayerTilingClient recycle_client;
recycle_client.SetTileSize(gfx::Size(100, 100));
- recycle_client.set_tree(PENDING_TREE);
recycle_client.set_twin_tiling(active_tiling.get());
- recycle_client.set_max_tiles_for_interest_area(10);
- scoped_ptr<TestablePictureLayerTiling> recycle_tiling;
- recycle_tiling = TestablePictureLayerTiling::Create(1.0f, // contents_scale
- gfx::Size(100, 100),
- &recycle_client);
+ LayerTreeSettings settings;
+
+ pile = FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ gfx::Size(100, 100));
+ scoped_ptr<TestablePictureLayerTiling> recycle_tiling =
+ TestablePictureLayerTiling::Create(PENDING_TREE, 1.0f, pile,
+ &recycle_client, settings);
// Create all tiles on the recycle tiling. All tiles should be shared.
- recycle_tiling->ComputeTilePriorityRects(
- PENDING_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion());
+ recycle_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f,
+ 1.0f, Occlusion());
// Set the second tiling as recycled.
active_client.set_twin_tiling(NULL);
- active_client.set_recycled_twin_tiling(recycle_tiling.get());
recycle_client.set_twin_tiling(NULL);
- // Verify that tiles exist and are shared.
EXPECT_TRUE(active_tiling->TileAt(0, 0));
- EXPECT_TRUE(recycle_tiling->TileAt(0, 0));
- EXPECT_EQ(active_tiling->TileAt(0, 0), recycle_tiling->TileAt(0, 0));
+ EXPECT_FALSE(recycle_tiling->TileAt(0, 0));
// Reset the active tiling. The recycle tiles should be released too.
active_tiling->Reset();
@@ -2178,5 +1969,31 @@ TEST(PictureLayerTilingTest, RecycledTilesClearedOnReset) {
EXPECT_FALSE(recycle_tiling->TileAt(0, 0));
}
+TEST_F(PictureLayerTilingIteratorTest, ResizeTilesAndUpdateToCurrent) {
+ // The tiling has four rows and three columns.
+ Initialize(gfx::Size(150, 100), 1.f, gfx::Size(250, 150));
+ tiling_->CreateAllTilesForTesting();
+ EXPECT_EQ(150, tiling_->TilingDataForTesting().max_texture_size().width());
+ EXPECT_EQ(100, tiling_->TilingDataForTesting().max_texture_size().height());
+ EXPECT_EQ(4u, tiling_->AllTilesForTesting().size());
+
+ client_.SetTileSize(gfx::Size(250, 200));
+
+ // Tile size in the tiling should still be 150x100.
+ EXPECT_EQ(150, tiling_->TilingDataForTesting().max_texture_size().width());
+ EXPECT_EQ(100, tiling_->TilingDataForTesting().max_texture_size().height());
+
+ // The layer's size isn't changed, but the tile size was.
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ gfx::Size(250, 150));
+ tiling_->SetRasterSourceAndResize(pile);
+
+ // Tile size in the tiling should be resized to 250x200.
+ EXPECT_EQ(250, tiling_->TilingDataForTesting().max_texture_size().width());
+ EXPECT_EQ(200, tiling_->TilingDataForTesting().max_texture_size().height());
+ EXPECT_EQ(0u, tiling_->AllTilesForTesting().size());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/tiles/prioritized_tile.cc b/chromium/cc/tiles/prioritized_tile.cc
new file mode 100644
index 00000000000..67f33c9dbc8
--- /dev/null
+++ b/chromium/cc/tiles/prioritized_tile.cc
@@ -0,0 +1,41 @@
+// 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.
+
+#include "cc/tiles/prioritized_tile.h"
+
+#include "cc/debug/traced_value.h"
+#include "cc/tiles/picture_layer_tiling.h"
+
+namespace cc {
+
+PrioritizedTile::PrioritizedTile()
+ : tile_(nullptr), raster_source_(nullptr), is_occluded_(false) {
+}
+
+PrioritizedTile::PrioritizedTile(Tile* tile,
+ RasterSource* raster_source,
+ const TilePriority priority,
+ bool is_occluded)
+ : tile_(tile),
+ raster_source_(raster_source),
+ priority_(priority),
+ is_occluded_(is_occluded) {
+}
+
+PrioritizedTile::~PrioritizedTile() {
+}
+
+void PrioritizedTile::AsValueInto(base::trace_event::TracedValue* value) const {
+ tile_->AsValueInto(value);
+
+ TracedValue::SetIDRef(raster_source(), value, "picture_pile");
+
+ value->BeginDictionary("combined_priority");
+ priority().AsValueInto(value);
+ value->EndDictionary();
+
+ value->SetString("resolution", TileResolutionToString(priority().resolution));
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/prioritized_tile.h b/chromium/cc/tiles/prioritized_tile.h
new file mode 100644
index 00000000000..6811d903a50
--- /dev/null
+++ b/chromium/cc/tiles/prioritized_tile.h
@@ -0,0 +1,46 @@
+// 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_TILES_PRIORITIZED_TILE_H_
+#define CC_TILES_PRIORITIZED_TILE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_priority.h"
+
+namespace cc {
+class PictureLayerTiling;
+class RasterSource;
+
+class CC_EXPORT PrioritizedTile {
+ public:
+ // This class is constructed and returned by a |PictureLayerTiling|, and
+ // represents a tile and its priority.
+ PrioritizedTile();
+ ~PrioritizedTile();
+
+ Tile* tile() const { return tile_; }
+ RasterSource* raster_source() const { return raster_source_; }
+ const TilePriority& priority() const { return priority_; }
+ bool is_occluded() const { return is_occluded_; }
+
+ void AsValueInto(base::trace_event::TracedValue* value) const;
+
+ private:
+ friend class PictureLayerTiling;
+
+ PrioritizedTile(Tile* tile,
+ RasterSource* raster_source,
+ const TilePriority priority,
+ bool is_occluded);
+
+ Tile* tile_;
+ RasterSource* raster_source_;
+ TilePriority priority_;
+ bool is_occluded_;
+};
+
+} // namespace cc
+
+#endif // CC_TILES_PRIORITIZED_TILE_H_
diff --git a/chromium/cc/tiles/raster_tile_priority_queue.cc b/chromium/cc/tiles/raster_tile_priority_queue.cc
new file mode 100644
index 00000000000..afa37555ef6
--- /dev/null
+++ b/chromium/cc/tiles/raster_tile_priority_queue.cc
@@ -0,0 +1,37 @@
+// 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.
+
+#include "cc/tiles/raster_tile_priority_queue.h"
+
+#include "cc/tiles/raster_tile_priority_queue_all.h"
+#include "cc/tiles/raster_tile_priority_queue_required.h"
+
+namespace cc {
+
+// static
+scoped_ptr<RasterTilePriorityQueue> RasterTilePriorityQueue::Create(
+ const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers,
+ TreePriority tree_priority,
+ Type type) {
+ switch (type) {
+ case Type::ALL: {
+ scoped_ptr<RasterTilePriorityQueueAll> queue(
+ new RasterTilePriorityQueueAll);
+ queue->Build(active_layers, pending_layers, tree_priority);
+ return queue.Pass();
+ }
+ case Type::REQUIRED_FOR_ACTIVATION:
+ case Type::REQUIRED_FOR_DRAW: {
+ scoped_ptr<RasterTilePriorityQueueRequired> queue(
+ new RasterTilePriorityQueueRequired);
+ queue->Build(active_layers, pending_layers, type);
+ return queue.Pass();
+ }
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/raster_tile_priority_queue.h b/chromium/cc/tiles/raster_tile_priority_queue.h
new file mode 100644
index 00000000000..e2187d2c627
--- /dev/null
+++ b/chromium/cc/tiles/raster_tile_priority_queue.h
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TILES_RASTER_TILE_PRIORITY_QUEUE_H_
+#define CC_TILES_RASTER_TILE_PRIORITY_QUEUE_H_
+
+#include <vector>
+
+#include "cc/base/cc_export.h"
+#include "cc/layers/picture_layer_impl.h"
+#include "cc/tiles/tile_priority.h"
+
+namespace cc {
+class PrioritizedTile;
+
+class CC_EXPORT RasterTilePriorityQueue {
+ public:
+ enum class Type { ALL, REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW };
+
+ static scoped_ptr<RasterTilePriorityQueue> Create(
+ const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers,
+ TreePriority tree_priority,
+ Type type);
+
+ virtual ~RasterTilePriorityQueue() {}
+
+ virtual bool IsEmpty() const = 0;
+ virtual const PrioritizedTile& Top() const = 0;
+ virtual void Pop() = 0;
+
+ protected:
+ RasterTilePriorityQueue() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RasterTilePriorityQueue);
+};
+
+} // namespace cc
+
+#endif // CC_TILES_RASTER_TILE_PRIORITY_QUEUE_H_
diff --git a/chromium/cc/tiles/raster_tile_priority_queue_all.cc b/chromium/cc/tiles/raster_tile_priority_queue_all.cc
new file mode 100644
index 00000000000..8f7bdbf0436
--- /dev/null
+++ b/chromium/cc/tiles/raster_tile_priority_queue_all.cc
@@ -0,0 +1,170 @@
+// 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.
+
+#include "cc/tiles/raster_tile_priority_queue_all.h"
+
+#include "cc/tiles/tiling_set_raster_queue_all.h"
+
+namespace cc {
+
+namespace {
+
+class RasterOrderComparator {
+ public:
+ explicit RasterOrderComparator(TreePriority tree_priority)
+ : tree_priority_(tree_priority) {}
+
+ bool operator()(const TilingSetRasterQueueAll* a_queue,
+ const TilingSetRasterQueueAll* b_queue) const {
+ // Note that in this function, we have to return true if and only if
+ // a is strictly lower priority than b.
+ const TilePriority& a_priority = a_queue->Top().priority();
+ const TilePriority& b_priority = b_queue->Top().priority();
+ bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY;
+
+ // If the bin is the same but the resolution is not, then the order will be
+ // determined by whether we prioritize low res or not.
+ // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile
+ // class but instead produced by the iterators.
+ if (b_priority.priority_bin == a_priority.priority_bin &&
+ b_priority.resolution != a_priority.resolution) {
+ // Non ideal resolution should be sorted lower than other resolutions.
+ if (a_priority.resolution == NON_IDEAL_RESOLUTION)
+ return true;
+
+ if (b_priority.resolution == NON_IDEAL_RESOLUTION)
+ return false;
+
+ if (prioritize_low_res)
+ return b_priority.resolution == LOW_RESOLUTION;
+ return b_priority.resolution == HIGH_RESOLUTION;
+ }
+
+ return b_priority.IsHigherPriorityThan(a_priority);
+ }
+
+ private:
+ TreePriority tree_priority_;
+};
+
+void CreateTilingSetRasterQueues(
+ const std::vector<PictureLayerImpl*>& layers,
+ TreePriority tree_priority,
+ ScopedPtrVector<TilingSetRasterQueueAll>* queues) {
+ DCHECK(queues->empty());
+
+ for (auto* layer : layers) {
+ if (!layer->HasValidTilePriorities())
+ continue;
+
+ PictureLayerTilingSet* tiling_set = layer->picture_layer_tiling_set();
+ bool prioritize_low_res = tree_priority == SMOOTHNESS_TAKES_PRIORITY;
+ scoped_ptr<TilingSetRasterQueueAll> tiling_set_queue = make_scoped_ptr(
+ new TilingSetRasterQueueAll(tiling_set, prioritize_low_res));
+ // Queues will only contain non empty tiling sets.
+ if (!tiling_set_queue->IsEmpty())
+ queues->push_back(tiling_set_queue.Pass());
+ }
+ queues->make_heap(RasterOrderComparator(tree_priority));
+}
+
+} // namespace
+
+RasterTilePriorityQueueAll::RasterTilePriorityQueueAll() {
+}
+
+RasterTilePriorityQueueAll::~RasterTilePriorityQueueAll() {
+}
+
+void RasterTilePriorityQueueAll::Build(
+ const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers,
+ TreePriority tree_priority) {
+ tree_priority_ = tree_priority;
+
+ CreateTilingSetRasterQueues(active_layers, tree_priority_, &active_queues_);
+ CreateTilingSetRasterQueues(pending_layers, tree_priority_, &pending_queues_);
+}
+
+bool RasterTilePriorityQueueAll::IsEmpty() const {
+ return active_queues_.empty() && pending_queues_.empty();
+}
+
+const PrioritizedTile& RasterTilePriorityQueueAll::Top() const {
+ DCHECK(!IsEmpty());
+ const ScopedPtrVector<TilingSetRasterQueueAll>& next_queues = GetNextQueues();
+ return next_queues.front()->Top();
+}
+
+void RasterTilePriorityQueueAll::Pop() {
+ DCHECK(!IsEmpty());
+
+ ScopedPtrVector<TilingSetRasterQueueAll>& next_queues = GetNextQueues();
+ next_queues.pop_heap(RasterOrderComparator(tree_priority_));
+ TilingSetRasterQueueAll* queue = next_queues.back();
+ queue->Pop();
+
+ // Remove empty queues.
+ if (queue->IsEmpty())
+ next_queues.pop_back();
+ else
+ next_queues.push_heap(RasterOrderComparator(tree_priority_));
+}
+
+ScopedPtrVector<TilingSetRasterQueueAll>&
+RasterTilePriorityQueueAll::GetNextQueues() {
+ return const_cast<ScopedPtrVector<TilingSetRasterQueueAll>&>(
+ static_cast<const RasterTilePriorityQueueAll*>(this)->GetNextQueues());
+}
+
+const ScopedPtrVector<TilingSetRasterQueueAll>&
+RasterTilePriorityQueueAll::GetNextQueues() const {
+ DCHECK(!IsEmpty());
+
+ // If we only have one queue with tiles, return it.
+ if (active_queues_.empty())
+ return pending_queues_;
+ if (pending_queues_.empty())
+ return active_queues_;
+
+ const PrioritizedTile& active_tile = active_queues_.front()->Top();
+ const PrioritizedTile& pending_tile = pending_queues_.front()->Top();
+
+ const TilePriority& active_priority = active_tile.priority();
+ const TilePriority& pending_priority = pending_tile.priority();
+
+ switch (tree_priority_) {
+ case SMOOTHNESS_TAKES_PRIORITY: {
+ // If we're down to eventually bin tiles on the active tree, process the
+ // pending tree to allow tiles required for activation to be initialized
+ // when memory policy only allows prepaint.
+ if (active_priority.priority_bin == TilePriority::EVENTUALLY &&
+ pending_priority.priority_bin == TilePriority::NOW) {
+ return pending_queues_;
+ }
+ return active_queues_;
+ }
+ case NEW_CONTENT_TAKES_PRIORITY: {
+ // If we're down to soon bin tiles on the pending tree, process the
+ // active tree to allow tiles required for activation to be initialized
+ // when memory policy only allows prepaint. Note that active required for
+ // activation tiles might come from either now or soon bins.
+ if (pending_priority.priority_bin >= TilePriority::SOON &&
+ active_priority.priority_bin <= TilePriority::SOON) {
+ return active_queues_;
+ }
+ return pending_queues_;
+ }
+ case SAME_PRIORITY_FOR_BOTH_TREES: {
+ if (active_priority.IsHigherPriorityThan(pending_priority))
+ return active_queues_;
+ return pending_queues_;
+ }
+ default:
+ NOTREACHED();
+ return active_queues_;
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/raster_tile_priority_queue_all.h b/chromium/cc/tiles/raster_tile_priority_queue_all.h
new file mode 100644
index 00000000000..507467f4371
--- /dev/null
+++ b/chromium/cc/tiles/raster_tile_priority_queue_all.h
@@ -0,0 +1,48 @@
+// 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_TILES_RASTER_TILE_PRIORITY_QUEUE_ALL_H_
+#define CC_TILES_RASTER_TILE_PRIORITY_QUEUE_ALL_H_
+
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "cc/base/cc_export.h"
+#include "cc/layers/picture_layer_impl.h"
+#include "cc/tiles/raster_tile_priority_queue.h"
+#include "cc/tiles/tile_priority.h"
+#include "cc/tiles/tiling_set_raster_queue_all.h"
+
+namespace cc {
+
+class CC_EXPORT RasterTilePriorityQueueAll : public RasterTilePriorityQueue {
+ public:
+ RasterTilePriorityQueueAll();
+ ~RasterTilePriorityQueueAll() override;
+
+ bool IsEmpty() const override;
+ const PrioritizedTile& Top() const override;
+ void Pop() override;
+
+ private:
+ friend class RasterTilePriorityQueue;
+
+ void Build(const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers,
+ TreePriority tree_priority);
+
+ ScopedPtrVector<TilingSetRasterQueueAll>& GetNextQueues();
+ const ScopedPtrVector<TilingSetRasterQueueAll>& GetNextQueues() const;
+
+ ScopedPtrVector<TilingSetRasterQueueAll> active_queues_;
+ ScopedPtrVector<TilingSetRasterQueueAll> pending_queues_;
+ TreePriority tree_priority_;
+
+ DISALLOW_COPY_AND_ASSIGN(RasterTilePriorityQueueAll);
+};
+
+} // namespace cc
+
+#endif // CC_TILES_RASTER_TILE_PRIORITY_QUEUE_ALL_H_
diff --git a/chromium/cc/tiles/raster_tile_priority_queue_required.cc b/chromium/cc/tiles/raster_tile_priority_queue_required.cc
new file mode 100644
index 00000000000..bccc34bc6c3
--- /dev/null
+++ b/chromium/cc/tiles/raster_tile_priority_queue_required.cc
@@ -0,0 +1,85 @@
+// 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.
+
+#include "cc/tiles/raster_tile_priority_queue_required.h"
+
+#include "cc/tiles/tiling_set_raster_queue_required.h"
+
+namespace cc {
+
+namespace {
+
+void AppendTilingSetRequiredQueues(
+ const std::vector<PictureLayerImpl*>& layers,
+ ScopedPtrVector<TilingSetRasterQueueRequired>* queues) {
+ for (auto* layer : layers) {
+ if (!layer->HasValidTilePriorities())
+ continue;
+
+ scoped_ptr<TilingSetRasterQueueRequired> tiling_set_queue(
+ new TilingSetRasterQueueRequired(
+ layer->picture_layer_tiling_set(),
+ RasterTilePriorityQueueRequired::Type::REQUIRED_FOR_ACTIVATION));
+ if (!tiling_set_queue->IsEmpty())
+ queues->push_back(tiling_set_queue.Pass());
+ }
+}
+
+} // namespace
+
+RasterTilePriorityQueueRequired::RasterTilePriorityQueueRequired() {
+}
+
+RasterTilePriorityQueueRequired::~RasterTilePriorityQueueRequired() {
+}
+
+void RasterTilePriorityQueueRequired::Build(
+ const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers,
+ Type type) {
+ DCHECK_NE(static_cast<int>(type), static_cast<int>(Type::ALL));
+ if (type == Type::REQUIRED_FOR_DRAW)
+ BuildRequiredForDraw(active_layers);
+ else
+ BuildRequiredForActivation(active_layers, pending_layers);
+}
+
+void RasterTilePriorityQueueRequired::BuildRequiredForDraw(
+ const std::vector<PictureLayerImpl*>& active_layers) {
+ for (const auto& layer : active_layers) {
+ if (!layer->HasValidTilePriorities())
+ continue;
+
+ scoped_ptr<TilingSetRasterQueueRequired> tiling_set_queue(
+ new TilingSetRasterQueueRequired(layer->picture_layer_tiling_set(),
+ Type::REQUIRED_FOR_DRAW));
+ if (!tiling_set_queue->IsEmpty())
+ tiling_set_queues_.push_back(tiling_set_queue.Pass());
+ }
+}
+
+void RasterTilePriorityQueueRequired::BuildRequiredForActivation(
+ const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers) {
+ AppendTilingSetRequiredQueues(active_layers, &tiling_set_queues_);
+ AppendTilingSetRequiredQueues(pending_layers, &tiling_set_queues_);
+}
+
+bool RasterTilePriorityQueueRequired::IsEmpty() const {
+ return tiling_set_queues_.empty();
+}
+
+const PrioritizedTile& RasterTilePriorityQueueRequired::Top() const {
+ DCHECK(!IsEmpty());
+ return tiling_set_queues_.back()->Top();
+}
+
+void RasterTilePriorityQueueRequired::Pop() {
+ DCHECK(!IsEmpty());
+ tiling_set_queues_.back()->Pop();
+ if (tiling_set_queues_.back()->IsEmpty())
+ tiling_set_queues_.pop_back();
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/raster_tile_priority_queue_required.h b/chromium/cc/tiles/raster_tile_priority_queue_required.h
new file mode 100644
index 00000000000..c554c189869
--- /dev/null
+++ b/chromium/cc/tiles/raster_tile_priority_queue_required.h
@@ -0,0 +1,45 @@
+// 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_TILES_RASTER_TILE_PRIORITY_QUEUE_REQUIRED_H_
+#define CC_TILES_RASTER_TILE_PRIORITY_QUEUE_REQUIRED_H_
+
+#include <vector>
+
+#include "cc/layers/picture_layer_impl.h"
+#include "cc/tiles/raster_tile_priority_queue.h"
+#include "cc/tiles/tiling_set_raster_queue_required.h"
+
+namespace cc {
+class PrioritizedTile;
+
+class RasterTilePriorityQueueRequired : public RasterTilePriorityQueue {
+ public:
+ RasterTilePriorityQueueRequired();
+ ~RasterTilePriorityQueueRequired() override;
+
+ bool IsEmpty() const override;
+ const PrioritizedTile& Top() const override;
+ void Pop() override;
+
+ private:
+ friend class RasterTilePriorityQueue;
+
+ void Build(const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers,
+ Type type);
+ void BuildRequiredForDraw(
+ const std::vector<PictureLayerImpl*>& active_layers);
+ void BuildRequiredForActivation(
+ const std::vector<PictureLayerImpl*>& active_layers,
+ const std::vector<PictureLayerImpl*>& pending_layers);
+
+ ScopedPtrVector<TilingSetRasterQueueRequired> tiling_set_queues_;
+
+ DISALLOW_COPY_AND_ASSIGN(RasterTilePriorityQueueRequired);
+};
+
+} // namespace cc
+
+#endif // CC_TILES_RASTER_TILE_PRIORITY_QUEUE_REQUIRED_H_
diff --git a/chromium/cc/tiles/tile.cc b/chromium/cc/tiles/tile.cc
new file mode 100644
index 00000000000..da4c08018d5
--- /dev/null
+++ b/chromium/cc/tiles/tile.cc
@@ -0,0 +1,78 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/tiles/tile.h"
+
+#include <algorithm>
+
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/base/math_util.h"
+#include "cc/debug/traced_value.h"
+#include "cc/tiles/tile_manager.h"
+
+namespace cc {
+
+Tile::Id Tile::s_next_id_ = 0;
+
+Tile::Tile(TileManager* tile_manager,
+ const gfx::Size& desired_texture_size,
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ int layer_id,
+ int source_frame_number,
+ int flags)
+ : tile_manager_(tile_manager),
+ desired_texture_size_(desired_texture_size),
+ content_rect_(content_rect),
+ contents_scale_(contents_scale),
+ layer_id_(layer_id),
+ source_frame_number_(source_frame_number),
+ flags_(flags),
+ tiling_i_index_(-1),
+ tiling_j_index_(-1),
+ required_for_activation_(false),
+ required_for_draw_(false),
+ id_(s_next_id_++),
+ scheduled_priority_(0) {
+}
+
+Tile::~Tile() {
+ TRACE_EVENT_OBJECT_DELETED_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "cc::Tile", this);
+}
+
+void Tile::AsValueInto(base::trace_event::TracedValue* value) const {
+ TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug"), value, "cc::Tile", this);
+ value->SetDouble("contents_scale", contents_scale_);
+
+ MathUtil::AddToTracedValue("content_rect", content_rect_, value);
+
+ value->SetInteger("layer_id", layer_id_);
+
+ value->BeginDictionary("draw_info");
+ draw_info_.AsValueInto(value);
+ value->EndDictionary();
+
+ value->SetBoolean("has_resource", draw_info().has_resource());
+ value->SetBoolean("is_using_gpu_memory",
+ draw_info().has_resource() || HasRasterTask());
+ value->SetInteger("scheduled_priority", scheduled_priority_);
+ value->SetBoolean("use_picture_analysis", use_picture_analysis());
+ value->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes());
+}
+
+size_t Tile::GPUMemoryUsageInBytes() const {
+ if (draw_info_.resource_)
+ return draw_info_.resource_->bytes();
+ return 0;
+}
+
+void Tile::Deleter::operator()(Tile* tile) const {
+ TileManager* tile_manager = tile->tile_manager_;
+ tile_manager->Release(tile);
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/tile.h b/chromium/cc/tiles/tile.h
new file mode 100644
index 00000000000..68c4fc13e34
--- /dev/null
+++ b/chromium/cc/tiles/tile.h
@@ -0,0 +1,117 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TILES_TILE_H_
+#define CC_TILES_TILE_H_
+
+#include "base/memory/ref_counted.h"
+#include "cc/tiles/tile_draw_info.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace cc {
+
+class PrioritizedTile;
+class TileManager;
+struct TilePriority;
+
+class CC_EXPORT Tile {
+ public:
+ class CC_EXPORT Deleter {
+ public:
+ void operator()(Tile* tile) const;
+ };
+
+ enum TileRasterFlags { USE_PICTURE_ANALYSIS = 1 << 0 };
+
+ typedef uint64 Id;
+
+ Id id() const {
+ return id_;
+ }
+
+ // TODO(vmpstr): Move this to the iterators.
+ bool required_for_activation() const { return required_for_activation_; }
+ void set_required_for_activation(bool is_required) {
+ required_for_activation_ = is_required;
+ }
+ bool required_for_draw() const { return required_for_draw_; }
+ void set_required_for_draw(bool is_required) {
+ required_for_draw_ = is_required;
+ }
+
+ bool use_picture_analysis() const {
+ return !!(flags_ & USE_PICTURE_ANALYSIS);
+ }
+
+ void AsValueInto(base::trace_event::TracedValue* value) const;
+
+ const TileDrawInfo& draw_info() const { return draw_info_; }
+ TileDrawInfo& draw_info() { return draw_info_; }
+
+ float contents_scale() const { return contents_scale_; }
+ gfx::Rect content_rect() const { return content_rect_; }
+
+ int layer_id() const { return layer_id_; }
+
+ int source_frame_number() const { return source_frame_number_; }
+
+ size_t GPUMemoryUsageInBytes() const;
+
+ gfx::Size desired_texture_size() const { return desired_texture_size_; }
+
+ void set_tiling_index(int i, int j) {
+ tiling_i_index_ = i;
+ tiling_j_index_ = j;
+ }
+ int tiling_i_index() const { return tiling_i_index_; }
+ int tiling_j_index() const { return tiling_j_index_; }
+
+ private:
+ friend class TileManager;
+ friend class FakeTileManager;
+ friend class FakePictureLayerImpl;
+
+ // Methods called by by tile manager.
+ Tile(TileManager* tile_manager,
+ const gfx::Size& desired_texture_size,
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ int layer_id,
+ int source_frame_number,
+ int flags);
+ ~Tile();
+
+ bool HasRasterTask() const { return !!raster_task_.get(); }
+
+ TileManager* tile_manager_;
+ gfx::Size desired_texture_size_;
+ gfx::Rect content_rect_;
+ float contents_scale_;
+
+ TileDrawInfo draw_info_;
+
+ int layer_id_;
+ int source_frame_number_;
+ int flags_;
+ int tiling_i_index_;
+ int tiling_j_index_;
+ bool required_for_activation_ : 1;
+ bool required_for_draw_ : 1;
+
+ Id id_;
+ static Id s_next_id_;
+
+ unsigned scheduled_priority_;
+
+ scoped_refptr<RasterTask> raster_task_;
+
+ DISALLOW_COPY_AND_ASSIGN(Tile);
+};
+
+using ScopedTilePtr = scoped_ptr<Tile, Tile::Deleter>;
+
+} // namespace cc
+
+#endif // CC_TILES_TILE_H_
diff --git a/chromium/cc/tiles/tile_draw_info.cc b/chromium/cc/tiles/tile_draw_info.cc
new file mode 100644
index 00000000000..e523079aac9
--- /dev/null
+++ b/chromium/cc/tiles/tile_draw_info.cc
@@ -0,0 +1,25 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/tiles/tile_draw_info.h"
+
+#include "cc/base/math_util.h"
+
+namespace cc {
+
+TileDrawInfo::TileDrawInfo()
+ : mode_(RESOURCE_MODE), solid_color_(SK_ColorWHITE) {
+}
+
+TileDrawInfo::~TileDrawInfo() {
+ DCHECK(!resource_);
+}
+
+void TileDrawInfo::AsValueInto(base::trace_event::TracedValue* state) const {
+ state->SetBoolean("is_solid_color", mode_ == SOLID_COLOR_MODE);
+ state->SetBoolean("is_transparent",
+ mode_ == SOLID_COLOR_MODE && !SkColorGetA(solid_color_));
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/tile_draw_info.h b/chromium/cc/tiles/tile_draw_info.h
new file mode 100644
index 00000000000..f094efd6f38
--- /dev/null
+++ b/chromium/cc/tiles/tile_draw_info.h
@@ -0,0 +1,106 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TILES_TILE_DRAW_INFO_H_
+#define CC_TILES_TILE_DRAW_INFO_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "cc/raster/tile_task_runner.h"
+#include "cc/resources/platform_color.h"
+#include "cc/resources/resource_provider.h"
+#include "cc/resources/scoped_resource.h"
+
+namespace cc {
+
+// This class holds all the state relevant to drawing a tile.
+class CC_EXPORT TileDrawInfo {
+ public:
+ enum Mode { RESOURCE_MODE, SOLID_COLOR_MODE, OOM_MODE };
+
+ TileDrawInfo();
+ ~TileDrawInfo();
+
+ Mode mode() const { return mode_; }
+
+ bool IsReadyToDraw() const {
+ switch (mode_) {
+ case RESOURCE_MODE:
+ return !!resource_;
+ case SOLID_COLOR_MODE:
+ case OOM_MODE:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+ }
+ bool NeedsRaster() const {
+ switch (mode_) {
+ case RESOURCE_MODE:
+ return !resource_;
+ case SOLID_COLOR_MODE:
+ return false;
+ case OOM_MODE:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+ }
+
+ ResourceProvider::ResourceId resource_id() const {
+ DCHECK(mode_ == RESOURCE_MODE);
+ DCHECK(resource_);
+ return resource_->id();
+ }
+
+ gfx::Size resource_size() const {
+ DCHECK(mode_ == RESOURCE_MODE);
+ DCHECK(resource_);
+ return resource_->size();
+ }
+
+ SkColor solid_color() const {
+ DCHECK(mode_ == SOLID_COLOR_MODE);
+ return solid_color_;
+ }
+
+ bool contents_swizzled() const {
+ DCHECK(resource_);
+ return !PlatformColor::SameComponentOrder(resource_->format());
+ }
+
+ bool requires_resource() const {
+ return mode_ == RESOURCE_MODE || mode_ == OOM_MODE;
+ }
+
+ inline bool has_resource() const { return !!resource_; }
+
+ void SetSolidColorForTesting(SkColor color) { set_solid_color(color); }
+ void SetResourceForTesting(scoped_ptr<ScopedResource> resource) {
+ resource_ = resource.Pass();
+ }
+
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+
+ private:
+ friend class Tile;
+ friend class TileManager;
+
+ void set_use_resource() { mode_ = RESOURCE_MODE; }
+
+ void set_solid_color(const SkColor& color) {
+ mode_ = SOLID_COLOR_MODE;
+ solid_color_ = color;
+ }
+
+ void set_oom() { mode_ = OOM_MODE; }
+
+ Mode mode_;
+ SkColor solid_color_;
+ scoped_ptr<ScopedResource> resource_;
+};
+
+} // namespace cc
+
+#endif // CC_TILES_TILE_DRAW_INFO_H_
diff --git a/chromium/cc/resources/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc
index 8b6a72afc6f..a67563a4402 100644
--- a/chromium/cc/resources/tile_manager.cc
+++ b/chromium/cc/tiles/tile_manager.cc
@@ -2,24 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/tile_manager.h"
+#include "cc/tiles/tile_manager.h"
#include <algorithm>
#include <limits>
#include <string>
#include "base/bind.h"
-#include "base/debug/trace_event_argument.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/frame_viewer_instrumentation.h"
#include "cc/debug/traced_value.h"
#include "cc/layers/picture_layer_impl.h"
-#include "cc/resources/raster_buffer.h"
-#include "cc/resources/rasterizer.h"
-#include "cc/resources/tile.h"
+#include "cc/raster/raster_buffer.h"
+#include "cc/raster/tile_task_runner.h"
+#include "cc/tiles/tile.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
@@ -41,7 +41,6 @@ class RasterTaskImpl : public RasterTask {
const void* tile_id,
int source_frame_number,
bool analyze_picture,
- RenderingStatsInstrumentation* rendering_stats,
const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>&
reply,
ImageDecodeTask::Vector* dependencies)
@@ -54,7 +53,6 @@ class RasterTaskImpl : public RasterTask {
tile_id_(tile_id),
source_frame_number_(source_frame_number),
analyze_picture_(analyze_picture),
- rendering_stats_(rendering_stats),
reply_(reply) {}
// Overridden from Task:
@@ -73,12 +71,12 @@ class RasterTaskImpl : public RasterTask {
Raster(raster_source_.get());
}
- // Overridden from RasterizerTask:
- void ScheduleOnOriginThread(RasterizerTaskClient* client) override {
+ // Overridden from TileTask:
+ void ScheduleOnOriginThread(TileTaskClient* client) override {
DCHECK(!raster_buffer_);
raster_buffer_ = client->AcquireBufferForRaster(resource());
}
- void CompleteOnOriginThread(RasterizerTaskClient* client) override {
+ void CompleteOnOriginThread(TileTaskClient* client) override {
client->ReleaseBufferForRaster(raster_buffer_.Pass());
}
void RunReplyOnOriginThread() override {
@@ -98,11 +96,6 @@ class RasterTaskImpl : public RasterTask {
raster_source->PerformSolidColorAnalysis(content_rect_, contents_scale_,
&analysis_);
-
- // Record the solid color prediction.
- UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
- analysis_.is_solid_color);
-
// Clear the flag if we're not using the estimator.
analysis_.is_solid_color &= kUseColorEstimator;
}
@@ -110,8 +103,6 @@ class RasterTaskImpl : public RasterTask {
void Raster(const RasterSource* raster_source) {
frame_viewer_instrumentation::ScopedRasterTask raster_task(
tile_id_, tile_resolution_, source_frame_number_, layer_id_);
- devtools_instrumentation::ScopedLayerTask layer_task(
- devtools_instrumentation::kRasterTask, layer_id_);
DCHECK(raster_source);
@@ -128,7 +119,6 @@ class RasterTaskImpl : public RasterTask {
const void* tile_id_;
int source_frame_number_;
bool analyze_picture_;
- RenderingStatsInstrumentation* rendering_stats_;
const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>
reply_;
scoped_ptr<RasterBuffer> raster_buffer_;
@@ -139,12 +129,8 @@ class RasterTaskImpl : public RasterTask {
class ImageDecodeTaskImpl : public ImageDecodeTask {
public:
ImageDecodeTaskImpl(SkPixelRef* pixel_ref,
- int layer_id,
- RenderingStatsInstrumentation* rendering_stats,
const base::Callback<void(bool was_canceled)>& reply)
: pixel_ref_(skia::SharePtr(pixel_ref)),
- layer_id_(layer_id),
- rendering_stats_(rendering_stats),
reply_(reply) {}
// Overridden from Task:
@@ -156,11 +142,15 @@ class ImageDecodeTaskImpl : public ImageDecodeTask {
// This will cause the image referred to by pixel ref to be decoded.
pixel_ref_->lockPixels();
pixel_ref_->unlockPixels();
+
+ // Release the reference after decoding image to ensure that it is not
+ // kept alive unless needed.
+ pixel_ref_.clear();
}
- // Overridden from RasterizerTask:
- void ScheduleOnOriginThread(RasterizerTaskClient* client) override {}
- void CompleteOnOriginThread(RasterizerTaskClient* client) override {}
+ // Overridden from TileTask:
+ void ScheduleOnOriginThread(TileTaskClient* client) override {}
+ void CompleteOnOriginThread(TileTaskClient* client) override {}
void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); }
protected:
@@ -168,22 +158,34 @@ class ImageDecodeTaskImpl : public ImageDecodeTask {
private:
skia::RefPtr<SkPixelRef> pixel_ref_;
- int layer_id_;
- RenderingStatsInstrumentation* rendering_stats_;
const base::Callback<void(bool was_canceled)> reply_;
DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
};
+const char* TaskSetName(TaskSet task_set) {
+ switch (task_set) {
+ case TileManager::ALL:
+ return "ALL";
+ case TileManager::REQUIRED_FOR_ACTIVATION:
+ return "REQUIRED_FOR_ACTIVATION";
+ case TileManager::REQUIRED_FOR_DRAW:
+ return "REQUIRED_FOR_DRAW";
+ }
+
+ NOTREACHED();
+ return "Invalid TaskSet";
+}
+
} // namespace
RasterTaskCompletionStats::RasterTaskCompletionStats()
: completed_count(0u), canceled_count(0u) {}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
state->SetInteger("completed_count", stats.completed_count);
state->SetInteger("canceled_count", stats.canceled_count);
return state;
@@ -194,14 +196,10 @@ scoped_ptr<TileManager> TileManager::Create(
TileManagerClient* client,
base::SequencedTaskRunner* task_runner,
ResourcePool* resource_pool,
- Rasterizer* rasterizer,
- RenderingStatsInstrumentation* rendering_stats_instrumentation,
+ TileTaskRunner* tile_task_runner,
size_t scheduled_raster_task_limit) {
- return make_scoped_ptr(new TileManager(client,
- task_runner,
- resource_pool,
- rasterizer,
- rendering_stats_instrumentation,
+ return make_scoped_ptr(new TileManager(client, task_runner, resource_pool,
+ tile_task_runner,
scheduled_raster_task_limit));
}
@@ -209,24 +207,30 @@ TileManager::TileManager(
TileManagerClient* client,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
ResourcePool* resource_pool,
- Rasterizer* rasterizer,
- RenderingStatsInstrumentation* rendering_stats_instrumentation,
+ TileTaskRunner* tile_task_runner,
size_t scheduled_raster_task_limit)
: client_(client),
task_runner_(task_runner),
resource_pool_(resource_pool),
- rasterizer_(rasterizer),
+ tile_task_runner_(tile_task_runner),
scheduled_raster_task_limit_(scheduled_raster_task_limit),
all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
- rendering_stats_instrumentation_(rendering_stats_instrumentation),
- did_initialize_visible_tile_(false),
did_check_for_completed_tasks_since_last_schedule_tasks_(true),
did_oom_on_last_assign_(false),
ready_to_activate_check_notifier_(
task_runner_.get(),
base::Bind(&TileManager::CheckIfReadyToActivate,
- base::Unretained(this))) {
- rasterizer_->SetClient(this);
+ base::Unretained(this))),
+ ready_to_draw_check_notifier_(
+ task_runner_.get(),
+ base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))),
+ more_tiles_need_prepare_check_notifier_(
+ task_runner_.get(),
+ base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
+ base::Unretained(this))),
+ did_notify_ready_to_activate_(false),
+ did_notify_ready_to_draw_(false) {
+ tile_task_runner_->SetClient(this);
}
TileManager::~TileManager() {
@@ -234,14 +238,14 @@ TileManager::~TileManager() {
// our memory usage to drop to zero.
global_state_ = GlobalStateThatImpactsTilePriority();
- RasterTaskQueue empty;
- rasterizer_->ScheduleTasks(&empty);
+ TileTaskQueue empty;
+ tile_task_runner_->ScheduleTasks(&empty);
orphan_raster_tasks_.clear();
// This should finish all pending tasks and release any uninitialized
// resources.
- rasterizer_->Shutdown();
- rasterizer_->CheckForCompletedTasks();
+ tile_task_runner_->Shutdown();
+ tile_task_runner_->CheckForCompletedTasks();
FreeResourcesForReleasedTiles();
CleanUpReleasedTiles();
@@ -259,25 +263,19 @@ TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const {
}
void TileManager::FreeResourcesForReleasedTiles() {
- for (std::vector<Tile*>::iterator it = released_tiles_.begin();
- it != released_tiles_.end();
- ++it) {
- Tile* tile = *it;
+ for (auto* tile : released_tiles_)
FreeResourcesForTile(tile);
- }
}
void TileManager::CleanUpReleasedTiles() {
- std::vector<Tile*>::iterator it = released_tiles_.begin();
- while (it != released_tiles_.end()) {
- Tile* tile = *it;
-
+ std::vector<Tile*> tiles_to_retain;
+ for (auto* tile : released_tiles_) {
if (tile->HasRasterTask()) {
- ++it;
+ tiles_to_retain.push_back(tile);
continue;
}
- DCHECK(!tile->HasResources());
+ DCHECK(!tile->draw_info().has_resource());
DCHECK(tiles_.find(tile->id()) != tiles_.end());
tiles_.erase(tile->id());
@@ -290,130 +288,88 @@ void TileManager::CleanUpReleasedTiles() {
}
delete tile;
- it = released_tiles_.erase(it);
}
+ released_tiles_.swap(tiles_to_retain);
}
-void TileManager::DidFinishRunningTasks(TaskSet task_set) {
- if (task_set == ALL) {
- TRACE_EVENT1("cc", "TileManager::DidFinishRunningTasks", "task_set", "ALL");
-
- bool memory_usage_above_limit = resource_pool_->total_memory_usage_bytes() >
- global_state_.soft_memory_limit_in_bytes;
+void TileManager::DidFinishRunningTileTasks(TaskSet task_set) {
+ TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set",
+ TaskSetName(task_set));
- // When OOM, keep re-assigning memory until we reach a steady state
- // where top-priority tiles are initialized.
- if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
- !memory_usage_above_limit)
- return;
+ switch (task_set) {
+ case ALL: {
+ bool memory_usage_above_limit =
+ resource_pool_->total_memory_usage_bytes() >
+ global_state_.soft_memory_limit_in_bytes;
- rasterizer_->CheckForCompletedTasks();
- did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
-
- TileVector tiles_that_need_to_be_rasterized;
- AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
+ if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
+ !memory_usage_above_limit)
+ return;
- // |tiles_that_need_to_be_rasterized| will be empty when we reach a
- // steady memory state. Keep scheduling tasks until we reach this state.
- if (!tiles_that_need_to_be_rasterized.empty()) {
- ScheduleTasks(tiles_that_need_to_be_rasterized);
+ more_tiles_need_prepare_check_notifier_.Schedule();
return;
}
-
- FreeResourcesForReleasedTiles();
-
- resource_pool_->ReduceResourceUsage();
-
- // We don't reserve memory for required-for-activation tiles during
- // accelerated gestures, so we just postpone activation when we don't
- // have these tiles, and activate after the accelerated gesture.
- // Likewise if we don't allow any tiles (as is the case when we're
- // invisible), if we have tiles that aren't ready, then we shouldn't
- // activate as activation can cause checkerboards.
- bool allow_rasterize_on_demand =
- global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
- global_state_.memory_limit_policy != ALLOW_NOTHING;
-
- // Use on-demand raster for any required-for-activation tiles that have not
- // been been assigned memory after reaching a steady memory state. This
- // ensures that we activate even when OOM. Note that we have to rebuilt the
- // queue in case the last AssignGpuMemoryToTiles evicted some tiles that
- // would otherwise not be picked up by the old raster queue.
- client_->BuildRasterQueue(&raster_priority_queue_,
- global_state_.tree_priority);
- bool ready_to_activate = true;
- while (!raster_priority_queue_.IsEmpty()) {
- Tile* tile = raster_priority_queue_.Top();
- ManagedTileState& mts = tile->managed_state();
-
- if (tile->required_for_activation() && !mts.draw_info.IsReadyToDraw()) {
- // If we can't raster on demand, give up early (and don't activate).
- if (!allow_rasterize_on_demand) {
- ready_to_activate = false;
- break;
- }
-
- mts.draw_info.set_rasterize_on_demand();
- client_->NotifyTileStateChanged(tile);
- }
- raster_priority_queue_.Pop();
- }
-
- if (ready_to_activate) {
- DCHECK(IsReadyToActivate());
+ case REQUIRED_FOR_ACTIVATION:
ready_to_activate_check_notifier_.Schedule();
- }
- raster_priority_queue_.Reset();
- return;
+ return;
+ case REQUIRED_FOR_DRAW:
+ ready_to_draw_check_notifier_.Schedule();
+ return;
}
- if (task_set == REQUIRED_FOR_ACTIVATION) {
- TRACE_EVENT1("cc",
- "TileManager::DidFinishRunningTasks",
- "task_set",
- "REQUIRED_FOR_ACTIVATION");
- ready_to_activate_check_notifier_.Schedule();
- }
+ NOTREACHED();
}
-void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) {
- TRACE_EVENT0("cc", "TileManager::ManageTiles");
+void TileManager::PrepareTiles(
+ const GlobalStateThatImpactsTilePriority& state) {
+ TRACE_EVENT0("cc", "TileManager::PrepareTiles");
global_state_ = state;
// We need to call CheckForCompletedTasks() once in-between each call
// to ScheduleTasks() to prevent canceled tasks from being scheduled.
if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
- rasterizer_->CheckForCompletedTasks();
+ tile_task_runner_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
}
FreeResourcesForReleasedTiles();
CleanUpReleasedTiles();
- TileVector tiles_that_need_to_be_rasterized;
- AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
-
- // Finally, schedule rasterizer tasks.
+ PrioritizedTileVector tiles_that_need_to_be_rasterized;
+ scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
+ client_->BuildRasterQueue(global_state_.tree_priority,
+ RasterTilePriorityQueue::Type::ALL));
+ AssignGpuMemoryToTiles(raster_priority_queue.get(),
+ scheduled_raster_task_limit_,
+ &tiles_that_need_to_be_rasterized);
+
+ // Inform the client that will likely require a draw if the highest priority
+ // tile that will be rasterized is required for draw.
+ client_->SetIsLikelyToRequireADraw(
+ !tiles_that_need_to_be_rasterized.empty() &&
+ tiles_that_need_to_be_rasterized.front().tile()->required_for_draw());
+
+ // Schedule tile tasks.
ScheduleTasks(tiles_that_need_to_be_rasterized);
- TRACE_EVENT_INSTANT1("cc",
- "DidManage",
- TRACE_EVENT_SCOPE_THREAD,
- "state",
- BasicStateAsValue());
+ did_notify_ready_to_activate_ = false;
+ did_notify_ready_to_draw_ = false;
+
+ TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
+ "state", BasicStateAsValue());
- TRACE_COUNTER_ID1("cc",
- "unused_memory_bytes",
- this,
+ TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
resource_pool_->total_memory_usage_bytes() -
resource_pool_->acquired_memory_usage_bytes());
}
-bool TileManager::UpdateVisibleTiles() {
+void TileManager::UpdateVisibleTiles(
+ const GlobalStateThatImpactsTilePriority& state) {
TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
- rasterizer_->CheckForCompletedTasks();
+ tile_task_runner_->CheckForCompletedTasks();
+
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
TRACE_EVENT_INSTANT1(
@@ -423,21 +379,18 @@ bool TileManager::UpdateVisibleTiles() {
"stats",
RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
update_visible_tiles_stats_ = RasterTaskCompletionStats();
-
- bool did_initialize_visible_tile = did_initialize_visible_tile_;
- did_initialize_visible_tile_ = false;
- return did_initialize_visible_tile;
}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
TileManager::BasicStateAsValue() const {
- scoped_refptr<base::debug::TracedValue> value =
- new base::debug::TracedValue();
+ scoped_refptr<base::trace_event::TracedValue> value =
+ new base::trace_event::TracedValue();
BasicStateAsValueInto(value.get());
return value;
}
-void TileManager::BasicStateAsValueInto(base::debug::TracedValue* state) const {
+void TileManager::BasicStateAsValueInto(
+ base::trace_event::TracedValue* state) const {
state->SetInteger("tile_count", tiles_.size());
state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
state->BeginDictionary("global_state");
@@ -445,54 +398,51 @@ void TileManager::BasicStateAsValueInto(base::debug::TracedValue* state) const {
state->EndDictionary();
}
-void TileManager::RebuildEvictionQueueIfNeeded() {
- TRACE_EVENT1("cc",
- "TileManager::RebuildEvictionQueueIfNeeded",
- "eviction_priority_queue_is_up_to_date",
- eviction_priority_queue_is_up_to_date_);
- if (eviction_priority_queue_is_up_to_date_)
- return;
-
- eviction_priority_queue_.Reset();
- client_->BuildEvictionQueue(&eviction_priority_queue_,
- global_state_.tree_priority);
- eviction_priority_queue_is_up_to_date_ = true;
-}
-
-bool TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
+scoped_ptr<EvictionTilePriorityQueue>
+TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
+ scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
const MemoryUsage& limit,
MemoryUsage* usage) {
while (usage->Exceeds(limit)) {
- RebuildEvictionQueueIfNeeded();
- if (eviction_priority_queue_.IsEmpty())
- return false;
+ if (!eviction_priority_queue) {
+ eviction_priority_queue =
+ client_->BuildEvictionQueue(global_state_.tree_priority);
+ }
+ if (eviction_priority_queue->IsEmpty())
+ break;
- Tile* tile = eviction_priority_queue_.Top();
+ Tile* tile = eviction_priority_queue->Top().tile();
*usage -= MemoryUsage::FromTile(tile);
FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
- eviction_priority_queue_.Pop();
+ eviction_priority_queue->Pop();
}
- return true;
+ return eviction_priority_queue;
}
-bool TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
+scoped_ptr<EvictionTilePriorityQueue>
+TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
+ scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
const MemoryUsage& limit,
const TilePriority& other_priority,
MemoryUsage* usage) {
while (usage->Exceeds(limit)) {
- RebuildEvictionQueueIfNeeded();
- if (eviction_priority_queue_.IsEmpty())
- return false;
+ if (!eviction_priority_queue) {
+ eviction_priority_queue =
+ client_->BuildEvictionQueue(global_state_.tree_priority);
+ }
+ if (eviction_priority_queue->IsEmpty())
+ break;
- Tile* tile = eviction_priority_queue_.Top();
- if (!other_priority.IsHigherPriorityThan(tile->combined_priority()))
- return false;
+ const PrioritizedTile& prioritized_tile = eviction_priority_queue->Top();
+ if (!other_priority.IsHigherPriorityThan(prioritized_tile.priority()))
+ break;
+ Tile* tile = prioritized_tile.tile();
*usage -= MemoryUsage::FromTile(tile);
FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
- eviction_priority_queue_.Pop();
+ eviction_priority_queue->Pop();
}
- return true;
+ return eviction_priority_queue;
}
bool TileManager::TilePriorityViolatesMemoryPolicy(
@@ -513,13 +463,14 @@ bool TileManager::TilePriorityViolatesMemoryPolicy(
}
void TileManager::AssignGpuMemoryToTiles(
- TileVector* tiles_that_need_to_be_rasterized) {
+ RasterTilePriorityQueue* raster_priority_queue,
+ size_t scheduled_raster_task_limit,
+ PrioritizedTileVector* tiles_that_need_to_be_rasterized) {
TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
// Maintain the list of released resources that can potentially be re-used
- // or deleted.
- // If this operation becomes expensive too, only do this after some
- // resource(s) was returned. Note that in that case, one also need to
+ // or deleted. If this operation becomes expensive too, only do this after
+ // some resource(s) was returned. Note that in that case, one also need to
// invalidate when releasing some resource from the pool.
resource_pool_->CheckBusyResources(false);
@@ -536,44 +487,38 @@ void TileManager::AssignGpuMemoryToTiles(
MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
resource_pool_->acquired_resource_count());
- eviction_priority_queue_is_up_to_date_ = false;
- client_->BuildRasterQueue(&raster_priority_queue_,
- global_state_.tree_priority);
-
- while (!raster_priority_queue_.IsEmpty()) {
- Tile* tile = raster_priority_queue_.Top();
- TilePriority priority = tile->combined_priority();
+ scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue;
+ for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
+ const PrioritizedTile& prioritized_tile = raster_priority_queue->Top();
+ Tile* tile = prioritized_tile.tile();
+ TilePriority priority = prioritized_tile.priority();
if (TilePriorityViolatesMemoryPolicy(priority)) {
TRACE_EVENT_INSTANT0(
- "cc",
- "TileManager::AssignGpuMemory tile violates memory policy",
+ "cc", "TileManager::AssignGpuMemory tile violates memory policy",
TRACE_EVENT_SCOPE_THREAD);
break;
}
// We won't be able to schedule this tile, so break out early.
if (tiles_that_need_to_be_rasterized->size() >=
- scheduled_raster_task_limit_) {
+ scheduled_raster_task_limit) {
all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
break;
}
- ManagedTileState& mts = tile->managed_state();
- mts.scheduled_priority = schedule_priority++;
- mts.resolution = priority.resolution;
+ tile->scheduled_priority_ = schedule_priority++;
- DCHECK(mts.draw_info.mode() ==
- ManagedTileState::DrawInfo::PICTURE_PILE_MODE ||
- !mts.draw_info.IsReadyToDraw());
+ DCHECK_IMPLIES(tile->draw_info().mode() != TileDrawInfo::OOM_MODE,
+ !tile->draw_info().IsReadyToDraw());
// If the tile already has a raster_task, then the memory used by it is
// already accounted for in memory_usage. Otherwise, we'll have to acquire
// more memory to create a raster task.
MemoryUsage memory_required_by_tile_to_be_scheduled;
- if (!mts.raster_task.get()) {
+ if (!tile->raster_task_.get()) {
memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
- tile->size(), resource_pool_->resource_format());
+ tile->desired_texture_size(), tile_task_runner_->GetResourceFormat());
}
bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
@@ -584,11 +529,14 @@ void TileManager::AssignGpuMemoryToTiles(
MemoryUsage& tile_memory_limit =
tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
- bool memory_usage_is_within_limit =
+ const MemoryUsage& scheduled_tile_memory_limit =
+ tile_memory_limit - memory_required_by_tile_to_be_scheduled;
+ eviction_priority_queue =
FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
- tile_memory_limit - memory_required_by_tile_to_be_scheduled,
- priority,
- &memory_usage);
+ eviction_priority_queue.Pass(), scheduled_tile_memory_limit,
+ priority, &memory_usage);
+ bool memory_usage_is_within_limit =
+ !memory_usage.Exceeds(scheduled_tile_memory_limit);
// If we couldn't fit the tile into our current memory limit, then we're
// done.
@@ -600,14 +548,14 @@ void TileManager::AssignGpuMemoryToTiles(
}
memory_usage += memory_required_by_tile_to_be_scheduled;
- tiles_that_need_to_be_rasterized->push_back(tile);
- raster_priority_queue_.Pop();
+ tiles_that_need_to_be_rasterized->push_back(prioritized_tile);
}
// Note that we should try and further reduce memory in case the above loop
// didn't reduce memory. This ensures that we always release as many resources
// as possible to stay within the memory limit.
- FreeTileResourcesUntilUsageIsWithinLimit(hard_memory_limit, &memory_usage);
+ eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
+ eviction_priority_queue.Pass(), hard_memory_limit, &memory_usage);
UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
!had_enough_memory_to_schedule_tiles_needed_now);
@@ -619,10 +567,7 @@ void TileManager::AssignGpuMemoryToTiles(
memory_stats_from_last_assign_.had_enough_memory =
had_enough_memory_to_schedule_tiles_needed_now;
- raster_priority_queue_.Reset();
-
- TRACE_EVENT_END2("cc",
- "TileManager::AssignGpuMemoryToTiles",
+ TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
"all_tiles_that_need_to_be_rasterized_are_scheduled",
all_tiles_that_need_to_be_rasterized_are_scheduled_,
"had_enough_memory_to_schedule_tiles_needed_now",
@@ -630,21 +575,21 @@ void TileManager::AssignGpuMemoryToTiles(
}
void TileManager::FreeResourcesForTile(Tile* tile) {
- ManagedTileState& mts = tile->managed_state();
- if (mts.draw_info.resource_)
- resource_pool_->ReleaseResource(mts.draw_info.resource_.Pass());
+ TileDrawInfo& draw_info = tile->draw_info();
+ if (draw_info.resource_)
+ resource_pool_->ReleaseResource(draw_info.resource_.Pass());
}
void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
Tile* tile) {
- bool was_ready_to_draw = tile->IsReadyToDraw();
+ bool was_ready_to_draw = tile->draw_info().IsReadyToDraw();
FreeResourcesForTile(tile);
if (was_ready_to_draw)
client_->NotifyTileStateChanged(tile);
}
void TileManager::ScheduleTasks(
- const TileVector& tiles_that_need_to_be_rasterized) {
+ const PrioritizedTileVector& tiles_that_need_to_be_rasterized) {
TRACE_EVENT1("cc",
"TileManager::ScheduleTasks",
"count",
@@ -656,24 +601,23 @@ void TileManager::ScheduleTasks(
// Build a new task queue containing all task currently needed. Tasks
// are added in order of priority, highest priority task first.
- for (TileVector::const_iterator it = tiles_that_need_to_be_rasterized.begin();
- it != tiles_that_need_to_be_rasterized.end();
- ++it) {
- Tile* tile = *it;
- ManagedTileState& mts = tile->managed_state();
+ for (auto& prioritized_tile : tiles_that_need_to_be_rasterized) {
+ Tile* tile = prioritized_tile.tile();
- DCHECK(mts.draw_info.requires_resource());
- DCHECK(!mts.draw_info.resource_);
+ DCHECK(tile->draw_info().requires_resource());
+ DCHECK(!tile->draw_info().resource_);
- if (!mts.raster_task.get())
- mts.raster_task = CreateRasterTask(tile);
+ if (!tile->raster_task_.get())
+ tile->raster_task_ = CreateRasterTask(prioritized_tile);
TaskSetCollection task_sets;
if (tile->required_for_activation())
task_sets.set(REQUIRED_FOR_ACTIVATION);
+ if (tile->required_for_draw())
+ task_sets.set(REQUIRED_FOR_DRAW);
task_sets.set(ALL);
raster_queue_.items.push_back(
- RasterTaskQueue::Item(mts.raster_task.get(), task_sets));
+ TileTaskQueue::Item(tile->raster_task_.get(), task_sets));
}
// We must reduce the amount of unused resoruces before calling
@@ -683,7 +627,7 @@ void TileManager::ScheduleTasks(
// Schedule running of |raster_queue_|. This replaces any previously
// scheduled tasks and effectively cancels all tasks not present
// in |raster_queue_|.
- rasterizer_->ScheduleTasks(&raster_queue_);
+ tile_task_runner_->ScheduleTasks(&raster_queue_);
// It's now safe to clean up orphan tasks as raster worker pool is not
// allowed to keep around unreferenced raster tasks after ScheduleTasks() has
@@ -698,26 +642,25 @@ scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
SkPixelRef* pixel_ref) {
return make_scoped_refptr(new ImageDecodeTaskImpl(
pixel_ref,
- tile->layer_id(),
- rendering_stats_instrumentation_,
base::Bind(&TileManager::OnImageDecodeTaskCompleted,
base::Unretained(this),
tile->layer_id(),
base::Unretained(pixel_ref))));
}
-scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
- ManagedTileState& mts = tile->managed_state();
-
+scoped_refptr<RasterTask> TileManager::CreateRasterTask(
+ const PrioritizedTile& prioritized_tile) {
+ Tile* tile = prioritized_tile.tile();
scoped_ptr<ScopedResource> resource =
- resource_pool_->AcquireResource(tile->size());
+ resource_pool_->AcquireResource(tile->desired_texture_size(),
+ tile_task_runner_->GetResourceFormat());
const ScopedResource* const_resource = resource.get();
// Create and queue all image decode tasks that this tile depends on.
ImageDecodeTask::Vector decode_tasks;
PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
std::vector<SkPixelRef*> pixel_refs;
- tile->raster_source()->GatherPixelRefs(
+ prioritized_tile.raster_source()->GatherPixelRefs(
tile->content_rect(), tile->contents_scale(), &pixel_refs);
for (SkPixelRef* pixel_ref : pixel_refs) {
uint32_t id = pixel_ref->getGenerationID();
@@ -736,22 +679,14 @@ scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
existing_pixel_refs[id] = decode_task;
}
- return make_scoped_refptr(
- new RasterTaskImpl(const_resource,
- tile->raster_source(),
- tile->content_rect(),
- tile->contents_scale(),
- mts.resolution,
- tile->layer_id(),
- static_cast<const void*>(tile),
- tile->source_frame_number(),
- tile->use_picture_analysis(),
- rendering_stats_instrumentation_,
- base::Bind(&TileManager::OnRasterTaskCompleted,
- base::Unretained(this),
- tile->id(),
- base::Passed(&resource)),
- &decode_tasks));
+ return make_scoped_refptr(new RasterTaskImpl(
+ const_resource, prioritized_tile.raster_source(), tile->content_rect(),
+ tile->contents_scale(), prioritized_tile.priority().resolution,
+ tile->layer_id(), static_cast<const void*>(tile),
+ tile->source_frame_number(), tile->use_picture_analysis(),
+ base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this),
+ tile->id(), base::Passed(&resource)),
+ &decode_tasks));
}
void TileManager::OnImageDecodeTaskCompleted(int layer_id,
@@ -782,10 +717,9 @@ void TileManager::OnRasterTaskCompleted(
DCHECK(tiles_.find(tile_id) != tiles_.end());
Tile* tile = tiles_[tile_id];
- ManagedTileState& mts = tile->managed_state();
- DCHECK(mts.raster_task.get());
- orphan_raster_tasks_.push_back(mts.raster_task);
- mts.raster_task = NULL;
+ DCHECK(tile->raster_task_.get());
+ orphan_raster_tasks_.push_back(tile->raster_task_);
+ tile->raster_task_ = nullptr;
if (was_canceled) {
++update_visible_tiles_stats_.canceled_count;
@@ -793,37 +727,39 @@ void TileManager::OnRasterTaskCompleted(
return;
}
+ UpdateTileDrawInfo(tile, resource.Pass(), analysis);
+}
+
+void TileManager::UpdateTileDrawInfo(
+ Tile* tile,
+ scoped_ptr<ScopedResource> resource,
+ const RasterSource::SolidColorAnalysis& analysis) {
+ TileDrawInfo& draw_info = tile->draw_info();
+
++update_visible_tiles_stats_.completed_count;
if (analysis.is_solid_color) {
- mts.draw_info.set_solid_color(analysis.solid_color);
- resource_pool_->ReleaseResource(resource.Pass());
+ draw_info.set_solid_color(analysis.solid_color);
+ if (resource)
+ resource_pool_->ReleaseResource(resource.Pass());
} else {
- mts.draw_info.set_use_resource();
- mts.draw_info.resource_ = resource.Pass();
+ DCHECK(resource);
+ draw_info.set_use_resource();
+ draw_info.resource_ = resource.Pass();
}
- if (tile->priority(ACTIVE_TREE).distance_to_visible == 0.f)
- did_initialize_visible_tile_ = true;
-
client_->NotifyTileStateChanged(tile);
}
-scoped_refptr<Tile> TileManager::CreateTile(RasterSource* raster_source,
- const gfx::Size& tile_size,
- const gfx::Rect& content_rect,
- float contents_scale,
- int layer_id,
- int source_frame_number,
- int flags) {
- scoped_refptr<Tile> tile = make_scoped_refptr(new Tile(this,
- raster_source,
- tile_size,
- content_rect,
- contents_scale,
- layer_id,
- source_frame_number,
- flags));
+ScopedTilePtr TileManager::CreateTile(const gfx::Size& desired_texture_size,
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ int layer_id,
+ int source_frame_number,
+ int flags) {
+ ScopedTilePtr tile(new Tile(this, desired_texture_size, content_rect,
+ contents_scale, layer_id, source_frame_number,
+ flags));
DCHECK(tiles_.find(tile->id()) == tiles_.end());
tiles_[tile->id()] = tile.get();
@@ -831,33 +767,159 @@ scoped_refptr<Tile> TileManager::CreateTile(RasterSource* raster_source,
return tile;
}
-void TileManager::SetRasterizerForTesting(Rasterizer* rasterizer) {
- rasterizer_ = rasterizer;
- rasterizer_->SetClient(this);
+void TileManager::SetTileTaskRunnerForTesting(
+ TileTaskRunner* tile_task_runner) {
+ tile_task_runner_ = tile_task_runner;
+ tile_task_runner_->SetClient(this);
}
-bool TileManager::IsReadyToActivate() const {
- TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
- const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
-
- for (std::vector<PictureLayerImpl*>::const_iterator it = layers.begin();
- it != layers.end();
- ++it) {
- if (!(*it)->AllTilesRequiredForActivationAreReadyToDraw())
+bool TileManager::AreRequiredTilesReadyToDraw(
+ RasterTilePriorityQueue::Type type) const {
+ scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
+ client_->BuildRasterQueue(global_state_.tree_priority, type));
+ // It is insufficient to check whether the raster queue we constructed is
+ // empty. The reason for this is that there are situations (rasterize on
+ // demand) when the tile both needs raster and it's ready to draw. Hence, we
+ // have to iterate the queue to check whether the required tiles are ready to
+ // draw.
+ for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
+ if (!raster_priority_queue->Top().tile()->draw_info().IsReadyToDraw())
return false;
}
+#if DCHECK_IS_ON()
+ scoped_ptr<RasterTilePriorityQueue> all_queue(
+ client_->BuildRasterQueue(global_state_.tree_priority, type));
+ for (; !all_queue->IsEmpty(); all_queue->Pop()) {
+ Tile* tile = all_queue->Top().tile();
+ DCHECK_IMPLIES(tile->required_for_activation(),
+ tile->draw_info().IsReadyToDraw());
+ }
+#endif
return true;
}
+bool TileManager::IsReadyToActivate() const {
+ TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
+ return AreRequiredTilesReadyToDraw(
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
+}
+
+bool TileManager::IsReadyToDraw() const {
+ TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
+ return AreRequiredTilesReadyToDraw(
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
+}
+
+void TileManager::NotifyReadyToActivate() {
+ TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
+ if (did_notify_ready_to_activate_)
+ return;
+ client_->NotifyReadyToActivate();
+ did_notify_ready_to_activate_ = true;
+}
+
+void TileManager::NotifyReadyToDraw() {
+ TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
+ if (did_notify_ready_to_draw_)
+ return;
+ client_->NotifyReadyToDraw();
+ did_notify_ready_to_draw_ = true;
+}
void TileManager::CheckIfReadyToActivate() {
TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
- rasterizer_->CheckForCompletedTasks();
+ tile_task_runner_->CheckForCompletedTasks();
+ did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
+
+ if (did_notify_ready_to_activate_)
+ return;
+ if (!IsReadyToActivate())
+ return;
+
+ NotifyReadyToActivate();
+}
+
+void TileManager::CheckIfReadyToDraw() {
+ TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
+
+ tile_task_runner_->CheckForCompletedTasks();
+ did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
+
+ if (did_notify_ready_to_draw_)
+ return;
+ if (!IsReadyToDraw())
+ return;
+
+ NotifyReadyToDraw();
+}
+
+void TileManager::CheckIfMoreTilesNeedToBePrepared() {
+ tile_task_runner_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
- if (IsReadyToActivate())
- client_->NotifyReadyToActivate();
+ // When OOM, keep re-assigning memory until we reach a steady state
+ // where top-priority tiles are initialized.
+ PrioritizedTileVector tiles_that_need_to_be_rasterized;
+ scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
+ client_->BuildRasterQueue(global_state_.tree_priority,
+ RasterTilePriorityQueue::Type::ALL));
+ AssignGpuMemoryToTiles(raster_priority_queue.get(),
+ scheduled_raster_task_limit_,
+ &tiles_that_need_to_be_rasterized);
+
+ // Inform the client that will likely require a draw if the highest priority
+ // tile that will be rasterized is required for draw.
+ client_->SetIsLikelyToRequireADraw(
+ !tiles_that_need_to_be_rasterized.empty() &&
+ tiles_that_need_to_be_rasterized.front().tile()->required_for_draw());
+
+ // |tiles_that_need_to_be_rasterized| will be empty when we reach a
+ // steady memory state. Keep scheduling tasks until we reach this state.
+ if (!tiles_that_need_to_be_rasterized.empty()) {
+ ScheduleTasks(tiles_that_need_to_be_rasterized);
+ return;
+ }
+
+ FreeResourcesForReleasedTiles();
+
+ resource_pool_->ReduceResourceUsage();
+
+ // We don't reserve memory for required-for-activation tiles during
+ // accelerated gestures, so we just postpone activation when we don't
+ // have these tiles, and activate after the accelerated gesture.
+ // Likewise if we don't allow any tiles (as is the case when we're
+ // invisible), if we have tiles that aren't ready, then we shouldn't
+ // activate as activation can cause checkerboards.
+ bool wait_for_all_required_tiles =
+ global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
+ global_state_.memory_limit_policy == ALLOW_NOTHING;
+
+ // Mark any required-for-activation tiles that have not been been assigned
+ // memory after reaching a steady memory state as OOM. This ensures that we
+ // activate even when OOM. Note that we can't reuse the queue we used for
+ // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
+ // evicted some tiles that would not be picked up by the old raster queue.
+ scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue(
+ client_->BuildRasterQueue(
+ global_state_.tree_priority,
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
+
+ // If we have tiles left to raster for activation, and we don't allow
+ // activating without them, then skip activation and return early.
+ if (!required_for_activation_queue->IsEmpty() && wait_for_all_required_tiles)
+ return;
+
+ // Mark required tiles as OOM so that we can activate without them.
+ for (; !required_for_activation_queue->IsEmpty();
+ required_for_activation_queue->Pop()) {
+ Tile* tile = required_for_activation_queue->Top().tile();
+ tile->draw_info().set_oom();
+ client_->NotifyTileStateChanged(tile);
+ }
+
+ DCHECK(IsReadyToActivate());
+ ready_to_activate_check_notifier_.Schedule();
}
TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
@@ -876,10 +938,10 @@ TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
// static
TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
- const ManagedTileState& mts = tile->managed_state();
- if (mts.draw_info.resource_) {
- return MemoryUsage::FromConfig(tile->size(),
- mts.draw_info.resource_->format());
+ const TileDrawInfo& draw_info = tile->draw_info();
+ if (draw_info.resource_) {
+ return MemoryUsage::FromConfig(draw_info.resource_->size(),
+ draw_info.resource_->format());
}
return MemoryUsage();
}
diff --git a/chromium/cc/resources/tile_manager.h b/chromium/cc/tiles/tile_manager.h
index f5bea383141..8611b3a3615 100644
--- a/chromium/cc/resources/tile_manager.h
+++ b/chromium/cc/tiles/tile_manager.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_TILE_MANAGER_H_
-#define CC_RESOURCES_TILE_MANAGER_H_
+#ifndef CC_TILES_TILE_MANAGER_H_
+#define CC_TILES_TILE_MANAGER_H_
#include <deque>
#include <queue>
@@ -14,20 +14,18 @@
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
-#include "cc/base/ref_counted_managed.h"
#include "cc/base/unique_notifier.h"
-#include "cc/debug/rendering_stats_instrumentation.h"
-#include "cc/resources/eviction_tile_priority_queue.h"
-#include "cc/resources/managed_tile_state.h"
+#include "cc/playback/raster_source.h"
+#include "cc/raster/tile_task_runner.h"
#include "cc/resources/memory_history.h"
-#include "cc/resources/raster_source.h"
-#include "cc/resources/raster_tile_priority_queue.h"
-#include "cc/resources/rasterizer.h"
#include "cc/resources/resource_pool.h"
-#include "cc/resources/tile.h"
+#include "cc/tiles/eviction_tile_priority_queue.h"
+#include "cc/tiles/raster_tile_priority_queue.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_draw_info.h"
namespace base {
-namespace debug {
+namespace trace_event {
class ConvertableToTraceFormat;
class TracedValue;
}
@@ -39,14 +37,12 @@ class ResourceProvider;
class CC_EXPORT TileManagerClient {
public:
- // Returns the set of layers that the tile manager should consider for raster.
- // TODO(vmpstr): Change the way we determine if we are ready to activate, so
- // that this can be removed.
- virtual const std::vector<PictureLayerImpl*>& GetPictureLayers() const = 0;
-
// Called when all tiles marked as required for activation are ready to draw.
virtual void NotifyReadyToActivate() = 0;
+ // Called when all tiles marked as required for draw are ready to draw.
+ virtual void NotifyReadyToDraw() = 0;
+
// Called when the visible representation of a tile might have changed. Some
// examples are:
// - Tile version initialized.
@@ -57,14 +53,20 @@ class CC_EXPORT TileManagerClient {
// Given an empty raster tile priority queue, this will build a priority queue
// that will return tiles in order in which they should be rasterized.
// Note if the queue was previous built, Reset must be called on it.
- virtual void BuildRasterQueue(RasterTilePriorityQueue* queue,
- TreePriority tree_priority) = 0;
+ virtual scoped_ptr<RasterTilePriorityQueue> BuildRasterQueue(
+ TreePriority tree_priority,
+ RasterTilePriorityQueue::Type type) = 0;
// Given an empty eviction tile priority queue, this will build a priority
// queue that will return tiles in order in which they should be evicted.
// Note if the queue was previous built, Reset must be called on it.
- virtual void BuildEvictionQueue(EvictionTilePriorityQueue* queue,
- TreePriority tree_priority) = 0;
+ virtual scoped_ptr<EvictionTilePriorityQueue> BuildEvictionQueue(
+ TreePriority tree_priority) = 0;
+
+ // Informs the client that due to the currently rasterizing (or scheduled to
+ // be rasterized) tiles, we will be in a position that will likely require a
+ // draw. This can be used to preemptively start a frame.
+ virtual void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) = 0;
protected:
virtual ~TileManagerClient() {}
@@ -76,58 +78,68 @@ struct RasterTaskCompletionStats {
size_t completed_count;
size_t canceled_count;
};
-scoped_refptr<base::debug::ConvertableToTraceFormat>
- RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats);
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats);
// This class manages tiles, deciding which should get rasterized and which
// should no longer have any memory assigned to them. Tile objects are "owned"
// by layers; they automatically register with the manager when they are
// created, and unregister from the manager when they are deleted.
-class CC_EXPORT TileManager : public RasterizerClient,
- public RefCountedManager<Tile> {
+class CC_EXPORT TileManager : public TileTaskRunnerClient {
public:
enum NamedTaskSet {
- REQUIRED_FOR_ACTIVATION = 0,
- ALL = 1,
+ REQUIRED_FOR_ACTIVATION,
+ REQUIRED_FOR_DRAW,
+ // PixelBufferTileTaskWorkerPool depends on ALL being last.
+ ALL
// Adding additional values requires increasing kNumberOfTaskSets in
- // rasterizer.h
+ // tile_task_runner.h
};
- static scoped_ptr<TileManager> Create(
- TileManagerClient* client,
- base::SequencedTaskRunner* task_runner,
- ResourcePool* resource_pool,
- Rasterizer* rasterizer,
- RenderingStatsInstrumentation* rendering_stats_instrumentation,
- size_t scheduled_raster_task_limit);
+ static_assert(NamedTaskSet::ALL == (kNumberOfTaskSets - 1),
+ "NamedTaskSet::ALL should be equal to kNumberOfTaskSets"
+ "minus 1");
+
+ static scoped_ptr<TileManager> Create(TileManagerClient* client,
+ base::SequencedTaskRunner* task_runner,
+ ResourcePool* resource_pool,
+ TileTaskRunner* tile_task_runner,
+ size_t scheduled_raster_task_limit);
~TileManager() override;
- void ManageTiles(const GlobalStateThatImpactsTilePriority& state);
+ // Assigns tile memory and schedules work to prepare tiles for drawing.
+ // - Runs client_->NotifyReadyToActivate() when all tiles required for
+ // activation are prepared, or failed to prepare due to OOM.
+ // - Runs client_->NotifyReadyToDraw() when all tiles required draw are
+ // prepared, or failed to prepare due to OOM.
+ void PrepareTiles(const GlobalStateThatImpactsTilePriority& state);
- // Returns true when visible tiles have been initialized.
- bool UpdateVisibleTiles();
+ void UpdateVisibleTiles(const GlobalStateThatImpactsTilePriority& state);
- scoped_refptr<Tile> CreateTile(RasterSource* raster_source,
- const gfx::Size& tile_size,
- const gfx::Rect& content_rect,
- float contents_scale,
- int layer_id,
- int source_frame_number,
- int flags);
+ ScopedTilePtr CreateTile(const gfx::Size& desired_texture_size,
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ int layer_id,
+ int source_frame_number,
+ int flags);
- scoped_refptr<base::debug::ConvertableToTraceFormat> BasicStateAsValue()
+ bool IsReadyToActivate() const;
+ bool IsReadyToDraw() const;
+
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> BasicStateAsValue()
const;
- void BasicStateAsValueInto(base::debug::TracedValue* dict) const;
+ void BasicStateAsValueInto(base::trace_event::TracedValue* dict) const;
const MemoryHistory::Entry& memory_stats_from_last_assign() const {
return memory_stats_from_last_assign_;
}
+ // Public methods for testing.
void InitializeTilesWithResourcesForTesting(const std::vector<Tile*>& tiles) {
for (size_t i = 0; i < tiles.size(); ++i) {
- ManagedTileState& mts = tiles[i]->managed_state();
-
- mts.draw_info.resource_ =
- resource_pool_->AcquireResource(tiles[i]->size());
+ TileDrawInfo& draw_info = tiles[i]->draw_info();
+ draw_info.resource_ = resource_pool_->AcquireResource(
+ tiles[i]->desired_texture_size(),
+ tile_task_runner_->GetResourceFormat());
}
}
@@ -143,7 +155,7 @@ class CC_EXPORT TileManager : public RasterizerClient,
global_state_ = state;
}
- void SetRasterizerForTesting(Rasterizer* rasterizer);
+ void SetTileTaskRunnerForTesting(TileTaskRunner* tile_task_runner);
void FreeResourcesAndCleanUpReleasedTilesForTesting() {
FreeResourcesForReleasedTiles();
@@ -159,33 +171,43 @@ class CC_EXPORT TileManager : public RasterizerClient,
return tiles;
}
+ void SetScheduledRasterTaskLimitForTesting(size_t limit) {
+ scheduled_raster_task_limit_ = limit;
+ }
+
+ void CheckIfMoreTilesNeedToBePreparedForTesting() {
+ CheckIfMoreTilesNeedToBePrepared();
+ }
+
protected:
TileManager(TileManagerClient* client,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
ResourcePool* resource_pool,
- Rasterizer* rasterizer,
- RenderingStatsInstrumentation* rendering_stats_instrumentation,
+ TileTaskRunner* tile_task_runner,
size_t scheduled_raster_task_limit);
void FreeResourcesForReleasedTiles();
void CleanUpReleasedTiles();
- // Overriden from RefCountedManager<Tile>:
friend class Tile;
- void Release(Tile* tile) override;
+ // Virtual for testing.
+ virtual void Release(Tile* tile);
- // Overriden from RasterizerClient:
- void DidFinishRunningTasks(TaskSet task_set) override;
+ // Overriden from TileTaskRunnerClient:
+ void DidFinishRunningTileTasks(TaskSet task_set) override;
TaskSetCollection TasksThatShouldBeForcedToComplete() const override;
- typedef std::vector<Tile*> TileVector;
+ typedef std::vector<PrioritizedTile> PrioritizedTileVector;
typedef std::set<Tile*> TileSet;
// Virtual for test
virtual void ScheduleTasks(
- const TileVector& tiles_that_need_to_be_rasterized);
+ const PrioritizedTileVector& tiles_that_need_to_be_rasterized);
- void AssignGpuMemoryToTiles(TileVector* tiles_that_need_to_be_rasterized);
+ void AssignGpuMemoryToTiles(
+ RasterTilePriorityQueue* raster_priority_queue,
+ size_t scheduled_raser_task_limit,
+ PrioritizedTileVector* tiles_that_need_to_be_rasterized);
private:
class MemoryUsage {
@@ -215,30 +237,42 @@ class CC_EXPORT TileManager : public RasterizerClient,
scoped_ptr<ScopedResource> resource,
const RasterSource::SolidColorAnalysis& analysis,
bool was_canceled);
+ void UpdateTileDrawInfo(Tile* tile,
+ scoped_ptr<ScopedResource> resource,
+ const RasterSource::SolidColorAnalysis& analysis);
void FreeResourcesForTile(Tile* tile);
void FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(Tile* tile);
scoped_refptr<ImageDecodeTask> CreateImageDecodeTask(Tile* tile,
SkPixelRef* pixel_ref);
- scoped_refptr<RasterTask> CreateRasterTask(Tile* tile);
+ scoped_refptr<RasterTask> CreateRasterTask(
+ const PrioritizedTile& prioritized_tile);
- void RebuildEvictionQueueIfNeeded();
- bool FreeTileResourcesUntilUsageIsWithinLimit(const MemoryUsage& limit,
- MemoryUsage* usage);
- bool FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
+ scoped_ptr<EvictionTilePriorityQueue>
+ FreeTileResourcesUntilUsageIsWithinLimit(
+ scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
+ const MemoryUsage& limit,
+ MemoryUsage* usage);
+ scoped_ptr<EvictionTilePriorityQueue>
+ FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
+ scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
const MemoryUsage& limit,
const TilePriority& oother_priority,
MemoryUsage* usage);
bool TilePriorityViolatesMemoryPolicy(const TilePriority& priority);
- bool IsReadyToActivate() const;
+ bool AreRequiredTilesReadyToDraw(RasterTilePriorityQueue::Type type) const;
+ void NotifyReadyToActivate();
+ void NotifyReadyToDraw();
void CheckIfReadyToActivate();
+ void CheckIfReadyToDraw();
+ void CheckIfMoreTilesNeedToBePrepared();
TileManagerClient* client_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
ResourcePool* resource_pool_;
- Rasterizer* rasterizer_;
+ TileTaskRunner* tile_task_runner_;
GlobalStateThatImpactsTilePriority global_state_;
- const size_t scheduled_raster_task_limit_;
+ size_t scheduled_raster_task_limit_;
typedef base::hash_map<Tile::Id, Tile*> TileMap;
TileMap tiles_;
@@ -246,9 +280,6 @@ class CC_EXPORT TileManager : public RasterizerClient,
bool all_tiles_that_need_to_be_rasterized_are_scheduled_;
MemoryHistory::Entry memory_stats_from_last_assign_;
- RenderingStatsInstrumentation* rendering_stats_instrumentation_;
-
- bool did_initialize_visible_tile_;
bool did_check_for_completed_tasks_since_last_schedule_tasks_;
bool did_oom_on_last_assign_;
@@ -264,22 +295,21 @@ class CC_EXPORT TileManager : public RasterizerClient,
std::vector<Tile*> released_tiles_;
- ResourceFormat resource_format_;
-
// Queue used when scheduling raster tasks.
- RasterTaskQueue raster_queue_;
+ TileTaskQueue raster_queue_;
std::vector<scoped_refptr<RasterTask>> orphan_raster_tasks_;
UniqueNotifier ready_to_activate_check_notifier_;
+ UniqueNotifier ready_to_draw_check_notifier_;
+ UniqueNotifier more_tiles_need_prepare_check_notifier_;
- RasterTilePriorityQueue raster_priority_queue_;
- EvictionTilePriorityQueue eviction_priority_queue_;
- bool eviction_priority_queue_is_up_to_date_;
+ bool did_notify_ready_to_activate_;
+ bool did_notify_ready_to_draw_;
DISALLOW_COPY_AND_ASSIGN(TileManager);
};
} // namespace cc
-#endif // CC_RESOURCES_TILE_MANAGER_H_
+#endif // CC_TILES_TILE_MANAGER_H_
diff --git a/chromium/cc/resources/tile_manager_perftest.cc b/chromium/cc/tiles/tile_manager_perftest.cc
index 43c10312cfb..7b75a7a09bb 100644
--- a/chromium/cc/resources/tile_manager_perftest.cc
+++ b/chromium/cc/tiles/tile_manager_perftest.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "cc/debug/lap_timer.h"
-#include "cc/resources/raster_buffer.h"
-#include "cc/resources/tile.h"
-#include "cc/resources/tile_priority.h"
+#include "cc/raster/raster_buffer.h"
#include "cc/test/begin_frame_args_test.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
@@ -18,7 +18,10 @@
#include "cc/test/fake_tile_manager_client.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_tile_priorities.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_priority.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,23 +30,20 @@
#include "ui/gfx/frame_time.h"
namespace cc {
-
namespace {
static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;
-class FakeRasterizerImpl : public Rasterizer, public RasterizerTaskClient {
+class FakeTileTaskRunnerImpl : public TileTaskRunner, public TileTaskClient {
public:
- // Overridden from Rasterizer:
- void SetClient(RasterizerClient* client) override {}
+ // Overridden from TileTaskRunner:
+ void SetClient(TileTaskRunnerClient* client) override {}
void Shutdown() override {}
- void ScheduleTasks(RasterTaskQueue* queue) override {
- for (RasterTaskQueue::Item::Vector::const_iterator it =
- queue->items.begin();
- it != queue->items.end();
- ++it) {
+ void ScheduleTasks(TileTaskQueue* queue) override {
+ for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end(); ++it) {
RasterTask* task = it->task;
task->WillSchedule();
@@ -67,8 +67,11 @@ class FakeRasterizerImpl : public Rasterizer, public RasterizerTaskClient {
}
completed_tasks_.clear();
}
+ ResourceFormat GetResourceFormat() override {
+ return RGBA_8888;
+ }
- // Overridden from RasterizerTaskClient:
+ // Overridden from TileTaskClient:
scoped_ptr<RasterBuffer> AcquireBufferForRaster(
const Resource* resource) override {
return nullptr;
@@ -78,7 +81,7 @@ class FakeRasterizerImpl : public Rasterizer, public RasterizerTaskClient {
private:
RasterTask::Vector completed_tasks_;
};
-base::LazyInstance<FakeRasterizerImpl> g_fake_rasterizer =
+base::LazyInstance<FakeTileTaskRunnerImpl> g_fake_tile_task_runner =
LAZY_INSTANCE_INITIALIZER;
class TileManagerPerfTest : public testing::Test {
@@ -87,10 +90,11 @@ class TileManagerPerfTest : public testing::Test {
: memory_limit_policy_(ALLOW_ANYTHING),
max_tiles_(10000),
id_(7),
- proxy_(base::MessageLoopProxy::current()),
+ proxy_(base::ThreadTaskRunnerHandle::Get()),
host_impl_(ImplSidePaintingSettings(10000),
&proxy_,
- &shared_bitmap_manager_),
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval) {}
@@ -111,14 +115,15 @@ class TileManagerPerfTest : public testing::Test {
host_impl_.tile_manager()->SetGlobalStateForTesting(state);
}
- virtual void SetUp() override {
+ void SetUp() override {
InitializeRenderer();
SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
}
virtual void InitializeRenderer() {
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d().Pass());
- tile_manager()->SetRasterizerForTesting(g_fake_rasterizer.Pointer());
+ tile_manager()->SetTileTaskRunnerForTesting(
+ g_fake_tile_task_runner.Pointer());
}
void SetupDefaultTrees(const gfx::Size& layer_bounds) {
@@ -159,21 +164,13 @@ class TileManagerPerfTest : public testing::Test {
pending_tree->DetachLayerTree();
scoped_ptr<FakePictureLayerImpl> pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+ FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, pile);
pending_layer->SetDrawsContent(true);
+ pending_layer->SetHasRenderSurface(true);
pending_tree->SetRootLayer(pending_layer.Pass());
pending_root_layer_ = static_cast<FakePictureLayerImpl*>(
host_impl_.pending_tree()->LayerById(id_));
- pending_root_layer_->DoPostCommitInitializationIfNeeded();
- }
-
- void CreateHighLowResAndSetAllTilesVisible() {
- // Active layer must get updated first so pending layer can share from it.
- active_root_layer_->CreateDefaultTilingsAndTiles();
- active_root_layer_->SetAllTilesVisible();
- pending_root_layer_->CreateDefaultTilingsAndTiles();
- pending_root_layer_->SetAllTilesVisible();
}
void RunRasterQueueConstructTest(const std::string& test_name,
@@ -183,16 +180,15 @@ class TileManagerPerfTest : public testing::Test {
NEW_CONTENT_TAKES_PRIORITY};
int priority_count = 0;
- std::vector<LayerImpl*> layers = CreateLayers(layer_count, 10);
+ std::vector<FakePictureLayerImpl*> layers = CreateLayers(layer_count, 10);
bool resourceless_software_draw = false;
- for (unsigned i = 0; i < layers.size(); ++i) {
- layers[i]->UpdateTiles(Occlusion(), resourceless_software_draw);
- }
+ for (const auto& layer : layers)
+ layer->UpdateTiles(resourceless_software_draw);
timer_.Reset();
do {
- RasterTilePriorityQueue queue;
- host_impl_.BuildRasterQueue(&queue, priorities[priority_count]);
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ priorities[priority_count], RasterTilePriorityQueue::Type::ALL));
priority_count = (priority_count + 1) % arraysize(priorities);
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
@@ -207,27 +203,26 @@ class TileManagerPerfTest : public testing::Test {
void RunRasterQueueConstructAndIterateTest(const std::string& test_name,
int layer_count,
- unsigned tile_count) {
+ int tile_count) {
TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
SMOOTHNESS_TAKES_PRIORITY,
NEW_CONTENT_TAKES_PRIORITY};
- std::vector<LayerImpl*> layers = CreateLayers(layer_count, 100);
+ std::vector<FakePictureLayerImpl*> layers = CreateLayers(layer_count, 100);
bool resourceless_software_draw = false;
- for (unsigned i = 0; i < layers.size(); ++i) {
- layers[i]->UpdateTiles(Occlusion(), resourceless_software_draw);
- }
+ for (const auto& layer : layers)
+ layer->UpdateTiles(resourceless_software_draw);
int priority_count = 0;
timer_.Reset();
do {
int count = tile_count;
- RasterTilePriorityQueue queue;
- host_impl_.BuildRasterQueue(&queue, priorities[priority_count]);
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ priorities[priority_count], RasterTilePriorityQueue::Type::ALL));
while (count--) {
- ASSERT_FALSE(queue.IsEmpty());
- ASSERT_TRUE(queue.Top() != NULL);
- queue.Pop();
+ ASSERT_FALSE(queue->IsEmpty());
+ ASSERT_TRUE(queue->Top().tile());
+ queue->Pop();
}
priority_count = (priority_count + 1) % arraysize(priorities);
timer_.NextLap();
@@ -249,22 +244,20 @@ class TileManagerPerfTest : public testing::Test {
NEW_CONTENT_TAKES_PRIORITY};
int priority_count = 0;
- std::vector<LayerImpl*> layers = CreateLayers(layer_count, 10);
+ std::vector<FakePictureLayerImpl*> layers = CreateLayers(layer_count, 10);
bool resourceless_software_draw = false;
- for (unsigned i = 0; i < layers.size(); ++i) {
- FakePictureLayerImpl* layer =
- static_cast<FakePictureLayerImpl*>(layers[i]);
- layer->UpdateTiles(Occlusion(), resourceless_software_draw);
- for (size_t j = 0; j < layer->GetTilings()->num_tilings(); ++j) {
+ for (const auto& layer : layers) {
+ layer->UpdateTiles(resourceless_software_draw);
+ for (size_t i = 0; i < layer->num_tilings(); ++i) {
tile_manager()->InitializeTilesWithResourcesForTesting(
- layer->GetTilings()->tiling_at(j)->AllTilesForTesting());
+ layer->tilings()->tiling_at(i)->AllTilesForTesting());
}
}
timer_.Reset();
do {
- EvictionTilePriorityQueue queue;
- host_impl_.BuildEvictionQueue(&queue, priorities[priority_count]);
+ scoped_ptr<EvictionTilePriorityQueue> queue(
+ host_impl_.BuildEvictionQueue(priorities[priority_count]));
priority_count = (priority_count + 1) % arraysize(priorities);
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
@@ -279,33 +272,32 @@ class TileManagerPerfTest : public testing::Test {
void RunEvictionQueueConstructAndIterateTest(const std::string& test_name,
int layer_count,
- unsigned tile_count) {
+ int tile_count) {
TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
SMOOTHNESS_TAKES_PRIORITY,
NEW_CONTENT_TAKES_PRIORITY};
int priority_count = 0;
- std::vector<LayerImpl*> layers = CreateLayers(layer_count, tile_count);
+ std::vector<FakePictureLayerImpl*> layers =
+ CreateLayers(layer_count, tile_count);
bool resourceless_software_draw = false;
- for (unsigned i = 0; i < layers.size(); ++i) {
- FakePictureLayerImpl* layer =
- static_cast<FakePictureLayerImpl*>(layers[i]);
- layer->UpdateTiles(Occlusion(), resourceless_software_draw);
- for (size_t j = 0; j < layer->GetTilings()->num_tilings(); ++j) {
+ for (const auto& layer : layers) {
+ layer->UpdateTiles(resourceless_software_draw);
+ for (size_t i = 0; i < layer->num_tilings(); ++i) {
tile_manager()->InitializeTilesWithResourcesForTesting(
- layer->GetTilings()->tiling_at(j)->AllTilesForTesting());
+ layer->tilings()->tiling_at(i)->AllTilesForTesting());
}
}
timer_.Reset();
do {
int count = tile_count;
- EvictionTilePriorityQueue queue;
- host_impl_.BuildEvictionQueue(&queue, priorities[priority_count]);
+ scoped_ptr<EvictionTilePriorityQueue> queue(
+ host_impl_.BuildEvictionQueue(priorities[priority_count]));
while (count--) {
- ASSERT_FALSE(queue.IsEmpty());
- ASSERT_TRUE(queue.Top() != NULL);
- queue.Pop();
+ ASSERT_FALSE(queue->IsEmpty());
+ ASSERT_TRUE(queue->Top().tile());
+ queue->Pop();
}
priority_count = (priority_count + 1) % arraysize(priorities);
timer_.NextLap();
@@ -320,8 +312,8 @@ class TileManagerPerfTest : public testing::Test {
true);
}
- std::vector<LayerImpl*> CreateLayers(int layer_count,
- int tiles_per_layer_count) {
+ std::vector<FakePictureLayerImpl*> CreateLayers(int layer_count,
+ int tiles_per_layer_count) {
// Compute the width/height required for high res to get
// tiles_per_layer_count tiles.
float width = std::sqrt(static_cast<float>(tiles_per_layer_count));
@@ -347,10 +339,7 @@ class TileManagerPerfTest : public testing::Test {
SetupDefaultTreesWithFixedTileSize(layer_bounds,
settings_.default_tile_size);
- active_root_layer_->CreateDefaultTilingsAndTiles();
- pending_root_layer_->CreateDefaultTilingsAndTiles();
-
- std::vector<LayerImpl*> layers;
+ std::vector<FakePictureLayerImpl*> layers;
// Pending layer counts as one layer.
layers.push_back(pending_root_layer_);
@@ -361,21 +350,20 @@ class TileManagerPerfTest : public testing::Test {
FakePicturePileImpl::CreateFilledPile(kDefaultTileSize, layer_bounds);
while (static_cast<int>(layers.size()) < layer_count) {
scoped_ptr<FakePictureLayerImpl> layer =
- FakePictureLayerImpl::CreateWithPile(host_impl_.pending_tree(),
- next_id, pile);
+ FakePictureLayerImpl::CreateWithRasterSource(
+ host_impl_.pending_tree(), next_id, pile);
layer->SetBounds(layer_bounds);
+ layer->SetDrawsContent(true);
layers.push_back(layer.get());
pending_root_layer_->AddChild(layer.Pass());
-
- FakePictureLayerImpl* fake_layer =
- static_cast<FakePictureLayerImpl*>(layers.back());
-
- fake_layer->SetDrawsContent(true);
- fake_layer->DoPostCommitInitializationIfNeeded();
- fake_layer->CreateDefaultTilingsAndTiles();
++next_id;
}
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+ for (FakePictureLayerImpl* layer : layers)
+ layer->CreateAllTiles();
+
return layers;
}
@@ -392,29 +380,29 @@ class TileManagerPerfTest : public testing::Test {
return state;
}
- void RunManageTilesTest(const std::string& test_name,
- int layer_count,
- int approximate_tile_count_per_layer) {
- std::vector<LayerImpl*> layers =
+ void RunPrepareTilesTest(const std::string& test_name,
+ int layer_count,
+ int approximate_tile_count_per_layer) {
+ std::vector<FakePictureLayerImpl*> layers =
CreateLayers(layer_count, approximate_tile_count_per_layer);
timer_.Reset();
bool resourceless_software_draw = false;
do {
- BeginFrameArgs args = CreateBeginFrameArgsForTesting();
- host_impl_.UpdateCurrentBeginFrameArgs(args);
- for (unsigned i = 0; i < layers.size(); ++i) {
- layers[i]->UpdateTiles(Occlusion(), resourceless_software_draw);
- }
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
+ host_impl_.WillBeginImplFrame(args);
+ for (const auto& layer : layers)
+ layer->UpdateTiles(resourceless_software_draw);
GlobalStateThatImpactsTilePriority global_state(GlobalStateForTest());
- tile_manager()->ManageTiles(global_state);
- tile_manager()->UpdateVisibleTiles();
+ tile_manager()->PrepareTiles(global_state);
+ tile_manager()->UpdateVisibleTiles(global_state);
timer_.NextLap();
- host_impl_.ResetCurrentBeginFrameArgsForNextFrame();
+ host_impl_.DidFinishImplFrame();
} while (!timer_.HasTimeLimitExpired());
- perf_test::PrintResult(
- "manage_tiles", "", test_name, timer_.LapsPerSecond(), "runs/s", true);
+ perf_test::PrintResult("prepare_tiles", "", test_name,
+ timer_.LapsPerSecond(), "runs/s", true);
}
TileManager* tile_manager() { return host_impl_.tile_manager(); }
@@ -423,6 +411,7 @@ class TileManagerPerfTest : public testing::Test {
GlobalStateThatImpactsTilePriority global_state_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
TileMemoryLimitPolicy memory_limit_policy_;
int max_tiles_;
int id_;
@@ -438,16 +427,16 @@ class TileManagerPerfTest : public testing::Test {
const gfx::Size TileManagerPerfTest::kDefaultTileSize(100, 100);
-TEST_F(TileManagerPerfTest, ManageTiles) {
- RunManageTilesTest("2_100", 2, 100);
- RunManageTilesTest("2_500", 2, 500);
- RunManageTilesTest("2_1000", 2, 1000);
- RunManageTilesTest("10_100", 10, 100);
- RunManageTilesTest("10_500", 10, 500);
- RunManageTilesTest("10_1000", 10, 1000);
- RunManageTilesTest("50_100", 100, 100);
- RunManageTilesTest("50_500", 100, 500);
- RunManageTilesTest("50_1000", 100, 1000);
+TEST_F(TileManagerPerfTest, PrepareTiles) {
+ RunPrepareTilesTest("2_100", 2, 100);
+ RunPrepareTilesTest("2_500", 2, 500);
+ RunPrepareTilesTest("2_1000", 2, 1000);
+ RunPrepareTilesTest("10_100", 10, 100);
+ RunPrepareTilesTest("10_500", 10, 500);
+ RunPrepareTilesTest("10_1000", 10, 1000);
+ RunPrepareTilesTest("50_100", 100, 100);
+ RunPrepareTilesTest("50_500", 100, 500);
+ RunPrepareTilesTest("50_1000", 100, 1000);
}
TEST_F(TileManagerPerfTest, RasterTileQueueConstruct) {
@@ -493,5 +482,4 @@ TEST_F(TileManagerPerfTest, EvictionTileQueueConstructAndIterate) {
}
} // namespace
-
} // namespace cc
diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc
new file mode 100644
index 00000000000..5c7e3c12b75
--- /dev/null
+++ b/chromium/cc/tiles/tile_manager_unittest.cc
@@ -0,0 +1,1428 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/thread_task_runner_handle.h"
+#include "cc/resources/resource_pool.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/fake_picture_layer_impl.h"
+#include "cc/test/fake_picture_layer_tiling_client.h"
+#include "cc/test/fake_picture_pile_impl.h"
+#include "cc/test/fake_tile_manager.h"
+#include "cc/test/impl_side_painting_settings.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
+#include "cc/test/test_tile_priorities.h"
+#include "cc/tiles/eviction_tile_priority_queue.h"
+#include "cc/tiles/raster_tile_priority_queue.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_priority.h"
+#include "cc/tiles/tiling_set_raster_queue_all.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class LowResTilingsSettings : public ImplSidePaintingSettings {
+ public:
+ LowResTilingsSettings() {
+ tiling_interest_area_viewport_multiplier = 10000;
+ create_low_res_tiling = true;
+ }
+};
+
+class TileManagerTilePriorityQueueTest : public testing::Test {
+ public:
+ TileManagerTilePriorityQueueTest()
+ : memory_limit_policy_(ALLOW_ANYTHING),
+ max_tiles_(10000),
+ ready_to_activate_(false),
+ id_(7),
+ proxy_(base::ThreadTaskRunnerHandle::Get()),
+ host_impl_(LowResTilingsSettings(),
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_) {}
+
+ void SetTreePriority(TreePriority tree_priority) {
+ GlobalStateThatImpactsTilePriority state;
+ gfx::Size tile_size(256, 256);
+
+ state.soft_memory_limit_in_bytes = 100 * 1000 * 1000;
+ state.num_resources_limit = max_tiles_;
+ state.hard_memory_limit_in_bytes = state.soft_memory_limit_in_bytes * 2;
+ state.memory_limit_policy = memory_limit_policy_;
+ state.tree_priority = tree_priority;
+
+ global_state_ = state;
+ host_impl_.resource_pool()->SetResourceUsageLimits(
+ state.soft_memory_limit_in_bytes,
+ state.soft_memory_limit_in_bytes,
+ state.num_resources_limit);
+ host_impl_.tile_manager()->SetGlobalStateForTesting(state);
+ }
+
+ void SetUp() override {
+ InitializeRenderer();
+ SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
+ }
+
+ virtual void InitializeRenderer() {
+ host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
+ }
+
+ void SetupDefaultTrees(const gfx::Size& layer_bounds) {
+ gfx::Size tile_size(100, 100);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+ }
+
+ void ActivateTree() {
+ host_impl_.ActivateSyncTree();
+ CHECK(!host_impl_.pending_tree());
+ pending_layer_ = NULL;
+ active_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.active_tree()->LayerById(id_));
+ }
+
+ void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds,
+ const gfx::Size& tile_size) {
+ SetupDefaultTrees(layer_bounds);
+ pending_layer_->set_fixed_tile_size(tile_size);
+ active_layer_->set_fixed_tile_size(tile_size);
+ }
+
+ void SetupTrees(scoped_refptr<PicturePileImpl> pending_pile,
+ scoped_refptr<PicturePileImpl> active_pile) {
+ SetupPendingTree(active_pile);
+ ActivateTree();
+ SetupPendingTree(pending_pile);
+ }
+
+ void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
+ host_impl_.CreatePendingTree();
+ LayerTreeImpl* pending_tree = host_impl_.pending_tree();
+
+ // Steal from the recycled tree.
+ scoped_ptr<LayerImpl> old_pending_root = pending_tree->DetachLayerTree();
+ DCHECK_IMPLIES(old_pending_root, old_pending_root->id() == id_);
+
+ scoped_ptr<FakePictureLayerImpl> pending_layer;
+ if (old_pending_root) {
+ pending_layer.reset(
+ static_cast<FakePictureLayerImpl*>(old_pending_root.release()));
+ pending_layer->SetRasterSourceOnPending(pile, Region());
+ } else {
+ pending_layer =
+ FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, pile);
+ pending_layer->SetDrawsContent(true);
+ pending_layer->SetHasRenderSurface(true);
+ }
+ // The bounds() just mirror the pile size.
+ pending_layer->SetBounds(pending_layer->raster_source()->GetSize());
+ pending_tree->SetRootLayer(pending_layer.Pass());
+
+ pending_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.pending_tree()->LayerById(id_));
+
+ // Add tilings/tiles for the layer.
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+ }
+
+ TileManager* tile_manager() { return host_impl_.tile_manager(); }
+
+ protected:
+ GlobalStateThatImpactsTilePriority global_state_;
+
+ TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
+ TileMemoryLimitPolicy memory_limit_policy_;
+ int max_tiles_;
+ bool ready_to_activate_;
+ int id_;
+ FakeImplProxy proxy_;
+ FakeLayerTreeHostImpl host_impl_;
+ FakePictureLayerImpl* pending_layer_;
+ FakePictureLayerImpl* active_layer_;
+};
+
+TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueue) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
+
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+
+ size_t tile_count = 0;
+ std::set<Tile*> all_tiles;
+ while (!queue->IsEmpty()) {
+ EXPECT_TRUE(queue->Top().tile());
+ all_tiles.insert(queue->Top().tile());
+ ++tile_count;
+ queue->Pop();
+ }
+
+ EXPECT_EQ(tile_count, all_tiles.size());
+ EXPECT_EQ(16u, tile_count);
+
+ // Sanity check, all tiles should be visible.
+ std::set<Tile*> smoothness_tiles;
+ queue = host_impl_.BuildRasterQueue(SMOOTHNESS_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::ALL);
+ bool had_low_res = false;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile());
+ EXPECT_EQ(TilePriority::NOW, prioritized_tile.priority().priority_bin);
+ if (prioritized_tile.priority().resolution == LOW_RESOLUTION)
+ had_low_res = true;
+ else
+ smoothness_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
+ }
+ EXPECT_EQ(all_tiles, smoothness_tiles);
+ EXPECT_TRUE(had_low_res);
+
+ // Check that everything is required for activation.
+ queue = host_impl_.BuildRasterQueue(
+ SMOOTHNESS_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
+ std::set<Tile*> required_for_activation_tiles;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile()->required_for_activation());
+ required_for_activation_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
+ }
+ EXPECT_EQ(all_tiles, required_for_activation_tiles);
+
+ // Check that everything is required for draw.
+ queue = host_impl_.BuildRasterQueue(
+ SMOOTHNESS_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
+ std::set<Tile*> required_for_draw_tiles;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile()->required_for_draw());
+ required_for_draw_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
+ }
+ EXPECT_EQ(all_tiles, required_for_draw_tiles);
+
+ Region invalidation(gfx::Rect(0, 0, 500, 500));
+
+ // Invalidate the pending tree.
+ pending_layer_->set_invalidation(invalidation);
+ pending_layer_->HighResTiling()->Invalidate(invalidation);
+ pending_layer_->LowResTiling()->Invalidate(invalidation);
+
+ // Renew all of the tile priorities.
+ gfx::Rect viewport(50, 50, 100, 100);
+ pending_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+
+ // Populate all tiles directly from the tilings.
+ all_tiles.clear();
+ std::set<Tile*> high_res_tiles;
+ std::vector<Tile*> pending_high_res_tiles =
+ pending_layer_->HighResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < pending_high_res_tiles.size(); ++i) {
+ all_tiles.insert(pending_high_res_tiles[i]);
+ high_res_tiles.insert(pending_high_res_tiles[i]);
+ }
+
+ std::vector<Tile*> pending_low_res_tiles =
+ pending_layer_->LowResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < pending_low_res_tiles.size(); ++i)
+ all_tiles.insert(pending_low_res_tiles[i]);
+
+ std::vector<Tile*> active_high_res_tiles =
+ active_layer_->HighResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < active_high_res_tiles.size(); ++i) {
+ all_tiles.insert(active_high_res_tiles[i]);
+ high_res_tiles.insert(active_high_res_tiles[i]);
+ }
+
+ std::vector<Tile*> active_low_res_tiles =
+ active_layer_->LowResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < active_low_res_tiles.size(); ++i)
+ all_tiles.insert(active_low_res_tiles[i]);
+
+ PrioritizedTile last_tile;
+ smoothness_tiles.clear();
+ tile_count = 0;
+ size_t correct_order_tiles = 0u;
+ // Here we expect to get increasing ACTIVE_TREE priority_bin.
+ queue = host_impl_.BuildRasterQueue(SMOOTHNESS_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::ALL);
+ std::set<Tile*> expected_required_for_draw_tiles;
+ std::set<Tile*> expected_required_for_activation_tiles;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile());
+
+ if (!last_tile.tile())
+ last_tile = prioritized_tile;
+
+ EXPECT_LE(last_tile.priority().priority_bin,
+ prioritized_tile.priority().priority_bin);
+ bool skip_updating_last_tile = false;
+ if (last_tile.priority().priority_bin ==
+ prioritized_tile.priority().priority_bin) {
+ correct_order_tiles += last_tile.priority().distance_to_visible <=
+ prioritized_tile.priority().distance_to_visible;
+ } else if (prioritized_tile.priority().priority_bin == TilePriority::NOW) {
+ // Since we'd return pending tree now tiles before the eventually tiles on
+ // the active tree, update the value.
+ ++correct_order_tiles;
+ skip_updating_last_tile = true;
+ }
+
+ if (prioritized_tile.priority().priority_bin == TilePriority::NOW &&
+ last_tile.priority().resolution !=
+ prioritized_tile.priority().resolution) {
+ // Low resolution should come first.
+ EXPECT_EQ(LOW_RESOLUTION, last_tile.priority().resolution);
+ }
+
+ if (!skip_updating_last_tile)
+ last_tile = prioritized_tile;
+ ++tile_count;
+ smoothness_tiles.insert(prioritized_tile.tile());
+ if (prioritized_tile.tile()->required_for_draw())
+ expected_required_for_draw_tiles.insert(prioritized_tile.tile());
+ if (prioritized_tile.tile()->required_for_activation())
+ expected_required_for_activation_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
+ }
+
+ EXPECT_EQ(tile_count, smoothness_tiles.size());
+ EXPECT_EQ(all_tiles, smoothness_tiles);
+ // Since we don't guarantee increasing distance due to spiral iterator, we
+ // should check that we're _mostly_ right.
+ EXPECT_GT(correct_order_tiles, 3 * tile_count / 4);
+
+ // Check that we have consistent required_for_activation tiles.
+ queue = host_impl_.BuildRasterQueue(
+ SMOOTHNESS_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
+ required_for_activation_tiles.clear();
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile()->required_for_activation());
+ required_for_activation_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
+ }
+ EXPECT_EQ(expected_required_for_activation_tiles,
+ required_for_activation_tiles);
+ EXPECT_NE(all_tiles, required_for_activation_tiles);
+
+ // Check that we have consistent required_for_draw tiles.
+ queue = host_impl_.BuildRasterQueue(
+ SMOOTHNESS_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
+ required_for_draw_tiles.clear();
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile()->required_for_draw());
+ required_for_draw_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
+ }
+ EXPECT_EQ(expected_required_for_draw_tiles, required_for_draw_tiles);
+ EXPECT_NE(all_tiles, required_for_draw_tiles);
+
+ std::set<Tile*> new_content_tiles;
+ last_tile = PrioritizedTile();
+ size_t increasing_distance_tiles = 0u;
+ // Here we expect to get increasing PENDING_TREE priority_bin.
+ queue = host_impl_.BuildRasterQueue(NEW_CONTENT_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::ALL);
+ tile_count = 0;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile());
+
+ if (!last_tile.tile())
+ last_tile = prioritized_tile;
+
+ EXPECT_LE(last_tile.priority().priority_bin,
+ prioritized_tile.priority().priority_bin);
+ if (last_tile.priority().priority_bin ==
+ prioritized_tile.priority().priority_bin) {
+ increasing_distance_tiles +=
+ last_tile.priority().distance_to_visible <=
+ prioritized_tile.priority().distance_to_visible;
+ }
+
+ if (prioritized_tile.priority().priority_bin == TilePriority::NOW &&
+ last_tile.priority().resolution !=
+ prioritized_tile.priority().resolution) {
+ // High resolution should come first.
+ EXPECT_EQ(HIGH_RESOLUTION, last_tile.priority().resolution);
+ }
+
+ last_tile = prioritized_tile;
+ new_content_tiles.insert(prioritized_tile.tile());
+ ++tile_count;
+ queue->Pop();
+ }
+
+ EXPECT_EQ(tile_count, new_content_tiles.size());
+ EXPECT_EQ(high_res_tiles, new_content_tiles);
+ // Since we don't guarantee increasing distance due to spiral iterator, we
+ // should check that we're _mostly_ right.
+ EXPECT_GE(increasing_distance_tiles, 3 * tile_count / 4);
+
+ // Check that we have consistent required_for_activation tiles.
+ queue = host_impl_.BuildRasterQueue(
+ NEW_CONTENT_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
+ required_for_activation_tiles.clear();
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile()->required_for_activation());
+ required_for_activation_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
+ }
+ EXPECT_EQ(expected_required_for_activation_tiles,
+ required_for_activation_tiles);
+ EXPECT_NE(new_content_tiles, required_for_activation_tiles);
+
+ // Check that we have consistent required_for_draw tiles.
+ queue = host_impl_.BuildRasterQueue(
+ NEW_CONTENT_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
+ required_for_draw_tiles.clear();
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile()->required_for_draw());
+ required_for_draw_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
+ }
+ EXPECT_EQ(expected_required_for_draw_tiles, required_for_draw_tiles);
+ EXPECT_NE(new_content_tiles, required_for_draw_tiles);
+}
+
+TEST_F(TileManagerTilePriorityQueueTest,
+ RasterTilePriorityQueueHighNonIdealTilings) {
+ const gfx::Size layer_bounds(1000, 1000);
+ const gfx::Size viewport(800, 800);
+ host_impl_.SetViewportSize(viewport);
+ SetupDefaultTrees(layer_bounds);
+
+ pending_layer_->tilings()->AddTiling(1.5f, pending_layer_->raster_source());
+ active_layer_->tilings()->AddTiling(1.5f, active_layer_->raster_source());
+ pending_layer_->tilings()->AddTiling(1.7f, pending_layer_->raster_source());
+ active_layer_->tilings()->AddTiling(1.7f, active_layer_->raster_source());
+
+ pending_layer_->tilings()->UpdateTilePriorities(gfx::Rect(viewport), 1.f, 5.0,
+ Occlusion(), true);
+ active_layer_->tilings()->UpdateTilePriorities(gfx::Rect(viewport), 1.f, 5.0,
+ Occlusion(), true);
+
+ std::set<Tile*> all_expected_tiles;
+ for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+ if (tiling->contents_scale() == 1.f) {
+ tiling->set_resolution(HIGH_RESOLUTION);
+ const auto& all_tiles = tiling->AllTilesForTesting();
+ all_expected_tiles.insert(all_tiles.begin(), all_tiles.end());
+ } else {
+ tiling->set_resolution(NON_IDEAL_RESOLUTION);
+ }
+ }
+
+ for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = active_layer_->tilings()->tiling_at(i);
+ if (tiling->contents_scale() == 1.5f) {
+ tiling->set_resolution(HIGH_RESOLUTION);
+ const auto& all_tiles = tiling->AllTilesForTesting();
+ all_expected_tiles.insert(all_tiles.begin(), all_tiles.end());
+ } else {
+ tiling->set_resolution(NON_IDEAL_RESOLUTION);
+ // Non ideal tilings with a high res pending twin have to be processed
+ // because of possible activation tiles.
+ if (tiling->contents_scale() == 1.f) {
+ tiling->UpdateAndGetAllPrioritizedTilesForTesting();
+ const auto& all_tiles = tiling->AllTilesForTesting();
+ for (auto* tile : all_tiles)
+ EXPECT_TRUE(tile->required_for_activation());
+ all_expected_tiles.insert(all_tiles.begin(), all_tiles.end());
+ }
+ }
+ }
+
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SMOOTHNESS_TAKES_PRIORITY, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+
+ size_t tile_count = 0;
+ std::set<Tile*> all_actual_tiles;
+ while (!queue->IsEmpty()) {
+ EXPECT_TRUE(queue->Top().tile());
+ all_actual_tiles.insert(queue->Top().tile());
+ ++tile_count;
+ queue->Pop();
+ }
+
+ EXPECT_EQ(tile_count, all_actual_tiles.size());
+ EXPECT_EQ(all_expected_tiles.size(), all_actual_tiles.size());
+ EXPECT_EQ(all_expected_tiles, all_actual_tiles);
+}
+
+TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueInvalidation) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(gfx::Size(500, 500));
+ SetupDefaultTrees(layer_bounds);
+
+ // Use a tile's content rect as an invalidation. We should inset it a bit to
+ // ensure that border math doesn't invalidate neighbouring tiles.
+ gfx::Rect invalidation =
+ active_layer_->HighResTiling()->TileAt(1, 0)->content_rect();
+ invalidation.Inset(2, 2);
+
+ pending_layer_->set_invalidation(invalidation);
+ pending_layer_->HighResTiling()->Invalidate(invalidation);
+ pending_layer_->HighResTiling()->CreateMissingTilesInLiveTilesRect();
+ pending_layer_->LowResTiling()->Invalidate(invalidation);
+ pending_layer_->LowResTiling()->CreateMissingTilesInLiveTilesRect();
+
+ // Sanity checks: Tile at 0, 0 not exist on the pending tree (it's not
+ // invalidated). Tile 1, 0 should exist on both.
+ EXPECT_FALSE(pending_layer_->HighResTiling()->TileAt(0, 0));
+ EXPECT_TRUE(active_layer_->HighResTiling()->TileAt(0, 0));
+ EXPECT_TRUE(pending_layer_->HighResTiling()->TileAt(1, 0));
+ EXPECT_TRUE(active_layer_->HighResTiling()->TileAt(1, 0));
+ EXPECT_NE(pending_layer_->HighResTiling()->TileAt(1, 0),
+ active_layer_->HighResTiling()->TileAt(1, 0));
+
+ std::set<Tile*> expected_now_tiles;
+ std::set<Tile*> expected_required_for_draw_tiles;
+ std::set<Tile*> expected_required_for_activation_tiles;
+ for (int i = 0; i <= 1; ++i) {
+ for (int j = 0; j <= 1; ++j) {
+ bool have_pending_tile = false;
+ if (pending_layer_->HighResTiling()->TileAt(i, j)) {
+ expected_now_tiles.insert(
+ pending_layer_->HighResTiling()->TileAt(i, j));
+ expected_required_for_activation_tiles.insert(
+ pending_layer_->HighResTiling()->TileAt(i, j));
+ have_pending_tile = true;
+ }
+ Tile* active_tile = active_layer_->HighResTiling()->TileAt(i, j);
+ EXPECT_TRUE(active_tile);
+ expected_now_tiles.insert(active_tile);
+ expected_required_for_draw_tiles.insert(active_tile);
+ if (!have_pending_tile)
+ expected_required_for_activation_tiles.insert(active_tile);
+ }
+ }
+ // Expect 3 shared tiles and 1 unshared tile in total.
+ EXPECT_EQ(5u, expected_now_tiles.size());
+ // Expect 4 tiles for each draw and activation, but not all the same.
+ EXPECT_EQ(4u, expected_required_for_activation_tiles.size());
+ EXPECT_EQ(4u, expected_required_for_draw_tiles.size());
+ EXPECT_NE(expected_required_for_draw_tiles,
+ expected_required_for_activation_tiles);
+
+ std::set<Tile*> expected_all_tiles;
+ for (int i = 0; i <= 3; ++i) {
+ for (int j = 0; j <= 3; ++j) {
+ if (pending_layer_->HighResTiling()->TileAt(i, j))
+ expected_all_tiles.insert(
+ pending_layer_->HighResTiling()->TileAt(i, j));
+ EXPECT_TRUE(active_layer_->HighResTiling()->TileAt(i, j));
+ expected_all_tiles.insert(active_layer_->HighResTiling()->TileAt(i, j));
+ }
+ }
+ // Expect 15 shared tiles and 1 unshared tile.
+ EXPECT_EQ(17u, expected_all_tiles.size());
+
+ // The actual test will now build different queues and verify that the queues
+ // return the same information as computed manually above.
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ std::set<Tile*> actual_now_tiles;
+ std::set<Tile*> actual_all_tiles;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ queue->Pop();
+ if (prioritized_tile.priority().priority_bin == TilePriority::NOW)
+ actual_now_tiles.insert(prioritized_tile.tile());
+ actual_all_tiles.insert(prioritized_tile.tile());
+ }
+ EXPECT_EQ(expected_now_tiles, actual_now_tiles);
+ EXPECT_EQ(expected_all_tiles, actual_all_tiles);
+
+ queue = host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES,
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
+ std::set<Tile*> actual_required_for_draw_tiles;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ queue->Pop();
+ actual_required_for_draw_tiles.insert(prioritized_tile.tile());
+ }
+ EXPECT_EQ(expected_required_for_draw_tiles, actual_required_for_draw_tiles);
+
+ queue = host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES,
+ RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
+ std::set<Tile*> actual_required_for_activation_tiles;
+ while (!queue->IsEmpty()) {
+ Tile* tile = queue->Top().tile();
+ queue->Pop();
+ actual_required_for_activation_tiles.insert(tile);
+ }
+ EXPECT_EQ(expected_required_for_activation_tiles,
+ actual_required_for_activation_tiles);
+}
+
+TEST_F(TileManagerTilePriorityQueueTest, ActivationComesBeforeEventually) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ gfx::Size layer_bounds(1000, 1000);
+ SetupDefaultTrees(layer_bounds);
+
+ // Create a pending child layer.
+ gfx::Size tile_size(256, 256);
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_ptr<FakePictureLayerImpl> pending_child =
+ FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(),
+ id_ + 1, pending_pile);
+ FakePictureLayerImpl* pending_child_raw = pending_child.get();
+ pending_child_raw->SetDrawsContent(true);
+ pending_layer_->AddChild(pending_child.Pass());
+
+ // Set a small viewport, so we have soon and eventually tiles.
+ host_impl_.SetViewportSize(gfx::Size(200, 200));
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+
+ host_impl_.SetRequiresHighResToDraw();
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SMOOTHNESS_TAKES_PRIORITY, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+
+ // Get all the tiles that are NOW or SOON and make sure they are ready to
+ // draw.
+ std::vector<Tile*> all_tiles;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ if (prioritized_tile.priority().priority_bin >= TilePriority::EVENTUALLY)
+ break;
+
+ all_tiles.push_back(prioritized_tile.tile());
+ queue->Pop();
+ }
+
+ tile_manager()->InitializeTilesWithResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ // Ensure we can activate.
+ EXPECT_TRUE(tile_manager()->IsReadyToActivate());
+}
+
+TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
+
+ scoped_ptr<EvictionTilePriorityQueue> empty_queue(
+ host_impl_.BuildEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES));
+ EXPECT_TRUE(empty_queue->IsEmpty());
+ std::set<Tile*> all_tiles;
+ size_t tile_count = 0;
+
+ scoped_ptr<RasterTilePriorityQueue> raster_queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ while (!raster_queue->IsEmpty()) {
+ ++tile_count;
+ EXPECT_TRUE(raster_queue->Top().tile());
+ all_tiles.insert(raster_queue->Top().tile());
+ raster_queue->Pop();
+ }
+
+ EXPECT_EQ(tile_count, all_tiles.size());
+ EXPECT_EQ(16u, tile_count);
+
+ tile_manager()->InitializeTilesWithResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ scoped_ptr<EvictionTilePriorityQueue> queue(
+ host_impl_.BuildEvictionQueue(SMOOTHNESS_TAKES_PRIORITY));
+ EXPECT_FALSE(queue->IsEmpty());
+
+ // Sanity check, all tiles should be visible.
+ std::set<Tile*> smoothness_tiles;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ EXPECT_TRUE(prioritized_tile.tile());
+ EXPECT_EQ(TilePriority::NOW, prioritized_tile.priority().priority_bin);
+ EXPECT_TRUE(prioritized_tile.tile()->draw_info().has_resource());
+ smoothness_tiles.insert(prioritized_tile.tile());
+ queue->Pop();
+ }
+ EXPECT_EQ(all_tiles, smoothness_tiles);
+
+ tile_manager()->ReleaseTileResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ Region invalidation(gfx::Rect(0, 0, 500, 500));
+
+ // Invalidate the pending tree.
+ pending_layer_->set_invalidation(invalidation);
+ pending_layer_->HighResTiling()->Invalidate(invalidation);
+ pending_layer_->HighResTiling()->CreateMissingTilesInLiveTilesRect();
+ pending_layer_->LowResTiling()->Invalidate(invalidation);
+ pending_layer_->LowResTiling()->CreateMissingTilesInLiveTilesRect();
+
+ // Renew all of the tile priorities.
+ gfx::Rect viewport(50, 50, 100, 100);
+ pending_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+
+ // Populate all tiles directly from the tilings.
+ all_tiles.clear();
+ std::vector<Tile*> pending_high_res_tiles =
+ pending_layer_->HighResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < pending_high_res_tiles.size(); ++i)
+ all_tiles.insert(pending_high_res_tiles[i]);
+
+ std::vector<Tile*> pending_low_res_tiles =
+ pending_layer_->LowResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < pending_low_res_tiles.size(); ++i)
+ all_tiles.insert(pending_low_res_tiles[i]);
+
+ std::vector<Tile*> active_high_res_tiles =
+ active_layer_->HighResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < active_high_res_tiles.size(); ++i)
+ all_tiles.insert(active_high_res_tiles[i]);
+
+ std::vector<Tile*> active_low_res_tiles =
+ active_layer_->LowResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < active_low_res_tiles.size(); ++i)
+ all_tiles.insert(active_low_res_tiles[i]);
+
+ tile_manager()->InitializeTilesWithResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ PrioritizedTile last_tile;
+ smoothness_tiles.clear();
+ tile_count = 0;
+ // Here we expect to get increasing combined priority_bin.
+ queue = host_impl_.BuildEvictionQueue(SMOOTHNESS_TAKES_PRIORITY);
+ int distance_increasing = 0;
+ int distance_decreasing = 0;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ Tile* tile = prioritized_tile.tile();
+ EXPECT_TRUE(tile);
+ EXPECT_TRUE(tile->draw_info().has_resource());
+
+ if (!last_tile.tile())
+ last_tile = prioritized_tile;
+
+ const TilePriority& last_priority = last_tile.priority();
+ const TilePriority& priority = prioritized_tile.priority();
+
+ EXPECT_GE(last_priority.priority_bin, priority.priority_bin);
+ if (last_priority.priority_bin == priority.priority_bin) {
+ EXPECT_LE(last_tile.tile()->required_for_activation(),
+ tile->required_for_activation());
+ if (last_tile.tile()->required_for_activation() ==
+ tile->required_for_activation()) {
+ if (last_priority.distance_to_visible >= priority.distance_to_visible)
+ ++distance_decreasing;
+ else
+ ++distance_increasing;
+ }
+ }
+
+ last_tile = prioritized_tile;
+ ++tile_count;
+ smoothness_tiles.insert(tile);
+ queue->Pop();
+ }
+
+ // Ensure that the distance is decreasing many more times than increasing.
+ EXPECT_EQ(3, distance_increasing);
+ EXPECT_EQ(17, distance_decreasing);
+ EXPECT_EQ(tile_count, smoothness_tiles.size());
+ EXPECT_EQ(all_tiles, smoothness_tiles);
+
+ std::set<Tile*> new_content_tiles;
+ last_tile = PrioritizedTile();
+ // Again, we expect to get increasing combined priority_bin.
+ queue = host_impl_.BuildEvictionQueue(NEW_CONTENT_TAKES_PRIORITY);
+ distance_decreasing = 0;
+ distance_increasing = 0;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ Tile* tile = prioritized_tile.tile();
+ EXPECT_TRUE(tile);
+
+ if (!last_tile.tile())
+ last_tile = prioritized_tile;
+
+ const TilePriority& last_priority = last_tile.priority();
+ const TilePriority& priority = prioritized_tile.priority();
+
+ EXPECT_GE(last_priority.priority_bin, priority.priority_bin);
+ if (last_priority.priority_bin == priority.priority_bin) {
+ EXPECT_LE(last_tile.tile()->required_for_activation(),
+ tile->required_for_activation());
+ if (last_tile.tile()->required_for_activation() ==
+ tile->required_for_activation()) {
+ if (last_priority.distance_to_visible >= priority.distance_to_visible)
+ ++distance_decreasing;
+ else
+ ++distance_increasing;
+ }
+ }
+
+ last_tile = prioritized_tile;
+ new_content_tiles.insert(tile);
+ queue->Pop();
+ }
+
+ // Ensure that the distance is decreasing many more times than increasing.
+ EXPECT_EQ(3, distance_increasing);
+ EXPECT_EQ(17, distance_decreasing);
+ EXPECT_EQ(tile_count, new_content_tiles.size());
+ EXPECT_EQ(all_tiles, new_content_tiles);
+}
+
+TEST_F(TileManagerTilePriorityQueueTest,
+ EvictionTilePriorityQueueWithOcclusion) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ gfx::Size tile_size(102, 102);
+ gfx::Size layer_bounds(1000, 1000);
+
+ host_impl_.SetViewportSize(layer_bounds);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ SetupPendingTree(pending_pile);
+
+ scoped_ptr<FakePictureLayerImpl> pending_child =
+ FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 2,
+ pending_pile);
+ pending_layer_->AddChild(pending_child.Pass());
+
+ FakePictureLayerImpl* pending_child_layer =
+ static_cast<FakePictureLayerImpl*>(pending_layer_->children()[0]);
+ pending_child_layer->SetDrawsContent(true);
+
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+
+ ActivateTree();
+ SetupPendingTree(pending_pile);
+
+ FakePictureLayerImpl* active_child_layer =
+ static_cast<FakePictureLayerImpl*>(active_layer_->children()[0]);
+
+ std::set<Tile*> all_tiles;
+ size_t tile_count = 0;
+ scoped_ptr<RasterTilePriorityQueue> raster_queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ while (!raster_queue->IsEmpty()) {
+ ++tile_count;
+ EXPECT_TRUE(raster_queue->Top().tile());
+ all_tiles.insert(raster_queue->Top().tile());
+ raster_queue->Pop();
+ }
+ EXPECT_EQ(tile_count, all_tiles.size());
+ EXPECT_EQ(32u, tile_count);
+
+ // Renew all of the tile priorities.
+ gfx::Rect viewport(layer_bounds);
+ pending_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_child_layer->HighResTiling()->ComputeTilePriorityRects(
+ viewport, 1.0f, 1.0, Occlusion());
+ pending_child_layer->LowResTiling()->ComputeTilePriorityRects(
+ viewport, 1.0f, 1.0, Occlusion());
+
+ active_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_child_layer->HighResTiling()->ComputeTilePriorityRects(
+ viewport, 1.0f, 1.0, Occlusion());
+ active_child_layer->LowResTiling()->ComputeTilePriorityRects(
+ viewport, 1.0f, 1.0, Occlusion());
+
+ // Populate all tiles directly from the tilings.
+ all_tiles.clear();
+ std::vector<Tile*> pending_high_res_tiles =
+ pending_layer_->HighResTiling()->AllTilesForTesting();
+ all_tiles.insert(pending_high_res_tiles.begin(),
+ pending_high_res_tiles.end());
+
+ std::vector<Tile*> pending_low_res_tiles =
+ pending_layer_->LowResTiling()->AllTilesForTesting();
+ all_tiles.insert(pending_low_res_tiles.begin(), pending_low_res_tiles.end());
+
+ // Set all tiles on the pending_child_layer as occluded on the pending tree.
+ std::vector<Tile*> pending_child_high_res_tiles =
+ pending_child_layer->HighResTiling()->AllTilesForTesting();
+ pending_child_layer->HighResTiling()->SetAllTilesOccludedForTesting();
+ active_child_layer->HighResTiling()->SetAllTilesOccludedForTesting();
+ all_tiles.insert(pending_child_high_res_tiles.begin(),
+ pending_child_high_res_tiles.end());
+
+ std::vector<Tile*> pending_child_low_res_tiles =
+ pending_child_layer->LowResTiling()->AllTilesForTesting();
+ pending_child_layer->LowResTiling()->SetAllTilesOccludedForTesting();
+ active_child_layer->LowResTiling()->SetAllTilesOccludedForTesting();
+ all_tiles.insert(pending_child_low_res_tiles.begin(),
+ pending_child_low_res_tiles.end());
+
+ tile_manager()->InitializeTilesWithResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ // Verify occlusion is considered by EvictionTilePriorityQueue.
+ TreePriority tree_priority = NEW_CONTENT_TAKES_PRIORITY;
+ size_t occluded_count = 0u;
+ PrioritizedTile last_tile;
+ scoped_ptr<EvictionTilePriorityQueue> queue(
+ host_impl_.BuildEvictionQueue(tree_priority));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ if (!last_tile.tile())
+ last_tile = prioritized_tile;
+
+ bool tile_is_occluded = prioritized_tile.is_occluded();
+
+ // The only way we will encounter an occluded tile after an unoccluded
+ // tile is if the priorty bin decreased, the tile is required for
+ // activation, or the scale changed.
+ if (tile_is_occluded) {
+ occluded_count++;
+
+ bool last_tile_is_occluded = last_tile.is_occluded();
+ if (!last_tile_is_occluded) {
+ TilePriority::PriorityBin tile_priority_bin =
+ prioritized_tile.priority().priority_bin;
+ TilePriority::PriorityBin last_tile_priority_bin =
+ last_tile.priority().priority_bin;
+
+ EXPECT_TRUE((tile_priority_bin < last_tile_priority_bin) ||
+ prioritized_tile.tile()->required_for_activation() ||
+ (prioritized_tile.tile()->contents_scale() !=
+ last_tile.tile()->contents_scale()));
+ }
+ }
+ last_tile = prioritized_tile;
+ queue->Pop();
+ }
+ size_t expected_occluded_count =
+ pending_child_high_res_tiles.size() + pending_child_low_res_tiles.size();
+ EXPECT_EQ(expected_occluded_count, occluded_count);
+}
+
+TEST_F(TileManagerTilePriorityQueueTest,
+ EvictionTilePriorityQueueWithTransparentLayer) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
+ gfx::Size tile_size(102, 102);
+ gfx::Size layer_bounds(1000, 1000);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ SetupPendingTree(pending_pile);
+
+ scoped_ptr<FakePictureLayerImpl> pending_child =
+ FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 2,
+ pending_pile);
+ FakePictureLayerImpl* pending_child_layer = pending_child.get();
+ pending_layer_->AddChild(pending_child.Pass());
+
+ // Create a fully transparent child layer so that its tile priorities are not
+ // considered to be valid.
+ pending_child_layer->SetDrawsContent(true);
+
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+
+ pending_child_layer->SetOpacity(0.0);
+
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
+
+ // Renew all of the tile priorities.
+ gfx::Rect viewport(layer_bounds);
+ pending_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_child_layer->HighResTiling()->ComputeTilePriorityRects(
+ viewport, 1.0f, 1.0, Occlusion());
+ pending_child_layer->LowResTiling()->ComputeTilePriorityRects(
+ viewport, 1.0f, 1.0, Occlusion());
+
+ // Populate all tiles directly from the tilings.
+ std::set<Tile*> all_pending_tiles;
+ std::vector<Tile*> pending_high_res_tiles =
+ pending_layer_->HighResTiling()->AllTilesForTesting();
+ all_pending_tiles.insert(pending_high_res_tiles.begin(),
+ pending_high_res_tiles.end());
+ EXPECT_EQ(16u, pending_high_res_tiles.size());
+
+ std::vector<Tile*> pending_low_res_tiles =
+ pending_layer_->LowResTiling()->AllTilesForTesting();
+ all_pending_tiles.insert(pending_low_res_tiles.begin(),
+ pending_low_res_tiles.end());
+ EXPECT_EQ(1u, pending_low_res_tiles.size());
+
+ std::set<Tile*> all_pending_child_tiles;
+ std::vector<Tile*> pending_child_high_res_tiles =
+ pending_child_layer->HighResTiling()->AllTilesForTesting();
+ all_pending_child_tiles.insert(pending_child_high_res_tiles.begin(),
+ pending_child_high_res_tiles.end());
+ EXPECT_EQ(16u, pending_child_high_res_tiles.size());
+
+ std::vector<Tile*> pending_child_low_res_tiles =
+ pending_child_layer->LowResTiling()->AllTilesForTesting();
+ all_pending_child_tiles.insert(pending_child_low_res_tiles.begin(),
+ pending_child_low_res_tiles.end());
+ EXPECT_EQ(1u, pending_child_low_res_tiles.size());
+
+ std::set<Tile*> all_tiles = all_pending_tiles;
+ all_tiles.insert(all_pending_child_tiles.begin(),
+ all_pending_child_tiles.end());
+
+ tile_manager()->InitializeTilesWithResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ EXPECT_TRUE(pending_layer_->HasValidTilePriorities());
+ EXPECT_FALSE(pending_child_layer->HasValidTilePriorities());
+
+ // Verify that eviction queue returns tiles also from layers without valid
+ // tile priorities and that the tile priority bin of those tiles is (at most)
+ // EVENTUALLY.
+ TreePriority tree_priority = NEW_CONTENT_TAKES_PRIORITY;
+ std::set<Tile*> new_content_tiles;
+ size_t tile_count = 0;
+ scoped_ptr<EvictionTilePriorityQueue> queue(
+ host_impl_.BuildEvictionQueue(tree_priority));
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ Tile* tile = prioritized_tile.tile();
+ const TilePriority& pending_priority = prioritized_tile.priority();
+ EXPECT_NE(std::numeric_limits<float>::infinity(),
+ pending_priority.distance_to_visible);
+ if (all_pending_child_tiles.find(tile) != all_pending_child_tiles.end())
+ EXPECT_EQ(TilePriority::EVENTUALLY, pending_priority.priority_bin);
+ else
+ EXPECT_EQ(TilePriority::NOW, pending_priority.priority_bin);
+ new_content_tiles.insert(tile);
+ ++tile_count;
+ queue->Pop();
+ }
+ EXPECT_EQ(tile_count, new_content_tiles.size());
+ EXPECT_EQ(all_tiles, new_content_tiles);
+}
+
+TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueEmptyLayers) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
+
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+
+ size_t tile_count = 0;
+ std::set<Tile*> all_tiles;
+ while (!queue->IsEmpty()) {
+ EXPECT_TRUE(queue->Top().tile());
+ all_tiles.insert(queue->Top().tile());
+ ++tile_count;
+ queue->Pop();
+ }
+
+ EXPECT_EQ(tile_count, all_tiles.size());
+ EXPECT_EQ(16u, tile_count);
+
+ for (int i = 1; i < 10; ++i) {
+ scoped_ptr<FakePictureLayerImpl> pending_layer =
+ FakePictureLayerImpl::Create(host_impl_.pending_tree(), id_ + i);
+ pending_layer->SetDrawsContent(true);
+ pending_layer->set_has_valid_tile_priorities(true);
+ pending_layer_->AddChild(pending_layer.Pass());
+ }
+
+ queue = host_impl_.BuildRasterQueue(SAME_PRIORITY_FOR_BOTH_TREES,
+ RasterTilePriorityQueue::Type::ALL);
+ EXPECT_FALSE(queue->IsEmpty());
+
+ tile_count = 0;
+ all_tiles.clear();
+ while (!queue->IsEmpty()) {
+ EXPECT_TRUE(queue->Top().tile());
+ all_tiles.insert(queue->Top().tile());
+ ++tile_count;
+ queue->Pop();
+ }
+ EXPECT_EQ(tile_count, all_tiles.size());
+ EXPECT_EQ(16u, tile_count);
+}
+
+TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueueEmptyLayers) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
+
+ scoped_ptr<RasterTilePriorityQueue> raster_queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(raster_queue->IsEmpty());
+
+ size_t tile_count = 0;
+ std::set<Tile*> all_tiles;
+ while (!raster_queue->IsEmpty()) {
+ EXPECT_TRUE(raster_queue->Top().tile());
+ all_tiles.insert(raster_queue->Top().tile());
+ ++tile_count;
+ raster_queue->Pop();
+ }
+ EXPECT_EQ(tile_count, all_tiles.size());
+ EXPECT_EQ(16u, tile_count);
+
+ std::vector<Tile*> tiles(all_tiles.begin(), all_tiles.end());
+ host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
+
+ for (int i = 1; i < 10; ++i) {
+ scoped_ptr<FakePictureLayerImpl> pending_layer =
+ FakePictureLayerImpl::Create(host_impl_.pending_tree(), id_ + i);
+ pending_layer->SetDrawsContent(true);
+ pending_layer->set_has_valid_tile_priorities(true);
+ pending_layer_->AddChild(pending_layer.Pass());
+ }
+
+ scoped_ptr<EvictionTilePriorityQueue> queue(
+ host_impl_.BuildEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES));
+ EXPECT_FALSE(queue->IsEmpty());
+
+ tile_count = 0;
+ all_tiles.clear();
+ while (!queue->IsEmpty()) {
+ EXPECT_TRUE(queue->Top().tile());
+ all_tiles.insert(queue->Top().tile());
+ ++tile_count;
+ queue->Pop();
+ }
+ EXPECT_EQ(tile_count, all_tiles.size());
+ EXPECT_EQ(16u, tile_count);
+}
+
+TEST_F(TileManagerTilePriorityQueueTest,
+ RasterTilePriorityQueueStaticViewport) {
+ FakePictureLayerTilingClient client;
+
+ gfx::Rect viewport(50, 50, 500, 500);
+ gfx::Size layer_bounds(1600, 1600);
+
+ float inset = PictureLayerTiling::CalculateSoonBorderDistance(viewport, 1.0f);
+ gfx::Rect soon_rect = viewport;
+ soon_rect.Inset(-inset, -inset);
+
+ client.SetTileSize(gfx::Size(30, 30));
+ LayerTreeSettings settings;
+ settings.tiling_interest_area_viewport_multiplier = 10000;
+
+ scoped_ptr<PictureLayerTilingSet> tiling_set = PictureLayerTilingSet::Create(
+ ACTIVE_TREE, &client, settings.tiling_interest_area_viewport_multiplier,
+ settings.skewport_target_time_in_seconds,
+ settings.skewport_extrapolation_limit_in_content_pixels);
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ PictureLayerTiling* tiling = tiling_set->AddTiling(1.0f, pile);
+ tiling->set_resolution(HIGH_RESOLUTION);
+
+ tiling_set->UpdateTilePriorities(viewport, 1.0f, 1.0, Occlusion(), true);
+ std::vector<Tile*> all_tiles = tiling->AllTilesForTesting();
+ // Sanity check.
+ EXPECT_EQ(3364u, all_tiles.size());
+
+ // The explanation of each iteration is as follows:
+ // 1. First iteration tests that we can get all of the tiles correctly.
+ // 2. Second iteration ensures that we can get all of the tiles again (first
+ // iteration didn't change any tiles), as well set all tiles to be ready to
+ // draw.
+ // 3. Third iteration ensures that no tiles are returned, since they were all
+ // marked as ready to draw.
+ for (int i = 0; i < 3; ++i) {
+ scoped_ptr<TilingSetRasterQueueAll> queue(
+ new TilingSetRasterQueueAll(tiling_set.get(), false));
+
+ // There are 3 bins in TilePriority.
+ bool have_tiles[3] = {};
+
+ // On the third iteration, we should get no tiles since everything was
+ // marked as ready to draw.
+ if (i == 2) {
+ EXPECT_TRUE(queue->IsEmpty());
+ continue;
+ }
+
+ EXPECT_FALSE(queue->IsEmpty());
+ std::set<Tile*> unique_tiles;
+ unique_tiles.insert(queue->Top().tile());
+ PrioritizedTile last_tile = queue->Top();
+ have_tiles[last_tile.priority().priority_bin] = true;
+
+ // On the second iteration, mark everything as ready to draw (solid color).
+ if (i == 1) {
+ TileDrawInfo& draw_info = last_tile.tile()->draw_info();
+ draw_info.SetSolidColorForTesting(SK_ColorRED);
+ }
+ queue->Pop();
+ int eventually_bin_order_correct_count = 0;
+ int eventually_bin_order_incorrect_count = 0;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile new_tile = queue->Top();
+ queue->Pop();
+ unique_tiles.insert(new_tile.tile());
+
+ TilePriority last_priority = last_tile.priority();
+ TilePriority new_priority = new_tile.priority();
+ EXPECT_LE(last_priority.priority_bin, new_priority.priority_bin);
+ if (last_priority.priority_bin == new_priority.priority_bin) {
+ if (last_priority.priority_bin == TilePriority::EVENTUALLY) {
+ bool order_correct = last_priority.distance_to_visible <=
+ new_priority.distance_to_visible;
+ eventually_bin_order_correct_count += order_correct;
+ eventually_bin_order_incorrect_count += !order_correct;
+ } else if (!soon_rect.Intersects(new_tile.tile()->content_rect()) &&
+ !soon_rect.Intersects(last_tile.tile()->content_rect())) {
+ EXPECT_LE(last_priority.distance_to_visible,
+ new_priority.distance_to_visible);
+ EXPECT_EQ(TilePriority::NOW, new_priority.priority_bin);
+ } else if (new_priority.distance_to_visible > 0.f) {
+ EXPECT_EQ(TilePriority::SOON, new_priority.priority_bin);
+ }
+ }
+ have_tiles[new_priority.priority_bin] = true;
+
+ last_tile = new_tile;
+
+ // On the second iteration, mark everything as ready to draw (solid
+ // color).
+ if (i == 1) {
+ TileDrawInfo& draw_info = last_tile.tile()->draw_info();
+ draw_info.SetSolidColorForTesting(SK_ColorRED);
+ }
+ }
+
+ EXPECT_GT(eventually_bin_order_correct_count,
+ eventually_bin_order_incorrect_count);
+
+ // We should have now and eventually tiles, as well as soon tiles from
+ // the border region.
+ EXPECT_TRUE(have_tiles[TilePriority::NOW]);
+ EXPECT_TRUE(have_tiles[TilePriority::SOON]);
+ EXPECT_TRUE(have_tiles[TilePriority::EVENTUALLY]);
+
+ EXPECT_EQ(unique_tiles.size(), all_tiles.size());
+ }
+}
+
+TEST_F(TileManagerTilePriorityQueueTest,
+ RasterTilePriorityQueueMovingViewport) {
+ FakePictureLayerTilingClient client;
+
+ gfx::Rect viewport(50, 0, 100, 100);
+ gfx::Rect moved_viewport(50, 0, 100, 500);
+ gfx::Size layer_bounds(1000, 1000);
+
+ client.SetTileSize(gfx::Size(30, 30));
+ LayerTreeSettings settings;
+
+ scoped_ptr<PictureLayerTilingSet> tiling_set = PictureLayerTilingSet::Create(
+ ACTIVE_TREE, &client, settings.tiling_interest_area_viewport_multiplier,
+ settings.skewport_target_time_in_seconds,
+ settings.skewport_extrapolation_limit_in_content_pixels);
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ PictureLayerTiling* tiling = tiling_set->AddTiling(1.0f, pile);
+ tiling->set_resolution(HIGH_RESOLUTION);
+
+ tiling_set->UpdateTilePriorities(viewport, 1.0f, 1.0, Occlusion(), true);
+ tiling_set->UpdateTilePriorities(moved_viewport, 1.0f, 2.0, Occlusion(),
+ true);
+
+ float inset =
+ PictureLayerTiling::CalculateSoonBorderDistance(moved_viewport, 1.0f);
+ gfx::Rect soon_rect = moved_viewport;
+ soon_rect.Inset(-inset, -inset);
+
+ // There are 3 bins in TilePriority.
+ bool have_tiles[3] = {};
+ PrioritizedTile last_tile;
+ int eventually_bin_order_correct_count = 0;
+ int eventually_bin_order_incorrect_count = 0;
+ scoped_ptr<TilingSetRasterQueueAll> queue(
+ new TilingSetRasterQueueAll(tiling_set.get(), false));
+ for (; !queue->IsEmpty(); queue->Pop()) {
+ if (!last_tile.tile())
+ last_tile = queue->Top();
+
+ const PrioritizedTile& new_tile = queue->Top();
+
+ TilePriority last_priority = last_tile.priority();
+ TilePriority new_priority = new_tile.priority();
+
+ have_tiles[new_priority.priority_bin] = true;
+
+ EXPECT_LE(last_priority.priority_bin, new_priority.priority_bin);
+ if (last_priority.priority_bin == new_priority.priority_bin) {
+ if (last_priority.priority_bin == TilePriority::EVENTUALLY) {
+ bool order_correct = last_priority.distance_to_visible <=
+ new_priority.distance_to_visible;
+ eventually_bin_order_correct_count += order_correct;
+ eventually_bin_order_incorrect_count += !order_correct;
+ } else if (!soon_rect.Intersects(new_tile.tile()->content_rect()) &&
+ !soon_rect.Intersects(last_tile.tile()->content_rect())) {
+ EXPECT_LE(last_priority.distance_to_visible,
+ new_priority.distance_to_visible);
+ } else if (new_priority.distance_to_visible > 0.f) {
+ EXPECT_EQ(TilePriority::SOON, new_priority.priority_bin);
+ }
+ }
+ last_tile = new_tile;
+ }
+
+ EXPECT_GT(eventually_bin_order_correct_count,
+ eventually_bin_order_incorrect_count);
+
+ EXPECT_TRUE(have_tiles[TilePriority::NOW]);
+ EXPECT_TRUE(have_tiles[TilePriority::SOON]);
+ EXPECT_TRUE(have_tiles[TilePriority::EVENTUALLY]);
+}
+
+TEST_F(TileManagerTilePriorityQueueTest, SetIsLikelyToRequireADraw) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
+
+ // Verify that the queue has a required for draw tile at Top.
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+ EXPECT_TRUE(queue->Top().tile()->required_for_draw());
+
+ EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());
+ host_impl_.tile_manager()->PrepareTiles(host_impl_.global_tile_state());
+ EXPECT_TRUE(host_impl_.is_likely_to_require_a_draw());
+}
+
+TEST_F(TileManagerTilePriorityQueueTest,
+ SetIsLikelyToRequireADrawOnZeroMemoryBudget) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
+
+ // Verify that the queue has a required for draw tile at Top.
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+ EXPECT_TRUE(queue->Top().tile()->required_for_draw());
+
+ ManagedMemoryPolicy policy = host_impl_.ActualManagedMemoryPolicy();
+ policy.bytes_limit_when_visible = 0;
+ host_impl_.SetMemoryPolicy(policy);
+
+ EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());
+ host_impl_.tile_manager()->PrepareTiles(host_impl_.global_tile_state());
+ EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());
+}
+
+TEST_F(TileManagerTilePriorityQueueTest,
+ SetIsLikelyToRequireADrawOnLimitedMemoryBudget) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
+
+ // Verify that the queue has a required for draw tile at Top.
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+ EXPECT_TRUE(queue->Top().tile()->required_for_draw());
+ EXPECT_EQ(gfx::Size(256, 256), queue->Top().tile()->desired_texture_size());
+ EXPECT_EQ(RGBA_8888, host_impl_.resource_provider()->best_texture_format());
+
+ ManagedMemoryPolicy policy = host_impl_.ActualManagedMemoryPolicy();
+ policy.bytes_limit_when_visible =
+ Resource::MemorySizeBytes(gfx::Size(256, 256), RGBA_8888);
+ host_impl_.SetMemoryPolicy(policy);
+
+ EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());
+ host_impl_.tile_manager()->PrepareTiles(host_impl_.global_tile_state());
+ EXPECT_TRUE(host_impl_.is_likely_to_require_a_draw());
+
+ scoped_ptr<ScopedResource> resource =
+ host_impl_.resource_pool()->AcquireResource(gfx::Size(256, 256),
+ RGBA_8888);
+
+ host_impl_.tile_manager()->CheckIfMoreTilesNeedToBePreparedForTesting();
+ EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());
+
+ host_impl_.resource_pool()->ReleaseResource(resource.Pass());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/resources/tile_priority.cc b/chromium/cc/tiles/tile_priority.cc
index 26826af450e..cf9872e6dcd 100644
--- a/chromium/cc/resources/tile_priority.cc
+++ b/chromium/cc/tiles/tile_priority.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/tile_priority.h"
+#include "cc/tiles/tile_priority.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/math_util.h"
@@ -48,7 +48,7 @@ std::string TilePriorityBinToString(TilePriority::PriorityBin bin) {
return "<unknown TilePriority::PriorityBin value>";
}
-void TilePriority::AsValueInto(base::debug::TracedValue* state) const {
+void TilePriority::AsValueInto(base::trace_event::TracedValue* state) const {
state->SetString("resolution", TileResolutionToString(resolution));
state->SetString("priority_bin", TilePriorityBinToString(priority_bin));
state->SetDouble("distance_to_visible",
@@ -86,7 +86,7 @@ std::string TreePriorityToString(TreePriority prio) {
}
void GlobalStateThatImpactsTilePriority::AsValueInto(
- base::debug::TracedValue* state) const {
+ base::trace_event::TracedValue* state) const {
state->SetString("memory_limit_policy",
TileMemoryLimitPolicyToString(memory_limit_policy));
state->SetInteger("soft_memory_limit_in_bytes", soft_memory_limit_in_bytes);
diff --git a/chromium/cc/resources/tile_priority.h b/chromium/cc/tiles/tile_priority.h
index d1610571863..184fc2dd181 100644
--- a/chromium/cc/resources/tile_priority.h
+++ b/chromium/cc/tiles/tile_priority.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_RESOURCES_TILE_PRIORITY_H_
-#define CC_RESOURCES_TILE_PRIORITY_H_
+#ifndef CC_TILES_TILE_PRIORITY_H_
+#define CC_TILES_TILE_PRIORITY_H_
#include <algorithm>
#include <limits>
#include <string>
-#include "base/debug/trace_event_argument.h"
#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/base/cc_export.h"
namespace base {
@@ -24,7 +24,7 @@ enum WhichTree {
// e.g. in Tile::priority_.
ACTIVE_TREE = 0,
PENDING_TREE = 1,
- NUM_TREES = 2
+ LAST_TREE = 1
// Be sure to update WhichTreeAsValue when adding new fields.
};
scoped_ptr<base::Value> WhichTreeAsValue(WhichTree tree);
@@ -51,40 +51,7 @@ struct CC_EXPORT TilePriority {
priority_bin(bin),
distance_to_visible(distance_to_visible) {}
- TilePriority(const TilePriority& active, const TilePriority& pending) {
- if (active.resolution == HIGH_RESOLUTION ||
- pending.resolution == HIGH_RESOLUTION)
- resolution = HIGH_RESOLUTION;
- else if (active.resolution == LOW_RESOLUTION ||
- pending.resolution == LOW_RESOLUTION)
- resolution = LOW_RESOLUTION;
- else
- resolution = NON_IDEAL_RESOLUTION;
-
- if (active.priority_bin < pending.priority_bin) {
- priority_bin = active.priority_bin;
- distance_to_visible = active.distance_to_visible;
- } else if (active.priority_bin > pending.priority_bin) {
- priority_bin = pending.priority_bin;
- distance_to_visible = pending.distance_to_visible;
- } else {
- priority_bin = active.priority_bin;
- distance_to_visible =
- std::min(active.distance_to_visible, pending.distance_to_visible);
- }
- }
-
- void AsValueInto(base::debug::TracedValue* dict) const;
-
- bool operator ==(const TilePriority& other) const {
- return resolution == other.resolution &&
- priority_bin == other.priority_bin &&
- distance_to_visible == other.distance_to_visible;
- }
-
- bool operator !=(const TilePriority& other) const {
- return !(*this == other);
- }
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
bool IsHigherPriorityThan(const TilePriority& other) const {
return priority_bin < other.priority_bin ||
@@ -118,7 +85,7 @@ enum TreePriority {
SAME_PRIORITY_FOR_BOTH_TREES,
SMOOTHNESS_TAKES_PRIORITY,
NEW_CONTENT_TAKES_PRIORITY,
- NUM_TREE_PRIORITIES
+ LAST_TREE_PRIORITY = NEW_CONTENT_TAKES_PRIORITY
// Be sure to update TreePriorityAsValue when adding new fields.
};
std::string TreePriorityToString(TreePriority prio);
@@ -151,9 +118,9 @@ class GlobalStateThatImpactsTilePriority {
return !(*this == other);
}
- void AsValueInto(base::debug::TracedValue* dict) const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
};
} // namespace cc
-#endif // CC_RESOURCES_TILE_PRIORITY_H_
+#endif // CC_TILES_TILE_PRIORITY_H_
diff --git a/chromium/cc/resources/tile_priority_unittest.cc b/chromium/cc/tiles/tile_priority_unittest.cc
index e134bc97642..14627bb5712 100644
--- a/chromium/cc/resources/tile_priority_unittest.cc
+++ b/chromium/cc/tiles/tile_priority_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/resources/tile_priority.h"
+#include "cc/tiles/tile_priority.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
diff --git a/chromium/cc/tiles/tiling_set_eviction_queue.cc b/chromium/cc/tiles/tiling_set_eviction_queue.cc
new file mode 100644
index 00000000000..9329d0db29a
--- /dev/null
+++ b/chromium/cc/tiles/tiling_set_eviction_queue.cc
@@ -0,0 +1,523 @@
+// Copyright 2014 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 <utility>
+
+#include "cc/tiles/tiling_set_eviction_queue.h"
+
+namespace cc {
+
+TilingSetEvictionQueue::TilingSetEvictionQueue(
+ PictureLayerTilingSet* tiling_set)
+ : tree_(tiling_set->tree()), phase_(EVENTUALLY_RECT) {
+ // Early out if the layer has no tilings.
+ if (!tiling_set->num_tilings())
+ return;
+ GenerateTilingOrder(tiling_set);
+ eventually_iterator_ = EventuallyTilingIterator(&tilings_, tree_);
+ if (eventually_iterator_.done()) {
+ AdvancePhase();
+ return;
+ }
+ current_tile_ = *eventually_iterator_;
+}
+
+TilingSetEvictionQueue::~TilingSetEvictionQueue() {
+}
+
+void TilingSetEvictionQueue::GenerateTilingOrder(
+ PictureLayerTilingSet* tiling_set) {
+ tilings_.reserve(tiling_set->num_tilings());
+ // Generate all of the tilings in the order described in the header comment
+ // for this class.
+ PictureLayerTilingSet::TilingRange range =
+ tiling_set->GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
+ for (int i = range.start; i < range.end; ++i) {
+ PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+ if (tiling->has_tiles())
+ tilings_.push_back(tiling);
+ }
+
+ range = tiling_set->GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES);
+ for (int i = range.end - 1; i >= range.start; --i) {
+ PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+ if (tiling->has_tiles())
+ tilings_.push_back(tiling);
+ }
+
+ range = tiling_set->GetTilingRange(
+ PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
+ for (int i = range.end - 1; i >= range.start; --i) {
+ PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+ if (tiling->has_tiles())
+ tilings_.push_back(tiling);
+ }
+
+ range = tiling_set->GetTilingRange(PictureLayerTilingSet::LOW_RES);
+ for (int i = range.start; i < range.end; ++i) {
+ PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+ if (tiling->has_tiles())
+ tilings_.push_back(tiling);
+ }
+
+ range = tiling_set->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
+ for (int i = range.start; i < range.end; ++i) {
+ PictureLayerTiling* tiling = tiling_set->tiling_at(i);
+ if (tiling->has_tiles())
+ tilings_.push_back(tiling);
+ }
+ DCHECK_GE(tiling_set->num_tilings(), tilings_.size());
+}
+
+void TilingSetEvictionQueue::AdvancePhase() {
+ current_tile_ = PrioritizedTile();
+ while (!current_tile_.tile() &&
+ phase_ != VISIBLE_RECT_REQUIRED_FOR_ACTIVATION_UNOCCLUDED) {
+ phase_ = static_cast<Phase>(phase_ + 1);
+ switch (phase_) {
+ case EVENTUALLY_RECT:
+ NOTREACHED();
+ break;
+ case SOON_BORDER_RECT:
+ soon_iterator_ = SoonBorderTilingIterator(&tilings_, tree_);
+ if (!soon_iterator_.done())
+ current_tile_ = *soon_iterator_;
+ break;
+ case SKEWPORT_RECT:
+ skewport_iterator_ = SkewportTilingIterator(&tilings_, tree_);
+ if (!skewport_iterator_.done())
+ current_tile_ = *skewport_iterator_;
+ break;
+ case PENDING_VISIBLE_RECT:
+ pending_visible_iterator_ = PendingVisibleTilingIterator(
+ &tilings_, tree_, false /* return required for activation tiles */);
+ if (!pending_visible_iterator_.done())
+ current_tile_ = *pending_visible_iterator_;
+ break;
+ case PENDING_VISIBLE_RECT_REQUIRED_FOR_ACTIVATION:
+ pending_visible_iterator_ = PendingVisibleTilingIterator(
+ &tilings_, tree_, true /* return required for activation tiles */);
+ if (!pending_visible_iterator_.done())
+ current_tile_ = *pending_visible_iterator_;
+ break;
+ case VISIBLE_RECT_OCCLUDED:
+ visible_iterator_ = VisibleTilingIterator(
+ &tilings_, tree_, true /* return occluded tiles */,
+ false /* return required for activation tiles */);
+ if (!visible_iterator_.done())
+ current_tile_ = *visible_iterator_;
+ break;
+ case VISIBLE_RECT_UNOCCLUDED:
+ visible_iterator_ = VisibleTilingIterator(
+ &tilings_, tree_, false /* return occluded tiles */,
+ false /* return required for activation tiles */);
+ if (!visible_iterator_.done())
+ current_tile_ = *visible_iterator_;
+ break;
+ case VISIBLE_RECT_REQUIRED_FOR_ACTIVATION_OCCLUDED:
+ visible_iterator_ = VisibleTilingIterator(
+ &tilings_, tree_, true /* return occluded tiles */,
+ true /* return required for activation tiles */);
+ if (!visible_iterator_.done())
+ current_tile_ = *visible_iterator_;
+ break;
+ case VISIBLE_RECT_REQUIRED_FOR_ACTIVATION_UNOCCLUDED:
+ visible_iterator_ = VisibleTilingIterator(
+ &tilings_, tree_, false /* return occluded tiles */,
+ true /* return required for activation tiles */);
+ if (!visible_iterator_.done())
+ current_tile_ = *visible_iterator_;
+ break;
+ }
+ }
+}
+
+bool TilingSetEvictionQueue::IsEmpty() const {
+ return !current_tile_.tile();
+}
+
+const PrioritizedTile& TilingSetEvictionQueue::Top() const {
+ DCHECK(!IsEmpty());
+ return current_tile_;
+}
+
+void TilingSetEvictionQueue::Pop() {
+ DCHECK(!IsEmpty());
+ current_tile_ = PrioritizedTile();
+ switch (phase_) {
+ case EVENTUALLY_RECT:
+ ++eventually_iterator_;
+ if (!eventually_iterator_.done())
+ current_tile_ = *eventually_iterator_;
+ break;
+ case SOON_BORDER_RECT:
+ ++soon_iterator_;
+ if (!soon_iterator_.done())
+ current_tile_ = *soon_iterator_;
+ break;
+ case SKEWPORT_RECT:
+ ++skewport_iterator_;
+ if (!skewport_iterator_.done())
+ current_tile_ = *skewport_iterator_;
+ break;
+ case PENDING_VISIBLE_RECT:
+ case PENDING_VISIBLE_RECT_REQUIRED_FOR_ACTIVATION:
+ ++pending_visible_iterator_;
+ if (!pending_visible_iterator_.done())
+ current_tile_ = *pending_visible_iterator_;
+ break;
+ case VISIBLE_RECT_OCCLUDED:
+ case VISIBLE_RECT_UNOCCLUDED:
+ case VISIBLE_RECT_REQUIRED_FOR_ACTIVATION_OCCLUDED:
+ case VISIBLE_RECT_REQUIRED_FOR_ACTIVATION_UNOCCLUDED:
+ ++visible_iterator_;
+ if (!visible_iterator_.done())
+ current_tile_ = *visible_iterator_;
+ break;
+ }
+ if (!current_tile_.tile())
+ AdvancePhase();
+}
+
+// EvictionRectIterator
+TilingSetEvictionQueue::EvictionRectIterator::EvictionRectIterator()
+ : tilings_(nullptr), tree_(ACTIVE_TREE), tiling_index_(0) {
+}
+
+TilingSetEvictionQueue::EvictionRectIterator::EvictionRectIterator(
+ std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree,
+ PictureLayerTiling::PriorityRectType priority_rect_type)
+ : tilings_(tilings),
+ tree_(tree),
+ priority_rect_type_(priority_rect_type),
+ tiling_index_(0) {
+}
+
+template <typename TilingIteratorType>
+bool TilingSetEvictionQueue::EvictionRectIterator::AdvanceToNextTile(
+ TilingIteratorType* iterator) {
+ bool found_tile = false;
+ while (!found_tile) {
+ ++(*iterator);
+ if (!(*iterator)) {
+ prioritized_tile_ = PrioritizedTile();
+ break;
+ }
+ found_tile = GetFirstTileAndCheckIfValid(iterator);
+ }
+ return found_tile;
+}
+
+template <typename TilingIteratorType>
+bool TilingSetEvictionQueue::EvictionRectIterator::GetFirstTileAndCheckIfValid(
+ TilingIteratorType* iterator) {
+ PictureLayerTiling* tiling = (*tilings_)[tiling_index_];
+ Tile* tile = tiling->TileAt(iterator->index_x(), iterator->index_y());
+ prioritized_tile_ = PrioritizedTile();
+ // If there's nothing to evict, return false.
+ if (!tile || !tile->draw_info().has_resource())
+ return false;
+ // After the pending visible rect has been processed, we must return false
+ // for pending visible rect tiles as tiling iterators do not ignore those
+ // tiles.
+ if (priority_rect_type_ > PictureLayerTiling::PENDING_VISIBLE_RECT &&
+ tiling->pending_visible_rect().Intersects(tile->content_rect())) {
+ return false;
+ }
+ (*tilings_)[tiling_index_]->UpdateRequiredStatesOnTile(tile);
+ prioritized_tile_ = (*tilings_)[tiling_index_]->MakePrioritizedTile(
+ tile, priority_rect_type_);
+ // In other cases, the tile we got is a viable candidate, return true.
+ return true;
+}
+
+// EventuallyTilingIterator
+TilingSetEvictionQueue::EventuallyTilingIterator::EventuallyTilingIterator(
+ std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree)
+ : EvictionRectIterator(tilings, tree, PictureLayerTiling::EVENTUALLY_RECT) {
+ // Find the first tiling with a tile.
+ while (tiling_index_ < tilings_->size()) {
+ if (!(*tilings_)[tiling_index_]->has_eventually_rect_tiles()) {
+ ++tiling_index_;
+ continue;
+ }
+ iterator_ = TilingData::ReverseSpiralDifferenceIterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->current_eventually_rect(),
+ (*tilings_)[tiling_index_]->current_skewport_rect(),
+ (*tilings_)[tiling_index_]->current_soon_border_rect());
+ if (!iterator_) {
+ ++tiling_index_;
+ continue;
+ }
+ break;
+ }
+ if (tiling_index_ >= tilings_->size())
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_))
+ ++(*this);
+}
+
+TilingSetEvictionQueue::EventuallyTilingIterator&
+ TilingSetEvictionQueue::EventuallyTilingIterator::
+ operator++() {
+ bool found_tile = AdvanceToNextTile(&iterator_);
+ while (!found_tile && (tiling_index_ + 1) < tilings_->size()) {
+ ++tiling_index_;
+ if (!(*tilings_)[tiling_index_]->has_eventually_rect_tiles())
+ continue;
+ iterator_ = TilingData::ReverseSpiralDifferenceIterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->current_eventually_rect(),
+ (*tilings_)[tiling_index_]->current_skewport_rect(),
+ (*tilings_)[tiling_index_]->current_soon_border_rect());
+ if (!iterator_)
+ continue;
+ found_tile = GetFirstTileAndCheckIfValid(&iterator_);
+ if (!found_tile)
+ found_tile = AdvanceToNextTile(&iterator_);
+ }
+ return *this;
+}
+
+// SoonBorderTilingIterator
+TilingSetEvictionQueue::SoonBorderTilingIterator::SoonBorderTilingIterator(
+ std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree)
+ : EvictionRectIterator(tilings,
+ tree,
+ PictureLayerTiling::SOON_BORDER_RECT) {
+ // Find the first tiling with a tile.
+ while (tiling_index_ < tilings_->size()) {
+ if (!(*tilings_)[tiling_index_]->has_soon_border_rect_tiles()) {
+ ++tiling_index_;
+ continue;
+ }
+ iterator_ = TilingData::ReverseSpiralDifferenceIterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->current_soon_border_rect(),
+ (*tilings_)[tiling_index_]->current_skewport_rect(),
+ (*tilings_)[tiling_index_]->current_visible_rect());
+ if (!iterator_) {
+ ++tiling_index_;
+ continue;
+ }
+ break;
+ }
+ if (tiling_index_ >= tilings_->size())
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_))
+ ++(*this);
+}
+
+TilingSetEvictionQueue::SoonBorderTilingIterator&
+ TilingSetEvictionQueue::SoonBorderTilingIterator::
+ operator++() {
+ bool found_tile = AdvanceToNextTile(&iterator_);
+ while (!found_tile && (tiling_index_ + 1) < tilings_->size()) {
+ ++tiling_index_;
+ if (!(*tilings_)[tiling_index_]->has_soon_border_rect_tiles())
+ continue;
+ iterator_ = TilingData::ReverseSpiralDifferenceIterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->current_soon_border_rect(),
+ (*tilings_)[tiling_index_]->current_skewport_rect(),
+ (*tilings_)[tiling_index_]->current_visible_rect());
+ if (!iterator_)
+ continue;
+ found_tile = GetFirstTileAndCheckIfValid(&iterator_);
+ if (!found_tile)
+ found_tile = AdvanceToNextTile(&iterator_);
+ }
+ return *this;
+}
+
+// SkewportTilingIterator
+TilingSetEvictionQueue::SkewportTilingIterator::SkewportTilingIterator(
+ std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree)
+ : EvictionRectIterator(tilings, tree, PictureLayerTiling::SKEWPORT_RECT) {
+ // Find the first tiling with a tile.
+ while (tiling_index_ < tilings_->size()) {
+ if (!(*tilings_)[tiling_index_]->has_skewport_rect_tiles()) {
+ ++tiling_index_;
+ continue;
+ }
+ iterator_ = TilingData::ReverseSpiralDifferenceIterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->current_skewport_rect(),
+ (*tilings_)[tiling_index_]->current_visible_rect(),
+ (*tilings_)[tiling_index_]->current_visible_rect());
+ if (!iterator_) {
+ ++tiling_index_;
+ continue;
+ }
+ break;
+ }
+ if (tiling_index_ >= tilings_->size())
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_))
+ ++(*this);
+}
+
+TilingSetEvictionQueue::SkewportTilingIterator&
+ TilingSetEvictionQueue::SkewportTilingIterator::
+ operator++() {
+ bool found_tile = AdvanceToNextTile(&iterator_);
+ while (!found_tile && (tiling_index_ + 1) < tilings_->size()) {
+ ++tiling_index_;
+ if (!(*tilings_)[tiling_index_]->has_skewport_rect_tiles())
+ continue;
+ iterator_ = TilingData::ReverseSpiralDifferenceIterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->current_skewport_rect(),
+ (*tilings_)[tiling_index_]->current_visible_rect(),
+ (*tilings_)[tiling_index_]->current_visible_rect());
+ if (!iterator_)
+ continue;
+ found_tile = GetFirstTileAndCheckIfValid(&iterator_);
+ if (!found_tile)
+ found_tile = AdvanceToNextTile(&iterator_);
+ }
+ return *this;
+}
+
+// PendingVisibleIterator
+TilingSetEvictionQueue::PendingVisibleTilingIterator::
+ PendingVisibleTilingIterator(std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree,
+ bool return_required_for_activation_tiles)
+ : EvictionRectIterator(tilings,
+ tree,
+ PictureLayerTiling::PENDING_VISIBLE_RECT),
+ return_required_for_activation_tiles_(
+ return_required_for_activation_tiles) {
+ // Find the first tiling with a tile.
+ while (tiling_index_ < tilings_->size()) {
+ iterator_ = TilingData::DifferenceIterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->pending_visible_rect(),
+ (*tilings_)[tiling_index_]->current_visible_rect());
+ if (!iterator_) {
+ ++tiling_index_;
+ continue;
+ }
+ break;
+ }
+ if (tiling_index_ >= tilings_->size())
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_)) {
+ ++(*this);
+ return;
+ }
+ if (!TileMatchesRequiredFlags(prioritized_tile_)) {
+ ++(*this);
+ return;
+ }
+}
+
+TilingSetEvictionQueue::PendingVisibleTilingIterator&
+ TilingSetEvictionQueue::PendingVisibleTilingIterator::
+ operator++() {
+ bool found_tile = AdvanceToNextTile(&iterator_);
+ while (found_tile && !TileMatchesRequiredFlags(prioritized_tile_))
+ found_tile = AdvanceToNextTile(&iterator_);
+
+ while (!found_tile && (tiling_index_ + 1) < tilings_->size()) {
+ ++tiling_index_;
+ iterator_ = TilingData::DifferenceIterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->pending_visible_rect(),
+ (*tilings_)[tiling_index_]->current_visible_rect());
+ if (!iterator_)
+ continue;
+ found_tile = GetFirstTileAndCheckIfValid(&iterator_);
+ if (!found_tile)
+ found_tile = AdvanceToNextTile(&iterator_);
+ while (found_tile && !TileMatchesRequiredFlags(prioritized_tile_))
+ found_tile = AdvanceToNextTile(&iterator_);
+ }
+ return *this;
+}
+
+bool TilingSetEvictionQueue::PendingVisibleTilingIterator::
+ TileMatchesRequiredFlags(const PrioritizedTile& tile) const {
+ bool activation_flag_matches = tile.tile()->required_for_activation() ==
+ return_required_for_activation_tiles_;
+ return activation_flag_matches;
+}
+
+// VisibleTilingIterator
+TilingSetEvictionQueue::VisibleTilingIterator::VisibleTilingIterator(
+ std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree,
+ bool return_occluded_tiles,
+ bool return_required_for_activation_tiles)
+ : EvictionRectIterator(tilings, tree, PictureLayerTiling::VISIBLE_RECT),
+ return_occluded_tiles_(return_occluded_tiles),
+ return_required_for_activation_tiles_(
+ return_required_for_activation_tiles) {
+ // Find the first tiling with a tile.
+ while (tiling_index_ < tilings_->size()) {
+ if (!(*tilings_)[tiling_index_]->has_visible_rect_tiles()) {
+ ++tiling_index_;
+ continue;
+ }
+ iterator_ = TilingData::Iterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->current_visible_rect(), false);
+ if (!iterator_) {
+ ++tiling_index_;
+ continue;
+ }
+ break;
+ }
+ if (tiling_index_ >= tilings_->size())
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_)) {
+ ++(*this);
+ return;
+ }
+ if (!TileMatchesRequiredFlags(prioritized_tile_)) {
+ ++(*this);
+ return;
+ }
+}
+
+TilingSetEvictionQueue::VisibleTilingIterator&
+ TilingSetEvictionQueue::VisibleTilingIterator::
+ operator++() {
+ bool found_tile = AdvanceToNextTile(&iterator_);
+ while (found_tile && !TileMatchesRequiredFlags(prioritized_tile_))
+ found_tile = AdvanceToNextTile(&iterator_);
+
+ while (!found_tile && (tiling_index_ + 1) < tilings_->size()) {
+ ++tiling_index_;
+ if (!(*tilings_)[tiling_index_]->has_visible_rect_tiles())
+ continue;
+ iterator_ = TilingData::Iterator(
+ (*tilings_)[tiling_index_]->tiling_data(),
+ (*tilings_)[tiling_index_]->current_visible_rect(), false);
+ if (!iterator_)
+ continue;
+ found_tile = GetFirstTileAndCheckIfValid(&iterator_);
+ if (!found_tile)
+ found_tile = AdvanceToNextTile(&iterator_);
+ while (found_tile && !TileMatchesRequiredFlags(prioritized_tile_))
+ found_tile = AdvanceToNextTile(&iterator_);
+ }
+ return *this;
+}
+
+bool TilingSetEvictionQueue::VisibleTilingIterator::TileMatchesRequiredFlags(
+ const PrioritizedTile& tile) const {
+ bool activation_flag_matches = tile.tile()->required_for_activation() ==
+ return_required_for_activation_tiles_;
+ bool occluded_flag_matches = tile.is_occluded() == return_occluded_tiles_;
+ return activation_flag_matches && occluded_flag_matches;
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/tiling_set_eviction_queue.h b/chromium/cc/tiles/tiling_set_eviction_queue.h
new file mode 100644
index 00000000000..dc9b6866974
--- /dev/null
+++ b/chromium/cc/tiles/tiling_set_eviction_queue.h
@@ -0,0 +1,203 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TILES_TILING_SET_EVICTION_QUEUE_H_
+#define CC_TILES_TILING_SET_EVICTION_QUEUE_H_
+
+#include <vector>
+
+#include "cc/base/cc_export.h"
+#include "cc/tiles/picture_layer_tiling_set.h"
+#include "cc/tiles/prioritized_tile.h"
+
+namespace cc {
+
+// This eviction queue returned tiles from all tilings in a tiling set in
+// the order in which the tiles should be evicted. It can be thought of as the
+// following:
+// for all phases:
+// for all ordered tilings:
+// yield the next tile for the given phase from the given tiling
+//
+// Phases are the following (in order in which they are processed):
+// EVENTUALLY_RECT - Tiles in the eventually region of the tiling.
+// SOON_BORDER_RECT - Tiles in the prepainting skirt of the tiling.
+// SKEWPORT_RECT - Tiles in the skewport of the tiling.
+// PENDING_VISIBLE_RECT - Tiles that will be visible upon activation, not
+// required for activation.
+// PENDING_VISIBLE_RECT_REQUIRED_FOR_ACTIVATION - Tiles that will be visible
+// upon activation, required for activation.
+// VISIBLE_RECT_OCCLUDED - Occluded, not required for activation, visible tiles.
+// VISIBLE_RECT_UNOCCLUDED - Unoccluded, not required for activation, visible
+// tiles.
+// VISIBLE_RECT_REQUIRED_FOR_ACTIVATION_OCCLUDED - Occluded, but required for
+// activation, visible tiles. This can happen when an active tree tile is
+// occluded, but is not occluded on the pending tree (and is required for
+// activation).
+// VISIBLE_RECT_REQUIRED_FOR_ACTIVATION_UNOCCLUDED - Unoccluded, required for
+// activation, tiles.
+//
+// The tilings are ordered as follows. Suppose we have tilings with the scales
+// below:
+// 2.0 1.5 1.0(HR) 0.8 0.5 0.25(LR) 0.2 0.1
+// With HR referring to high res tiling and LR referring to low res tiling,
+// then tilings are processed in this order:
+// 2.0 1.5 0.1 0.2 0.5 0.8 0.25(LR) 1.0(HR).
+//
+// To put it differently:
+// 1. Process the highest scale tiling down to, but not including, high res
+// tiling.
+// 2. Process the lowest scale tiling up to, but not including, the low res
+// tiling. In cases without a low res tiling, this is an empty set.
+// 3. Process low res tiling up to high res tiling, including neither high
+// nor low res tilings. In cases without a low res tiling, this set
+// includes all tilings with a lower scale than the high res tiling.
+// 4. Process the low res tiling.
+// 5. Process the high res tiling.
+//
+// Additional notes:
+// Since eventually the tiles are considered to have the priority which is the
+// higher of the two trees, we might visit a tile that should actually be
+// returned by its twin. In those situations, the tiles are not returned. That
+// is, since the twin has higher priority, it should return it when it gets to
+// it. This ensures that we don't block raster because we've returned a tile
+// with low priority on one tree, but high combined priority.
+class CC_EXPORT TilingSetEvictionQueue {
+ public:
+ explicit TilingSetEvictionQueue(PictureLayerTilingSet* tiling_set);
+ ~TilingSetEvictionQueue();
+
+ const PrioritizedTile& Top() const;
+ void Pop();
+ bool IsEmpty() const;
+
+ private:
+ enum Phase {
+ EVENTUALLY_RECT,
+ SOON_BORDER_RECT,
+ SKEWPORT_RECT,
+ PENDING_VISIBLE_RECT,
+ PENDING_VISIBLE_RECT_REQUIRED_FOR_ACTIVATION,
+ VISIBLE_RECT_OCCLUDED,
+ VISIBLE_RECT_UNOCCLUDED,
+ VISIBLE_RECT_REQUIRED_FOR_ACTIVATION_OCCLUDED,
+ VISIBLE_RECT_REQUIRED_FOR_ACTIVATION_UNOCCLUDED
+ };
+
+ void GenerateTilingOrder(PictureLayerTilingSet* tiling_set);
+
+ // Helper base class for individual region iterators.
+ class EvictionRectIterator {
+ public:
+ EvictionRectIterator();
+ EvictionRectIterator(
+ std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree,
+ PictureLayerTiling::PriorityRectType priority_rect_type);
+
+ bool done() const { return !prioritized_tile_.tile(); }
+ const PrioritizedTile& operator*() const { return prioritized_tile_; }
+
+ protected:
+ ~EvictionRectIterator() = default;
+
+ template <typename TilingIteratorType>
+ bool AdvanceToNextTile(TilingIteratorType* iterator);
+ template <typename TilingIteratorType>
+ bool GetFirstTileAndCheckIfValid(TilingIteratorType* iterator);
+
+ PrioritizedTile prioritized_tile_;
+ std::vector<PictureLayerTiling*>* tilings_;
+ WhichTree tree_;
+ PictureLayerTiling::PriorityRectType priority_rect_type_;
+ size_t tiling_index_;
+ };
+
+ class PendingVisibleTilingIterator : public EvictionRectIterator {
+ public:
+ PendingVisibleTilingIterator() = default;
+ PendingVisibleTilingIterator(std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree,
+ bool return_required_for_activation_tiles);
+
+ PendingVisibleTilingIterator& operator++();
+
+ private:
+ bool TileMatchesRequiredFlags(const PrioritizedTile& tile) const;
+
+ TilingData::DifferenceIterator iterator_;
+ bool return_required_for_activation_tiles_;
+ };
+
+ class VisibleTilingIterator : public EvictionRectIterator {
+ public:
+ VisibleTilingIterator() = default;
+ VisibleTilingIterator(std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree,
+ bool return_occluded_tiles,
+ bool return_required_for_activation_tiles);
+
+ VisibleTilingIterator& operator++();
+
+ private:
+ bool TileMatchesRequiredFlags(const PrioritizedTile& tile) const;
+
+ TilingData::Iterator iterator_;
+ bool return_occluded_tiles_;
+ bool return_required_for_activation_tiles_;
+ };
+
+ class SkewportTilingIterator : public EvictionRectIterator {
+ public:
+ SkewportTilingIterator() = default;
+ SkewportTilingIterator(std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree);
+
+ SkewportTilingIterator& operator++();
+
+ private:
+ TilingData::ReverseSpiralDifferenceIterator iterator_;
+ };
+
+ class SoonBorderTilingIterator : public EvictionRectIterator {
+ public:
+ SoonBorderTilingIterator() = default;
+ SoonBorderTilingIterator(std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree);
+
+ SoonBorderTilingIterator& operator++();
+
+ private:
+ TilingData::ReverseSpiralDifferenceIterator iterator_;
+ };
+
+ class EventuallyTilingIterator : public EvictionRectIterator {
+ public:
+ EventuallyTilingIterator() = default;
+ EventuallyTilingIterator(std::vector<PictureLayerTiling*>* tilings,
+ WhichTree tree);
+
+ EventuallyTilingIterator& operator++();
+
+ private:
+ TilingData::ReverseSpiralDifferenceIterator iterator_;
+ };
+
+ void AdvancePhase();
+
+ WhichTree tree_;
+ Phase phase_;
+ PrioritizedTile current_tile_;
+ std::vector<PictureLayerTiling*> tilings_;
+
+ EventuallyTilingIterator eventually_iterator_;
+ SoonBorderTilingIterator soon_iterator_;
+ SkewportTilingIterator skewport_iterator_;
+ PendingVisibleTilingIterator pending_visible_iterator_;
+ VisibleTilingIterator visible_iterator_;
+};
+
+} // namespace cc
+
+#endif // CC_TILES_TILING_SET_EVICTION_QUEUE_H_
diff --git a/chromium/cc/tiles/tiling_set_raster_queue_all.cc b/chromium/cc/tiles/tiling_set_raster_queue_all.cc
new file mode 100644
index 00000000000..ae91f271fc2
--- /dev/null
+++ b/chromium/cc/tiles/tiling_set_raster_queue_all.cc
@@ -0,0 +1,460 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/tiles/tiling_set_raster_queue_all.h"
+
+#include <utility>
+
+#include "cc/tiles/picture_layer_tiling_set.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_priority.h"
+
+namespace cc {
+
+TilingSetRasterQueueAll::IterationStage::IterationStage(
+ IteratorType type,
+ TilePriority::PriorityBin bin)
+ : iterator_type(type), tile_type(bin) {
+}
+
+TilingSetRasterQueueAll::TilingSetRasterQueueAll(
+ PictureLayerTilingSet* tiling_set,
+ bool prioritize_low_res)
+ : tiling_set_(tiling_set), current_stage_(0) {
+ DCHECK(tiling_set_);
+
+ // Early out if the tiling set has no tilings.
+ if (!tiling_set_->num_tilings())
+ return;
+
+ const PictureLayerTilingClient* client = tiling_set->client();
+ WhichTree tree = tiling_set->tree();
+ // Find high and low res tilings and initialize the iterators.
+ PictureLayerTiling* high_res_tiling = nullptr;
+ PictureLayerTiling* low_res_tiling = nullptr;
+ // This variable would point to a tiling that has a NON_IDEAL_RESOLUTION
+ // resolution on the active tree, but HIGH_RESOLUTION on the pending tree.
+ // These tilings are the only non-ideal tilings that could have required for
+ // activation tiles, so they need to be considered for rasterization.
+ PictureLayerTiling* active_non_ideal_pending_high_res_tiling = nullptr;
+ for (size_t i = 0; i < tiling_set_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = tiling_set_->tiling_at(i);
+ if (tiling->resolution() == HIGH_RESOLUTION)
+ high_res_tiling = tiling;
+ if (prioritize_low_res && tiling->resolution() == LOW_RESOLUTION)
+ low_res_tiling = tiling;
+ if (tree == ACTIVE_TREE && tiling->resolution() == NON_IDEAL_RESOLUTION) {
+ const PictureLayerTiling* twin =
+ client->GetPendingOrActiveTwinTiling(tiling);
+ if (twin && twin->resolution() == HIGH_RESOLUTION)
+ active_non_ideal_pending_high_res_tiling = tiling;
+ }
+ }
+
+ bool use_low_res_tiling = low_res_tiling && low_res_tiling->has_tiles();
+ if (use_low_res_tiling && prioritize_low_res) {
+ iterators_[LOW_RES] =
+ TilingIterator(low_res_tiling, &low_res_tiling->tiling_data_);
+ stages_->push_back(IterationStage(LOW_RES, TilePriority::NOW));
+ }
+
+ bool use_high_res_tiling = high_res_tiling && high_res_tiling->has_tiles();
+ if (use_high_res_tiling) {
+ iterators_[HIGH_RES] =
+ TilingIterator(high_res_tiling, &high_res_tiling->tiling_data_);
+ stages_->push_back(IterationStage(HIGH_RES, TilePriority::NOW));
+ }
+
+ if (low_res_tiling && !prioritize_low_res) {
+ iterators_[LOW_RES] =
+ TilingIterator(low_res_tiling, &low_res_tiling->tiling_data_);
+ stages_->push_back(IterationStage(LOW_RES, TilePriority::NOW));
+ }
+
+ if (active_non_ideal_pending_high_res_tiling &&
+ active_non_ideal_pending_high_res_tiling->has_tiles()) {
+ iterators_[ACTIVE_NON_IDEAL_PENDING_HIGH_RES] =
+ TilingIterator(active_non_ideal_pending_high_res_tiling,
+ &active_non_ideal_pending_high_res_tiling->tiling_data_);
+
+ stages_->push_back(
+ IterationStage(ACTIVE_NON_IDEAL_PENDING_HIGH_RES, TilePriority::NOW));
+ stages_->push_back(
+ IterationStage(ACTIVE_NON_IDEAL_PENDING_HIGH_RES, TilePriority::SOON));
+ }
+
+ if (use_high_res_tiling) {
+ stages_->push_back(IterationStage(HIGH_RES, TilePriority::SOON));
+ stages_->push_back(IterationStage(HIGH_RES, TilePriority::EVENTUALLY));
+ }
+
+ if (stages_->empty())
+ return;
+
+ IteratorType index = stages_[current_stage_].iterator_type;
+ TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
+ if (iterators_[index].done() || iterators_[index].type() != tile_type)
+ AdvanceToNextStage();
+}
+
+TilingSetRasterQueueAll::~TilingSetRasterQueueAll() {
+}
+
+bool TilingSetRasterQueueAll::IsEmpty() const {
+ return current_stage_ >= stages_->size();
+}
+
+void TilingSetRasterQueueAll::Pop() {
+ IteratorType index = stages_[current_stage_].iterator_type;
+ TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
+
+ // First advance the iterator.
+ DCHECK(!iterators_[index].done());
+ DCHECK(iterators_[index].type() == tile_type);
+ ++iterators_[index];
+
+ if (iterators_[index].done() || iterators_[index].type() != tile_type)
+ AdvanceToNextStage();
+}
+
+const PrioritizedTile& TilingSetRasterQueueAll::Top() const {
+ DCHECK(!IsEmpty());
+
+ IteratorType index = stages_[current_stage_].iterator_type;
+ DCHECK(!iterators_[index].done());
+ DCHECK(iterators_[index].type() == stages_[current_stage_].tile_type);
+
+ return *iterators_[index];
+}
+
+void TilingSetRasterQueueAll::AdvanceToNextStage() {
+ DCHECK_LT(current_stage_, stages_->size());
+ ++current_stage_;
+ while (current_stage_ < stages_->size()) {
+ IteratorType index = stages_[current_stage_].iterator_type;
+ TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
+
+ if (!iterators_[index].done() && iterators_[index].type() == tile_type)
+ break;
+ ++current_stage_;
+ }
+}
+
+// OnePriorityRectIterator
+TilingSetRasterQueueAll::OnePriorityRectIterator::OnePriorityRectIterator()
+ : tiling_(nullptr), tiling_data_(nullptr) {
+}
+
+TilingSetRasterQueueAll::OnePriorityRectIterator::OnePriorityRectIterator(
+ PictureLayerTiling* tiling,
+ TilingData* tiling_data,
+ PictureLayerTiling::PriorityRectType priority_rect_type)
+ : tiling_(tiling),
+ tiling_data_(tiling_data),
+ priority_rect_type_(priority_rect_type) {
+}
+
+template <typename TilingIteratorType>
+void TilingSetRasterQueueAll::OnePriorityRectIterator::AdvanceToNextTile(
+ TilingIteratorType* iterator) {
+ bool found_tile = false;
+ while (!found_tile) {
+ ++(*iterator);
+ if (!(*iterator)) {
+ current_tile_ = PrioritizedTile();
+ break;
+ }
+ found_tile = GetFirstTileAndCheckIfValid(iterator);
+ }
+}
+
+template <typename TilingIteratorType>
+bool TilingSetRasterQueueAll::OnePriorityRectIterator::
+ GetFirstTileAndCheckIfValid(TilingIteratorType* iterator) {
+ Tile* tile = tiling_->TileAt(iterator->index_x(), iterator->index_y());
+ if (!tile || !TileNeedsRaster(tile)) {
+ current_tile_ = PrioritizedTile();
+ return false;
+ }
+ // After the pending visible rect has been processed, we must return false
+ // for pending visible rect tiles as tiling iterators do not ignore those
+ // tiles.
+ if (priority_rect_type_ > PictureLayerTiling::PENDING_VISIBLE_RECT &&
+ tiling_->pending_visible_rect().Intersects(tile->content_rect())) {
+ current_tile_ = PrioritizedTile();
+ return false;
+ }
+ tiling_->UpdateRequiredStatesOnTile(tile);
+ current_tile_ = tiling_->MakePrioritizedTile(tile, priority_rect_type_);
+ return true;
+}
+
+// VisibleTilingIterator.
+TilingSetRasterQueueAll::VisibleTilingIterator::VisibleTilingIterator(
+ PictureLayerTiling* tiling,
+ TilingData* tiling_data)
+ : OnePriorityRectIterator(tiling,
+ tiling_data,
+ PictureLayerTiling::VISIBLE_RECT) {
+ if (!tiling_->has_visible_rect_tiles())
+ return;
+ iterator_ =
+ TilingData::Iterator(tiling_data_, tiling_->current_visible_rect(),
+ false /* include_borders */);
+ if (!iterator_)
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_))
+ ++(*this);
+}
+
+TilingSetRasterQueueAll::VisibleTilingIterator&
+ TilingSetRasterQueueAll::VisibleTilingIterator::
+ operator++() {
+ AdvanceToNextTile(&iterator_);
+ return *this;
+}
+
+// PendingVisibleTilingIterator.
+TilingSetRasterQueueAll::PendingVisibleTilingIterator::
+ PendingVisibleTilingIterator(PictureLayerTiling* tiling,
+ TilingData* tiling_data)
+ : OnePriorityRectIterator(tiling,
+ tiling_data,
+ PictureLayerTiling::PENDING_VISIBLE_RECT) {
+ iterator_ = TilingData::DifferenceIterator(tiling_data_,
+ tiling_->pending_visible_rect(),
+ tiling_->current_visible_rect());
+ if (!iterator_)
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_))
+ ++(*this);
+}
+
+TilingSetRasterQueueAll::PendingVisibleTilingIterator&
+ TilingSetRasterQueueAll::PendingVisibleTilingIterator::
+ operator++() {
+ AdvanceToNextTile(&iterator_);
+ return *this;
+}
+
+// SkewportTilingIterator.
+TilingSetRasterQueueAll::SkewportTilingIterator::SkewportTilingIterator(
+ PictureLayerTiling* tiling,
+ TilingData* tiling_data)
+ : OnePriorityRectIterator(tiling,
+ tiling_data,
+ PictureLayerTiling::SKEWPORT_RECT),
+ pending_visible_rect_(tiling->pending_visible_rect()) {
+ if (!tiling_->has_skewport_rect_tiles())
+ return;
+ iterator_ = TilingData::SpiralDifferenceIterator(
+ tiling_data_, tiling_->current_skewport_rect(),
+ tiling_->current_visible_rect(), tiling_->current_visible_rect());
+ if (!iterator_)
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_)) {
+ ++(*this);
+ return;
+ }
+ // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid
+ // does the same checking.
+ if (current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
+ ++(*this);
+}
+
+TilingSetRasterQueueAll::SkewportTilingIterator&
+ TilingSetRasterQueueAll::SkewportTilingIterator::
+ operator++() {
+ AdvanceToNextTile(&iterator_);
+ // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid called
+ // by AdvanceToNextTile does the same checking.
+ while (!done()) {
+ if (!current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
+ break;
+ AdvanceToNextTile(&iterator_);
+ }
+ return *this;
+}
+
+// SoonBorderTilingIterator.
+TilingSetRasterQueueAll::SoonBorderTilingIterator::SoonBorderTilingIterator(
+ PictureLayerTiling* tiling,
+ TilingData* tiling_data)
+ : OnePriorityRectIterator(tiling,
+ tiling_data,
+ PictureLayerTiling::SOON_BORDER_RECT),
+ pending_visible_rect_(tiling->pending_visible_rect()) {
+ if (!tiling_->has_soon_border_rect_tiles())
+ return;
+ iterator_ = TilingData::SpiralDifferenceIterator(
+ tiling_data_, tiling_->current_soon_border_rect(),
+ tiling_->current_skewport_rect(), tiling_->current_visible_rect());
+ if (!iterator_)
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_)) {
+ ++(*this);
+ return;
+ }
+ // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid
+ // does the same checking.
+ if (current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
+ ++(*this);
+}
+
+TilingSetRasterQueueAll::SoonBorderTilingIterator&
+ TilingSetRasterQueueAll::SoonBorderTilingIterator::
+ operator++() {
+ AdvanceToNextTile(&iterator_);
+ // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid called
+ // by AdvanceToNextTile does the same checking.
+ while (!done()) {
+ if (!current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
+ break;
+ AdvanceToNextTile(&iterator_);
+ }
+ return *this;
+}
+
+// EventuallyTilingIterator.
+TilingSetRasterQueueAll::EventuallyTilingIterator::EventuallyTilingIterator(
+ PictureLayerTiling* tiling,
+ TilingData* tiling_data)
+ : OnePriorityRectIterator(tiling,
+ tiling_data,
+ PictureLayerTiling::EVENTUALLY_RECT),
+ pending_visible_rect_(tiling->pending_visible_rect()) {
+ if (!tiling_->has_eventually_rect_tiles())
+ return;
+ iterator_ = TilingData::SpiralDifferenceIterator(
+ tiling_data_, tiling_->current_eventually_rect(),
+ tiling_->current_skewport_rect(), tiling_->current_soon_border_rect());
+ if (!iterator_)
+ return;
+ if (!GetFirstTileAndCheckIfValid(&iterator_)) {
+ ++(*this);
+ return;
+ }
+ // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid
+ // does the same checking.
+ if (current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
+ ++(*this);
+}
+
+TilingSetRasterQueueAll::EventuallyTilingIterator&
+ TilingSetRasterQueueAll::EventuallyTilingIterator::
+ operator++() {
+ AdvanceToNextTile(&iterator_);
+ // TODO(e_hakkinen): This is not needed as GetFirstTileAndCheckIfValid called
+ // by AdvanceToNextTile does the same checking.
+ while (!done()) {
+ if (!current_tile_.tile()->content_rect().Intersects(pending_visible_rect_))
+ break;
+ AdvanceToNextTile(&iterator_);
+ }
+ return *this;
+}
+
+// TilingIterator
+TilingSetRasterQueueAll::TilingIterator::TilingIterator() : tiling_(nullptr) {
+}
+
+TilingSetRasterQueueAll::TilingIterator::TilingIterator(
+ PictureLayerTiling* tiling,
+ TilingData* tiling_data)
+ : tiling_(tiling), tiling_data_(tiling_data), phase_(Phase::VISIBLE_RECT) {
+ visible_iterator_ = VisibleTilingIterator(tiling_, tiling_data_);
+ if (visible_iterator_.done()) {
+ AdvancePhase();
+ return;
+ }
+ current_tile_ = *visible_iterator_;
+}
+
+TilingSetRasterQueueAll::TilingIterator::~TilingIterator() {
+}
+
+void TilingSetRasterQueueAll::TilingIterator::AdvancePhase() {
+ DCHECK_LT(phase_, Phase::EVENTUALLY_RECT);
+
+ current_tile_ = PrioritizedTile();
+ while (!current_tile_.tile() && phase_ < Phase::EVENTUALLY_RECT) {
+ phase_ = static_cast<Phase>(phase_ + 1);
+ switch (phase_) {
+ case Phase::VISIBLE_RECT:
+ NOTREACHED();
+ return;
+ case Phase::PENDING_VISIBLE_RECT:
+ pending_visible_iterator_ =
+ PendingVisibleTilingIterator(tiling_, tiling_data_);
+ if (!pending_visible_iterator_.done())
+ current_tile_ = *pending_visible_iterator_;
+ break;
+ case Phase::SKEWPORT_RECT:
+ skewport_iterator_ = SkewportTilingIterator(tiling_, tiling_data_);
+ if (!skewport_iterator_.done())
+ current_tile_ = *skewport_iterator_;
+ break;
+ case Phase::SOON_BORDER_RECT:
+ soon_border_iterator_ = SoonBorderTilingIterator(tiling_, tiling_data_);
+ if (!soon_border_iterator_.done())
+ current_tile_ = *soon_border_iterator_;
+ break;
+ case Phase::EVENTUALLY_RECT:
+ eventually_iterator_ = EventuallyTilingIterator(tiling_, tiling_data_);
+ if (!eventually_iterator_.done())
+ current_tile_ = *eventually_iterator_;
+ break;
+ }
+ }
+}
+
+TilingSetRasterQueueAll::TilingIterator&
+ TilingSetRasterQueueAll::TilingIterator::
+ operator++() {
+ switch (phase_) {
+ case Phase::VISIBLE_RECT:
+ ++visible_iterator_;
+ if (visible_iterator_.done()) {
+ AdvancePhase();
+ return *this;
+ }
+ current_tile_ = *visible_iterator_;
+ break;
+ case Phase::PENDING_VISIBLE_RECT:
+ ++pending_visible_iterator_;
+ if (pending_visible_iterator_.done()) {
+ AdvancePhase();
+ return *this;
+ }
+ current_tile_ = *pending_visible_iterator_;
+ break;
+ case Phase::SKEWPORT_RECT:
+ ++skewport_iterator_;
+ if (skewport_iterator_.done()) {
+ AdvancePhase();
+ return *this;
+ }
+ current_tile_ = *skewport_iterator_;
+ break;
+ case Phase::SOON_BORDER_RECT:
+ ++soon_border_iterator_;
+ if (soon_border_iterator_.done()) {
+ AdvancePhase();
+ return *this;
+ }
+ current_tile_ = *soon_border_iterator_;
+ break;
+ case Phase::EVENTUALLY_RECT:
+ ++eventually_iterator_;
+ if (eventually_iterator_.done()) {
+ current_tile_ = PrioritizedTile();
+ return *this;
+ }
+ current_tile_ = *eventually_iterator_;
+ break;
+ }
+ return *this;
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/tiling_set_raster_queue_all.h b/chromium/cc/tiles/tiling_set_raster_queue_all.h
new file mode 100644
index 00000000000..62d22493730
--- /dev/null
+++ b/chromium/cc/tiles/tiling_set_raster_queue_all.h
@@ -0,0 +1,199 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TILES_TILING_SET_RASTER_QUEUE_ALL_H_
+#define CC_TILES_TILING_SET_RASTER_QUEUE_ALL_H_
+
+#include "base/containers/stack_container.h"
+#include "cc/base/cc_export.h"
+#include "cc/tiles/picture_layer_tiling_set.h"
+#include "cc/tiles/prioritized_tile.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_priority.h"
+
+namespace cc {
+
+// This queue returns all tiles required to be rasterized from HIGH_RESOLUTION
+// and LOW_RESOLUTION tilings.
+class CC_EXPORT TilingSetRasterQueueAll {
+ public:
+ TilingSetRasterQueueAll(PictureLayerTilingSet* tiling_set,
+ bool prioritize_low_res);
+ ~TilingSetRasterQueueAll();
+
+ const PrioritizedTile& Top() const;
+ void Pop();
+ bool IsEmpty() const;
+
+ private:
+ // Helper base class for individual region iterators.
+ class OnePriorityRectIterator {
+ public:
+ OnePriorityRectIterator();
+ OnePriorityRectIterator(
+ PictureLayerTiling* tiling,
+ TilingData* tiling_data,
+ PictureLayerTiling::PriorityRectType priority_rect_type);
+
+ bool done() const { return !current_tile_.tile(); }
+ const PrioritizedTile& operator*() const { return current_tile_; }
+
+ protected:
+ ~OnePriorityRectIterator() = default;
+ bool TileNeedsRaster(Tile* tile) const {
+ return tile->draw_info().NeedsRaster() && !tiling_->IsTileOccluded(tile);
+ }
+
+ template <typename TilingIteratorType>
+ void AdvanceToNextTile(TilingIteratorType* iterator);
+ template <typename TilingIteratorType>
+ bool GetFirstTileAndCheckIfValid(TilingIteratorType* iterator);
+
+ PrioritizedTile current_tile_;
+ PictureLayerTiling* tiling_;
+ TilingData* tiling_data_;
+ PictureLayerTiling::PriorityRectType priority_rect_type_;
+ };
+
+ // Iterates over visible rect only, left to right top to bottom order.
+ class VisibleTilingIterator : public OnePriorityRectIterator {
+ public:
+ VisibleTilingIterator() = default;
+ VisibleTilingIterator(PictureLayerTiling* tiling, TilingData* tiling_data);
+
+ VisibleTilingIterator& operator++();
+
+ private:
+ TilingData::Iterator iterator_;
+ };
+
+ class PendingVisibleTilingIterator : public OnePriorityRectIterator {
+ public:
+ PendingVisibleTilingIterator() = default;
+ PendingVisibleTilingIterator(PictureLayerTiling* tiling,
+ TilingData* tiling_data);
+
+ PendingVisibleTilingIterator& operator++();
+
+ private:
+ TilingData::DifferenceIterator iterator_;
+ };
+
+ // Iterates over skewport only, spiral around the visible rect.
+ class SkewportTilingIterator : public OnePriorityRectIterator {
+ public:
+ SkewportTilingIterator() = default;
+ SkewportTilingIterator(PictureLayerTiling* tiling, TilingData* tiling_data);
+
+ SkewportTilingIterator& operator++();
+
+ private:
+ TilingData::SpiralDifferenceIterator iterator_;
+ gfx::Rect pending_visible_rect_;
+ };
+
+ // Iterates over soon border only, spiral around the visible rect.
+ class SoonBorderTilingIterator : public OnePriorityRectIterator {
+ public:
+ SoonBorderTilingIterator() = default;
+ SoonBorderTilingIterator(PictureLayerTiling* tiling,
+ TilingData* tiling_data);
+
+ SoonBorderTilingIterator& operator++();
+
+ private:
+ TilingData::SpiralDifferenceIterator iterator_;
+ gfx::Rect pending_visible_rect_;
+ };
+
+ // Iterates over eventually rect only, spiral around the soon rect.
+ class EventuallyTilingIterator : public OnePriorityRectIterator {
+ public:
+ EventuallyTilingIterator() = default;
+ EventuallyTilingIterator(PictureLayerTiling* tiling,
+ TilingData* tiling_data);
+
+ EventuallyTilingIterator& operator++();
+
+ private:
+ TilingData::SpiralDifferenceIterator iterator_;
+ gfx::Rect pending_visible_rect_;
+ };
+
+ // Iterates over all of the above phases in the following order: visible,
+ // skewport, soon border, eventually.
+ class TilingIterator {
+ public:
+ TilingIterator();
+ explicit TilingIterator(PictureLayerTiling* tiling,
+ TilingData* tiling_data);
+ ~TilingIterator();
+
+ bool done() const { return !current_tile_.tile(); }
+ const PrioritizedTile& operator*() const { return current_tile_; }
+ TilePriority::PriorityBin type() const {
+ switch (phase_) {
+ case Phase::VISIBLE_RECT:
+ return TilePriority::NOW;
+ case Phase::PENDING_VISIBLE_RECT:
+ case Phase::SKEWPORT_RECT:
+ case Phase::SOON_BORDER_RECT:
+ return TilePriority::SOON;
+ case Phase::EVENTUALLY_RECT:
+ return TilePriority::EVENTUALLY;
+ }
+ NOTREACHED();
+ return TilePriority::EVENTUALLY;
+ }
+
+ TilingIterator& operator++();
+
+ private:
+ using Phase = PictureLayerTiling::PriorityRectType;
+
+ void AdvancePhase();
+
+ PictureLayerTiling* tiling_;
+ TilingData* tiling_data_;
+
+ Phase phase_;
+
+ PrioritizedTile current_tile_;
+ VisibleTilingIterator visible_iterator_;
+ PendingVisibleTilingIterator pending_visible_iterator_;
+ SkewportTilingIterator skewport_iterator_;
+ SoonBorderTilingIterator soon_border_iterator_;
+ EventuallyTilingIterator eventually_iterator_;
+ };
+
+ enum IteratorType {
+ LOW_RES,
+ HIGH_RES,
+ ACTIVE_NON_IDEAL_PENDING_HIGH_RES,
+ NUM_ITERATORS
+ };
+
+ void AdvanceToNextStage();
+
+ PictureLayerTilingSet* tiling_set_;
+
+ struct IterationStage {
+ IterationStage(IteratorType type, TilePriority::PriorityBin bin);
+ IteratorType iterator_type;
+ TilePriority::PriorityBin tile_type;
+ };
+
+ size_t current_stage_;
+
+ // The max number of stages is 6: 1 low res, 3 high res, and 2 active non
+ // ideal pending high res.
+ base::StackVector<IterationStage, 6> stages_;
+ TilingIterator iterators_[NUM_ITERATORS];
+
+ DISALLOW_COPY_AND_ASSIGN(TilingSetRasterQueueAll);
+};
+
+} // namespace cc
+
+#endif // CC_TILES_TILING_SET_RASTER_QUEUE_ALL_H_
diff --git a/chromium/cc/tiles/tiling_set_raster_queue_required.cc b/chromium/cc/tiles/tiling_set_raster_queue_required.cc
new file mode 100644
index 00000000000..07b123484c5
--- /dev/null
+++ b/chromium/cc/tiles/tiling_set_raster_queue_required.cc
@@ -0,0 +1,152 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/tiles/tiling_set_raster_queue_required.h"
+
+#include <utility>
+
+#include "cc/tiles/picture_layer_tiling_set.h"
+#include "cc/tiles/tile.h"
+#include "cc/tiles/tile_priority.h"
+
+namespace cc {
+
+TilingSetRasterQueueRequired::TilingSetRasterQueueRequired(
+ PictureLayerTilingSet* tiling_set,
+ RasterTilePriorityQueue::Type type)
+ : type_(type) {
+ DCHECK_NE(static_cast<int>(type),
+ static_cast<int>(RasterTilePriorityQueue::Type::ALL));
+
+ // Required tiles should only come from HIGH_RESOLUTION tilings. However, if
+ // we want required for activation tiles on the active tree, then it will come
+ // from tilings whose pending twin is high resolution.
+ PictureLayerTiling* tiling = nullptr;
+ if (type == RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION &&
+ tiling_set->tree() == ACTIVE_TREE) {
+ for (size_t i = 0; i < tiling_set->num_tilings(); ++i) {
+ PictureLayerTiling* active_tiling = tiling_set->tiling_at(i);
+ const PictureLayerTiling* pending_twin =
+ tiling_set->client()->GetPendingOrActiveTwinTiling(active_tiling);
+ if (pending_twin && pending_twin->resolution() == HIGH_RESOLUTION) {
+ tiling = active_tiling;
+ break;
+ }
+ }
+ } else {
+ tiling = tiling_set->FindTilingWithResolution(HIGH_RESOLUTION);
+ }
+
+ // If we don't have a tiling, then this queue will yield no tiles. See
+ // PictureLayerImpl::CanHaveTilings for examples of when a HIGH_RESOLUTION
+ // tiling would not be generated.
+ if (!tiling)
+ return;
+
+ if (type == RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION) {
+ iterator_ = TilingIterator(tiling, &tiling->tiling_data_,
+ tiling->pending_visible_rect());
+ } else {
+ iterator_ = TilingIterator(tiling, &tiling->tiling_data_,
+ tiling->current_visible_rect());
+ }
+
+ while (!iterator_.done() && !IsTileRequired(*iterator_))
+ ++iterator_;
+}
+
+TilingSetRasterQueueRequired::~TilingSetRasterQueueRequired() {
+}
+
+bool TilingSetRasterQueueRequired::IsEmpty() const {
+ return iterator_.done();
+}
+
+void TilingSetRasterQueueRequired::Pop() {
+ DCHECK(!IsEmpty());
+ ++iterator_;
+ while (!iterator_.done() && !IsTileRequired(*iterator_))
+ ++iterator_;
+}
+
+const PrioritizedTile& TilingSetRasterQueueRequired::Top() const {
+ DCHECK(!IsEmpty());
+ return *iterator_;
+}
+
+bool TilingSetRasterQueueRequired::IsTileRequired(
+ const PrioritizedTile& prioritized_tile) const {
+ return (type_ == RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION &&
+ prioritized_tile.tile()->required_for_activation()) ||
+ (type_ == RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW &&
+ prioritized_tile.tile()->required_for_draw());
+}
+
+TilingSetRasterQueueRequired::TilingIterator::TilingIterator()
+ : tiling_(nullptr) {
+}
+
+TilingSetRasterQueueRequired::TilingIterator::TilingIterator(
+ PictureLayerTiling* tiling,
+ TilingData* tiling_data,
+ const gfx::Rect& rect)
+ : tiling_(tiling), tiling_data_(tiling_data) {
+ visible_iterator_ =
+ TilingData::Iterator(tiling_data_, rect, false /* include_borders */);
+ if (!visible_iterator_)
+ return;
+
+ Tile* tile =
+ tiling_->TileAt(visible_iterator_.index_x(), visible_iterator_.index_y());
+ // If this is a valid tile, return it. Note that we have to use a tiling check
+ // for occlusion, since the tile's internal state has not yet been updated.
+ if (tile && tile->draw_info().NeedsRaster() &&
+ !tiling_->IsTileOccluded(tile)) {
+ tiling_->UpdateRequiredStatesOnTile(tile);
+ current_tile_ = tiling_->MakePrioritizedTile(
+ tile, tiling_->ComputePriorityRectTypeForTile(tile));
+ return;
+ }
+ ++(*this);
+}
+
+TilingSetRasterQueueRequired::TilingIterator::~TilingIterator() {
+}
+
+TilingSetRasterQueueRequired::TilingIterator&
+ TilingSetRasterQueueRequired::TilingIterator::
+ operator++() {
+ Tile* tile = nullptr;
+ while (true) {
+ ++visible_iterator_;
+ if (!visible_iterator_) {
+ current_tile_ = PrioritizedTile();
+ return *this;
+ }
+ std::pair<int, int> next_index = visible_iterator_.index();
+ tile = tiling_->TileAt(next_index.first, next_index.second);
+ // If the tile doesn't exist or if it exists but doesn't need raster work,
+ // we can move on to the next tile.
+ if (!tile || !tile->draw_info().NeedsRaster())
+ continue;
+
+ // If the tile is occluded, we also can skip it. Note that we use the tiling
+ // check for occlusion, since tile's internal state has not yet been updated
+ // (by UpdateTilePriority). The tiling check does not rely on tile's
+ // internal state (it is, in fact, used to determine the tile's state).
+ if (tiling_->IsTileOccluded(tile))
+ continue;
+
+ // If we get here, that means we have a valid tile that needs raster and is
+ // in the NOW bin, which means that it can be required.
+ break;
+ }
+
+ tiling_->UpdateRequiredStatesOnTile(tile);
+ current_tile_ = tiling_->MakePrioritizedTile(
+ tile, tiling_->ComputePriorityRectTypeForTile(tile));
+ return *this;
+}
+
+} // namespace cc
diff --git a/chromium/cc/tiles/tiling_set_raster_queue_required.h b/chromium/cc/tiles/tiling_set_raster_queue_required.h
new file mode 100644
index 00000000000..4573d040939
--- /dev/null
+++ b/chromium/cc/tiles/tiling_set_raster_queue_required.h
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TILES_TILING_SET_RASTER_QUEUE_REQUIRED_H_
+#define CC_TILES_TILING_SET_RASTER_QUEUE_REQUIRED_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/tiles/picture_layer_tiling_set.h"
+#include "cc/tiles/raster_tile_priority_queue.h"
+#include "cc/tiles/tile.h"
+
+namespace cc {
+
+// This queue only returns tiles that are required for either activation or
+// draw, as specified by RasterTilePriorityQueue::Type passed in the
+// constructor.
+class CC_EXPORT TilingSetRasterQueueRequired {
+ public:
+ TilingSetRasterQueueRequired(PictureLayerTilingSet* tiling_set,
+ RasterTilePriorityQueue::Type type);
+ ~TilingSetRasterQueueRequired();
+
+ const PrioritizedTile& Top() const;
+ void Pop();
+ bool IsEmpty() const;
+
+ private:
+ // This iterator will return all tiles that are in the NOW bin on the given
+ // tiling. The queue can then use these tiles and further filter them based on
+ // whether they are required or not.
+ class TilingIterator {
+ public:
+ TilingIterator();
+ explicit TilingIterator(PictureLayerTiling* tiling,
+ TilingData* tiling_data,
+ const gfx::Rect& rect);
+ ~TilingIterator();
+
+ bool done() const { return !current_tile_.tile(); }
+ const PrioritizedTile& operator*() const { return current_tile_; }
+ TilingIterator& operator++();
+
+ private:
+ PictureLayerTiling* tiling_;
+ TilingData* tiling_data_;
+
+ PrioritizedTile current_tile_;
+ TilingData::Iterator visible_iterator_;
+ };
+
+ bool IsTileRequired(const PrioritizedTile& prioritized_tile) const;
+
+ TilingIterator iterator_;
+ RasterTilePriorityQueue::Type type_;
+};
+
+} // namespace cc
+
+#endif // CC_TILES_TILING_SET_RASTER_QUEUE_REQUIRED_H_
diff --git a/chromium/cc/trees/blocking_task_runner_unittest.cc b/chromium/cc/trees/blocking_task_runner_unittest.cc
index ba4f96a80d4..f837a7ccd48 100644
--- a/chromium/cc/trees/blocking_task_runner_unittest.cc
+++ b/chromium/cc/trees/blocking_task_runner_unittest.cc
@@ -5,7 +5,10 @@
#include "cc/trees/blocking_task_runner.h"
#include "base/bind.h"
+#include "base/location.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/test/ordered_simple_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,7 +22,7 @@ void TestTask(bool* result) {
TEST(BlockingTaskRunnerTest, NoCapture) {
bool did_run = false;
scoped_ptr<BlockingTaskRunner> runner(
- BlockingTaskRunner::Create(base::MessageLoopProxy::current()));
+ BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get()));
runner->PostTask(FROM_HERE, base::Bind(&TestTask, &did_run));
EXPECT_FALSE(did_run);
base::RunLoop().RunUntilIdle();
@@ -29,7 +32,7 @@ TEST(BlockingTaskRunnerTest, NoCapture) {
TEST(BlockingTaskRunnerTest, Capture) {
bool did_run = false;
scoped_ptr<BlockingTaskRunner> runner(
- BlockingTaskRunner::Create(base::MessageLoopProxy::current()));
+ BlockingTaskRunner::Create(base::ThreadTaskRunnerHandle::Get()));
{
BlockingTaskRunner::CapturePostTasks capture(runner.get());
runner->PostTask(FROM_HERE, base::Bind(&TestTask, &did_run));
diff --git a/chromium/cc/trees/damage_tracker.cc b/chromium/cc/trees/damage_tracker.cc
index 866f09d6569..235dfcfd7ef 100644
--- a/chromium/cc/trees/damage_tracker.cc
+++ b/chromium/cc/trees/damage_tracker.cc
@@ -283,8 +283,7 @@ void DamageTracker::ExtendDamageForLayer(LayerImpl* layer,
RectMapData& data = RectDataForLayer(layer->id(), &layer_is_new);
gfx::Rect old_rect_in_target_space = data.rect_;
- gfx::Rect rect_in_target_space = MathUtil::MapEnclosingClippedRect(
- layer->draw_transform(), gfx::Rect(layer->content_bounds()));
+ gfx::Rect rect_in_target_space = layer->GetEnclosingRectInTargetSpace();
data.Update(rect_in_target_space, mailboxId_);
gfx::RectF damage_rect =
diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc
index 90b5b8a151e..2df71ddf2a7 100644
--- a/chromium/cc/trees/damage_tracker_unittest.cc
+++ b/chromium/cc/trees/damage_tracker_unittest.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -74,7 +75,8 @@ void EmulateDrawingOneFrame(LayerImpl* root) {
class DamageTrackerTest : public testing::Test {
public:
- DamageTrackerTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {}
+ DamageTrackerTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {}
scoped_ptr<LayerImpl> CreateTestTreeWithOneSurface() {
scoped_ptr<LayerImpl> root =
@@ -86,7 +88,7 @@ class DamageTrackerTest : public testing::Test {
root->SetBounds(gfx::Size(500, 500));
root->SetContentBounds(gfx::Size(500, 500));
root->SetDrawsContent(true);
- root->CreateRenderSurface();
+ root->SetHasRenderSurface(true);
root->render_surface()->SetContentRect(gfx::Rect(0, 0, 500, 500));
child->SetPosition(gfx::PointF(100.f, 100.f));
@@ -118,7 +120,7 @@ class DamageTrackerTest : public testing::Test {
root->SetBounds(gfx::Size(500, 500));
root->SetContentBounds(gfx::Size(500, 500));
root->SetDrawsContent(true);
- root->CreateRenderSurface();
+ root->SetHasRenderSurface(true);
root->render_surface()->SetContentRect(gfx::Rect(0, 0, 500, 500));
child1->SetPosition(gfx::PointF(100.f, 100.f));
@@ -126,11 +128,9 @@ class DamageTrackerTest : public testing::Test {
child1->SetContentBounds(gfx::Size(30, 30));
// With a child that draws_content, opacity will cause the layer to create
// its own RenderSurface. This layer does not draw, but is intended to
- // create its own RenderSurface. TODO: setting opacity and
- // ForceRenderSurface may be redundant here.
- child1->SetOpacity(0.5f);
+ // create its own RenderSurface.
child1->SetDrawsContent(false);
- child1->SetForceRenderSurface(true);
+ child1->SetHasRenderSurface(true);
child2->SetPosition(gfx::PointF(11.f, 11.f));
child2->SetBounds(gfx::Size(18, 18));
@@ -178,6 +178,7 @@ class DamageTrackerTest : public testing::Test {
protected:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
};
@@ -542,6 +543,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) {
// Setting the filter will damage the whole surface.
ClearDamageForAllSurfaces(root.get());
+ child->SetHasRenderSurface(true);
child->SetFilters(filters);
EmulateDrawingOneFrame(root.get());
root_damage_rect =
@@ -926,8 +928,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) {
// CASE 1: If a descendant surface disappears, its entire old area becomes
// exposed.
ClearDamageForAllSurfaces(root.get());
- child1->SetOpacity(1.f);
- child1->SetForceRenderSurface(false);
+ child1->SetHasRenderSurface(false);
EmulateDrawingOneFrame(root.get());
// Sanity check that there is only one surface now.
@@ -952,8 +953,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) {
// Then change the tree so that the render surface is added back.
ClearDamageForAllSurfaces(root.get());
- child1->SetOpacity(0.5f);
- child1->SetForceRenderSurface(true);
+ child1->SetHasRenderSurface(true);
+
EmulateDrawingOneFrame(root.get());
// Sanity check that there is a new surface now.
@@ -1056,6 +1057,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplica) {
reflection.Scale3d(-1.0, 1.0, 1.0);
grand_child1_replica->SetTransform(reflection);
grand_child1->SetReplicaLayer(grand_child1_replica.Pass());
+ grand_child1->SetHasRenderSurface(true);
}
EmulateDrawingOneFrame(root.get());
@@ -1106,6 +1108,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplica) {
// reflection to damage the target surface.
ClearDamageForAllSurfaces(root.get());
grand_child1->SetReplicaLayer(nullptr);
+ grand_child1->SetHasRenderSurface(false);
EmulateDrawingOneFrame(root.get());
ASSERT_EQ(old_content_rect.width(),
child1->render_surface()->content_rect().width());
@@ -1140,12 +1143,12 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
mask_layer->SetBounds(child->bounds());
mask_layer->SetContentBounds(child->bounds());
child->SetMaskLayer(mask_layer.Pass());
+ child->SetHasRenderSurface(true);
}
LayerImpl* mask_layer = child->mask_layer();
// Add opacity and a grand_child so that the render surface persists even
// after we remove the mask.
- child->SetOpacity(0.5f);
{
scoped_ptr<LayerImpl> grand_child =
LayerImpl::Create(host_impl_.active_tree(), 4);
@@ -1157,9 +1160,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
}
EmulateDrawingOneFrame(root.get());
- // Sanity check that a new surface was created for the child.
- ASSERT_TRUE(child->render_surface());
-
// CASE 1: the update_rect on a mask layer should damage the entire target
// surface.
ClearDamageForAllSurfaces(root.get());
@@ -1233,6 +1233,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMask) {
reflection.Scale3d(-1.0, 1.0, 1.0);
grand_child1_replica->SetTransform(reflection);
grand_child1->SetReplicaLayer(grand_child1_replica.Pass());
+ grand_child1->SetHasRenderSurface(true);
}
LayerImpl* grand_child1_replica = grand_child1->replica_layer();
@@ -1310,6 +1311,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMaskWithTransformOrigin) {
reflection.Scale3d(-1.0, 1.0, 1.0);
grand_child1_replica->SetTransform(reflection);
grand_child1->SetReplicaLayer(grand_child1_replica.Pass());
+ grand_child1->SetHasRenderSurface(true);
}
LayerImpl* grand_child1_replica = grand_child1->replica_layer();
@@ -1377,7 +1379,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForEmptyLayerList) {
// tracker does not crash when it receives an empty layer_list.
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_.active_tree(), 1);
- root->CreateRenderSurface();
+ root->SetHasRenderSurface(true);
+ root->draw_properties().render_target = root.get();
ASSERT_TRUE(root == root->render_target());
RenderSurfaceImpl* target_surface = root->render_surface();
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
new file mode 100644
index 00000000000..b1b4de1dd74
--- /dev/null
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -0,0 +1,595 @@
+// Copyright 2014 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/draw_property_utils.h"
+
+#include <vector>
+
+#include "cc/base/math_util.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/layer_impl.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/property_tree.h"
+#include "cc/trees/property_tree_builder.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+
+namespace cc {
+
+namespace {
+
+template <typename LayerType>
+void CalculateVisibleRects(const std::vector<LayerType*>& visible_layer_list,
+ const ClipTree& clip_tree,
+ const TransformTree& transform_tree) {
+ for (auto& layer : visible_layer_list) {
+ // TODO(ajuma): Compute content_scale rather than using it. Note that for
+ // PictureLayer and PictureImageLayers, content_bounds == bounds and
+ // content_scale_x == content_scale_y == 1.0, so once impl painting is on
+ // everywhere, this code will be unnecessary.
+ gfx::Size layer_bounds = layer->bounds();
+ const bool has_clip = layer->clip_tree_index() > 0;
+ const TransformNode* transform_node =
+ transform_tree.Node(layer->transform_tree_index());
+ if (has_clip) {
+ const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
+ const TransformNode* clip_transform_node =
+ transform_tree.Node(clip_node->data.transform_id);
+ const bool target_is_root_surface =
+ transform_node->data.content_target_id == 1;
+ // When the target is the root surface, we need to include the root
+ // transform by walking up to the root of the transform tree.
+ const int target_id =
+ target_is_root_surface ? 0 : transform_node->data.content_target_id;
+ const TransformNode* target_node = transform_tree.Node(target_id);
+
+ gfx::Transform content_to_target = transform_node->data.to_target;
+
+ content_to_target.Translate(layer->offset_to_transform_parent().x(),
+ layer->offset_to_transform_parent().y());
+
+ gfx::Rect clip_rect_in_target_space;
+ gfx::Transform clip_to_target;
+ bool success = true;
+ if (clip_transform_node->data.target_id == target_node->id) {
+ clip_to_target = clip_transform_node->data.to_target;
+ } else {
+ success = transform_tree.ComputeTransformWithDestinationSublayerScale(
+ clip_transform_node->id, target_node->id, &clip_to_target);
+ }
+
+ if (target_node->id > clip_node->data.transform_id) {
+ if (!success) {
+ DCHECK(target_node->data.to_screen_is_animated);
+
+ // An animated singular transform may become non-singular during the
+ // animation, so we still need to compute a visible rect. In this
+ // situation, we treat the entire layer as visible.
+ layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
+ continue;
+ }
+
+ clip_rect_in_target_space =
+ gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
+ clip_to_target, clip_node->data.combined_clip));
+ } else {
+ // Computing a transform to an ancestor should always succeed.
+ DCHECK(success);
+ clip_rect_in_target_space =
+ gfx::ToEnclosingRect(MathUtil::MapClippedRect(
+ clip_to_target, clip_node->data.combined_clip));
+ }
+
+ gfx::Rect layer_content_rect = gfx::Rect(layer_bounds);
+ gfx::Rect layer_content_bounds_in_target_space =
+ MathUtil::MapEnclosingClippedRect(content_to_target,
+ layer_content_rect);
+ clip_rect_in_target_space.Intersect(layer_content_bounds_in_target_space);
+ if (clip_rect_in_target_space.IsEmpty()) {
+ layer->set_visible_rect_from_property_trees(gfx::Rect());
+ continue;
+ }
+
+ gfx::Transform target_to_content;
+ gfx::Transform target_to_layer;
+
+ if (transform_node->data.ancestors_are_invertible) {
+ target_to_layer = transform_node->data.from_target;
+ success = true;
+ } else {
+ success = transform_tree.ComputeTransformWithSourceSublayerScale(
+ target_node->id, transform_node->id, &target_to_layer);
+ }
+
+ if (!success) {
+ DCHECK(transform_node->data.to_screen_is_animated);
+
+ // An animated singular transform may become non-singular during the
+ // animation, so we still need to compute a visible rect. In this
+ // situation, we treat the entire layer as visible.
+ layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
+ continue;
+ }
+
+ target_to_content.Translate(-layer->offset_to_transform_parent().x(),
+ -layer->offset_to_transform_parent().y());
+ target_to_content.PreconcatTransform(target_to_layer);
+
+ gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect(
+ target_to_content, clip_rect_in_target_space);
+
+ visible_rect.Intersect(gfx::Rect(layer_bounds));
+
+ layer->set_visible_rect_from_property_trees(visible_rect);
+ } else {
+ layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
+ }
+ }
+}
+
+template <typename LayerType>
+static bool IsRootLayerOfNewRenderingContext(LayerType* layer) {
+ if (layer->parent())
+ return !layer->parent()->Is3dSorted() && layer->Is3dSorted();
+ return layer->Is3dSorted();
+}
+
+template <typename LayerType>
+static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
+ return layer->Is3dSorted() && layer->parent() &&
+ layer->parent()->Is3dSorted();
+}
+
+template <typename LayerType>
+static bool TransformToScreenIsKnown(LayerType* layer,
+ const TransformTree& tree) {
+ const TransformNode* node = tree.Node(layer->transform_tree_index());
+ return !node->data.to_screen_is_animated;
+}
+
+template <typename LayerType>
+static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) {
+ const TransformNode* node = tree.Node(layer->transform_tree_index());
+ return !node->data.is_invertible || !node->data.ancestors_are_invertible;
+}
+
+template <typename LayerType>
+static bool IsLayerBackFaceVisible(LayerType* layer,
+ const TransformTree& tree) {
+ // The current W3C spec on CSS transforms says that backface visibility should
+ // be determined differently depending on whether the layer is in a "3d
+ // rendering context" or not. For Chromium code, we can determine whether we
+ // are in a 3d rendering context by checking if the parent preserves 3d.
+
+ if (LayerIsInExisting3DRenderingContext(layer))
+ return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible();
+
+ // In this case, either the layer establishes a new 3d rendering context, or
+ // is not in a 3d rendering context at all.
+ return layer->transform().IsBackFaceVisible();
+}
+
+template <typename LayerType>
+static bool IsAnimatingTransformToScreen(LayerType* layer,
+ const TransformTree& tree) {
+ const TransformNode* node = tree.Node(layer->transform_tree_index());
+ return node->data.to_screen_is_animated;
+}
+
+static inline bool TransformToScreenIsKnown(Layer* layer,
+ const TransformTree& tree) {
+ return !IsAnimatingTransformToScreen(layer, tree);
+}
+
+static inline bool TransformToScreenIsKnown(LayerImpl* layer,
+ const TransformTree& tree) {
+ return true;
+}
+
+template <typename LayerType>
+static bool HasInvertibleOrAnimatedTransform(LayerType* layer) {
+ return layer->transform_is_invertible() || layer->TransformIsAnimating();
+}
+
+static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
+ bool layer_is_drawn) {
+ // If the layer transform is not invertible, it should not be drawn.
+ // TODO(ajuma): Correctly process subtrees with singular transform for the
+ // case where we may animate to a non-singular transform and wish to
+ // pre-raster.
+ if (!HasInvertibleOrAnimatedTransform(layer))
+ return true;
+
+ // When we need to do a readback/copy of a layer's output, we can not skip
+ // it or any of its ancestors.
+ if (layer->draw_properties().layer_or_descendant_has_copy_request)
+ return false;
+
+ // We cannot skip the the subtree if a descendant has a wheel or touch handler
+ // or the hit testing code will break (it requires fresh transforms, etc).
+ if (layer->draw_properties().layer_or_descendant_has_input_handler)
+ return false;
+
+ // If the layer is not drawn, then skip it and its subtree.
+ if (!layer_is_drawn)
+ return true;
+
+ // If layer is on the pending tree and opacity is being animated then
+ // this subtree can't be skipped as we need to create, prioritize and
+ // include tiles for this layer when deciding if tree can be activated.
+ if (layer->layer_tree_impl()->IsPendingTree() && layer->OpacityIsAnimating())
+ return false;
+
+ // The opacity of a layer always applies to its children (either implicitly
+ // via a render surface or explicitly if the parent preserves 3D), so the
+ // entire subtree can be skipped if this layer is fully transparent.
+ return !layer->opacity();
+}
+
+static inline bool SubtreeShouldBeSkipped(Layer* layer, bool layer_is_drawn) {
+ // If the layer transform is not invertible, it should not be drawn.
+ if (!layer->transform_is_invertible() && !layer->TransformIsAnimating())
+ return true;
+
+ // When we need to do a readback/copy of a layer's output, we can not skip
+ // it or any of its ancestors.
+ if (layer->draw_properties().layer_or_descendant_has_copy_request)
+ return false;
+
+ // We cannot skip the the subtree if a descendant has a wheel or touch handler
+ // or the hit testing code will break (it requires fresh transforms, etc).
+ if (layer->draw_properties().layer_or_descendant_has_input_handler)
+ return false;
+
+ // If the layer is not drawn, then skip it and its subtree.
+ if (!layer_is_drawn)
+ return true;
+
+ // If the opacity is being animated then the opacity on the main thread is
+ // unreliable (since the impl thread may be using a different opacity), so it
+ // should not be trusted.
+ // In particular, it should not cause the subtree to be skipped.
+ // Similarly, for layers that might animate opacity using an impl-only
+ // animation, their subtree should also not be skipped.
+ return !layer->opacity() && !layer->OpacityIsAnimating() &&
+ !layer->OpacityCanAnimateOnImplThread();
+}
+
+template <typename LayerType>
+static bool LayerShouldBeSkipped(LayerType* layer,
+ bool layer_is_drawn,
+ const TransformTree& tree) {
+ // Layers can be skipped if any of these conditions are met.
+ // - is not drawn due to it or one of its ancestors being hidden (or having
+ // no copy requests).
+ // - does not draw content.
+ // - is transparent.
+ // - has empty bounds
+ // - the layer is not double-sided, but its back face is visible.
+ //
+ // Some additional conditions need to be computed at a later point after the
+ // recursion is finished.
+ // - the intersection of render_surface content and layer clip_rect is empty
+ // - the visible_content_rect is empty
+ //
+ // Note, if the layer should not have been drawn due to being fully
+ // transparent, we would have skipped the entire subtree and never made it
+ // into this function, so it is safe to omit this check here.
+ if (!layer_is_drawn)
+ return true;
+
+ if (!layer->DrawsContent() || layer->bounds().IsEmpty())
+ return true;
+
+ LayerType* backface_test_layer = layer;
+ if (layer->use_parent_backface_visibility()) {
+ DCHECK(layer->parent());
+ DCHECK(!layer->parent()->use_parent_backface_visibility());
+ backface_test_layer = layer->parent();
+ }
+
+ // The layer should not be drawn if (1) it is not double-sided and (2) the
+ // back of the layer is known to be facing the screen.
+ if (!backface_test_layer->double_sided() &&
+ TransformToScreenIsKnown(backface_test_layer, tree) &&
+ IsLayerBackFaceVisible(backface_test_layer, tree))
+ return true;
+
+ return false;
+}
+
+template <typename LayerType>
+void FindLayersThatNeedUpdates(
+ LayerType* layer,
+ const TransformTree& tree,
+ bool subtree_is_visible_from_ancestor,
+ typename LayerType::LayerListType* update_layer_list,
+ std::vector<LayerType*>* visible_layer_list) {
+ bool layer_is_drawn =
+ layer->HasCopyRequest() ||
+ (subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree());
+
+ if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn))
+ return;
+
+ if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree)) {
+ visible_layer_list->push_back(layer);
+ update_layer_list->push_back(layer);
+ }
+
+ // Append mask layers to the update layer list. They don't have valid visible
+ // rects, so need to get added after the above calculation. Replica layers
+ // don't need to be updated.
+ if (LayerType* mask_layer = layer->mask_layer())
+ update_layer_list->push_back(mask_layer);
+ if (LayerType* replica_layer = layer->replica_layer()) {
+ if (LayerType* mask_layer = replica_layer->mask_layer())
+ update_layer_list->push_back(mask_layer);
+ }
+
+ for (size_t i = 0; i < layer->children().size(); ++i) {
+ FindLayersThatNeedUpdates(layer->child_at(i), tree, layer_is_drawn,
+ update_layer_list, visible_layer_list);
+ }
+}
+
+} // namespace
+
+void ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree) {
+ if (!clip_tree->needs_update())
+ return;
+ for (int i = 0; i < static_cast<int>(clip_tree->size()); ++i) {
+ ClipNode* clip_node = clip_tree->Node(i);
+
+ // Only descendants of a real clipping layer (i.e., not 0) may have their
+ // clip adjusted due to intersecting with an ancestor clip.
+ const bool is_clipped = clip_node->parent_id > 0;
+ if (!is_clipped) {
+ clip_node->data.combined_clip = clip_node->data.clip;
+ continue;
+ }
+
+ ClipNode* parent_clip_node = clip_tree->parent(clip_node);
+ const TransformNode* parent_transform_node =
+ transform_tree.Node(parent_clip_node->data.transform_id);
+ const TransformNode* transform_node =
+ transform_tree.Node(clip_node->data.transform_id);
+
+ // Clips must be combined in target space. We cannot, for example, combine
+ // clips in the space of the child clip. The reason is non-affine
+ // transforms. Say we have the following tree T->A->B->C, and B clips C, but
+ // draw into target T. It may be the case that A applies a perspective
+ // transform, and B and C are at different z positions. When projected into
+ // target space, the relative sizes and positions of B and C can shift.
+ // Since it's the relationship in target space that matters, that's where we
+ // must combine clips.
+ gfx::Transform parent_to_target;
+ gfx::Transform clip_to_target;
+ gfx::Transform target_to_clip;
+
+ const bool target_is_root_surface = clip_node->data.target_id == 1;
+ // When the target is the root surface, we need to include the root
+ // transform by walking up to the root of the transform tree.
+ const int target_id =
+ target_is_root_surface ? 0 : clip_node->data.target_id;
+
+ bool success = true;
+ if (parent_transform_node->data.content_target_id ==
+ clip_node->data.target_id) {
+ parent_to_target = parent_transform_node->data.to_target;
+ } else {
+ success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
+ parent_transform_node->id, target_id, &parent_to_target);
+ }
+
+ if (transform_node->data.content_target_id == clip_node->data.target_id) {
+ clip_to_target = transform_node->data.to_target;
+ } else {
+ success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
+ transform_node->id, target_id, &clip_to_target);
+ }
+
+ if (transform_node->data.content_target_id == clip_node->data.target_id &&
+ transform_node->data.ancestors_are_invertible) {
+ target_to_clip = transform_node->data.from_target;
+ } else {
+ success &= clip_to_target.GetInverse(&target_to_clip);
+ }
+
+ // If we can't compute a transform, it's because we had to use the inverse
+ // of a singular transform. We won't draw in this case, so there's no need
+ // to compute clips.
+ if (!success)
+ continue;
+
+ // In order to intersect with as small a rect as possible, we do a
+ // preliminary clip in target space so that when we project back, there's
+ // less likelihood of intersecting the view plane.
+ gfx::RectF inherited_clip_in_target_space = MathUtil::MapClippedRect(
+ parent_to_target, parent_clip_node->data.combined_clip);
+
+ gfx::RectF clip_in_target_space =
+ MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip);
+
+ gfx::RectF intersected_in_target_space = gfx::IntersectRects(
+ inherited_clip_in_target_space, clip_in_target_space);
+
+ clip_node->data.combined_clip = MathUtil::ProjectClippedRect(
+ target_to_clip, intersected_in_target_space);
+
+ clip_node->data.combined_clip.Intersect(clip_node->data.clip);
+ }
+ clip_tree->set_needs_update(false);
+}
+
+void ComputeTransforms(TransformTree* transform_tree) {
+ if (!transform_tree->needs_update())
+ return;
+ for (int i = 1; i < static_cast<int>(transform_tree->size()); ++i)
+ transform_tree->UpdateTransforms(i);
+ transform_tree->set_needs_update(false);
+}
+
+template <typename LayerType>
+void ComputeVisibleRectsUsingPropertyTreesInternal(
+ LayerType* root_layer,
+ PropertyTrees* property_trees,
+ typename LayerType::LayerListType* update_layer_list) {
+ if (property_trees->transform_tree.needs_update())
+ property_trees->clip_tree.set_needs_update(true);
+ ComputeTransforms(&property_trees->transform_tree);
+ ComputeClips(&property_trees->clip_tree, property_trees->transform_tree);
+
+ const bool subtree_is_visible_from_ancestor = true;
+ std::vector<LayerType*> visible_layer_list;
+ FindLayersThatNeedUpdates(root_layer, property_trees->transform_tree,
+ subtree_is_visible_from_ancestor, update_layer_list,
+ &visible_layer_list);
+ CalculateVisibleRects<LayerType>(visible_layer_list,
+ property_trees->clip_tree,
+ property_trees->transform_tree);
+}
+
+void BuildPropertyTreesAndComputeVisibleRects(
+ Layer* root_layer,
+ const Layer* page_scale_layer,
+ float page_scale_factor,
+ float device_scale_factor,
+ const gfx::Rect& viewport,
+ const gfx::Transform& device_transform,
+ PropertyTrees* property_trees,
+ LayerList* update_layer_list) {
+ PropertyTreeBuilder::BuildPropertyTrees(
+ root_layer, page_scale_layer, page_scale_factor, device_scale_factor,
+ viewport, device_transform, property_trees);
+ ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
+ update_layer_list);
+}
+
+void BuildPropertyTreesAndComputeVisibleRects(
+ LayerImpl* root_layer,
+ const LayerImpl* page_scale_layer,
+ float page_scale_factor,
+ float device_scale_factor,
+ const gfx::Rect& viewport,
+ const gfx::Transform& device_transform,
+ PropertyTrees* property_trees,
+ LayerImplList* update_layer_list) {
+ PropertyTreeBuilder::BuildPropertyTrees(
+ root_layer, page_scale_layer, page_scale_factor, device_scale_factor,
+ viewport, device_transform, property_trees);
+ ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
+ update_layer_list);
+}
+
+void ComputeVisibleRectsUsingPropertyTrees(Layer* root_layer,
+ PropertyTrees* property_trees,
+ LayerList* update_layer_list) {
+ ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
+ update_layer_list);
+}
+
+void ComputeVisibleRectsUsingPropertyTrees(LayerImpl* root_layer,
+ PropertyTrees* property_trees,
+ LayerImplList* update_layer_list) {
+ ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
+ update_layer_list);
+}
+
+template <typename LayerType>
+gfx::Transform DrawTransformFromPropertyTreesInternal(
+ const LayerType* layer,
+ const TransformTree& tree) {
+ const TransformNode* node = tree.Node(layer->transform_tree_index());
+ // TODO(vollick): ultimately we'll need to find this information (whether or
+ // not we establish a render surface) somewhere other than the layer.
+ const TransformNode* target_node =
+ layer->render_surface() ? node : tree.Node(node->data.content_target_id);
+
+ gfx::Transform xform;
+ const bool owns_non_root_surface = layer->parent() && layer->render_surface();
+ if (!owns_non_root_surface) {
+ // If you're not the root, or you don't own a surface, you need to apply
+ // your local offset.
+ xform = node->data.to_target;
+ if (layer->should_flatten_transform_from_property_tree())
+ xform.FlattenTo2d();
+ xform.Translate(layer->offset_to_transform_parent().x(),
+ layer->offset_to_transform_parent().y());
+ } else {
+ // Surfaces need to apply their sublayer scale.
+ xform.Scale(target_node->data.sublayer_scale.x(),
+ target_node->data.sublayer_scale.y());
+ }
+ return xform;
+}
+
+gfx::Transform DrawTransformFromPropertyTrees(const Layer* layer,
+ const TransformTree& tree) {
+ return DrawTransformFromPropertyTreesInternal(layer, tree);
+}
+
+gfx::Transform DrawTransformFromPropertyTrees(const LayerImpl* layer,
+ const TransformTree& tree) {
+ return DrawTransformFromPropertyTreesInternal(layer, tree);
+}
+
+template <typename LayerType>
+gfx::Transform ScreenSpaceTransformFromPropertyTreesInternal(
+ LayerType* layer,
+ const TransformTree& tree) {
+ gfx::Transform xform(1, 0, 0, 1, layer->offset_to_transform_parent().x(),
+ layer->offset_to_transform_parent().y());
+ if (layer->transform_tree_index() >= 0) {
+ gfx::Transform ssxform =
+ tree.Node(layer->transform_tree_index())->data.to_screen;
+ xform.ConcatTransform(ssxform);
+ if (layer->should_flatten_transform_from_property_tree())
+ xform.FlattenTo2d();
+ }
+ return xform;
+}
+
+gfx::Transform ScreenSpaceTransformFromPropertyTrees(
+ const Layer* layer,
+ const TransformTree& tree) {
+ return ScreenSpaceTransformFromPropertyTreesInternal(layer, tree);
+}
+
+gfx::Transform ScreenSpaceTransformFromPropertyTrees(
+ const LayerImpl* layer,
+ const TransformTree& tree) {
+ return ScreenSpaceTransformFromPropertyTreesInternal(layer, tree);
+}
+
+template <typename LayerType>
+float DrawOpacityFromPropertyTreesInternal(LayerType layer,
+ const OpacityTree& tree) {
+ if (!layer->render_target())
+ return 0.f;
+
+ const OpacityNode* target_node =
+ tree.Node(layer->render_target()->opacity_tree_index());
+ const OpacityNode* node = tree.Node(layer->opacity_tree_index());
+ if (node == target_node)
+ return 1.f;
+
+ float draw_opacity = 1.f;
+ while (node != target_node) {
+ draw_opacity *= node->data;
+ node = tree.parent(node);
+ }
+ return draw_opacity;
+}
+
+float DrawOpacityFromPropertyTrees(const Layer* layer,
+ const OpacityTree& tree) {
+ return DrawOpacityFromPropertyTreesInternal(layer, tree);
+}
+
+float DrawOpacityFromPropertyTrees(const LayerImpl* layer,
+ const OpacityTree& tree) {
+ return DrawOpacityFromPropertyTreesInternal(layer, tree);
+}
+
+} // namespace cc
diff --git a/chromium/cc/trees/draw_property_utils.h b/chromium/cc/trees/draw_property_utils.h
new file mode 100644
index 00000000000..893645d7dd9
--- /dev/null
+++ b/chromium/cc/trees/draw_property_utils.h
@@ -0,0 +1,92 @@
+// Copyright 2014 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_DRAW_PROPERTY_UTILS_H_
+#define CC_TREES_DRAW_PROPERTY_UTILS_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/layers/layer_lists.h"
+
+namespace gfx {
+class Rect;
+class Transform;
+} // namespace gfx
+
+namespace cc {
+
+class ClipTree;
+class Layer;
+class LayerImpl;
+class OpacityTree;
+class TransformTree;
+class PropertyTrees;
+
+// Computes combined clips for every node in |clip_tree|. This function requires
+// that |transform_tree| has been updated via |ComputeTransforms|.
+// TODO(vollick): ComputeClips and ComputeTransforms will eventually need to be
+// done on both threads.
+void CC_EXPORT
+ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree);
+
+// Computes combined (screen space) transforms for every node in the transform
+// tree. This must be done prior to calling |ComputeClips|.
+void CC_EXPORT ComputeTransforms(TransformTree* transform_tree);
+
+// Computes the visible content rect for every layer under |root_layer|. The
+// visible content rect is the clipped content space rect that will be used for
+// recording.
+void CC_EXPORT
+BuildPropertyTreesAndComputeVisibleRects(Layer* root_layer,
+ const Layer* page_scale_layer,
+ float page_scale_factor,
+ float device_scale_factor,
+ const gfx::Rect& viewport,
+ const gfx::Transform& device_transform,
+ PropertyTrees* property_trees,
+ LayerList* update_layer_list);
+
+void CC_EXPORT
+BuildPropertyTreesAndComputeVisibleRects(LayerImpl* root_layer,
+ const LayerImpl* page_scale_layer,
+ float page_scale_factor,
+ float device_scale_factor,
+ const gfx::Rect& viewport,
+ const gfx::Transform& device_transform,
+ PropertyTrees* property_trees,
+ LayerImplList* update_layer_list);
+
+void CC_EXPORT
+ComputeVisibleRectsUsingPropertyTrees(Layer* root_layer,
+ PropertyTrees* property_trees,
+ LayerList* update_layer_list);
+
+void CC_EXPORT
+ComputeVisibleRectsUsingPropertyTrees(LayerImpl* root_layer,
+ PropertyTrees* property_trees,
+ LayerImplList* update_layer_list);
+
+gfx::Transform CC_EXPORT
+DrawTransformFromPropertyTrees(const Layer* layer, const TransformTree& tree);
+
+gfx::Transform CC_EXPORT
+DrawTransformFromPropertyTrees(const LayerImpl* layer,
+ const TransformTree& tree);
+
+gfx::Transform CC_EXPORT
+ScreenSpaceTransformFromPropertyTrees(const Layer* layer,
+ const TransformTree& tree);
+
+gfx::Transform CC_EXPORT
+ScreenSpaceTransformFromPropertyTrees(const LayerImpl* layer,
+ const TransformTree& tree);
+
+float CC_EXPORT
+DrawOpacityFromPropertyTrees(const Layer* layer, const OpacityTree& tree);
+
+float CC_EXPORT
+DrawOpacityFromPropertyTrees(const LayerImpl* layer, const OpacityTree& tree);
+
+} // namespace cc
+
+#endif // CC_TREES_DRAW_PROPERTY_UTILS_H_
diff --git a/chromium/cc/base/latency_info_swap_promise_monitor.cc b/chromium/cc/trees/latency_info_swap_promise_monitor.cc
index dc2873988b3..c63ac5b0a04 100644
--- a/chromium/cc/base/latency_info_swap_promise_monitor.cc
+++ b/chromium/cc/trees/latency_info_swap_promise_monitor.cc
@@ -2,34 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/base/latency_info_swap_promise_monitor.h"
+#include "cc/trees/latency_info_swap_promise_monitor.h"
#include "base/threading/platform_thread.h"
-#include "cc/base/latency_info_swap_promise.h"
+#include "cc/output/latency_info_swap_promise.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
namespace {
-bool AddRenderingScheduledComponent(ui::LatencyInfo* latency_info) {
- if (latency_info->FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, nullptr))
+bool AddRenderingScheduledComponent(ui::LatencyInfo* latency_info,
+ bool on_main) {
+ ui::LatencyComponentType type =
+ on_main ? ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT
+ : ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT;
+ if (latency_info->FindLatency(type, 0, nullptr))
return false;
- latency_info->AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, 0);
+ latency_info->AddLatencyNumber(type, 0, 0);
return true;
}
bool AddForwardingScrollUpdateToMainComponent(ui::LatencyInfo* latency_info) {
if (latency_info->FindLatency(
- ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT,
- 0,
+ ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT, 0,
nullptr))
return false;
latency_info->AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT,
- 0,
+ ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT, 0,
latency_info->trace_id);
return true;
}
@@ -43,19 +43,21 @@ LatencyInfoSwapPromiseMonitor::LatencyInfoSwapPromiseMonitor(
LayerTreeHost* layer_tree_host,
LayerTreeHostImpl* layer_tree_host_impl)
: SwapPromiseMonitor(layer_tree_host, layer_tree_host_impl),
- latency_(latency) {}
+ latency_(latency) {
+}
-LatencyInfoSwapPromiseMonitor::~LatencyInfoSwapPromiseMonitor() {}
+LatencyInfoSwapPromiseMonitor::~LatencyInfoSwapPromiseMonitor() {
+}
void LatencyInfoSwapPromiseMonitor::OnSetNeedsCommitOnMain() {
- if (AddRenderingScheduledComponent(latency_)) {
+ if (AddRenderingScheduledComponent(latency_, true /* on_main */)) {
scoped_ptr<SwapPromise> swap_promise(new LatencyInfoSwapPromise(*latency_));
layer_tree_host_->QueueSwapPromise(swap_promise.Pass());
}
}
void LatencyInfoSwapPromiseMonitor::OnSetNeedsRedrawOnImpl() {
- if (AddRenderingScheduledComponent(latency_)) {
+ if (AddRenderingScheduledComponent(latency_, false /* on_main */)) {
scoped_ptr<SwapPromise> swap_promise(new LatencyInfoSwapPromise(*latency_));
layer_tree_host_impl_->active_tree()->QueueSwapPromise(swap_promise.Pass());
}
@@ -66,24 +68,23 @@ void LatencyInfoSwapPromiseMonitor::OnForwardScrollUpdateToMainThreadOnImpl() {
int64 new_sequence_number = 0;
for (ui::LatencyInfo::LatencyMap::const_iterator it =
latency_->latency_components.begin();
- it != latency_->latency_components.end();
- ++it) {
+ it != latency_->latency_components.end(); ++it) {
if (it->first.first == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT) {
new_sequence_number =
- (static_cast<int64>(base::PlatformThread::CurrentId()) << 32) |
+ ((static_cast<int64>(base::PlatformThread::CurrentId()) << 32) ^
+ (reinterpret_cast<uint64>(this) << 32)) |
(it->second.sequence_number & 0xffffffff);
- DCHECK(new_sequence_number != it->second.sequence_number);
+ if (new_sequence_number == it->second.sequence_number)
+ return;
break;
}
}
if (!new_sequence_number)
return;
ui::LatencyInfo new_latency;
- new_latency.AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_BEGIN_SCROLL_UPDATE_MAIN_COMPONENT,
- 0,
- new_sequence_number);
- new_latency.TraceEventType("ScrollUpdate");
+ new_latency.AddLatencyNumberWithTraceName(
+ ui::LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT, 0,
+ new_sequence_number, "ScrollUpdate");
new_latency.CopyLatencyFrom(
*latency_,
ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT);
diff --git a/chromium/cc/base/latency_info_swap_promise_monitor.h b/chromium/cc/trees/latency_info_swap_promise_monitor.h
index d9e71fbdb65..c1d9973911e 100644
--- a/chromium/cc/base/latency_info_swap_promise_monitor.h
+++ b/chromium/cc/trees/latency_info_swap_promise_monitor.h
@@ -3,10 +3,10 @@
// found in the LICENSE file.
#include "base/compiler_specific.h"
-#include "cc/base/swap_promise_monitor.h"
+#include "cc/trees/swap_promise_monitor.h"
-#ifndef CC_BASE_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_
-#define CC_BASE_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_
+#ifndef CC_TREES_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_
+#define CC_TREES_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_
namespace ui {
struct LatencyInfo;
@@ -34,4 +34,4 @@ class CC_EXPORT LatencyInfoSwapPromiseMonitor : public SwapPromiseMonitor {
} // namespace cc
-#endif // CC_BASE_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_
+#endif // CC_TREES_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_
diff --git a/chromium/cc/trees/layer_sorter.cc b/chromium/cc/trees/layer_sorter.cc
deleted file mode 100644
index e171fe01120..00000000000
--- a/chromium/cc/trees/layer_sorter.cc
+++ /dev/null
@@ -1,470 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/trees/layer_sorter.h"
-
-#include <algorithm>
-#include <deque>
-#include <limits>
-#include <vector>
-
-#include "base/logging.h"
-#include "cc/base/math_util.h"
-#include "cc/layers/render_surface_impl.h"
-#include "ui/gfx/transform.h"
-
-namespace cc {
-
-// This epsilon is used to determine if two layers are too close to each other
-// to be able to tell which is in front of the other. It's a relative epsilon
-// so it is robust to changes in scene scale. This value was chosen by picking
-// a value near machine epsilon and then increasing it until the flickering on
-// the test scene went away.
-const float k_layer_epsilon = 1e-4f;
-
-inline static float PerpProduct(const gfx::Vector2dF& u,
- const gfx::Vector2dF& v) {
- return u.x() * v.y() - u.y() * v.x();
-}
-
-// Tests if two edges defined by their endpoints (a,b) and (c,d) intersect.
-// Returns true and the point of intersection if they do and false otherwise.
-static bool EdgeEdgeTest(const gfx::PointF& a,
- const gfx::PointF& b,
- const gfx::PointF& c,
- const gfx::PointF& d,
- gfx::PointF* r) {
- gfx::Vector2dF u = b - a;
- gfx::Vector2dF v = d - c;
- gfx::Vector2dF w = a - c;
-
- float denom = PerpProduct(u, v);
-
- // If denom == 0 then the edges are parallel. While they could be overlapping
- // we don't bother to check here as the we'll find their intersections from
- // the corner to quad tests.
- if (!denom)
- return false;
-
- float s = PerpProduct(v, w) / denom;
- if (s < 0.f || s > 1.f)
- return false;
-
- float t = PerpProduct(u, w) / denom;
- if (t < 0.f || t > 1.f)
- return false;
-
- u.Scale(s);
- *r = a + u;
- return true;
-}
-
-GraphNode::GraphNode(LayerImpl* layer_impl)
- : layer(layer_impl),
- incoming_edge_weight(0.f) {}
-
-GraphNode::~GraphNode() {}
-
-LayerSorter::LayerSorter()
- : z_range_(0.f) {}
-
-LayerSorter::~LayerSorter() {}
-
-static float CheckFloatingPointNumericAccuracy(float a, float b) {
- float abs_dif = std::abs(b - a);
- float abs_max = std::max(std::abs(b), std::abs(a));
- // Check to see if we've got a result with a reasonable amount of error.
- return abs_dif / abs_max;
-}
-
-// Checks whether layer "a" draws on top of layer "b". The weight value returned
-// is an indication of the maximum z-depth difference between the layers or zero
-// if the layers are found to be intesecting (some features are in front and
-// some are behind).
-LayerSorter::ABCompareResult LayerSorter::CheckOverlap(LayerShape* a,
- LayerShape* b,
- float z_threshold,
- float* weight) {
- *weight = 0.f;
-
- // Early out if the projected bounds don't overlap.
- if (!a->projected_bounds.Intersects(b->projected_bounds))
- return None;
-
- gfx::PointF aPoints[4] = { a->projected_quad.p1(),
- a->projected_quad.p2(),
- a->projected_quad.p3(),
- a->projected_quad.p4() };
- gfx::PointF bPoints[4] = { b->projected_quad.p1(),
- b->projected_quad.p2(),
- b->projected_quad.p3(),
- b->projected_quad.p4() };
-
- // Make a list of points that inside both layer quad projections.
- std::vector<gfx::PointF> overlap_points;
-
- // Check all four corners of one layer against the other layer's quad.
- for (int i = 0; i < 4; ++i) {
- if (a->projected_quad.Contains(bPoints[i]))
- overlap_points.push_back(bPoints[i]);
- if (b->projected_quad.Contains(aPoints[i]))
- overlap_points.push_back(aPoints[i]);
- }
-
- // Check all the edges of one layer for intersection with the other layer's
- // edges.
- gfx::PointF r;
- for (int ea = 0; ea < 4; ++ea)
- for (int eb = 0; eb < 4; ++eb)
- if (EdgeEdgeTest(aPoints[ea], aPoints[(ea + 1) % 4],
- bPoints[eb], bPoints[(eb + 1) % 4],
- &r))
- overlap_points.push_back(r);
-
- if (overlap_points.empty())
- return None;
-
- // Check the corresponding layer depth value for all overlap points to
- // determine which layer is in front.
- float max_positive = 0.f;
- float max_negative = 0.f;
-
- // This flag tracks the existance of a numerically accurate seperation
- // between two layers. If there is no accurate seperation, the layers
- // cannot be effectively sorted.
- bool accurate = false;
-
- for (size_t o = 0; o < overlap_points.size(); o++) {
- float za = a->LayerZFromProjectedPoint(overlap_points[o]);
- float zb = b->LayerZFromProjectedPoint(overlap_points[o]);
-
- // Here we attempt to avoid numeric issues with layers that are too
- // close together. If we have 2-sided quads that are very close
- // together then we will draw them in document order to avoid
- // flickering. The correct solution is for the content maker to turn
- // on back-face culling or move the quads apart (if they're not two
- // sides of one object).
- if (CheckFloatingPointNumericAccuracy(za, zb) > k_layer_epsilon)
- accurate = true;
-
- float diff = za - zb;
- if (diff > max_positive)
- max_positive = diff;
- if (diff < max_negative)
- max_negative = diff;
- }
-
- // If we can't tell which should come first, we use document order.
- if (!accurate)
- return ABeforeB;
-
- float max_diff =
- std::abs(max_positive) > std::abs(max_negative) ?
- max_positive : max_negative;
-
- // If the results are inconsistent (and the z difference substantial to rule
- // out numerical errors) then the layers are intersecting. We will still
- // return an order based on the maximum depth difference but with an edge
- // weight of zero these layers will get priority if a graph cycle is present
- // and needs to be broken.
- if (max_positive > z_threshold && max_negative < -z_threshold)
- *weight = 0.f;
- else
- *weight = std::abs(max_diff);
-
- // Maintain relative order if the layers have the same depth at all
- // intersection points.
- if (max_diff <= 0.f)
- return ABeforeB;
-
- return BBeforeA;
-}
-
-LayerShape::LayerShape() {}
-
-LayerShape::LayerShape(float width,
- float height,
- const gfx::Transform& draw_transform) {
- gfx::QuadF layer_quad(gfx::RectF(0.f, 0.f, width, height));
-
- // Compute the projection of the layer quad onto the z = 0 plane.
-
- gfx::PointF clipped_quad[8];
- int num_vertices_in_clipped_quad;
- MathUtil::MapClippedQuad(draw_transform,
- layer_quad,
- clipped_quad,
- &num_vertices_in_clipped_quad);
-
- if (num_vertices_in_clipped_quad < 3) {
- projected_bounds = gfx::RectF();
- return;
- }
-
- projected_bounds =
- MathUtil::ComputeEnclosingRectOfVertices(clipped_quad,
- num_vertices_in_clipped_quad);
-
- // NOTE: it will require very significant refactoring and overhead to deal
- // with generalized polygons or multiple quads per layer here. For the sake of
- // layer sorting it is equally correct to take a subsection of the polygon
- // that can be made into a quad. This will only be incorrect in the case of
- // intersecting layers, which are not supported yet anyway.
- projected_quad.set_p1(clipped_quad[0]);
- projected_quad.set_p2(clipped_quad[1]);
- projected_quad.set_p3(clipped_quad[2]);
- if (num_vertices_in_clipped_quad >= 4) {
- projected_quad.set_p4(clipped_quad[3]);
- } else {
- // This will be a degenerate quad that is actually a triangle.
- projected_quad.set_p4(clipped_quad[2]);
- }
-
- // Compute the normal of the layer's plane.
- bool clipped = false;
- gfx::Point3F c1 =
- MathUtil::MapPoint(draw_transform, gfx::Point3F(0.f, 0.f, 0.f), &clipped);
- gfx::Point3F c2 =
- MathUtil::MapPoint(draw_transform, gfx::Point3F(0.f, 1.f, 0.f), &clipped);
- gfx::Point3F c3 =
- MathUtil::MapPoint(draw_transform, gfx::Point3F(1.f, 0.f, 0.f), &clipped);
- // TODO(shawnsingh): Deal with clipping.
- gfx::Vector3dF c12 = c2 - c1;
- gfx::Vector3dF c13 = c3 - c1;
- layer_normal = gfx::CrossProduct(c13, c12);
-
- transform_origin = c1;
-}
-
-LayerShape::~LayerShape() {}
-
-// Returns the Z coordinate of a point on the layer that projects
-// to point p which lies on the z = 0 plane. It does it by computing the
-// intersection of a line starting from p along the Z axis and the plane
-// of the layer.
-float LayerShape::LayerZFromProjectedPoint(const gfx::PointF& p) const {
- gfx::Vector3dF z_axis(0.f, 0.f, 1.f);
- gfx::Vector3dF w = gfx::Point3F(p) - transform_origin;
-
- float d = gfx::DotProduct(layer_normal, z_axis);
- float n = -gfx::DotProduct(layer_normal, w);
-
- // Check if layer is parallel to the z = 0 axis which will make it
- // invisible and hence returning zero is fine.
- if (!d)
- return 0.f;
-
- // The intersection point would be given by:
- // p + (n / d) * u but since we are only interested in the
- // z coordinate and p's z coord is zero, all we need is the value of n/d.
- return n / d;
-}
-
-void LayerSorter::CreateGraphNodes(LayerImplList::iterator first,
- LayerImplList::iterator last) {
- DVLOG(2) << "Creating graph nodes:";
- float min_z = FLT_MAX;
- float max_z = -FLT_MAX;
- for (LayerImplList::const_iterator it = first; it < last; it++) {
- nodes_.push_back(GraphNode(*it));
- GraphNode& node = nodes_.at(nodes_.size() - 1);
- RenderSurfaceImpl* render_surface = node.layer->render_surface();
- if (!node.layer->DrawsContent() && !render_surface)
- continue;
-
- DVLOG(2) << "Layer " << node.layer->id() <<
- " (" << node.layer->bounds().width() <<
- " x " << node.layer->bounds().height() << ")";
-
- gfx::Transform draw_transform;
- float layer_width, layer_height;
- if (render_surface) {
- draw_transform = render_surface->draw_transform();
- layer_width = render_surface->content_rect().width();
- layer_height = render_surface->content_rect().height();
- } else {
- draw_transform = node.layer->draw_transform();
- layer_width = node.layer->content_bounds().width();
- layer_height = node.layer->content_bounds().height();
- }
-
- node.shape = LayerShape(layer_width, layer_height, draw_transform);
-
- max_z = std::max(max_z, node.shape.transform_origin.z());
- min_z = std::min(min_z, node.shape.transform_origin.z());
- }
-
- z_range_ = std::abs(max_z - min_z);
-}
-
-void LayerSorter::CreateGraphEdges() {
- DVLOG(2) << "Edges:";
- // Fraction of the total z_range below which z differences
- // are not considered reliable.
- const float z_threshold_factor = 0.01f;
- float z_threshold = z_range_ * z_threshold_factor;
-
- for (size_t na = 0; na < nodes_.size(); na++) {
- GraphNode& node_a = nodes_[na];
- if (!node_a.layer->DrawsContent() && !node_a.layer->render_surface())
- continue;
- for (size_t nb = na + 1; nb < nodes_.size(); nb++) {
- GraphNode& node_b = nodes_[nb];
- if (!node_b.layer->DrawsContent() && !node_b.layer->render_surface())
- continue;
- float weight = 0.f;
- ABCompareResult overlap_result = CheckOverlap(&node_a.shape,
- &node_b.shape,
- z_threshold,
- &weight);
- GraphNode* start_node = NULL;
- GraphNode* end_node = NULL;
- if (overlap_result == ABeforeB) {
- start_node = &node_a;
- end_node = &node_b;
- } else if (overlap_result == BBeforeA) {
- start_node = &node_b;
- end_node = &node_a;
- }
-
- if (start_node) {
- DVLOG(2) << start_node->layer->id() << " -> " << end_node->layer->id();
- edges_.push_back(GraphEdge(start_node, end_node, weight));
- }
- }
- }
-
- for (size_t i = 0; i < edges_.size(); i++) {
- GraphEdge& edge = edges_[i];
- active_edges_[&edge] = &edge;
- edge.from->outgoing.push_back(&edge);
- edge.to->incoming.push_back(&edge);
- edge.to->incoming_edge_weight += edge.weight;
- }
-}
-
-// Finds and removes an edge from the list by doing a swap with the
-// last element of the list.
-void LayerSorter::RemoveEdgeFromList(GraphEdge* edge,
- std::vector<GraphEdge*>* list) {
- std::vector<GraphEdge*>::iterator iter =
- std::find(list->begin(), list->end(), edge);
- DCHECK(iter != list->end());
- list->erase(iter);
-}
-
-// Sorts the given list of layers such that they can be painted in a
-// back-to-front order. Sorting produces correct results for non-intersecting
-// layers that don't have cyclical order dependencies. Cycles and intersections
-// are broken (somewhat) aribtrarily. Sorting of layers is done via a
-// topological sort of a directed graph whose nodes are the layers themselves.
-// An edge from node A to node B signifies that layer A needs to be drawn before
-// layer B. If A and B have no dependency between each other, then we preserve
-// the ordering of those layers as they were in the original list.
-//
-// The draw order between two layers is determined by projecting the two
-// triangles making up each layer quad to the Z = 0 plane, finding points of
-// intersection between the triangles and backprojecting those points to the
-// plane of the layer to determine the corresponding Z coordinate. The layer
-// with the lower Z coordinate (farther from the eye) needs to be rendered
-// first.
-//
-// If the layer projections don't intersect, then no edges (dependencies) are
-// created between them in the graph. HOWEVER, in this case we still need to
-// preserve the ordering of the original list of layers, since that list should
-// already have proper z-index ordering of layers.
-//
-void LayerSorter::Sort(LayerImplList::iterator first,
- LayerImplList::iterator last) {
- DVLOG(2) << "Sorting start ----";
- CreateGraphNodes(first, last);
-
- CreateGraphEdges();
-
- std::vector<GraphNode*> sorted_list;
- std::deque<GraphNode*> no_incoming_edge_node_list;
-
- // Find all the nodes that don't have incoming edges.
- for (NodeList::iterator la = nodes_.begin(); la < nodes_.end(); la++) {
- if (!la->incoming.size())
- no_incoming_edge_node_list.push_back(&(*la));
- }
-
- DVLOG(2) << "Sorted list: ";
- while (active_edges_.size() || no_incoming_edge_node_list.size()) {
- while (no_incoming_edge_node_list.size()) {
- // It is necessary to preserve the existing ordering of layers, when there
- // are no explicit dependencies (because this existing ordering has
- // correct z-index/layout ordering). To preserve this ordering, we process
- // Nodes in the same order that they were added to the list.
- GraphNode* from_node = no_incoming_edge_node_list.front();
- no_incoming_edge_node_list.pop_front();
-
- // Add it to the final list.
- sorted_list.push_back(from_node);
-
- DVLOG(2) << from_node->layer->id() << ", ";
-
- // Remove all its outgoing edges from the graph.
- for (size_t i = 0; i < from_node->outgoing.size(); i++) {
- GraphEdge* outgoing_edge = from_node->outgoing[i];
-
- active_edges_.erase(outgoing_edge);
- RemoveEdgeFromList(outgoing_edge, &outgoing_edge->to->incoming);
- outgoing_edge->to->incoming_edge_weight -= outgoing_edge->weight;
-
- if (!outgoing_edge->to->incoming.size())
- no_incoming_edge_node_list.push_back(outgoing_edge->to);
- }
- from_node->outgoing.clear();
- }
-
- if (!active_edges_.size())
- break;
-
- // If there are still active edges but the list of nodes without incoming
- // edges is empty then we have run into a cycle. Break the cycle by finding
- // the node with the smallest overall incoming edge weight and use it. This
- // will favor nodes that have zero-weight incoming edges i.e. layers that
- // are being occluded by a layer that intersects them.
- float min_incoming_edge_weight = FLT_MAX;
- GraphNode* next_node = NULL;
- for (size_t i = 0; i < nodes_.size(); i++) {
- if (nodes_[i].incoming.size() &&
- nodes_[i].incoming_edge_weight < min_incoming_edge_weight) {
- min_incoming_edge_weight = nodes_[i].incoming_edge_weight;
- next_node = &nodes_[i];
- }
- }
- DCHECK(next_node);
- // Remove all its incoming edges.
- for (size_t e = 0; e < next_node->incoming.size(); e++) {
- GraphEdge* incoming_edge = next_node->incoming[e];
-
- active_edges_.erase(incoming_edge);
- RemoveEdgeFromList(incoming_edge, &incoming_edge->from->outgoing);
- }
- next_node->incoming.clear();
- next_node->incoming_edge_weight = 0.f;
- no_incoming_edge_node_list.push_back(next_node);
- DVLOG(2) << "Breaking cycle by cleaning up incoming edges from " <<
- next_node->layer->id() <<
- " (weight = " << min_incoming_edge_weight << ")";
- }
-
- // Note: The original elements of the list are in no danger of having their
- // ref count go to zero here as they are all nodes of the layer hierarchy and
- // are kept alive by their parent nodes.
- int count = 0;
- for (LayerImplList::iterator it = first; it < last; it++)
- *it = sorted_list[count++]->layer;
-
- DVLOG(2) << "Sorting end ----";
-
- nodes_.clear();
- edges_.clear();
- active_edges_.clear();
-}
-
-} // namespace cc
diff --git a/chromium/cc/trees/layer_sorter.h b/chromium/cc/trees/layer_sorter.h
deleted file mode 100644
index b783ded0c51..00000000000
--- a/chromium/cc/trees/layer_sorter.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_TREES_LAYER_SORTER_H_
-#define CC_TREES_LAYER_SORTER_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/containers/hash_tables.h"
-#include "cc/base/cc_export.h"
-#include "cc/layers/layer_impl.h"
-#include "ui/gfx/geometry/point3_f.h"
-#include "ui/gfx/geometry/quad_f.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/geometry/vector3d_f.h"
-
-namespace gfx {
-class Transform;
-}
-
-namespace cc {
-struct GraphEdge;
-
-// Holds various useful properties derived from a layer's 3D outline.
-struct CC_EXPORT LayerShape {
- LayerShape();
- LayerShape(float width, float height, const gfx::Transform& draw_transform);
- ~LayerShape();
-
- float LayerZFromProjectedPoint(const gfx::PointF& p) const;
-
- gfx::Vector3dF layer_normal;
- gfx::Point3F transform_origin;
- gfx::QuadF projected_quad;
- gfx::RectF projected_bounds;
-};
-
-struct GraphNode {
- explicit GraphNode(LayerImpl* layer_impl);
- ~GraphNode();
-
- LayerImpl* layer;
- LayerShape shape;
- std::vector<GraphEdge*> incoming;
- std::vector<GraphEdge*> outgoing;
- float incoming_edge_weight;
-};
-
-struct GraphEdge {
- GraphEdge(GraphNode* from_node, GraphNode* to_node, float weight)
- : from(from_node),
- to(to_node),
- weight(weight) {}
-
- GraphNode* from;
- GraphNode* to;
- float weight;
-};
-
-
-
-class CC_EXPORT LayerSorter {
- public:
- LayerSorter();
- ~LayerSorter();
-
- void Sort(LayerImplList::iterator first, LayerImplList::iterator last);
-
- enum ABCompareResult {
- ABeforeB,
- BBeforeA,
- None
- };
-
- static ABCompareResult CheckOverlap(LayerShape* a,
- LayerShape* b,
- float z_threshold,
- float* weight);
-
- private:
- typedef std::vector<GraphNode> NodeList;
- typedef std::vector<GraphEdge> EdgeList;
- NodeList nodes_;
- EdgeList edges_;
- float z_range_;
-
- typedef base::hash_map<GraphEdge*, GraphEdge*> EdgeMap;
- EdgeMap active_edges_;
-
- void CreateGraphNodes(LayerImplList::iterator first,
- LayerImplList::iterator last);
- void CreateGraphEdges();
- void RemoveEdgeFromList(GraphEdge* graph, std::vector<GraphEdge*>* list);
-
- DISALLOW_COPY_AND_ASSIGN(LayerSorter);
-};
-
-} // namespace cc
-#endif // CC_TREES_LAYER_SORTER_H_
diff --git a/chromium/cc/trees/layer_sorter_unittest.cc b/chromium/cc/trees/layer_sorter_unittest.cc
deleted file mode 100644
index ba7765bd6fb..00000000000
--- a/chromium/cc/trees/layer_sorter_unittest.cc
+++ /dev/null
@@ -1,329 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/trees/layer_sorter.h"
-
-#include "cc/base/math_util.h"
-#include "cc/layers/layer_impl.h"
-#include "cc/test/fake_impl_proxy.h"
-#include "cc/test/fake_layer_tree_host_impl.h"
-#include "cc/test/test_shared_bitmap_manager.h"
-#include "cc/trees/single_thread_proxy.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/transform.h"
-
-namespace cc {
-namespace {
-
-// Note: In the following overlap tests, the "camera" is looking down the
-// negative Z axis, meaning that layers with smaller z values (more negative)
-// are further from the camera and therefore must be drawn before layers with
-// higher z values.
-
-TEST(LayerSorterTest, BasicOverlap) {
- LayerSorter::ABCompareResult overlap_result;
- const float z_threshold = 0.1f;
- float weight = 0.f;
-
- // Trivial test, with one layer directly obscuring the other.
- gfx::Transform neg4_translate;
- neg4_translate.Translate3d(0.0, 0.0, -4.0);
- LayerShape front(2.f, 2.f, neg4_translate);
-
- gfx::Transform neg5_translate;
- neg5_translate.Translate3d(0.0, 0.0, -5.0);
- LayerShape back(2.f, 2.f, neg5_translate);
-
- overlap_result =
- LayerSorter::CheckOverlap(&front, &back, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::BBeforeA, overlap_result);
- EXPECT_EQ(1.f, weight);
-
- overlap_result =
- LayerSorter::CheckOverlap(&back, &front, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::ABeforeB, overlap_result);
- EXPECT_EQ(1.f, weight);
-
- // One layer translated off to the right. No overlap should be detected.
- gfx::Transform right_translate;
- right_translate.Translate3d(10.0, 0.0, -5.0);
- LayerShape back_right(2.f, 2.f, right_translate);
- overlap_result =
- LayerSorter::CheckOverlap(&front, &back_right, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::None, overlap_result);
-
- // When comparing a layer with itself, z difference is always 0.
- overlap_result =
- LayerSorter::CheckOverlap(&front, &front, z_threshold, &weight);
- EXPECT_EQ(0.f, weight);
-}
-
-TEST(LayerSorterTest, RightAngleOverlap) {
- LayerSorter::ABCompareResult overlap_result;
- const float z_threshold = 0.1f;
- float weight = 0.f;
-
- gfx::Transform perspective_matrix;
- perspective_matrix.ApplyPerspectiveDepth(1000.0);
-
- // Two layers forming a right angle with a perspective viewing transform.
- gfx::Transform left_face_matrix;
- left_face_matrix.Translate3d(-1.0, 0.0, -5.0);
- left_face_matrix.RotateAboutYAxis(-90.0);
- left_face_matrix.Translate(-1.0, -1.0);
- LayerShape left_face(2.f, 2.f, perspective_matrix * left_face_matrix);
- gfx::Transform front_face_matrix;
- front_face_matrix.Translate3d(0.0, 0.0, -4.0);
- front_face_matrix.Translate(-1.0, -1.0);
- LayerShape front_face(2.f, 2.f, perspective_matrix * front_face_matrix);
-
- overlap_result =
- LayerSorter::CheckOverlap(&front_face, &left_face, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::BBeforeA, overlap_result);
-}
-
-TEST(LayerSorterTest, IntersectingLayerOverlap) {
- LayerSorter::ABCompareResult overlap_result;
- const float z_threshold = 0.1f;
- float weight = 0.f;
-
- gfx::Transform perspective_matrix;
- perspective_matrix.ApplyPerspectiveDepth(1000.0);
-
- // Intersecting layers. An explicit order will be returned based on relative z
- // values at the overlapping features but the weight returned should be zero.
- gfx::Transform front_face_matrix;
- front_face_matrix.Translate3d(0.0, 0.0, -4.0);
- front_face_matrix.Translate(-1.0, -1.0);
- LayerShape front_face(2.f, 2.f, perspective_matrix * front_face_matrix);
-
- gfx::Transform through_matrix;
- through_matrix.Translate3d(0.0, 0.0, -4.0);
- through_matrix.RotateAboutYAxis(45.0);
- through_matrix.Translate(-1.0, -1.0);
- LayerShape rotated_face(2.f, 2.f, perspective_matrix * through_matrix);
- overlap_result = LayerSorter::CheckOverlap(&front_face,
- &rotated_face,
- z_threshold,
- &weight);
- EXPECT_NE(LayerSorter::None, overlap_result);
- EXPECT_EQ(0.f, weight);
-}
-
-TEST(LayerSorterTest, LayersAtAngleOverlap) {
- LayerSorter::ABCompareResult overlap_result;
- const float z_threshold = 0.1f;
- float weight = 0.f;
-
- // Trickier test with layers at an angle.
- //
- // -x . . . . 0 . . . . +x
- // -z /
- // : /----B----
- // 0 C
- // : ----A----/
- // +z /
- //
- // C is in front of A and behind B (not what you'd expect by comparing
- // centers). A and B don't overlap, so they're incomparable.
-
- gfx::Transform transform_a;
- transform_a.Translate3d(-6.0, 0.0, 1.0);
- transform_a.Translate(-4.0, -10.0);
- LayerShape layer_a(8.f, 20.f, transform_a);
-
- gfx::Transform transform_b;
- transform_b.Translate3d(6.0, 0.0, -1.0);
- transform_b.Translate(-4.0, -10.0);
- LayerShape layer_b(8.f, 20.f, transform_b);
-
- gfx::Transform transform_c;
- transform_c.RotateAboutYAxis(40.0);
- transform_c.Translate(-4.0, -10.0);
- LayerShape layer_c(8.f, 20.f, transform_c);
-
- overlap_result =
- LayerSorter::CheckOverlap(&layer_a, &layer_c, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::ABeforeB, overlap_result);
- overlap_result =
- LayerSorter::CheckOverlap(&layer_c, &layer_b, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::ABeforeB, overlap_result);
- overlap_result =
- LayerSorter::CheckOverlap(&layer_a, &layer_b, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::None, overlap_result);
-}
-
-TEST(LayerSorterTest, LayersUnderPathologicalPerspectiveTransform) {
- LayerSorter::ABCompareResult overlap_result;
- const float z_threshold = 0.1f;
- float weight = 0.f;
-
- // On perspective projection, if w becomes negative, the re-projected point
- // will be invalid and un-usable. Correct code needs to clip away portions of
- // the geometry where w < 0. If the code uses the invalid value, it will think
- // that a layer has different bounds than it really does, which can cause
- // things to sort incorrectly.
-
- gfx::Transform perspective_matrix;
- perspective_matrix.ApplyPerspectiveDepth(1);
-
- gfx::Transform transform_a;
- transform_a.Translate3d(-15.0, 0.0, -2.0);
- transform_a.Translate(-5.0, -5.0);
- LayerShape layer_a(10.f, 10.f, perspective_matrix * transform_a);
-
- // With this sequence of transforms, when layer B is correctly clipped, it
- // will be visible on the left half of the projection plane, in front of
- // layer_a. When it is not clipped, its bounds will actually incorrectly
- // appear much smaller and the correct sorting dependency will not be found.
- gfx::Transform transform_b;
- transform_b.Translate3d(0.f, 0.f, 0.7f);
- transform_b.RotateAboutYAxis(45.0);
- transform_b.Translate(-5.0, -5.0);
- LayerShape layer_b(10.f, 10.f, perspective_matrix * transform_b);
-
- // Sanity check that the test case actually covers the intended scenario,
- // where part of layer B go behind the w = 0 plane.
- gfx::QuadF test_quad = gfx::QuadF(gfx::RectF(-0.5f, -0.5f, 1.f, 1.f));
- bool clipped = false;
- MathUtil::MapQuad(perspective_matrix * transform_b, test_quad, &clipped);
- ASSERT_TRUE(clipped);
-
- overlap_result =
- LayerSorter::CheckOverlap(&layer_a, &layer_b, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::ABeforeB, overlap_result);
-}
-
-TEST(LayerSorterTest, VerifyExistingOrderingPreservedWhenNoZDiff) {
- // If there is no reason to re-sort the layers (i.e. no 3d z difference), then
- // the existing ordering provided on input should be retained. This test
- // covers the fix in https://bugs.webkit.org/show_bug.cgi?id=75046. Before
- // this fix, ordering was accidentally reversed, causing bugs in z-index
- // ordering on websites when preserves3D triggered the LayerSorter.
-
- // Input list of layers: [1, 2, 3, 4, 5].
- // Expected output: [3, 4, 1, 2, 5].
- // - 1, 2, and 5 do not have a 3d z difference, and therefore their
- // relative ordering should be retained.
- // - 3 and 4 do not have a 3d z difference, and therefore their relative
- // ordering should be retained.
- // - 3 and 4 should be re-sorted so they are in front of 1, 2, and 5.
-
- FakeImplProxy proxy;
- TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
-
- scoped_ptr<LayerImpl> layer1 = LayerImpl::Create(host_impl.active_tree(), 1);
- scoped_ptr<LayerImpl> layer2 = LayerImpl::Create(host_impl.active_tree(), 2);
- scoped_ptr<LayerImpl> layer3 = LayerImpl::Create(host_impl.active_tree(), 3);
- scoped_ptr<LayerImpl> layer4 = LayerImpl::Create(host_impl.active_tree(), 4);
- scoped_ptr<LayerImpl> layer5 = LayerImpl::Create(host_impl.active_tree(), 5);
-
- gfx::Transform BehindMatrix;
- BehindMatrix.Translate3d(0.0, 0.0, 2.0);
- gfx::Transform FrontMatrix;
- FrontMatrix.Translate3d(0.0, 0.0, 1.0);
-
- layer1->SetBounds(gfx::Size(10, 10));
- layer1->SetContentBounds(gfx::Size(10, 10));
- layer1->draw_properties().target_space_transform = BehindMatrix;
- layer1->SetDrawsContent(true);
-
- layer2->SetBounds(gfx::Size(20, 20));
- layer2->SetContentBounds(gfx::Size(20, 20));
- layer2->draw_properties().target_space_transform = BehindMatrix;
- layer2->SetDrawsContent(true);
-
- layer3->SetBounds(gfx::Size(30, 30));
- layer3->SetContentBounds(gfx::Size(30, 30));
- layer3->draw_properties().target_space_transform = FrontMatrix;
- layer3->SetDrawsContent(true);
-
- layer4->SetBounds(gfx::Size(40, 40));
- layer4->SetContentBounds(gfx::Size(40, 40));
- layer4->draw_properties().target_space_transform = FrontMatrix;
- layer4->SetDrawsContent(true);
-
- layer5->SetBounds(gfx::Size(50, 50));
- layer5->SetContentBounds(gfx::Size(50, 50));
- layer5->draw_properties().target_space_transform = BehindMatrix;
- layer5->SetDrawsContent(true);
-
- LayerImplList layer_list;
- layer_list.push_back(layer1.get());
- layer_list.push_back(layer2.get());
- layer_list.push_back(layer3.get());
- layer_list.push_back(layer4.get());
- layer_list.push_back(layer5.get());
-
- ASSERT_EQ(5u, layer_list.size());
- EXPECT_EQ(1, layer_list[0]->id());
- EXPECT_EQ(2, layer_list[1]->id());
- EXPECT_EQ(3, layer_list[2]->id());
- EXPECT_EQ(4, layer_list[3]->id());
- EXPECT_EQ(5, layer_list[4]->id());
-
- LayerSorter layer_sorter;
- layer_sorter.Sort(layer_list.begin(), layer_list.end());
-
- ASSERT_EQ(5u, layer_list.size());
- EXPECT_EQ(3, layer_list[0]->id());
- EXPECT_EQ(4, layer_list[1]->id());
- EXPECT_EQ(1, layer_list[2]->id());
- EXPECT_EQ(2, layer_list[3]->id());
- EXPECT_EQ(5, layer_list[4]->id());
-}
-
-TEST(LayerSorterTest, VerifyConcidentLayerPrecisionLossResultsInDocumentOrder) {
- FakeImplProxy proxy;
- TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
-
- scoped_ptr<LayerImpl> layer1 = LayerImpl::Create(host_impl.active_tree(), 1);
- scoped_ptr<LayerImpl> layer2 = LayerImpl::Create(host_impl.active_tree(), 2);
-
- // Layer 1 should occur before layer 2 in paint. However, due to numeric
- // issues in the sorter, it will put the layers in the wrong order
- // in some situations. Here we test a patch that results in document
- // order rather than calculated order when numeric percision is suspect
- // in calculated order.
-
- gfx::Transform BehindMatrix;
- BehindMatrix.Translate3d(0.f, 0.f, 0.999999f);
- BehindMatrix.RotateAboutXAxis(38.5);
- BehindMatrix.RotateAboutYAxis(77.0);
- gfx::Transform FrontMatrix;
- FrontMatrix.Translate3d(0, 0, 1.0);
- FrontMatrix.RotateAboutXAxis(38.5);
- FrontMatrix.RotateAboutYAxis(77.0);
-
- layer1->SetBounds(gfx::Size(10, 10));
- layer1->SetContentBounds(gfx::Size(10, 10));
- layer1->draw_properties().target_space_transform = BehindMatrix;
- layer1->SetDrawsContent(true);
-
- layer2->SetBounds(gfx::Size(10, 10));
- layer2->SetContentBounds(gfx::Size(10, 10));
- layer2->draw_properties().target_space_transform = FrontMatrix;
- layer2->SetDrawsContent(true);
-
- LayerImplList layer_list;
- layer_list.push_back(layer1.get());
- layer_list.push_back(layer2.get());
-
- ASSERT_EQ(2u, layer_list.size());
- EXPECT_EQ(1, layer_list[0]->id());
- EXPECT_EQ(2, layer_list[1]->id());
-
- LayerSorter layer_sorter;
- layer_sorter.Sort(layer_list.begin(), layer_list.end());
-
- ASSERT_EQ(2u, layer_list.size());
- EXPECT_EQ(1, layer_list[0]->id());
- EXPECT_EQ(2, layer_list[1]->id());
-}
-
-} // namespace
-} // namespace cc
-
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index af7eb5bc96e..6c4696ee10b 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -9,20 +9,25 @@
#include <string>
#include "base/atomic_sequence_num.h"
+#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
#include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/animation/animation_registrar.h"
#include "cc/animation/layer_animation_controller.h"
#include "cc/base/math_util.h"
#include "cc/debug/devtools_instrumentation.h"
+#include "cc/debug/frame_viewer_instrumentation.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/input/layer_selection_bound.h"
+#include "cc/input/page_scale_animation.h"
#include "cc/input/top_controls_manager.h"
#include "cc/layers/heads_up_display_layer.h"
#include "cc/layers/heads_up_display_layer_impl.h"
@@ -32,6 +37,8 @@
#include "cc/layers/render_surface.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/ui_resource_request.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/trees/draw_property_utils.h"
#include "cc/trees/layer_tree_host_client.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_host_impl.h"
@@ -41,6 +48,7 @@
#include "cc/trees/thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
namespace {
static base::StaticAtomicSequenceNumber s_layer_tree_host_sequence_number;
@@ -48,70 +56,51 @@ static base::StaticAtomicSequenceNumber s_layer_tree_host_sequence_number;
namespace cc {
-RendererCapabilities::RendererCapabilities(ResourceFormat best_texture_format,
- bool allow_partial_texture_updates,
- int max_texture_size,
- bool using_shared_memory_resources)
- : best_texture_format(best_texture_format),
- allow_partial_texture_updates(allow_partial_texture_updates),
- max_texture_size(max_texture_size),
- using_shared_memory_resources(using_shared_memory_resources) {}
-
-RendererCapabilities::RendererCapabilities()
- : best_texture_format(RGBA_8888),
- allow_partial_texture_updates(false),
- max_texture_size(0),
- using_shared_memory_resources(false) {}
+LayerTreeHost::InitParams::InitParams() {
+}
-RendererCapabilities::~RendererCapabilities() {}
+LayerTreeHost::InitParams::~InitParams() {
+}
scoped_ptr<LayerTreeHost> LayerTreeHost::CreateThreaded(
- LayerTreeHostClient* client,
- SharedBitmapManager* shared_bitmap_manager,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- const LayerTreeSettings& settings,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
- DCHECK(main_task_runner.get());
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ InitParams* params) {
+ DCHECK(params->main_task_runner.get());
DCHECK(impl_task_runner.get());
- scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(
- client, shared_bitmap_manager, gpu_memory_buffer_manager, settings));
- layer_tree_host->InitializeThreaded(main_task_runner, impl_task_runner);
+ DCHECK(params->settings);
+ scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(params));
+ layer_tree_host->InitializeThreaded(
+ params->main_task_runner, impl_task_runner,
+ params->external_begin_frame_source.Pass());
return layer_tree_host.Pass();
}
scoped_ptr<LayerTreeHost> LayerTreeHost::CreateSingleThreaded(
- LayerTreeHostClient* client,
LayerTreeHostSingleThreadClient* single_thread_client,
- SharedBitmapManager* shared_bitmap_manager,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- const LayerTreeSettings& settings,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
- scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(
- client, shared_bitmap_manager, gpu_memory_buffer_manager, settings));
- layer_tree_host->InitializeSingleThreaded(single_thread_client,
- main_task_runner);
+ InitParams* params) {
+ DCHECK(params->settings);
+ scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(params));
+ layer_tree_host->InitializeSingleThreaded(
+ single_thread_client, params->main_task_runner,
+ params->external_begin_frame_source.Pass());
return layer_tree_host.Pass();
}
-LayerTreeHost::LayerTreeHost(
- LayerTreeHostClient* client,
- SharedBitmapManager* shared_bitmap_manager,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- const LayerTreeSettings& settings)
+LayerTreeHost::LayerTreeHost(InitParams* params)
: micro_benchmark_controller_(this),
next_ui_resource_id_(1),
inside_begin_main_frame_(false),
needs_full_tree_sync_(true),
- client_(client),
+ needs_meta_info_recomputation_(true),
+ client_(params->client),
source_frame_number_(0),
rendering_stats_instrumentation_(RenderingStatsInstrumentation::Create()),
output_surface_lost_(true),
- num_failed_recreate_attempts_(0),
- settings_(settings),
- debug_state_(settings.initial_debug_state),
- top_controls_layout_height_(0.f),
- top_controls_content_offset_(0.f),
+ settings_(*params->settings),
+ debug_state_(settings_.initial_debug_state),
+ top_controls_shrink_blink_size_(false),
+ top_controls_height_(0.f),
+ top_controls_shown_ratio_(0.f),
device_scale_factor_(1.f),
visible_(true),
page_scale_factor_(1.f),
@@ -123,12 +112,13 @@ LayerTreeHost::LayerTreeHost(
background_color_(SK_ColorWHITE),
has_transparent_background_(false),
partial_texture_update_requests_(0),
+ did_complete_scale_animation_(false),
in_paint_layer_contents_(false),
- total_frames_used_for_lcd_text_metrics_(0),
id_(s_layer_tree_host_sequence_number.GetNext() + 1),
next_commit_forces_redraw_(false),
- shared_bitmap_manager_(shared_bitmap_manager),
- gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+ shared_bitmap_manager_(params->shared_bitmap_manager),
+ gpu_memory_buffer_manager_(params->gpu_memory_buffer_manager),
+ task_graph_runner_(params->task_graph_runner),
surface_id_namespace_(0u),
next_surface_sequence_(1u) {
if (settings_.accelerated_animation_enabled)
@@ -139,16 +129,23 @@ LayerTreeHost::LayerTreeHost(
void LayerTreeHost::InitializeThreaded(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
- InitializeProxy(
- ThreadProxy::Create(this, main_task_runner, impl_task_runner));
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+ InitializeProxy(ThreadProxy::Create(this,
+ main_task_runner,
+ impl_task_runner,
+ external_begin_frame_source.Pass()));
}
void LayerTreeHost::InitializeSingleThreaded(
LayerTreeHostSingleThreadClient* single_thread_client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
InitializeProxy(
- SingleThreadProxy::Create(this, single_thread_client, main_task_runner));
+ SingleThreadProxy::Create(this,
+ single_thread_client,
+ main_task_runner,
+ external_begin_frame_source.Pass()));
}
void LayerTreeHost::InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing) {
@@ -169,8 +166,6 @@ void LayerTreeHost::InitializeProxy(scoped_ptr<Proxy> proxy) {
LayerTreeHost::~LayerTreeHost() {
TRACE_EVENT0("cc", "LayerTreeHost::~LayerTreeHost");
- overhang_ui_resource_ = nullptr;
-
if (root_layer_.get())
root_layer_->SetLayerTreeHost(NULL);
@@ -184,7 +179,7 @@ LayerTreeHost::~LayerTreeHost() {
}
// We must clear any pointers into the layer tree prior to destroying it.
- RegisterViewportLayers(NULL, NULL, NULL);
+ RegisterViewportLayers(NULL, NULL, NULL, NULL);
if (root_layer_.get()) {
// The layer tree must be destroyed before the layer tree host. We've
@@ -198,44 +193,6 @@ void LayerTreeHost::SetLayerTreeHostClientReady() {
proxy_->SetLayerTreeHostClientReady();
}
-static void LayerTreeHostOnOutputSurfaceCreatedCallback(Layer* layer) {
- layer->OnOutputSurfaceCreated();
-}
-
-void LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted(bool success) {
- DCHECK(output_surface_lost_);
- TRACE_EVENT1("cc",
- "LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted",
- "success",
- success);
-
- if (!success) {
- // Tolerate a certain number of recreation failures to work around races
- // in the output-surface-lost machinery.
- ++num_failed_recreate_attempts_;
- if (num_failed_recreate_attempts_ >= 5)
- LOG(FATAL) << "Failed to create a fallback OutputSurface.";
- client_->DidFailToInitializeOutputSurface();
- return;
- }
-
- output_surface_lost_ = false;
-
- if (!contents_texture_manager_ && !settings_.impl_side_painting) {
- contents_texture_manager_ =
- PrioritizedResourceManager::Create(proxy_.get());
- surface_memory_placeholder_ =
- contents_texture_manager_->CreateTexture(gfx::Size(), RGBA_8888);
- }
-
- if (root_layer()) {
- LayerTreeHostCommon::CallFunctionForSubtree(
- root_layer(), base::Bind(&LayerTreeHostOnOutputSurfaceCreatedCallback));
- }
-
- client_->DidInitializeOutputSurface();
-}
-
void LayerTreeHost::DeleteContentsTexturesOnImplThread(
ResourceProvider* resource_provider) {
DCHECK(proxy_->IsImplThread());
@@ -243,10 +200,20 @@ void LayerTreeHost::DeleteContentsTexturesOnImplThread(
contents_texture_manager_->ClearAllMemory(resource_provider);
}
+void LayerTreeHost::WillBeginMainFrame() {
+ devtools_instrumentation::WillBeginMainThreadFrame(id(),
+ source_frame_number());
+ client_->WillBeginMainFrame();
+}
+
void LayerTreeHost::DidBeginMainFrame() {
client_->DidBeginMainFrame();
}
+void LayerTreeHost::BeginMainFrameNotExpectedSoon() {
+ client_->BeginMainFrameNotExpectedSoon();
+}
+
void LayerTreeHost::BeginMainFrame(const BeginFrameArgs& args) {
inside_begin_main_frame_ = true;
client_->BeginMainFrame(args);
@@ -300,6 +267,15 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
contents_texture_manager_->ReduceMemory(host_impl->resource_provider());
}
+ bool is_new_trace;
+ TRACE_EVENT_IS_NEW_TRACE(&is_new_trace);
+ if (is_new_trace &&
+ frame_viewer_instrumentation::IsTracingLayerTreeSnapshots() &&
+ root_layer()) {
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ root_layer(), [](Layer* layer) { layer->DidBeginTracing(); });
+ }
+
LayerTreeImpl* sync_tree = host_impl->sync_tree();
if (next_commit_forces_redraw_) {
@@ -313,12 +289,6 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
sync_tree->SetRootLayer(TreeSynchronizer::SynchronizeTrees(
root_layer(), sync_tree->DetachLayerTree(), sync_tree));
}
-
- {
- TRACE_EVENT0("cc", "LayerTreeHost::PushProperties");
- TreeSynchronizer::PushProperties(root_layer(), sync_tree->root_layer());
- }
-
sync_tree->set_needs_full_tree_sync(needs_full_tree_sync_);
needs_full_tree_sync_ = false;
@@ -334,57 +304,49 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
sync_tree->set_has_transparent_background(has_transparent_background_);
if (page_scale_layer_.get() && inner_viewport_scroll_layer_.get()) {
- sync_tree->SetViewportLayersFromIds(page_scale_layer_->id(),
- inner_viewport_scroll_layer_->id(),
- outer_viewport_scroll_layer_.get()
- ? outer_viewport_scroll_layer_->id()
- : Layer::INVALID_ID);
+ sync_tree->SetViewportLayersFromIds(
+ overscroll_elasticity_layer_.get() ? overscroll_elasticity_layer_->id()
+ : Layer::INVALID_ID,
+ page_scale_layer_->id(), inner_viewport_scroll_layer_->id(),
+ outer_viewport_scroll_layer_.get() ? outer_viewport_scroll_layer_->id()
+ : Layer::INVALID_ID);
+ DCHECK(inner_viewport_scroll_layer_->IsContainerForFixedPositionLayers());
} else {
sync_tree->ClearViewportLayers();
}
- sync_tree->RegisterSelection(selection_start_, selection_end_);
+ sync_tree->RegisterSelection(selection_);
- float page_scale_delta =
- sync_tree->page_scale_delta() / sync_tree->sent_page_scale_delta();
- sync_tree->SetPageScaleValues(page_scale_factor_,
- min_page_scale_factor_,
- max_page_scale_factor_,
- page_scale_delta);
- sync_tree->set_sent_page_scale_delta(1.f);
+ sync_tree->PushPageScaleFromMainThread(
+ page_scale_factor_, min_page_scale_factor_, max_page_scale_factor_);
+ sync_tree->elastic_overscroll()->PushFromMainThread(elastic_overscroll_);
+ if (sync_tree->IsActiveTree())
+ sync_tree->elastic_overscroll()->PushPendingToActive();
sync_tree->PassSwapPromises(&swap_promise_list_);
- sync_tree->set_top_controls_layout_height(top_controls_layout_height_);
- sync_tree->set_top_controls_content_offset(top_controls_content_offset_);
- sync_tree->set_top_controls_delta(sync_tree->top_controls_delta() -
- sync_tree->sent_top_controls_delta());
- sync_tree->set_sent_top_controls_delta(0.f);
+ sync_tree->set_top_controls_shrink_blink_size(
+ top_controls_shrink_blink_size_);
+ sync_tree->set_top_controls_height(top_controls_height_);
+ sync_tree->PushTopControlsFromMainThread(top_controls_shown_ratio_);
- host_impl->SetUseGpuRasterization(UseGpuRasterization());
+ host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
+ host_impl->SetContentIsSuitableForGpuRasterization(
+ content_is_suitable_for_gpu_rasterization_);
RecordGpuRasterizationHistogram();
host_impl->SetViewportSize(device_viewport_size_);
host_impl->SetDeviceScaleFactor(device_scale_factor_);
host_impl->SetDebugState(debug_state_);
if (pending_page_scale_animation_) {
- sync_tree->SetPageScaleAnimation(
- pending_page_scale_animation_->target_offset,
- pending_page_scale_animation_->use_anchor,
- pending_page_scale_animation_->scale,
- pending_page_scale_animation_->duration);
- pending_page_scale_animation_ = nullptr;
+ sync_tree->SetPendingPageScaleAnimation(
+ pending_page_scale_animation_.Pass());
}
if (!ui_resource_request_queue_.empty()) {
sync_tree->set_ui_resource_request_queue(ui_resource_request_queue_);
ui_resource_request_queue_.clear();
}
- if (overhang_ui_resource_) {
- host_impl->SetOverhangUIResource(
- overhang_ui_resource_->id(),
- GetUIResourceSize(overhang_ui_resource_->id()));
- }
DCHECK(!sync_tree->ViewportSizeInvalid());
@@ -394,6 +356,12 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
}
sync_tree->set_has_ever_been_drawn(false);
+ sync_tree->SetPropertyTrees(property_trees_);
+
+ {
+ TRACE_EVENT0("cc", "LayerTreeHost::PushProperties");
+ TreeSynchronizer::PushProperties(root_layer(), sync_tree->root_layer());
+ }
micro_benchmark_controller_.ScheduleImplBenchmarks(host_impl);
}
@@ -418,35 +386,62 @@ void LayerTreeHost::UpdateHudLayer() {
void LayerTreeHost::CommitComplete() {
source_frame_number_++;
client_->DidCommit();
+ if (did_complete_scale_animation_) {
+ client_->DidCompletePageScaleAnimation();
+ did_complete_scale_animation_ = false;
+ }
}
void LayerTreeHost::SetOutputSurface(scoped_ptr<OutputSurface> surface) {
+ TRACE_EVENT0("cc", "LayerTreeHost::SetOutputSurface");
+ DCHECK(output_surface_lost_);
+ DCHECK(surface);
+
proxy_->SetOutputSurface(surface.Pass());
}
void LayerTreeHost::RequestNewOutputSurface() {
- client_->RequestNewOutputSurface(num_failed_recreate_attempts_ >= 4);
+ client_->RequestNewOutputSurface();
+}
+
+void LayerTreeHost::DidInitializeOutputSurface() {
+ output_surface_lost_ = false;
+
+ if (!contents_texture_manager_ && !settings_.impl_side_painting) {
+ contents_texture_manager_ =
+ PrioritizedResourceManager::Create(proxy_.get());
+ surface_memory_placeholder_ =
+ contents_texture_manager_->CreateTexture(gfx::Size(), RGBA_8888);
+ }
+
+ if (root_layer()) {
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ root_layer(), [](Layer* layer) { layer->OnOutputSurfaceCreated(); });
+ }
+
+ client_->DidInitializeOutputSurface();
+}
+
+void LayerTreeHost::DidFailToInitializeOutputSurface() {
+ DCHECK(output_surface_lost_);
+ client_->DidFailToInitializeOutputSurface();
}
scoped_ptr<LayerTreeHostImpl> LayerTreeHost::CreateLayerTreeHostImpl(
LayerTreeHostImplClient* client) {
DCHECK(proxy_->IsImplThread());
- scoped_ptr<LayerTreeHostImpl> host_impl =
- LayerTreeHostImpl::Create(settings_,
- client,
- proxy_.get(),
- rendering_stats_instrumentation_.get(),
- shared_bitmap_manager_,
- gpu_memory_buffer_manager_,
- id_);
- host_impl->SetUseGpuRasterization(UseGpuRasterization());
+ scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
+ settings_, client, proxy_.get(), rendering_stats_instrumentation_.get(),
+ shared_bitmap_manager_, gpu_memory_buffer_manager_, task_graph_runner_,
+ id_);
+ host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
+ host_impl->SetContentIsSuitableForGpuRasterization(
+ content_is_suitable_for_gpu_rasterization_);
shared_bitmap_manager_ = NULL;
gpu_memory_buffer_manager_ = NULL;
- if (settings_.calculate_top_controls_position &&
- host_impl->top_controls_manager()) {
- top_controls_manager_weak_ptr_ =
- host_impl->top_controls_manager()->AsWeakPtr();
- }
+ task_graph_runner_ = NULL;
+ top_controls_manager_weak_ptr_ =
+ host_impl->top_controls_manager()->AsWeakPtr();
input_handler_weak_ptr_ = host_impl->AsWeakPtr();
return host_impl.Pass();
}
@@ -458,7 +453,6 @@ void LayerTreeHost::DidLoseOutputSurface() {
if (output_surface_lost_)
return;
- num_failed_recreate_attempts_ = 0;
output_surface_lost_ = true;
SetNeedsCommit();
}
@@ -471,8 +465,6 @@ void LayerTreeHost::SetDeferCommits(bool defer_commits) {
proxy_->SetDeferCommits(defer_commits);
}
-void LayerTreeHost::DidDeferCommit() {}
-
void LayerTreeHost::SetNeedsDisplayOnAllLayers() {
std::stack<Layer*> layer_stack;
layer_stack.push(root_layer());
@@ -513,9 +505,16 @@ void LayerTreeHost::SetNeedsCommit() {
void LayerTreeHost::SetNeedsFullTreeSync() {
needs_full_tree_sync_ = true;
+ needs_meta_info_recomputation_ = true;
+
+ property_trees_.needs_rebuild = true;
SetNeedsCommit();
}
+void LayerTreeHost::SetNeedsMetaInfoRecomputation(bool needs_recomputation) {
+ needs_meta_info_recomputation_ = needs_recomputation;
+}
+
void LayerTreeHost::SetNeedsRedraw() {
SetNeedsRedrawRect(gfx::Rect(device_viewport_size_));
}
@@ -544,35 +543,7 @@ void LayerTreeHost::SetNextCommitForcesRedraw() {
void LayerTreeHost::SetAnimationEvents(
scoped_ptr<AnimationEventsVector> events) {
DCHECK(proxy_->IsMainThread());
- for (size_t event_index = 0; event_index < events->size(); ++event_index) {
- int event_layer_id = (*events)[event_index].layer_id;
-
- // Use the map of all controllers, not just active ones, since non-active
- // controllers may still receive events for impl-only animations.
- const AnimationRegistrar::AnimationControllerMap& animation_controllers =
- animation_registrar_->all_animation_controllers();
- AnimationRegistrar::AnimationControllerMap::const_iterator iter =
- animation_controllers.find(event_layer_id);
- if (iter != animation_controllers.end()) {
- switch ((*events)[event_index].type) {
- case AnimationEvent::Started:
- (*iter).second->NotifyAnimationStarted((*events)[event_index]);
- break;
-
- case AnimationEvent::Finished:
- (*iter).second->NotifyAnimationFinished((*events)[event_index]);
- break;
-
- case AnimationEvent::Aborted:
- (*iter).second->NotifyAnimationAborted((*events)[event_index]);
- break;
-
- case AnimationEvent::PropertyUpdate:
- (*iter).second->NotifyAnimationPropertyUpdate((*events)[event_index]);
- break;
- }
- }
- }
+ animation_registrar_->SetAnimationEvents(events.Pass());
}
void LayerTreeHost::SetRootLayer(scoped_refptr<Layer> root_layer) {
@@ -614,17 +585,6 @@ void LayerTreeHost::SetDebugState(const LayerTreeDebugState& debug_state) {
proxy_->SetDebugState(debug_state);
}
-bool LayerTreeHost::UseGpuRasterization() const {
- if (settings_.gpu_rasterization_forced) {
- return true;
- } else if (settings_.gpu_rasterization_enabled) {
- return has_gpu_rasterization_trigger_ &&
- content_is_suitable_for_gpu_rasterization_;
- } else {
- return false;
- }
-}
-
void LayerTreeHost::SetHasGpuRasterizationTrigger(bool has_trigger) {
if (has_trigger == has_gpu_rasterization_trigger_)
return;
@@ -643,28 +603,34 @@ void LayerTreeHost::SetViewportSize(const gfx::Size& device_viewport_size) {
device_viewport_size_ = device_viewport_size;
+ property_trees_.needs_rebuild = true;
SetNeedsCommit();
}
-void LayerTreeHost::SetTopControlsLayoutHeight(float height) {
- if (top_controls_layout_height_ == height)
+void LayerTreeHost::SetTopControlsHeight(float height, bool shrink) {
+ if (top_controls_height_ == height &&
+ top_controls_shrink_blink_size_ == shrink)
return;
- top_controls_layout_height_ = height;
+ top_controls_height_ = height;
+ top_controls_shrink_blink_size_ = shrink;
SetNeedsCommit();
}
-void LayerTreeHost::SetTopControlsContentOffset(float offset) {
- if (top_controls_content_offset_ == offset)
+void LayerTreeHost::SetTopControlsShownRatio(float ratio) {
+ if (top_controls_shown_ratio_ == ratio)
return;
- top_controls_content_offset_ = offset;
+ top_controls_shown_ratio_ = ratio;
SetNeedsCommit();
}
void LayerTreeHost::ApplyPageScaleDeltaFromImplSide(float page_scale_delta) {
DCHECK(CommitRequested());
+ if (page_scale_delta == 1.f)
+ return;
page_scale_factor_ *= page_scale_delta;
+ property_trees_.needs_rebuild = true;
}
void LayerTreeHost::SetPageScaleFactorAndLimits(float page_scale_factor,
@@ -678,26 +644,10 @@ void LayerTreeHost::SetPageScaleFactorAndLimits(float page_scale_factor,
page_scale_factor_ = page_scale_factor;
min_page_scale_factor_ = min_page_scale_factor;
max_page_scale_factor_ = max_page_scale_factor;
+ property_trees_.needs_rebuild = true;
SetNeedsCommit();
}
-void LayerTreeHost::SetOverhangBitmap(const SkBitmap& bitmap) {
- DCHECK(bitmap.width() && bitmap.height());
- DCHECK_EQ(bitmap.bytesPerPixel(), 4);
-
- SkBitmap bitmap_copy;
- if (bitmap.isImmutable()) {
- bitmap_copy = bitmap;
- } else {
- bitmap.copyTo(&bitmap_copy);
- bitmap_copy.setImmutable();
- }
-
- UIResourceBitmap overhang_bitmap(bitmap_copy);
- overhang_bitmap.SetWrapMode(UIResourceBitmap::REPEAT);
- overhang_ui_resource_ = ScopedUIResource::Create(this, overhang_bitmap);
-}
-
void LayerTreeHost::SetVisible(bool visible) {
if (visible_ == visible)
return;
@@ -707,15 +657,20 @@ void LayerTreeHost::SetVisible(bool visible) {
proxy_->SetVisible(visible);
}
+void LayerTreeHost::SetThrottleFrameProduction(bool throttle) {
+ proxy_->SetThrottleFrameProduction(throttle);
+}
+
void LayerTreeHost::StartPageScaleAnimation(const gfx::Vector2d& target_offset,
bool use_anchor,
float scale,
base::TimeDelta duration) {
- pending_page_scale_animation_.reset(new PendingPageScaleAnimation);
- pending_page_scale_animation_->target_offset = target_offset;
- pending_page_scale_animation_->use_anchor = use_anchor;
- pending_page_scale_animation_->scale = scale;
- pending_page_scale_animation_->duration = duration;
+ pending_page_scale_animation_.reset(
+ new PendingPageScaleAnimation(
+ target_offset,
+ use_anchor,
+ scale,
+ duration));
SetNeedsCommit();
}
@@ -749,6 +704,10 @@ bool LayerTreeHost::UpdateLayers(ResourceUpdateQueue* queue) {
return result || next_commit_forces_redraw_;
}
+void LayerTreeHost::DidCompletePageScaleAnimation() {
+ did_complete_scale_animation_ = true;
+}
+
static Layer* FindFirstScrollableLayer(Layer* layer) {
if (!layer)
return NULL;
@@ -790,18 +749,6 @@ void LayerTreeHost::RecordGpuRasterizationHistogram() {
gpu_rasterization_histogram_recorded_ = true;
}
-void LayerTreeHost::CalculateLCDTextMetricsCallback(Layer* layer) {
- if (!layer->SupportsLCDText())
- return;
-
- lcd_text_metrics_.total_num_cc_layers++;
- if (layer->draw_properties().can_use_lcd_text) {
- lcd_text_metrics_.total_num_cc_layers_can_use_lcd_text++;
- if (layer->contents_opaque())
- lcd_text_metrics_.total_num_cc_layers_will_use_lcd_text++;
- }
-}
-
bool LayerTreeHost::UsingSharedMemoryResources() {
return GetRendererCapabilities().using_shared_memory_resources;
}
@@ -811,63 +758,81 @@ bool LayerTreeHost::UpdateLayers(Layer* root_layer,
TRACE_EVENT1("cc", "LayerTreeHost::UpdateLayers",
"source_frame_number", source_frame_number());
- RenderSurfaceLayerList update_list;
- {
- UpdateHudLayer();
+ RenderSurfaceLayerList render_surface_layer_list;
- Layer* root_scroll = FindFirstScrollableLayer(root_layer);
- Layer* page_scale_layer = page_scale_layer_.get();
- if (!page_scale_layer && root_scroll)
- page_scale_layer = root_scroll->parent();
+ UpdateHudLayer();
- if (hud_layer_.get()) {
- hud_layer_->PrepareForCalculateDrawProperties(
- device_viewport_size(), device_scale_factor_);
- }
+ Layer* root_scroll = FindFirstScrollableLayer(root_layer);
+ Layer* page_scale_layer = page_scale_layer_.get();
+ if (!page_scale_layer && root_scroll)
+ page_scale_layer = root_scroll->parent();
+
+ if (hud_layer_.get()) {
+ hud_layer_->PrepareForCalculateDrawProperties(device_viewport_size(),
+ device_scale_factor_);
+ }
+ bool can_render_to_separate_surface = true;
+ // TODO(vmpstr): Passing 0 as the current render surface layer list id means
+ // that we won't be able to detect if a layer is part of
+ // |render_surface_layer_list|. Change this if this information is
+ // required.
+ int render_surface_layer_list_id = 0;
+ LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(
+ root_layer, device_viewport_size(), gfx::Transform(),
+ device_scale_factor_, page_scale_factor_, page_scale_layer,
+ elastic_overscroll_, overscroll_elasticity_layer_.get(),
+ GetRendererCapabilities().max_texture_size, settings_.can_use_lcd_text,
+ settings_.layers_always_allowed_lcd_text, can_render_to_separate_surface,
+ settings_.layer_transforms_should_scale_layer_contents,
+ settings_.verify_property_trees, &render_surface_layer_list,
+ render_surface_layer_list_id, &property_trees_);
+
+ // This is a temporary state of affairs until impl-side painting is shipped
+ // everywhere and main thread property trees can be used in all cases.
+ // This code here implies that even if verify property trees is on,
+ // no verification will occur and only property trees will be used on the
+ // main thread.
+ if (using_only_property_trees()) {
TRACE_EVENT0("cc", "LayerTreeHost::UpdateLayers::CalcDrawProps");
- bool can_render_to_separate_surface = true;
- // TODO(vmpstr): Passing 0 as the current render surface layer list id means
- // that we won't be able to detect if a layer is part of |update_list|.
- // Change this if this information is required.
- int render_surface_layer_list_id = 0;
- LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(
- root_layer,
- device_viewport_size(),
- gfx::Transform(),
- device_scale_factor_,
- page_scale_factor_,
- page_scale_layer,
- GetRendererCapabilities().max_texture_size,
- settings_.can_use_lcd_text,
- can_render_to_separate_surface,
- settings_.layer_transforms_should_scale_layer_contents,
- &update_list,
- render_surface_layer_list_id);
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
- if (total_frames_used_for_lcd_text_metrics_ <=
- kTotalFramesToUseForLCDTextMetrics) {
- LayerTreeHostCommon::CallFunctionForSubtree(
- root_layer,
- base::Bind(&LayerTreeHost::CalculateLCDTextMetricsCallback,
- base::Unretained(this)));
- total_frames_used_for_lcd_text_metrics_++;
+ LayerTreeHostCommon::PreCalculateMetaInformation(root_layer);
+
+ bool preserves_2d_axis_alignment = false;
+ gfx::Transform identity_transform;
+ LayerList update_layer_list;
+
+ LayerTreeHostCommon::UpdateRenderSurfaces(
+ root_layer, can_render_to_separate_surface, identity_transform,
+ preserves_2d_axis_alignment);
+ {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
+ "LayerTreeHostCommon::ComputeVisibleRectsWithPropertyTrees");
+ BuildPropertyTreesAndComputeVisibleRects(
+ root_layer, page_scale_layer, page_scale_factor_,
+ device_scale_factor_, gfx::Rect(device_viewport_size_),
+ identity_transform, &property_trees_, &update_layer_list);
}
- if (total_frames_used_for_lcd_text_metrics_ ==
- kTotalFramesToUseForLCDTextMetrics) {
- total_frames_used_for_lcd_text_metrics_++;
-
- UMA_HISTOGRAM_PERCENTAGE(
- "Renderer4.LCDText.PercentageOfCandidateLayers",
- lcd_text_metrics_.total_num_cc_layers_can_use_lcd_text * 100.0 /
- lcd_text_metrics_.total_num_cc_layers);
- UMA_HISTOGRAM_PERCENTAGE(
- "Renderer4.LCDText.PercentageOfAALayers",
- lcd_text_metrics_.total_num_cc_layers_will_use_lcd_text * 100.0 /
- lcd_text_metrics_.total_num_cc_layers_can_use_lcd_text);
+ for (const auto& layer : update_layer_list)
+ layer->SavePaintProperties();
+
+ base::AutoReset<bool> painting(&in_paint_layer_contents_, true);
+ bool did_paint_content = false;
+ for (const auto& layer : update_layer_list) {
+ // TODO(enne): temporarily clobber draw properties visible rect.
+ layer->draw_properties().visible_content_rect =
+ layer->visible_rect_from_property_trees();
+ did_paint_content |= layer->Update(queue, nullptr);
+ content_is_suitable_for_gpu_rasterization_ &=
+ layer->IsSuitableForGpuRasterization();
}
+ return did_paint_content;
+ }
+
+ {
+ TRACE_EVENT0("cc", "LayerTreeHost::UpdateLayers::CalcDrawProps");
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
}
// Reset partial texture update requests.
@@ -875,15 +840,15 @@ bool LayerTreeHost::UpdateLayers(Layer* root_layer,
bool did_paint_content = false;
bool need_more_updates = false;
- PaintLayerContents(
- update_list, queue, &did_paint_content, &need_more_updates);
+ PaintLayerContents(render_surface_layer_list, queue, &did_paint_content,
+ &need_more_updates);
if (need_more_updates) {
TRACE_EVENT0("cc", "LayerTreeHost::UpdateLayers::posting prepaint task");
prepaint_callback_.Reset(base::Bind(&LayerTreeHost::TriggerPrepaint,
base::Unretained(this)));
static base::TimeDelta prepaint_delay =
base::TimeDelta::FromMilliseconds(100);
- base::MessageLoop::current()->PostDelayedTask(
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, prepaint_callback_.callback(), prepaint_delay);
}
@@ -896,17 +861,12 @@ void LayerTreeHost::TriggerPrepaint() {
SetNeedsCommit();
}
-static void LayerTreeHostReduceMemoryCallback(Layer* layer) {
- layer->ReduceMemoryUsage();
-}
-
void LayerTreeHost::ReduceMemoryUsage() {
if (!root_layer())
return;
LayerTreeHostCommon::CallFunctionForSubtree(
- root_layer(),
- base::Bind(&LayerTreeHostReduceMemoryCallback));
+ root_layer(), [](Layer* layer) { layer->ReduceMemoryUsage(); });
}
void LayerTreeHost::SetPrioritiesForSurfaces(size_t surface_memory_bytes) {
@@ -960,7 +920,6 @@ void LayerTreeHost::PrioritizeTextures(
size_t LayerTreeHost::CalculateMemoryForRenderSurfaces(
const RenderSurfaceLayerList& update_list) {
size_t readback_bytes = 0;
- size_t max_background_texture_bytes = 0;
size_t contents_texture_bytes = 0;
// Start iteration at 1 to skip the root surface as it does not have a texture
@@ -974,17 +933,16 @@ size_t LayerTreeHost::CalculateMemoryForRenderSurfaces(
RGBA_8888);
contents_texture_bytes += bytes;
- if (render_surface_layer->background_filters().IsEmpty())
+ if (render_surface_layer->background_filters().IsEmpty() &&
+ render_surface_layer->uses_default_blend_mode())
continue;
- if (bytes > max_background_texture_bytes)
- max_background_texture_bytes = bytes;
if (!readback_bytes) {
readback_bytes = Resource::MemorySizeBytes(device_viewport_size_,
RGBA_8888);
}
}
- return readback_bytes + max_background_texture_bytes + contents_texture_bytes;
+ return readback_bytes + contents_texture_bytes;
}
void LayerTreeHost::PaintMasksForRenderSurface(Layer* render_surface_layer,
@@ -1070,8 +1028,8 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) {
QueueSwapPromise(swap_promise.Pass());
}
- gfx::Vector2d inner_viewport_scroll_delta;
- gfx::Vector2d outer_viewport_scroll_delta;
+ gfx::Vector2dF inner_viewport_scroll_delta;
+ gfx::Vector2dF outer_viewport_scroll_delta;
if (root_layer_.get()) {
for (size_t i = 0; i < info->scrolls.size(); ++i) {
@@ -1092,9 +1050,8 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) {
}
if (!inner_viewport_scroll_delta.IsZero() ||
- !outer_viewport_scroll_delta.IsZero() ||
- info->page_scale_delta != 1.f ||
- info->top_controls_delta) {
+ !outer_viewport_scroll_delta.IsZero() || info->page_scale_delta != 1.f ||
+ !info->elastic_overscroll_delta.IsZero() || info->top_controls_delta) {
// Preemptively apply the scroll offset and scale delta here before sending
// it to the client. If the client comes back and sets it to the same
// value, then the layer can early out without needing a full commit.
@@ -1113,16 +1070,21 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) {
}
ApplyPageScaleDeltaFromImplSide(info->page_scale_delta);
+ elastic_overscroll_ += info->elastic_overscroll_delta;
if (!settings_.use_pinch_virtual_viewport) {
+ // TODO(miletus): Make sure either this code path is totally gone,
+ // or revisit the flooring here if the old pinch viewport code path
+ // is causing problems with fractional scroll offset.
client_->ApplyViewportDeltas(
- inner_viewport_scroll_delta + outer_viewport_scroll_delta,
- info->page_scale_delta,
- info->top_controls_delta);
+ gfx::ToFlooredVector2d(inner_viewport_scroll_delta +
+ outer_viewport_scroll_delta),
+ info->page_scale_delta, info->top_controls_delta);
} else {
+ // TODO(ccameron): pass the elastic overscroll here so that input events
+ // may be translated appropriately.
client_->ApplyViewportDeltas(
- inner_viewport_scroll_delta,
- outer_viewport_scroll_delta,
- info->page_scale_delta,
+ inner_viewport_scroll_delta, outer_viewport_scroll_delta,
+ info->elastic_overscroll_delta, info->page_scale_delta,
info->top_controls_delta);
}
}
@@ -1182,15 +1144,13 @@ void LayerTreeHost::SetDeviceScaleFactor(float device_scale_factor) {
return;
device_scale_factor_ = device_scale_factor;
+ property_trees_.needs_rebuild = true;
SetNeedsCommit();
}
void LayerTreeHost::UpdateTopControlsState(TopControlsState constraints,
TopControlsState current,
bool animate) {
- if (!settings_.calculate_top_controls_position)
- return;
-
// Top controls are only used in threaded mode.
proxy_->ImplThreadTaskRunner()->PostTask(
FROM_HERE,
@@ -1201,27 +1161,15 @@ void LayerTreeHost::UpdateTopControlsState(TopControlsState constraints,
animate));
}
-void LayerTreeHost::AsValueInto(base::debug::TracedValue* state) const {
- state->BeginDictionary("proxy");
- proxy_->AsValueInto(state);
- state->EndDictionary();
-}
-
void LayerTreeHost::AnimateLayers(base::TimeTicks monotonic_time) {
- if (!settings_.accelerated_animation_enabled ||
- animation_registrar_->active_animation_controllers().empty())
+ if (!settings_.accelerated_animation_enabled)
return;
- TRACE_EVENT0("cc", "LayerTreeHost::AnimateLayers");
-
- AnimationRegistrar::AnimationControllerMap copy =
- animation_registrar_->active_animation_controllers();
- for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
- iter != copy.end();
- ++iter) {
- (*iter).second->Animate(monotonic_time);
- bool start_ready_animations = true;
- (*iter).second->UpdateState(start_ready_animations, NULL);
+ AnimationEventsVector events;
+ if (animation_registrar_->AnimateLayers(monotonic_time)) {
+ animation_registrar_->UpdateAnimationState(true, &events);
+ if (!events.empty())
+ property_trees_.needs_rebuild = true;
}
}
@@ -1233,8 +1181,7 @@ UIResourceId LayerTreeHost::CreateUIResource(UIResourceClient* client) {
ui_resource_client_map_.end());
bool resource_lost = false;
- UIResourceRequest request(UIResourceRequest::UIResourceCreate,
- next_id,
+ UIResourceRequest request(UIResourceRequest::UI_RESOURCE_CREATE, next_id,
client->GetBitmap(next_id, resource_lost));
ui_resource_request_queue_.push_back(request);
@@ -1252,7 +1199,7 @@ void LayerTreeHost::DeleteUIResource(UIResourceId uid) {
if (iter == ui_resource_client_map_.end())
return;
- UIResourceRequest request(UIResourceRequest::UIResourceDelete, uid);
+ UIResourceRequest request(UIResourceRequest::UI_RESOURCE_DELETE, uid);
ui_resource_request_queue_.push_back(request);
ui_resource_client_map_.erase(iter);
}
@@ -1264,8 +1211,7 @@ void LayerTreeHost::RecreateUIResources() {
UIResourceId uid = iter->first;
const UIResourceClientData& data = iter->second;
bool resource_lost = true;
- UIResourceRequest request(UIResourceRequest::UIResourceCreate,
- uid,
+ UIResourceRequest request(UIResourceRequest::UI_RESOURCE_CREATE, uid,
data.client->GetBitmap(uid, resource_lost));
ui_resource_request_queue_.push_back(request);
}
@@ -1282,21 +1228,21 @@ gfx::Size LayerTreeHost::GetUIResourceSize(UIResourceId uid) const {
}
void LayerTreeHost::RegisterViewportLayers(
+ scoped_refptr<Layer> overscroll_elasticity_layer,
scoped_refptr<Layer> page_scale_layer,
scoped_refptr<Layer> inner_viewport_scroll_layer,
scoped_refptr<Layer> outer_viewport_scroll_layer) {
+ overscroll_elasticity_layer_ = overscroll_elasticity_layer;
page_scale_layer_ = page_scale_layer;
inner_viewport_scroll_layer_ = inner_viewport_scroll_layer;
outer_viewport_scroll_layer_ = outer_viewport_scroll_layer;
}
-void LayerTreeHost::RegisterSelection(const LayerSelectionBound& start,
- const LayerSelectionBound& end) {
- if (selection_start_ == start && selection_end_ == end)
+void LayerTreeHost::RegisterSelection(const LayerSelection& selection) {
+ if (selection_ == selection)
return;
- selection_start_ = start;
- selection_end_ = end;
+ selection_ = selection;
SetNeedsCommit();
}
@@ -1333,8 +1279,8 @@ void LayerTreeHost::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) {
}
void LayerTreeHost::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) {
- for (size_t i = 0; i < swap_promise_list_.size(); i++)
- swap_promise_list_[i]->DidNotSwap(reason);
+ for (auto* swap_promise : swap_promise_list_)
+ swap_promise->DidNotSwap(reason);
swap_promise_list_.clear();
}
@@ -1346,4 +1292,19 @@ SurfaceSequence LayerTreeHost::CreateSurfaceSequence() {
return SurfaceSequence(surface_id_namespace_, next_surface_sequence_++);
}
+void LayerTreeHost::SetChildrenNeedBeginFrames(
+ bool children_need_begin_frames) const {
+ proxy_->SetChildrenNeedBeginFrames(children_need_begin_frames);
+}
+
+void LayerTreeHost::SendBeginFramesToChildren(
+ const BeginFrameArgs& args) const {
+ client_->SendBeginFramesToChildren(args);
+}
+
+void LayerTreeHost::SetAuthoritativeVSyncInterval(
+ const base::TimeDelta& interval) {
+ proxy_->SetAuthoritativeVSyncInterval(interval);
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index a56a6cd43d5..cf47facddd4 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -6,7 +6,6 @@
#define CC_TREES_LAYER_TREE_HOST_H_
#include <limits>
-#include <list>
#include <set>
#include <string>
#include <vector>
@@ -22,8 +21,6 @@
#include "cc/animation/animation_events.h"
#include "cc/base/cc_export.h"
#include "cc/base/scoped_ptr_vector.h"
-#include "cc/base/swap_promise.h"
-#include "cc/base/swap_promise_monitor.h"
#include "cc/debug/micro_benchmark.h"
#include "cc/debug/micro_benchmark_controller.h"
#include "cc/input/input_handler.h"
@@ -32,6 +29,8 @@
#include "cc/input/top_controls_state.h"
#include "cc/layers/layer_lists.h"
#include "cc/output/output_surface.h"
+#include "cc/output/renderer_capabilities.h"
+#include "cc/output/swap_promise.h"
#include "cc/resources/resource_format.h"
#include "cc/resources/scoped_ui_resource.h"
#include "cc/surfaces/surface_sequence.h"
@@ -39,6 +38,7 @@
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_settings.h"
#include "cc/trees/proxy.h"
+#include "cc/trees/swap_promise_monitor.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/rect.h"
@@ -48,6 +48,7 @@ class GpuMemoryBufferManager;
namespace cc {
class AnimationRegistrar;
+class BeginFrameSource;
class HeadsUpDisplayLayer;
class Layer;
class LayerTreeHostImpl;
@@ -55,62 +56,53 @@ class LayerTreeHostImplClient;
class LayerTreeHostSingleThreadClient;
class PrioritizedResource;
class PrioritizedResourceManager;
+class PropertyTrees;
class Region;
class RenderingStatsInstrumentation;
class ResourceProvider;
class ResourceUpdateQueue;
class SharedBitmapManager;
+class TaskGraphRunner;
class TopControlsManager;
class UIResourceRequest;
+struct PendingPageScaleAnimation;
struct RenderingStats;
struct ScrollAndScaleSet;
-// Provides information on an Impl's rendering capabilities back to the
-// LayerTreeHost.
-struct CC_EXPORT RendererCapabilities {
- RendererCapabilities(ResourceFormat best_texture_format,
- bool allow_partial_texture_updates,
- int max_texture_size,
- bool using_shared_memory_resources);
-
- RendererCapabilities();
- ~RendererCapabilities();
-
- // Duplicate any modification to this list to RendererCapabilitiesImpl.
- ResourceFormat best_texture_format;
- bool allow_partial_texture_updates;
- int max_texture_size;
- bool using_shared_memory_resources;
-};
-
class CC_EXPORT LayerTreeHost {
public:
+ // TODO(sad): InitParams should be a movable type so that it can be
+ // std::move()d to the Create* functions.
+ struct CC_EXPORT InitParams {
+ LayerTreeHostClient* client = nullptr;
+ SharedBitmapManager* shared_bitmap_manager = nullptr;
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = nullptr;
+ TaskGraphRunner* task_graph_runner = nullptr;
+ LayerTreeSettings const* settings = nullptr;
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner;
+ scoped_ptr<BeginFrameSource> external_begin_frame_source;
+
+ InitParams();
+ ~InitParams();
+ };
+
// The SharedBitmapManager will be used on the compositor thread.
static scoped_ptr<LayerTreeHost> CreateThreaded(
- LayerTreeHostClient* client,
- SharedBitmapManager* shared_bitmap_manager,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- const LayerTreeSettings& settings,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ InitParams* params);
static scoped_ptr<LayerTreeHost> CreateSingleThreaded(
- LayerTreeHostClient* client,
LayerTreeHostSingleThreadClient* single_thread_client,
- SharedBitmapManager* shared_bitmap_manager,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- const LayerTreeSettings& settings,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ InitParams* params);
virtual ~LayerTreeHost();
void SetLayerTreeHostClientReady();
// LayerTreeHost interface to Proxy.
- void WillBeginMainFrame() {
- client_->WillBeginMainFrame(source_frame_number_);
- }
+ void WillBeginMainFrame();
void DidBeginMainFrame();
void BeginMainFrame(const BeginFrameArgs& args);
+ void BeginMainFrameNotExpectedSoon();
void AnimateLayers(base::TimeTicks monotonic_frame_begin_time);
void DidStopFlinging();
void Layout();
@@ -120,16 +112,20 @@ class CC_EXPORT LayerTreeHost {
void CommitComplete();
void SetOutputSurface(scoped_ptr<OutputSurface> output_surface);
void RequestNewOutputSurface();
+ void DidInitializeOutputSurface();
+ void DidFailToInitializeOutputSurface();
virtual scoped_ptr<LayerTreeHostImpl> CreateLayerTreeHostImpl(
LayerTreeHostImplClient* client);
void DidLoseOutputSurface();
bool output_surface_lost() const { return output_surface_lost_; }
- virtual void OnCreateAndInitializeOutputSurfaceAttempted(bool success);
void DidCommitAndDrawFrame() { client_->DidCommitAndDrawFrame(); }
void DidCompleteSwapBuffers() { client_->DidCompleteSwapBuffers(); }
void DeleteContentsTexturesOnImplThread(ResourceProvider* resource_provider);
bool UpdateLayers(ResourceUpdateQueue* queue);
+ // Called when the compositor completed page scale animation.
+ void DidCompletePageScaleAnimation();
+
LayerTreeHostClient* client() { return client_; }
const base::WeakPtr<InputHandler>& GetInputHandler() {
return input_handler_weak_ptr_;
@@ -143,9 +139,6 @@ class CC_EXPORT LayerTreeHost {
void SetDeferCommits(bool defer_commits);
- // Test only hook
- virtual void DidDeferCommit();
-
int source_frame_number() const { return source_frame_number_; }
void SetNeedsDisplayOnAllLayers();
@@ -162,6 +155,8 @@ class CC_EXPORT LayerTreeHost {
virtual void SetNeedsUpdateLayers();
virtual void SetNeedsCommit();
virtual void SetNeedsFullTreeSync();
+ virtual void SetNeedsMetaInfoRecomputation(
+ bool needs_meta_info_recomputation);
void SetNeedsRedraw();
void SetNeedsRedrawRect(const gfx::Rect& damage_rect);
bool CommitRequested() const;
@@ -176,11 +171,14 @@ class CC_EXPORT LayerTreeHost {
void SetRootLayer(scoped_refptr<Layer> root_layer);
Layer* root_layer() { return root_layer_.get(); }
const Layer* root_layer() const { return root_layer_.get(); }
+ const Layer* overscroll_elasticity_layer() const {
+ return overscroll_elasticity_layer_.get();
+ }
const Layer* page_scale_layer() const { return page_scale_layer_.get(); }
- void RegisterViewportLayers(
- scoped_refptr<Layer> page_scale_layer,
- scoped_refptr<Layer> inner_viewport_scroll_layer,
- scoped_refptr<Layer> outer_viewport_scroll_layer);
+ void RegisterViewportLayers(scoped_refptr<Layer> overscroll_elasticity_layer,
+ scoped_refptr<Layer> page_scale_layer,
+ scoped_refptr<Layer> inner_viewport_scroll_layer,
+ scoped_refptr<Layer> outer_viewport_scroll_layer);
Layer* inner_viewport_scroll_layer() const {
return inner_viewport_scroll_layer_.get();
}
@@ -188,8 +186,7 @@ class CC_EXPORT LayerTreeHost {
return outer_viewport_scroll_layer_.get();
}
- void RegisterSelection(const LayerSelectionBound& start,
- const LayerSelectionBound& end);
+ void RegisterSelection(const LayerSelection& selection);
const LayerTreeSettings& settings() const { return settings_; }
@@ -200,11 +197,10 @@ class CC_EXPORT LayerTreeHost {
return has_gpu_rasterization_trigger_;
}
void SetHasGpuRasterizationTrigger(bool has_trigger);
- bool UseGpuRasterization() const;
void SetViewportSize(const gfx::Size& device_viewport_size);
- void SetTopControlsLayoutHeight(float height);
- void SetTopControlsContentOffset(float offset);
+ void SetTopControlsHeight(float height, bool shrink);
+ void SetTopControlsShownRatio(float ratio);
gfx::Size device_viewport_size() const { return device_viewport_size_; }
@@ -213,6 +209,7 @@ class CC_EXPORT LayerTreeHost {
float min_page_scale_factor,
float max_page_scale_factor);
float page_scale_factor() const { return page_scale_factor_; }
+ gfx::Vector2dF elastic_overscroll() const { return elastic_overscroll_; }
SkColor background_color() const { return background_color_; }
void set_background_color(SkColor color) { background_color_ = color; }
@@ -221,8 +218,6 @@ class CC_EXPORT LayerTreeHost {
has_transparent_background_ = transparent;
}
- void SetOverhangBitmap(const SkBitmap& bitmap);
-
PrioritizedResourceManager* contents_texture_manager() const {
return contents_texture_manager_.get();
}
@@ -230,6 +225,8 @@ class CC_EXPORT LayerTreeHost {
void SetVisible(bool visible);
bool visible() const { return visible_; }
+ void SetThrottleFrameProduction(bool throttle);
+
void StartPageScaleAnimation(const gfx::Vector2d& target_offset,
bool use_anchor,
float scale,
@@ -263,9 +260,6 @@ class CC_EXPORT LayerTreeHost {
return animation_registrar_.get();
}
- // Obtains a thorough dump of the LayerTreeHost as a value.
- void AsValueInto(base::debug::TracedValue* value) const;
-
bool in_paint_layer_contents() const { return in_paint_layer_contents_; }
// CreateUIResource creates a resource given a bitmap. The bitmap is
@@ -311,22 +305,48 @@ class CC_EXPORT LayerTreeHost {
void set_surface_id_namespace(uint32_t id_namespace);
SurfaceSequence CreateSurfaceSequence();
+ void SetChildrenNeedBeginFrames(bool children_need_begin_frames) const;
+ void SendBeginFramesToChildren(const BeginFrameArgs& args) const;
+
+ void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval);
+
+ PropertyTrees* property_trees() { return &property_trees_; }
+ bool needs_meta_info_recomputation() {
+ return needs_meta_info_recomputation_;
+ }
+
+ // If this is true, only property trees will be used for main thread CDP.
+ // CDP will not be run, and verify_property_trees will be ignored.
+ bool using_only_property_trees() const {
+ return settings().impl_side_painting;
+ }
+
protected:
- LayerTreeHost(LayerTreeHostClient* client,
- SharedBitmapManager* shared_bitmap_manager,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- const LayerTreeSettings& settings);
+ explicit LayerTreeHost(InitParams* params);
void InitializeThreaded(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
void InitializeSingleThreaded(
LayerTreeHostSingleThreadClient* single_thread_client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
void InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing);
void SetOutputSurfaceLostForTesting(bool is_lost) {
output_surface_lost_ = is_lost;
}
+ // shared_bitmap_manager(), gpu_memory_buffer_manager(), and
+ // task_graph_runner() return valid values only until the LayerTreeHostImpl is
+ // created in CreateLayerTreeHostImpl().
+ SharedBitmapManager* shared_bitmap_manager() const {
+ return shared_bitmap_manager_;
+ }
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager() const {
+ return gpu_memory_buffer_manager_;
+ }
+ TaskGraphRunner* task_graph_runner() const { return task_graph_runner_; }
+
MicroBenchmarkController micro_benchmark_controller_;
private:
@@ -366,7 +386,7 @@ class CC_EXPORT LayerTreeHost {
UIResourceClientMap ui_resource_client_map_;
int next_ui_resource_id_;
- typedef std::list<UIResourceRequest> UIResourceRequestQueue;
+ typedef std::vector<UIResourceRequest> UIResourceRequestQueue;
UIResourceRequestQueue ui_resource_request_queue_;
void RecordGpuRasterizationHistogram();
@@ -376,6 +396,7 @@ class CC_EXPORT LayerTreeHost {
bool inside_begin_main_frame_;
bool needs_full_tree_sync_;
+ bool needs_meta_info_recomputation_;
base::CancelableClosure prepaint_callback_;
@@ -386,7 +407,6 @@ class CC_EXPORT LayerTreeHost {
scoped_ptr<RenderingStatsInstrumentation> rendering_stats_instrumentation_;
bool output_surface_lost_;
- int num_failed_recreate_attempts_;
scoped_refptr<Layer> root_layer_;
scoped_refptr<HeadsUpDisplayLayer> hud_layer_;
@@ -401,8 +421,9 @@ class CC_EXPORT LayerTreeHost {
LayerTreeDebugState debug_state_;
gfx::Size device_viewport_size_;
- float top_controls_layout_height_;
- float top_controls_content_offset_;
+ bool top_controls_shrink_blink_size_;
+ float top_controls_height_;
+ float top_controls_shown_ratio_;
float device_scale_factor_;
bool visible_;
@@ -412,6 +433,7 @@ class CC_EXPORT LayerTreeHost {
float page_scale_factor_;
float min_page_scale_factor_;
float max_page_scale_factor_;
+ gfx::Vector2dF elastic_overscroll_;
bool has_gpu_rasterization_trigger_;
bool content_is_suitable_for_gpu_rasterization_;
bool gpu_rasterization_histogram_recorded_;
@@ -419,55 +441,38 @@ class CC_EXPORT LayerTreeHost {
SkColor background_color_;
bool has_transparent_background_;
- // If set, this texture is used to fill in the parts of the screen not
- // covered by layers.
- scoped_ptr<ScopedUIResource> overhang_ui_resource_;
-
typedef ScopedPtrVector<PrioritizedResource> TextureList;
size_t partial_texture_update_requests_;
scoped_ptr<AnimationRegistrar> animation_registrar_;
- struct PendingPageScaleAnimation {
- gfx::Vector2d target_offset;
- bool use_anchor;
- float scale;
- base::TimeDelta duration;
- };
scoped_ptr<PendingPageScaleAnimation> pending_page_scale_animation_;
- bool in_paint_layer_contents_;
-
- static const int kTotalFramesToUseForLCDTextMetrics = 50;
- int total_frames_used_for_lcd_text_metrics_;
+ // If set, then page scale animation has completed, but the client hasn't been
+ // notified about it yet.
+ bool did_complete_scale_animation_;
- struct LCDTextMetrics {
- LCDTextMetrics()
- : total_num_cc_layers(0),
- total_num_cc_layers_can_use_lcd_text(0),
- total_num_cc_layers_will_use_lcd_text(0) {}
+ bool in_paint_layer_contents_;
- int64 total_num_cc_layers;
- int64 total_num_cc_layers_can_use_lcd_text;
- int64 total_num_cc_layers_will_use_lcd_text;
- };
- LCDTextMetrics lcd_text_metrics_;
int id_;
bool next_commit_forces_redraw_;
+ scoped_refptr<Layer> overscroll_elasticity_layer_;
scoped_refptr<Layer> page_scale_layer_;
scoped_refptr<Layer> inner_viewport_scroll_layer_;
scoped_refptr<Layer> outer_viewport_scroll_layer_;
- LayerSelectionBound selection_start_;
- LayerSelectionBound selection_end_;
+ LayerSelection selection_;
SharedBitmapManager* shared_bitmap_manager_;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ TaskGraphRunner* task_graph_runner_;
ScopedPtrVector<SwapPromise> swap_promise_list_;
std::set<SwapPromiseMonitor*> swap_promise_monitor_;
+ PropertyTrees property_trees_;
+
uint32_t surface_id_namespace_;
uint32_t next_surface_sequence_;
diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h
index dca389da82d..6b305326ff9 100644
--- a/chromium/cc/trees/layer_tree_host_client.h
+++ b/chromium/cc/trees/layer_tree_host_client.h
@@ -11,6 +11,7 @@
namespace gfx {
class Vector2d;
+class Vector2dF;
}
namespace cc {
@@ -21,39 +22,47 @@ struct BeginFrameArgs;
class LayerTreeHostClient {
public:
- virtual void WillBeginMainFrame(int frame_id) = 0;
+ virtual void WillBeginMainFrame() = 0;
// Marks finishing compositing-related tasks on the main thread. In threaded
// mode, this corresponds to DidCommit().
virtual void BeginMainFrame(const BeginFrameArgs& args) = 0;
+ virtual void BeginMainFrameNotExpectedSoon() = 0;
virtual void DidBeginMainFrame() = 0;
virtual void Layout() = 0;
- virtual void ApplyViewportDeltas(const gfx::Vector2d& inner_delta,
- const gfx::Vector2d& outer_delta,
- float page_scale,
- float top_controls_delta) = 0;
+ virtual void ApplyViewportDeltas(
+ const gfx::Vector2dF& inner_delta,
+ const gfx::Vector2dF& outer_delta,
+ const gfx::Vector2dF& elastic_overscroll_delta,
+ float page_scale,
+ float top_controls_delta) = 0;
virtual void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta,
float page_scale,
float top_controls_delta) = 0;
// Request an OutputSurface from the client. When the client has one it should
- // call LayerTreeHost::SetOutputSurface. If fallback is true, it should
- // attempt to create an OutputSurface that is guaranteed to initialize
- // correctly.
- virtual void RequestNewOutputSurface(bool fallback) = 0;
+ // call LayerTreeHost::SetOutputSurface. This will result in either
+ // DidFailToInitializeOutputSurface or DidInitializeOutputSurface being
+ // called.
+ virtual void RequestNewOutputSurface() = 0;
virtual void DidInitializeOutputSurface() = 0;
+ virtual void DidFailToInitializeOutputSurface() = 0;
virtual void WillCommit() = 0;
virtual void DidCommit() = 0;
virtual void DidCommitAndDrawFrame() = 0;
virtual void DidCompleteSwapBuffers() = 0;
+ // Called when page scale animation has completed.
+ virtual void DidCompletePageScaleAnimation() = 0;
+
+ // TODO(simonhong): Makes this to pure virtual function when client
+ // implementation is ready.
+ virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) {}
+
// Requests that the client insert a rate limiting token in the shared main
// thread context's command stream that will block if the context gets too far
// ahead of the compositor's command stream. Only needed if the tree contains
// a TextureLayer that calls SetRateLimitContext(true).
virtual void RateLimitSharedMainThreadContext() {}
- // This hook is for testing.
- virtual void DidFailToInitializeOutputSurface() {}
-
protected:
virtual ~LayerTreeHostClient() {}
};
diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc
index fd15b529989..09882856e55 100644
--- a/chromium/cc/trees/layer_tree_host_common.cc
+++ b/chromium/cc/trees/layer_tree_host_common.cc
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/debug/trace_event.h"
+#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/layer.h"
@@ -14,10 +14,13 @@
#include "cc/layers/layer_iterator.h"
#include "cc/layers/render_surface.h"
#include "cc/layers/render_surface_impl.h"
-#include "cc/trees/layer_sorter.h"
+#include "cc/trees/draw_property_utils.h"
+#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_util.h"
namespace cc {
@@ -27,35 +30,30 @@ ScrollAndScaleSet::ScrollAndScaleSet()
ScrollAndScaleSet::~ScrollAndScaleSet() {}
-static void SortLayers(LayerList::iterator forst,
- LayerList::iterator end,
- void* layer_sorter) {
- NOTREACHED();
-}
-
-static void SortLayers(LayerImplList::iterator first,
- LayerImplList::iterator end,
- LayerSorter* layer_sorter) {
- DCHECK(layer_sorter);
- TRACE_EVENT0("cc", "LayerTreeHostCommon::SortLayers");
- layer_sorter->Sort(first, end);
-}
-
template <typename LayerType>
static gfx::Vector2dF GetEffectiveScrollDelta(LayerType* layer) {
- gfx::Vector2dF scroll_delta = layer->ScrollDelta();
+ // Layer's scroll offset can have an integer part and fractional part.
+ // Due to Blink's limitation, it only counter-scrolls the position-fixed
+ // layer using the integer part of Layer's scroll offset.
+ // CC scrolls the layer using the full scroll offset, so we have to
+ // add the ScrollCompensationAdjustment (fractional part of the scroll
+ // offset) to the effective scroll delta which is used to counter-scroll
+ // the position-fixed layer.
+ gfx::Vector2dF scroll_delta =
+ layer->ScrollDelta() + layer->ScrollCompensationAdjustment();
// The scroll parent's scroll delta is the amount we've scrolled on the
// compositor thread since the commit for this layer tree's source frame.
// we last reported to the main thread. I.e., it's the discrepancy between
// a scroll parent's scroll delta and offset, so we must add it here.
if (layer->scroll_parent())
- scroll_delta += layer->scroll_parent()->ScrollDelta();
+ scroll_delta += layer->scroll_parent()->ScrollDelta() +
+ layer->ScrollCompensationAdjustment();
return scroll_delta;
}
template <typename LayerType>
-static gfx::ScrollOffset GetEffectiveTotalScrollOffset(LayerType* layer) {
- gfx::ScrollOffset offset = layer->TotalScrollOffset();
+static gfx::ScrollOffset GetEffectiveCurrentScrollOffset(LayerType* layer) {
+ gfx::ScrollOffset offset = layer->CurrentScrollOffset();
// The scroll parent's total scroll offset (scroll offset + scroll delta)
// can't be used because its scroll offset has already been applied to the
// scroll children's positions by the main thread layer positioning code.
@@ -148,8 +146,8 @@ static gfx::Vector2dF ComputeChangeOfBasisTranslation(
}
enum TranslateRectDirection {
- TranslateRectDirectionToAncestor,
- TranslateRectDirectionToDescendant
+ TRANSLATE_RECT_DIRECTION_TO_ANCESTOR,
+ TRANSLATE_RECT_DIRECTION_TO_DESCENDANT
};
template <typename LayerType>
@@ -159,7 +157,7 @@ static gfx::Rect TranslateRectToTargetSpace(const LayerType& ancestor_layer,
TranslateRectDirection direction) {
gfx::Vector2dF translation = ComputeChangeOfBasisTranslation<LayerType>(
ancestor_layer, descendant_layer);
- if (direction == TranslateRectDirectionToDescendant)
+ if (direction == TRANSLATE_RECT_DIRECTION_TO_DESCENDANT)
translation.Scale(-1.f);
return gfx::ToEnclosingRect(
gfx::RectF(rect.origin() + translation, rect.size()));
@@ -198,20 +196,16 @@ static void UpdateClipRectsForClipChild(
// clip rects will want to be in its target space, not ours.
if (clip_parent == layer->clip_parent()) {
*clip_rect_in_parent_target_space = TranslateRectToTargetSpace<LayerType>(
- *clip_parent,
- *layer->parent(),
- *clip_rect_in_parent_target_space,
- TranslateRectDirectionToDescendant);
+ *clip_parent, *layer->parent(), *clip_rect_in_parent_target_space,
+ TRANSLATE_RECT_DIRECTION_TO_DESCENDANT);
} else {
// If we're being clipped by our scroll parent, we must translate through
// our common ancestor. This happens to be our parent, so it is sufficent to
// translate from our clip parent's space to the space of its ancestor (our
// parent).
- *clip_rect_in_parent_target_space =
- TranslateRectToTargetSpace<LayerType>(*layer->parent(),
- *clip_parent,
- *clip_rect_in_parent_target_space,
- TranslateRectDirectionToAncestor);
+ *clip_rect_in_parent_target_space = TranslateRectToTargetSpace<LayerType>(
+ *layer->parent(), *clip_parent, *clip_rect_in_parent_target_space,
+ TRANSLATE_RECT_DIRECTION_TO_ANCESTOR);
}
}
@@ -273,10 +267,8 @@ void UpdateAccumulatedSurfaceState(
// so we'll need to transform it before it is applied.
if (layer->clip_parent()) {
clip_rect = TranslateRectToTargetSpace<LayerType>(
- *layer->clip_parent(),
- *layer,
- clip_rect,
- TranslateRectDirectionToDescendant);
+ *layer->clip_parent(), *layer, clip_rect,
+ TRANSLATE_RECT_DIRECTION_TO_DESCENDANT);
}
target_rect.Intersect(clip_rect);
}
@@ -330,7 +322,8 @@ template <typename LayerType> static inline bool IsRootLayer(LayerType* layer) {
template <typename LayerType>
static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
return layer->Is3dSorted() && layer->parent() &&
- layer->parent()->Is3dSorted();
+ layer->parent()->Is3dSorted() &&
+ (layer->parent()->sorting_context_id() == layer->sorting_context_id());
}
template <typename LayerType>
@@ -392,7 +385,7 @@ static gfx::Rect CalculateVisibleContentRect(
gfx::Rect visible_rect_in_target_surface_space =
layer->drawable_content_rect();
- if (!layer->render_target()->render_surface()->clip_rect().IsEmpty()) {
+ if (layer->render_target()->render_surface()->is_clipped()) {
// The |layer| L has a target T which owns a surface Ts. The surface Ts
// has a target TsT.
//
@@ -550,9 +543,8 @@ static inline void SavePaintPropertiesLayer(Layer* layer) {
layer->replica_layer()->mask_layer()->SavePaintProperties();
}
-template <typename LayerType>
static bool SubtreeShouldRenderToSeparateSurface(
- LayerType* layer,
+ Layer* layer,
bool axis_aligned_with_respect_to_parent) {
//
// A layer and its descendants should render onto a new RenderSurfaceImpl if
@@ -584,6 +576,13 @@ static bool SubtreeShouldRenderToSeparateSurface(
return true;
}
+ // If the layer will use a CSS filter. In this case, the animation
+ // will start and add a filter to this layer, so it needs a surface.
+ if (layer->FilterIsAnimating()) {
+ DCHECK(!is_root);
+ return true;
+ }
+
int num_descendants_that_draw_content =
layer->NumDescendantsThatDrawContent();
@@ -682,9 +681,10 @@ static bool SubtreeShouldRenderToSeparateSurface(
// This function returns a translation matrix that can be applied on a vector
// that's in the layer's target surface coordinate, while the position offset is
// specified in some ancestor layer's coordinate.
+template <typename LayerType>
gfx::Transform ComputeSizeDeltaCompensation(
- LayerImpl* layer,
- LayerImpl* container,
+ LayerType* layer,
+ LayerType* container,
const gfx::Vector2dF& position_offset) {
gfx::Transform result_transform;
@@ -699,8 +699,8 @@ gfx::Transform ComputeSizeDeltaCompensation(
gfx::Transform target_surface_space_to_container_layer_space;
// Calculate step 1a
- LayerImpl* container_target_surface = container->render_target();
- for (LayerImpl* current_target_surface = NextTargetSurface(layer);
+ LayerType* container_target_surface = container->render_target();
+ for (LayerType* current_target_surface = NextTargetSurface(layer);
current_target_surface &&
current_target_surface != container_target_surface;
current_target_surface = NextTargetSurface(current_target_surface)) {
@@ -747,14 +747,10 @@ gfx::Transform ComputeSizeDeltaCompensation(
return result_transform;
}
+template <typename LayerType>
void ApplyPositionAdjustment(
- Layer* layer,
- Layer* container,
- const gfx::Transform& scroll_compensation,
- gfx::Transform* combined_transform) {}
-void ApplyPositionAdjustment(
- LayerImpl* layer,
- LayerImpl* container,
+ LayerType* layer,
+ LayerType* container,
const gfx::Transform& scroll_compensation,
gfx::Transform* combined_transform) {
if (!layer->position_constraint().is_fixed_position())
@@ -785,8 +781,9 @@ void ApplyPositionAdjustment(
ComputeSizeDeltaCompensation(layer, container, position_offset));
}
+template <typename LayerType>
gfx::Transform ComputeScrollCompensationForThisLayer(
- LayerImpl* scrolling_layer,
+ LayerType* scrolling_layer,
const gfx::Transform& parent_matrix,
const gfx::Vector2dF& scroll_delta) {
// For every layer that has non-zero scroll_delta, we have to compute a
@@ -824,18 +821,9 @@ gfx::Transform ComputeScrollCompensationForThisLayer(
return scroll_compensation_for_this_layer;
}
+template <typename LayerType>
gfx::Transform ComputeScrollCompensationMatrixForChildren(
- Layer* current_layer,
- const gfx::Transform& current_parent_matrix,
- const gfx::Transform& current_scroll_compensation,
- const gfx::Vector2dF& scroll_delta) {
- // The main thread (i.e. Layer) does not need to worry about scroll
- // compensation. So we can just return an identity matrix here.
- return gfx::Transform();
-}
-
-gfx::Transform ComputeScrollCompensationMatrixForChildren(
- LayerImpl* layer,
+ LayerType* layer,
const gfx::Transform& parent_matrix,
const gfx::Transform& current_scroll_compensation_matrix,
const gfx::Vector2dF& scroll_delta) {
@@ -925,11 +913,14 @@ static inline void UpdateLayerScaleDrawProperties(
LayerType* layer,
float ideal_contents_scale,
float maximum_animation_contents_scale,
+ float starting_animation_contents_scale,
float page_scale_factor,
float device_scale_factor) {
layer->draw_properties().ideal_contents_scale = ideal_contents_scale;
layer->draw_properties().maximum_animation_contents_scale =
maximum_animation_contents_scale;
+ layer->draw_properties().starting_animation_contents_scale =
+ starting_animation_contents_scale;
layer->draw_properties().page_scale_factor = page_scale_factor;
layer->draw_properties().device_scale_factor = device_scale_factor;
}
@@ -1029,9 +1020,11 @@ static inline void CalculateAnimationContentsScale(
const gfx::Transform& parent_transform,
const gfx::Transform& combined_transform,
bool* combined_is_animating_scale,
- float* combined_maximum_animation_contents_scale) {
+ float* combined_maximum_animation_contents_scale,
+ float* combined_starting_animation_contents_scale) {
*combined_is_animating_scale = false;
*combined_maximum_animation_contents_scale = 0.f;
+ *combined_starting_animation_contents_scale = 0.f;
}
static inline void CalculateAnimationContentsScale(
@@ -1041,12 +1034,14 @@ static inline void CalculateAnimationContentsScale(
const gfx::Transform& ancestor_transform,
const gfx::Transform& combined_transform,
bool* combined_is_animating_scale,
- float* combined_maximum_animation_contents_scale) {
+ float* combined_maximum_animation_contents_scale,
+ float* combined_starting_animation_contents_scale) {
if (ancestor_is_animating_scale &&
ancestor_maximum_animation_contents_scale == 0.f) {
// We've already failed to compute a maximum animated scale at an
// ancestor, so we'll continue to fail.
*combined_maximum_animation_contents_scale = 0.f;
+ *combined_starting_animation_contents_scale = 0.f;
*combined_is_animating_scale = true;
return;
}
@@ -1055,6 +1050,7 @@ static inline void CalculateAnimationContentsScale(
// Computing maximum animated scale in the presence of
// non-scale/translation transforms isn't supported.
*combined_maximum_animation_contents_scale = 0.f;
+ *combined_starting_animation_contents_scale = 0.f;
*combined_is_animating_scale = true;
return;
}
@@ -1068,6 +1064,7 @@ static inline void CalculateAnimationContentsScale(
if (!layer_is_animating_scale && !ancestor_is_animating_scale) {
*combined_maximum_animation_contents_scale = 0.f;
+ *combined_starting_animation_contents_scale = 0.f;
*combined_is_animating_scale = false;
return;
}
@@ -1079,6 +1076,7 @@ static inline void CalculateAnimationContentsScale(
// a scale of 100.
if (layer_is_animating_scale && ancestor_is_animating_scale) {
*combined_maximum_animation_contents_scale = 0.f;
+ *combined_starting_animation_contents_scale = 0.f;
*combined_is_animating_scale = true;
return;
}
@@ -1092,32 +1090,32 @@ static inline void CalculateAnimationContentsScale(
*combined_maximum_animation_contents_scale =
ancestor_maximum_animation_contents_scale *
std::max(layer_transform_scales.x(), layer_transform_scales.y());
+ *combined_starting_animation_contents_scale =
+ *combined_maximum_animation_contents_scale;
return;
}
float layer_maximum_animated_scale = 0.f;
+ float layer_start_animated_scale = 0.f;
if (!layer->layer_animation_controller()->MaximumTargetScale(
&layer_maximum_animated_scale)) {
*combined_maximum_animation_contents_scale = 0.f;
return;
}
+ if (!layer->layer_animation_controller()->AnimationStartScale(
+ &layer_start_animated_scale)) {
+ *combined_starting_animation_contents_scale = 0.f;
+ return;
+ }
+
gfx::Vector2dF ancestor_transform_scales =
MathUtil::ComputeTransform2dScaleComponents(ancestor_transform, 0.f);
- *combined_maximum_animation_contents_scale =
- layer_maximum_animated_scale *
+ float max_scale_xy =
std::max(ancestor_transform_scales.x(), ancestor_transform_scales.y());
-}
-
-template <typename LayerType>
-static inline typename LayerType::RenderSurfaceType* CreateOrReuseRenderSurface(
- LayerType* layer) {
- if (!layer->render_surface()) {
- layer->CreateRenderSurface();
- return layer->render_surface();
- }
-
- layer->render_surface()->ClearLayerLists();
- return layer->render_surface();
+ *combined_maximum_animation_contents_scale =
+ layer_maximum_animated_scale * max_scale_xy;
+ *combined_starting_animation_contents_scale =
+ layer_start_animated_scale * max_scale_xy;
}
template <typename LayerTypePtr>
@@ -1126,6 +1124,8 @@ static inline void MarkLayerWithRenderSurfaceLayerListId(
int current_render_surface_layer_list_id) {
layer->draw_properties().last_drawn_render_surface_layer_list_id =
current_render_surface_layer_list_id;
+ layer->draw_properties().layer_or_descendant_is_drawn =
+ !!current_render_surface_layer_list_id;
}
template <typename LayerTypePtr>
@@ -1184,34 +1184,134 @@ static inline void RemoveSurfaceForEarlyExit(
}
struct PreCalculateMetaInformationRecursiveData {
- bool layer_or_descendant_has_copy_request;
- bool layer_or_descendant_has_input_handler;
int num_unclipped_descendants;
+ int num_layer_or_descendants_with_copy_request;
+ int num_layer_or_descendants_with_input_handler;
PreCalculateMetaInformationRecursiveData()
- : layer_or_descendant_has_copy_request(false),
- layer_or_descendant_has_input_handler(false),
- num_unclipped_descendants(0) {}
+ : num_unclipped_descendants(0),
+ num_layer_or_descendants_with_copy_request(0),
+ num_layer_or_descendants_with_input_handler(0) {}
void Merge(const PreCalculateMetaInformationRecursiveData& data) {
- layer_or_descendant_has_copy_request |=
- data.layer_or_descendant_has_copy_request;
- layer_or_descendant_has_input_handler |=
- data.layer_or_descendant_has_input_handler;
- num_unclipped_descendants +=
- data.num_unclipped_descendants;
+ num_layer_or_descendants_with_copy_request +=
+ data.num_layer_or_descendants_with_copy_request;
+ num_layer_or_descendants_with_input_handler +=
+ data.num_layer_or_descendants_with_input_handler;
+ num_unclipped_descendants += data.num_unclipped_descendants;
}
};
-// Recursively walks the layer tree to compute any information that is needed
-// before doing the main recursion.
-template <typename LayerType>
-static void PreCalculateMetaInformation(
- LayerType* layer,
+static void ValidateRenderSurface(LayerImpl* layer) {
+ // This test verifies that there are no cases where a LayerImpl needs
+ // a render surface, but doesn't have one.
+ if (layer->render_surface())
+ return;
+
+ DCHECK(layer->filters().IsEmpty()) << "layer: " << layer->id();
+ DCHECK(layer->background_filters().IsEmpty()) << "layer: " << layer->id();
+ DCHECK(!layer->mask_layer()) << "layer: " << layer->id();
+ DCHECK(!layer->replica_layer()) << "layer: " << layer->id();
+ DCHECK(!IsRootLayer(layer)) << "layer: " << layer->id();
+ DCHECK(!layer->is_root_for_isolated_group()) << "layer: " << layer->id();
+ DCHECK(!layer->HasCopyRequest()) << "layer: " << layer->id();
+}
+
+static void ValidateRenderSurface(Layer* layer) {
+}
+
+static void ResetDrawProperties(Layer* layer) {
+ layer->draw_properties().sorted_for_recursion = false;
+ layer->draw_properties().has_child_with_a_scroll_parent = false;
+ layer->draw_properties().layer_or_descendant_is_drawn = false;
+ layer->draw_properties().visited = false;
+ if (!HasInvertibleOrAnimatedTransform(layer)) {
+ // Layers with singular transforms should not be drawn, the whole subtree
+ // can be skipped.
+ return;
+ }
+
+ for (size_t i = 0; i < layer->children().size(); ++i) {
+ Layer* child_layer = layer->child_at(i);
+ if (child_layer->scroll_parent())
+ layer->draw_properties().has_child_with_a_scroll_parent = true;
+ ResetDrawProperties(child_layer);
+ }
+}
+
+static void ResetDrawProperties(LayerImpl* layer) {
+}
+
+static bool IsMetaInformationRecomputationNeeded(Layer* layer) {
+ return layer->layer_tree_host()->needs_meta_info_recomputation();
+}
+
+// Recursively walks the layer tree(if needed) to compute any information
+// that is needed before doing the main recursion.
+static void PreCalculateMetaInformationInternal(
+ Layer* layer,
+ PreCalculateMetaInformationRecursiveData* recursive_data) {
+ ValidateRenderSurface(layer);
+ if (!HasInvertibleOrAnimatedTransform(layer)) {
+ // Layers with singular transforms should not be drawn, the whole subtree
+ // can be skipped.
+ return;
+ }
+
+ if (!IsMetaInformationRecomputationNeeded(layer)) {
+ DCHECK(IsRootLayer(layer));
+ return;
+ }
+
+ if (layer->clip_parent())
+ recursive_data->num_unclipped_descendants++;
+
+ for (size_t i = 0; i < layer->children().size(); ++i) {
+ Layer* child_layer = layer->child_at(i);
+
+ PreCalculateMetaInformationRecursiveData data_for_child;
+ PreCalculateMetaInformationInternal(child_layer, &data_for_child);
+
+ recursive_data->Merge(data_for_child);
+ }
+
+ if (layer->clip_children()) {
+ int num_clip_children = layer->clip_children()->size();
+ DCHECK_GE(recursive_data->num_unclipped_descendants, num_clip_children);
+ recursive_data->num_unclipped_descendants -= num_clip_children;
+ }
+
+ if (layer->HasCopyRequest())
+ recursive_data->num_layer_or_descendants_with_copy_request++;
+
+ if (!layer->touch_event_handler_region().IsEmpty() ||
+ layer->have_wheel_event_handlers())
+ recursive_data->num_layer_or_descendants_with_input_handler++;
+
+ layer->draw_properties().num_unclipped_descendants =
+ recursive_data->num_unclipped_descendants;
+ layer->draw_properties().layer_or_descendant_has_copy_request =
+ (recursive_data->num_layer_or_descendants_with_copy_request != 0);
+ layer->draw_properties().layer_or_descendant_has_input_handler =
+ (recursive_data->num_layer_or_descendants_with_input_handler != 0);
+ layer->set_num_layer_or_descandant_with_copy_request(
+ recursive_data->num_layer_or_descendants_with_copy_request);
+ layer->set_num_layer_or_descandant_with_input_handler(
+ recursive_data->num_layer_or_descendants_with_input_handler);
+
+ if (IsRootLayer(layer))
+ layer->layer_tree_host()->SetNeedsMetaInfoRecomputation(false);
+}
+
+static void PreCalculateMetaInformationInternal(
+ LayerImpl* layer,
PreCalculateMetaInformationRecursiveData* recursive_data) {
+ ValidateRenderSurface(layer);
layer->draw_properties().sorted_for_recursion = false;
layer->draw_properties().has_child_with_a_scroll_parent = false;
+ layer->draw_properties().layer_or_descendant_is_drawn = false;
+ layer->draw_properties().visited = false;
if (!HasInvertibleOrAnimatedTransform(layer)) {
// Layers with singular transforms should not be drawn, the whole subtree
@@ -1223,11 +1323,10 @@ static void PreCalculateMetaInformation(
recursive_data->num_unclipped_descendants++;
for (size_t i = 0; i < layer->children().size(); ++i) {
- LayerType* child_layer =
- LayerTreeHostCommon::get_layer_as_raw_ptr(layer->children(), i);
+ LayerImpl* child_layer = layer->child_at(i);
PreCalculateMetaInformationRecursiveData data_for_child;
- PreCalculateMetaInformation(child_layer, &data_for_child);
+ PreCalculateMetaInformationInternal(child_layer, &data_for_child);
if (child_layer->scroll_parent())
layer->draw_properties().has_child_with_a_scroll_parent = true;
@@ -1241,34 +1340,36 @@ static void PreCalculateMetaInformation(
}
if (layer->HasCopyRequest())
- recursive_data->layer_or_descendant_has_copy_request = true;
+ recursive_data->num_layer_or_descendants_with_copy_request++;
if (!layer->touch_event_handler_region().IsEmpty() ||
layer->have_wheel_event_handlers())
- recursive_data->layer_or_descendant_has_input_handler = true;
+ recursive_data->num_layer_or_descendants_with_input_handler++;
layer->draw_properties().num_unclipped_descendants =
recursive_data->num_unclipped_descendants;
layer->draw_properties().layer_or_descendant_has_copy_request =
- recursive_data->layer_or_descendant_has_copy_request;
+ (recursive_data->num_layer_or_descendants_with_copy_request != 0);
layer->draw_properties().layer_or_descendant_has_input_handler =
- recursive_data->layer_or_descendant_has_input_handler;
+ (recursive_data->num_layer_or_descendants_with_input_handler != 0);
}
-static void RoundTranslationComponents(gfx::Transform* transform) {
- transform->matrix().set(0, 3, MathUtil::Round(transform->matrix().get(0, 3)));
- transform->matrix().set(1, 3, MathUtil::Round(transform->matrix().get(1, 3)));
+void LayerTreeHostCommon::PreCalculateMetaInformation(Layer* root_layer) {
+ PreCalculateMetaInformationRecursiveData recursive_data;
+ PreCalculateMetaInformationInternal(root_layer, &recursive_data);
}
template <typename LayerType>
struct SubtreeGlobals {
- LayerSorter* layer_sorter;
int max_texture_size;
float device_scale_factor;
float page_scale_factor;
const LayerType* page_scale_application_layer;
+ gfx::Vector2dF elastic_overscroll;
+ const LayerType* elastic_overscroll_application_layer;
bool can_adjust_raster_scales;
bool can_render_to_separate_surface;
+ bool layers_always_allowed_lcd_text;
};
template<typename LayerType>
@@ -1417,6 +1518,14 @@ static LayerImplList* GetLayerListForSorting(LayerImplList* layer_list) {
return layer_list;
}
+static inline gfx::Vector2d BoundsDelta(Layer* layer) {
+ return gfx::Vector2d();
+}
+
+static inline gfx::Vector2d BoundsDelta(LayerImpl* layer) {
+ return gfx::ToCeiledVector2d(layer->bounds_delta());
+}
+
template <typename LayerType, typename GetIndexAndCountType>
static void SortLayerListContributions(
const LayerType& parent,
@@ -1573,6 +1682,9 @@ static void CalculateDrawPropertiesInternal(
DCHECK(globals.page_scale_application_layer ||
(globals.page_scale_factor == 1.f));
+ CHECK(!layer->draw_properties().visited);
+ layer->draw_properties().visited = true;
+
DataForRecursion<LayerType> data_for_children;
typename LayerType::RenderSurfaceType*
nearest_occlusion_immune_ancestor_surface =
@@ -1595,6 +1707,7 @@ static void CalculateDrawPropertiesInternal(
if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_drawn)) {
if (layer->render_surface())
layer->ClearRenderSurfaceLayerList();
+ layer->draw_properties().render_target = nullptr;
return;
}
@@ -1647,7 +1760,7 @@ static void CalculateDrawPropertiesInternal(
layer->parent()->screen_space_transform_is_animating();
}
gfx::Point3F transform_origin = layer->transform_origin();
- gfx::ScrollOffset scroll_offset = GetEffectiveTotalScrollOffset(layer);
+ gfx::ScrollOffset scroll_offset = GetEffectiveCurrentScrollOffset(layer);
gfx::PointF position =
layer->position() - ScrollOffsetToVector2dF(scroll_offset);
gfx::Transform combined_transform = data_from_ancestor.parent_matrix;
@@ -1673,7 +1786,7 @@ static void CalculateDrawPropertiesInternal(
// blurriness. To avoid side-effects, do this only if the transform is
// simple.
gfx::Vector2dF previous_translation = combined_transform.To2dTranslation();
- RoundTranslationComponents(&combined_transform);
+ combined_transform.RoundTranslationComponents();
gfx::Vector2dF current_translation = combined_transform.To2dTranslation();
// This rounding changes the scroll delta, and so must be included
@@ -1696,15 +1809,15 @@ static void CalculateDrawPropertiesInternal(
bool combined_is_animating_scale = false;
float combined_maximum_animation_contents_scale = 0.f;
+ float combined_starting_animation_contents_scale = 0.f;
if (globals.can_adjust_raster_scales) {
CalculateAnimationContentsScale(
- layer,
- data_from_ancestor.ancestor_is_animating_scale,
+ layer, data_from_ancestor.ancestor_is_animating_scale,
data_from_ancestor.maximum_animation_contents_scale,
- data_from_ancestor.parent_matrix,
- combined_transform,
+ data_from_ancestor.parent_matrix, combined_transform,
&combined_is_animating_scale,
- &combined_maximum_animation_contents_scale);
+ &combined_maximum_animation_contents_scale,
+ &combined_starting_animation_contents_scale);
}
data_for_children.ancestor_is_animating_scale = combined_is_animating_scale;
data_for_children.maximum_animation_contents_scale =
@@ -1736,9 +1849,8 @@ static void CalculateDrawPropertiesInternal(
animating_transform_to_screen);
UpdateLayerScaleDrawProperties(
- layer,
- ideal_contents_scale,
- combined_maximum_animation_contents_scale,
+ layer, ideal_contents_scale, combined_maximum_animation_contents_scale,
+ combined_starting_animation_contents_scale,
data_from_ancestor.in_subtree_of_page_scale_application_layer
? globals.page_scale_factor
: 1.f,
@@ -1747,9 +1859,9 @@ static void CalculateDrawPropertiesInternal(
LayerType* mask_layer = layer->mask_layer();
if (mask_layer) {
UpdateLayerScaleDrawProperties(
- mask_layer,
- ideal_contents_scale,
+ mask_layer, ideal_contents_scale,
combined_maximum_animation_contents_scale,
+ combined_starting_animation_contents_scale,
data_from_ancestor.in_subtree_of_page_scale_application_layer
? globals.page_scale_factor
: 1.f,
@@ -1760,9 +1872,9 @@ static void CalculateDrawPropertiesInternal(
layer->replica_layer() ? layer->replica_layer()->mask_layer() : NULL;
if (replica_mask_layer) {
UpdateLayerScaleDrawProperties(
- replica_mask_layer,
- ideal_contents_scale,
+ replica_mask_layer, ideal_contents_scale,
combined_maximum_animation_contents_scale,
+ combined_starting_animation_contents_scale,
data_from_ancestor.in_subtree_of_page_scale_application_layer
? globals.page_scale_factor
: 1.f,
@@ -1782,24 +1894,22 @@ static void CalculateDrawPropertiesInternal(
// layer's "screen space" and local content space.
layer_draw_properties.screen_space_transform =
data_from_ancestor.full_hierarchy_matrix;
- if (layer->should_flatten_transform())
- layer_draw_properties.screen_space_transform.FlattenTo2d();
layer_draw_properties.screen_space_transform.PreconcatTransform
(layer_draw_properties.target_space_transform);
- // Adjusting text AA method during animation may cause repaints, which in-turn
- // causes jank.
- bool adjust_text_aa =
- !animating_opacity_to_screen && !animating_transform_to_screen;
- // To avoid color fringing, LCD text should only be used on opaque layers with
- // just integral translation.
- bool layer_can_use_lcd_text =
- data_from_ancestor.subtree_can_use_lcd_text &&
- accumulated_draw_opacity == 1.f &&
- layer_draw_properties.target_space_transform.
- IsIdentityOrIntegerTranslation();
-
- gfx::Rect content_rect(layer->content_bounds());
+ bool layer_can_use_lcd_text = true;
+ bool subtree_can_use_lcd_text = true;
+ if (!globals.layers_always_allowed_lcd_text) {
+ // To avoid color fringing, LCD text should only be used on opaque layers
+ // with just integral translation.
+ subtree_can_use_lcd_text = data_from_ancestor.subtree_can_use_lcd_text &&
+ accumulated_draw_opacity == 1.f &&
+ layer_draw_properties.target_space_transform
+ .IsIdentityOrIntegerTranslation();
+ // Also disable LCD text locally for non-opaque content.
+ layer_can_use_lcd_text = subtree_can_use_lcd_text &&
+ layer->contents_opaque();
+ }
// full_hierarchy_matrix is the matrix that transforms objects between screen
// space (except projection matrix) and the most recent RenderSurfaceImpl's
@@ -1808,33 +1918,26 @@ static void CalculateDrawPropertiesInternal(
data_for_children.full_hierarchy_matrix =
data_from_ancestor.full_hierarchy_matrix;
- // If the subtree will scale layer contents by the transform hierarchy, then
- // we should scale things into the render surface by the transform hierarchy
- // to take advantage of that.
- gfx::Vector2dF render_surface_sublayer_scale =
- globals.can_adjust_raster_scales
- ? combined_transform_scales
- : gfx::Vector2dF(layer_scale_factors, layer_scale_factors);
+ bool render_to_separate_surface =
+ IsRootLayer(layer) ||
+ (globals.can_render_to_separate_surface && layer->render_surface());
- bool render_to_separate_surface;
- if (globals.can_render_to_separate_surface) {
- render_to_separate_surface = SubtreeShouldRenderToSeparateSurface(
- layer, combined_transform.Preserves2dAxisAlignment());
- } else {
- render_to_separate_surface = IsRootLayer(layer);
- }
if (render_to_separate_surface) {
+ DCHECK(layer->render_surface());
// Check back-face visibility before continuing with this surface and its
// subtree
if (!layer->double_sided() && TransformToParentIsKnown(layer) &&
IsSurfaceBackFaceVisible(layer, combined_transform)) {
layer->ClearRenderSurfaceLayerList();
+ layer->draw_properties().render_target = nullptr;
return;
}
typename LayerType::RenderSurfaceType* render_surface =
- CreateOrReuseRenderSurface(layer);
+ layer->render_surface();
+ layer->ClearRenderSurfaceLayerList();
+ layer_draw_properties.render_target = layer;
if (IsRootLayer(layer)) {
// The root layer's render surface size is predetermined and so the root
// layer can't directly support non-identity transforms. It should just
@@ -1849,17 +1952,19 @@ static void CalculateDrawPropertiesInternal(
// space which we do not want; so here we use the combined_transform
// instead of the draw_transform. However, we do need to add a different
// scale factor that accounts for the surface's pixel dimensions.
- combined_transform.Scale(1.0 / render_surface_sublayer_scale.x(),
- 1.0 / render_surface_sublayer_scale.y());
- render_surface->SetDrawTransform(combined_transform);
+ // Remove the combined_transform scale from the draw transform.
+ gfx::Transform draw_transform = combined_transform;
+ draw_transform.Scale(1.0 / combined_transform_scales.x(),
+ 1.0 / combined_transform_scales.y());
+ render_surface->SetDrawTransform(draw_transform);
// The owning layer's transform was re-parented by the surface, so the
// layer's new draw_transform only needs to scale the layer to surface
// space.
layer_draw_properties.target_space_transform.MakeIdentity();
- layer_draw_properties.target_space_transform.
- Scale(render_surface_sublayer_scale.x() / layer->contents_scale_x(),
- render_surface_sublayer_scale.y() / layer->contents_scale_y());
+ layer_draw_properties.target_space_transform.Scale(
+ combined_transform_scales.x() / layer->contents_scale_x(),
+ combined_transform_scales.y() / layer->contents_scale_y());
// Inside the surface's subtree, we scale everything to the owning layer's
// scale. The sublayer matrix transforms layer rects into target surface
@@ -1868,8 +1973,8 @@ static void CalculateDrawPropertiesInternal(
// but we apply it explicitly to the owning layer and the remainder of the
// subtree independently.
DCHECK(data_for_children.parent_matrix.IsIdentity());
- data_for_children.parent_matrix.Scale(render_surface_sublayer_scale.x(),
- render_surface_sublayer_scale.y());
+ data_for_children.parent_matrix.Scale(combined_transform_scales.x(),
+ combined_transform_scales.y());
// Even if the |layer_is_drawn|, it only contributes to a drawn surface
// when the |layer_is_visible|.
@@ -1883,6 +1988,7 @@ static void CalculateDrawPropertiesInternal(
render_surface->SetDrawOpacityIsAnimating(animating_opacity_to_target);
animating_opacity_to_target = false;
layer_draw_properties.opacity = 1.f;
+ layer_draw_properties.blend_mode = SkXfermode::kSrcOver_Mode;
layer_draw_properties.opacity_is_animating = animating_opacity_to_target;
layer_draw_properties.screen_space_opacity_is_animating =
animating_opacity_to_screen;
@@ -1902,6 +2008,10 @@ static void CalculateDrawPropertiesInternal(
data_for_children.full_hierarchy_matrix.PreconcatTransform(
render_surface->draw_transform());
+ // A render surface inherently acts as a flattening point for the content of
+ // its descendants.
+ data_for_children.full_hierarchy_matrix.FlattenTo2d();
+
if (layer->mask_layer()) {
DrawProperties<LayerType>& mask_layer_draw_properties =
layer->mask_layer()->draw_properties();
@@ -1994,7 +2104,7 @@ static void CalculateDrawPropertiesInternal(
// If the new render surface is drawn translucent or with a non-integral
// translation then the subtree that gets drawn on this render surface
// cannot use LCD text.
- data_for_children.subtree_can_use_lcd_text = layer_can_use_lcd_text;
+ data_for_children.subtree_can_use_lcd_text = subtree_can_use_lcd_text;
render_surface_layer_list->push_back(layer);
} else {
@@ -2007,13 +2117,12 @@ static void CalculateDrawPropertiesInternal(
layer_draw_properties.screen_space_transform_is_animating =
animating_transform_to_screen;
layer_draw_properties.opacity = accumulated_draw_opacity;
+ layer_draw_properties.blend_mode = layer->blend_mode();
layer_draw_properties.opacity_is_animating = animating_opacity_to_target;
layer_draw_properties.screen_space_opacity_is_animating =
animating_opacity_to_screen;
data_for_children.parent_matrix = combined_transform;
- layer->ClearRenderSurface();
-
// Layers without render_surfaces directly inherit the ancestor's clip
// status.
layer_or_ancestor_clips_descendants = ancestor_clips_subtree;
@@ -2032,15 +2141,28 @@ static void CalculateDrawPropertiesInternal(
layer_draw_properties.render_target = layer->parent()->render_target();
}
- if (adjust_text_aa)
- layer_draw_properties.can_use_lcd_text = layer_can_use_lcd_text;
+ layer_draw_properties.can_use_lcd_text = layer_can_use_lcd_text;
+
+ gfx::Size content_size_affected_by_delta(layer->content_bounds());
- gfx::Rect rect_in_target_space =
- MathUtil::MapEnclosingClippedRect(layer->draw_transform(), content_rect);
+ // Non-zero BoundsDelta imply the contents_scale of 1.0
+ // because BoundsDela is only set on Android where
+ // ContentScalingLayer is never used.
+ DCHECK_IMPLIES(!BoundsDelta(layer).IsZero(),
+ (layer->contents_scale_x() == 1.0 &&
+ layer->contents_scale_y() == 1.0));
+
+ // Thus we can omit contents scale in the following calculation.
+ gfx::Vector2d bounds_delta = BoundsDelta(layer);
+ content_size_affected_by_delta.Enlarge(bounds_delta.x(), bounds_delta.y());
+
+ gfx::Rect rect_in_target_space = MathUtil::MapEnclosingClippedRect(
+ layer->draw_transform(),
+ gfx::Rect(content_size_affected_by_delta));
if (LayerClipsSubtree(layer)) {
layer_or_ancestor_clips_descendants = true;
- if (ancestor_clips_subtree && !layer->render_surface()) {
+ if (ancestor_clips_subtree && !render_to_separate_surface) {
// A layer without render surface shares the same target as its ancestor.
clip_rect_in_target_space =
ancestor_clip_rect_in_target_space;
@@ -2065,8 +2187,8 @@ static void CalculateDrawPropertiesInternal(
}
typename LayerType::LayerListType& descendants =
- (layer->render_surface() ? layer->render_surface()->layer_list()
- : *layer_list);
+ (render_to_separate_surface ? layer->render_surface()->layer_list()
+ : *layer_list);
// Any layers that are appended after this point are in the layer's subtree
// and should be included in the sorting process.
@@ -2091,6 +2213,10 @@ static void CalculateDrawPropertiesInternal(
globals.page_scale_factor);
data_for_children.in_subtree_of_page_scale_application_layer = true;
}
+ if (layer == globals.elastic_overscroll_application_layer) {
+ data_for_children.parent_matrix.Translate(
+ -globals.elastic_overscroll.x(), -globals.elastic_overscroll.y());
+ }
// Flatten to 2D if the layer doesn't preserve 3D.
if (layer->should_flatten_transform())
@@ -2144,7 +2270,8 @@ static void CalculateDrawPropertiesInternal(
&descendants,
accumulated_surface_state,
current_render_surface_layer_list_id);
- if (child->render_surface() &&
+ // If the child is its own render target, then it has a render surface.
+ if (child->render_target() == child &&
!child->render_surface()->layer_list().empty() &&
!child->render_surface()->content_rect().IsEmpty()) {
// This child will contribute its render surface, which means
@@ -2162,6 +2289,8 @@ static void CalculateDrawPropertiesInternal(
render_surface_layer_list->size() -
child->draw_properties()
.index_of_first_render_surface_layer_list_addition;
+ layer_draw_properties.layer_or_descendant_is_drawn |=
+ child->draw_properties().layer_or_descendant_is_drawn;
}
// Add the unsorted layer list contributions, if necessary.
@@ -2183,12 +2312,12 @@ static void CalculateDrawPropertiesInternal(
// target surface space).
gfx::Rect local_drawable_content_rect_of_subtree =
accumulated_surface_state->back().drawable_content_rect;
- if (layer->render_surface()) {
+ if (render_to_separate_surface) {
DCHECK(accumulated_surface_state->back().render_target == layer);
accumulated_surface_state->pop_back();
}
- if (layer->render_surface() && !IsRootLayer(layer) &&
+ if (render_to_separate_surface && !IsRootLayer(layer) &&
layer->render_surface()->layer_list().empty()) {
RemoveSurfaceForEarlyExit(layer, render_surface_layer_list);
return;
@@ -2214,10 +2343,10 @@ static void CalculateDrawPropertiesInternal(
// one.
if (IsRootLayer(layer)) {
// The root layer's surface's content_rect is always the entire viewport.
- DCHECK(layer->render_surface());
+ DCHECK(render_to_separate_surface);
layer->render_surface()->SetContentRect(
ancestor_clip_rect_in_target_space);
- } else if (layer->render_surface()) {
+ } else if (render_to_separate_surface) {
typename LayerType::RenderSurfaceType* render_surface =
layer->render_surface();
gfx::Rect clipped_content_rect = local_drawable_content_rect_of_subtree;
@@ -2268,14 +2397,14 @@ static void CalculateDrawPropertiesInternal(
// surface's subtree into layer space.
gfx::Transform screen_space_transform = layer->screen_space_transform();
screen_space_transform.Scale(
- layer->contents_scale_x() / render_surface_sublayer_scale.x(),
- layer->contents_scale_y() / render_surface_sublayer_scale.y());
+ layer->contents_scale_x() / combined_transform_scales.x(),
+ layer->contents_scale_y() / combined_transform_scales.y());
render_surface->SetScreenSpaceTransform(screen_space_transform);
if (layer->replica_layer()) {
gfx::Transform surface_origin_to_replica_origin_transform;
surface_origin_to_replica_origin_transform.Scale(
- render_surface_sublayer_scale.x(), render_surface_sublayer_scale.y());
+ combined_transform_scales.x(), combined_transform_scales.y());
surface_origin_to_replica_origin_transform.Translate(
layer->replica_layer()->position().x() +
layer->replica_layer()->transform_origin().x(),
@@ -2287,8 +2416,8 @@ static void CalculateDrawPropertiesInternal(
-layer->replica_layer()->transform_origin().x(),
-layer->replica_layer()->transform_origin().y());
surface_origin_to_replica_origin_transform.Scale(
- 1.0 / render_surface_sublayer_scale.x(),
- 1.0 / render_surface_sublayer_scale.y());
+ 1.0 / combined_transform_scales.x(),
+ 1.0 / combined_transform_scales.y());
// Compute the replica's "originTransform" that maps from the replica's
// origin space to the target surface origin space.
@@ -2311,21 +2440,10 @@ static void CalculateDrawPropertiesInternal(
// If neither this layer nor any of its children were added, early out.
if (sorting_start_index == descendants.size()) {
- DCHECK(!layer->render_surface() || IsRootLayer(layer));
+ DCHECK(!render_to_separate_surface || IsRootLayer(layer));
return;
}
- // If preserves-3d then sort all the descendants in 3D so that they can be
- // drawn from back to front. If the preserves-3d property is also set on the
- // parent then skip the sorting as the parent will sort all the descendants
- // anyway.
- if (globals.layer_sorter && descendants.size() && layer->Is3dSorted() &&
- !LayerIsInExisting3DRenderingContext(layer)) {
- SortLayers(descendants.begin() + sorting_start_index,
- descendants.end(),
- globals.layer_sorter);
- }
-
UpdateAccumulatedSurfaceState<LayerType>(
layer, local_drawable_content_rect_of_subtree, accumulated_surface_state);
@@ -2363,15 +2481,19 @@ static void ProcessCalcDrawPropsInputs(
scaled_device_transform.Scale(inputs.device_scale_factor,
inputs.device_scale_factor);
- globals->layer_sorter = NULL;
globals->max_texture_size = inputs.max_texture_size;
globals->device_scale_factor =
inputs.device_scale_factor * device_transform_scale;
globals->page_scale_factor = inputs.page_scale_factor;
globals->page_scale_application_layer = inputs.page_scale_application_layer;
+ globals->elastic_overscroll = inputs.elastic_overscroll;
+ globals->elastic_overscroll_application_layer =
+ inputs.elastic_overscroll_application_layer;
globals->can_render_to_separate_surface =
inputs.can_render_to_separate_surface;
globals->can_adjust_raster_scales = inputs.can_adjust_raster_scales;
+ globals->layers_always_allowed_lcd_text =
+ inputs.layers_always_allowed_lcd_text;
data_for_recursion->parent_matrix = scaled_device_transform;
data_for_recursion->full_hierarchy_matrix = identity_matrix;
@@ -2389,24 +2511,216 @@ static void ProcessCalcDrawPropsInputs(
data_for_recursion->subtree_is_visible_from_ancestor = true;
}
-void LayerTreeHostCommon::CalculateDrawProperties(
- CalcDrawPropsMainInputs* inputs) {
- LayerList dummy_layer_list;
- SubtreeGlobals<Layer> globals;
- DataForRecursion<Layer> data_for_recursion;
- ProcessCalcDrawPropsInputs(*inputs, &globals, &data_for_recursion);
+void LayerTreeHostCommon::UpdateRenderSurface(
+ Layer* layer,
+ bool can_render_to_separate_surface,
+ gfx::Transform* transform,
+ bool* draw_transform_is_axis_aligned) {
+ bool preserves_2d_axis_alignment =
+ transform->Preserves2dAxisAlignment() && *draw_transform_is_axis_aligned;
+ if (IsRootLayer(layer) || (can_render_to_separate_surface &&
+ SubtreeShouldRenderToSeparateSurface(
+ layer, preserves_2d_axis_alignment))) {
+ // We reset the transform here so that any axis-changing transforms
+ // will now be relative to this RenderSurface.
+ transform->MakeIdentity();
+ *draw_transform_is_axis_aligned = true;
+ if (!layer->render_surface()) {
+ layer->CreateRenderSurface();
+ }
+ layer->SetHasRenderSurface(true);
+ return;
+ }
+ layer->SetHasRenderSurface(false);
+ if (layer->render_surface())
+ layer->ClearRenderSurface();
+}
+
+void LayerTreeHostCommon::UpdateRenderSurfaces(
+ Layer* layer,
+ bool can_render_to_separate_surface,
+ const gfx::Transform& parent_transform,
+ bool draw_transform_is_axis_aligned) {
+ gfx::Transform transform_for_children = layer->transform();
+ transform_for_children *= parent_transform;
+ draw_transform_is_axis_aligned &= layer->AnimationsPreserveAxisAlignment();
+ UpdateRenderSurface(layer, can_render_to_separate_surface,
+ &transform_for_children, &draw_transform_is_axis_aligned);
+
+ for (size_t i = 0; i < layer->children().size(); ++i) {
+ UpdateRenderSurfaces(layer->children()[i].get(),
+ can_render_to_separate_surface, transform_for_children,
+ draw_transform_is_axis_aligned);
+ }
+}
+
+static bool ApproximatelyEqual(const gfx::Rect& r1, const gfx::Rect& r2) {
+ // TODO(vollick): This tolerance should be lower: crbug.com/471786
+ static const int tolerance = 3;
+
+ if (r1.IsEmpty())
+ return std::min(r2.width(), r2.height()) < tolerance;
+
+ if (r2.IsEmpty())
+ return std::min(r1.width(), r1.height()) < tolerance;
+
+ return std::abs(r1.x() - r2.x()) <= tolerance &&
+ std::abs(r1.y() - r2.y()) <= tolerance &&
+ std::abs(r1.right() - r2.right()) <= tolerance &&
+ std::abs(r1.bottom() - r2.bottom()) <= tolerance;
+}
+
+static bool ApproximatelyEqual(const gfx::Transform& a,
+ const gfx::Transform& b) {
+ static const float component_tolerance = 0.1f;
+
+ // We may have a larger discrepancy in the scroll components due to snapping
+ // (floating point error might round the other way).
+ static const float translation_tolerance = 1.f;
+
+ for (int row = 0; row < 4; row++) {
+ for (int col = 0; col < 4; col++) {
+ const float delta =
+ std::abs(a.matrix().get(row, col) - b.matrix().get(row, col));
+ const float tolerance =
+ col == 3 && row < 3 ? translation_tolerance : component_tolerance;
+ if (delta > tolerance)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void VerifyPropertyTreeValues(
+ LayerTreeHostCommon::CalcDrawPropsMainInputs* inputs) {
+ LayerIterator<Layer> it, end;
+ for (it = LayerIterator<Layer>::Begin(inputs->render_surface_layer_list),
+ end = LayerIterator<Layer>::End(inputs->render_surface_layer_list);
+ it != end; ++it) {
+ Layer* current_layer = *it;
+ if (!it.represents_itself() || !current_layer->DrawsContent())
+ continue;
+
+ const bool visible_rects_match =
+ ApproximatelyEqual(current_layer->visible_content_rect(),
+ current_layer->visible_rect_from_property_trees());
+ CHECK(visible_rects_match)
+ << "expected: " << current_layer->visible_content_rect().ToString()
+ << " actual: "
+ << current_layer->visible_rect_from_property_trees().ToString();
+
+ const bool draw_transforms_match = ApproximatelyEqual(
+ current_layer->draw_transform(),
+ DrawTransformFromPropertyTrees(current_layer,
+ inputs->property_trees->transform_tree));
+ CHECK(draw_transforms_match)
+ << "expected: " << current_layer->draw_transform().ToString()
+ << " actual: "
+ << DrawTransformFromPropertyTrees(
+ current_layer, inputs->property_trees->transform_tree)
+ .ToString();
+
+ const bool draw_opacities_match =
+ current_layer->draw_opacity() ==
+ DrawOpacityFromPropertyTrees(current_layer,
+ inputs->property_trees->opacity_tree);
+ CHECK(draw_opacities_match)
+ << "expected: " << current_layer->draw_opacity() << " actual: "
+ << DrawOpacityFromPropertyTrees(current_layer,
+ inputs->property_trees->opacity_tree);
+ }
+}
+
+void VerifyPropertyTreeValues(
+ LayerTreeHostCommon::CalcDrawPropsImplInputs* inputs) {
+ // TODO(enne): need to synchronize compositor thread changes
+ // for animation and scrolling to the property trees before these
+ // can be correct.
+}
+
+enum PropertyTreeOption {
+ BUILD_PROPERTY_TREES_IF_NEEDED,
+ DONT_BUILD_PROPERTY_TREES
+};
+
+template <typename LayerType, typename RenderSurfaceLayerListType>
+void CalculateDrawPropertiesAndVerify(LayerTreeHostCommon::CalcDrawPropsInputs<
+ LayerType,
+ RenderSurfaceLayerListType>* inputs,
+ PropertyTreeOption property_tree_option) {
+ typename LayerType::LayerListType dummy_layer_list;
+ SubtreeGlobals<LayerType> globals;
+ DataForRecursion<LayerType> data_for_recursion;
+ ProcessCalcDrawPropsInputs(*inputs, &globals, &data_for_recursion);
PreCalculateMetaInformationRecursiveData recursive_data;
- PreCalculateMetaInformation(inputs->root_layer, &recursive_data);
- std::vector<AccumulatedSurfaceState<Layer>> accumulated_surface_state;
- CalculateDrawPropertiesInternal<Layer>(
- inputs->root_layer,
- globals,
- data_for_recursion,
- inputs->render_surface_layer_list,
- &dummy_layer_list,
- &accumulated_surface_state,
- inputs->current_render_surface_layer_list_id);
+ PreCalculateMetaInformationInternal(inputs->root_layer, &recursive_data);
+
+ const bool should_measure_property_tree_performance =
+ inputs->verify_property_trees &&
+ (property_tree_option == BUILD_PROPERTY_TREES_IF_NEEDED);
+
+ if (should_measure_property_tree_performance) {
+ TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
+ "LayerTreeHostCommon::CalculateDrawProperties");
+ }
+ ResetDrawProperties(inputs->root_layer);
+
+ std::vector<AccumulatedSurfaceState<LayerType>> accumulated_surface_state;
+ CalculateDrawPropertiesInternal<LayerType>(
+ inputs->root_layer, globals, data_for_recursion,
+ inputs->render_surface_layer_list, &dummy_layer_list,
+ &accumulated_surface_state, inputs->current_render_surface_layer_list_id);
+
+ if (should_measure_property_tree_performance) {
+ TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
+ "LayerTreeHostCommon::CalculateDrawProperties");
+ }
+
+ if (inputs->verify_property_trees) {
+ typename LayerType::LayerListType update_layer_list;
+
+ // For testing purposes, sometimes property trees need to be built on the
+ // compositor thread, so this can't just switch on Layer vs LayerImpl,
+ // even though in practice only the main thread builds property trees.
+ switch (property_tree_option) {
+ case BUILD_PROPERTY_TREES_IF_NEEDED: {
+ // The translation from layer to property trees is an intermediate
+ // state. We will eventually get these data passed directly to the
+ // compositor.
+ if (should_measure_property_tree_performance) {
+ TRACE_EVENT_BEGIN0(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
+ "LayerTreeHostCommon::ComputeVisibleRectsWithPropertyTrees");
+ }
+
+ BuildPropertyTreesAndComputeVisibleRects(
+ inputs->root_layer, inputs->page_scale_application_layer,
+ inputs->page_scale_factor, inputs->device_scale_factor,
+ gfx::Rect(inputs->device_viewport_size), inputs->device_transform,
+ inputs->property_trees, &update_layer_list);
+
+ if (should_measure_property_tree_performance) {
+ TRACE_EVENT_END0(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
+ "LayerTreeHostCommon::ComputeVisibleRectsWithPropertyTrees");
+ }
+
+ break;
+ }
+ case DONT_BUILD_PROPERTY_TREES: {
+ TRACE_EVENT0(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
+ "LayerTreeHostCommon::ComputeJustVisibleRectsWithPropertyTrees");
+ ComputeVisibleRectsUsingPropertyTrees(
+ inputs->root_layer, inputs->property_trees, &update_layer_list);
+ break;
+ }
+ }
+
+ VerifyPropertyTreeValues(inputs);
+ }
// The dummy layer list should not have been used.
DCHECK_EQ(0u, dummy_layer_list.size());
@@ -2416,32 +2730,31 @@ void LayerTreeHostCommon::CalculateDrawProperties(
}
void LayerTreeHostCommon::CalculateDrawProperties(
+ CalcDrawPropsMainInputs* inputs) {
+ UpdateRenderSurfaces(inputs->root_layer,
+ inputs->can_render_to_separate_surface, gfx::Transform(),
+ false);
+ CalculateDrawPropertiesAndVerify(inputs, BUILD_PROPERTY_TREES_IF_NEEDED);
+}
+
+void LayerTreeHostCommon::CalculateDrawProperties(
CalcDrawPropsImplInputs* inputs) {
- LayerImplList dummy_layer_list;
- SubtreeGlobals<LayerImpl> globals;
- DataForRecursion<LayerImpl> data_for_recursion;
- ProcessCalcDrawPropsInputs(*inputs, &globals, &data_for_recursion);
+ CalculateDrawPropertiesAndVerify(inputs, DONT_BUILD_PROPERTY_TREES);
+}
- LayerSorter layer_sorter;
- globals.layer_sorter = &layer_sorter;
+void LayerTreeHostCommon::CalculateDrawProperties(
+ CalcDrawPropsImplInputsForTesting* inputs) {
+ CalculateDrawPropertiesAndVerify(inputs, BUILD_PROPERTY_TREES_IF_NEEDED);
+}
- PreCalculateMetaInformationRecursiveData recursive_data;
- PreCalculateMetaInformation(inputs->root_layer, &recursive_data);
- std::vector<AccumulatedSurfaceState<LayerImpl>> accumulated_surface_state;
- CalculateDrawPropertiesInternal<LayerImpl>(
- inputs->root_layer,
- globals,
- data_for_recursion,
- inputs->render_surface_layer_list,
- &dummy_layer_list,
- &accumulated_surface_state,
- inputs->current_render_surface_layer_list_id);
+PropertyTrees* GetPropertyTrees(Layer* layer,
+ PropertyTrees* trees_from_inputs) {
+ return layer->layer_tree_host()->property_trees();
+}
- // The dummy layer list should not have been used.
- DCHECK_EQ(0u, dummy_layer_list.size());
- // A root layer render_surface should always exist after
- // CalculateDrawProperties.
- DCHECK(inputs->root_layer->render_surface());
+PropertyTrees* GetPropertyTrees(LayerImpl* layer,
+ PropertyTrees* trees_from_inputs) {
+ return trees_from_inputs;
}
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_common.h b/chromium/cc/trees/layer_tree_host_common.h
index 089fe2933f2..7d90445023f 100644
--- a/chromium/cc/trees/layer_tree_host_common.h
+++ b/chromium/cc/trees/layer_tree_host_common.h
@@ -13,6 +13,7 @@
#include "cc/base/cc_export.h"
#include "cc/base/scoped_ptr_vector.h"
#include "cc/layers/layer_lists.h"
+#include "cc/trees/property_tree.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/transform.h"
@@ -22,6 +23,7 @@ namespace cc {
class LayerImpl;
class Layer;
class SwapPromise;
+class PropertyTrees;
class CC_EXPORT LayerTreeHostCommon {
public:
@@ -38,38 +40,54 @@ class CC_EXPORT LayerTreeHostCommon {
float device_scale_factor,
float page_scale_factor,
const LayerType* page_scale_application_layer,
+ const gfx::Vector2dF& elastic_overscroll,
+ const LayerType* elastic_overscroll_application_layer,
int max_texture_size,
bool can_use_lcd_text,
+ bool layers_always_allowed_lcd_text,
bool can_render_to_separate_surface,
bool can_adjust_raster_scales,
+ bool verify_property_trees,
RenderSurfaceLayerListType* render_surface_layer_list,
- int current_render_surface_layer_list_id)
+ int current_render_surface_layer_list_id,
+ PropertyTrees* property_trees)
: root_layer(root_layer),
device_viewport_size(device_viewport_size),
device_transform(device_transform),
device_scale_factor(device_scale_factor),
page_scale_factor(page_scale_factor),
page_scale_application_layer(page_scale_application_layer),
+ elastic_overscroll(elastic_overscroll),
+ elastic_overscroll_application_layer(
+ elastic_overscroll_application_layer),
max_texture_size(max_texture_size),
can_use_lcd_text(can_use_lcd_text),
+ layers_always_allowed_lcd_text(layers_always_allowed_lcd_text),
can_render_to_separate_surface(can_render_to_separate_surface),
can_adjust_raster_scales(can_adjust_raster_scales),
+ verify_property_trees(verify_property_trees),
render_surface_layer_list(render_surface_layer_list),
current_render_surface_layer_list_id(
- current_render_surface_layer_list_id) {}
+ current_render_surface_layer_list_id),
+ property_trees(property_trees) {}
LayerType* root_layer;
gfx::Size device_viewport_size;
- const gfx::Transform& device_transform;
+ gfx::Transform device_transform;
float device_scale_factor;
float page_scale_factor;
const LayerType* page_scale_application_layer;
+ gfx::Vector2dF elastic_overscroll;
+ const LayerType* elastic_overscroll_application_layer;
int max_texture_size;
bool can_use_lcd_text;
+ bool layers_always_allowed_lcd_text;
bool can_render_to_separate_surface;
bool can_adjust_raster_scales;
+ bool verify_property_trees;
RenderSurfaceLayerListType* render_surface_layer_list;
int current_render_surface_layer_list_id;
+ PropertyTrees* property_trees;
};
template <typename LayerType, typename RenderSurfaceLayerListType>
@@ -86,28 +104,38 @@ class CC_EXPORT LayerTreeHostCommon {
RenderSurfaceLayerListType* render_surface_layer_list);
private:
- const gfx::Transform identity_transform_;
+ PropertyTrees temporary_property_trees;
};
typedef CalcDrawPropsInputs<Layer, RenderSurfaceLayerList>
CalcDrawPropsMainInputs;
typedef CalcDrawPropsInputsForTesting<Layer, RenderSurfaceLayerList>
CalcDrawPropsMainInputsForTesting;
+ static void UpdateRenderSurfaces(Layer* root_layer,
+ bool can_render_to_separate_surface,
+ const gfx::Transform& transform,
+ bool preserves_2d_axis_alignment);
+ static void UpdateRenderSurface(Layer* layer,
+ bool can_render_to_separate_surface,
+ gfx::Transform* transform,
+ bool* animation_preserves_axis_alignment);
static void CalculateDrawProperties(CalcDrawPropsMainInputs* inputs);
+ static void PreCalculateMetaInformation(Layer* root_layer);
typedef CalcDrawPropsInputs<LayerImpl, LayerImplList> CalcDrawPropsImplInputs;
typedef CalcDrawPropsInputsForTesting<LayerImpl, LayerImplList>
CalcDrawPropsImplInputsForTesting;
static void CalculateDrawProperties(CalcDrawPropsImplInputs* inputs);
+ static void CalculateDrawProperties(
+ CalcDrawPropsImplInputsForTesting* inputs);
template <typename LayerType>
static bool RenderSurfaceContributesToTarget(LayerType*,
int target_surface_layer_id);
- template <typename LayerType>
- static void CallFunctionForSubtree(
- LayerType* root_layer,
- const base::Callback<void(LayerType* layer)>& function);
+ template <typename LayerType, typename Function>
+ static void CallFunctionForSubtree(LayerType* layer,
+ const Function& function);
// Returns a layer with the given id if one exists in the subtree starting
// from the given root layer (including mask and replica layers).
@@ -130,7 +158,7 @@ class CC_EXPORT LayerTreeHostCommon {
struct ScrollUpdateInfo {
int layer_id;
- // TODO(miletus) : Use ScrollOffset once LayerTreeHost/Blink fully supports
+ // TODO(miletus): Use ScrollOffset once LayerTreeHost/Blink fully supports
// franctional scroll offset.
gfx::Vector2d scroll_delta;
};
@@ -142,6 +170,7 @@ struct CC_EXPORT ScrollAndScaleSet {
std::vector<LayerTreeHostCommon::ScrollUpdateInfo> scrolls;
float page_scale_delta;
+ gfx::Vector2dF elastic_overscroll_delta;
float top_controls_delta;
ScopedPtrVector<SwapPromise> swap_promises;
};
@@ -153,12 +182,14 @@ bool LayerTreeHostCommon::RenderSurfaceContributesToTarget(
// A layer will either contribute its own content, or its render surface's
// content, to the target surface. The layer contributes its surface's content
// when both the following are true:
- // (1) The layer actually has a render surface, and
+ // (1) The layer actually has a render surface and rendering into that
+ // surface, and
// (2) The layer's render surface is not the same as the target surface.
//
// Otherwise, the layer just contributes itself to the target surface.
- return layer->render_surface() && layer->id() != target_surface_layer_id;
+ return layer->render_target() == layer &&
+ layer->id() != target_surface_layer_id;
}
template <typename LayerType>
@@ -185,26 +216,30 @@ LayerType* LayerTreeHostCommon::FindLayerInSubtree(LayerType* root_layer,
return NULL;
}
-template <typename LayerType>
-void LayerTreeHostCommon::CallFunctionForSubtree(
- LayerType* root_layer,
- const base::Callback<void(LayerType* layer)>& function) {
- function.Run(root_layer);
-
- if (LayerType* mask_layer = root_layer->mask_layer())
- function.Run(mask_layer);
- if (LayerType* replica_layer = root_layer->replica_layer()) {
- function.Run(replica_layer);
+template <typename LayerType, typename Function>
+void LayerTreeHostCommon::CallFunctionForSubtree(LayerType* layer,
+ const Function& function) {
+ function(layer);
+
+ if (LayerType* mask_layer = layer->mask_layer())
+ function(mask_layer);
+ if (LayerType* replica_layer = layer->replica_layer()) {
+ function(replica_layer);
if (LayerType* mask_layer = replica_layer->mask_layer())
- function.Run(mask_layer);
+ function(mask_layer);
}
- for (size_t i = 0; i < root_layer->children().size(); ++i) {
- CallFunctionForSubtree(get_layer_as_raw_ptr(root_layer->children(), i),
+ for (size_t i = 0; i < layer->children().size(); ++i) {
+ CallFunctionForSubtree(get_layer_as_raw_ptr(layer->children(), i),
function);
}
}
+CC_EXPORT PropertyTrees* GetPropertyTrees(Layer* layer,
+ PropertyTrees* trees_from_inputs);
+CC_EXPORT PropertyTrees* GetPropertyTrees(LayerImpl* layer,
+ PropertyTrees* trees_from_inputs);
+
template <typename LayerType, typename RenderSurfaceLayerListType>
LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType,
RenderSurfaceLayerListType>::
@@ -220,12 +255,17 @@ LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType,
1.f,
1.f,
NULL,
+ gfx::Vector2dF(),
+ NULL,
std::numeric_limits<int>::max() / 2,
false,
+ false,
true,
false,
+ true,
render_surface_layer_list,
- 0) {
+ 0,
+ GetPropertyTrees(root_layer, &temporary_property_trees)) {
DCHECK(root_layer);
DCHECK(render_surface_layer_list);
}
@@ -240,16 +280,21 @@ LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType,
: CalcDrawPropsInputs<LayerType, RenderSurfaceLayerListType>(
root_layer,
device_viewport_size,
- identity_transform_,
+ gfx::Transform(),
1.f,
1.f,
NULL,
+ gfx::Vector2dF(),
+ NULL,
std::numeric_limits<int>::max() / 2,
false,
+ false,
true,
false,
+ true,
render_surface_layer_list,
- 0) {
+ 0,
+ GetPropertyTrees(root_layer, &temporary_property_trees)) {
DCHECK(root_layer);
DCHECK(render_surface_layer_list);
}
diff --git a/chromium/cc/trees/layer_tree_host_common_perftest.cc b/chromium/cc/trees/layer_tree_host_common_perftest.cc
index 12e7a5e2f9d..9a5de06bb0f 100644
--- a/chromium/cc/trees/layer_tree_host_common_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_perftest.cc
@@ -25,7 +25,6 @@
#include "cc/test/layer_tree_json_parser.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/paths.h"
-#include "cc/trees/layer_sorter.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/perf/perf_test.h"
@@ -80,32 +79,32 @@ class LayerTreeHostCommonPerfTest : public LayerTreeTest {
class CalcDrawPropsMainTest : public LayerTreeHostCommonPerfTest {
public:
- void RunCalcDrawProps() {
- RunTest(false, false, false);
- }
+ void RunCalcDrawProps() { RunTest(false, false, false); }
void BeginTest() override {
timer_.Reset();
do {
bool can_render_to_separate_surface = true;
+ bool verify_property_trees = false;
int max_texture_size = 8096;
RenderSurfaceLayerList update_list;
+ PropertyTrees property_trees;
LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(
layer_tree_host()->root_layer(),
- layer_tree_host()->device_viewport_size(),
- gfx::Transform(),
+ layer_tree_host()->device_viewport_size(), gfx::Transform(),
layer_tree_host()->device_scale_factor(),
layer_tree_host()->page_scale_factor(),
- layer_tree_host()->page_scale_layer(),
- max_texture_size,
+ layer_tree_host()->overscroll_elasticity_layer(),
+ layer_tree_host()->elastic_overscroll(),
+ layer_tree_host()->page_scale_layer(), max_texture_size,
layer_tree_host()->settings().can_use_lcd_text,
+ layer_tree_host()->settings().layers_always_allowed_lcd_text,
can_render_to_separate_surface,
layer_tree_host()
->settings()
.layer_transforms_should_scale_layer_contents,
- &update_list,
- 0);
+ verify_property_trees, &update_list, 0, &property_trees);
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
timer_.NextLap();
@@ -146,73 +145,27 @@ class CalcDrawPropsImplTest : public LayerTreeHostCommonPerfTest {
LayerTreeImpl* active_tree,
LayerTreeHostImpl* host_impl) {
LayerImplList update_list;
+ PropertyTrees property_trees;
+ bool verify_property_trees = false;
LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
- active_tree->root_layer(),
- active_tree->DrawViewportSize(),
- host_impl->DrawTransform(),
- active_tree->device_scale_factor(),
- active_tree->total_page_scale_factor(),
+ active_tree->root_layer(), active_tree->DrawViewportSize(),
+ host_impl->DrawTransform(), active_tree->device_scale_factor(),
+ active_tree->current_page_scale_factor(),
active_tree->InnerViewportContainerLayer(),
- max_texture_size,
+ active_tree->elastic_overscroll()->Current(active_tree->IsActiveTree()),
+ active_tree->overscroll_elasticity_layer(), max_texture_size,
host_impl->settings().can_use_lcd_text,
+ host_impl->settings().layers_always_allowed_lcd_text,
can_render_to_separate_surface,
host_impl->settings().layer_transforms_should_scale_layer_contents,
- &update_list,
- 0);
+ verify_property_trees, &update_list, 0, &property_trees);
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
}
};
-class LayerSorterMainTest : public CalcDrawPropsImplTest {
- public:
- void RunSortLayers() { RunTest(false, false, false); }
-
- void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
- void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
- LayerTreeImpl* active_tree = host_impl->active_tree();
- // First build the tree and then we'll start running tests on layersorter
- // itself
- bool can_render_to_separate_surface = true;
- int max_texture_size = 8096;
- DoCalcDrawPropertiesImpl(can_render_to_separate_surface,
- max_texture_size,
- active_tree,
- host_impl);
-
- // Behaviour of this test is different from that of sorting in practice.
- // In this case, all layers that exist in any 3D context are put into a list
- // and are sorted as one big 3D context instead of several smaller ones.
- BuildLayerImplList(active_tree->root_layer(), &base_list_);
- timer_.Reset();
- do {
- // Here we'll move the layers into a LayerImpl list of their own to be
- // sorted so we don't have a sorted list for every run after the first
- LayerImplList test_list = base_list_;
- layer_sorter_.Sort(test_list.begin(), test_list.end());
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- EndTest();
- }
-
- void BuildLayerImplList(LayerImpl* layer, LayerImplList* list) {
- if (layer->Is3dSorted()) {
- list->push_back(layer);
- }
-
- for (size_t i = 0; i < layer->children().size(); i++) {
- BuildLayerImplList(layer->children()[i], list);
- }
- }
-
- private:
- LayerImplList base_list_;
- LayerSorter layer_sorter_;
-};
-
-class BspTreePerfTest : public LayerSorterMainTest {
+class BspTreePerfTest : public CalcDrawPropsImplTest {
public:
+ BspTreePerfTest() : num_duplicates_(1) {}
void RunSortLayers() { RunTest(false, false, false); }
void SetNumberOfDuplicates(int num_duplicates) {
@@ -262,7 +215,18 @@ class BspTreePerfTest : public LayerSorterMainTest {
EndTest();
}
+ void BuildLayerImplList(LayerImpl* layer, LayerImplList* list) {
+ if (layer->Is3dSorted()) {
+ list->push_back(layer);
+ }
+
+ for (size_t i = 0; i < layer->children().size(); i++) {
+ BuildLayerImplList(layer->children()[i], list);
+ }
+ }
+
private:
+ LayerImplList base_list_;
int num_duplicates_;
};
@@ -314,16 +278,21 @@ TEST_F(CalcDrawPropsImplTest, TouchRegionHeavy) {
RunCalcDrawProps();
}
-TEST_F(LayerSorterMainTest, LayerSorterCubes) {
+TEST_F(BspTreePerfTest, LayerSorterCubes) {
SetTestName("layer_sort_cubes");
ReadTestFile("layer_sort_cubes");
RunSortLayers();
}
-TEST_F(LayerSorterMainTest, LayerSorterRubik) {
+TEST_F(BspTreePerfTest, LayerSorterRubik) {
SetTestName("layer_sort_rubik");
ReadTestFile("layer_sort_rubik");
+ // TODO(vollick): Remove verify_property_trees setting after
+ // crbug.com/444219 is fixed.
+ bool old_verify_property_trees = verify_property_trees();
+ set_verify_property_trees(false);
RunSortLayers();
+ set_verify_property_trees(old_verify_property_trees);
}
TEST_F(BspTreePerfTest, BspTreeCubes) {
@@ -337,7 +306,12 @@ TEST_F(BspTreePerfTest, BspTreeRubik) {
SetTestName("bsp_tree_rubik");
SetNumberOfDuplicates(1);
ReadTestFile("layer_sort_rubik");
+ // TODO(vollick): Remove verify_property_trees setting after
+ // crbug.com/444219 is fixed.
+ bool old_verify_property_trees = verify_property_trees();
+ set_verify_property_trees(false);
RunSortLayers();
+ set_verify_property_trees(old_verify_property_trees);
}
TEST_F(BspTreePerfTest, BspTreeCubes_2) {
diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc
index e0436bad3cc..591f48c4329 100644
--- a/chromium/cc/trees/layer_tree_host_common_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc
@@ -21,6 +21,9 @@
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/test/animation_test_common.h"
+#include "cc/test/fake_content_layer.h"
+#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_content_layer_impl.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_layer_tree_host_impl.h"
@@ -28,12 +31,14 @@
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_host_common_test.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/proxy.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/transform.h"
namespace cc {
@@ -55,11 +60,15 @@ class MockContentLayerClient : public ContentLayerClient {
public:
MockContentLayerClient() {}
~MockContentLayerClient() override {}
- void PaintContents(
- SkCanvas* canvas,
+ void PaintContents(SkCanvas* canvas,
+ const gfx::Rect& clip,
+ PaintingControlSetting picture_control) override {}
+ void PaintContentsToDisplayList(
+ DisplayItemList* display_list,
const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus gc_status) override {}
- void DidChangeLayerCanUseLCDText() override {}
+ PaintingControlSetting picture_control) override {
+ NOTIMPLEMENTED();
+ }
bool FillsBoundsCompletely() const override { return false; }
};
@@ -310,7 +319,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
gfx::Transform identity_matrix;
scoped_ptr<LayerImpl> sublayer_scoped_ptr(
@@ -318,23 +327,15 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) {
LayerImpl* sublayer = sublayer_scoped_ptr.get();
sublayer->SetContentsScale(kPageScale * kDeviceScale,
kPageScale * kDeviceScale);
- SetLayerPropertiesForTesting(sublayer,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(500, 500),
- true,
+ SetLayerPropertiesForTesting(sublayer, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(500, 500), true, false,
false);
scoped_ptr<LayerImpl> scroll_layer_scoped_ptr(
LayerImpl::Create(host_impl.active_tree(), 2));
LayerImpl* scroll_layer = scroll_layer_scoped_ptr.get();
- SetLayerPropertiesForTesting(scroll_layer,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(10, 20),
- true,
+ SetLayerPropertiesForTesting(scroll_layer, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 20), true, false,
false);
scoped_ptr<LayerImpl> clip_layer_scoped_ptr(
LayerImpl::Create(host_impl.active_tree(), 4));
@@ -350,17 +351,14 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) {
scroll_layer->AddChild(sublayer_scoped_ptr.Pass());
LayerImpl* scroll_layer_raw_ptr = scroll_layer_scoped_ptr.get();
clip_layer->AddChild(scroll_layer_scoped_ptr.Pass());
- scroll_layer_raw_ptr->SetScrollOffset(kScrollOffset);
+ scroll_layer_raw_ptr->PushScrollOffsetFromMainThread(kScrollOffset);
scoped_ptr<LayerImpl> root(LayerImpl::Create(host_impl.active_tree(), 3));
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(3, 4),
- true,
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(3, 4), true, false,
false);
root->AddChild(clip_layer_scoped_ptr.Pass());
+ root->SetHasRenderSurface(true);
ExecuteCalculateDrawProperties(
root.get(), kDeviceScale, kPageScale, scroll_layer->parent());
@@ -378,13 +376,9 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) {
const float kTranslateX = 10.6f;
const float kTranslateY = 20.6f;
arbitrary_translate.Translate(kTranslateX, kTranslateY);
- SetLayerPropertiesForTesting(scroll_layer,
- arbitrary_translate,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(10, 20),
- true,
- false);
+ SetLayerPropertiesForTesting(scroll_layer, arbitrary_translate,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(10, 20),
+ true, false, false);
ExecuteCalculateDrawProperties(
root.get(), kDeviceScale, kPageScale, scroll_layer->parent());
expected_transform.MakeIdentity();
@@ -665,7 +659,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsForReplica) {
gfx::Transform replica_composite_transform =
parent_composite_transform * replica_layer_transform *
Inverse(surface_sublayer_transform);
-
+ child_replica->SetIsDrawable(true);
// Child's render surface should not exist yet.
ASSERT_FALSE(child->render_surface());
@@ -1016,6 +1010,8 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) {
scoped_refptr<Layer> child = Layer::Create();
scoped_refptr<LayerWithForcedDrawsContent> grand_child =
make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> great_grand_child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
gfx::Transform rotation_about_y_axis;
rotation_about_y_axis.RotateAboutYAxis(30.0);
@@ -1042,9 +1038,13 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) {
gfx::Size(10, 10),
true,
false);
+ SetLayerPropertiesForTesting(great_grand_child.get(), identity_matrix,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10),
+ true, false);
root->AddChild(child);
child->AddChild(grand_child);
+ grand_child->AddChild(great_grand_child);
child->SetForceRenderSurface(true);
scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
@@ -1054,6 +1054,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) {
ASSERT_TRUE(root->should_flatten_transform());
ASSERT_TRUE(child->should_flatten_transform());
ASSERT_TRUE(grand_child->should_flatten_transform());
+ ASSERT_TRUE(great_grand_child->should_flatten_transform());
gfx::Transform expected_child_draw_transform = rotation_about_y_axis;
gfx::Transform expected_child_screen_space_transform = rotation_about_y_axis;
@@ -1063,6 +1064,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) {
flattened_rotation_about_y.FlattenTo2d();
gfx::Transform expected_grand_child_screen_space_transform =
flattened_rotation_about_y * rotation_about_y_axis;
+ gfx::Transform expected_great_grand_child_draw_transform =
+ flattened_rotation_about_y;
+ gfx::Transform expected_great_grand_child_screen_space_transform =
+ flattened_rotation_about_y * flattened_rotation_about_y;
ExecuteCalculateDrawProperties(root.get());
@@ -1080,6 +1085,11 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) {
grand_child->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform,
grand_child->screen_space_transform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_draw_transform,
+ great_grand_child->draw_transform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ expected_great_grand_child_screen_space_transform,
+ great_grand_child->screen_space_transform());
}
TEST_F(LayerTreeHostCommonTest, TransformsForDegenerateIntermediateLayer) {
@@ -1176,6 +1186,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
root.get(), root->bounds(), translate, &render_surface_layer_list);
inputs.can_adjust_raster_scales = true;
+ inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_EQ(translate, root->draw_properties().target_space_transform);
EXPECT_EQ(translate, child->draw_properties().target_space_transform);
@@ -1191,6 +1202,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
root.get(), root->bounds(), scale, &render_surface_layer_list);
inputs.can_adjust_raster_scales = true;
+ inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_EQ(scale, root->draw_properties().target_space_transform);
EXPECT_EQ(scale, child->draw_properties().target_space_transform);
@@ -1206,6 +1218,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
root.get(), root->bounds(), rotate, &render_surface_layer_list);
inputs.can_adjust_raster_scales = true;
+ inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_EQ(rotate, root->draw_properties().target_space_transform);
EXPECT_EQ(rotate, child->draw_properties().target_space_transform);
@@ -1223,6 +1236,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
root.get(), root->bounds(), composite, &render_surface_layer_list);
inputs.can_adjust_raster_scales = true;
+ inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_EQ(composite, root->draw_properties().target_space_transform);
EXPECT_EQ(composite, child->draw_properties().target_space_transform);
@@ -1238,6 +1252,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
root.get(), root->bounds(), translate, &render_surface_layer_list);
inputs.device_scale_factor = device_scale_factor;
inputs.can_adjust_raster_scales = true;
+ inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
gfx::Transform device_scaled_translate = translate;
device_scaled_translate.Scale(device_scale_factor, device_scale_factor);
@@ -1261,6 +1276,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_application_layer = root.get();
inputs.can_adjust_raster_scales = true;
+ inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
gfx::Transform page_scaled_translate = translate;
page_scaled_translate.Scale(page_scale_factor, page_scale_factor);
@@ -1392,6 +1408,36 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) {
EXPECT_EQ(gfx::Rect(), parent->drawable_content_rect());
}
+TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) {
+ scoped_refptr<Layer> parent = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(parent);
+
+ const gfx::Transform identity_matrix;
+ const SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode;
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+
+ parent->AddChild(child);
+ child->SetBlendMode(blend_mode);
+
+ RenderSurfaceLayerList render_surface_layer_list;
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ parent.get(), parent->bounds(), &render_surface_layer_list);
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ // Since the child layer has a blend mode other than normal, it should get
+ // its own render surface. Also, layer's draw_properties should contain the
+ // default blend mode, since the render surface becomes responsible for
+ // applying the blend mode.
+ ASSERT_TRUE(child->render_surface());
+ EXPECT_EQ(1U, child->render_surface()->layer_list().size());
+ EXPECT_EQ(SkXfermode::kSrcOver_Mode, child->draw_properties().blend_mode);
+}
+
TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) {
scoped_refptr<Layer> parent = Layer::Create();
scoped_refptr<Layer> render_surface1 = Layer::Create();
@@ -1458,6 +1504,74 @@ TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) {
}
}
+TEST_F(LayerTreeHostCommonTest, RenderSurfacesFlattenScreenSpaceTransform) {
+ // Render surfaces act as a flattening point for their subtree, so should
+ // always flatten the target-to-screen space transform seen by descendants.
+
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> parent = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> grand_child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+
+ gfx::Transform rotation_about_y_axis;
+ rotation_about_y_axis.RotateAboutYAxis(30.0);
+ // Make |parent| have a render surface.
+ parent->SetOpacity(0.9f);
+
+ const gfx::Transform identity_matrix;
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(parent.get(), rotation_about_y_axis,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10),
+ true, false);
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+ SetLayerPropertiesForTesting(grand_child.get(), identity_matrix,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10),
+ true, false);
+
+ root->AddChild(parent);
+ parent->AddChild(child);
+ child->AddChild(grand_child);
+
+ grand_child->SetShouldFlattenTransform(false);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ // Only grand_child should preserve 3d.
+ EXPECT_TRUE(root->should_flatten_transform());
+ EXPECT_TRUE(parent->should_flatten_transform());
+ EXPECT_TRUE(child->should_flatten_transform());
+ EXPECT_FALSE(grand_child->should_flatten_transform());
+
+ gfx::Transform expected_child_draw_transform = identity_matrix;
+ gfx::Transform expected_grand_child_draw_transform = identity_matrix;
+
+ gfx::Transform flattened_rotation_about_y = rotation_about_y_axis;
+ flattened_rotation_about_y.FlattenTo2d();
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ EXPECT_TRUE(parent->render_surface());
+ EXPECT_FALSE(child->render_surface());
+ EXPECT_FALSE(grand_child->render_surface());
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->draw_transform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix,
+ grand_child->draw_transform());
+
+ // The screen-space transform inherited by |child| and |grand_child| should
+ // have been flattened at their render target. In particular, the fact that
+ // |grand_child| happens to preserve 3d shouldn't affect this flattening.
+ EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_y,
+ child->screen_space_transform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_y,
+ grand_child->screen_space_transform());
+}
+
TEST_F(LayerTreeHostCommonTest, ClipRectCullsRenderSurfaces) {
// The entire subtree of layers that are outside the clip rect should be
// culled away, and should not affect the render_surface_layer_list.
@@ -1908,12 +2022,9 @@ TEST_F(LayerTreeHostCommonTest, DrawableContentRectForLayers) {
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 10, 10),
- grand_child1->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(15, 15, 5, 5),
- grand_child3->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(15, 15, 5, 5),
- grand_child3->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(5, 5, 10, 10), grand_child1->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(15, 15, 5, 5), grand_child3->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(15, 15, 5, 5), grand_child3->drawable_content_rect());
EXPECT_TRUE(grand_child4->drawable_content_rect().IsEmpty());
}
@@ -2055,12 +2166,12 @@ TEST_F(LayerTreeHostCommonTest, ClipRectIsPropagatedCorrectlyToSurfaces) {
// Surfaces are clipped by their parent, but un-affected by the owning layer's
// masksToBounds.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 20, 20),
- grand_child1->render_surface()->clip_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 20, 20),
- grand_child2->render_surface()->clip_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 20, 20),
- grand_child3->render_surface()->clip_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 20, 20),
+ grand_child1->render_surface()->clip_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 20, 20),
+ grand_child2->render_surface()->clip_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 20, 20),
+ grand_child3->render_surface()->clip_rect());
}
TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) {
@@ -2285,7 +2396,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectForIdentityTransform) {
gfx::Rect expected = gfx::Rect(10, 10, 30, 30);
gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
// Case 2: Layer is outside the surface rect.
layer_content_rect = gfx::Rect(120, 120, 30, 30);
@@ -2298,7 +2409,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectForIdentityTransform) {
expected = gfx::Rect(80, 80, 20, 20);
actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
}
TEST_F(LayerTreeHostCommonTest, VisibleRectForTranslations) {
@@ -2315,7 +2426,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectForTranslations) {
gfx::Rect expected = gfx::Rect(0, 0, 30, 30);
gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
// Case 2: Layer is outside the surface rect.
layer_to_surface_transform.MakeIdentity();
@@ -2330,7 +2441,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectForTranslations) {
expected = gfx::Rect(0, 0, 20, 20);
actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
}
TEST_F(LayerTreeHostCommonTest, VisibleRectFor2DRotations) {
@@ -2349,7 +2460,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectFor2DRotations) {
gfx::Rect expected = gfx::Rect(0, 0, 30, 30);
gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
// Case 2: Layer is outside the surface rect.
layer_to_surface_transform.MakeIdentity();
@@ -2369,7 +2480,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectFor2DRotations) {
expected = gfx::Rect(0, 0, 30, 30);
actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
// Case 4: The layer is rotated about its top-left corner, and translated
// upwards. In surface space, the layer is oriented diagonally, with only the
@@ -2382,7 +2493,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectFor2DRotations) {
expected = gfx::Rect(15, 0, 15, 30); // Right half of layer bounds.
actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
}
TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dOrthographicTransform) {
@@ -2400,7 +2511,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dOrthographicTransform) {
gfx::Rect expected = gfx::Rect(0, 0, 100, 100);
gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
// Case 2: Orthographic projection of a layer rotated about y-axis by 45
// degrees, but shifted to the side so only the right-half the layer would be
@@ -2415,7 +2526,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dOrthographicTransform) {
expected = gfx::Rect(50, 0, 50, 100); // Tight half of the layer.
actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
}
TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveTransform) {
@@ -2443,7 +2554,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveTransform) {
gfx::Rect expected = gfx::Rect(-50, -50, 200, 200);
gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
// Case 2: same projection as before, except that the layer is also translated
// to the side, so that only the right half of the layer should be visible.
@@ -2460,7 +2571,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveTransform) {
// bounding rect.
actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
}
TEST_F(LayerTreeHostCommonTest,
@@ -2484,7 +2595,7 @@ TEST_F(LayerTreeHostCommonTest,
gfx::Rect expected = gfx::Rect(0, 0, 100, 100);
gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
}
TEST_F(LayerTreeHostCommonTest, VisibleRectFor3dPerspectiveWhenClippedByW) {
@@ -2557,7 +2668,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectForPerspectiveUnprojection) {
gfx::Rect expected = gfx::Rect(-10, -10, 20, 20);
gfx::Rect actual = LayerTreeHostCommon::CalculateVisibleRect(
target_surface_rect, layer_content_rect, layer_to_surface_transform);
- EXPECT_RECT_EQ(expected, actual);
+ EXPECT_EQ(expected, actual);
}
TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) {
@@ -2607,22 +2718,22 @@ TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) {
ExecuteCalculateDrawProperties(root.get());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
- root->render_surface()->DrawableContentRect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+ root->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
// Layers that do not draw content should have empty visible_content_rects.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
// layer visible_content_rects are clipped by their target surface.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect());
EXPECT_TRUE(child3->visible_content_rect().IsEmpty());
// layer drawable_content_rects are not clipped.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
}
TEST_F(LayerTreeHostCommonTest,
@@ -2685,27 +2796,58 @@ TEST_F(LayerTreeHostCommonTest,
ASSERT_FALSE(child->render_surface());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
- root->render_surface()->DrawableContentRect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+ root->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
// Layers that do not draw content should have empty visible content rects.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), child->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), child->visible_content_rect());
// All grandchild visible content rects should be clipped by child.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), grand_child1->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 25, 25), grand_child2->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), grand_child1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 25, 25), grand_child2->visible_content_rect());
EXPECT_TRUE(grand_child3->visible_content_rect().IsEmpty());
// All grandchild DrawableContentRects should also be clipped by child.
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50),
- grand_child1->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(75, 75, 25, 25),
- grand_child2->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(5, 5, 50, 50), grand_child1->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(75, 75, 25, 25), grand_child2->drawable_content_rect());
EXPECT_TRUE(grand_child3->drawable_content_rect().IsEmpty());
}
+TEST_F(LayerTreeHostCommonTest, VisibleContentRectWithClippingAndScaling) {
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> child = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> grand_child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ root->AddChild(child);
+ child->AddChild(grand_child);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ gfx::Transform identity_matrix;
+ gfx::Transform child_scale_matrix;
+ child_scale_matrix.Scale(0.25f, 0.25f);
+ gfx::Transform grand_child_scale_matrix;
+ grand_child_scale_matrix.Scale(0.246f, 0.246f);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(child.get(), child_scale_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+ SetLayerPropertiesForTesting(grand_child.get(), grand_child_scale_matrix,
+ gfx::Point3F(), gfx::PointF(),
+ gfx::Size(100, 100), true, false);
+
+ child->SetMasksToBounds(true);
+ ExecuteCalculateDrawProperties(root.get());
+
+ // The visible rect is expanded to integer coordinates in target space before
+ // being projected back to layer space, where it is once again expanded to
+ // integer coordinates.
+ EXPECT_EQ(gfx::Rect(49, 49), grand_child->visible_rect_from_property_trees());
+}
+
TEST_F(LayerTreeHostCommonTest,
DrawableAndVisibleContentRectsForLayersInUnclippedRenderSurface) {
scoped_refptr<Layer> root = Layer::Create();
@@ -2766,28 +2908,77 @@ TEST_F(LayerTreeHostCommonTest,
ASSERT_TRUE(render_surface1->render_surface());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
- root->render_surface()->DrawableContentRect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+ root->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
// Layers that do not draw content should have empty visible content rects.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
- render_surface1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect());
// An unclipped surface grows its DrawableContentRect to include all drawable
// regions of the subtree.
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 170, 170),
- render_surface1->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(5, 5, 170, 170),
+ render_surface1->render_surface()->DrawableContentRect());
// All layers that draw content into the unclipped surface are also unclipped.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
+}
+
+TEST_F(LayerTreeHostCommonTest,
+ VisibleContentRectsForClippedSurfaceWithEmptyClip) {
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> child1 =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> child2 =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> child3 =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ root->AddChild(child1);
+ root->AddChild(child2);
+ root->AddChild(child3);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ gfx::Transform identity_matrix;
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(child1.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true,
+ false);
+ SetLayerPropertiesForTesting(child2.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true,
+ false);
+ SetLayerPropertiesForTesting(child3.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(125.f, 125.f), gfx::Size(50, 50),
+ true, false);
+
+ RenderSurfaceLayerList render_surface_layer_list;
+ // Now set the root render surface an empty clip.
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ root.get(), gfx::Size(), &render_surface_layer_list);
+
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+ ASSERT_TRUE(root->render_surface());
+ EXPECT_FALSE(root->is_clipped());
+
+ gfx::Rect empty;
+ EXPECT_EQ(empty, root->render_surface()->clip_rect());
+ EXPECT_TRUE(root->render_surface()->is_clipped());
+
+ // Visible content rect calculation will check if the target surface is
+ // clipped or not. An empty clip rect does not indicate the render surface
+ // is unclipped.
+ EXPECT_EQ(empty, child1->visible_content_rect());
+ EXPECT_EQ(empty, child2->visible_content_rect());
+ EXPECT_EQ(empty, child3->visible_content_rect());
}
TEST_F(LayerTreeHostCommonTest,
@@ -3000,30 +3191,29 @@ TEST_F(LayerTreeHostCommonTest,
ASSERT_TRUE(render_surface1->render_surface());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
- root->render_surface()->DrawableContentRect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+ root->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
// Layers that do not draw content should have empty visible content rects.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
- render_surface1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect());
// A clipped surface grows its DrawableContentRect to include all drawable
// regions of the subtree, but also gets clamped by the ancestor's clip.
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 95, 95),
- render_surface1->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(5, 5, 95, 95),
+ render_surface1->render_surface()->DrawableContentRect());
// All layers that draw content into the surface have their visible content
// rect clipped by the surface clip rect.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_content_rect());
EXPECT_TRUE(child3->visible_content_rect().IsEmpty());
// But the DrawableContentRects are unclipped.
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
}
TEST_F(LayerTreeHostCommonTest,
@@ -3099,37 +3289,35 @@ TEST_F(LayerTreeHostCommonTest,
ASSERT_TRUE(render_surface1->render_surface());
ASSERT_TRUE(render_surface2->render_surface());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
- root->render_surface()->DrawableContentRect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+ root->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
// Layers that do not draw content should have empty visible content rects.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
- render_surface1->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
- render_surface2->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface2->visible_content_rect());
// A clipped surface grows its DrawableContentRect to include all drawable
// regions of the subtree, but also gets clamped by the ancestor's clip.
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 95, 95),
- render_surface1->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(5, 5, 95, 95),
+ render_surface1->render_surface()->DrawableContentRect());
// render_surface1 lives in the "unclipped universe" of render_surface1, and
// is only implicitly clipped by render_surface1's content rect. So,
// render_surface2 grows to enclose all drawable content of its subtree.
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 170, 170),
- render_surface2->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(5, 5, 170, 170),
+ render_surface2->render_surface()->DrawableContentRect());
// All layers that draw content into render_surface2 think they are unclipped.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
// DrawableContentRects are also unclipped.
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(5, 5, 50, 50), child1->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3->drawable_content_rect());
}
TEST_F(LayerTreeHostCommonTest,
@@ -3177,14 +3365,13 @@ TEST_F(LayerTreeHostCommonTest,
ASSERT_TRUE(render_surface1->render_surface());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
- root->render_surface()->DrawableContentRect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+ root->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect());
// Layers that do not draw content should have empty visible content rects.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
- render_surface1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_content_rect());
// The unclipped surface grows its DrawableContentRect to include all drawable
// regions of the subtree.
@@ -3194,13 +3381,12 @@ TEST_F(LayerTreeHostCommonTest,
50 - diagonal_radius,
diagonal_radius * 2,
diagonal_radius * 2);
- EXPECT_RECT_EQ(expected_surface_drawable_content,
- render_surface1->render_surface()->DrawableContentRect());
+ EXPECT_EQ(expected_surface_drawable_content,
+ render_surface1->render_surface()->DrawableContentRect());
// All layers that draw content into the unclipped surface are also unclipped.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
- EXPECT_RECT_EQ(expected_surface_drawable_content,
- child1->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+ EXPECT_EQ(expected_surface_drawable_content, child1->drawable_content_rect());
}
TEST_F(LayerTreeHostCommonTest,
@@ -3259,18 +3445,18 @@ TEST_F(LayerTreeHostCommonTest,
diagonal_radius * 2);
gfx::Rect expected_surface_drawable_content =
gfx::IntersectRects(unclipped_surface_content, gfx::Rect(0, 0, 50, 50));
- EXPECT_RECT_EQ(expected_surface_drawable_content,
- render_surface1->render_surface()->DrawableContentRect());
+ EXPECT_EQ(expected_surface_drawable_content,
+ render_surface1->render_surface()->DrawableContentRect());
// On the clipped surface, only a quarter of the child1 is visible, but when
// rotating it back to child1's content space, the actual enclosing rect ends
// up covering the full left half of child1.
//
// Given the floating point math, this number is a little bit fuzzy.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 26, 50), child1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 26, 50), child1->visible_content_rect());
// The child's DrawableContentRect is unclipped.
- EXPECT_RECT_EQ(unclipped_surface_content, child1->drawable_content_rect());
+ EXPECT_EQ(unclipped_surface_content, child1->drawable_content_rect());
}
TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsInHighDPI) {
@@ -3349,35 +3535,31 @@ TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsInHighDPI) {
// drawable_content_rects for all layers and surfaces are scaled by
// device_scale_factor.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 200, 200),
- root->render_surface()->DrawableContentRect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 200, 200), root->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(10, 10, 190, 190),
- render_surface1->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 200),
+ root->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 200), root->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(10, 10, 190, 190),
+ render_surface1->render_surface()->DrawableContentRect());
// render_surface2 lives in the "unclipped universe" of render_surface1, and
// is only implicitly clipped by render_surface1.
- EXPECT_RECT_EQ(gfx::Rect(10, 10, 350, 350),
- render_surface2->render_surface()->DrawableContentRect());
+ EXPECT_EQ(gfx::Rect(10, 10, 350, 350),
+ render_surface2->render_surface()->DrawableContentRect());
- EXPECT_RECT_EQ(gfx::Rect(10, 10, 100, 100), child1->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(150, 150, 100, 100),
- child2->drawable_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(250, 250, 100, 100),
- child3->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(10, 10, 100, 100), child1->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(150, 150, 100, 100), child2->drawable_content_rect());
+ EXPECT_EQ(gfx::Rect(250, 250, 100, 100), child3->drawable_content_rect());
// The root layer does not actually draw content of its own.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_content_rect());
// All layer visible content rects are not expressed in content space of each
// layer, so they are not scaled by the device_scale_factor.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 3, 4),
- render_surface1->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 7, 13),
- render_surface2->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 3, 4), render_surface1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 7, 13), render_surface2->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child2->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child3->visible_content_rect());
}
TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithoutPreserves3d) {
@@ -3724,11 +3906,13 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithPreserves3d) {
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
- // Verify which render surfaces were created.
+ // Verify which render surfaces were created and used.
EXPECT_FALSE(front_facing_child->render_surface());
EXPECT_FALSE(back_facing_child->render_surface());
EXPECT_TRUE(front_facing_surface->render_surface());
- EXPECT_FALSE(back_facing_surface->render_surface());
+ EXPECT_NE(back_facing_surface->render_target(), back_facing_surface);
+ // We expect that a render_surface was created but not used.
+ EXPECT_TRUE(back_facing_surface->render_surface());
EXPECT_FALSE(front_facing_child_of_front_facing_surface->render_surface());
EXPECT_FALSE(back_facing_child_of_front_facing_surface->render_surface());
EXPECT_FALSE(front_facing_child_of_back_facing_surface->render_surface());
@@ -3992,10 +4176,13 @@ TEST_F(LayerTreeHostCommonTest,
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
- // Verify which render surfaces were created.
+ // Verify which render surfaces were created and used.
EXPECT_TRUE(front_facing_surface->render_surface());
- EXPECT_FALSE(
- back_facing_surface->render_surface()); // because it should be culled
+
+ // We expect the render surface to have been created, but remain unused.
+ EXPECT_TRUE(back_facing_surface->render_surface());
+ EXPECT_NE(back_facing_surface->render_target(),
+ back_facing_surface); // because it should be culled
EXPECT_FALSE(child1->render_surface());
EXPECT_FALSE(child2->render_surface());
@@ -4342,6 +4529,7 @@ TEST_F(LayerTreeHostCommonTest,
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_application_layer = parent.get();
inputs.can_adjust_raster_scales = true;
+ inputs.verify_property_trees = false;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_CONTENTS_SCALE_EQ(device_scale_factor * page_scale_factor, parent);
@@ -4482,6 +4670,7 @@ TEST_F(LayerTreeHostCommonTest, ContentsScale) {
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_application_layer = root.get();
inputs.can_adjust_raster_scales = true;
+ inputs.verify_property_trees = false;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_CONTENTS_SCALE_EQ(device_scale_factor * page_scale_factor *
@@ -4525,6 +4714,7 @@ TEST_F(LayerTreeHostCommonTest, ContentsScale) {
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_application_layer = root.get();
inputs.can_adjust_raster_scales = true;
+ inputs.verify_property_trees = false;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_CONTENTS_SCALE_EQ(
@@ -4553,6 +4743,7 @@ TEST_F(LayerTreeHostCommonTest, ContentsScale) {
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_application_layer = root.get();
inputs.can_adjust_raster_scales = true;
+ inputs.verify_property_trees = false;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_CONTENTS_SCALE_EQ(device_scale_factor * page_scale_factor *
@@ -4578,6 +4769,7 @@ TEST_F(LayerTreeHostCommonTest, ContentsScale) {
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_application_layer = root.get();
inputs.can_adjust_raster_scales = true;
+ inputs.verify_property_trees = false;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_CONTENTS_SCALE_EQ(device_scale_factor * page_scale_factor *
@@ -4665,7 +4857,8 @@ TEST_F(LayerTreeHostCommonTest,
root.get(), root->bounds(), &render_surface_layer_list);
inputs.device_scale_factor = device_scale_factor;
inputs.page_scale_factor = page_scale_factor;
- inputs.page_scale_application_layer = root.get(),
+ inputs.page_scale_application_layer = root.get();
+ inputs.verify_property_trees = false;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_CONTENTS_SCALE_EQ(device_scale_factor * page_scale_factor, parent);
@@ -4875,6 +5068,7 @@ TEST_F(LayerTreeHostCommonTest, ContentsScaleForSurfaces) {
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_application_layer = root.get();
inputs.can_adjust_raster_scales = true;
+ inputs.verify_property_trees = false;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_CONTENTS_SCALE_EQ(
@@ -5076,6 +5270,7 @@ TEST_F(LayerTreeHostCommonTest,
inputs.device_scale_factor = device_scale_factor;
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_application_layer = root.get();
+ inputs.verify_property_trees = false;
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_CONTENTS_SCALE_EQ(device_scale_factor * page_scale_factor,
@@ -5097,75 +5292,81 @@ TEST_F(LayerTreeHostCommonTest,
EXPECT_FLOAT_EQ(initial_parent_scale,
parent->draw_transform().matrix().get(1, 1));
- // The child surface is scaled up during draw since its subtree is not scaled
+ // The child surface is not scaled up during draw since its subtree is scaled
// by the transform hierarchy.
EXPECT_FLOAT_EQ(
- initial_parent_scale * initial_child_scale,
+ 1.f,
surface_scale->render_surface()->draw_transform().matrix().get(0, 0));
EXPECT_FLOAT_EQ(
- initial_parent_scale * initial_child_scale,
+ 1.f,
surface_scale->render_surface()->draw_transform().matrix().get(1, 1));
- // The surface_scale's RenderSurface is scaled during draw, so the layer does
- // not need to be scaled when drawing into its surface.
- EXPECT_FLOAT_EQ(1.0, surface_scale->draw_transform().matrix().get(0, 0));
- EXPECT_FLOAT_EQ(1.0, surface_scale->draw_transform().matrix().get(1, 1));
+ // The surface_scale's RenderSurface is not scaled during draw, so the layer
+ // needs to be scaled when drawing into its surface.
+ EXPECT_FLOAT_EQ(initial_parent_scale * initial_child_scale,
+ surface_scale->draw_transform().matrix().get(0, 0));
+ EXPECT_FLOAT_EQ(initial_parent_scale * initial_child_scale,
+ surface_scale->draw_transform().matrix().get(1, 1));
- // The surface_scale_child_scale is scaled when drawing into its surface,
- // since its content bounds are not scaled by the transform hierarchy.
+ // The surface_scale_child_scale is not scaled when drawing into its surface,
+ // since its content bounds are scaled by the transform hierarchy.
EXPECT_FLOAT_EQ(
- initial_child_scale,
+ initial_child_scale * initial_child_scale * initial_parent_scale,
surface_scale_child_scale->draw_transform().matrix().get(0, 0));
EXPECT_FLOAT_EQ(
- initial_child_scale,
+ initial_child_scale * initial_child_scale * initial_parent_scale,
surface_scale_child_scale->draw_transform().matrix().get(1, 1));
- // The surface_scale_child_no_scale has a fixed contents scale of 1, so it
- // needs to be scaled by the device and page scale factors, along with the
- // transform hierarchy.
+ // The surface_scale_child_no_scale is scaled by the device scale, page scale
+ // and transform hierarchy.
EXPECT_FLOAT_EQ(
- device_scale_factor * page_scale_factor * initial_child_scale,
+ device_scale_factor * page_scale_factor * initial_parent_scale *
+ initial_child_scale * initial_child_scale,
surface_scale_child_no_scale->draw_transform().matrix().get(0, 0));
EXPECT_FLOAT_EQ(
- device_scale_factor * page_scale_factor * initial_child_scale,
+ device_scale_factor * page_scale_factor * initial_parent_scale *
+ initial_child_scale * initial_child_scale,
surface_scale_child_no_scale->draw_transform().matrix().get(1, 1));
- // The child surface is scaled up during draw since its subtree is not scaled
+ // The child surface is not scaled up during draw since its subtree is scaled
// by the transform hierarchy.
EXPECT_FLOAT_EQ(
- initial_parent_scale * initial_child_scale,
+ 1.f,
surface_no_scale->render_surface()->draw_transform().matrix().get(0, 0));
EXPECT_FLOAT_EQ(
- initial_parent_scale * initial_child_scale,
+ 1.f,
surface_no_scale->render_surface()->draw_transform().matrix().get(1, 1));
// The surface_no_scale layer has a fixed contents scale of 1, so it needs to
// be scaled by the device and page scale factors. Its surface is already
// scaled by the transform hierarchy so those don't need to scale the layer's
// drawing.
- EXPECT_FLOAT_EQ(device_scale_factor * page_scale_factor,
+ EXPECT_FLOAT_EQ(initial_parent_scale * initial_child_scale *
+ device_scale_factor * page_scale_factor,
surface_no_scale->draw_transform().matrix().get(0, 0));
- EXPECT_FLOAT_EQ(device_scale_factor * page_scale_factor,
+ EXPECT_FLOAT_EQ(initial_parent_scale * initial_child_scale *
+ device_scale_factor * page_scale_factor,
surface_no_scale->draw_transform().matrix().get(1, 1));
// The surface_no_scale_child_scale has its contents scaled by the page and
// device scale factors, but needs to be scaled by the transform hierarchy
// when drawing.
EXPECT_FLOAT_EQ(
- initial_child_scale,
+ initial_parent_scale * initial_child_scale * initial_child_scale,
surface_no_scale_child_scale->draw_transform().matrix().get(0, 0));
EXPECT_FLOAT_EQ(
- initial_child_scale,
+ initial_parent_scale * initial_child_scale * initial_child_scale,
surface_no_scale_child_scale->draw_transform().matrix().get(1, 1));
- // The surface_no_scale_child_no_scale has a fixed contents scale of 1, so it
- // needs to be scaled by the device and page scale factors. It also needs to
- // be scaled by any transform heirarchy below its target surface.
+ // The surface_no_scale_child_no_scale needs to be scaled by the device and
+ // page scale factors and by any transform heirarchy below its target surface.
EXPECT_FLOAT_EQ(
- device_scale_factor * page_scale_factor * initial_child_scale,
+ device_scale_factor * page_scale_factor * initial_parent_scale *
+ initial_child_scale * initial_child_scale,
surface_no_scale_child_no_scale->draw_transform().matrix().get(0, 0));
EXPECT_FLOAT_EQ(
- device_scale_factor * page_scale_factor * initial_child_scale,
+ device_scale_factor * page_scale_factor * initial_parent_scale *
+ initial_child_scale * initial_child_scale,
surface_no_scale_child_no_scale->draw_transform().matrix().get(1, 1));
}
@@ -5256,8 +5457,16 @@ TEST_F(LayerTreeHostCommonTest,
root->reset_needs_push_properties_for_testing();
child->reset_needs_push_properties_for_testing();
+ gfx::Size device_viewport_size = gfx::Size(100, 100);
+ RenderSurfaceLayerList render_surface_layer_list;
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ root.get(), device_viewport_size, &render_surface_layer_list);
+ inputs.device_scale_factor = 1.f;
+ inputs.can_adjust_raster_scales = true;
+ inputs.verify_property_trees = false;
+
// This will change both layers' content bounds.
- ExecuteCalculateDrawProperties(root.get());
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_TRUE(root->needs_push_properties());
EXPECT_TRUE(child->needs_push_properties());
@@ -5266,7 +5475,8 @@ TEST_F(LayerTreeHostCommonTest,
// This will change only the child layer's contents scale and content bounds,
// since the root layer is not a ContentsScalingLayer.
- ExecuteCalculateDrawProperties(root.get(), 2.f);
+ inputs.device_scale_factor = 2.f;
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_FALSE(root->needs_push_properties());
EXPECT_TRUE(child->needs_push_properties());
@@ -5274,7 +5484,7 @@ TEST_F(LayerTreeHostCommonTest,
child->reset_needs_push_properties_for_testing();
// This will not change either layer's contents scale or content bounds.
- ExecuteCalculateDrawProperties(root.get(), 2.f);
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_FALSE(root->needs_push_properties());
EXPECT_FALSE(child->needs_push_properties());
}
@@ -5373,8 +5583,8 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) {
EXPECT_TRANSFORMATION_MATRIX_EQ(
child->screen_space_transform(),
duplicate_child_non_owner->screen_space_transform());
- EXPECT_RECT_EQ(child->drawable_content_rect(),
- duplicate_child_non_owner->drawable_content_rect());
+ EXPECT_EQ(child->drawable_content_rect(),
+ duplicate_child_non_owner->drawable_content_rect());
EXPECT_EQ(child->content_bounds(),
duplicate_child_non_owner->content_bounds());
@@ -5571,27 +5781,19 @@ TEST_F(LayerTreeHostCommonTest, TransparentChildRenderSurfaceCreation) {
TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.pending_tree(), 1);
const gfx::Transform identity_matrix;
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(100, 100),
- true,
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false,
false);
root->SetDrawsContent(true);
scoped_ptr<LayerImpl> child = LayerImpl::Create(host_impl.pending_tree(), 2);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- true,
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false,
false);
child->SetDrawsContent(true);
child->SetOpacity(0.0f);
@@ -5601,6 +5803,7 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
child->layer_animation_controller(), 10.0, 0.0f, 1.0f, false);
root->AddChild(child.Pass());
+ root->SetHasRenderSurface(true);
LayerImplList render_surface_layer_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
@@ -5614,164 +5817,222 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
ASSERT_EQ(2u, root->render_surface()->layer_list().size());
}
-typedef std::tr1::tuple<bool, bool> LCDTextTestParam;
+using LCDTextTestParam = std::tr1::tuple<bool, bool, bool>;
class LCDTextTest
: public LayerTreeHostCommonTestBase,
public testing::TestWithParam<LCDTextTestParam> {
+ public:
+ LCDTextTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
+ root_(nullptr),
+ child_(nullptr),
+ grand_child_(nullptr) {}
+
protected:
- virtual void SetUp() {
+ void SetUp() override {
can_use_lcd_text_ = std::tr1::get<0>(GetParam());
+ layers_always_allowed_lcd_text_ = std::tr1::get<1>(GetParam());
- root_ = Layer::Create();
- child_ = Layer::Create();
- grand_child_ = Layer::Create();
- child_->AddChild(grand_child_.get());
- root_->AddChild(child_.get());
+ scoped_ptr<LayerImpl> root_ptr =
+ LayerImpl::Create(host_impl_.active_tree(), 1);
+ scoped_ptr<LayerImpl> child_ptr =
+ LayerImpl::Create(host_impl_.active_tree(), 2);
+ scoped_ptr<LayerImpl> grand_child_ptr =
+ LayerImpl::Create(host_impl_.active_tree(), 3);
- gfx::Transform identity_matrix;
- SetLayerPropertiesForTesting(root_.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 1),
- true,
- false);
- SetLayerPropertiesForTesting(child_.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 1),
- true,
- false);
- SetLayerPropertiesForTesting(grand_child_.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 1),
- true,
- false);
+ // Stash raw pointers to look at later.
+ root_ = root_ptr.get();
+ child_ = child_ptr.get();
+ grand_child_ = grand_child_ptr.get();
+
+ child_->AddChild(grand_child_ptr.Pass());
+ root_->AddChild(child_ptr.Pass());
+ host_impl_.active_tree()->SetRootLayer(root_ptr.Pass());
- child_->SetForceRenderSurface(std::tr1::get<1>(GetParam()));
+ root_->SetContentsOpaque(true);
+ child_->SetContentsOpaque(true);
+ grand_child_->SetContentsOpaque(true);
- host_ = CreateFakeLayerTreeHost();
- host_->SetRootLayer(root_);
+ gfx::Transform identity_matrix;
+ SetLayerPropertiesForTesting(root_, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 1), true, false,
+ true);
+ SetLayerPropertiesForTesting(child_, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 1), true, false,
+ std::tr1::get<2>(GetParam()));
+ SetLayerPropertiesForTesting(grand_child_, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 1), true, false,
+ false);
}
bool can_use_lcd_text_;
- scoped_ptr<FakeLayerTreeHost> host_;
- scoped_refptr<Layer> root_;
- scoped_refptr<Layer> child_;
- scoped_refptr<Layer> grand_child_;
+ bool layers_always_allowed_lcd_text_;
+
+ FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
+ FakeLayerTreeHostImpl host_impl_;
+
+ LayerImpl* root_;
+ LayerImpl* child_;
+ LayerImpl* grand_child_;
};
TEST_P(LCDTextTest, CanUseLCDText) {
+ bool expect_lcd_text = can_use_lcd_text_ || layers_always_allowed_lcd_text_;
+ bool expect_not_lcd_text = layers_always_allowed_lcd_text_;
+
// Case 1: Identity transform.
gfx::Transform identity_matrix;
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
// Case 2: Integral translation.
gfx::Transform integral_translation;
integral_translation.Translate(1.0, 2.0);
child_->SetTransform(integral_translation);
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
// Case 3: Non-integral translation.
gfx::Transform non_integral_translation;
non_integral_translation.Translate(1.5, 2.5);
child_->SetTransform(non_integral_translation);
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_FALSE(child_->can_use_lcd_text());
- EXPECT_FALSE(grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
// Case 4: Rotation.
gfx::Transform rotation;
rotation.Rotate(10.0);
child_->SetTransform(rotation);
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_FALSE(child_->can_use_lcd_text());
- EXPECT_FALSE(grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
// Case 5: Scale.
gfx::Transform scale;
scale.Scale(2.0, 2.0);
child_->SetTransform(scale);
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_FALSE(child_->can_use_lcd_text());
- EXPECT_FALSE(grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
// Case 6: Skew.
gfx::Transform skew;
skew.SkewX(10.0);
child_->SetTransform(skew);
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_FALSE(child_->can_use_lcd_text());
- EXPECT_FALSE(grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
// Case 7: Translucent.
child_->SetTransform(identity_matrix);
child_->SetOpacity(0.5f);
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_FALSE(child_->can_use_lcd_text());
- EXPECT_FALSE(grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
// Case 8: Sanity check: restore transform and opacity.
child_->SetTransform(identity_matrix);
child_->SetOpacity(1.f);
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
+
+ // Case 9: Non-opaque content.
+ child_->SetContentsOpaque(false);
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
+
+ // Case 10: Sanity check: restore content opaqueness.
+ child_->SetContentsOpaque(true);
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
}
TEST_P(LCDTextTest, CanUseLCDTextWithAnimation) {
+ bool expect_lcd_text = can_use_lcd_text_ || layers_always_allowed_lcd_text_;
+ bool expect_not_lcd_text = layers_always_allowed_lcd_text_;
+
// Sanity check: Make sure can_use_lcd_text_ is set on each node.
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
// Add opacity animation.
child_->SetOpacity(0.9f);
AddOpacityTransitionToController(
child_->layer_animation_controller(), 10.0, 0.9f, 0.1f, false);
- ExecuteCalculateDrawProperties(
- root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
- // Text AA should not be adjusted while animation is active.
- // Make sure LCD text AA setting remains unchanged.
- EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
- EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ // Text LCD should be adjusted while animation is active.
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
+}
+
+TEST_P(LCDTextTest, CanUseLCDTextWithAnimationContentsOpaque) {
+ bool expect_lcd_text = can_use_lcd_text_ || layers_always_allowed_lcd_text_;
+ bool expect_not_lcd_text = layers_always_allowed_lcd_text_;
+
+ // Sanity check: Make sure can_use_lcd_text_ is set on each node.
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
+
+ // Mark contents non-opaque within the first animation frame.
+ child_->SetContentsOpaque(false);
+ AddOpacityTransitionToController(child_->layer_animation_controller(), 10.0,
+ 0.9f, 0.1f, false);
+
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
+ layers_always_allowed_lcd_text_);
+ // LCD text should be disabled for non-opaque layers even during animations.
+ EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+ EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
+ EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
}
INSTANTIATE_TEST_CASE_P(LayerTreeHostCommonTest,
LCDTextTest,
- testing::Combine(testing::Bool(), testing::Bool()));
+ testing::Combine(testing::Bool(),
+ testing::Bool(),
+ testing::Bool()));
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayer) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -5829,44 +6090,33 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayer) {
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.pending_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- true,
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false,
false);
root->SetDrawsContent(true);
scoped_ptr<LayerImpl> child = LayerImpl::Create(host_impl.pending_tree(), 2);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(40, 40),
- true,
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(40, 40), true, false,
false);
child->SetDrawsContent(true);
scoped_ptr<LayerImpl> grand_child =
LayerImpl::Create(host_impl.pending_tree(), 3);
- SetLayerPropertiesForTesting(grand_child.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(30, 30),
- true,
- false);
+ SetLayerPropertiesForTesting(grand_child.get(), identity_matrix,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30),
+ true, false, false);
grand_child->SetDrawsContent(true);
grand_child->SetHideLayerAndSubtree(true);
child->AddChild(grand_child.Pass());
root->AddChild(child.Pass());
+ root->SetHasRenderSurface(true);
LayerImplList render_surface_layer_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
@@ -5885,7 +6135,7 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) {
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayers) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -5942,40 +6192,28 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayers) {
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayersImpl) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.pending_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false,
+ true);
root->SetDrawsContent(true);
scoped_ptr<LayerImpl> child = LayerImpl::Create(host_impl.pending_tree(), 2);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(40, 40),
- true,
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(40, 40), true, false,
false);
child->SetDrawsContent(true);
child->SetHideLayerAndSubtree(true);
scoped_ptr<LayerImpl> grand_child =
LayerImpl::Create(host_impl.pending_tree(), 3);
- SetLayerPropertiesForTesting(grand_child.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(30, 30),
- true,
- false);
+ SetLayerPropertiesForTesting(grand_child.get(), identity_matrix,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30),
+ true, false, false);
grand_child->SetDrawsContent(true);
child->AddChild(grand_child.Pass());
@@ -5999,7 +6237,7 @@ void EmptyCopyOutputCallback(scoped_ptr<CopyOutputResult> result) {}
TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6146,7 +6384,7 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6221,7 +6459,7 @@ TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) {
TEST_F(LayerTreeHostCommonTest, VisibleContentRectInsideSurface) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6832,7 +7070,7 @@ TEST_F(LayerTreeHostCommonTest,
TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> root =
LayerImpl::Create(host_impl.active_tree(), 12345);
scoped_ptr<LayerImpl> child1 =
@@ -6846,40 +7084,20 @@ TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
// This layer structure normally forces render surface due to preserves3d
// behavior.
- SetLayerPropertiesForTesting(child1.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- false,
- true);
+ SetLayerPropertiesForTesting(child1.get(), identity_matrix, transform_origin,
+ position, bounds, false, true, true);
child1->SetDrawsContent(true);
- SetLayerPropertiesForTesting(child2.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child2.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, false);
child2->SetDrawsContent(true);
- SetLayerPropertiesForTesting(child3.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child3.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, false);
child3->SetDrawsContent(true);
child2->Set3dSortingContextId(1);
@@ -6898,6 +7116,27 @@ TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_EQ(2u, render_surface_layer_list.size());
+
+ int count_represents_target_render_surface = 0;
+ int count_represents_contributing_render_surface = 0;
+ int count_represents_itself = 0;
+ auto end = LayerIterator<LayerImpl>::End(&render_surface_layer_list);
+ for (auto it = LayerIterator<LayerImpl>::Begin(&render_surface_layer_list);
+ it != end; ++it) {
+ if (it.represents_target_render_surface())
+ count_represents_target_render_surface++;
+ if (it.represents_contributing_render_surface())
+ count_represents_contributing_render_surface++;
+ if (it.represents_itself())
+ count_represents_itself++;
+ }
+
+ // Two render surfaces.
+ EXPECT_EQ(2, count_represents_target_render_surface);
+ // Second render surface contributes to root render surface.
+ EXPECT_EQ(1, count_represents_contributing_render_surface);
+ // All 4 layers represent itself.
+ EXPECT_EQ(4, count_represents_itself);
}
{
@@ -6908,6 +7147,27 @@ TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
EXPECT_EQ(1u, render_surface_layer_list.size());
+
+ int count_represents_target_render_surface = 0;
+ int count_represents_contributing_render_surface = 0;
+ int count_represents_itself = 0;
+ auto end = LayerIterator<LayerImpl>::End(&render_surface_layer_list);
+ for (auto it = LayerIterator<LayerImpl>::Begin(&render_surface_layer_list);
+ it != end; ++it) {
+ if (it.represents_target_render_surface())
+ count_represents_target_render_surface++;
+ if (it.represents_contributing_render_surface())
+ count_represents_contributing_render_surface++;
+ if (it.represents_itself())
+ count_represents_itself++;
+ }
+
+ // Only root layer has a render surface.
+ EXPECT_EQ(1, count_represents_target_render_surface);
+ // No layer contributes a render surface to root render surface.
+ EXPECT_EQ(0, count_represents_contributing_render_surface);
+ // All 4 layers represent itself.
+ EXPECT_EQ(4, count_represents_itself);
}
}
@@ -7471,136 +7731,70 @@ TEST_F(LayerTreeHostCommonTest, OutOfOrderClippingRequiresRSLLSorting) {
EXPECT_TRUE(render_surface_layer_list.at(2)->render_surface());
}
-TEST_F(LayerTreeHostCommonTest, DoNotClobberSorting) {
- // We rearrange layer list contributions if we have to visit children out of
- // order, but it should be a 'stable' rearrangement. That is, the layer list
- // additions for a single layer should not be reordered, though their position
- // wrt to the contributions due to a sibling may vary.
+TEST_F(LayerTreeHostCommonTest, FixedPositionWithInterveningRenderSurface) {
+ // Ensures that when we have a render surface between a fixed position layer
+ // and its container, we compute the fixed position layer's draw transform
+ // with respect to that intervening render surface, not with respect to its
+ // container's render target.
//
// + root
- // + scroll_child
- // + top_content
- // + bottom_content
- // + scroll_parent_border
- // + scroll_parent_clip
- // + scroll_parent
+ // + render_surface
+ // + fixed
+ // + child
//
- FakeImplProxy proxy;
- TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
- host_impl.CreatePendingTree();
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
- scoped_ptr<LayerImpl> scroll_parent_border =
- LayerImpl::Create(host_impl.active_tree(), 2);
- scoped_ptr<LayerImpl> scroll_parent_clip =
- LayerImpl::Create(host_impl.active_tree(), 3);
- scoped_ptr<LayerImpl> scroll_parent =
- LayerImpl::Create(host_impl.active_tree(), 4);
- scoped_ptr<LayerImpl> scroll_child =
- LayerImpl::Create(host_impl.active_tree(), 5);
- scoped_ptr<LayerImpl> bottom_content =
- LayerImpl::Create(host_impl.active_tree(), 6);
- scoped_ptr<LayerImpl> top_content =
- LayerImpl::Create(host_impl.active_tree(), 7);
-
- scroll_parent_clip->SetMasksToBounds(true);
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> render_surface =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> fixed =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
- scroll_child->SetScrollParent(scroll_parent.get());
- scoped_ptr<std::set<LayerImpl*>> scroll_children(new std::set<LayerImpl*>);
- scroll_children->insert(scroll_child.get());
- scroll_parent->SetScrollChildren(scroll_children.release());
+ root->AddChild(render_surface);
+ render_surface->AddChild(fixed);
+ fixed->AddChild(child);
- scroll_child->SetDrawsContent(true);
- scroll_parent->SetDrawsContent(true);
- top_content->SetDrawsContent(true);
- bottom_content->SetDrawsContent(true);
+ root->SetIsContainerForFixedPositionLayers(true);
+ render_surface->SetForceRenderSurface(true);
- gfx::Transform identity_transform;
- gfx::Transform top_transform;
- top_transform.Translate3d(0.0, 0.0, 5.0);
- gfx::Transform bottom_transform;
- bottom_transform.Translate3d(0.0, 0.0, 3.0);
+ LayerPositionConstraint constraint;
+ constraint.set_is_fixed_position(true);
+ fixed->SetPositionConstraint(constraint);
- SetLayerPropertiesForTesting(root.get(),
- identity_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- true,
- false);
- SetLayerPropertiesForTesting(scroll_parent_border.get(),
- identity_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(40, 40),
- true,
- false);
- SetLayerPropertiesForTesting(scroll_parent_clip.get(),
- identity_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(30, 30),
- true,
+ SetLayerPropertiesForTesting(root.get(), gfx::Transform(), gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false);
+ SetLayerPropertiesForTesting(render_surface.get(), gfx::Transform(),
+ gfx::Point3F(), gfx::PointF(7.f, 9.f),
+ gfx::Size(50, 50), true, false);
+ SetLayerPropertiesForTesting(fixed.get(), gfx::Transform(), gfx::Point3F(),
+ gfx::PointF(10.f, 15.f), gfx::Size(50, 50), true,
false);
- SetLayerPropertiesForTesting(scroll_parent.get(),
- identity_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- true,
+ SetLayerPropertiesForTesting(child.get(), gfx::Transform(), gfx::Point3F(),
+ gfx::PointF(1.f, 2.f), gfx::Size(50, 50), true,
false);
- SetLayerPropertiesForTesting(scroll_child.get(),
- identity_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- true,
- false);
- SetLayerPropertiesForTesting(top_content.get(),
- top_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- false,
- true);
- SetLayerPropertiesForTesting(bottom_content.get(),
- bottom_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- false,
- true);
- scroll_child->SetShouldFlattenTransform(false);
- scroll_child->Set3dSortingContextId(1);
-
- scroll_child->AddChild(top_content.Pass());
- scroll_child->AddChild(bottom_content.Pass());
- root->AddChild(scroll_child.Pass());
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
- scroll_parent_clip->AddChild(scroll_parent.Pass());
- scroll_parent_border->AddChild(scroll_parent_clip.Pass());
- root->AddChild(scroll_parent_border.Pass());
+ ExecuteCalculateDrawProperties(root.get());
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
+ gfx::Transform expected_fixed_draw_transform;
+ expected_fixed_draw_transform.Translate(10.f, 15.f);
+ EXPECT_EQ(expected_fixed_draw_transform, fixed->draw_transform());
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+ gfx::Transform expected_fixed_screen_space_transform;
+ expected_fixed_screen_space_transform.Translate(17.f, 24.f);
+ EXPECT_EQ(expected_fixed_screen_space_transform,
+ fixed->screen_space_transform());
- EXPECT_TRUE(root->render_surface());
+ gfx::Transform expected_child_draw_transform;
+ expected_child_draw_transform.Translate(11.f, 17.f);
+ EXPECT_EQ(expected_child_draw_transform, child->draw_transform());
- // If we don't sort by depth and let the layers get added in the order they
- // would normally be visited in, then layers 6 and 7 will be out of order. In
- // other words, although we've had to shift 5, 6, and 7 to appear before 4
- // in the list (because of the scroll parent relationship), this should not
- // have an effect on the the order of 5, 6, and 7 (which had been reordered
- // due to layer sorting).
- EXPECT_EQ(4u, root->render_surface()->layer_list().size());
- EXPECT_EQ(5, root->render_surface()->layer_list().at(0)->id());
- EXPECT_EQ(6, root->render_surface()->layer_list().at(1)->id());
- EXPECT_EQ(7, root->render_surface()->layer_list().at(2)->id());
- EXPECT_EQ(4, root->render_surface()->layer_list().at(3)->id());
+ gfx::Transform expected_child_screen_space_transform;
+ expected_child_screen_space_transform.Translate(18.f, 26.f);
+ EXPECT_EQ(expected_child_screen_space_transform,
+ child->screen_space_transform());
}
TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
@@ -7614,7 +7808,7 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
//
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
scoped_ptr<LayerImpl> container =
@@ -7639,33 +7833,17 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
container_transform.Translate3d(10.0, 20.0, 0.0);
gfx::Vector2dF container_offset = container_transform.To2dTranslation();
- SetLayerPropertiesForTesting(root.get(),
- identity_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- true,
- false);
- SetLayerPropertiesForTesting(container.get(),
- container_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(40, 40),
- true,
- false);
- SetLayerPropertiesForTesting(scroller.get(),
- identity_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(30, 30),
- true,
- false);
- SetLayerPropertiesForTesting(fixed.get(),
- identity_transform,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(50, 50),
- true,
+ SetLayerPropertiesForTesting(root.get(), identity_transform, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false,
+ true);
+ SetLayerPropertiesForTesting(container.get(), container_transform,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(40, 40),
+ true, false, false);
+ SetLayerPropertiesForTesting(scroller.get(), identity_transform,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30),
+ true, false, false);
+ SetLayerPropertiesForTesting(fixed.get(), identity_transform, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false,
false);
scroller->AddChild(fixed.Pass());
@@ -7762,6 +7940,90 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
}
}
+TEST_F(LayerTreeHostCommonTest,
+ ScrollCompensationMainScrollOffsetFractionalPart) {
+ // This test verifies that a scrolling layer that has fractional scroll offset
+ // from main doesn't move a fixed position child.
+ //
+ // + root
+ // + container
+ // + scroller
+ // + fixed
+ //
+ FakeImplProxy proxy;
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+ host_impl.CreatePendingTree();
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
+ scoped_ptr<LayerImpl> container =
+ LayerImpl::Create(host_impl.active_tree(), 2);
+ LayerImpl* container_layer = container.get();
+ scoped_ptr<LayerImpl> scroller =
+ LayerImpl::Create(host_impl.active_tree(), 3);
+ LayerImpl* scroll_layer = scroller.get();
+ scoped_ptr<LayerImpl> fixed = LayerImpl::Create(host_impl.active_tree(), 4);
+ LayerImpl* fixed_layer = fixed.get();
+
+ container->SetIsContainerForFixedPositionLayers(true);
+
+ LayerPositionConstraint constraint;
+ constraint.set_is_fixed_position(true);
+ fixed->SetPositionConstraint(constraint);
+
+ scroller->SetScrollClipLayer(container->id());
+
+ gfx::Transform identity_transform;
+ gfx::Transform container_transform;
+ container_transform.Translate3d(10.0, 20.0, 0.0);
+ gfx::Vector2dF container_offset = container_transform.To2dTranslation();
+
+ SetLayerPropertiesForTesting(root.get(), identity_transform, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false,
+ true);
+ SetLayerPropertiesForTesting(container.get(), container_transform,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(40, 40),
+ true, false, false);
+ SetLayerPropertiesForTesting(scroller.get(), identity_transform,
+ gfx::Point3F(), gfx::PointF(0.0, 0.0),
+ gfx::Size(30, 30), true, false, false);
+
+ gfx::ScrollOffset scroll_offset(3.3, 4.2);
+ gfx::Vector2dF main_scroll_fractional_part(0.3f, 0.2f);
+ gfx::Vector2dF scroll_delta(0.1f, 0.4f);
+ // Blink only uses the integer part of the scroll_offset for fixed
+ // position layer.
+ SetLayerPropertiesForTesting(fixed.get(), identity_transform, gfx::Point3F(),
+ gfx::PointF(3.0f, 4.0f), gfx::Size(50, 50), true,
+ false, false);
+ scroll_layer->PushScrollOffsetFromMainThread(scroll_offset);
+ scroll_layer->SetScrollDelta(scroll_delta);
+ scroll_layer->SetScrollCompensationAdjustment(main_scroll_fractional_part);
+
+ scroller->AddChild(fixed.Pass());
+ container->AddChild(scroller.Pass());
+ root->AddChild(container.Pass());
+
+ LayerImplList render_surface_layer_list;
+ LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+ root.get(), root->bounds(), &render_surface_layer_list);
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ container_layer->draw_properties().screen_space_transform,
+ fixed_layer->draw_properties().screen_space_transform);
+ EXPECT_VECTOR_EQ(
+ fixed_layer->draw_properties().screen_space_transform.To2dTranslation(),
+ container_offset);
+
+ gfx::ScrollOffset effective_scroll_offset =
+ ScrollOffsetWithDelta(scroll_offset, scroll_delta);
+ gfx::Vector2d rounded_effective_scroll_offset =
+ ToRoundedVector2d(ScrollOffsetToVector2dF(effective_scroll_offset));
+ EXPECT_VECTOR_EQ(
+ scroll_layer->draw_properties().screen_space_transform.To2dTranslation(),
+ container_offset - rounded_effective_scroll_offset);
+}
+
class AnimationScaleFactorTrackingLayerImpl : public LayerImpl {
public:
static scoped_ptr<AnimationScaleFactorTrackingLayerImpl> Create(
@@ -7784,7 +8046,7 @@ class AnimationScaleFactorTrackingLayerImpl : public LayerImpl {
TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
gfx::Transform identity_matrix;
scoped_ptr<AnimationScaleFactorTrackingLayerImpl> grand_parent =
AnimationScaleFactorTrackingLayerImpl::Create(host_impl.active_tree(), 1);
@@ -7803,33 +8065,18 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) {
parent->AddChild(child.Pass());
grand_parent->AddChild(parent.Pass());
- SetLayerPropertiesForTesting(grand_parent.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 2),
- true,
+ SetLayerPropertiesForTesting(grand_parent.get(), identity_matrix,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(1, 2),
+ true, false, true);
+ SetLayerPropertiesForTesting(parent_raw, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 2), true, false,
false);
- SetLayerPropertiesForTesting(parent_raw,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 2),
- true,
+ SetLayerPropertiesForTesting(child_raw, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 2), true, false,
false);
- SetLayerPropertiesForTesting(child_raw,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 2),
- true,
- false);
- SetLayerPropertiesForTesting(grand_child_raw,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 2),
- true,
+
+ SetLayerPropertiesForTesting(grand_child_raw, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 2), true, false,
false);
ExecuteCalculateDrawProperties(grand_parent.get());
@@ -7901,11 +8148,11 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) {
0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
grand_parent->layer_animation_controller()->AbortAnimations(
- Animation::Transform);
+ Animation::TRANSFORM);
parent_raw->layer_animation_controller()->AbortAnimations(
- Animation::Transform);
+ Animation::TRANSFORM);
child_raw->layer_animation_controller()->AbortAnimations(
- Animation::Transform);
+ Animation::TRANSFORM);
TransformOperations perspective;
perspective.AppendPerspective(10.f);
@@ -7925,7 +8172,7 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) {
0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
child_raw->layer_animation_controller()->AbortAnimations(
- Animation::Transform);
+ Animation::TRANSFORM);
gfx::Transform scale_matrix;
scale_matrix.Scale(1.f, 2.f);
@@ -8016,7 +8263,7 @@ static void GatherDrawnLayers(LayerImplList* rsll,
TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
gfx::Transform identity_matrix;
scoped_ptr<LayerImpl> grand_parent =
@@ -8039,42 +8286,25 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
parent->AddChild(child.Pass());
grand_parent->AddChild(parent.Pass());
- SetLayerPropertiesForTesting(grand_parent_raw,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 2),
- true,
- false);
- SetLayerPropertiesForTesting(parent_raw,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 2),
- true,
- false);
- SetLayerPropertiesForTesting(child_raw,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 2),
- true,
+ SetLayerPropertiesForTesting(grand_parent_raw, identity_matrix,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(1, 2),
+ true, false, true);
+ SetLayerPropertiesForTesting(parent_raw, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 2), true, false,
false);
- SetLayerPropertiesForTesting(grand_child1_raw,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 2),
- true,
- false);
- SetLayerPropertiesForTesting(grand_child2_raw,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 2),
- true,
+
+ SetLayerPropertiesForTesting(child_raw, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 2), true, false,
false);
+ SetLayerPropertiesForTesting(grand_child1_raw, identity_matrix,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(1, 2),
+ true, false, false);
+
+ SetLayerPropertiesForTesting(grand_child2_raw, identity_matrix,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(1, 2),
+ true, false, false);
+
// Start with nothing being drawn.
ExecuteCalculateDrawProperties(grand_parent_raw);
int member_id = render_surface_layer_list_count();
@@ -8092,7 +8322,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
// If we force render surface, but none of the layers are in the layer list,
// then this layer should not appear in RSLL.
- grand_child1_raw->SetForceRenderSurface(true);
+ grand_child1_raw->SetHasRenderSurface(true);
ExecuteCalculateDrawProperties(grand_parent_raw);
member_id = render_surface_layer_list_count();
@@ -8131,8 +8361,8 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
// Now child is forced to have a render surface, and one if its children draws
// content.
grand_child1_raw->SetDrawsContent(false);
- grand_child1_raw->SetForceRenderSurface(false);
- child_raw->SetForceRenderSurface(true);
+ grand_child1_raw->SetHasRenderSurface(false);
+ child_raw->SetHasRenderSurface(true);
grand_child2_raw->SetDrawsContent(true);
ExecuteCalculateDrawProperties(grand_parent_raw);
@@ -8276,7 +8506,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
LayerImpl* root_layer = root.get();
@@ -8287,34 +8517,29 @@ TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
root->AddChild(child1.Pass());
root->AddChild(child2.Pass());
+ root->SetHasRenderSurface(true);
gfx::Transform identity_matrix, scale_transform_child1,
scale_transform_child2;
scale_transform_child1.Scale(2, 3);
scale_transform_child2.Scale(4, 5);
- SetLayerPropertiesForTesting(root_layer,
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 1),
- true,
- false);
- SetLayerPropertiesForTesting(child1_layer,
- scale_transform_child1,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(),
- true,
- false);
+ SetLayerPropertiesForTesting(root_layer, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 1), true, false,
+ true);
+ SetLayerPropertiesForTesting(child1_layer, scale_transform_child1,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(), true,
+ false, false);
child1_layer->SetMaskLayer(
LayerImpl::Create(host_impl.active_tree(), 4).Pass());
scoped_ptr<LayerImpl> replica_layer =
LayerImpl::Create(host_impl.active_tree(), 5);
+ replica_layer->SetHasRenderSurface(true);
replica_layer->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 6));
child1_layer->SetReplicaLayer(replica_layer.Pass());
+ child1_layer->SetHasRenderSurface(true);
ExecuteCalculateDrawProperties(root_layer);
@@ -8322,13 +8547,9 @@ TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
scale.AppendScale(5.f, 8.f, 3.f);
AddAnimatedTransformToLayer(child2_layer, 1.0, TransformOperations(), scale);
- SetLayerPropertiesForTesting(child2_layer,
- scale_transform_child2,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(),
- true,
- false);
+ SetLayerPropertiesForTesting(child2_layer, scale_transform_child2,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(), true,
+ false, false);
ExecuteCalculateDrawProperties(root_layer);
@@ -8562,5 +8783,818 @@ TEST_F(LayerTreeHostCommonTest, VisibleContentRectInChildRenderSurface) {
EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), content->visible_content_rect());
}
+TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) {
+ FakeImplProxy proxy;
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+ // Set two layers: the root layer clips it's child,
+ // the child draws its content.
+
+ gfx::Size root_size = gfx::Size(300, 500);
+
+ // Sublayer should be bigger than the root enlarged by bounds_delta.
+ gfx::Size sublayer_size = gfx::Size(300, 1000);
+
+ // Device viewport accomidated the root and the top controls.
+ gfx::Size device_viewport_size = gfx::Size(300, 600);
+ gfx::Transform identity_matrix;
+
+ host_impl.active_tree()->SetRootLayer(
+ LayerImpl::Create(host_impl.active_tree(), 1));
+
+ LayerImpl* root = host_impl.active_tree()->root_layer();
+ SetLayerPropertiesForTesting(root,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ root_size,
+ false,
+ false,
+ true);
+
+ root->SetContentBounds(root_size);
+ root->SetMasksToBounds(true);
+
+ root->AddChild(LayerImpl::Create(host_impl.active_tree(), 2));
+
+ LayerImpl* sublayer = root->child_at(0);
+ SetLayerPropertiesForTesting(sublayer,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ sublayer_size,
+ false,
+ false,
+ false);
+
+ sublayer->SetContentBounds(sublayer_size);
+ sublayer->SetDrawsContent(true);
+
+ LayerImplList layer_impl_list;
+ LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+ root, device_viewport_size, &layer_impl_list);
+
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ EXPECT_EQ(gfx::Rect(root_size), sublayer->visible_content_rect());
+
+ root->SetBoundsDelta(gfx::Vector2dF(0.0, 50.0));
+
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ gfx::Rect affected_by_delta(0, 0, root_size.width(),
+ root_size.height() + 50);
+ EXPECT_EQ(affected_by_delta, sublayer->visible_content_rect());
+}
+
+TEST_F(LayerTreeHostCommonTest, VisibleContentRectForAnimatedLayer) {
+ const gfx::Transform identity_matrix;
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> animated =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+
+ root->AddChild(animated);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(animated.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(20, 20), true, false);
+
+ root->SetMasksToBounds(true);
+ root->SetForceRenderSurface(true);
+ animated->SetOpacity(0.f);
+
+ AddOpacityTransitionToController(animated->layer_animation_controller(), 10.0,
+ 0.f, 1.f, false);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ EXPECT_FALSE(animated->visible_rect_from_property_trees().IsEmpty());
+}
+
+TEST_F(LayerTreeHostCommonTest,
+ VisibleContentRectForAnimatedLayerWithSingularTransform) {
+ const gfx::Transform identity_matrix;
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> clip = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> animated =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> surface =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> descendant_of_animation =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+
+ root->AddChild(clip);
+ clip->AddChild(animated);
+ animated->AddChild(surface);
+ surface->AddChild(descendant_of_animation);
+
+ clip->SetMasksToBounds(true);
+ surface->SetForceRenderSurface(true);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ gfx::Transform uninvertible_matrix;
+ uninvertible_matrix.Scale3d(6.f, 6.f, 0.f);
+
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(clip.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+ SetLayerPropertiesForTesting(animated.get(), uninvertible_matrix,
+ gfx::Point3F(), gfx::PointF(),
+ gfx::Size(120, 120), true, false);
+ SetLayerPropertiesForTesting(surface.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(descendant_of_animation.get(), identity_matrix,
+ gfx::Point3F(), gfx::PointF(),
+ gfx::Size(200, 200), true, false);
+
+ TransformOperations start_transform_operations;
+ start_transform_operations.AppendMatrix(uninvertible_matrix);
+ TransformOperations end_transform_operations;
+
+ AddAnimatedTransformToLayer(animated.get(), 10.0, start_transform_operations,
+ end_transform_operations);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ // The animated layer has a singular transform and maps to a non-empty rect in
+ // clipped target space, so is treated as fully visible.
+ EXPECT_EQ(gfx::Rect(120, 120), animated->visible_rect_from_property_trees());
+
+ // The singular transform on |animated| is flattened when inherited by
+ // |surface|, and this happens to make it invertible.
+ EXPECT_EQ(gfx::Rect(2, 2), surface->visible_rect_from_property_trees());
+ EXPECT_EQ(gfx::Rect(2, 2),
+ descendant_of_animation->visible_rect_from_property_trees());
+
+ gfx::Transform zero_matrix;
+ zero_matrix.Scale3d(0.f, 0.f, 0.f);
+ SetLayerPropertiesForTesting(animated.get(), zero_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(120, 120), true, false);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ // The animated layer maps to the empty rect in clipped target space, so is
+ // treated as having an empty visible rect.
+ EXPECT_EQ(gfx::Rect(), animated->visible_rect_from_property_trees());
+
+ // This time, flattening does not make |animated|'s transform invertible. This
+ // means the clip cannot be projected into |surface|'s space, so we treat
+ // |surface| and layers that draw into it as fully visible.
+ EXPECT_EQ(gfx::Rect(100, 100), surface->visible_rect_from_property_trees());
+ EXPECT_EQ(gfx::Rect(200, 200),
+ descendant_of_animation->visible_rect_from_property_trees());
+}
+
+// Verify that having an animated filter (but no current filter, as these
+// are mutually exclusive) correctly creates a render surface.
+TEST_F(LayerTreeHostCommonTest, AnimatedFilterCreatesRenderSurface) {
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> child = Layer::Create();
+ scoped_refptr<Layer> grandchild = Layer::Create();
+ root->AddChild(child);
+ child->AddChild(grandchild);
+
+ gfx::Transform identity_transform;
+ SetLayerPropertiesForTesting(root.get(), identity_transform, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false);
+ SetLayerPropertiesForTesting(child.get(), identity_transform, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false);
+ SetLayerPropertiesForTesting(grandchild.get(), identity_transform,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(50, 50),
+ true, false);
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ AddAnimatedFilterToLayer(child.get(), 10.0, 0.1f, 0.2f);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ EXPECT_TRUE(root->render_surface());
+ EXPECT_TRUE(child->render_surface());
+ EXPECT_FALSE(grandchild->render_surface());
+
+ EXPECT_TRUE(root->filters().IsEmpty());
+ EXPECT_TRUE(child->filters().IsEmpty());
+ EXPECT_TRUE(grandchild->filters().IsEmpty());
+
+ EXPECT_FALSE(root->FilterIsAnimating());
+ EXPECT_TRUE(child->FilterIsAnimating());
+ EXPECT_FALSE(grandchild->FilterIsAnimating());
+}
+
+// Ensures that the property tree code accounts for offsets between fixed
+// position layers and their respective containers.
+TEST_F(LayerTreeHostCommonTest, PropertyTreesAccountForFixedParentOffset) {
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> child = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> grandchild =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+
+ root->AddChild(child);
+ child->AddChild(grandchild);
+
+ gfx::Transform identity_transform;
+ SetLayerPropertiesForTesting(root.get(), identity_transform, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false);
+ SetLayerPropertiesForTesting(child.get(), identity_transform, gfx::Point3F(),
+ gfx::PointF(1000, 1000), gfx::Size(50, 50), true,
+ false);
+ SetLayerPropertiesForTesting(grandchild.get(), identity_transform,
+ gfx::Point3F(), gfx::PointF(-1000, -1000),
+ gfx::Size(50, 50), true, false);
+
+ root->SetMasksToBounds(true);
+ root->SetIsContainerForFixedPositionLayers(true);
+ LayerPositionConstraint constraint;
+ constraint.set_is_fixed_position(true);
+ grandchild->SetPositionConstraint(constraint);
+
+ root->SetIsContainerForFixedPositionLayers(true);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50),
+ grandchild->visible_rect_from_property_trees());
+}
+
+TEST_F(LayerTreeHostCommonTest, CombineClipsUsingContentTarget) {
+ // In the following layer tree, the layer |box|'s render target is |surface|.
+ // |surface| also creates a transform node. We want to combine clips for |box|
+ // in the space of its target (i.e., |surface|), not its target's target. This
+ // test ensures that happens.
+
+ gfx::Transform rotate;
+ rotate.Rotate(5);
+ gfx::Transform identity;
+
+ scoped_refptr<Layer> root = Layer::Create();
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(2500, 1500), true,
+ false);
+
+ scoped_refptr<Layer> frame_clip = Layer::Create();
+ SetLayerPropertiesForTesting(frame_clip.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(2500, 1500), true,
+ false);
+ frame_clip->SetMasksToBounds(true);
+
+ scoped_refptr<Layer> rotated = Layer::Create();
+ SetLayerPropertiesForTesting(rotated.get(), rotate,
+ gfx::Point3F(1250, 250, 0), gfx::PointF(),
+ gfx::Size(2500, 500), true, false);
+
+ scoped_refptr<Layer> surface = Layer::Create();
+ SetLayerPropertiesForTesting(surface.get(), rotate, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(2500, 500), true,
+ false);
+ surface->SetOpacity(0.5);
+
+ scoped_refptr<LayerWithForcedDrawsContent> container =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(container.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(300, 300), true, false);
+
+ scoped_refptr<LayerWithForcedDrawsContent> box =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(box.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+
+ root->AddChild(frame_clip);
+ frame_clip->AddChild(rotated);
+ rotated->AddChild(surface);
+ surface->AddChild(container);
+ surface->AddChild(box);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+}
+
+TEST_F(LayerTreeHostCommonTest, OnlyApplyFixedPositioningOnce) {
+ gfx::Transform identity;
+ gfx::Transform translate_z;
+ translate_z.Translate3d(0, 0, 10);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(800, 800), true, false);
+ root->SetIsContainerForFixedPositionLayers(true);
+
+ scoped_refptr<Layer> frame_clip = Layer::Create();
+ SetLayerPropertiesForTesting(frame_clip.get(), translate_z, gfx::Point3F(),
+ gfx::PointF(500, 100), gfx::Size(100, 100), true,
+ false);
+ frame_clip->SetMasksToBounds(true);
+
+ scoped_refptr<LayerWithForcedDrawsContent> fixed =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(fixed.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1000, 1000), true,
+ false);
+
+ LayerPositionConstraint constraint;
+ constraint.set_is_fixed_position(true);
+ fixed->SetPositionConstraint(constraint);
+
+ root->AddChild(frame_clip);
+ frame_clip->AddChild(fixed);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ gfx::Rect expected(0, 0, 100, 100);
+ EXPECT_EQ(expected, fixed->visible_rect_from_property_trees());
+}
+
+TEST_F(LayerTreeHostCommonTest,
+ PropertyTreesAccountForScrollCompensationAdjustment) {
+ gfx::Transform identity;
+ gfx::Transform translate_z;
+ translate_z.Translate3d(0, 0, 10);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(800, 800), true, false);
+ root->SetIsContainerForFixedPositionLayers(true);
+
+ scoped_refptr<Layer> frame_clip = Layer::Create();
+ SetLayerPropertiesForTesting(frame_clip.get(), translate_z, gfx::Point3F(),
+ gfx::PointF(500, 100), gfx::Size(100, 100), true,
+ false);
+ frame_clip->SetMasksToBounds(true);
+
+ scoped_refptr<LayerWithForcedDrawsContent> scroller =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(scroller.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1000, 1000), true,
+ false);
+
+ scroller->SetScrollCompensationAdjustment(gfx::Vector2dF(0.3f, 0.7f));
+ scroller->SetScrollOffset(gfx::ScrollOffset(0.3, 0.7));
+ scroller->SetScrollClipLayerId(frame_clip->id());
+
+ scoped_refptr<LayerWithForcedDrawsContent> fixed =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(fixed.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false);
+
+ LayerPositionConstraint constraint;
+ constraint.set_is_fixed_position(true);
+ fixed->SetPositionConstraint(constraint);
+
+ scoped_refptr<LayerWithForcedDrawsContent> fixed_child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(fixed_child.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+
+ fixed_child->SetPositionConstraint(constraint);
+
+ root->AddChild(frame_clip);
+ frame_clip->AddChild(scroller);
+ scroller->AddChild(fixed);
+ fixed->AddChild(fixed_child);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ gfx::Rect expected(0, 0, 50, 50);
+ EXPECT_EQ(expected, fixed->visible_rect_from_property_trees());
+
+ expected = gfx::Rect(0, 0, 10, 10);
+ EXPECT_EQ(expected, fixed_child->visible_rect_from_property_trees());
+}
+
+TEST_F(LayerTreeHostCommonTest, FixedClipsShouldBeAssociatedWithTheRightNode) {
+ gfx::Transform identity;
+
+ scoped_refptr<Layer> root = Layer::Create();
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(800, 800), true, false);
+ root->SetIsContainerForFixedPositionLayers(true);
+
+ scoped_refptr<Layer> frame_clip = Layer::Create();
+ SetLayerPropertiesForTesting(frame_clip.get(), identity, gfx::Point3F(),
+ gfx::PointF(500, 100), gfx::Size(100, 100), true,
+ false);
+ frame_clip->SetMasksToBounds(true);
+
+ scoped_refptr<LayerWithForcedDrawsContent> scroller =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(scroller.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1000, 1000), true,
+ false);
+
+ scroller->SetScrollOffset(gfx::ScrollOffset(100, 100));
+ scroller->SetScrollClipLayerId(frame_clip->id());
+
+ scoped_refptr<LayerWithForcedDrawsContent> fixed =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(fixed.get(), identity, gfx::Point3F(),
+ gfx::PointF(100, 100), gfx::Size(50, 50), true,
+ false);
+
+ LayerPositionConstraint constraint;
+ constraint.set_is_fixed_position(true);
+ fixed->SetPositionConstraint(constraint);
+ fixed->SetForceRenderSurface(true);
+ fixed->SetMasksToBounds(true);
+
+ root->AddChild(frame_clip);
+ frame_clip->AddChild(scroller);
+ scroller->AddChild(fixed);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ gfx::Rect expected(0, 0, 50, 50);
+ EXPECT_EQ(expected, fixed->visible_rect_from_property_trees());
+}
+
+TEST_F(LayerTreeHostCommonTest, ChangingAxisAlignmentTriggersRebuild) {
+ gfx::Transform identity;
+ gfx::Transform translate;
+ gfx::Transform rotate;
+
+ translate.Translate(10, 10);
+ rotate.Rotate(45);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(800, 800), true, false);
+ root->SetIsContainerForFixedPositionLayers(true);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ root->SetTransform(translate);
+ EXPECT_FALSE(host->property_trees()->needs_rebuild);
+
+ root->SetTransform(rotate);
+ EXPECT_TRUE(host->property_trees()->needs_rebuild);
+}
+
+TEST_F(LayerTreeHostCommonTest, ChangeTransformOrigin) {
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ root->AddChild(child);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ gfx::Transform identity_matrix;
+ gfx::Transform scale_matrix;
+ scale_matrix.Scale(2.f, 2.f);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(child.get(), scale_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(10, 10), child->visible_rect_from_property_trees());
+
+ child->SetTransformOrigin(gfx::Point3F(10.f, 10.f, 10.f));
+
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(5, 5, 5, 5), child->visible_rect_from_property_trees());
+}
+
+TEST_F(LayerTreeHostCommonTest, UpdateScrollChildPosition) {
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> scroll_parent =
+ make_scoped_refptr(new LayerWithForcedDrawsContent);
+ scoped_refptr<LayerWithForcedDrawsContent> scroll_child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent);
+
+ root->AddChild(scroll_child);
+ root->AddChild(scroll_parent);
+ scroll_child->SetScrollParent(scroll_parent.get());
+ scroll_parent->SetScrollClipLayerId(root->id());
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ gfx::Transform identity_transform;
+ gfx::Transform scale;
+ scale.Scale(2.f, 2.f);
+ SetLayerPropertiesForTesting(root.get(), identity_transform, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false);
+ SetLayerPropertiesForTesting(scroll_child.get(), scale, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(40, 40), true, false);
+ SetLayerPropertiesForTesting(scroll_parent.get(), identity_transform,
+ gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30),
+ true, false);
+
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(25, 25),
+ scroll_child->visible_rect_from_property_trees());
+
+ scroll_child->SetPosition(gfx::PointF(0, -10.f));
+ scroll_parent->SetScrollOffset(gfx::ScrollOffset(0.f, 10.f));
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 5, 25, 25),
+ scroll_child->visible_rect_from_property_trees());
+}
+
+static void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
+}
+
+TEST_F(LayerTreeHostCommonTest, SkippingSubtreeMain) {
+ gfx::Transform identity;
+ FakeContentLayerClient client;
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> grandchild =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<FakeContentLayer> greatgrandchild(
+ FakeContentLayer::Create(&client));
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(child.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+ SetLayerPropertiesForTesting(grandchild.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+ SetLayerPropertiesForTesting(greatgrandchild.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+
+ root->AddChild(child);
+ child->AddChild(grandchild);
+ grandchild->AddChild(greatgrandchild);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ // Check the non-skipped case.
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_rect_from_property_trees());
+
+ // Now we will reset the visible rect from property trees for the grandchild,
+ // and we will configure |child| in several ways that should force the subtree
+ // to be skipped. The visible content rect for |grandchild| should, therefore,
+ // remain empty.
+ grandchild->set_visible_rect_from_property_trees(gfx::Rect());
+ gfx::Transform singular;
+ singular.matrix().set(0, 0, 0);
+
+ child->SetTransform(singular);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0), grandchild->visible_rect_from_property_trees());
+ child->SetTransform(identity);
+
+ child->SetHideLayerAndSubtree(true);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0), grandchild->visible_rect_from_property_trees());
+ child->SetHideLayerAndSubtree(false);
+
+ child->SetOpacity(0.f);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0), grandchild->visible_rect_from_property_trees());
+
+ // Now, even though child has zero opacity, we will configure |grandchild| and
+ // |greatgrandchild| in several ways that should force the subtree to be
+ // processed anyhow.
+ grandchild->SetTouchEventHandlerRegion(Region(gfx::Rect(0, 0, 10, 10)));
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_rect_from_property_trees());
+ grandchild->set_visible_rect_from_property_trees(gfx::Rect());
+ grandchild->SetTouchEventHandlerRegion(Region());
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0), grandchild->visible_rect_from_property_trees());
+ grandchild->set_visible_rect_from_property_trees(gfx::Rect());
+
+ greatgrandchild->RequestCopyOfOutput(
+ CopyOutputRequest::CreateBitmapRequest(base::Bind(&CopyOutputCallback)));
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_rect_from_property_trees());
+}
+
+TEST_F(LayerTreeHostCommonTest, SkippingSubtreeImpl) {
+ FakeImplProxy proxy;
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+ gfx::Transform identity;
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
+ scoped_ptr<LayerImpl> child = LayerImpl::Create(host_impl.active_tree(), 2);
+ scoped_ptr<LayerImpl> grandchild =
+ LayerImpl::Create(host_impl.active_tree(), 3);
+
+ scoped_ptr<FakeContentLayerImpl> greatgrandchild(
+ FakeContentLayerImpl::Create(host_impl.active_tree(), 4));
+
+ child->SetDrawsContent(true);
+ grandchild->SetDrawsContent(true);
+ greatgrandchild->SetDrawsContent(true);
+
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false,
+ true);
+ SetLayerPropertiesForTesting(child.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false,
+ false);
+ SetLayerPropertiesForTesting(grandchild.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false,
+ false);
+ SetLayerPropertiesForTesting(greatgrandchild.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false,
+ true);
+
+ LayerImpl* child_ptr = child.get();
+ LayerImpl* grandchild_ptr = grandchild.get();
+ LayerImpl* greatgrandchild_ptr = greatgrandchild.get();
+
+ grandchild->AddChild(greatgrandchild.Pass());
+ child->AddChild(grandchild.Pass());
+ root->AddChild(child.Pass());
+
+ // Check the non-skipped case.
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(10, 10),
+ grandchild_ptr->visible_rect_from_property_trees());
+
+ // Now we will reset the visible rect from property trees for the grandchild,
+ // and we will configure |child| in several ways that should force the subtree
+ // to be skipped. The visible content rect for |grandchild| should, therefore,
+ // remain empty.
+ grandchild_ptr->set_visible_rect_from_property_trees(gfx::Rect());
+ gfx::Transform singular;
+ singular.matrix().set(0, 0, 0);
+
+ child_ptr->SetTransform(singular);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0),
+ grandchild_ptr->visible_rect_from_property_trees());
+ child_ptr->SetTransform(identity);
+
+ child_ptr->SetHideLayerAndSubtree(true);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0),
+ grandchild_ptr->visible_rect_from_property_trees());
+ child_ptr->SetHideLayerAndSubtree(false);
+
+ child_ptr->SetOpacity(0.f);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0),
+ grandchild_ptr->visible_rect_from_property_trees());
+
+ // Now, even though child has zero opacity, we will configure |grandchild| and
+ // |greatgrandchild| in several ways that should force the subtree to be
+ // processed anyhow.
+ grandchild_ptr->SetTouchEventHandlerRegion(Region(gfx::Rect(0, 0, 10, 10)));
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(10, 10),
+ grandchild_ptr->visible_rect_from_property_trees());
+ grandchild_ptr->set_visible_rect_from_property_trees(gfx::Rect());
+ grandchild_ptr->SetTouchEventHandlerRegion(Region());
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0),
+ grandchild_ptr->visible_rect_from_property_trees());
+ grandchild_ptr->set_visible_rect_from_property_trees(gfx::Rect());
+
+ ScopedPtrVector<CopyOutputRequest> requests;
+ requests.push_back(CopyOutputRequest::CreateEmptyRequest());
+
+ greatgrandchild_ptr->PassCopyRequests(&requests);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(10, 10),
+ grandchild_ptr->visible_rect_from_property_trees());
+}
+
+TEST_F(LayerTreeHostCommonTest, SkippingLayer) {
+ gfx::Transform identity;
+ FakeContentLayerClient client;
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(child.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+ root->AddChild(child);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(10, 10), child->visible_rect_from_property_trees());
+ child->set_visible_rect_from_property_trees(gfx::Rect());
+
+ child->SetHideLayerAndSubtree(true);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0), child->visible_rect_from_property_trees());
+ child->SetHideLayerAndSubtree(false);
+
+ child->SetBounds(gfx::Size());
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0), child->visible_rect_from_property_trees());
+ child->SetBounds(gfx::Size(10, 10));
+
+ gfx::Transform rotate;
+ child->SetDoubleSided(false);
+ rotate.RotateAboutXAxis(180.f);
+ child->SetTransform(rotate);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0), child->visible_rect_from_property_trees());
+ child->SetDoubleSided(true);
+ child->SetTransform(identity);
+
+ child->SetOpacity(0.f);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(gfx::Rect(0, 0), child->visible_rect_from_property_trees());
+}
+
+TEST_F(LayerTreeHostCommonTest, LayerTreeRebuildTest) {
+ // Ensure that the treewalk in LayerTreeHostCommom::
+ // PreCalculateMetaInformation happens when its required.
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> parent = Layer::Create();
+ scoped_refptr<Layer> child = Layer::Create();
+
+ root->AddChild(parent);
+ parent->AddChild(child);
+
+ child->SetClipParent(root.get());
+
+ gfx::Transform identity;
+
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(parent.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(child.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(parent->draw_properties().num_unclipped_descendants, 1);
+
+ // Ensure the dynamic update to input handlers happens.
+ child->SetHaveWheelEventHandlers(true);
+ EXPECT_TRUE(root->draw_properties().layer_or_descendant_has_input_handler);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_TRUE(root->draw_properties().layer_or_descendant_has_input_handler);
+
+ child->SetHaveWheelEventHandlers(false);
+ EXPECT_FALSE(root->draw_properties().layer_or_descendant_has_input_handler);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_FALSE(root->draw_properties().layer_or_descendant_has_input_handler);
+
+ child->RequestCopyOfOutput(
+ CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+ EXPECT_TRUE(root->draw_properties().layer_or_descendant_has_copy_request);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_TRUE(root->draw_properties().layer_or_descendant_has_copy_request);
+}
+
+TEST_F(LayerTreeHostCommonTest, InputHandlersRecursiveUpdateTest) {
+ // Ensure that the treewalk in LayertreeHostCommon::
+ // PreCalculateMetaInformation updates input handlers correctly.
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> child = Layer::Create();
+
+ root->AddChild(child);
+
+ child->SetHaveWheelEventHandlers(true);
+
+ gfx::Transform identity;
+
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+ SetLayerPropertiesForTesting(child.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(100, 100), true, false);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ EXPECT_EQ(root->num_layer_or_descendants_with_input_handler(), 0);
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_EQ(root->num_layer_or_descendants_with_input_handler(), 1);
+ child->SetHaveWheelEventHandlers(false);
+ EXPECT_EQ(root->num_layer_or_descendants_with_input_handler(), 0);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index 9bee07e1118..ae6fcb8ae82 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -6,29 +6,33 @@
#include <algorithm>
#include <limits>
+#include <map>
+#include <set>
#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/containers/small_map.h"
#include "base/json/json_writer.h"
#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/scrollbar_animation_controller.h"
#include "cc/animation/timing_function.h"
-#include "cc/base/latency_info_swap_promise_monitor.h"
#include "cc/base/math_util.h"
#include "cc/base/util.h"
#include "cc/debug/benchmark_instrumentation.h"
#include "cc/debug/debug_rect_history.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/frame_rate_counter.h"
+#include "cc/debug/frame_viewer_instrumentation.h"
#include "cc/debug/paint_time_counter.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/debug/traced_value.h"
#include "cc/input/page_scale_animation.h"
+#include "cc/input/scroll_elasticity_helper.h"
#include "cc/input/top_controls_manager.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/heads_up_display_layer_impl.h"
@@ -37,41 +41,44 @@
#include "cc/layers/painted_scrollbar_layer_impl.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/layers/scrollbar_layer_impl_base.h"
+#include "cc/layers/viewport.h"
#include "cc/output/compositor_frame_metadata.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/delegating_renderer.h"
#include "cc/output/gl_renderer.h"
#include "cc/output/software_renderer.h"
+#include "cc/output/texture_mailbox_deleter.h"
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/shared_quad_state.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
-#include "cc/resources/bitmap_raster_worker_pool.h"
-#include "cc/resources/eviction_tile_priority_queue.h"
-#include "cc/resources/gpu_raster_worker_pool.h"
+#include "cc/raster/bitmap_tile_task_worker_pool.h"
+#include "cc/raster/gpu_rasterizer.h"
+#include "cc/raster/gpu_tile_task_worker_pool.h"
+#include "cc/raster/one_copy_tile_task_worker_pool.h"
+#include "cc/raster/pixel_buffer_tile_task_worker_pool.h"
+#include "cc/raster/tile_task_worker_pool.h"
+#include "cc/raster/zero_copy_tile_task_worker_pool.h"
#include "cc/resources/memory_history.h"
-#include "cc/resources/one_copy_raster_worker_pool.h"
-#include "cc/resources/picture_layer_tiling.h"
-#include "cc/resources/pixel_buffer_raster_worker_pool.h"
#include "cc/resources/prioritized_resource_manager.h"
-#include "cc/resources/raster_tile_priority_queue.h"
-#include "cc/resources/raster_worker_pool.h"
#include "cc/resources/resource_pool.h"
-#include "cc/resources/texture_mailbox_deleter.h"
#include "cc/resources/ui_resource_bitmap.h"
-#include "cc/resources/zero_copy_raster_worker_pool.h"
#include "cc/scheduler/delay_based_time_source.h"
+#include "cc/tiles/eviction_tile_priority_queue.h"
+#include "cc/tiles/picture_layer_tiling.h"
+#include "cc/tiles/raster_tile_priority_queue.h"
#include "cc/trees/damage_tracker.h"
+#include "cc/trees/latency_info_swap_promise_monitor.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
-#include "cc/trees/occlusion_tracker.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
#include "ui/gfx/frame_time.h"
#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/scroll_offset.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
@@ -85,10 +92,10 @@ class ViewportAnchor {
ViewportAnchor(LayerImpl* inner_scroll, LayerImpl* outer_scroll)
: inner_(inner_scroll),
outer_(outer_scroll) {
- viewport_in_content_coordinates_ = inner_->TotalScrollOffset();
+ viewport_in_content_coordinates_ = inner_->CurrentScrollOffset();
if (outer_)
- viewport_in_content_coordinates_ += outer_->TotalScrollOffset();
+ viewport_in_content_coordinates_ += outer_->CurrentScrollOffset();
}
void ResetViewportToAnchoredPosition() {
@@ -97,8 +104,8 @@ class ViewportAnchor {
inner_->ClampScrollToMaxScrollOffset();
outer_->ClampScrollToMaxScrollOffset();
- gfx::ScrollOffset viewport_location = inner_->TotalScrollOffset() +
- outer_->TotalScrollOffset();
+ gfx::ScrollOffset viewport_location =
+ inner_->CurrentScrollOffset() + outer_->CurrentScrollOffset();
gfx::Vector2dF delta =
viewport_in_content_coordinates_.DeltaFrom(viewport_location);
@@ -113,18 +120,14 @@ class ViewportAnchor {
gfx::ScrollOffset viewport_in_content_coordinates_;
};
-
void DidVisibilityChange(LayerTreeHostImpl* id, bool visible) {
if (visible) {
- TRACE_EVENT_ASYNC_BEGIN1("webkit",
- "LayerTreeHostImpl::SetVisible",
- id,
- "LayerTreeHostImpl",
- id);
+ TRACE_EVENT_ASYNC_BEGIN1("cc", "LayerTreeHostImpl::SetVisible", id,
+ "LayerTreeHostImpl", id);
return;
}
- TRACE_EVENT_ASYNC_END0("webkit", "LayerTreeHostImpl::SetVisible", id);
+ TRACE_EVENT_ASYNC_END0("cc", "LayerTreeHostImpl::SetVisible", id);
}
size_t GetMaxTransferBufferUsageBytes(
@@ -150,22 +153,6 @@ size_t GetMaxTransferBufferUsageBytes(
max_transfer_buffer_usage_bytes);
}
-unsigned GetMapImageTextureTarget(
- const ContextProvider::Capabilities& context_capabilities) {
-// TODO(reveman): This should be a setting passed to the compositor instead
-// of hard-coded here. The target that need to be used depends on our choice
-// of GpuMemoryBuffer type. Note: SURFACE_TEXTURE needs EXTERNAL_OES,
-// IO_SURFACE needs RECTANGLE_ARB. crbug.com/431059
-#if defined(OS_ANDROID)
- if (context_capabilities.gpu.egl_image_external)
- return GL_TEXTURE_EXTERNAL_OES;
-#endif
- if (context_capabilities.gpu.texture_rectangle)
- return GL_TEXTURE_RECTANGLE_ARB;
-
- return GL_TEXTURE_2D;
-}
-
size_t GetMaxStagingResourceCount() {
// Upper bound for number of staging resource to allow.
return 32;
@@ -173,79 +160,8 @@ size_t GetMaxStagingResourceCount() {
} // namespace
-class LayerTreeHostImplTimeSourceAdapter : public TimeSourceClient {
- public:
- static scoped_ptr<LayerTreeHostImplTimeSourceAdapter> Create(
- LayerTreeHostImpl* layer_tree_host_impl,
- scoped_refptr<DelayBasedTimeSource> time_source) {
- return make_scoped_ptr(
- new LayerTreeHostImplTimeSourceAdapter(layer_tree_host_impl,
- time_source));
- }
- ~LayerTreeHostImplTimeSourceAdapter() override {
- time_source_->SetClient(NULL);
- time_source_->SetActive(false);
- }
-
- void OnTimerTick() override {
- // In single threaded mode we attempt to simulate changing the current
- // thread by maintaining a fake thread id. When we switch from one
- // thread to another, we construct DebugScopedSetXXXThread objects that
- // update the thread id. This lets DCHECKS that ensure we're on the
- // right thread to work correctly in single threaded mode. The problem
- // here is that the timer tasks are run via the message loop, and when
- // they run, we've had no chance to construct a DebugScopedSetXXXThread
- // object. The result is that we report that we're running on the main
- // thread. In multi-threaded mode, this timer is run on the compositor
- // thread, so to keep this consistent in single-threaded mode, we'll
- // construct a DebugScopedSetImplThread object. There is no need to do
- // this in multi-threaded mode since the real thread id's will be
- // correct. In fact, setting fake thread id's interferes with the real
- // thread id's and causes breakage.
- scoped_ptr<DebugScopedSetImplThread> set_impl_thread;
- if (!layer_tree_host_impl_->proxy()->HasImplThread()) {
- set_impl_thread.reset(
- new DebugScopedSetImplThread(layer_tree_host_impl_->proxy()));
- }
-
- layer_tree_host_impl_->Animate(
- layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
- layer_tree_host_impl_->UpdateBackgroundAnimateTicking(true);
- bool start_ready_animations = true;
- layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
-
- if (layer_tree_host_impl_->pending_tree()) {
- layer_tree_host_impl_->pending_tree()->UpdateDrawProperties();
- layer_tree_host_impl_->ManageTiles();
- }
-
- layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
- }
-
- void SetActive(bool active) {
- if (active != time_source_->Active())
- time_source_->SetActive(active);
- }
-
- bool Active() const { return time_source_->Active(); }
-
- private:
- LayerTreeHostImplTimeSourceAdapter(
- LayerTreeHostImpl* layer_tree_host_impl,
- scoped_refptr<DelayBasedTimeSource> time_source)
- : layer_tree_host_impl_(layer_tree_host_impl),
- time_source_(time_source) {
- time_source_->SetClient(this);
- }
-
- LayerTreeHostImpl* layer_tree_host_impl_;
- scoped_refptr<DelayBasedTimeSource> time_source_;
-
- DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImplTimeSourceAdapter);
-};
-
-LayerTreeHostImpl::FrameData::FrameData()
- : contains_incomplete_tile(false), has_no_damage(false) {}
+LayerTreeHostImpl::FrameData::FrameData() : has_no_damage(false) {
+}
LayerTreeHostImpl::FrameData::~FrameData() {}
@@ -256,14 +172,11 @@ scoped_ptr<LayerTreeHostImpl> LayerTreeHostImpl::Create(
RenderingStatsInstrumentation* rendering_stats_instrumentation,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
int id) {
- return make_scoped_ptr(new LayerTreeHostImpl(settings,
- client,
- proxy,
- rendering_stats_instrumentation,
- shared_bitmap_manager,
- gpu_memory_buffer_manager,
- id));
+ return make_scoped_ptr(new LayerTreeHostImpl(
+ settings, client, proxy, rendering_stats_instrumentation,
+ shared_bitmap_manager, gpu_memory_buffer_manager, task_graph_runner, id));
}
LayerTreeHostImpl::LayerTreeHostImpl(
@@ -273,11 +186,16 @@ LayerTreeHostImpl::LayerTreeHostImpl(
RenderingStatsInstrumentation* rendering_stats_instrumentation,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
int id)
- : BeginFrameSourceMixIn(),
- client_(client),
+ : client_(client),
proxy_(proxy),
+ content_is_suitable_for_gpu_rasterization_(true),
+ has_gpu_rasterization_trigger_(false),
use_gpu_rasterization_(false),
+ use_msaa_(false),
+ gpu_rasterization_status_(GpuRasterizationStatus::OFF_DEVICE),
+ tree_resources_for_gpu_rasterization_dirty_(false),
input_handler_client_(NULL),
did_lock_scrolling_layer_(false),
should_bubble_scrolls_(false),
@@ -302,19 +220,19 @@ LayerTreeHostImpl::LayerTreeHostImpl(
proxy_->HasImplThread() ? proxy_->ImplThreadTaskRunner()
: proxy_->MainThreadTaskRunner())),
max_memory_needed_bytes_(0),
- zero_budget_(false),
device_scale_factor_(1.f),
- overhang_ui_resource_id_(0),
resourceless_software_draw_(false),
begin_impl_frame_interval_(BeginFrameArgs::DefaultInterval()),
animation_registrar_(AnimationRegistrar::Create()),
rendering_stats_instrumentation_(rendering_stats_instrumentation),
micro_benchmark_controller_(this),
- need_to_update_visible_tiles_before_draw_(false),
shared_bitmap_manager_(shared_bitmap_manager),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+ task_graph_runner_(task_graph_runner),
id_(id),
- requires_high_res_to_draw_(false) {
+ requires_high_res_to_draw_(false),
+ is_likely_to_require_a_draw_(false),
+ frame_timing_tracker_(FrameTimingTracker::Create()) {
DCHECK(proxy_->IsImplThread());
DidVisibilityChange(this, visible_);
animation_registrar_->set_supports_scroll_animations(
@@ -323,23 +241,19 @@ LayerTreeHostImpl::LayerTreeHostImpl(
SetDebugState(settings.initial_debug_state);
// LTHI always has an active tree.
- active_tree_ = LayerTreeImpl::create(this);
+ active_tree_ =
+ LayerTreeImpl::create(this, new SyncedProperty<ScaleGroup>(),
+ new SyncedTopControls, new SyncedElasticOverscroll);
+
+ viewport_ = Viewport::Create(this);
+
TRACE_EVENT_OBJECT_CREATED_WITH_ID(
TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", id_);
- if (settings.calculate_top_controls_position) {
- top_controls_manager_ =
- TopControlsManager::Create(this,
- settings.top_controls_height,
- settings.top_controls_show_threshold,
- settings.top_controls_hide_threshold);
-
- // TODO(bokan): This is a quick fix. The browser should lock the top
- // controls to shown on creation but this appears not to work. Tracked
- // in crbug.com/417680.
- // Initialize with top controls showing.
- SetControlsTopOffset(0.f);
- }
+ top_controls_manager_ =
+ TopControlsManager::Create(this,
+ settings.top_controls_show_threshold,
+ settings.top_controls_hide_threshold);
}
LayerTreeHostImpl::~LayerTreeHostImpl() {
@@ -352,6 +266,8 @@ LayerTreeHostImpl::~LayerTreeHostImpl() {
input_handler_client_->WillShutdown();
input_handler_client_ = NULL;
}
+ if (scroll_elasticity_helper_)
+ scroll_elasticity_helper_.reset();
// The layer trees must be destroyed before the layer tree host. We've
// made a contract with our animation controllers that the registrar
@@ -367,11 +283,11 @@ LayerTreeHostImpl::~LayerTreeHostImpl() {
DestroyTileManager();
}
-void LayerTreeHostImpl::BeginMainFrameAborted(bool did_handle) {
+void LayerTreeHostImpl::BeginMainFrameAborted(CommitEarlyOutReason reason) {
// If the begin frame data was handled, then scroll and scale set was applied
// by the main thread, so the active tree needs to be updated as if these sent
// values were applied and committed.
- if (did_handle) {
+ if (CommitEarlyOutHandledCommit(reason)) {
active_tree_->ApplySentScrollAndScaleDeltasFromAbortedCommit();
active_tree_->ResetContentsTexturesPurged();
}
@@ -380,27 +296,45 @@ void LayerTreeHostImpl::BeginMainFrameAborted(bool did_handle) {
void LayerTreeHostImpl::BeginCommit() {
TRACE_EVENT0("cc", "LayerTreeHostImpl::BeginCommit");
- if (UsePendingTreeForSync())
+ // Ensure all textures are returned so partial texture updates can happen
+ // during the commit. Impl-side-painting doesn't upload during commits, so
+ // is unaffected.
+ if (!settings_.impl_side_painting && output_surface_)
+ output_surface_->ForceReclaimResources();
+
+ if (settings_.impl_side_painting && !proxy_->CommitToActiveTree())
CreatePendingTree();
}
void LayerTreeHostImpl::CommitComplete() {
TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete");
- if (pending_tree_)
- pending_tree_->ApplyScrollDeltasSinceBeginMainFrame();
+ // LayerTreeHost may have changed the GPU rasterization flags state, which
+ // may require an update of the tree resources.
+ UpdateTreeResourcesForGpuRasterizationIfNeeded();
sync_tree()->set_needs_update_draw_properties();
if (settings_.impl_side_painting) {
// Impl-side painting needs an update immediately post-commit to have the
// opportunity to create tilings. Other paths can call UpdateDrawProperties
- // more lazily when needed prior to drawing.
- sync_tree()->UpdateDrawProperties();
+ // more lazily when needed prior to drawing. Because invalidations may
+ // be coming from the main thread, it's safe to do an update for lcd text
+ // at this point and see if lcd text needs to be disabled on any layers.
+ bool update_lcd_text = true;
+ sync_tree()->UpdateDrawProperties(update_lcd_text);
// Start working on newly created tiles immediately if needed.
- if (tile_manager_ && tile_priorities_dirty_)
- ManageTiles();
- else
+ if (tile_manager_ && tile_priorities_dirty_) {
+ PrepareTiles();
+ } else {
NotifyReadyToActivate();
+
+ // Ensure we get ReadyToDraw signal even when PrepareTiles not run. This
+ // is important for SingleThreadProxy and impl-side painting case. For
+ // STP, we commit to active tree and RequiresHighResToDraw, and set
+ // Scheduler to wait for ReadyToDraw signal to avoid Checkerboard.
+ if (proxy_->CommitToActiveTree())
+ NotifyReadyToDraw();
+ }
} else {
// If we're not in impl-side painting, the tree is immediately considered
// active.
@@ -471,16 +405,56 @@ void LayerTreeHostImpl::Animate(base::TimeTicks monotonic_time) {
AnimateTopControls(monotonic_time);
}
-void LayerTreeHostImpl::ManageTiles() {
+void LayerTreeHostImpl::PrepareTiles() {
if (!tile_manager_)
return;
if (!tile_priorities_dirty_)
return;
tile_priorities_dirty_ = false;
- tile_manager_->ManageTiles(global_tile_state_);
+ tile_manager_->PrepareTiles(global_tile_state_);
- client_->DidManageTiles();
+ client_->DidPrepareTiles();
+}
+
+void LayerTreeHostImpl::StartPageScaleAnimation(
+ const gfx::Vector2d& target_offset,
+ bool anchor_point,
+ float page_scale,
+ base::TimeDelta duration) {
+ if (!InnerViewportScrollLayer())
+ return;
+
+ gfx::ScrollOffset scroll_total = active_tree_->TotalScrollOffset();
+ gfx::SizeF scaled_scrollable_size = active_tree_->ScrollableSize();
+ gfx::SizeF viewport_size =
+ active_tree_->InnerViewportContainerLayer()->bounds();
+
+ // Easing constants experimentally determined.
+ scoped_ptr<TimingFunction> timing_function =
+ CubicBezierTimingFunction::Create(.8, 0, .3, .9);
+
+ // TODO(miletus) : Pass in ScrollOffset.
+ page_scale_animation_ = PageScaleAnimation::Create(
+ ScrollOffsetToVector2dF(scroll_total),
+ active_tree_->current_page_scale_factor(), viewport_size,
+ scaled_scrollable_size, timing_function.Pass());
+
+ if (anchor_point) {
+ gfx::Vector2dF anchor(target_offset);
+ page_scale_animation_->ZoomWithAnchor(anchor,
+ page_scale,
+ duration.InSecondsF());
+ } else {
+ gfx::Vector2dF scaled_target_offset = target_offset;
+ page_scale_animation_->ZoomTo(scaled_target_offset,
+ page_scale,
+ duration.InSecondsF());
+ }
+
+ SetNeedsAnimate();
+ client_->SetNeedsCommitOnImplThread();
+ client_->RenewTreePriority();
}
bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt(
@@ -498,22 +472,72 @@ bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt(
bool scroll_on_main_thread = false;
LayerImpl* scrolling_layer_impl = FindScrollLayerForDeviceViewportPoint(
device_viewport_point, type, layer_impl, &scroll_on_main_thread, NULL);
- return CurrentlyScrollingLayer() == scrolling_layer_impl;
+
+ if (!scrolling_layer_impl)
+ return false;
+
+ if (CurrentlyScrollingLayer() == scrolling_layer_impl)
+ return true;
+
+ // For active scrolling state treat the inner/outer viewports interchangeably.
+ if ((CurrentlyScrollingLayer() == InnerViewportScrollLayer() &&
+ scrolling_layer_impl == OuterViewportScrollLayer()) ||
+ (CurrentlyScrollingLayer() == OuterViewportScrollLayer() &&
+ scrolling_layer_impl == InnerViewportScrollLayer())) {
+ return true;
+ }
+
+ return false;
}
-bool LayerTreeHostImpl::HaveTouchEventHandlersAt(
+bool LayerTreeHostImpl::HaveWheelEventHandlersAt(
const gfx::Point& viewport_point) {
-
gfx::PointF device_viewport_point =
gfx::ScalePoint(viewport_point, device_scale_factor_);
LayerImpl* layer_impl =
- active_tree_->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ active_tree_->FindLayerWithWheelHandlerThatIsHitByPoint(
device_viewport_point);
return layer_impl != NULL;
}
+static LayerImpl* NextScrollLayer(LayerImpl* layer) {
+ if (LayerImpl* scroll_parent = layer->scroll_parent())
+ return scroll_parent;
+ return layer->parent();
+}
+
+static ScrollBlocksOn EffectiveScrollBlocksOn(LayerImpl* layer) {
+ ScrollBlocksOn blocks = SCROLL_BLOCKS_ON_NONE;
+ for (; layer; layer = NextScrollLayer(layer)) {
+ blocks |= layer->scroll_blocks_on();
+ }
+ return blocks;
+}
+
+bool LayerTreeHostImpl::DoTouchEventsBlockScrollAt(
+ const gfx::Point& viewport_point) {
+ gfx::PointF device_viewport_point =
+ gfx::ScalePoint(viewport_point, device_scale_factor_);
+
+ // First check if scrolling at this point is required to block on any
+ // touch event handlers. Note that we must start at the innermost layer
+ // (as opposed to only the layer found to contain a touch handler region
+ // below) to ensure all relevant scroll-blocks-on values are applied.
+ LayerImpl* layer_impl =
+ active_tree_->FindLayerThatIsHitByPoint(device_viewport_point);
+ ScrollBlocksOn blocking = EffectiveScrollBlocksOn(layer_impl);
+ if (!(blocking & SCROLL_BLOCKS_ON_START_TOUCH))
+ return false;
+
+ // Now determine if there are actually any handlers at that point.
+ // TODO(rbyers): Consider also honoring touch-action (crbug.com/347272).
+ layer_impl = active_tree_->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ device_viewport_point);
+ return layer_impl != NULL;
+}
+
scoped_ptr<SwapPromiseMonitor>
LayerTreeHostImpl::CreateLatencyInfoSwapPromiseMonitor(
ui::LatencyInfo* latency) {
@@ -521,6 +545,15 @@ LayerTreeHostImpl::CreateLatencyInfoSwapPromiseMonitor(
new LatencyInfoSwapPromiseMonitor(latency, NULL, this));
}
+ScrollElasticityHelper* LayerTreeHostImpl::CreateScrollElasticityHelper() {
+ DCHECK(!scroll_elasticity_helper_);
+ if (settings_.enable_elastic_overscroll) {
+ scroll_elasticity_helper_.reset(
+ ScrollElasticityHelper::CreateForLayerTreeHostImpl(this));
+ }
+ return scroll_elasticity_helper_.get();
+}
+
void LayerTreeHostImpl::QueueSwapPromiseForMainThreadScrollUpdate(
scoped_ptr<SwapPromise> swap_promise) {
swap_promises_for_main_thread_scroll_update_.push_back(swap_promise.Pass());
@@ -551,8 +584,7 @@ void LayerTreeHostImpl::TrackDamageForAllSurfaces(
}
void LayerTreeHostImpl::FrameData::AsValueInto(
- base::debug::TracedValue* value) const {
- value->SetBoolean("contains_incomplete_tile", contains_incomplete_tile);
+ base::trace_event::TracedValue* value) const {
value->SetBoolean("has_no_damage", has_no_damage);
// Quad data can be quite large, so only dump render passes if we select
@@ -583,75 +615,61 @@ DrawMode LayerTreeHostImpl::GetDrawMode() const {
} else if (output_surface_->context_provider()) {
return DRAW_MODE_HARDWARE;
} else {
- DCHECK_EQ(!output_surface_->software_device(),
- output_surface_->capabilities().delegated_rendering &&
- !output_surface_->capabilities().deferred_gl_initialization)
- << output_surface_->capabilities().delegated_rendering << " "
- << output_surface_->capabilities().deferred_gl_initialization;
return DRAW_MODE_SOFTWARE;
}
}
-static void AppendQuadsForLayer(
- RenderPass* target_render_pass,
- LayerImpl* layer,
- const OcclusionTracker<LayerImpl>& occlusion_tracker,
- AppendQuadsData* append_quads_data) {
- layer->AppendQuads(
- target_render_pass,
- occlusion_tracker.GetCurrentOcclusionForLayer(layer->draw_transform()),
- append_quads_data);
-}
-
static void AppendQuadsForRenderSurfaceLayer(
RenderPass* target_render_pass,
LayerImpl* layer,
const RenderPass* contributing_render_pass,
- const OcclusionTracker<LayerImpl>& occlusion_tracker,
AppendQuadsData* append_quads_data) {
- bool is_replica = false;
- layer->render_surface()->AppendQuads(target_render_pass,
- occlusion_tracker,
- append_quads_data,
- is_replica,
- contributing_render_pass->id);
+ RenderSurfaceImpl* surface = layer->render_surface();
+ const gfx::Transform& draw_transform = surface->draw_transform();
+ const Occlusion& occlusion = surface->occlusion_in_content_space();
+ SkColor debug_border_color = surface->GetDebugBorderColor();
+ float debug_border_width = surface->GetDebugBorderWidth();
+ LayerImpl* mask_layer = layer->mask_layer();
+
+ surface->AppendQuads(target_render_pass, draw_transform, occlusion,
+ debug_border_color, debug_border_width, mask_layer,
+ append_quads_data, contributing_render_pass->id);
// Add replica after the surface so that it appears below the surface.
if (layer->has_replica()) {
- is_replica = true;
- layer->render_surface()->AppendQuads(target_render_pass,
- occlusion_tracker,
- append_quads_data,
- is_replica,
- contributing_render_pass->id);
- }
-}
-
-static void AppendQuadsToFillScreen(
- ResourceProvider::ResourceId overhang_resource_id,
- const gfx::SizeF& overhang_resource_scaled_size,
- const gfx::Rect& root_scroll_layer_rect,
- RenderPass* target_render_pass,
- LayerImpl* root_layer,
- SkColor screen_background_color,
- const OcclusionTracker<LayerImpl>& occlusion_tracker) {
+ const gfx::Transform& replica_draw_transform =
+ surface->replica_draw_transform();
+ Occlusion replica_occlusion = occlusion.GetOcclusionWithGivenDrawTransform(
+ surface->replica_draw_transform());
+ SkColor replica_debug_border_color = surface->GetReplicaDebugBorderColor();
+ float replica_debug_border_width = surface->GetReplicaDebugBorderWidth();
+ // TODO(danakj): By using the same RenderSurfaceImpl for both the
+ // content and its reflection, it's currently not possible to apply a
+ // separate mask to the reflection layer or correctly handle opacity in
+ // reflections (opacity must be applied after drawing both the layer and its
+ // reflection). The solution is to introduce yet another RenderSurfaceImpl
+ // to draw the layer and its reflection in. For now we only apply a separate
+ // reflection mask if the contents don't have a mask of their own.
+ LayerImpl* replica_mask_layer =
+ mask_layer ? mask_layer : layer->replica_layer()->mask_layer();
+
+ surface->AppendQuads(target_render_pass, replica_draw_transform,
+ replica_occlusion, replica_debug_border_color,
+ replica_debug_border_width, replica_mask_layer,
+ append_quads_data, contributing_render_pass->id);
+ }
+}
+
+static void AppendQuadsToFillScreen(const gfx::Rect& root_scroll_layer_rect,
+ RenderPass* target_render_pass,
+ LayerImpl* root_layer,
+ SkColor screen_background_color,
+ const Region& fill_region) {
if (!root_layer || !SkColorGetA(screen_background_color))
return;
-
- Region fill_region = occlusion_tracker.ComputeVisibleRegionInScreen();
if (fill_region.IsEmpty())
return;
- // Divide the fill region into the part to be filled with the overhang
- // resource and the part to be filled with the background color.
- Region screen_background_color_region = fill_region;
- Region overhang_region;
- if (overhang_resource_id) {
- overhang_region = fill_region;
- overhang_region.Subtract(root_scroll_layer_rect);
- screen_background_color_region.Intersect(root_scroll_layer_rect);
- }
-
// Manually create the quad state for the gutter quads, as the root layer
// doesn't have any bounds and so can't generate this itself.
// TODO(danakj): Make the gutter quads generated by the solid color layer
@@ -671,8 +689,7 @@ static void AppendQuadsToFillScreen(
SkXfermode::kSrcOver_Mode,
sorting_context_id);
- for (Region::Iterator fill_rects(screen_background_color_region);
- fill_rects.has_rect();
+ for (Region::Iterator fill_rects(fill_region); fill_rects.has_rect();
fill_rects.next()) {
gfx::Rect screen_space_rect = fill_rects.rect();
gfx::Rect visible_screen_space_rect = screen_space_rect;
@@ -686,34 +703,6 @@ static void AppendQuadsToFillScreen(
screen_background_color,
false);
}
- for (Region::Iterator fill_rects(overhang_region);
- fill_rects.has_rect();
- fill_rects.next()) {
- DCHECK(overhang_resource_id);
- gfx::Rect screen_space_rect = fill_rects.rect();
- gfx::Rect opaque_screen_space_rect = screen_space_rect;
- gfx::Rect visible_screen_space_rect = screen_space_rect;
- TextureDrawQuad* tex_quad =
- target_render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- const float vertex_opacity[4] = {1.f, 1.f, 1.f, 1.f};
- tex_quad->SetNew(
- shared_quad_state,
- screen_space_rect,
- opaque_screen_space_rect,
- visible_screen_space_rect,
- overhang_resource_id,
- false,
- gfx::PointF(
- screen_space_rect.x() / overhang_resource_scaled_size.width(),
- screen_space_rect.y() / overhang_resource_scaled_size.height()),
- gfx::PointF(
- screen_space_rect.right() / overhang_resource_scaled_size.width(),
- screen_space_rect.bottom() /
- overhang_resource_scaled_size.height()),
- screen_background_color,
- vertex_opacity,
- false);
- }
}
DrawResult LayerTreeHostImpl::CalculateRenderPasses(
@@ -739,6 +728,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
if (root_surface_has_contributing_layers &&
root_surface_has_no_visible_damage &&
active_tree_->LayersWithCopyOutputRequest().empty() &&
+ !output_surface_->capabilities().can_force_reclaim_resources &&
!hud_wants_to_draw_) {
TRACE_EVENT0("cc",
"LayerTreeHostImpl::CalculateRenderPasses::EmptyDamageRect");
@@ -748,10 +738,11 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
return DRAW_SUCCESS;
}
- TRACE_EVENT1("cc",
- "LayerTreeHostImpl::CalculateRenderPasses",
- "render_surface_layer_list.size()",
- static_cast<uint64>(frame->render_surface_layer_list->size()));
+ TRACE_EVENT_BEGIN2(
+ "cc", "LayerTreeHostImpl::CalculateRenderPasses",
+ "render_surface_layer_list.size()",
+ static_cast<uint64>(frame->render_surface_layer_list->size()),
+ "RequiresHighResToDraw", RequiresHighResToDraw());
// Create the render passes in dependency order.
for (int surface_index = frame->render_surface_layer_list->size() - 1;
@@ -766,7 +757,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
render_surface->contributes_to_drawn_surface() ||
render_surface_layer->HasCopyRequest();
if (should_draw_into_render_pass)
- render_surface_layer->render_surface()->AppendRenderPasses(frame);
+ render_surface->AppendRenderPasses(frame);
}
// When we are displaying the HUD, change the root damage rect to cover the
@@ -780,32 +771,20 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
root_pass->damage_rect = root_pass->output_rect;
}
- OcclusionTracker<LayerImpl> occlusion_tracker(
- active_tree_->root_layer()->render_surface()->content_rect());
- occlusion_tracker.set_minimum_tracking_size(
- settings_.minimum_occlusion_tracking_size);
-
- if (debug_state_.show_occluding_rects) {
- occlusion_tracker.set_occluding_screen_space_rects_container(
- &frame->occluding_screen_space_rects);
- }
- if (debug_state_.show_non_occluding_rects) {
- occlusion_tracker.set_non_occluding_screen_space_rects_container(
- &frame->non_occluding_screen_space_rects);
- }
-
- // Add quads to the Render passes in front-to-back order to allow for testing
- // occlusion and performing culling during the tree walk.
- typedef LayerIterator<LayerImpl> LayerIteratorType;
+ // Grab this region here before iterating layers. Taking copy requests from
+ // the layers while constructing the render passes will dirty the render
+ // surface layer list and this unoccluded region, flipping the dirty bit to
+ // true, and making us able to query for it without doing
+ // UpdateDrawProperties again. The value inside the Region is not actually
+ // changed until UpdateDrawProperties happens, so a reference to it is safe.
+ const Region& unoccluded_screen_space_region =
+ active_tree_->UnoccludedScreenSpaceRegion();
// Typically when we are missing a texture and use a checkerboard quad, we
// still draw the frame. However when the layer being checkerboarded is moving
// due to an impl-animation, we drop the frame to avoid flashing due to the
// texture suddenly appearing in the future.
DrawResult draw_result = DRAW_SUCCESS;
- // When we have a copy request for a layer, we need to draw no matter
- // what, as the layer may disappear after this frame.
- bool have_copy_request = false;
int layers_drawn = 0;
@@ -813,21 +792,19 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
int num_missing_tiles = 0;
int num_incomplete_tiles = 0;
+ bool have_copy_request = false;
+ bool have_missing_animated_tiles = false;
- LayerIteratorType end =
- LayerIteratorType::End(frame->render_surface_layer_list);
- for (LayerIteratorType it =
- LayerIteratorType::Begin(frame->render_surface_layer_list);
- it != end;
- ++it) {
+ auto end = LayerIterator<LayerImpl>::End(frame->render_surface_layer_list);
+ for (auto it =
+ LayerIterator<LayerImpl>::Begin(frame->render_surface_layer_list);
+ it != end; ++it) {
RenderPassId target_render_pass_id =
it.target_render_surface_layer()->render_surface()->GetRenderPassId();
RenderPass* target_render_pass =
frame->render_passes_by_id[target_render_pass_id];
- occlusion_tracker.EnterLayer(it);
-
- AppendQuadsData append_quads_data(target_render_pass_id);
+ AppendQuadsData append_quads_data;
if (it.represents_target_render_surface()) {
if (it->HasCopyRequest()) {
@@ -844,13 +821,12 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
AppendQuadsForRenderSurfaceLayer(target_render_pass,
*it,
contributing_render_pass,
- occlusion_tracker,
&append_quads_data);
} else if (it.represents_itself() &&
!it->visible_content_rect().IsEmpty()) {
bool occluded =
- occlusion_tracker.GetCurrentOcclusionForLayer(it->draw_transform())
- .IsOccluded(it->visible_content_rect());
+ it->draw_properties().occlusion_in_content_space.IsOccluded(
+ it->visible_content_rect());
if (!occluded && it->WillDraw(draw_mode, resource_provider_.get())) {
DCHECK_EQ(active_tree_, it->layer_tree_impl());
@@ -864,21 +840,26 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
RenderPass* render_pass =
frame->render_passes_by_id[contributing_render_pass_id];
- AppendQuadsData append_quads_data(render_pass->id);
- AppendQuadsForLayer(render_pass,
- *it,
- occlusion_tracker,
- &append_quads_data);
+ it->AppendQuads(render_pass, &append_quads_data);
contributing_render_pass_id =
it->NextContributingRenderPassId(contributing_render_pass_id);
}
}
- AppendQuadsForLayer(target_render_pass,
- *it,
- occlusion_tracker,
- &append_quads_data);
+ it->AppendQuads(target_render_pass, &append_quads_data);
+
+ // For layers that represent themselves, add composite frame timing
+ // requests if the visible rect intersects the requested rect.
+ for (const auto& request : it->frame_timing_requests()) {
+ const gfx::Rect& request_content_rect =
+ it->LayerRectToContentRect(request.rect());
+ if (request_content_rect.Intersects(it->visible_content_rect())) {
+ frame->composite_events.push_back(
+ FrameTimingTracker::FrameAndRectIds(
+ active_tree_->source_frame_number(), request.id()));
+ }
+ }
}
++layers_drawn;
@@ -888,6 +869,8 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
append_quads_data.visible_content_area);
rendering_stats_instrumentation_->AddApproximatedVisibleContentArea(
append_quads_data.approximated_visible_content_area);
+ rendering_stats_instrumentation_->AddCheckerboardedVisibleContentArea(
+ append_quads_data.checkerboarded_visible_content_area);
num_missing_tiles += append_quads_data.num_missing_tiles;
num_incomplete_tiles += append_quads_data.num_incomplete_tiles;
@@ -897,24 +880,30 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
it->screen_space_transform_is_animating() ||
it->draw_transform_is_animating();
if (layer_has_animating_transform)
- draw_result = DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
+ have_missing_animated_tiles = true;
}
+ }
- if (append_quads_data.num_incomplete_tiles ||
- append_quads_data.num_missing_tiles) {
- frame->contains_incomplete_tile = true;
- if (RequiresHighResToDraw())
- draw_result = DRAW_ABORTED_MISSING_HIGH_RES_CONTENT;
- }
+ if (have_missing_animated_tiles)
+ draw_result = DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
- occlusion_tracker.LeaveLayer(it);
+ // When we require high res to draw, abort the draw (almost) always. This does
+ // not cause the scheduler to do a main frame, instead it will continue to try
+ // drawing until we finally complete, so the copy request will not be lost.
+ // TODO(weiliangc): Remove RequiresHighResToDraw. crbug.com/469175
+ if (num_incomplete_tiles || num_missing_tiles) {
+ if (RequiresHighResToDraw())
+ draw_result = DRAW_ABORTED_MISSING_HIGH_RES_CONTENT;
}
- if (have_copy_request ||
- output_surface_->capabilities().draw_and_swap_full_viewport_every_frame)
+ // When this capability is set we don't have control over the surface the
+ // compositor draws to, so even though the frame may not be complete, the
+ // previous frame has already been potentially lost, so an incomplete frame is
+ // better than nothing, so this takes highest precidence.
+ if (output_surface_->capabilities().draw_and_swap_full_viewport_every_frame)
draw_result = DRAW_SUCCESS;
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
for (const auto& render_pass : frame->render_passes) {
for (const auto& quad : render_pass->quad_list)
DCHECK(quad->shared_quad_state);
@@ -927,16 +916,12 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
if (!active_tree_->has_transparent_background()) {
frame->render_passes.back()->has_transparent_background = false;
AppendQuadsToFillScreen(
- ResourceIdForUIResource(overhang_ui_resource_id_),
- gfx::ScaleSize(overhang_ui_resource_size_, device_scale_factor_),
active_tree_->RootScrollLayerDeviceViewportBounds(),
- frame->render_passes.back(),
- active_tree_->root_layer(),
- active_tree_->background_color(),
- occlusion_tracker);
+ frame->render_passes.back(), active_tree_->root_layer(),
+ active_tree_->background_color(), unoccluded_screen_space_region);
}
- RemoveRenderPasses(CullRenderPassesWithNoQuads(), frame);
+ RemoveRenderPasses(frame);
renderer_->DecideRenderPassAllocationsForFrame(frame->render_passes);
// Any copy requests left in the tree are not going to get serviced, and
@@ -966,36 +951,28 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(
frame->render_passes.size() == 1u)
<< frame->render_passes.size();
+ TRACE_EVENT_END2("cc", "LayerTreeHostImpl::CalculateRenderPasses",
+ "draw_result", draw_result, "missing tiles",
+ num_missing_tiles);
+
+ // Draw has to be successful to not drop the copy request layer.
+ // When we have a copy request for a layer, we need to draw even if there
+ // would be animating checkerboards, because failing under those conditions
+ // triggers a new main frame, which may cause the copy request layer to be
+ // destroyed.
+ // TODO(weiliangc): Test copy request w/ output surface recreation. Would
+ // trigger this DCHECK.
+ DCHECK_IMPLIES(have_copy_request, draw_result == DRAW_SUCCESS);
+
return draw_result;
}
void LayerTreeHostImpl::MainThreadHasStoppedFlinging() {
+ top_controls_manager_->MainThreadHasStoppedFlinging();
if (input_handler_client_)
input_handler_client_->MainThreadHasStoppedFlinging();
}
-void LayerTreeHostImpl::UpdateBackgroundAnimateTicking(
- bool should_background_tick) {
- DCHECK(proxy_->IsImplThread());
- if (should_background_tick)
- DCHECK(active_tree_->root_layer());
-
- bool enabled = should_background_tick && needs_animate_layers();
-
- // Lazily create the time_source adapter so that we can vary the interval for
- // testing.
- if (!time_source_client_adapter_) {
- time_source_client_adapter_ = LayerTreeHostImplTimeSourceAdapter::Create(
- this,
- DelayBasedTimeSource::Create(
- LowFrequencyAnimationInterval(),
- proxy_->HasImplThread() ? proxy_->ImplThreadTaskRunner()
- : proxy_->MainThreadTaskRunner()));
- }
-
- time_source_client_adapter_->SetActive(enabled);
-}
-
void LayerTreeHostImpl::DidAnimateScrollOffset() {
client_->SetNeedsCommitOnImplThread();
client_->RenewTreePriority();
@@ -1005,138 +982,39 @@ void LayerTreeHostImpl::SetViewportDamage(const gfx::Rect& damage_rect) {
viewport_damage_rect_.Union(damage_rect);
}
-static inline RenderPass* FindRenderPassById(
- RenderPassId render_pass_id,
- const LayerTreeHostImpl::FrameData& frame) {
- RenderPassIdHashMap::const_iterator it =
- frame.render_passes_by_id.find(render_pass_id);
- return it != frame.render_passes_by_id.end() ? it->second : NULL;
-}
-
-static void RemoveRenderPassesRecursive(RenderPassId remove_render_pass_id,
- LayerTreeHostImpl::FrameData* frame) {
- RenderPass* remove_render_pass =
- FindRenderPassById(remove_render_pass_id, *frame);
- // The pass was already removed by another quad - probably the original, and
- // we are the replica.
- if (!remove_render_pass)
- return;
- RenderPassList& render_passes = frame->render_passes;
- RenderPassList::iterator to_remove = std::find(render_passes.begin(),
- render_passes.end(),
- remove_render_pass);
-
- DCHECK(to_remove != render_passes.end());
-
- scoped_ptr<RenderPass> removed_pass = render_passes.take(to_remove);
- frame->render_passes.erase(to_remove);
- frame->render_passes_by_id.erase(remove_render_pass_id);
-
- // Now follow up for all RenderPass quads and remove their RenderPasses
- // recursively.
- const QuadList& quad_list = removed_pass->quad_list;
- for (auto quad_list_iterator = quad_list.BackToFrontBegin();
- quad_list_iterator != quad_list.BackToFrontEnd();
- ++quad_list_iterator) {
- const DrawQuad* current_quad = *quad_list_iterator;
- if (current_quad->material != DrawQuad::RENDER_PASS)
- continue;
-
- RenderPassId next_remove_render_pass_id =
- RenderPassDrawQuad::MaterialCast(current_quad)->render_pass_id;
- RemoveRenderPassesRecursive(next_remove_render_pass_id, frame);
- }
-}
-
-bool LayerTreeHostImpl::CullRenderPassesWithNoQuads::ShouldRemoveRenderPass(
- const RenderPassDrawQuad& quad, const FrameData& frame) const {
- const RenderPass* render_pass =
- FindRenderPassById(quad.render_pass_id, frame);
- if (!render_pass)
- return false;
-
- // If any quad or RenderPass draws into this RenderPass, then keep it.
- const QuadList& quad_list = render_pass->quad_list;
- for (auto quad_list_iterator = quad_list.BackToFrontBegin();
- quad_list_iterator != quad_list.BackToFrontEnd();
- ++quad_list_iterator) {
- const DrawQuad* current_quad = *quad_list_iterator;
-
- if (current_quad->material != DrawQuad::RENDER_PASS)
- return false;
-
- const RenderPass* contributing_pass = FindRenderPassById(
- RenderPassDrawQuad::MaterialCast(current_quad)->render_pass_id, frame);
- if (contributing_pass)
- return false;
- }
- return true;
-}
-
-// Defined for linking tests.
-template CC_EXPORT void LayerTreeHostImpl::RemoveRenderPasses<
- LayerTreeHostImpl::CullRenderPassesWithNoQuads>(
- CullRenderPassesWithNoQuads culler, FrameData*);
-
-// static
-template <typename RenderPassCuller>
-void LayerTreeHostImpl::RemoveRenderPasses(RenderPassCuller culler,
- FrameData* frame) {
- for (size_t it = culler.RenderPassListBegin(frame->render_passes);
- it != culler.RenderPassListEnd(frame->render_passes);
- it = culler.RenderPassListNext(it)) {
- const RenderPass* current_pass = frame->render_passes[it];
- const QuadList& quad_list = current_pass->quad_list;
-
- for (auto quad_list_iterator = quad_list.BackToFrontBegin();
- quad_list_iterator != quad_list.BackToFrontEnd();
- ++quad_list_iterator) {
- const DrawQuad* current_quad = *quad_list_iterator;
-
- if (current_quad->material != DrawQuad::RENDER_PASS)
- continue;
-
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(current_quad);
- if (!culler.ShouldRemoveRenderPass(*render_pass_quad, *frame))
- continue;
-
- // We are changing the vector in the middle of iteration. Because we
- // delete render passes that draw into the current pass, we are
- // guaranteed that any data from the iterator to the end will not
- // change. So, capture the iterator position from the end of the
- // list, and restore it after the change.
- size_t position_from_end = frame->render_passes.size() - it;
- RemoveRenderPassesRecursive(render_pass_quad->render_pass_id, frame);
- it = frame->render_passes.size() - position_from_end;
- DCHECK_GE(frame->render_passes.size(), position_from_end);
- }
- }
-}
-
DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
TRACE_EVENT1("cc",
"LayerTreeHostImpl::PrepareToDraw",
"SourceFrameNumber",
active_tree_->source_frame_number());
-
- if (need_to_update_visible_tiles_before_draw_ &&
- tile_manager_ && tile_manager_->UpdateVisibleTiles()) {
- DidInitializeVisibleTile();
- }
- need_to_update_visible_tiles_before_draw_ = true;
+ if (input_handler_client_)
+ input_handler_client_->ReconcileElasticOverscrollAndRootScroll();
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Compositing.NumActiveLayers", active_tree_->NumLayers(), 1, 400, 20);
- bool ok = active_tree_->UpdateDrawProperties();
+ size_t total_picture_memory = 0;
+ for (const PictureLayerImpl* layer : active_tree()->picture_layers())
+ total_picture_memory += layer->GetRasterSource()->GetPictureMemoryUsage();
+ if (total_picture_memory != 0) {
+ UMA_HISTOGRAM_COUNTS("Compositing.PictureMemoryUsageKb",
+ total_picture_memory / 1024);
+ }
+
+ bool update_lcd_text = false;
+ bool ok = active_tree_->UpdateDrawProperties(update_lcd_text);
DCHECK(ok) << "UpdateDrawProperties failed during draw";
+ // This will cause NotifyTileStateChanged() to be called for any visible tiles
+ // that completed, which will add damage to the frame for them so they appear
+ // as part of the current frame being drawn.
+ if (tile_manager_)
+ tile_manager_->UpdateVisibleTiles(global_tile_state_);
+
frame->render_surface_layer_list = &active_tree_->RenderSurfaceLayerList();
frame->render_passes.clear();
frame->render_passes_by_id.clear();
frame->will_draw_layers.clear();
- frame->contains_incomplete_tile = false;
frame->has_no_damage = false;
if (active_tree_->root_layer()) {
@@ -1159,6 +1037,90 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
return draw_result;
}
+void LayerTreeHostImpl::RemoveRenderPasses(FrameData* frame) {
+ // There is always at least a root RenderPass.
+ DCHECK_GE(frame->render_passes.size(), 1u);
+
+ // A set of RenderPasses that we have seen.
+ std::set<RenderPassId> pass_exists;
+ // A set of RenderPassDrawQuads that we have seen (stored by the RenderPasses
+ // they refer to).
+ base::SmallMap<base::hash_map<RenderPassId, int>> pass_references;
+
+ // Iterate RenderPasses in draw order, removing empty render passes (except
+ // the root RenderPass).
+ for (size_t i = 0; i < frame->render_passes.size(); ++i) {
+ RenderPass* pass = frame->render_passes[i];
+
+ // Remove orphan RenderPassDrawQuads.
+ bool removed = true;
+ while (removed) {
+ removed = false;
+ for (auto it = pass->quad_list.begin(); it != pass->quad_list.end();
+ ++it) {
+ if (it->material != DrawQuad::RENDER_PASS)
+ continue;
+ const RenderPassDrawQuad* quad = RenderPassDrawQuad::MaterialCast(*it);
+ // If the RenderPass doesn't exist, we can remove the quad.
+ if (pass_exists.count(quad->render_pass_id)) {
+ // Otherwise, save a reference to the RenderPass so we know there's a
+ // quad using it.
+ pass_references[quad->render_pass_id]++;
+ continue;
+ }
+ // This invalidates the iterator. So break out of the loop and look
+ // again. Luckily there's not a lot of render passes cuz this is
+ // terrible.
+ // TODO(danakj): We could make erase not invalidate the iterator.
+ pass->quad_list.EraseAndInvalidateAllPointers(it);
+ removed = true;
+ break;
+ }
+ }
+
+ if (i == frame->render_passes.size() - 1) {
+ // Don't remove the root RenderPass.
+ break;
+ }
+
+ if (pass->quad_list.empty() && pass->copy_requests.empty()) {
+ // Remove the pass and decrement |i| to counter the for loop's increment,
+ // so we don't skip the next pass in the loop.
+ frame->render_passes_by_id.erase(pass->id);
+ frame->render_passes.erase(frame->render_passes.begin() + i);
+ --i;
+ continue;
+ }
+
+ pass_exists.insert(pass->id);
+ }
+
+ // Remove RenderPasses that are not referenced by any draw quads or copy
+ // requests (except the root RenderPass).
+ for (size_t i = 0; i < frame->render_passes.size() - 1; ++i) {
+ // Iterating from the back of the list to the front, skipping over the
+ // back-most (root) pass, in order to remove each qualified RenderPass, and
+ // drop references to earlier RenderPasses allowing them to be removed to.
+ RenderPass* pass =
+ frame->render_passes[frame->render_passes.size() - 2 - i];
+ if (!pass->copy_requests.empty())
+ continue;
+ if (pass_references[pass->id])
+ continue;
+
+ for (auto it = pass->quad_list.begin(); it != pass->quad_list.end(); ++it) {
+ if (it->material != DrawQuad::RENDER_PASS)
+ continue;
+ const RenderPassDrawQuad* quad = RenderPassDrawQuad::MaterialCast(*it);
+ pass_references[quad->render_pass_id]--;
+ }
+
+ frame->render_passes_by_id.erase(pass->id);
+ frame->render_passes.erase(frame->render_passes.end() - 2 - i);
+ --i;
+ }
+}
+
void LayerTreeHostImpl::EvictTexturesForTesting() {
EnforceManagedMemoryPolicy(ManagedMemoryPolicy(0));
}
@@ -1167,17 +1129,13 @@ void LayerTreeHostImpl::BlockNotifyReadyToActivateForTesting(bool block) {
NOTREACHED();
}
-void LayerTreeHostImpl::DidInitializeVisibleTileForTesting() {
- // Add arbitrary damage, to trigger prepare-to-draws.
- // Here, setting damage as viewport size, used only for testing.
- SetFullRootLayerDamage();
- DidInitializeVisibleTile();
-}
-
void LayerTreeHostImpl::ResetTreesForTesting() {
if (active_tree_)
active_tree_->DetachLayerTree();
- active_tree_ = LayerTreeImpl::create(this);
+ active_tree_ =
+ LayerTreeImpl::create(this, active_tree()->page_scale_factor(),
+ active_tree()->top_controls_shown_ratio(),
+ active_tree()->elastic_overscroll());
if (pending_tree_)
pending_tree_->DetachLayerTree();
pending_tree_ = nullptr;
@@ -1260,73 +1218,57 @@ void LayerTreeHostImpl::UpdateTileManagerMemoryPolicy(
void LayerTreeHostImpl::DidModifyTilePriorities() {
DCHECK(settings_.impl_side_painting);
- // Mark priorities as dirty and schedule a ManageTiles().
+ // Mark priorities as dirty and schedule a PrepareTiles().
tile_priorities_dirty_ = true;
- client_->SetNeedsManageTilesOnImplThread();
+ client_->SetNeedsPrepareTilesOnImplThread();
}
-void LayerTreeHostImpl::DidInitializeVisibleTile() {
- if (client_ && !client_->IsInsideDraw())
- client_->DidInitializeVisibleTileOnImplThread();
-}
-
-void LayerTreeHostImpl::GetPictureLayerImplPairs(
- std::vector<PictureLayerImpl::Pair>* layer_pairs) const {
- DCHECK(layer_pairs->empty());
- for (std::vector<PictureLayerImpl*>::const_iterator it =
- picture_layers_.begin();
- it != picture_layers_.end();
- ++it) {
- PictureLayerImpl* layer = *it;
-
- // TODO(vmpstr): Iterators and should handle this instead. crbug.com/381704
- if (!layer->HasValidTilePriorities())
- continue;
-
- PictureLayerImpl* twin_layer = layer->GetPendingOrActiveTwinLayer();
-
- // Ignore the twin layer when tile priorities are invalid.
- // TODO(vmpstr): Iterators should handle this instead. crbug.com/381704
- if (twin_layer && !twin_layer->HasValidTilePriorities())
- twin_layer = NULL;
-
- // If the current tree is ACTIVE_TREE, then always generate a layer_pair.
- // If current tree is PENDING_TREE, then only generate a layer_pair if
- // there is no twin layer.
- if (layer->GetTree() == ACTIVE_TREE) {
- DCHECK(!twin_layer || twin_layer->GetTree() == PENDING_TREE);
- layer_pairs->push_back(PictureLayerImpl::Pair(layer, twin_layer));
- } else if (!twin_layer) {
- layer_pairs->push_back(PictureLayerImpl::Pair(NULL, layer));
- }
- }
-}
-
-void LayerTreeHostImpl::BuildRasterQueue(RasterTilePriorityQueue* queue,
- TreePriority tree_priority) {
+scoped_ptr<RasterTilePriorityQueue> LayerTreeHostImpl::BuildRasterQueue(
+ TreePriority tree_priority,
+ RasterTilePriorityQueue::Type type) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::BuildRasterQueue");
- picture_layer_pairs_.clear();
- GetPictureLayerImplPairs(&picture_layer_pairs_);
- queue->Build(picture_layer_pairs_, tree_priority);
+
+ return RasterTilePriorityQueue::Create(active_tree_->picture_layers(),
+ pending_tree_
+ ? pending_tree_->picture_layers()
+ : std::vector<PictureLayerImpl*>(),
+ tree_priority, type);
}
-void LayerTreeHostImpl::BuildEvictionQueue(EvictionTilePriorityQueue* queue,
- TreePriority tree_priority) {
+scoped_ptr<EvictionTilePriorityQueue> LayerTreeHostImpl::BuildEvictionQueue(
+ TreePriority tree_priority) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::BuildEvictionQueue");
- picture_layer_pairs_.clear();
- GetPictureLayerImplPairs(&picture_layer_pairs_);
- queue->Build(picture_layer_pairs_, tree_priority);
+
+ scoped_ptr<EvictionTilePriorityQueue> queue(new EvictionTilePriorityQueue);
+ queue->Build(active_tree_->picture_layers(),
+ pending_tree_ ? pending_tree_->picture_layers()
+ : std::vector<PictureLayerImpl*>(),
+ tree_priority);
+ return queue;
}
-const std::vector<PictureLayerImpl*>& LayerTreeHostImpl::GetPictureLayers()
- const {
- return picture_layers_;
+void LayerTreeHostImpl::SetIsLikelyToRequireADraw(
+ bool is_likely_to_require_a_draw) {
+ // Proactively tell the scheduler that we expect to draw within each vsync
+ // until we get all the tiles ready to draw. If we happen to miss a required
+ // for draw tile here, then we will miss telling the scheduler each frame that
+ // we intend to draw so it may make worse scheduling decisions.
+ is_likely_to_require_a_draw_ = is_likely_to_require_a_draw;
}
void LayerTreeHostImpl::NotifyReadyToActivate() {
client_->NotifyReadyToActivate();
}
+void LayerTreeHostImpl::NotifyReadyToDraw() {
+ // Tiles that are ready will cause NotifyTileStateChanged() to be called so we
+ // don't need to schedule a draw here. Just stop WillBeginImplFrame() from
+ // causing optimistic requests to draw a frame.
+ is_likely_to_require_a_draw_ = false;
+
+ client_->NotifyReadyToDraw();
+}
+
void LayerTreeHostImpl::NotifyTileStateChanged(const Tile* tile) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::NotifyTileStateChanged");
@@ -1343,10 +1285,31 @@ void LayerTreeHostImpl::NotifyTileStateChanged(const Tile* tile) {
if (layer_impl)
layer_impl->NotifyTileStateChanged(tile);
}
+
+ // Check for a non-null active tree to avoid doing this during shutdown.
+ if (active_tree_ && !client_->IsInsideDraw() && tile->required_for_draw()) {
+ // The LayerImpl::NotifyTileStateChanged() should damage the layer, so this
+ // redraw will make those tiles be displayed.
+ SetNeedsRedraw();
+ }
}
void LayerTreeHostImpl::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
- SetManagedMemoryPolicy(policy, zero_budget_);
+ SetManagedMemoryPolicy(policy);
+
+ // This is short term solution to synchronously drop tile resources when
+ // using synchronous compositing to avoid memory usage regression.
+ // TODO(boliu): crbug.com/499004 to track removing this.
+ if (!policy.bytes_limit_when_visible && tile_manager_ &&
+ settings_.using_synchronous_renderer_compositor) {
+ ReleaseTreeResources();
+ // TileManager destruction will synchronoulsy wait for all tile workers to
+ // be cancelled or completed. This allows all resources to be freed
+ // synchronously.
+ DestroyTileManager();
+ CreateAndSetTileManager();
+ RecreateTreeResources();
+ }
}
void LayerTreeHostImpl::SetTreeActivationCallback(
@@ -1357,14 +1320,13 @@ void LayerTreeHostImpl::SetTreeActivationCallback(
}
void LayerTreeHostImpl::SetManagedMemoryPolicy(
- const ManagedMemoryPolicy& policy, bool zero_budget) {
- if (cached_managed_memory_policy_ == policy && zero_budget_ == zero_budget)
+ const ManagedMemoryPolicy& policy) {
+ if (cached_managed_memory_policy_ == policy)
return;
ManagedMemoryPolicy old_policy = ActualManagedMemoryPolicy();
cached_managed_memory_policy_ = policy;
- zero_budget_ = zero_budget;
ManagedMemoryPolicy actual_policy = ActualManagedMemoryPolicy();
if (old_policy == actual_policy)
@@ -1437,10 +1399,6 @@ void LayerTreeHostImpl::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
client_->SetNeedsRedrawRectOnImplThread(damage_rect);
}
-void LayerTreeHostImpl::BeginFrame(const BeginFrameArgs& args) {
- CallOnBeginFrame(args);
-}
-
void LayerTreeHostImpl::DidSwapBuffers() {
client_->DidSwapBuffersOnImplThread();
}
@@ -1471,6 +1429,10 @@ void LayerTreeHostImpl::ReclaimResources(const CompositorFrameAck* ack) {
}
}
+void LayerTreeHostImpl::OnDraw() {
+ client_->OnDrawForOutputSurface();
+}
+
void LayerTreeHostImpl::OnCanDrawStateChangedForTree() {
client_->OnCanDrawStateChanged(CanDraw());
}
@@ -1478,20 +1440,27 @@ void LayerTreeHostImpl::OnCanDrawStateChangedForTree() {
CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const {
CompositorFrameMetadata metadata;
metadata.device_scale_factor = device_scale_factor_;
- metadata.page_scale_factor = active_tree_->total_page_scale_factor();
+ metadata.page_scale_factor = active_tree_->current_page_scale_factor();
metadata.scrollable_viewport_size = active_tree_->ScrollableViewportSize();
metadata.root_layer_size = active_tree_->ScrollableSize();
metadata.min_page_scale_factor = active_tree_->min_page_scale_factor();
metadata.max_page_scale_factor = active_tree_->max_page_scale_factor();
- if (top_controls_manager_) {
- metadata.location_bar_offset =
- gfx::Vector2dF(0.f, top_controls_manager_->ControlsTopOffset());
- metadata.location_bar_content_translation =
- gfx::Vector2dF(0.f, top_controls_manager_->ContentTopOffset());
- }
+ metadata.location_bar_offset =
+ gfx::Vector2dF(0.f, top_controls_manager_->ControlsTopOffset());
+ metadata.location_bar_content_translation =
+ gfx::Vector2dF(0.f, top_controls_manager_->ContentTopOffset());
- active_tree_->GetViewportSelection(&metadata.selection_start,
- &metadata.selection_end);
+ active_tree_->GetViewportSelection(&metadata.selection);
+
+ LayerImpl* root_layer_for_overflow = OuterViewportScrollLayer()
+ ? OuterViewportScrollLayer()
+ : InnerViewportScrollLayer();
+ if (root_layer_for_overflow) {
+ metadata.root_overflow_x_hidden =
+ !root_layer_for_overflow->user_scrollable_horizontal();
+ metadata.root_overflow_y_hidden =
+ !root_layer_for_overflow->user_scrollable_vertical();
+ }
if (!InnerViewportScrollLayer())
return metadata;
@@ -1503,15 +1472,17 @@ CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const {
return metadata;
}
-static void LayerTreeHostImplDidBeginTracingCallback(LayerImpl* layer) {
- layer->DidBeginTracing();
-}
-
-void LayerTreeHostImpl::DrawLayers(FrameData* frame,
- base::TimeTicks frame_begin_time) {
+void LayerTreeHostImpl::DrawLayers(FrameData* frame) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::DrawLayers");
+
+ base::TimeTicks frame_begin_time = CurrentBeginFrameArgs().frame_time;
DCHECK(CanDraw());
+ if (!frame->composite_events.empty()) {
+ frame_timing_tracker_->SaveTimeStamps(frame_begin_time,
+ frame->composite_events);
+ }
+
if (frame->has_no_damage) {
TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoDamage", TRACE_EVENT_SCOPE_THREAD);
DCHECK(!output_surface_->capabilities()
@@ -1535,15 +1506,14 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
active_tree_->root_layer(),
active_tree_->hud_layer(),
*frame->render_surface_layer_list,
- frame->occluding_screen_space_rects,
- frame->non_occluding_screen_space_rects,
debug_state_);
}
if (!settings_.impl_side_painting && debug_state_.continuous_painting) {
const RenderingStats& stats =
rendering_stats_instrumentation_->GetRenderingStats();
- paint_time_counter_->SavePaintTime(stats.main_stats.paint_time);
+ paint_time_counter_->SavePaintTime(
+ stats.begin_main_frame_to_commit_duration.GetLastTimeDelta());
}
bool is_new_trace;
@@ -1552,22 +1522,18 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
if (pending_tree_) {
LayerTreeHostCommon::CallFunctionForSubtree(
pending_tree_->root_layer(),
- base::Bind(&LayerTreeHostImplDidBeginTracingCallback));
+ [](LayerImpl* layer) { layer->DidBeginTracing(); });
}
LayerTreeHostCommon::CallFunctionForSubtree(
active_tree_->root_layer(),
- base::Bind(&LayerTreeHostImplDidBeginTracingCallback));
+ [](LayerImpl* layer) { layer->DidBeginTracing(); });
}
{
TRACE_EVENT0("cc", "DrawLayers.FrameViewerTracing");
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug") ","
- TRACE_DISABLED_BY_DEFAULT("cc.debug.quads") ","
- TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers"),
- "cc::LayerTreeHostImpl",
- id_,
- AsValueWithFrame(frame));
+ frame_viewer_instrumentation::kCategoryLayerTree,
+ "cc::LayerTreeHostImpl", id_, AsValueWithFrame(frame));
}
const DrawMode draw_mode = GetDrawMode();
@@ -1583,10 +1549,11 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) {
bool disable_picture_quad_image_filtering =
- IsActivelyScrolling() || needs_animate_layers();
+ IsActivelyScrolling() || animation_registrar_->needs_animate_layers();
scoped_ptr<SoftwareRenderer> temp_software_renderer =
- SoftwareRenderer::Create(this, &settings_, output_surface_.get(), NULL);
+ SoftwareRenderer::Create(this, &settings_.renderer_settings,
+ output_surface_.get(), NULL);
temp_software_renderer->DrawFrame(&frame->render_passes,
device_scale_factor_,
DeviceViewport(),
@@ -1624,6 +1591,9 @@ void LayerTreeHostImpl::DidDrawAllLayers(const FrameData& frame) {
for (size_t i = 0; i < frame.will_draw_layers.size(); ++i)
frame.will_draw_layers[i]->DidDraw(resource_provider_.get());
+ for (auto& it : video_frame_controllers_)
+ it->DidDrawFrame();
+
// Once all layers have been drawn, pending texture uploads should no
// longer block future uploads.
resource_provider_->MarkPendingUploadsAsNonBlocking();
@@ -1634,28 +1604,95 @@ void LayerTreeHostImpl::FinishAllRendering() {
renderer_->Finish();
}
-void LayerTreeHostImpl::SetUseGpuRasterization(bool use_gpu) {
- if (use_gpu == use_gpu_rasterization_)
+bool LayerTreeHostImpl::CanUseGpuRasterization() {
+ if (!(output_surface_ && output_surface_->context_provider() &&
+ output_surface_->worker_context_provider()))
+ return false;
+
+ ContextProvider* context_provider =
+ output_surface_->worker_context_provider();
+ base::AutoLock context_lock(*context_provider->GetLock());
+ if (!context_provider->GrContext())
+ return false;
+
+ return true;
+}
+
+void LayerTreeHostImpl::UpdateGpuRasterizationStatus() {
+ bool use_gpu = false;
+ bool use_msaa = false;
+ bool using_msaa_for_complex_content =
+ renderer() && settings_.gpu_rasterization_msaa_sample_count > 0 &&
+ GetRendererCapabilities().max_msaa_samples >=
+ settings_.gpu_rasterization_msaa_sample_count;
+ if (settings_.gpu_rasterization_forced) {
+ use_gpu = true;
+ gpu_rasterization_status_ = GpuRasterizationStatus::ON_FORCED;
+ use_msaa = !content_is_suitable_for_gpu_rasterization_ &&
+ using_msaa_for_complex_content;
+ if (use_msaa) {
+ gpu_rasterization_status_ = GpuRasterizationStatus::MSAA_CONTENT;
+ }
+ } else if (!settings_.gpu_rasterization_enabled) {
+ gpu_rasterization_status_ = GpuRasterizationStatus::OFF_DEVICE;
+ } else if (!has_gpu_rasterization_trigger_) {
+ gpu_rasterization_status_ = GpuRasterizationStatus::OFF_VIEWPORT;
+ } else if (content_is_suitable_for_gpu_rasterization_) {
+ use_gpu = true;
+ gpu_rasterization_status_ = GpuRasterizationStatus::ON;
+ } else if (using_msaa_for_complex_content) {
+ use_gpu = use_msaa = true;
+ gpu_rasterization_status_ = GpuRasterizationStatus::MSAA_CONTENT;
+ } else {
+ gpu_rasterization_status_ = GpuRasterizationStatus::OFF_CONTENT;
+ }
+
+ if (use_gpu && !use_gpu_rasterization_) {
+ if (!CanUseGpuRasterization()) {
+ // If GPU rasterization is unusable, e.g. if GlContext could not
+ // be created due to losing the GL context, force use of software
+ // raster.
+ use_gpu = false;
+ use_msaa = false;
+ gpu_rasterization_status_ = GpuRasterizationStatus::OFF_DEVICE;
+ }
+ }
+
+ if (use_gpu == use_gpu_rasterization_ && use_msaa == use_msaa_)
return;
+ // Note that this must happen first, in case the rest of the calls want to
+ // query the new state of |use_gpu_rasterization_|.
use_gpu_rasterization_ = use_gpu;
- ReleaseTreeResources();
+ use_msaa_ = use_msaa;
- // Replace existing tile manager with another one that uses appropriate
- // rasterizer.
+ tree_resources_for_gpu_rasterization_dirty_ = true;
+}
+
+void LayerTreeHostImpl::UpdateTreeResourcesForGpuRasterizationIfNeeded() {
+ if (!tree_resources_for_gpu_rasterization_dirty_)
+ return;
+
+ // Clean up and replace existing tile manager with another one that uses
+ // appropriate rasterizer.
+ ReleaseTreeResources();
if (tile_manager_) {
DestroyTileManager();
CreateAndSetTileManager();
}
+ RecreateTreeResources();
// We have released tilings for both active and pending tree.
// We would not have any content to draw until the pending tree is activated.
// Prevent the active tree from drawing until activation.
SetRequiresHighResToDraw();
+
+ tree_resources_for_gpu_rasterization_dirty_ = false;
}
const RendererCapabilitiesImpl&
LayerTreeHostImpl::GetRendererCapabilities() const {
+ CHECK(renderer_);
return renderer_->Capabilities();
}
@@ -1667,47 +1704,83 @@ bool LayerTreeHostImpl::SwapBuffers(const LayerTreeHostImpl::FrameData& frame) {
}
CompositorFrameMetadata metadata = MakeCompositorFrameMetadata();
active_tree()->FinishSwapPromises(&metadata);
- for (size_t i = 0; i < metadata.latency_info.size(); i++) {
+ for (auto& latency : metadata.latency_info) {
TRACE_EVENT_FLOW_STEP0(
- "input",
+ "input,benchmark",
"LatencyInfo.Flow",
- TRACE_ID_DONT_MANGLE(metadata.latency_info[i].trace_id),
+ TRACE_ID_DONT_MANGLE(latency.trace_id),
"SwapBuffers");
+ // Only add the latency component once for renderer swap, not the browser
+ // swap.
+ if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT,
+ 0, nullptr)) {
+ latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT,
+ 0, 0);
+ }
}
renderer_->SwapBuffers(metadata);
return true;
}
-void LayerTreeHostImpl::OnNeedsBeginFramesChange(bool enable) {
- if (output_surface_)
- output_surface_->SetNeedsBeginFrame(enable);
- else
- DCHECK(!enable);
-}
-
void LayerTreeHostImpl::WillBeginImplFrame(const BeginFrameArgs& args) {
// Sample the frame time now. This time will be used for updating animations
// when we draw.
- UpdateCurrentBeginFrameArgs(args);
+ DCHECK(!current_begin_frame_args_.IsValid());
+ current_begin_frame_args_ = args;
+ // TODO(mithro): Stop overriding the frame time once the usage of frame
+ // timing is unified.
+ current_begin_frame_args_.frame_time = gfx::FrameTime::Now();
+
// Cache the begin impl frame interval
begin_impl_frame_interval_ = args.interval;
+
+ if (is_likely_to_require_a_draw_) {
+ // Optimistically schedule a draw. This will let us expect the tile manager
+ // to complete its work so that we can draw new tiles within the impl frame
+ // we are beginning now.
+ SetNeedsRedraw();
+ }
+
+ for (auto& it : video_frame_controllers_)
+ it->OnBeginFrame(args);
+}
+
+void LayerTreeHostImpl::DidFinishImplFrame() {
+ DCHECK(current_begin_frame_args_.IsValid());
+ current_begin_frame_args_ = BeginFrameArgs();
}
void LayerTreeHostImpl::UpdateViewportContainerSizes() {
LayerImpl* inner_container = active_tree_->InnerViewportContainerLayer();
LayerImpl* outer_container = active_tree_->OuterViewportContainerLayer();
- if (!inner_container || !top_controls_manager_)
+ if (!inner_container)
+ return;
+
+ // TODO(bokan): This code is currently specific to top controls. It should be
+ // made general. crbug.com/464814.
+ if (!TopControlsHeight()) {
+ if (outer_container)
+ outer_container->SetBoundsDelta(gfx::Vector2dF());
+
+ inner_container->SetBoundsDelta(gfx::Vector2dF());
+ active_tree_->InnerViewportScrollLayer()->SetBoundsDelta(gfx::Vector2dF());
+
return;
+ }
ViewportAnchor anchor(InnerViewportScrollLayer(),
OuterViewportScrollLayer());
// Adjust the inner viewport by shrinking/expanding the container to account
// for the change in top controls height since the last Resize from Blink.
- inner_container->SetBoundsDelta(
- gfx::Vector2dF(0, active_tree_->top_controls_layout_height() -
- active_tree_->total_top_controls_content_offset()));
+ float top_controls_layout_height =
+ active_tree_->top_controls_shrink_blink_size()
+ ? active_tree_->top_controls_height()
+ : 0.f;
+ inner_container->SetBoundsDelta(gfx::Vector2dF(
+ 0,
+ top_controls_layout_height - top_controls_manager_->ContentTopOffset()));
if (!outer_container || outer_container->BoundsForScrolling().IsEmpty())
return;
@@ -1730,19 +1803,11 @@ void LayerTreeHostImpl::UpdateViewportContainerSizes() {
anchor.ResetViewportToAnchoredPosition();
}
-void LayerTreeHostImpl::SetTopControlsLayoutHeight(float height) {
- if (active_tree_->top_controls_layout_height() == height)
- return;
-
- active_tree_->set_top_controls_layout_height(height);
- UpdateViewportContainerSizes();
- SetFullRootLayerDamage();
-}
-
void LayerTreeHostImpl::SynchronouslyInitializeAllTiles() {
// Only valid for the single-threaded non-scheduled/synchronous case
// using the zero copy raster worker pool.
- single_thread_synchronous_task_graph_runner_->RunUntilIdle();
+ if (tile_manager_)
+ single_thread_synchronous_task_graph_runner_->RunUntilIdle();
}
void LayerTreeHostImpl::DidLoseOutputSurface() {
@@ -1802,31 +1867,16 @@ void LayerTreeHostImpl::CreatePendingTree() {
if (recycle_tree_)
recycle_tree_.swap(pending_tree_);
else
- pending_tree_ = LayerTreeImpl::create(this);
-
- // Update the delta from the active tree, which may have
- // adjusted its delta prior to the pending tree being created.
- DCHECK_EQ(1.f, pending_tree_->sent_page_scale_delta());
- DCHECK_EQ(0.f, pending_tree_->sent_top_controls_delta());
- pending_tree_->SetPageScaleDelta(active_tree_->page_scale_delta() /
- active_tree_->sent_page_scale_delta());
- pending_tree_->set_top_controls_delta(
- active_tree_->top_controls_delta() -
- active_tree_->sent_top_controls_delta());
+ pending_tree_ =
+ LayerTreeImpl::create(this, active_tree()->page_scale_factor(),
+ active_tree()->top_controls_shown_ratio(),
+ active_tree()->elastic_overscroll());
client_->OnCanDrawStateChanged(CanDraw());
TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get());
}
-void LayerTreeHostImpl::UpdateVisibleTiles() {
- if (tile_manager_ && tile_manager_->UpdateVisibleTiles())
- DidInitializeVisibleTile();
- need_to_update_visible_tiles_before_draw_ = false;
-}
-
void LayerTreeHostImpl::ActivateSyncTree() {
- need_to_update_visible_tiles_before_draw_ = true;
-
if (pending_tree_) {
TRACE_EVENT_ASYNC_END0("cc", "PendingTree:waiting", pending_tree_.get());
@@ -1856,12 +1906,6 @@ void LayerTreeHostImpl::ActivateSyncTree() {
active_tree_->SetRootLayerScrollOffsetDelegate(
root_layer_scroll_offset_delegate_);
- if (top_controls_manager_) {
- top_controls_manager_->SetControlsTopOffset(
- active_tree_->total_top_controls_content_offset() -
- top_controls_manager_->top_controls_height());
- }
-
UpdateViewportContainerSizes();
} else {
active_tree_->ProcessUIResourceRequestQueue();
@@ -1869,8 +1913,13 @@ void LayerTreeHostImpl::ActivateSyncTree() {
active_tree_->DidBecomeActive();
ActivateAnimations();
- if (settings_.impl_side_painting)
+ if (settings_.impl_side_painting) {
client_->RenewTreePriority();
+ // If we have any picture layers, then by activating we also modified tile
+ // priorities.
+ if (!active_tree_->picture_layers().empty())
+ DidModifyTilePriorities();
+ }
client_->OnCanDrawStateChanged(CanDraw());
client_->DidActivateSyncTree();
@@ -1883,20 +1932,18 @@ void LayerTreeHostImpl::ActivateSyncTree() {
// TODO(hendrikw): This requires a different metric when we commit directly
// to the active tree. See crbug.com/429311.
paint_time_counter_->SavePaintTime(
- stats.impl_stats.commit_to_activate_duration.GetLastTimeDelta() +
- stats.impl_stats.draw_duration.GetLastTimeDelta());
+ stats.commit_to_activate_duration.GetLastTimeDelta() +
+ stats.draw_duration.GetLastTimeDelta());
}
- if (time_source_client_adapter_ && time_source_client_adapter_->Active())
- DCHECK(active_tree_->root_layer());
-
- scoped_ptr<PageScaleAnimation> page_scale_animation =
- active_tree_->TakePageScaleAnimation();
- if (page_scale_animation) {
- page_scale_animation_ = page_scale_animation.Pass();
- SetNeedsAnimate();
- client_->SetNeedsCommitOnImplThread();
- client_->RenewTreePriority();
+ scoped_ptr<PendingPageScaleAnimation> pending_page_scale_animation =
+ active_tree_->TakePendingPageScaleAnimation();
+ if (pending_page_scale_animation) {
+ StartPageScaleAnimation(
+ pending_page_scale_animation->target_offset,
+ pending_page_scale_animation->use_anchor,
+ pending_page_scale_animation->scale,
+ pending_page_scale_animation->duration);
}
}
@@ -1919,7 +1966,7 @@ void LayerTreeHostImpl::SetVisible(bool visible) {
// Evict tiles immediately if invisible since this tab may never get another
// draw or timer tick.
if (!visible_)
- ManageTiles();
+ PrepareTiles();
if (!renderer_)
return;
@@ -1946,11 +1993,6 @@ ManagedMemoryPolicy LayerTreeHostImpl::ActualManagedMemoryPolicy() const {
actual.priority_cutoff_when_visible =
gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
}
-
- if (zero_budget_) {
- actual.bytes_limit_when_visible = 0;
- }
-
return actual;
}
@@ -1973,24 +2015,32 @@ void LayerTreeHostImpl::ReleaseTreeResources() {
EvictAllUIResources();
}
+void LayerTreeHostImpl::RecreateTreeResources() {
+ active_tree_->RecreateResources();
+ if (pending_tree_)
+ pending_tree_->RecreateResources();
+ if (recycle_tree_)
+ recycle_tree_->RecreateResources();
+}
+
void LayerTreeHostImpl::CreateAndSetRenderer() {
DCHECK(!renderer_);
DCHECK(output_surface_);
DCHECK(resource_provider_);
if (output_surface_->capabilities().delegated_rendering) {
- renderer_ = DelegatingRenderer::Create(
- this, &settings_, output_surface_.get(), resource_provider_.get());
+ renderer_ = DelegatingRenderer::Create(this, &settings_.renderer_settings,
+ output_surface_.get(),
+ resource_provider_.get());
} else if (output_surface_->context_provider()) {
- renderer_ = GLRenderer::Create(this,
- &settings_,
- output_surface_.get(),
- resource_provider_.get(),
- texture_mailbox_deleter_.get(),
- settings_.highp_threshold_min);
+ renderer_ = GLRenderer::Create(
+ this, &settings_.renderer_settings, output_surface_.get(),
+ resource_provider_.get(), texture_mailbox_deleter_.get(),
+ settings_.renderer_settings.highp_threshold_min);
} else if (output_surface_->software_device()) {
- renderer_ = SoftwareRenderer::Create(
- this, &settings_, output_surface_.get(), resource_provider_.get());
+ renderer_ = SoftwareRenderer::Create(this, &settings_.renderer_settings,
+ output_surface_.get(),
+ resource_provider_.get());
}
DCHECK(renderer_);
@@ -2012,9 +2062,9 @@ void LayerTreeHostImpl::CreateAndSetTileManager() {
DCHECK(output_surface_);
DCHECK(resource_provider_);
- CreateResourceAndRasterWorkerPool(
- &raster_worker_pool_, &resource_pool_, &staging_resource_pool_);
- DCHECK(raster_worker_pool_);
+ CreateResourceAndTileTaskWorkerPool(&tile_task_worker_pool_, &resource_pool_,
+ &staging_resource_pool_);
+ DCHECK(tile_task_worker_pool_);
DCHECK(resource_pool_);
base::SingleThreadTaskRunner* task_runner =
@@ -2024,19 +2074,15 @@ void LayerTreeHostImpl::CreateAndSetTileManager() {
size_t scheduled_raster_task_limit =
IsSynchronousSingleThreaded() ? std::numeric_limits<size_t>::max()
: settings_.scheduled_raster_task_limit;
- tile_manager_ = TileManager::Create(this,
- task_runner,
- resource_pool_.get(),
- raster_worker_pool_->AsRasterizer(),
- rendering_stats_instrumentation_,
- scheduled_raster_task_limit);
+ tile_manager_ = TileManager::Create(
+ this, task_runner, resource_pool_.get(),
+ tile_task_worker_pool_->AsTileTaskRunner(), scheduled_raster_task_limit);
UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
- need_to_update_visible_tiles_before_draw_ = false;
}
-void LayerTreeHostImpl::CreateResourceAndRasterWorkerPool(
- scoped_ptr<RasterWorkerPool>* raster_worker_pool,
+void LayerTreeHostImpl::CreateResourceAndTileTaskWorkerPool(
+ scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool,
scoped_ptr<ResourcePool>* resource_pool,
scoped_ptr<ResourcePool>* staging_resource_pool) {
base::SingleThreadTaskRunner* task_runner =
@@ -2044,113 +2090,112 @@ void LayerTreeHostImpl::CreateResourceAndRasterWorkerPool(
: proxy_->MainThreadTaskRunner();
DCHECK(task_runner);
- ContextProvider* context_provider = output_surface_->context_provider();
- bool should_use_zero_copy_rasterizer =
- settings_.use_zero_copy || IsSynchronousSingleThreaded();
+ // Pass the single-threaded synchronous task graph runner to the worker pool
+ // if we're in synchronous single-threaded mode.
+ TaskGraphRunner* task_graph_runner = task_graph_runner_;
+ if (IsSynchronousSingleThreaded()) {
+ DCHECK(!single_thread_synchronous_task_graph_runner_);
+ single_thread_synchronous_task_graph_runner_.reset(new TaskGraphRunner);
+ task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
+ }
+ ContextProvider* context_provider = output_surface_->context_provider();
if (!context_provider) {
*resource_pool =
- ResourcePool::Create(resource_provider_.get(),
- GL_TEXTURE_2D,
- resource_provider_->best_texture_format());
-
- *raster_worker_pool =
- BitmapRasterWorkerPool::Create(task_runner,
- RasterWorkerPool::GetTaskGraphRunner(),
- resource_provider_.get());
- } else if (use_gpu_rasterization_) {
- *resource_pool =
- ResourcePool::Create(resource_provider_.get(),
- GL_TEXTURE_2D,
- resource_provider_->best_texture_format());
-
- *raster_worker_pool =
- GpuRasterWorkerPool::Create(task_runner,
- context_provider,
- resource_provider_.get(),
- settings_.use_distance_field_text);
- } else if (should_use_zero_copy_rasterizer && CanUseZeroCopyRasterizer()) {
- *resource_pool = ResourcePool::Create(
- resource_provider_.get(),
- GetMapImageTextureTarget(context_provider->ContextCapabilities()),
- resource_provider_->best_texture_format());
-
- TaskGraphRunner* task_graph_runner;
- if (IsSynchronousSingleThreaded()) {
- DCHECK(!single_thread_synchronous_task_graph_runner_);
- single_thread_synchronous_task_graph_runner_.reset(new TaskGraphRunner);
- task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
- } else {
- task_graph_runner = RasterWorkerPool::GetTaskGraphRunner();
- }
+ ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D);
- *raster_worker_pool = ZeroCopyRasterWorkerPool::Create(
+ *tile_task_worker_pool = BitmapTileTaskWorkerPool::Create(
task_runner, task_graph_runner, resource_provider_.get());
- } else if (settings_.use_one_copy && CanUseOneCopyRasterizer()) {
- // We need to create a staging resource pool when using copy rasterizer.
- *staging_resource_pool = ResourcePool::Create(
- resource_provider_.get(),
- GetMapImageTextureTarget(context_provider->ContextCapabilities()),
- resource_provider_->best_texture_format());
+ return;
+ }
+
+ if (use_gpu_rasterization_) {
*resource_pool =
- ResourcePool::Create(resource_provider_.get(),
- GL_TEXTURE_2D,
- resource_provider_->best_texture_format());
-
- *raster_worker_pool =
- OneCopyRasterWorkerPool::Create(task_runner,
- RasterWorkerPool::GetTaskGraphRunner(),
- context_provider,
- resource_provider_.get(),
- staging_resource_pool_.get());
- } else {
- *resource_pool = ResourcePool::Create(
- resource_provider_.get(),
- GL_TEXTURE_2D,
- resource_provider_->memory_efficient_texture_format());
+ ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D);
- *raster_worker_pool = PixelBufferRasterWorkerPool::Create(
- task_runner,
- RasterWorkerPool::GetTaskGraphRunner(),
- context_provider,
- resource_provider_.get(),
- GetMaxTransferBufferUsageBytes(context_provider->ContextCapabilities(),
- settings_.refresh_rate));
+ int msaa_sample_count =
+ use_msaa_ ? settings_.gpu_rasterization_msaa_sample_count : 0;
+
+ *tile_task_worker_pool = GpuTileTaskWorkerPool::Create(
+ task_runner, task_graph_runner, context_provider,
+ resource_provider_.get(), settings_.use_distance_field_text,
+ msaa_sample_count);
+ return;
}
+
+ if (GetRendererCapabilities().using_image) {
+ unsigned image_target = settings_.use_image_texture_target;
+ DCHECK_IMPLIES(
+ image_target == GL_TEXTURE_RECTANGLE_ARB,
+ context_provider->ContextCapabilities().gpu.texture_rectangle);
+ DCHECK_IMPLIES(
+ image_target == GL_TEXTURE_EXTERNAL_OES,
+ context_provider->ContextCapabilities().gpu.egl_image_external);
+
+ if (settings_.use_zero_copy || IsSynchronousSingleThreaded()) {
+ *resource_pool =
+ ResourcePool::Create(resource_provider_.get(), image_target);
+
+ *tile_task_worker_pool = ZeroCopyTileTaskWorkerPool::Create(
+ task_runner, task_graph_runner, resource_provider_.get());
+ return;
+ }
+
+ if (settings_.use_one_copy) {
+ // We need to create a staging resource pool when using copy rasterizer.
+ *staging_resource_pool =
+ ResourcePool::Create(resource_provider_.get(), image_target);
+ *resource_pool =
+ ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D);
+
+ *tile_task_worker_pool = OneCopyTileTaskWorkerPool::Create(
+ task_runner, task_graph_runner, context_provider,
+ resource_provider_.get(), staging_resource_pool_.get());
+ return;
+ }
+ }
+
+ // Synchronous single-threaded mode depends on tiles being ready to
+ // draw when raster is complete. Therefore, it must use one of zero
+ // copy, software raster, or GPU raster (in the branches above).
+ DCHECK(!IsSynchronousSingleThreaded());
+
+ *resource_pool = ResourcePool::Create(
+ resource_provider_.get(), GL_TEXTURE_2D);
+
+ *tile_task_worker_pool = PixelBufferTileTaskWorkerPool::Create(
+ task_runner, task_graph_runner_, context_provider,
+ resource_provider_.get(),
+ GetMaxTransferBufferUsageBytes(context_provider->ContextCapabilities(),
+ settings_.renderer_settings.refresh_rate));
+}
+
+void LayerTreeHostImpl::RecordMainFrameTiming(
+ const BeginFrameArgs& start_of_main_frame_args,
+ const BeginFrameArgs& expected_next_main_frame_args) {
+ std::vector<int64_t> request_ids;
+ active_tree_->GatherFrameTimingRequestIds(&request_ids);
+ if (request_ids.empty())
+ return;
+
+ base::TimeTicks start_time = start_of_main_frame_args.frame_time;
+ base::TimeTicks end_time = expected_next_main_frame_args.frame_time;
+ frame_timing_tracker_->SaveMainFrameTimeStamps(
+ request_ids, start_time, end_time, active_tree_->source_frame_number());
}
void LayerTreeHostImpl::DestroyTileManager() {
tile_manager_ = nullptr;
resource_pool_ = nullptr;
staging_resource_pool_ = nullptr;
- raster_worker_pool_ = nullptr;
+ tile_task_worker_pool_ = nullptr;
single_thread_synchronous_task_graph_runner_ = nullptr;
}
-bool LayerTreeHostImpl::UsePendingTreeForSync() const {
- // In impl-side painting, synchronize to the pending tree so that it has
- // time to raster before being displayed.
- return settings_.impl_side_painting;
-}
-
bool LayerTreeHostImpl::IsSynchronousSingleThreaded() const {
return !proxy_->HasImplThread() && !settings_.single_thread_proxy_scheduler;
}
-bool LayerTreeHostImpl::CanUseZeroCopyRasterizer() const {
- return GetRendererCapabilities().using_image;
-}
-
-bool LayerTreeHostImpl::CanUseOneCopyRasterizer() const {
- // Sync query support is required by one-copy rasterizer.
- return GetRendererCapabilities().using_image &&
- resource_provider_->use_sync_query();
-}
-
-void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) {
- SetManagedMemoryPolicy(cached_managed_memory_policy_, zero_budget);
-}
-
bool LayerTreeHostImpl::InitializeRenderer(
scoped_ptr<OutputSurface> output_surface) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::InitializeRenderer");
@@ -2166,36 +2211,40 @@ bool LayerTreeHostImpl::InitializeRenderer(
resource_provider_ = nullptr;
output_surface_ = nullptr;
- if (!output_surface->BindToClient(this))
+ if (!output_surface->BindToClient(this)) {
+ // Avoid recreating tree resources because we might not have enough
+ // information to do this yet (eg. we don't have a TileManager at this
+ // point).
return false;
+ }
output_surface_ = output_surface.Pass();
- resource_provider_ =
- ResourceProvider::Create(output_surface_.get(),
- shared_bitmap_manager_,
- gpu_memory_buffer_manager_,
- proxy_->blocking_main_thread_task_runner(),
- settings_.highp_threshold_min,
- settings_.use_rgba_4444_textures,
- settings_.texture_id_allocation_chunk_size);
-
- if (output_surface_->capabilities().deferred_gl_initialization)
- EnforceZeroBudget(true);
+ resource_provider_ = ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_, gpu_memory_buffer_manager_,
+ proxy_->blocking_main_thread_task_runner(),
+ settings_.renderer_settings.highp_threshold_min,
+ settings_.renderer_settings.use_rgba_4444_textures,
+ settings_.renderer_settings.texture_id_allocation_chunk_size);
CreateAndSetRenderer();
- if (settings_.impl_side_painting)
+ // Since the new renderer may be capable of MSAA, update status here.
+ UpdateGpuRasterizationStatus();
+
+ if (settings_.impl_side_painting && settings_.raster_enabled)
CreateAndSetTileManager();
+ RecreateTreeResources();
// Initialize vsync parameters to sane values.
const base::TimeDelta display_refresh_interval =
- base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond /
- settings_.refresh_rate);
+ base::TimeDelta::FromMicroseconds(
+ base::Time::kMicrosecondsPerSecond /
+ settings_.renderer_settings.refresh_rate);
CommitVSyncParameters(base::TimeTicks(), display_refresh_interval);
// TODO(brianderson): Don't use a hard-coded parent draw time.
base::TimeDelta parent_draw_time =
- (!settings_.begin_frame_scheduling_enabled &&
+ (!settings_.use_external_begin_frame_source &&
output_surface_->capabilities().adjust_deadline_for_parent)
? BeginFrameArgs::DefaultEstimatedParentDrawTime()
: base::TimeDelta();
@@ -2220,46 +2269,13 @@ void LayerTreeHostImpl::CommitVSyncParameters(base::TimeTicks timebase,
client_->CommitVSyncParameters(timebase, interval);
}
-void LayerTreeHostImpl::DeferredInitialize() {
- DCHECK(output_surface_->capabilities().deferred_gl_initialization);
- DCHECK(settings_.impl_side_painting);
- DCHECK(output_surface_->context_provider());
-
- ReleaseTreeResources();
- renderer_ = nullptr;
- DestroyTileManager();
-
- resource_provider_->InitializeGL();
-
- CreateAndSetRenderer();
- EnforceZeroBudget(false);
- CreateAndSetTileManager();
-
- client_->SetNeedsCommitOnImplThread();
-}
-
-void LayerTreeHostImpl::ReleaseGL() {
- DCHECK(output_surface_->capabilities().deferred_gl_initialization);
- DCHECK(settings_.impl_side_painting);
- DCHECK(output_surface_->context_provider());
-
- ReleaseTreeResources();
- renderer_ = nullptr;
- DestroyTileManager();
-
- resource_provider_->InitializeSoftware();
- output_surface_->ReleaseContextProvider();
-
- CreateAndSetRenderer();
- EnforceZeroBudget(true);
- CreateAndSetTileManager();
-
- client_->SetNeedsCommitOnImplThread();
-}
-
void LayerTreeHostImpl::SetViewportSize(const gfx::Size& device_viewport_size) {
if (device_viewport_size == device_viewport_size_)
return;
+ TRACE_EVENT_INSTANT2("cc", "LayerTreeHostImpl::SetViewportSize",
+ TRACE_EVENT_SCOPE_THREAD, "width",
+ device_viewport_size.width(), "height",
+ device_viewport_size.height());
if (pending_tree_)
active_tree_->SetViewportSizeInvalid();
@@ -2272,13 +2288,6 @@ void LayerTreeHostImpl::SetViewportSize(const gfx::Size& device_viewport_size) {
active_tree_->set_needs_update_draw_properties();
}
-void LayerTreeHostImpl::SetOverhangUIResource(
- UIResourceId overhang_ui_resource_id,
- const gfx::Size& overhang_ui_resource_size) {
- overhang_ui_resource_id_ = overhang_ui_resource_id;
- overhang_ui_resource_size_ = overhang_ui_resource_size;
-}
-
void LayerTreeHostImpl::SetDeviceScaleFactor(float device_scale_factor) {
if (device_scale_factor == device_scale_factor_)
return;
@@ -2287,6 +2296,10 @@ void LayerTreeHostImpl::SetDeviceScaleFactor(float device_scale_factor) {
SetFullRootLayerDamage();
}
+void LayerTreeHostImpl::SetPageScaleOnActiveTree(float page_scale_factor) {
+ active_tree_->SetPageScaleOnActiveTree(page_scale_factor);
+}
+
const gfx::Rect LayerTreeHostImpl::ViewportRectForTilePriority() const {
if (viewport_rect_for_tile_priority_.IsEmpty())
return DeviceViewport();
@@ -2324,15 +2337,17 @@ void LayerTreeHostImpl::DidChangeTopControlsPosition() {
SetFullRootLayerDamage();
}
-void LayerTreeHostImpl::SetControlsTopOffset(float offset) {
- float current_top_offset = active_tree_->top_controls_content_offset() -
- top_controls_manager_->top_controls_height();
- active_tree_->set_top_controls_delta(offset - current_top_offset);
+float LayerTreeHostImpl::TopControlsHeight() const {
+ return active_tree_->top_controls_height();
+}
+
+void LayerTreeHostImpl::SetCurrentTopControlsShownRatio(float ratio) {
+ if (active_tree_->SetCurrentTopControlsShownRatio(ratio))
+ DidChangeTopControlsPosition();
}
-float LayerTreeHostImpl::ControlsTopOffset() const {
- return active_tree_->total_top_controls_content_offset() -
- top_controls_manager_->top_controls_height();
+float LayerTreeHostImpl::CurrentTopControlsShownRatio() const {
+ return active_tree_->CurrentTopControlsShownRatio();
}
void LayerTreeHostImpl::BindToClient(InputHandlerClient* client) {
@@ -2340,12 +2355,6 @@ void LayerTreeHostImpl::BindToClient(InputHandlerClient* client) {
input_handler_client_ = client;
}
-static LayerImpl* NextScrollLayer(LayerImpl* layer) {
- if (LayerImpl* scroll_parent = layer->scroll_parent())
- return scroll_parent;
- return layer->parent();
-}
-
LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
const gfx::PointF& device_viewport_point,
InputHandler::ScrollInputType type,
@@ -2354,13 +2363,16 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
bool* optional_has_ancestor_scroll_handler) const {
DCHECK(scroll_on_main_thread);
+ ScrollBlocksOn block_mode = EffectiveScrollBlocksOn(layer_impl);
+
// Walk up the hierarchy and look for a scrollable layer.
LayerImpl* potentially_scrolling_layer_impl = NULL;
for (; layer_impl; layer_impl = NextScrollLayer(layer_impl)) {
// The content layer can also block attempts to scroll outside the main
// thread.
- ScrollStatus status = layer_impl->TryScroll(device_viewport_point, type);
- if (status == ScrollOnMainThread) {
+ ScrollStatus status =
+ layer_impl->TryScroll(device_viewport_point, type, block_mode);
+ if (status == SCROLL_ON_MAIN_THREAD) {
*scroll_on_main_thread = true;
return NULL;
}
@@ -2369,9 +2381,10 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
if (!scroll_layer_impl)
continue;
- status = scroll_layer_impl->TryScroll(device_viewport_point, type);
+ status =
+ scroll_layer_impl->TryScroll(device_viewport_point, type, block_mode);
// If any layer wants to divert the scroll event to the main thread, abort.
- if (status == ScrollOnMainThread) {
+ if (status == SCROLL_ON_MAIN_THREAD) {
*scroll_on_main_thread = true;
return NULL;
}
@@ -2380,7 +2393,7 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
scroll_layer_impl->have_scroll_event_handlers())
*optional_has_ancestor_scroll_handler = true;
- if (status == ScrollStarted && !potentially_scrolling_layer_impl)
+ if (status == SCROLL_STARTED && !potentially_scrolling_layer_impl)
potentially_scrolling_layer_impl = scroll_layer_impl;
}
@@ -2411,8 +2424,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin(
InputHandler::ScrollInputType type) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBegin");
- if (top_controls_manager_)
- top_controls_manager_->ScrollBegin();
+ top_controls_manager_->ScrollBegin();
DCHECK(!CurrentlyScrollingLayer());
ClearCurrentlyScrollingLayer();
@@ -2427,7 +2439,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin(
active_tree_->FindFirstScrollingLayerThatIsHitByPoint(
device_viewport_point);
if (scroll_layer_impl && !HasScrollAncestor(layer_impl, scroll_layer_impl))
- return ScrollUnknown;
+ return SCROLL_UNKNOWN;
}
bool scroll_on_main_thread = false;
@@ -2440,56 +2452,40 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin(
if (scroll_on_main_thread) {
UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true);
- return ScrollOnMainThread;
+ return SCROLL_ON_MAIN_THREAD;
}
if (scrolling_layer_impl) {
active_tree_->SetCurrentlyScrollingLayer(scrolling_layer_impl);
- should_bubble_scrolls_ = (type != NonBubblingGesture);
- wheel_scrolling_ = (type == Wheel);
+ should_bubble_scrolls_ = (type != NON_BUBBLING_GESTURE);
+ wheel_scrolling_ = (type == WHEEL);
client_->RenewTreePriority();
UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", false);
- return ScrollStarted;
+ return SCROLL_STARTED;
}
- return ScrollIgnored;
+ return SCROLL_IGNORED;
}
InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
const gfx::Point& viewport_point,
const gfx::Vector2dF& scroll_delta) {
if (LayerImpl* layer_impl = CurrentlyScrollingLayer()) {
- Animation* animation =
- layer_impl->layer_animation_controller()->GetAnimation(
- Animation::ScrollOffset);
- if (!animation)
- return ScrollIgnored;
-
- ScrollOffsetAnimationCurve* curve =
- animation->curve()->ToScrollOffsetAnimationCurve();
-
- gfx::ScrollOffset new_target =
- gfx::ScrollOffsetWithDelta(curve->target_value(), scroll_delta);
- new_target.SetToMax(gfx::ScrollOffset());
- new_target.SetToMin(layer_impl->MaxScrollOffset());
-
- curve->UpdateTarget(animation->TrimTimeToCurrentIteration(
- CurrentBeginFrameArgs().frame_time),
- new_target);
-
- return ScrollStarted;
+ return ScrollAnimationUpdateTarget(layer_impl, scroll_delta)
+ ? SCROLL_STARTED
+ : SCROLL_IGNORED;
}
// ScrollAnimated is only used for wheel scrolls. We use the same bubbling
// behavior as ScrollBy to determine which layer to animate, but we do not
// do the Android-specific things in ScrollBy like showing top controls.
- InputHandler::ScrollStatus scroll_status = ScrollBegin(viewport_point, Wheel);
- if (scroll_status == ScrollStarted) {
+ InputHandler::ScrollStatus scroll_status = ScrollBegin(viewport_point, WHEEL);
+ if (scroll_status == SCROLL_STARTED) {
gfx::Vector2dF pending_delta = scroll_delta;
for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); layer_impl;
layer_impl = layer_impl->parent()) {
if (!layer_impl->scrollable())
continue;
- gfx::ScrollOffset current_offset = layer_impl->TotalScrollOffset();
+ gfx::ScrollOffset current_offset = layer_impl->CurrentScrollOffset();
gfx::ScrollOffset target_offset =
ScrollOffsetWithDelta(current_offset, pending_delta);
target_offset.SetToMax(gfx::ScrollOffset());
@@ -2508,22 +2504,10 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
active_tree_->SetCurrentlyScrollingLayer(layer_impl);
- scoped_ptr<ScrollOffsetAnimationCurve> curve =
- ScrollOffsetAnimationCurve::Create(target_offset,
- EaseInOutTimingFunction::Create());
- curve->SetInitialValue(current_offset);
-
- scoped_ptr<Animation> animation =
- Animation::Create(curve.Pass(),
- AnimationIdProvider::NextAnimationId(),
- AnimationIdProvider::NextGroupId(),
- Animation::ScrollOffset);
- animation->set_is_impl_only(true);
-
- layer_impl->layer_animation_controller()->AddAnimation(animation.Pass());
+ ScrollAnimationCreate(layer_impl, target_offset, current_offset);
SetNeedsAnimate();
- return ScrollStarted;
+ return SCROLL_STARTED;
}
}
ScrollEnd();
@@ -2532,7 +2516,6 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
gfx::Vector2dF LayerTreeHostImpl::ScrollLayerWithViewportSpaceDelta(
LayerImpl* layer_impl,
- float scale_from_viewport_to_screen_space,
const gfx::PointF& viewport_point,
const gfx::Vector2dF& viewport_delta) {
// Layers with non-invertible screen space transforms should not have passed
@@ -2546,6 +2529,7 @@ gfx::Vector2dF LayerTreeHostImpl::ScrollLayerWithViewportSpaceDelta(
// layers, we may need to explicitly handle uninvertible transforms here.
DCHECK(did_invert);
+ float scale_from_viewport_to_screen_space = device_scale_factor_;
gfx::PointF screen_space_point =
gfx::ScalePoint(viewport_point, scale_from_viewport_to_screen_space);
@@ -2579,14 +2563,15 @@ gfx::Vector2dF LayerTreeHostImpl::ScrollLayerWithViewportSpaceDelta(
local_end_point.Scale(width_scale, height_scale);
// Apply the scroll delta.
- gfx::Vector2dF previous_delta = layer_impl->ScrollDelta();
+ gfx::ScrollOffset previous_offset = layer_impl->CurrentScrollOffset();
layer_impl->ScrollBy(local_end_point - local_start_point);
+ gfx::ScrollOffset scrolled =
+ layer_impl->CurrentScrollOffset() - previous_offset;
// Get the end point in the layer's content space so we can apply its
// ScreenSpaceTransform.
- gfx::PointF actual_local_end_point = local_start_point +
- layer_impl->ScrollDelta() -
- previous_delta;
+ gfx::PointF actual_local_end_point =
+ local_start_point + gfx::Vector2dF(scrolled.x(), scrolled.y());
gfx::PointF actual_local_content_end_point =
gfx::ScalePoint(actual_local_end_point,
1.f / width_scale,
@@ -2606,36 +2591,38 @@ gfx::Vector2dF LayerTreeHostImpl::ScrollLayerWithViewportSpaceDelta(
return actual_viewport_end_point - viewport_point;
}
-static gfx::Vector2dF ScrollLayerWithLocalDelta(LayerImpl* layer_impl,
- const gfx::Vector2dF& local_delta) {
- gfx::Vector2dF previous_delta(layer_impl->ScrollDelta());
- layer_impl->ScrollBy(local_delta);
- return layer_impl->ScrollDelta() - previous_delta;
-}
-
-bool LayerTreeHostImpl::ShouldTopControlsConsumeScroll(
- const gfx::Vector2dF& scroll_delta) const {
- DCHECK(CurrentlyScrollingLayer());
-
- if (!top_controls_manager_)
- return false;
-
- // Always consume if it's in the direction to show the top controls.
- if (scroll_delta.y() < 0)
- return true;
-
- if (CurrentlyScrollingLayer() != InnerViewportScrollLayer() &&
- CurrentlyScrollingLayer() != OuterViewportScrollLayer())
- return false;
-
- if (InnerViewportScrollLayer()->MaxScrollOffset().y() > 0)
- return true;
-
- if (OuterViewportScrollLayer() &&
- OuterViewportScrollLayer()->MaxScrollOffset().y() > 0)
- return true;
-
- return false;
+static gfx::Vector2dF ScrollLayerWithLocalDelta(
+ LayerImpl* layer_impl,
+ const gfx::Vector2dF& local_delta,
+ float page_scale_factor) {
+ gfx::ScrollOffset previous_offset = layer_impl->CurrentScrollOffset();
+ gfx::Vector2dF delta = local_delta;
+ delta.Scale(1.f / page_scale_factor);
+ layer_impl->ScrollBy(delta);
+ gfx::ScrollOffset scrolled =
+ layer_impl->CurrentScrollOffset() - previous_offset;
+ return gfx::Vector2dF(scrolled.x(), scrolled.y());
+}
+
+gfx::Vector2dF LayerTreeHostImpl::ScrollLayer(LayerImpl* layer_impl,
+ const gfx::Vector2dF& delta,
+ const gfx::Point& viewport_point,
+ bool is_wheel_scroll) {
+ // Gesture events need to be transformed from viewport coordinates to
+ // local layer coordinates so that the scrolling contents exactly follow
+ // the user's finger. In contrast, wheel events represent a fixed amount
+ // of scrolling so we can just apply them directly, but the page scale
+ // factor is applied to the scroll delta.
+ if (is_wheel_scroll) {
+ float scale_factor = active_tree()->current_page_scale_factor();
+ return ScrollLayerWithLocalDelta(layer_impl,
+ delta,
+ scale_factor);
+ }
+
+ return ScrollLayerWithViewportSpaceDelta(layer_impl,
+ viewport_point,
+ delta);
}
InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
@@ -2651,119 +2638,68 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
bool did_scroll_y = false;
bool did_scroll_top_controls = false;
- bool consume_by_top_controls = ShouldTopControlsConsumeScroll(scroll_delta);
-
- // There's an edge case where the outer viewport isn't scrollable when the
- // scroll starts, however, as the top controls show the outer viewport becomes
- // scrollable. Therefore, always try scrolling the outer viewport before the
- // inner.
- // TODO(bokan): Move the top controls logic out of the loop since the scroll
- // that causes the outer viewport to become scrollable will still be applied
- // to the inner viewport.
- LayerImpl* start_layer = CurrentlyScrollingLayer();
- if (start_layer == InnerViewportScrollLayer() && OuterViewportScrollLayer())
- start_layer = OuterViewportScrollLayer();
-
- for (LayerImpl* layer_impl = start_layer;
+ for (LayerImpl* layer_impl = CurrentlyScrollingLayer();
layer_impl;
layer_impl = layer_impl->parent()) {
- if (!layer_impl->scrollable())
+ // Skip the outer viewport scroll layer so that we try to scroll the
+ // viewport only once. i.e. The inner viewport layer represents the
+ // viewport.
+ if (!layer_impl->scrollable() || layer_impl == OuterViewportScrollLayer())
continue;
- if (layer_impl == InnerViewportScrollLayer() ||
- layer_impl == OuterViewportScrollLayer()) {
- if (consume_by_top_controls) {
- gfx::Vector2dF excess_delta =
- top_controls_manager_->ScrollBy(pending_delta);
- gfx::Vector2dF applied_delta = pending_delta - excess_delta;
- pending_delta = excess_delta;
- // Force updating of vertical adjust values if needed.
- if (applied_delta.y() != 0)
- did_scroll_top_controls = true;
- }
- // Track root layer deltas for reporting overscroll.
- if (layer_impl == InnerViewportScrollLayer())
- unused_root_delta = pending_delta;
- }
-
gfx::Vector2dF applied_delta;
- // Gesture events need to be transformed from viewport coordinates to local
- // layer coordinates so that the scrolling contents exactly follow the
- // user's finger. In contrast, wheel events represent a fixed amount of
- // scrolling so we can just apply them directly.
- if (!wheel_scrolling_) {
- float scale_from_viewport_to_screen_space = device_scale_factor_;
- applied_delta =
- ScrollLayerWithViewportSpaceDelta(layer_impl,
- scale_from_viewport_to_screen_space,
- viewport_point, pending_delta);
- } else {
- applied_delta = ScrollLayerWithLocalDelta(layer_impl, pending_delta);
- }
-
- const float kEpsilon = 0.1f;
if (layer_impl == InnerViewportScrollLayer()) {
- unused_root_delta.Subtract(applied_delta);
- if (std::abs(unused_root_delta.x()) < kEpsilon)
- unused_root_delta.set_x(0.0f);
- if (std::abs(unused_root_delta.y()) < kEpsilon)
- unused_root_delta.set_y(0.0f);
- // Disable overscroll on axes which is impossible to scroll.
- if (settings_.report_overscroll_only_for_scrollable_axes) {
- if (std::abs(active_tree_->TotalMaxScrollOffset().x()) <= kEpsilon ||
- !layer_impl->user_scrollable_horizontal())
- unused_root_delta.set_x(0.0f);
- if (std::abs(active_tree_->TotalMaxScrollOffset().y()) <= kEpsilon ||
- !layer_impl->user_scrollable_vertical())
- unused_root_delta.set_y(0.0f);
- }
+ Viewport::ScrollResult result = viewport()->ScrollBy(pending_delta,
+ viewport_point,
+ wheel_scrolling_);
+ applied_delta = result.applied_delta;
+ unused_root_delta = result.unused_scroll_delta;
+ did_scroll_top_controls = result.top_controls_applied_delta.y() != 0;
+ } else {
+ applied_delta = ScrollLayer(layer_impl,
+ pending_delta,
+ viewport_point,
+ wheel_scrolling_);
}
- // Scrolls should bubble perfectly between the outer and inner viewports.
- bool allow_unrestricted_bubbling_for_current_layer =
- layer_impl == OuterViewportScrollLayer();
- bool allow_bubbling_for_current_layer =
- allow_unrestricted_bubbling_for_current_layer || should_bubble_scrolls_;
-
// If the layer wasn't able to move, try the next one in the hierarchy.
+ const float kEpsilon = 0.1f;
bool did_move_layer_x = std::abs(applied_delta.x()) > kEpsilon;
bool did_move_layer_y = std::abs(applied_delta.y()) > kEpsilon;
did_scroll_x |= did_move_layer_x;
did_scroll_y |= did_move_layer_y;
- if (!did_move_layer_x && !did_move_layer_y) {
- if (allow_bubbling_for_current_layer || !did_lock_scrolling_layer_)
- continue;
- else
- break;
- }
- did_lock_scrolling_layer_ = true;
- if (!allow_bubbling_for_current_layer) {
- active_tree_->SetCurrentlyScrollingLayer(layer_impl);
- break;
- }
+ if (did_move_layer_x || did_move_layer_y) {
+ did_lock_scrolling_layer_ = true;
+
+ // When scrolls are allowed to bubble, it's important that the original
+ // scrolling layer be preserved. This ensures that, after a scroll
+ // bubbles, the user can reverse scroll directions and immediately resume
+ // scrolling the original layer that scrolled.
+ if (!should_bubble_scrolls_) {
+ active_tree_->SetCurrentlyScrollingLayer(layer_impl);
+ break;
+ }
- if (allow_unrestricted_bubbling_for_current_layer) {
- pending_delta -= applied_delta;
- } else {
// If the applied delta is within 45 degrees of the input delta, bail out
// to make it easier to scroll just one layer in one direction without
// affecting any of its parents.
float angle_threshold = 45;
if (MathUtil::SmallestAngleBetweenVectors(applied_delta, pending_delta) <
- angle_threshold) {
- pending_delta = gfx::Vector2dF();
+ angle_threshold)
break;
- }
// Allow further movement only on an axis perpendicular to the direction
// in which the layer moved.
gfx::Vector2dF perpendicular_axis(-applied_delta.y(), applied_delta.x());
pending_delta =
MathUtil::ProjectVector(pending_delta, perpendicular_axis);
+
+ if (gfx::ToRoundedVector2d(pending_delta).IsZero())
+ break;
}
- if (gfx::ToRoundedVector2d(pending_delta).IsZero())
+ if (!should_bubble_scrolls_ && did_lock_scrolling_layer_)
break;
}
@@ -2820,7 +2756,8 @@ bool LayerTreeHostImpl::ScrollVerticallyByPage(const gfx::Point& viewport_point,
gfx::Vector2dF delta = gfx::Vector2dF(0.f, page);
- gfx::Vector2dF applied_delta = ScrollLayerWithLocalDelta(layer_impl, delta);
+ gfx::Vector2dF applied_delta =
+ ScrollLayerWithLocalDelta(layer_impl, delta, 1.f);
if (!applied_delta.IsZero()) {
client_->SetNeedsCommitOnImplThread();
@@ -2844,9 +2781,9 @@ void LayerTreeHostImpl::SetRootLayerScrollOffsetDelegate(
void LayerTreeHostImpl::OnRootLayerDelegatedScrollOffsetChanged() {
DCHECK(root_layer_scroll_offset_delegate_);
+ active_tree_->DistributeRootScrollOffset();
client_->SetNeedsCommitOnImplThread();
SetNeedsRedraw();
- active_tree_->OnRootLayerDelegatedScrollOffsetChanged();
active_tree_->set_needs_update_draw_properties();
}
@@ -2858,20 +2795,19 @@ void LayerTreeHostImpl::ClearCurrentlyScrollingLayer() {
}
void LayerTreeHostImpl::ScrollEnd() {
- if (top_controls_manager_)
- top_controls_manager_->ScrollEnd();
+ top_controls_manager_->ScrollEnd();
ClearCurrentlyScrollingLayer();
}
InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() {
if (!active_tree_->CurrentlyScrollingLayer())
- return ScrollIgnored;
+ return SCROLL_IGNORED;
if (settings_.ignore_root_layer_flings &&
(active_tree_->CurrentlyScrollingLayer() == InnerViewportScrollLayer() ||
active_tree_->CurrentlyScrollingLayer() == OuterViewportScrollLayer())) {
ClearCurrentlyScrollingLayer();
- return ScrollIgnored;
+ return SCROLL_IGNORED;
}
if (!wheel_scrolling_) {
@@ -2881,7 +2817,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() {
should_bubble_scrolls_ = false;
}
- return ScrollStarted;
+ return SCROLL_STARTED;
}
float LayerTreeHostImpl::DeviceSpaceDistanceToLayer(
@@ -2925,12 +2861,9 @@ void LayerTreeHostImpl::MouseMoveAt(const gfx::Point& viewport_point) {
}
bool scroll_on_main_thread = false;
- LayerImpl* scroll_layer_impl =
- FindScrollLayerForDeviceViewportPoint(device_viewport_point,
- InputHandler::Gesture,
- layer_impl,
- &scroll_on_main_thread,
- NULL);
+ LayerImpl* scroll_layer_impl = FindScrollLayerForDeviceViewportPoint(
+ device_viewport_point, InputHandler::GESTURE, layer_impl,
+ &scroll_on_main_thread, NULL);
if (scroll_on_main_thread || !scroll_layer_impl)
return;
@@ -2983,8 +2916,7 @@ void LayerTreeHostImpl::PinchGestureBegin() {
active_tree_->SetCurrentlyScrollingLayer(
active_tree_->InnerViewportScrollLayer());
}
- if (top_controls_manager_)
- top_controls_manager_->PinchBegin();
+ top_controls_manager_->PinchBegin();
}
void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta,
@@ -3001,18 +2933,15 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta,
// Keep the center-of-pinch anchor specified by (x, y) in a stable
// position over the course of the magnify.
- float page_scale_delta = active_tree_->page_scale_delta();
- gfx::PointF previous_scale_anchor =
- gfx::ScalePoint(anchor, 1.f / page_scale_delta);
- active_tree_->SetPageScaleDelta(page_scale_delta * magnify_delta);
- page_scale_delta = active_tree_->page_scale_delta();
- gfx::PointF new_scale_anchor =
- gfx::ScalePoint(anchor, 1.f / page_scale_delta);
+ float page_scale = active_tree_->current_page_scale_factor();
+ gfx::PointF previous_scale_anchor = gfx::ScalePoint(anchor, 1.f / page_scale);
+ active_tree_->SetPageScaleOnActiveTree(page_scale * magnify_delta);
+ page_scale = active_tree_->current_page_scale_factor();
+ gfx::PointF new_scale_anchor = gfx::ScalePoint(anchor, 1.f / page_scale);
gfx::Vector2dF move = previous_scale_anchor - new_scale_anchor;
previous_pinch_anchor_ = anchor;
- move.Scale(1 / active_tree_->page_scale_factor());
// If clamping the inner viewport scroll offset causes a change, it should
// be accounted for from the intended move.
move -= InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset();
@@ -3046,17 +2975,13 @@ void LayerTreeHostImpl::PinchGestureEnd() {
pinch_gesture_end_should_clear_scrolling_layer_ = false;
ClearCurrentlyScrollingLayer();
}
- if (top_controls_manager_)
- top_controls_manager_->PinchEnd();
+ top_controls_manager_->PinchEnd();
client_->SetNeedsCommitOnImplThread();
// When a pinch ends, we may be displaying content cached at incorrect scales,
// so updating draw properties and drawing will ensure we are using the right
// scales that we want when we're not inside a pinch.
active_tree_->set_needs_update_draw_properties();
SetNeedsRedraw();
- // TODO(danakj): Don't set root damage. Just updating draw properties and
- // getting new tiles rastered should be enough! crbug.com/427423
- SetFullRootLayerDamage();
}
static void CollectScrollDeltas(ScrollAndScaleSet* scroll_info,
@@ -3064,14 +2989,13 @@ static void CollectScrollDeltas(ScrollAndScaleSet* scroll_info,
if (!layer_impl)
return;
- gfx::Vector2d scroll_delta =
- gfx::ToFlooredVector2d(layer_impl->ScrollDelta());
+ gfx::ScrollOffset scroll_delta = layer_impl->PullDeltaForMainThread();
+
if (!scroll_delta.IsZero()) {
LayerTreeHostCommon::ScrollUpdateInfo scroll;
scroll.layer_id = layer_impl->id();
- scroll.scroll_delta = scroll_delta;
+ scroll.scroll_delta = gfx::Vector2d(scroll_delta.x(), scroll_delta.y());
scroll_info->scrolls.push_back(scroll);
- layer_impl->SetSentScrollDelta(scroll_delta);
}
for (size_t i = 0; i < layer_impl->children().size(); ++i)
@@ -3082,11 +3006,13 @@ scoped_ptr<ScrollAndScaleSet> LayerTreeHostImpl::ProcessScrollDeltas() {
scoped_ptr<ScrollAndScaleSet> scroll_info(new ScrollAndScaleSet());
CollectScrollDeltas(scroll_info.get(), active_tree_->root_layer());
- scroll_info->page_scale_delta = active_tree_->page_scale_delta();
- active_tree_->set_sent_page_scale_delta(scroll_info->page_scale_delta);
+ scroll_info->page_scale_delta =
+ active_tree_->page_scale_factor()->PullDeltaForMainThread();
+ scroll_info->top_controls_delta =
+ active_tree()->top_controls_shown_ratio()->PullDeltaForMainThread();
+ scroll_info->elastic_overscroll_delta =
+ active_tree_->elastic_overscroll()->PullDeltaForMainThread();
scroll_info->swap_promises.swap(swap_promises_for_main_thread_scroll_update_);
- scroll_info->top_controls_delta = active_tree()->top_controls_delta();
- active_tree_->set_sent_top_controls_delta(scroll_info->top_controls_delta);
return scroll_info.Pass();
}
@@ -3125,9 +3051,8 @@ void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) {
if (!page_scale_animation_->IsAnimationStarted())
page_scale_animation_->StartAnimation(monotonic_time);
- active_tree_->SetPageScaleDelta(
- page_scale_animation_->PageScaleFactorAtTime(monotonic_time) /
- active_tree_->page_scale_factor());
+ active_tree_->SetPageScaleOnActiveTree(
+ page_scale_animation_->PageScaleFactorAtTime(monotonic_time));
gfx::ScrollOffset next_scroll = gfx::ScrollOffset(
page_scale_animation_->ScrollOffsetAtTime(monotonic_time));
@@ -3138,13 +3063,14 @@ void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) {
page_scale_animation_ = nullptr;
client_->SetNeedsCommitOnImplThread();
client_->RenewTreePriority();
+ client_->DidCompletePageScaleAnimationOnImplThread();
} else {
SetNeedsAnimate();
}
}
void LayerTreeHostImpl::AnimateTopControls(base::TimeTicks time) {
- if (!top_controls_manager_ || !top_controls_manager_->animation())
+ if (!top_controls_manager_->animation())
return;
gfx::Vector2dF scroll = top_controls_manager_->Animate(time);
@@ -3159,68 +3085,55 @@ void LayerTreeHostImpl::AnimateTopControls(base::TimeTicks time) {
return;
ScrollViewportBy(gfx::ScaleVector2d(
- scroll, 1.f / active_tree_->total_page_scale_factor()));
+ scroll, 1.f / active_tree_->current_page_scale_factor()));
SetNeedsRedraw();
client_->SetNeedsCommitOnImplThread();
client_->RenewTreePriority();
}
-void LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time) {
- if (!settings_.accelerated_animation_enabled ||
- !needs_animate_layers() ||
- !active_tree_->root_layer())
+void LayerTreeHostImpl::AnimateScrollbars(base::TimeTicks monotonic_time) {
+ if (scrollbar_animation_controllers_.empty())
return;
- TRACE_EVENT0("cc", "LayerTreeHostImpl::AnimateLayers");
- AnimationRegistrar::AnimationControllerMap copy =
- animation_registrar_->active_animation_controllers();
- for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
- iter != copy.end();
- ++iter)
- (*iter).second->Animate(monotonic_time);
+ TRACE_EVENT0("cc", "LayerTreeHostImpl::AnimateScrollbars");
+ std::set<ScrollbarAnimationController*> controllers_copy =
+ scrollbar_animation_controllers_;
+ for (auto& it : controllers_copy)
+ it->Animate(monotonic_time);
SetNeedsAnimate();
}
+void LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time) {
+ if (!settings_.accelerated_animation_enabled || !active_tree_->root_layer())
+ return;
+
+ if (animation_registrar_->AnimateLayers(monotonic_time))
+ SetNeedsAnimate();
+}
+
void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) {
- if (!settings_.accelerated_animation_enabled ||
- !needs_animate_layers() ||
- !active_tree_->root_layer())
+ if (!settings_.accelerated_animation_enabled || !active_tree_->root_layer())
return;
- TRACE_EVENT0("cc", "LayerTreeHostImpl::UpdateAnimationState");
scoped_ptr<AnimationEventsVector> events =
- make_scoped_ptr(new AnimationEventsVector);
- AnimationRegistrar::AnimationControllerMap copy =
- animation_registrar_->active_animation_controllers();
- for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
- iter != copy.end();
- ++iter)
- (*iter).second->UpdateState(start_ready_animations, events.get());
-
- if (!events->empty()) {
+ animation_registrar_->CreateEvents();
+ const bool has_active_animations = animation_registrar_->UpdateAnimationState(
+ start_ready_animations, events.get());
+
+ if (!events->empty())
client_->PostAnimationEventsToMainThreadOnImplThread(events.Pass());
- }
- SetNeedsAnimate();
+ if (has_active_animations)
+ SetNeedsAnimate();
}
void LayerTreeHostImpl::ActivateAnimations() {
- if (!settings_.accelerated_animation_enabled || !needs_animate_layers() ||
- !active_tree_->root_layer())
+ if (!settings_.accelerated_animation_enabled || !active_tree_->root_layer())
return;
- TRACE_EVENT0("cc", "LayerTreeHostImpl::ActivateAnimations");
- AnimationRegistrar::AnimationControllerMap copy =
- animation_registrar_->active_animation_controllers();
- for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
- iter != copy.end();
- ++iter)
- (*iter).second->ActivateAnimations();
-}
-
-base::TimeDelta LayerTreeHostImpl::LowFrequencyAnimationInterval() const {
- return base::TimeDelta::FromSeconds(1);
+ if (animation_registrar_->ActivateAnimations())
+ SetNeedsAnimate();
}
std::string LayerTreeHostImpl::LayerTreeAsJson() const {
@@ -3237,36 +3150,42 @@ int LayerTreeHostImpl::SourceAnimationFrameNumber() const {
return fps_counter_->current_frame_number();
}
-void LayerTreeHostImpl::AnimateScrollbars(base::TimeTicks time) {
- AnimateScrollbarsRecursive(active_tree_->root_layer(), time);
+void LayerTreeHostImpl::StartAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) {
+ scrollbar_animation_controllers_.insert(controller);
+ SetNeedsAnimate();
}
-void LayerTreeHostImpl::AnimateScrollbarsRecursive(LayerImpl* layer,
- base::TimeTicks time) {
- if (!layer)
- return;
+void LayerTreeHostImpl::StopAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) {
+ scrollbar_animation_controllers_.erase(controller);
+}
- ScrollbarAnimationController* scrollbar_controller =
- layer->scrollbar_animation_controller();
- if (scrollbar_controller)
- scrollbar_controller->Animate(time);
+void LayerTreeHostImpl::PostDelayedScrollbarAnimationTask(
+ const base::Closure& task,
+ base::TimeDelta delay) {
+ client_->PostDelayedAnimationTaskOnImplThread(task, delay);
+}
- for (size_t i = 0; i < layer->children().size(); ++i)
- AnimateScrollbarsRecursive(layer->children()[i], time);
+void LayerTreeHostImpl::SetNeedsRedrawForScrollbarAnimation() {
+ SetNeedsRedraw();
}
-void LayerTreeHostImpl::PostDelayedScrollbarFade(
- const base::Closure& start_fade,
- base::TimeDelta delay) {
- client_->PostDelayedScrollbarFadeOnImplThread(start_fade, delay);
+void LayerTreeHostImpl::AddVideoFrameController(
+ VideoFrameController* controller) {
+ bool was_empty = video_frame_controllers_.empty();
+ video_frame_controllers_.insert(controller);
+ if (current_begin_frame_args_.IsValid())
+ controller->OnBeginFrame(current_begin_frame_args_);
+ if (was_empty)
+ client_->SetVideoNeedsBeginFrames(true);
}
-void LayerTreeHostImpl::SetNeedsScrollbarAnimationFrame() {
- TRACE_EVENT_INSTANT0(
- "cc",
- "LayerTreeHostImpl::SetNeedsRedraw due to scrollbar fade",
- TRACE_EVENT_SCOPE_THREAD);
- SetNeedsAnimate();
+void LayerTreeHostImpl::RemoveVideoFrameController(
+ VideoFrameController* controller) {
+ video_frame_controllers_.erase(controller);
+ if (video_frame_controllers_.empty())
+ client_->SetVideoNeedsBeginFrames(false);
}
void LayerTreeHostImpl::SetTreePriority(TreePriority priority) {
@@ -3283,72 +3202,45 @@ TreePriority LayerTreeHostImpl::GetTreePriority() const {
return global_tile_state_.tree_priority;
}
-void LayerTreeHostImpl::UpdateCurrentBeginFrameArgs(
- const BeginFrameArgs& args) {
- DCHECK(!current_begin_frame_args_.IsValid());
- current_begin_frame_args_ = args;
- // TODO(skyostil): Stop overriding the frame time once the usage of frame
- // timing is unified.
- current_begin_frame_args_.frame_time = gfx::FrameTime::Now();
-}
-
-void LayerTreeHostImpl::ResetCurrentBeginFrameArgsForNextFrame() {
- current_begin_frame_args_ = BeginFrameArgs();
-}
-
BeginFrameArgs LayerTreeHostImpl::CurrentBeginFrameArgs() const {
// Try to use the current frame time to keep animations non-jittery. But if
// we're not in a frame (because this is during an input event or a delayed
// task), fall back to physical time. This should still be monotonic.
if (current_begin_frame_args_.IsValid())
return current_begin_frame_args_;
- return BeginFrameArgs::Create(gfx::FrameTime::Now(),
- base::TimeTicks(),
- BeginFrameArgs::DefaultInterval());
+ return BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, gfx::FrameTime::Now(), base::TimeTicks(),
+ BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
}
-void LayerTreeHostImpl::AsValueInto(base::debug::TracedValue* value) const {
- return AsValueWithFrameInto(NULL, value);
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-LayerTreeHostImpl::AsValue() const {
- return AsValueWithFrame(NULL);
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
LayerTreeHostImpl::AsValueWithFrame(FrameData* frame) const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
+ scoped_refptr<base::trace_event::TracedValue> state =
+ new base::trace_event::TracedValue();
AsValueWithFrameInto(frame, state.get());
return state;
}
void LayerTreeHostImpl::AsValueWithFrameInto(
FrameData* frame,
- base::debug::TracedValue* state) const {
+ base::trace_event::TracedValue* state) const {
if (this->pending_tree_) {
state->BeginDictionary("activation_state");
ActivationStateAsValueInto(state);
state->EndDictionary();
}
- state->BeginDictionary("device_viewport_size");
- MathUtil::AddToTracedValue(device_viewport_size_, state);
- state->EndDictionary();
+ MathUtil::AddToTracedValue("device_viewport_size", device_viewport_size_,
+ state);
- std::set<const Tile*> tiles;
- active_tree_->GetAllTilesForTracing(&tiles);
+ std::vector<PrioritizedTile> prioritized_tiles;
+ active_tree_->GetAllPrioritizedTilesForTracing(&prioritized_tiles);
if (pending_tree_)
- pending_tree_->GetAllTilesForTracing(&tiles);
+ pending_tree_->GetAllPrioritizedTilesForTracing(&prioritized_tiles);
state->BeginArray("active_tiles");
- for (std::set<const Tile*>::const_iterator it = tiles.begin();
- it != tiles.end();
- ++it) {
- const Tile* tile = *it;
-
+ for (const auto& prioritized_tile : prioritized_tiles) {
state->BeginDictionary();
- tile->AsValueInto(state);
+ prioritized_tile.AsValueInto(state);
state->EndDictionary();
}
state->EndArray();
@@ -3373,16 +3265,8 @@ void LayerTreeHostImpl::AsValueWithFrameInto(
}
}
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-LayerTreeHostImpl::ActivationStateAsValue() const {
- scoped_refptr<base::debug::TracedValue> state =
- new base::debug::TracedValue();
- ActivationStateAsValueInto(state.get());
- return state;
-}
-
void LayerTreeHostImpl::ActivationStateAsValueInto(
- base::debug::TracedValue* state) const {
+ base::trace_event::TracedValue* state) const {
TracedValue::SetIDRef(this, state, "lthi");
if (tile_manager_) {
state->BeginDictionary("tile_manager");
@@ -3434,11 +3318,9 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
format = ETC1;
break;
}
- id =
- resource_provider_->CreateResource(bitmap.GetSize(),
- wrap_mode,
- ResourceProvider::TextureHintImmutable,
- format);
+ id = resource_provider_->CreateResource(
+ bitmap.GetSize(), wrap_mode, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ format);
UIResourceData data;
data.resource_id = id;
@@ -3448,11 +3330,8 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
ui_resource_map_[uid] = data;
AutoLockUIResourceBitmap bitmap_lock(bitmap);
- resource_provider_->SetPixels(id,
- bitmap_lock.GetPixels(),
- gfx::Rect(bitmap.GetSize()),
- gfx::Rect(bitmap.GetSize()),
- gfx::Vector2d(0, 0));
+ resource_provider_->CopyToResource(id, bitmap_lock.GetPixels(),
+ bitmap.GetSize());
MarkUIResourceNotEvicted(uid);
}
@@ -3535,17 +3414,47 @@ void LayerTreeHostImpl::NotifySwapPromiseMonitorsOfForwardingToMainThread() {
(*it)->OnForwardScrollUpdateToMainThreadOnImpl();
}
-void LayerTreeHostImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
- DCHECK(std::find(picture_layers_.begin(), picture_layers_.end(), layer) ==
- picture_layers_.end());
- picture_layers_.push_back(layer);
-}
+void LayerTreeHostImpl::ScrollAnimationCreate(
+ LayerImpl* layer_impl,
+ const gfx::ScrollOffset& target_offset,
+ const gfx::ScrollOffset& current_offset) {
+ scoped_ptr<ScrollOffsetAnimationCurve> curve =
+ ScrollOffsetAnimationCurve::Create(target_offset,
+ EaseInOutTimingFunction::Create());
+ curve->SetInitialValue(current_offset);
-void LayerTreeHostImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
- std::vector<PictureLayerImpl*>::iterator it =
- std::find(picture_layers_.begin(), picture_layers_.end(), layer);
- DCHECK(it != picture_layers_.end());
- picture_layers_.erase(it);
+ scoped_ptr<Animation> animation = Animation::Create(
+ curve.Pass(), AnimationIdProvider::NextAnimationId(),
+ AnimationIdProvider::NextGroupId(), Animation::SCROLL_OFFSET);
+ animation->set_is_impl_only(true);
+
+ layer_impl->layer_animation_controller()->AddAnimation(animation.Pass());
}
+bool LayerTreeHostImpl::ScrollAnimationUpdateTarget(
+ LayerImpl* layer_impl,
+ const gfx::Vector2dF& scroll_delta) {
+ Animation* animation =
+ layer_impl->layer_animation_controller()
+ ? layer_impl->layer_animation_controller()->GetAnimation(
+ Animation::SCROLL_OFFSET)
+ : nullptr;
+ if (!animation)
+ return false;
+
+ ScrollOffsetAnimationCurve* curve =
+ animation->curve()->ToScrollOffsetAnimationCurve();
+
+ gfx::ScrollOffset new_target =
+ gfx::ScrollOffsetWithDelta(curve->target_value(), scroll_delta);
+ new_target.SetToMax(gfx::ScrollOffset());
+ new_target.SetToMin(layer_impl->MaxScrollOffset());
+
+ curve->UpdateTarget(
+ animation->TrimTimeToCurrentIteration(CurrentBeginFrameArgs().frame_time)
+ .InSecondsF(),
+ new_target);
+
+ return true;
+}
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index 2309ef77d5f..42454a61c00 100644
--- a/chromium/cc/trees/layer_tree_host_impl.h
+++ b/chromium/cc/trees/layer_tree_host_impl.h
@@ -5,7 +5,6 @@
#ifndef CC_TREES_LAYER_TREE_HOST_IMPL_H_
#define CC_TREES_LAYER_TREE_HOST_IMPL_H_
-#include <list>
#include <set>
#include <string>
#include <vector>
@@ -18,6 +17,8 @@
#include "cc/animation/animation_registrar.h"
#include "cc/animation/scrollbar_animation_controller.h"
#include "cc/base/cc_export.h"
+#include "cc/base/synced_property.h"
+#include "cc/debug/frame_timing_tracker.h"
#include "cc/debug/micro_benchmark_controller_impl.h"
#include "cc/input/input_handler.h"
#include "cc/input/layer_scroll_offset_delegate.h"
@@ -30,13 +31,21 @@
#include "cc/output/renderer.h"
#include "cc/quads/render_pass.h"
#include "cc/resources/resource_provider.h"
-#include "cc/resources/tile_manager.h"
-#include "cc/scheduler/begin_frame_source.h"
+#include "cc/resources/ui_resource_client.h"
+#include "cc/scheduler/commit_earlyout_reason.h"
#include "cc/scheduler/draw_result.h"
+#include "cc/scheduler/video_frame_controller.h"
+#include "cc/tiles/tile_manager.h"
+#include "cc/trees/layer_tree_settings.h"
+#include "cc/trees/proxy.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/rect.h"
+namespace gfx {
+class ScrollOffset;
+}
+
namespace cc {
class CompletionEvent;
@@ -45,23 +54,35 @@ class DebugRectHistory;
class EvictionTilePriorityQueue;
class FrameRateCounter;
class LayerImpl;
-class LayerTreeHostImplTimeSourceAdapter;
class LayerTreeImpl;
class MemoryHistory;
class PageScaleAnimation;
class PaintTimeCounter;
class PictureLayerImpl;
class RasterTilePriorityQueue;
-class RasterWorkerPool;
+class TileTaskWorkerPool;
class RenderPassDrawQuad;
class RenderingStatsInstrumentation;
class ResourcePool;
+class ScrollElasticityHelper;
class ScrollbarLayerImplBase;
+class SwapPromise;
+class SwapPromiseMonitor;
class TextureMailboxDeleter;
class TopControlsManager;
class UIResourceBitmap;
class UIResourceRequest;
-struct RendererCapabilitiesImpl;
+struct ScrollAndScaleSet;
+class Viewport;
+
+enum class GpuRasterizationStatus {
+ ON,
+ ON_FORCED,
+ OFF_DEVICE,
+ OFF_VIEWPORT,
+ MSAA_CONTENT,
+ OFF_CONTENT
+};
// LayerTreeHost->Proxy callback interface.
class LayerTreeHostImplClient {
@@ -76,15 +97,16 @@ class LayerTreeHostImplClient {
virtual void DidSwapBuffersCompleteOnImplThread() = 0;
virtual void OnCanDrawStateChanged(bool can_draw) = 0;
virtual void NotifyReadyToActivate() = 0;
+ virtual void NotifyReadyToDraw() = 0;
// Please call these 3 functions through
// LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
// SetNeedsAnimate().
virtual void SetNeedsRedrawOnImplThread() = 0;
virtual void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) = 0;
virtual void SetNeedsAnimateOnImplThread() = 0;
- virtual void DidInitializeVisibleTileOnImplThread() = 0;
virtual void SetNeedsCommitOnImplThread() = 0;
- virtual void SetNeedsManageTilesOnImplThread() = 0;
+ virtual void SetNeedsPrepareTilesOnImplThread() = 0;
+ virtual void SetVideoNeedsBeginFrames(bool needs_begin_frames) = 0;
virtual void PostAnimationEventsToMainThreadOnImplThread(
scoped_ptr<AnimationEventsVector> events) = 0;
// Returns true if resources were deleted by this call.
@@ -93,11 +115,16 @@ class LayerTreeHostImplClient {
int priority_cutoff) = 0;
virtual bool IsInsideDraw() = 0;
virtual void RenewTreePriority() = 0;
- virtual void PostDelayedScrollbarFadeOnImplThread(
- const base::Closure& start_fade,
- base::TimeDelta delay) = 0;
+ virtual void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
+ base::TimeDelta delay) = 0;
virtual void DidActivateSyncTree() = 0;
- virtual void DidManageTiles() = 0;
+ virtual void DidPrepareTiles() = 0;
+
+ // Called when page scale animation has completed on the impl thread.
+ virtual void DidCompletePageScaleAnimationOnImplThread() = 0;
+
+ // Called when output surface asks for a draw.
+ virtual void OnDrawForOutputSurface() = 0;
protected:
virtual ~LayerTreeHostImplClient() {}
@@ -112,7 +139,7 @@ class CC_EXPORT LayerTreeHostImpl
public OutputSurfaceClient,
public TopControlsManagerClient,
public ScrollbarAnimationControllerClient,
- public BeginFrameSourceMixIn,
+ public VideoFrameControllerClient,
public base::SupportsWeakPtr<LayerTreeHostImpl> {
public:
static scoped_ptr<LayerTreeHostImpl> Create(
@@ -122,12 +149,10 @@ class CC_EXPORT LayerTreeHostImpl
RenderingStatsInstrumentation* rendering_stats_instrumentation,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
int id);
~LayerTreeHostImpl() override;
- // BeginFrameSourceMixIn implementation
- void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
-
// InputHandler implementation
void BindToClient(InputHandlerClient* client) override;
InputHandler::ScrollStatus ScrollBegin(
@@ -151,56 +176,64 @@ class CC_EXPORT LayerTreeHostImpl
void PinchGestureUpdate(float magnify_delta,
const gfx::Point& anchor) override;
void PinchGestureEnd() override;
+ void StartPageScaleAnimation(const gfx::Vector2d& target_offset,
+ bool anchor_point,
+ float page_scale,
+ base::TimeDelta duration);
void SetNeedsAnimate() override;
bool IsCurrentlyScrollingLayerAt(const gfx::Point& viewport_point,
InputHandler::ScrollInputType type) override;
- bool HaveTouchEventHandlersAt(const gfx::Point& viewport_port) override;
+ bool HaveWheelEventHandlersAt(const gfx::Point& viewport_point) override;
+ bool DoTouchEventsBlockScrollAt(const gfx::Point& viewport_port) override;
scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
ui::LatencyInfo* latency) override;
+ ScrollElasticityHelper* CreateScrollElasticityHelper() override;
// TopControlsManagerClient implementation.
- void SetControlsTopOffset(float offset) override;
- float ControlsTopOffset() const override;
+ float TopControlsHeight() const override;
+ void SetCurrentTopControlsShownRatio(float offset) override;
+ float CurrentTopControlsShownRatio() const override;
void DidChangeTopControlsPosition() override;
bool HaveRootScrollLayer() const override;
+ void UpdateViewportContainerSizes();
+
struct CC_EXPORT FrameData : public RenderPassSink {
FrameData();
~FrameData() override;
- void AsValueInto(base::debug::TracedValue* value) const;
+ void AsValueInto(base::trace_event::TracedValue* value) const;
std::vector<gfx::Rect> occluding_screen_space_rects;
std::vector<gfx::Rect> non_occluding_screen_space_rects;
+ std::vector<FrameTimingTracker::FrameAndRectIds> composite_events;
RenderPassList render_passes;
RenderPassIdHashMap render_passes_by_id;
const LayerImplList* render_surface_layer_list;
LayerImplList will_draw_layers;
- bool contains_incomplete_tile;
bool has_no_damage;
// RenderPassSink implementation.
void AppendRenderPass(scoped_ptr<RenderPass> render_pass) override;
};
- virtual void BeginMainFrameAborted(bool did_handle);
+ virtual void BeginMainFrameAborted(CommitEarlyOutReason reason);
virtual void BeginCommit();
virtual void CommitComplete();
virtual void Animate(base::TimeTicks monotonic_time);
virtual void UpdateAnimationState(bool start_ready_animations);
void ActivateAnimations();
void MainThreadHasStoppedFlinging();
- void UpdateBackgroundAnimateTicking(bool should_background_tick);
void DidAnimateScrollOffset();
void SetViewportDamage(const gfx::Rect& damage_rect);
- virtual void ManageTiles();
+ virtual void PrepareTiles();
// Returns DRAW_SUCCESS unless problems occured preparing the frame, and we
// should try to avoid displaying the frame. If PrepareToDraw is called,
// DidDrawAllLayers must also be called, regardless of whether DrawLayers is
// called between the two.
virtual DrawResult PrepareToDraw(FrameData* frame);
- virtual void DrawLayers(FrameData* frame, base::TimeTicks frame_begin_time);
+ virtual void DrawLayers(FrameData* frame);
// Must be called if and only if PrepareToDraw was called.
void DidDrawAllLayers(const FrameData& frame);
@@ -214,9 +247,6 @@ class CC_EXPORT LayerTreeHostImpl
// immediately if any notifications had been blocked while blocking.
virtual void BlockNotifyReadyToActivateForTesting(bool block);
- // This allows us to inject DidInitializeVisibleTile events for testing.
- void DidInitializeVisibleTileForTesting();
-
// Resets all of the trees to an empty state.
void ResetTreesForTesting();
@@ -233,27 +263,33 @@ class CC_EXPORT LayerTreeHostImpl
void SetFullRootLayerDamage() override;
// TileManagerClient implementation.
- const std::vector<PictureLayerImpl*>& GetPictureLayers() const override;
void NotifyReadyToActivate() override;
+ void NotifyReadyToDraw() override;
void NotifyTileStateChanged(const Tile* tile) override;
- void BuildRasterQueue(RasterTilePriorityQueue* queue,
- TreePriority tree_priority) override;
- void BuildEvictionQueue(EvictionTilePriorityQueue* queue,
- TreePriority tree_priority) override;
+ scoped_ptr<RasterTilePriorityQueue> BuildRasterQueue(
+ TreePriority tree_priority,
+ RasterTilePriorityQueue::Type type) override;
+ scoped_ptr<EvictionTilePriorityQueue> BuildEvictionQueue(
+ TreePriority tree_priority) override;
+ void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) override;
// ScrollbarAnimationControllerClient implementation.
- void PostDelayedScrollbarFade(const base::Closure& start_fade,
- base::TimeDelta delay) override;
- void SetNeedsScrollbarAnimationFrame() override;
+ void StartAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) override;
+ void StopAnimatingScrollbarAnimationController(
+ ScrollbarAnimationController* controller) override;
+ void PostDelayedScrollbarAnimationTask(const base::Closure& task,
+ base::TimeDelta delay) override;
+ void SetNeedsRedrawForScrollbarAnimation() override;
+
+ // VideoBeginFrameSource implementation.
+ void AddVideoFrameController(VideoFrameController* controller) override;
+ void RemoveVideoFrameController(VideoFrameController* controller) override;
// OutputSurfaceClient implementation.
- void DeferredInitialize() override;
- void ReleaseGL() override;
void CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) override;
void SetNeedsRedrawRect(const gfx::Rect& rect) override;
- void BeginFrame(const BeginFrameArgs& args) override;
-
void SetExternalDrawConstraints(
const gfx::Transform& transform,
const gfx::Rect& viewport,
@@ -267,6 +303,7 @@ class CC_EXPORT LayerTreeHostImpl
void ReclaimResources(const CompositorFrameAck* ack) override;
void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
void SetTreeActivationCallback(const base::Closure& callback) override;
+ void OnDraw() override;
// Called from LayerTreeImpl.
void OnCanDrawStateChangedForTree();
@@ -283,8 +320,24 @@ class CC_EXPORT LayerTreeHostImpl
virtual bool InitializeRenderer(scoped_ptr<OutputSurface> output_surface);
TileManager* tile_manager() { return tile_manager_.get(); }
- void SetUseGpuRasterization(bool use_gpu);
+
+ void SetHasGpuRasterizationTrigger(bool flag) {
+ has_gpu_rasterization_trigger_ = flag;
+ UpdateGpuRasterizationStatus();
+ }
+ void SetContentIsSuitableForGpuRasterization(bool flag) {
+ content_is_suitable_for_gpu_rasterization_ = flag;
+ UpdateGpuRasterizationStatus();
+ }
+ bool CanUseGpuRasterization();
+ void UpdateTreeResourcesForGpuRasterizationIfNeeded();
bool use_gpu_rasterization() const { return use_gpu_rasterization_; }
+ bool use_msaa() const { return use_msaa_; }
+
+ GpuRasterizationStatus gpu_rasterization_status() const {
+ return gpu_rasterization_status_;
+ }
+
bool create_low_res_tiling() const {
return settings_.create_low_res_tiling && !use_gpu_rasterization_;
}
@@ -294,6 +347,7 @@ class CC_EXPORT LayerTreeHostImpl
virtual bool SwapBuffers(const FrameData& frame);
virtual void WillBeginImplFrame(const BeginFrameArgs& args);
+ virtual void DidFinishImplFrame();
void DidModifyTilePriorities();
LayerTreeImpl* active_tree() { return active_tree_.get(); }
@@ -304,10 +358,11 @@ class CC_EXPORT LayerTreeHostImpl
const LayerTreeImpl* recycle_tree() const { return recycle_tree_.get(); }
// Returns the tree LTH synchronizes with.
LayerTreeImpl* sync_tree() {
+ // TODO(enne): This is bogus. It should return based on the value of
+ // Proxy::CommitToActiveTree and not whether the pending tree exists.
return pending_tree_ ? pending_tree_.get() : active_tree_.get();
}
virtual void CreatePendingTree();
- virtual void UpdateVisibleTiles();
virtual void ActivateSyncTree();
// Shortcuts to layers on the active tree.
@@ -330,6 +385,8 @@ class CC_EXPORT LayerTreeHostImpl
virtual void SetVisible(bool visible);
bool visible() const { return visible_; }
+ bool AnimationsAreVisible() { return visible() && CanDraw(); }
+
void SetNeedsCommit() { client_->SetNeedsCommitOnImplThread(); }
void SetNeedsRedraw();
@@ -341,20 +398,15 @@ class CC_EXPORT LayerTreeHostImpl
void SetViewportSize(const gfx::Size& device_viewport_size);
gfx::Size device_viewport_size() const { return device_viewport_size_; }
- void SetOverhangUIResource(UIResourceId overhang_ui_resource_id,
- const gfx::Size& overhang_ui_resource_size);
-
void SetDeviceScaleFactor(float device_scale_factor);
float device_scale_factor() const { return device_scale_factor_; }
+ void SetPageScaleOnActiveTree(float page_scale_factor);
+
const gfx::Transform& DrawTransform() const;
scoped_ptr<ScrollAndScaleSet> ProcessScrollDeltas();
- bool needs_animate_layers() const {
- return !animation_registrar_->active_animation_controllers().empty();
- }
-
void set_max_memory_needed_bytes(size_t bytes) {
max_memory_needed_bytes_ = bytes;
}
@@ -390,23 +442,6 @@ class CC_EXPORT LayerTreeHostImpl
void SetDebugState(const LayerTreeDebugState& new_debug_state);
const LayerTreeDebugState& debug_state() const { return debug_state_; }
- class CC_EXPORT CullRenderPassesWithNoQuads {
- public:
- bool ShouldRemoveRenderPass(const RenderPassDrawQuad& quad,
- const FrameData& frame) const;
-
- // Iterates in draw order, so that when a surface is removed, and its
- // target becomes empty, then its target can be removed also.
- size_t RenderPassListBegin(const RenderPassList& list) const { return 0; }
- size_t RenderPassListEnd(const RenderPassList& list) const {
- return list.size();
- }
- size_t RenderPassListNext(size_t it) const { return it + 1; }
- };
-
- template <typename RenderPassCuller>
- static void RemoveRenderPasses(RenderPassCuller culler, FrameData* frame);
-
gfx::Vector2dF accumulated_root_overscroll() const {
return accumulated_root_overscroll_;
}
@@ -416,8 +451,6 @@ class CC_EXPORT LayerTreeHostImpl
void SetTreePriority(TreePriority priority);
TreePriority GetTreePriority() const;
- void UpdateCurrentBeginFrameArgs(const BeginFrameArgs& args);
- void ResetCurrentBeginFrameArgsForNextFrame();
virtual BeginFrameArgs CurrentBeginFrameArgs() const;
// Expected time between two begin impl frame calls.
@@ -425,15 +458,11 @@ class CC_EXPORT LayerTreeHostImpl
return begin_impl_frame_interval_;
}
- void AsValueInto(base::debug::TracedValue* value) const override;
void AsValueWithFrameInto(FrameData* frame,
- base::debug::TracedValue* value) const;
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsValueWithFrame(
+ base::trace_event::TracedValue* value) const;
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValueWithFrame(
FrameData* frame) const;
- scoped_refptr<base::debug::ConvertableToTraceFormat> ActivationStateAsValue()
- const;
- void ActivationStateAsValueInto(base::debug::TracedValue* value) const;
+ void ActivationStateAsValueInto(base::trace_event::TracedValue* value) const;
bool page_scale_animation_active() const { return !!page_scale_animation_; }
@@ -471,14 +500,8 @@ class CC_EXPORT LayerTreeHostImpl
void InsertSwapPromiseMonitor(SwapPromiseMonitor* monitor);
void RemoveSwapPromiseMonitor(SwapPromiseMonitor* monitor);
- void RegisterPictureLayerImpl(PictureLayerImpl* layer);
- void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
-
- void GetPictureLayerImplPairs(
- std::vector<PictureLayerImpl::Pair>* layers) const;
-
- void SetTopControlsLayoutHeight(float height);
-
+ // TODO(weiliangc): Replace RequiresHighResToDraw with scheduler waits for
+ // ReadyToDraw. crbug.com/469175
void SetRequiresHighResToDraw() { requires_high_res_to_draw_ = true; }
void ResetRequiresHighResToDraw() { requires_high_res_to_draw_ = false; }
bool RequiresHighResToDraw() const { return requires_high_res_to_draw_; }
@@ -486,13 +509,35 @@ class CC_EXPORT LayerTreeHostImpl
// Only valid for synchronous (non-scheduled) single-threaded case.
void SynchronouslyInitializeAllTiles();
- bool CanUseZeroCopyRasterizer() const;
- bool CanUseOneCopyRasterizer() const;
- virtual void CreateResourceAndRasterWorkerPool(
- scoped_ptr<RasterWorkerPool>* raster_worker_pool,
+ virtual void CreateResourceAndTileTaskWorkerPool(
+ scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool,
scoped_ptr<ResourcePool>* resource_pool,
scoped_ptr<ResourcePool>* staging_resource_pool);
+ bool prepare_tiles_needed() const { return tile_priorities_dirty_; }
+
+ FrameTimingTracker* frame_timing_tracker() {
+ return frame_timing_tracker_.get();
+ }
+
+ gfx::Vector2dF ScrollLayer(LayerImpl* layer_impl,
+ const gfx::Vector2dF& delta,
+ const gfx::Point& viewport_point,
+ bool is_wheel_scroll);
+
+ // Record main frame timing information.
+ // |start_of_main_frame_args| is the BeginFrameArgs of the beginning of the
+ // main frame (ie the frame that kicked off the main frame).
+ // |expected_next_main_frame_args| is the BeginFrameArgs of the frame that
+ // follows the completion of the main frame (whether it is activation or some
+ // other completion, such as early out). Note that if there is a main frame
+ // scheduled in that frame, then this BeginFrameArgs will become the main
+ // frame args. However, if no such frame is scheduled, then this _would_ be
+ // the main frame args if it was scheduled.
+ void RecordMainFrameTiming(
+ const BeginFrameArgs& start_of_main_frame_args,
+ const BeginFrameArgs& expected_next_main_frame_args);
+
protected:
LayerTreeHostImpl(
const LayerTreeSettings& settings,
@@ -501,52 +546,51 @@ class CC_EXPORT LayerTreeHostImpl
RenderingStatsInstrumentation* rendering_stats_instrumentation,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
int id);
- void UpdateViewportContainerSizes();
-
// Virtual for testing.
virtual void AnimateLayers(base::TimeTicks monotonic_time);
- virtual base::TimeDelta LowFrequencyAnimationInterval() const;
- const AnimationRegistrar::AnimationControllerMap&
- active_animation_controllers() const {
- return animation_registrar_->active_animation_controllers();
+ bool is_likely_to_require_a_draw() const {
+ return is_likely_to_require_a_draw_;
}
- bool manage_tiles_needed() const { return tile_priorities_dirty_; }
+ // Removes empty or orphan RenderPasses from the frame.
+ static void RemoveRenderPasses(FrameData* frame);
LayerTreeHostImplClient* client_;
Proxy* proxy_;
private:
+ gfx::Vector2dF ScrollLayerWithViewportSpaceDelta(
+ LayerImpl* layer_impl,
+ const gfx::PointF& viewport_point,
+ const gfx::Vector2dF& viewport_delta);
+
void CreateAndSetRenderer();
void CreateAndSetTileManager();
void DestroyTileManager();
void ReleaseTreeResources();
- void EnforceZeroBudget(bool zero_budget);
+ void RecreateTreeResources();
+
+ void UpdateGpuRasterizationStatus();
- bool UsePendingTreeForSync() const;
bool IsSynchronousSingleThreaded() const;
+ Viewport* viewport() { return viewport_.get(); }
+
// Scroll by preferring to move the outer viewport first, only moving the
// inner if the outer is at its scroll extents.
void ScrollViewportBy(gfx::Vector2dF scroll_delta);
// Scroll by preferring to move the inner viewport first, only moving the
// outer if the inner is at its scroll extents.
void ScrollViewportInnerFirst(gfx::Vector2dF scroll_delta);
+
void AnimatePageScale(base::TimeTicks monotonic_time);
void AnimateScrollbars(base::TimeTicks monotonic_time);
void AnimateTopControls(base::TimeTicks monotonic_time);
- bool ShouldTopControlsConsumeScroll(const gfx::Vector2dF& scroll_delta) const;
-
- gfx::Vector2dF ScrollLayerWithViewportSpaceDelta(
- LayerImpl* layer_impl,
- float scale_from_viewport_to_screen_space,
- const gfx::PointF& viewport_point,
- const gfx::Vector2dF& viewport_delta);
-
void TrackDamageForAllSurfaces(
LayerImpl* root_draw_layer,
const LayerImplList& render_surface_layer_list);
@@ -563,9 +607,6 @@ class CC_EXPORT LayerTreeHostImpl
bool HandleMouseOverScrollbar(LayerImpl* layer_impl,
const gfx::PointF& device_viewport_point);
- void AnimateScrollbarsRecursive(LayerImpl* layer,
- base::TimeTicks time);
-
LayerImpl* FindScrollLayerForDeviceViewportPoint(
const gfx::PointF& device_viewport_point,
InputHandler::ScrollInputType type,
@@ -575,17 +616,20 @@ class CC_EXPORT LayerTreeHostImpl
float DeviceSpaceDistanceToLayer(const gfx::PointF& device_viewport_point,
LayerImpl* layer_impl);
void StartScrollbarFadeRecursive(LayerImpl* layer);
- void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy,
- bool zero_budget);
+ void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy);
void EnforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy);
- void DidInitializeVisibleTile();
-
void MarkUIResourceNotEvicted(UIResourceId uid);
void NotifySwapPromiseMonitorsOfSetNeedsRedraw();
void NotifySwapPromiseMonitorsOfForwardingToMainThread();
+ void ScrollAnimationCreate(LayerImpl* layer_impl,
+ const gfx::ScrollOffset& target_offset,
+ const gfx::ScrollOffset& current_offset);
+ bool ScrollAnimationUpdateTarget(LayerImpl* layer_impl,
+ const gfx::Vector2dF& scroll_delta);
+
typedef base::hash_map<UIResourceId, UIResourceData>
UIResourceMap;
UIResourceMap ui_resource_map_;
@@ -599,10 +643,16 @@ class CC_EXPORT LayerTreeHostImpl
// |resource_provider_| and |tile_manager_| can be NULL, e.g. when using tile-
// free rendering - see OutputSurface::ForcedDrawToSoftwareDevice().
+ // |tile_manager_| can also be NULL when raster_enabled is false.
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<TileManager> tile_manager_;
+ bool content_is_suitable_for_gpu_rasterization_;
+ bool has_gpu_rasterization_trigger_;
bool use_gpu_rasterization_;
- scoped_ptr<RasterWorkerPool> raster_worker_pool_;
+ bool use_msaa_;
+ GpuRasterizationStatus gpu_rasterization_status_;
+ bool tree_resources_for_gpu_rasterization_dirty_;
+ scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_;
scoped_ptr<ResourcePool> resource_pool_;
scoped_ptr<ResourcePool> staging_resource_pool_;
scoped_ptr<Renderer> renderer_;
@@ -628,11 +678,15 @@ class CC_EXPORT LayerTreeHostImpl
int scroll_layer_id_when_mouse_over_scrollbar_;
ScopedPtrVector<SwapPromise> swap_promises_for_main_thread_scroll_update_;
+ // An object to implement the ScrollElasticityHelper interface and
+ // hold all state related to elasticity. May be NULL if never requested.
+ scoped_ptr<ScrollElasticityHelper> scroll_elasticity_helper_;
+
bool tile_priorities_dirty_;
// The optional delegate for the root layer scroll offset.
LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate_;
- LayerTreeSettings settings_;
+ const LayerTreeSettings settings_;
LayerTreeDebugState debug_state_;
bool visible_;
ManagedMemoryPolicy cached_managed_memory_policy_;
@@ -647,9 +701,6 @@ class CC_EXPORT LayerTreeHostImpl
scoped_ptr<PageScaleAnimation> page_scale_animation_;
- // This is used for ticking animations slowly when hidden.
- scoped_ptr<LayerTreeHostImplTimeSourceAdapter> time_source_client_adapter_;
-
scoped_ptr<FrameRateCounter> fps_counter_;
scoped_ptr<PaintTimeCounter> paint_time_counter_;
scoped_ptr<MemoryHistory> memory_history_;
@@ -661,8 +712,6 @@ class CC_EXPORT LayerTreeHostImpl
// manager, if there were no limit on memory usage.
size_t max_memory_needed_bytes_;
- bool zero_budget_;
-
// Viewport size passed in from the main thread, in physical pixels. This
// value is the default size for all concepts of physical viewport (draw
// viewport, scrolling viewport and device viewport), but it can be
@@ -673,10 +722,6 @@ class CC_EXPORT LayerTreeHostImpl
// pageScaleFactor=1.
float device_scale_factor_;
- // UI resource to use for drawing overhang gutters.
- UIResourceId overhang_ui_resource_id_;
- gfx::Size overhang_ui_resource_size_;
-
// Optional top-level constraints that can be set by the OutputSurface.
// - external_transform_ applies a transform above the root layer
// - external_viewport_ is used DrawProperties, tile management and
@@ -698,26 +743,29 @@ class CC_EXPORT LayerTreeHostImpl
base::TimeDelta begin_impl_frame_interval_;
scoped_ptr<AnimationRegistrar> animation_registrar_;
+ std::set<ScrollbarAnimationController*> scrollbar_animation_controllers_;
+ std::set<VideoFrameController*> video_frame_controllers_;
RenderingStatsInstrumentation* rendering_stats_instrumentation_;
MicroBenchmarkControllerImpl micro_benchmark_controller_;
scoped_ptr<TaskGraphRunner> single_thread_synchronous_task_graph_runner_;
- bool need_to_update_visible_tiles_before_draw_;
-
// Optional callback to notify of new tree activations.
base::Closure tree_activation_callback_;
SharedBitmapManager* shared_bitmap_manager_;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ TaskGraphRunner* task_graph_runner_;
int id_;
std::set<SwapPromiseMonitor*> swap_promise_monitor_;
- std::vector<PictureLayerImpl*> picture_layers_;
- std::vector<PictureLayerImpl::Pair> picture_layer_pairs_;
-
bool requires_high_res_to_draw_;
+ bool is_likely_to_require_a_draw_;
+
+ scoped_ptr<FrameTimingTracker> frame_timing_tracker_;
+
+ scoped_ptr<Viewport> viewport_;
DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl);
};
diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
index adc11d0cdc7..ffc0b31e746 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -11,8 +11,9 @@
#include "base/command_line.h"
#include "base/containers/hash_tables.h"
#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/location.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/animation/scrollbar_animation_controller_thinning.h"
-#include "cc/base/latency_info_swap_promise.h"
#include "cc/base/math_util.h"
#include "cc/input/page_scale_animation.h"
#include "cc/input/top_controls_manager.h"
@@ -34,11 +35,11 @@
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/output/gl_renderer.h"
+#include "cc/output/latency_info_swap_promise.h"
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
-#include "cc/resources/layer_tiling_data.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/begin_frame_args_test.h"
#include "cc/test/fake_layer_tree_host_impl.h"
@@ -49,11 +50,15 @@
#include "cc/test/fake_proxy.h"
#include "cc/test/fake_video_frame_provider.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/gpu_rasterization_enabled_settings.h"
#include "cc/test/layer_test_common.h"
+#include "cc/test/layer_tree_test.h"
#include "cc/test/render_pass_test_common.h"
#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/tiles/layer_tiling_data.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
#include "media/base/media.h"
@@ -79,19 +84,20 @@ class LayerTreeHostImplTest : public testing::Test,
public LayerTreeHostImplClient {
public:
LayerTreeHostImplTest()
- : proxy_(base::MessageLoopProxy::current(),
- base::MessageLoopProxy::current()),
+ : proxy_(base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get()),
always_impl_thread_(&proxy_),
always_main_thread_blocked_(&proxy_),
shared_bitmap_manager_(new TestSharedBitmapManager),
gpu_memory_buffer_manager_(new TestGpuMemoryBufferManager),
+ task_graph_runner_(new TestTaskGraphRunner),
on_can_draw_state_changed_called_(false),
did_notify_ready_to_activate_(false),
did_request_commit_(false),
did_request_redraw_(false),
did_request_animate_(false),
- did_request_manage_tiles_(false),
- did_upload_visible_tile_(false),
+ did_request_prepare_tiles_(false),
+ did_complete_page_scale_animation_(false),
reduce_memory_result_(true),
current_limit_bytes_(0),
current_priority_cutoff_value_(0) {
@@ -102,17 +108,18 @@ class LayerTreeHostImplTest : public testing::Test,
LayerTreeSettings settings;
settings.minimum_occlusion_tracking_size = gfx::Size();
settings.impl_side_painting = true;
- settings.texture_id_allocation_chunk_size = 1;
+ settings.renderer_settings.texture_id_allocation_chunk_size = 1;
settings.report_overscroll_only_for_scrollable_axes = true;
settings.use_pinch_virtual_viewport = true;
+ settings.gpu_rasterization_enabled = true;
return settings;
}
- virtual void SetUp() override {
+ void SetUp() override {
CreateHostImpl(DefaultSettings(), CreateOutputSurface());
}
- virtual void TearDown() override {}
+ void TearDown() override {}
void UpdateRendererCapabilitiesOnImplThread() override {}
void DidLoseOutputSurfaceOnImplThread() override {}
@@ -129,18 +136,17 @@ class LayerTreeHostImplTest : public testing::Test,
did_notify_ready_to_activate_ = true;
host_impl_->ActivateSyncTree();
}
+ void NotifyReadyToDraw() override {}
void SetNeedsRedrawOnImplThread() override { did_request_redraw_ = true; }
void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) override {
did_request_redraw_ = true;
}
void SetNeedsAnimateOnImplThread() override { did_request_animate_ = true; }
- void SetNeedsManageTilesOnImplThread() override {
- did_request_manage_tiles_ = true;
- }
- void DidInitializeVisibleTileOnImplThread() override {
- did_upload_visible_tile_ = true;
+ void SetNeedsPrepareTilesOnImplThread() override {
+ did_request_prepare_tiles_ = true;
}
void SetNeedsCommitOnImplThread() override { did_request_commit_ = true; }
+ void SetVideoNeedsBeginFrames(bool needs_begin_frames) override {}
void PostAnimationEventsToMainThreadOnImplThread(
scoped_ptr<AnimationEventsVector> events) override {}
bool ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes,
@@ -151,27 +157,28 @@ class LayerTreeHostImplTest : public testing::Test,
}
bool IsInsideDraw() override { return false; }
void RenewTreePriority() override {}
- void PostDelayedScrollbarFadeOnImplThread(const base::Closure& start_fade,
+ void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
base::TimeDelta delay) override {
- scrollbar_fade_start_ = start_fade;
- requested_scrollbar_animation_delay_ = delay;
+ animation_task_ = task;
+ requested_animation_delay_ = delay;
}
void DidActivateSyncTree() override {}
- void DidManageTiles() override {}
+ void DidPrepareTiles() override {}
+ void DidCompletePageScaleAnimationOnImplThread() override {
+ did_complete_page_scale_animation_ = true;
+ }
+ void OnDrawForOutputSurface() override {}
void set_reduce_memory_result(bool reduce_memory_result) {
reduce_memory_result_ = reduce_memory_result;
}
- bool CreateHostImpl(const LayerTreeSettings& settings,
- scoped_ptr<OutputSurface> output_surface) {
- host_impl_ = LayerTreeHostImpl::Create(settings,
- this,
- &proxy_,
- &stats_instrumentation_,
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
- 0);
+ virtual bool CreateHostImpl(const LayerTreeSettings& settings,
+ scoped_ptr<OutputSurface> output_surface) {
+ host_impl_ = LayerTreeHostImpl::Create(
+ settings, this, &proxy_, &stats_instrumentation_,
+ shared_bitmap_manager_.get(), gpu_memory_buffer_manager_.get(),
+ task_graph_runner_.get(), 0);
bool init = host_impl_->InitializeRenderer(output_surface.Pass());
host_impl_->SetViewportSize(gfx::Size(10, 10));
return init;
@@ -183,6 +190,7 @@ class LayerTreeHostImplTest : public testing::Test,
root->SetContentBounds(gfx::Size(10, 10));
root->SetDrawsContent(true);
root->draw_properties().visible_content_rect = gfx::Rect(0, 0, 10, 10);
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
}
@@ -221,52 +229,75 @@ class LayerTreeHostImplTest : public testing::Test,
LayerImpl* CreateScrollAndContentsLayers(LayerTreeImpl* layer_tree_impl,
const gfx::Size& content_size) {
+ // Create both an inner viewport scroll layer and an outer viewport scroll
+ // layer. The MaxScrollOffset of the outer viewport scroll layer will be
+ // 0x0, so the scrolls will be applied directly to the inner viewport.
+ const int kOuterViewportClipLayerId = 116;
+ const int kOuterViewportScrollLayerId = 117;
+ const int kContentLayerId = 118;
const int kInnerViewportScrollLayerId = 2;
const int kInnerViewportClipLayerId = 4;
const int kPageScaleLayerId = 5;
+
scoped_ptr<LayerImpl> root =
LayerImpl::Create(layer_tree_impl, 1);
root->SetBounds(content_size);
root->SetContentBounds(content_size);
root->SetPosition(gfx::PointF());
+ root->SetHasRenderSurface(true);
- scoped_ptr<LayerImpl> scroll =
+ scoped_ptr<LayerImpl> inner_scroll =
LayerImpl::Create(layer_tree_impl, kInnerViewportScrollLayerId);
- LayerImpl* scroll_layer = scroll.get();
- scroll->SetIsContainerForFixedPositionLayers(true);
- scroll->SetScrollOffset(gfx::ScrollOffset());
+ inner_scroll->SetIsContainerForFixedPositionLayers(true);
+ inner_scroll->PushScrollOffsetFromMainThread(gfx::ScrollOffset());
- scoped_ptr<LayerImpl> clip =
+ scoped_ptr<LayerImpl> inner_clip =
LayerImpl::Create(layer_tree_impl, kInnerViewportClipLayerId);
- clip->SetBounds(
+ inner_clip->SetBounds(
gfx::Size(content_size.width() / 2, content_size.height() / 2));
scoped_ptr<LayerImpl> page_scale =
LayerImpl::Create(layer_tree_impl, kPageScaleLayerId);
- scroll->SetScrollClipLayer(clip->id());
- scroll->SetBounds(content_size);
- scroll->SetContentBounds(content_size);
- scroll->SetPosition(gfx::PointF());
- scroll->SetIsContainerForFixedPositionLayers(true);
+ inner_scroll->SetScrollClipLayer(inner_clip->id());
+ inner_scroll->SetBounds(content_size);
+ inner_scroll->SetContentBounds(content_size);
+ inner_scroll->SetPosition(gfx::PointF());
+
+ scoped_ptr<LayerImpl> outer_clip =
+ LayerImpl::Create(layer_tree_impl, kOuterViewportClipLayerId);
+ outer_clip->SetBounds(content_size);
+ outer_clip->SetIsContainerForFixedPositionLayers(true);
+
+ scoped_ptr<LayerImpl> outer_scroll =
+ LayerImpl::Create(layer_tree_impl, kOuterViewportScrollLayerId);
+ outer_scroll->SetScrollClipLayer(outer_clip->id());
+ outer_scroll->PushScrollOffsetFromMainThread(gfx::ScrollOffset());
+ outer_scroll->SetBounds(content_size);
+ outer_scroll->SetContentBounds(content_size);
+ outer_scroll->SetPosition(gfx::PointF());
scoped_ptr<LayerImpl> contents =
- LayerImpl::Create(layer_tree_impl, 3);
+ LayerImpl::Create(layer_tree_impl, kContentLayerId);
contents->SetDrawsContent(true);
contents->SetBounds(content_size);
contents->SetContentBounds(content_size);
contents->SetPosition(gfx::PointF());
- scroll->AddChild(contents.Pass());
- page_scale->AddChild(scroll.Pass());
- clip->AddChild(page_scale.Pass());
- root->AddChild(clip.Pass());
+ outer_scroll->AddChild(contents.Pass());
+ outer_clip->AddChild(outer_scroll.Pass());
+ inner_scroll->AddChild(outer_clip.Pass());
+ page_scale->AddChild(inner_scroll.Pass());
+ inner_clip->AddChild(page_scale.Pass());
+ root->AddChild(inner_clip.Pass());
layer_tree_impl->SetRootLayer(root.Pass());
layer_tree_impl->SetViewportLayersFromIds(
- kPageScaleLayerId, kInnerViewportScrollLayerId, Layer::INVALID_ID);
+ Layer::INVALID_ID, kPageScaleLayerId, kInnerViewportScrollLayerId,
+ kOuterViewportScrollLayerId);
- return scroll_layer;
+ layer_tree_impl->DidBecomeActive();
+ return layer_tree_impl->InnerViewportScrollLayer();
}
LayerImpl* SetupScrollAndContentsLayers(const gfx::Size& content_size) {
@@ -295,7 +326,7 @@ class LayerTreeHostImplTest : public testing::Test,
void DrawFrame() {
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -390,6 +421,7 @@ class LayerTreeHostImplTest : public testing::Test,
scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ scoped_ptr<TestTaskGraphRunner> task_graph_runner_;
scoped_ptr<LayerTreeHostImpl> host_impl_;
FakeRenderingStatsInstrumentation stats_instrumentation_;
bool on_can_draw_state_changed_called_;
@@ -397,11 +429,11 @@ class LayerTreeHostImplTest : public testing::Test,
bool did_request_commit_;
bool did_request_redraw_;
bool did_request_animate_;
- bool did_request_manage_tiles_;
- bool did_upload_visible_tile_;
+ bool did_request_prepare_tiles_;
+ bool did_complete_page_scale_animation_;
bool reduce_memory_result_;
- base::Closure scrollbar_fade_start_;
- base::TimeDelta requested_scrollbar_animation_delay_;
+ base::Closure animation_task_;
+ base::TimeDelta requested_animation_delay_;
size_t current_limit_bytes_;
int current_priority_cutoff_value_;
};
@@ -468,7 +500,7 @@ TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) {
root_clip->AddChild(root.Pass());
root_layer->SetBounds(gfx::Size(110, 110));
root_layer->SetScrollClipLayer(root_clip->id());
- root_layer->SetScrollOffset(scroll_offset);
+ root_layer->PushScrollOffsetFromMainThread(scroll_offset);
root_layer->ScrollBy(scroll_delta);
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
}
@@ -478,19 +510,17 @@ TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) {
scroll_info = host_impl_->ProcessScrollDeltas();
ASSERT_EQ(scroll_info->scrolls.size(), 1u);
- EXPECT_VECTOR_EQ(root->sent_scroll_delta(), scroll_delta);
ExpectContains(*scroll_info, root->id(), scroll_delta);
gfx::Vector2d scroll_delta2(-5, 27);
root->ScrollBy(scroll_delta2);
scroll_info = host_impl_->ProcessScrollDeltas();
ASSERT_EQ(scroll_info->scrolls.size(), 1u);
- EXPECT_VECTOR_EQ(root->sent_scroll_delta(), scroll_delta + scroll_delta2);
ExpectContains(*scroll_info, root->id(), scroll_delta + scroll_delta2);
root->ScrollBy(gfx::Vector2d());
scroll_info = host_impl_->ProcessScrollDeltas();
- EXPECT_EQ(root->sent_scroll_delta(), scroll_delta + scroll_delta2);
+ ExpectContains(*scroll_info, root->id(), scroll_delta + scroll_delta2);
}
TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) {
@@ -498,16 +528,16 @@ TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) {
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
- InputHandler::Wheel));
+ InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, 10),
- InputHandler::Wheel));
+ InputHandler::WHEEL));
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
- InputHandler::Wheel));
+ InputHandler::WHEEL));
EXPECT_TRUE(did_request_redraw_);
EXPECT_TRUE(did_request_commit_);
}
@@ -517,8 +547,8 @@ TEST_F(LayerTreeHostImplTest, ScrollActiveOnlyAfterScrollMovement) {
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_FALSE(host_impl_->IsActivelyScrolling());
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_TRUE(host_impl_->IsActivelyScrolling());
@@ -528,8 +558,8 @@ TEST_F(LayerTreeHostImplTest, ScrollActiveOnlyAfterScrollMovement) {
TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) {
// We should not crash when trying to scroll an empty layer tree.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) {
@@ -545,8 +575,8 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) {
// We should not crash when trying to scroll after the renderer initialization
// fails.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) {
@@ -555,8 +585,8 @@ TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) {
DrawFrame();
// We should not crash if the tree is replaced while we are scrolling.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->active_tree()->DetachLayerTree();
scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
@@ -570,36 +600,183 @@ TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) {
ExpectContains(*scroll_info, scroll_layer->id(), scroll_delta);
}
-TEST_F(LayerTreeHostImplTest, ClearRootRenderSurfaceAndScroll) {
+TEST_F(LayerTreeHostImplTest, ScrollBlocksOnWheelEventHandlers) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
+ LayerImpl* root = host_impl_->active_tree()->root_layer();
+
+ // With registered event handlers, wheel scrolls don't necessarily
+ // have to go to the main thread.
+ root->SetHaveWheelEventHandlers(true);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
+ host_impl_->ScrollEnd();
- // We should be able to scroll even if the root layer loses its render surface
- // after the most recent render.
- host_impl_->active_tree()->root_layer()->ClearRenderSurface();
- host_impl_->active_tree()->set_needs_update_draw_properties();
+ // But typically the scroll-blocks-on mode will require them to.
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT |
+ SCROLL_BLOCKS_ON_START_TOUCH);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ // But gesture scrolls can still be handled.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ host_impl_->ScrollEnd();
+
+ // And if the handlers go away, wheel scrolls can again be processed
+ // on impl (despite the scroll-blocks-on mode).
+ root->SetHaveWheelEventHandlers(false);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
+ host_impl_->ScrollEnd();
}
-TEST_F(LayerTreeHostImplTest, WheelEventHandlers) {
+TEST_F(LayerTreeHostImplTest, ScrollBlocksOnTouchEventHandlers) {
+ LayerImpl* scroll = SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ DrawFrame();
+ LayerImpl* root = host_impl_->active_tree()->root_layer();
+
+ LayerImpl* child = 0;
+ {
+ scoped_ptr<LayerImpl> child_layer =
+ LayerImpl::Create(host_impl_->active_tree(), 6);
+ child = child_layer.get();
+ child_layer->SetDrawsContent(true);
+ child_layer->SetPosition(gfx::PointF(0, 20));
+ child_layer->SetBounds(gfx::Size(50, 50));
+ child_layer->SetContentBounds(gfx::Size(50, 50));
+ scroll->AddChild(child_layer.Pass());
+ }
+
+ // Touch handler regions determine whether touch events block scroll.
+ root->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 100, 100));
+ EXPECT_FALSE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 10)));
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_START_TOUCH |
+ SCROLL_BLOCKS_ON_WHEEL_EVENT);
+ EXPECT_TRUE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 10)));
+
+ // But they don't influence the actual handling of the scroll gestures.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ host_impl_->ScrollEnd();
+
+ // It's the union of scroll-blocks-on mode bits across all layers in the
+ // scroll paret chain that matters.
+ EXPECT_TRUE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 30)));
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_NONE);
+ EXPECT_FALSE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 30)));
+ child->SetScrollBlocksOn(SCROLL_BLOCKS_ON_START_TOUCH);
+ EXPECT_TRUE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 30)));
+}
+
+TEST_F(LayerTreeHostImplTest, ScrollBlocksOnScrollEventHandlers) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
LayerImpl* root = host_impl_->active_tree()->root_layer();
- root->SetHaveWheelEventHandlers(true);
+ // With registered scroll handlers, scrolls don't generally have to go
+ // to the main thread.
+ root->SetHaveScrollEventHandlers(true);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
+ host_impl_->ScrollEnd();
+
+ // Even the default scroll blocks on mode doesn't require this.
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT |
+ SCROLL_BLOCKS_ON_START_TOUCH);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ host_impl_->ScrollEnd();
- // With registered event handlers, wheel scrolls have to go to the main
- // thread.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ // But the page can opt in to blocking on scroll event handlers.
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
- // But gesture scrolls can still be handled.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ // GESTURE and WHEEL scrolls behave identically in this regard.
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
+
+ // And if the handlers go away, scrolls can again be processed on impl
+ // (despite the scroll-blocks-on mode).
+ root->SetHaveScrollEventHandlers(false);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ host_impl_->ScrollEnd();
+}
+
+TEST_F(LayerTreeHostImplTest, ScrollBlocksOnLayerTopology) {
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+
+ // Create a normal scrollable root layer
+ LayerImpl* root_scroll = SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ LayerImpl* root_child = root_scroll->children()[0];
+ LayerImpl* root = host_impl_->active_tree()->root_layer();
+ DrawFrame();
+
+ // Create two child scrollable layers
+ LayerImpl* child1 = 0;
+ {
+ scoped_ptr<LayerImpl> scrollable_child_clip_1 =
+ LayerImpl::Create(host_impl_->active_tree(), 6);
+ scoped_ptr<LayerImpl> scrollable_child_1 = CreateScrollableLayer(
+ 7, gfx::Size(10, 10), scrollable_child_clip_1.get());
+ child1 = scrollable_child_1.get();
+ scrollable_child_1->SetPosition(gfx::Point(5, 5));
+ scrollable_child_1->SetHaveWheelEventHandlers(true);
+ scrollable_child_1->SetHaveScrollEventHandlers(true);
+ scrollable_child_clip_1->AddChild(scrollable_child_1.Pass());
+ root_child->AddChild(scrollable_child_clip_1.Pass());
+ }
+
+ LayerImpl* child2 = 0;
+ {
+ scoped_ptr<LayerImpl> scrollable_child_clip_2 =
+ LayerImpl::Create(host_impl_->active_tree(), 8);
+ scoped_ptr<LayerImpl> scrollable_child_2 = CreateScrollableLayer(
+ 9, gfx::Size(10, 10), scrollable_child_clip_2.get());
+ child2 = scrollable_child_2.get();
+ scrollable_child_2->SetPosition(gfx::Point(5, 20));
+ scrollable_child_2->SetHaveWheelEventHandlers(true);
+ scrollable_child_2->SetHaveScrollEventHandlers(true);
+ scrollable_child_clip_2->AddChild(scrollable_child_2.Pass());
+ root_child->AddChild(scrollable_child_clip_2.Pass());
+ }
+
+ // Scroll-blocks-on on a layer affects scrolls that hit that layer.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::GESTURE));
+ host_impl_->ScrollEnd();
+ child1->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::GESTURE));
+
+ // But not those that hit only other layers.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::GESTURE));
+ host_impl_->ScrollEnd();
+
+ // It's the union of bits set across the scroll ancestor chain that matters.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::GESTURE));
+ host_impl_->ScrollEnd();
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::WHEEL));
+ host_impl_->ScrollEnd();
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::GESTURE));
+ host_impl_->ScrollEnd();
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::WHEEL));
+ child2->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::WHEEL));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::GESTURE));
}
TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) {
@@ -608,16 +785,14 @@ TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) {
DrawFrame();
// Ignore the fling since no layer is being scrolled
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin());
// Start scrolling a layer
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// Now the fling should go ahead since we've started scrolling a layer
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
}
TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) {
@@ -626,16 +801,14 @@ TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) {
DrawFrame();
// Ignore the fling since no layer is being scrolled
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin());
// Start scrolling a layer
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
// Now the fling should go ahead since we've started scrolling a layer
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
}
TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) {
@@ -647,12 +820,11 @@ TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) {
root->SetShouldScrollOnMainThread(true);
// Start scrolling a layer
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// The fling should be ignored since there's no layer being scrolled impl-side
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin());
}
TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) {
@@ -663,10 +835,10 @@ TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) {
root->SetShouldScrollOnMainThread(true);
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
}
TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) {
@@ -680,38 +852,34 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) {
DrawFrame();
// All scroll types inside the non-fast scrollable region should fail.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(25, 25),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(25, 25), InputHandler::WHEEL));
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
- InputHandler::Wheel));
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(25, 25),
- InputHandler::Gesture));
+ InputHandler::WHEEL));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(25, 25), InputHandler::GESTURE));
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
// All scroll types outside this region should succeed.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(75, 75),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(75, 75), InputHandler::WHEEL));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
- InputHandler::Gesture));
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(75, 75),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(75, 75), InputHandler::GESTURE));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
}
TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
@@ -727,18 +895,16 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
// This point would fall into the non-fast scrollable region except that we've
// moved the layer down by 25 pixels.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(40, 10),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(40, 10), InputHandler::WHEEL));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(40, 10),
- InputHandler::Wheel));
+ InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 1));
host_impl_->ScrollEnd();
// This point is still inside the non-fast region.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(10, 10),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollHandlerNotPresent) {
@@ -748,7 +914,7 @@ TEST_F(LayerTreeHostImplTest, ScrollHandlerNotPresent) {
DrawFrame();
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
@@ -761,7 +927,7 @@ TEST_F(LayerTreeHostImplTest, ScrollHandlerPresent) {
DrawFrame();
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
EXPECT_TRUE(host_impl_->scroll_affects_scroll_handler());
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
@@ -773,8 +939,8 @@ TEST_F(LayerTreeHostImplTest, ScrollByReturnsCorrectValue) {
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// Trying to scroll to the left/top will not succeed.
EXPECT_FALSE(
@@ -819,9 +985,8 @@ TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) {
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
// Trying to scroll without a vertical scrollbar will fail.
EXPECT_FALSE(host_impl_->ScrollVerticallyByPage(
@@ -857,60 +1022,46 @@ TEST_F(LayerTreeHostImplTest, ScrollWithUserUnscrollableLayers) {
overflow->SetBounds(overflow_size);
overflow->SetContentBounds(overflow_size);
overflow->SetScrollClipLayer(scroll_layer->parent()->id());
- overflow->SetScrollOffset(gfx::ScrollOffset());
+ overflow->PushScrollOffsetFromMainThread(gfx::ScrollOffset());
overflow->SetPosition(gfx::PointF());
DrawFrame();
gfx::Point scroll_position(10, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(scroll_position, InputHandler::Wheel));
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), overflow->TotalScrollOffset());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(scroll_position, InputHandler::WHEEL));
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), overflow->CurrentScrollOffset());
gfx::Vector2dF scroll_delta(10, 10);
host_impl_->ScrollBy(scroll_position, scroll_delta);
host_impl_->ScrollEnd();
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->CurrentScrollOffset());
overflow->set_user_scrollable_horizontal(false);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(scroll_position, InputHandler::Wheel));
- EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->TotalScrollOffset());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(scroll_position, InputHandler::WHEEL));
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->CurrentScrollOffset());
host_impl_->ScrollBy(scroll_position, scroll_delta);
host_impl_->ScrollEnd();
- EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 0), scroll_layer->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 0), scroll_layer->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset());
overflow->set_user_scrollable_vertical(false);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(scroll_position, InputHandler::Wheel));
- EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 0), scroll_layer->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->TotalScrollOffset());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(scroll_position, InputHandler::WHEEL));
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 0), scroll_layer->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset());
host_impl_->ScrollBy(scroll_position, scroll_delta);
host_impl_->ScrollEnd();
- EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 10), scroll_layer->TotalScrollOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->TotalScrollOffset());
-}
-
-TEST_F(LayerTreeHostImplTest,
- ClearRootRenderSurfaceAndHitTestTouchHandlerRegion) {
- SetupScrollAndContentsLayers(gfx::Size(100, 100));
- host_impl_->SetViewportSize(gfx::Size(50, 50));
- DrawFrame();
-
- // We should be able to hit test for touch event handlers even if the root
- // layer loses its render surface after the most recent render.
- host_impl_->active_tree()->root_layer()->ClearRenderSurface();
- host_impl_->active_tree()->set_needs_update_draw_properties();
-
- EXPECT_EQ(host_impl_->HaveTouchEventHandlersAt(gfx::Point()), false);
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(20, 10), scroll_layer->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset());
}
TEST_F(LayerTreeHostImplTest, ImplPinchZoom) {
@@ -927,14 +1078,14 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) {
// The impl-based pinch zoom should adjust the max scroll position.
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(
+ host_impl_->active_tree()->PushPageScaleFromMainThread(
page_scale_factor, min_page_scale, max_page_scale);
- host_impl_->active_tree()->SetPageScaleDelta(1.f);
+ host_impl_->SetPageScaleOnActiveTree(page_scale_factor);
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 2.f;
- host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
host_impl_->PinchGestureEnd();
@@ -953,32 +1104,30 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) {
}
// Scrolling after a pinch gesture should always be in local space. The
- // scroll deltas do not have the page scale factor applied.
+ // scroll deltas have the page scale factor applied.
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(
+ host_impl_->active_tree()->PushPageScaleFromMainThread(
page_scale_factor, min_page_scale, max_page_scale);
- host_impl_->active_tree()->SetPageScaleDelta(1.f);
+ host_impl_->SetPageScaleOnActiveTree(page_scale_factor);
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 2.f;
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
host_impl_->PinchGestureEnd();
host_impl_->ScrollEnd();
gfx::Vector2d scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
scoped_ptr<ScrollAndScaleSet> scroll_info =
host_impl_->ProcessScrollDeltas();
- ExpectContains(*scroll_info.get(),
- scroll_layer->id(),
- scroll_delta);
+ ExpectContains(*scroll_info.get(), scroll_layer->id(),
+ gfx::Vector2d(0, scroll_delta.y() / page_scale_delta));
}
}
@@ -989,8 +1138,8 @@ TEST_F(LayerTreeHostImplTest, ScrollWithSwapPromises) {
new LatencyInfoSwapPromise(latency_info));
SetupScrollAndContentsLayers(gfx::Size(100, 100));
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
host_impl_->QueueSwapPromiseForMainThreadScrollUpdate(swap_promise.Pass());
host_impl_->ScrollEnd();
@@ -1013,13 +1162,12 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
// Basic pinch zoom in gesture
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 2.f;
- host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
host_impl_->PinchGestureEnd();
@@ -1035,13 +1183,12 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
// Zoom-in clamping
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 10.f;
- host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
host_impl_->PinchGestureEnd();
@@ -1054,14 +1201,14 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
// Zoom-out clamping
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
scroll_layer->SetScrollDelta(gfx::Vector2d());
- scroll_layer->SetScrollOffset(gfx::ScrollOffset(50, 50));
+ scroll_layer->PullDeltaForMainThread();
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50));
float page_scale_delta = 0.1f;
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
host_impl_->PinchGestureEnd();
@@ -1076,14 +1223,14 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
// Two-finger panning should not happen based on pinch events only
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
scroll_layer->SetScrollDelta(gfx::Vector2d());
- scroll_layer->SetScrollOffset(gfx::ScrollOffset(20, 20));
+ scroll_layer->PullDeltaForMainThread();
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(20, 20));
float page_scale_delta = 1.f;
- host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10));
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20));
@@ -1098,14 +1245,14 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
// Two-finger panning should work with interleaved scroll events
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
scroll_layer->SetScrollDelta(gfx::Vector2d());
- scroll_layer->SetScrollOffset(gfx::ScrollOffset(20, 20));
+ scroll_layer->PullDeltaForMainThread();
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(20, 20));
float page_scale_delta = 1.f;
- host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10));
host_impl_->ScrollBy(gfx::Point(10, 10), gfx::Vector2d(-10, -10));
@@ -1121,13 +1268,12 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
// Two-finger panning should work when starting fully zoomed out.
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(0.5f,
- 0.5f,
- 4.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(0.5f, 0.5f, 4.f);
scroll_layer->SetScrollDelta(gfx::Vector2d());
- scroll_layer->SetScrollOffset(gfx::ScrollOffset(0, 0));
+ scroll_layer->PullDeltaForMainThread();
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 0));
- host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(2.f, gfx::Point(0, 0));
host_impl_->PinchGestureUpdate(1.f, gfx::Point(0, 0));
@@ -1161,18 +1307,18 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) {
// Non-anchor zoom-in
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
- scroll_layer->SetScrollOffset(gfx::ScrollOffset(50, 50));
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50));
did_request_redraw_ = false;
did_request_animate_ = false;
- host_impl_->active_tree()->SetPageScaleAnimation(
- gfx::Vector2d(),
- false,
- 2.f,
- duration);
+ host_impl_->active_tree()->SetPendingPageScaleAnimation(
+ scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation(
+ gfx::Vector2d(),
+ false,
+ 2.f,
+ duration)));
host_impl_->ActivateSyncTree();
EXPECT_FALSE(did_request_redraw_);
EXPECT_TRUE(did_request_animate_);
@@ -1204,15 +1350,18 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) {
// Anchor zoom-out
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
- scroll_layer->SetScrollOffset(gfx::ScrollOffset(50, 50));
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50));
did_request_redraw_ = false;
did_request_animate_ = false;
- host_impl_->active_tree()->SetPageScaleAnimation(
- gfx::Vector2d(25, 25), true, min_page_scale, duration);
+ host_impl_->active_tree()->SetPendingPageScaleAnimation(
+ scoped_ptr<PendingPageScaleAnimation> (new PendingPageScaleAnimation(
+ gfx::Vector2d(25, 25),
+ true,
+ min_page_scale,
+ duration)));
host_impl_->ActivateSyncTree();
EXPECT_FALSE(did_request_redraw_);
EXPECT_TRUE(did_request_animate_);
@@ -1257,16 +1406,16 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) {
// Anchor zoom with unchanged page scale should not change scroll or scale.
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
- scroll_layer->SetScrollOffset(gfx::ScrollOffset(50, 50));
-
- host_impl_->active_tree()->SetPageScaleAnimation(
- gfx::Vector2d(),
- true,
- 1.f,
- duration);
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50));
+
+ host_impl_->active_tree()->SetPendingPageScaleAnimation(
+ scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation(
+ gfx::Vector2d(),
+ true,
+ 1.f,
+ duration)));
host_impl_->ActivateSyncTree();
host_impl_->Animate(start_time);
host_impl_->Animate(halfway_through_animation);
@@ -1294,8 +1443,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) {
float min_page_scale = 0.5f;
float max_page_scale = 4.f;
- host_impl_->sync_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
+ host_impl_->sync_tree()->PushPageScaleFromMainThread(1.f, min_page_scale,
max_page_scale);
host_impl_->ActivateSyncTree();
@@ -1307,29 +1455,32 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) {
base::TimeTicks end_time = start_time + duration;
float target_scale = 2.f;
- scroll_layer->SetScrollOffset(gfx::ScrollOffset(50, 50));
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50));
// Make sure TakePageScaleAnimation works properly.
- host_impl_->sync_tree()->SetPageScaleAnimation(
- gfx::Vector2d(),
- false,
- target_scale,
- duration);
- scoped_ptr<PageScaleAnimation> psa =
- host_impl_->sync_tree()->TakePageScaleAnimation();
- EXPECT_EQ(target_scale, psa->target_page_scale_factor());
- EXPECT_EQ(duration, psa->duration());
- EXPECT_EQ(nullptr, host_impl_->sync_tree()->TakePageScaleAnimation());
+
+ host_impl_->sync_tree()->SetPendingPageScaleAnimation(
+ scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation(
+ gfx::Vector2d(),
+ false,
+ target_scale,
+ duration)));
+ scoped_ptr<PendingPageScaleAnimation> psa =
+ host_impl_->sync_tree()->TakePendingPageScaleAnimation();
+ EXPECT_EQ(target_scale, psa->scale);
+ EXPECT_EQ(duration, psa->duration);
+ EXPECT_EQ(nullptr, host_impl_->sync_tree()->TakePendingPageScaleAnimation());
// Recreate the PSA. Nothing should happen here since the tree containing the
// PSA hasn't been activated yet.
did_request_redraw_ = false;
did_request_animate_ = false;
- host_impl_->sync_tree()->SetPageScaleAnimation(
- gfx::Vector2d(),
- false,
- target_scale,
- duration);
+ host_impl_->sync_tree()->SetPendingPageScaleAnimation(
+ scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation(
+ gfx::Vector2d(),
+ false,
+ target_scale,
+ duration)));
host_impl_->Animate(halfway_through_animation);
EXPECT_FALSE(did_request_animate_);
EXPECT_FALSE(did_request_redraw_);
@@ -1337,7 +1488,8 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) {
// Activate the sync tree. This should cause the animation to become enabled.
// It should also clear the pointer on the sync tree.
host_impl_->ActivateSyncTree();
- EXPECT_EQ(nullptr, host_impl_->sync_tree()->TakePageScaleAnimation().get());
+ EXPECT_EQ(nullptr,
+ host_impl_->sync_tree()->TakePendingPageScaleAnimation().get());
EXPECT_FALSE(did_request_redraw_);
EXPECT_TRUE(did_request_animate_);
@@ -1376,6 +1528,38 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) {
ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-50, -50));
}
+TEST_F(LayerTreeHostImplTest, PageScaleAnimationCompletedNotification) {
+ SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ DrawFrame();
+
+ LayerImpl* scroll_layer = host_impl_->InnerViewportScrollLayer();
+ DCHECK(scroll_layer);
+
+ base::TimeTicks start_time =
+ base::TimeTicks() + base::TimeDelta::FromSeconds(1);
+ base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100);
+ base::TimeTicks halfway_through_animation = start_time + duration / 2;
+ base::TimeTicks end_time = start_time + duration;
+
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f);
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50));
+
+ did_complete_page_scale_animation_ = false;
+ host_impl_->active_tree()->SetPendingPageScaleAnimation(
+ scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation(
+ gfx::Vector2d(), false, 2.f, duration)));
+ host_impl_->ActivateSyncTree();
+ host_impl_->Animate(start_time);
+ EXPECT_FALSE(did_complete_page_scale_animation_);
+
+ host_impl_->Animate(halfway_through_animation);
+ EXPECT_FALSE(did_complete_page_scale_animation_);
+
+ host_impl_->Animate(end_time);
+ EXPECT_TRUE(did_complete_page_scale_animation_);
+}
+
class LayerTreeHostImplOverridePhysicalTime : public LayerTreeHostImpl {
public:
LayerTreeHostImplOverridePhysicalTime(
@@ -1390,10 +1574,12 @@ class LayerTreeHostImplOverridePhysicalTime : public LayerTreeHostImpl {
rendering_stats_instrumentation,
manager,
NULL,
+ NULL,
0) {}
BeginFrameArgs CurrentBeginFrameArgs() const override {
- return CreateBeginFrameArgsForTesting(fake_current_physical_time_);
+ return CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE,
+ fake_current_physical_time_);
}
void SetCurrentPhysicalTimeTicksForTest(base::TimeTicks fake_now) {
@@ -1404,169 +1590,160 @@ class LayerTreeHostImplOverridePhysicalTime : public LayerTreeHostImpl {
base::TimeTicks fake_current_physical_time_;
};
-#define SETUP_LAYERS_FOR_SCROLLBAR_ANIMATION_TEST() \
- gfx::Size viewport_size(10, 10); \
- gfx::Size content_size(100, 100); \
- \
- LayerTreeHostImplOverridePhysicalTime* host_impl_override_time = \
- new LayerTreeHostImplOverridePhysicalTime(settings, \
- this, \
- &proxy_, \
- shared_bitmap_manager_.get(), \
- &stats_instrumentation_); \
- host_impl_ = make_scoped_ptr(host_impl_override_time); \
- host_impl_->InitializeRenderer(CreateOutputSurface()); \
- host_impl_->SetViewportSize(viewport_size); \
- \
- scoped_ptr<LayerImpl> root = \
- LayerImpl::Create(host_impl_->active_tree(), 1); \
- root->SetBounds(viewport_size); \
- \
- scoped_ptr<LayerImpl> scroll = \
- LayerImpl::Create(host_impl_->active_tree(), 2); \
- scroll->SetScrollClipLayer(root->id()); \
- scroll->SetScrollOffset(gfx::ScrollOffset()); \
- root->SetBounds(viewport_size); \
- scroll->SetBounds(content_size); \
- scroll->SetContentBounds(content_size); \
- scroll->SetIsContainerForFixedPositionLayers(true); \
- \
- scoped_ptr<LayerImpl> contents = \
- LayerImpl::Create(host_impl_->active_tree(), 3); \
- contents->SetDrawsContent(true); \
- contents->SetBounds(content_size); \
- contents->SetContentBounds(content_size); \
- \
- scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar = \
- SolidColorScrollbarLayerImpl::Create( \
- host_impl_->active_tree(), 4, VERTICAL, 10, 0, false, true); \
- EXPECT_FLOAT_EQ(0.f, scrollbar->opacity()); \
- \
- scroll->AddChild(contents.Pass()); \
- root->AddChild(scroll.Pass()); \
- scrollbar->SetScrollLayerAndClipLayerByIds(2, 1); \
- root->AddChild(scrollbar.Pass()); \
- \
- host_impl_->active_tree()->SetRootLayer(root.Pass()); \
- host_impl_->active_tree()->SetViewportLayersFromIds( \
- 1, 2, Layer::INVALID_ID); \
- host_impl_->active_tree()->DidBecomeActive(); \
- DrawFrame();
+class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest {
+ protected:
+ void SetupLayers(LayerTreeSettings settings) {
+ gfx::Size viewport_size(10, 10);
+ gfx::Size content_size(100, 100);
+
+ LayerTreeHostImplOverridePhysicalTime* host_impl_override_time =
+ new LayerTreeHostImplOverridePhysicalTime(settings, this, &proxy_,
+ shared_bitmap_manager_.get(),
+ &stats_instrumentation_);
+ host_impl_ = make_scoped_ptr(host_impl_override_time);
+ host_impl_->InitializeRenderer(CreateOutputSurface());
+ host_impl_->SetViewportSize(viewport_size);
-TEST_F(LayerTreeHostImplTest, ScrollbarLinearFadeScheduling) {
- LayerTreeSettings settings;
- settings.scrollbar_animator = LayerTreeSettings::LinearFade;
- settings.scrollbar_fade_delay_ms = 20;
- settings.scrollbar_fade_duration_ms = 20;
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl_->active_tree(), 1);
+ root->SetBounds(viewport_size);
- SETUP_LAYERS_FOR_SCROLLBAR_ANIMATION_TEST();
+ scoped_ptr<LayerImpl> scroll =
+ LayerImpl::Create(host_impl_->active_tree(), 2);
+ scroll->SetScrollClipLayer(root->id());
+ scroll->PushScrollOffsetFromMainThread(gfx::ScrollOffset());
+ root->SetBounds(viewport_size);
+ scroll->SetBounds(content_size);
+ scroll->SetContentBounds(content_size);
+ scroll->SetIsContainerForFixedPositionLayers(true);
- base::TimeTicks fake_now = gfx::FrameTime::Now();
+ scoped_ptr<LayerImpl> contents =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ contents->SetDrawsContent(true);
+ contents->SetBounds(content_size);
+ contents->SetContentBounds(content_size);
- EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_redraw_);
+ scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar =
+ SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), 4,
+ VERTICAL, 10, 0, false, true);
+ EXPECT_FLOAT_EQ(0.f, scrollbar->opacity());
- // If no scroll happened during a scroll gesture, it should have no effect.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
- host_impl_->ScrollEnd();
- EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_redraw_);
- EXPECT_TRUE(scrollbar_fade_start_.Equals(base::Closure()));
+ scroll->AddChild(contents.Pass());
+ root->AddChild(scroll.Pass());
+ root->SetHasRenderSurface(true);
+ scrollbar->SetScrollLayerAndClipLayerByIds(2, 1);
+ root->AddChild(scrollbar.Pass());
- // After a scroll, a fade animation should be scheduled about 20ms from now.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 5));
- host_impl_->ScrollEnd();
- did_request_redraw_ = false;
- did_request_animate_ = false;
- EXPECT_LT(base::TimeDelta::FromMilliseconds(19),
- requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_redraw_);
- EXPECT_FALSE(did_request_animate_);
- requested_scrollbar_animation_delay_ = base::TimeDelta();
- scrollbar_fade_start_.Run();
- host_impl_->Animate(fake_now);
-
- // After the fade begins, we should start getting redraws instead of a
- // scheduled animation.
- fake_now += base::TimeDelta::FromMilliseconds(25);
- EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
- EXPECT_TRUE(did_request_animate_);
- did_request_animate_ = false;
+ host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2,
+ Layer::INVALID_ID);
+ host_impl_->active_tree()->DidBecomeActive();
+ DrawFrame();
+ }
- // Setting the scroll offset outside a scroll should also cause the scrollbar
- // to appear and to schedule a fade.
- host_impl_->InnerViewportScrollLayer()->SetScrollOffset(
- gfx::ScrollOffset(5, 5));
- EXPECT_LT(base::TimeDelta::FromMilliseconds(19),
- requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_redraw_);
- EXPECT_FALSE(did_request_animate_);
- requested_scrollbar_animation_delay_ = base::TimeDelta();
+ void RunTest(LayerTreeSettings::ScrollbarAnimator animator) {
+ LayerTreeSettings settings;
+ settings.scrollbar_animator = animator;
+ settings.scrollbar_fade_delay_ms = 20;
+ settings.scrollbar_fade_duration_ms = 20;
- // Unnecessarily Fade animation of solid color scrollbar is not triggered.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
- host_impl_->ScrollEnd();
- EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
-}
+ SetupLayers(settings);
-TEST_F(LayerTreeHostImplTest, ScrollbarFadePinchZoomScrollbars) {
- LayerTreeSettings settings;
- settings.scrollbar_animator = LayerTreeSettings::LinearFade;
- settings.scrollbar_fade_delay_ms = 20;
- settings.scrollbar_fade_duration_ms = 20;
- settings.use_pinch_zoom_scrollbars = true;
+ base::TimeTicks fake_now = gfx::FrameTime::Now();
- SETUP_LAYERS_FOR_SCROLLBAR_ANIMATION_TEST();
+ EXPECT_FALSE(did_request_animate_);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+ EXPECT_TRUE(animation_task_.Equals(base::Closure()));
- base::TimeTicks fake_now = gfx::FrameTime::Now();
+ // If no scroll happened during a scroll gesture, it should have no effect.
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
+ host_impl_->ScrollEnd();
+ EXPECT_FALSE(did_request_animate_);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+ EXPECT_TRUE(animation_task_.Equals(base::Closure()));
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+ // After a scroll, a scrollbar animation should be scheduled about 20ms from
+ // now.
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 5));
+ EXPECT_FALSE(did_request_animate_);
+ EXPECT_TRUE(did_request_redraw_);
+ did_request_redraw_ = false;
+ EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+ EXPECT_TRUE(animation_task_.Equals(base::Closure()));
- EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_animate_);
+ host_impl_->ScrollEnd();
+ EXPECT_FALSE(did_request_animate_);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
+ requested_animation_delay_);
+ EXPECT_FALSE(animation_task_.Equals(base::Closure()));
+
+ fake_now += requested_animation_delay_;
+ requested_animation_delay_ = base::TimeDelta();
+ animation_task_.Run();
+ animation_task_ = base::Closure();
+ EXPECT_TRUE(did_request_animate_);
+ did_request_animate_ = false;
+ EXPECT_FALSE(did_request_redraw_);
- // If no scroll happened during a scroll gesture, it should have no effect.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
- host_impl_->ScrollEnd();
- EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_animate_);
- EXPECT_TRUE(scrollbar_fade_start_.Equals(base::Closure()));
+ // After the scrollbar animation begins, we should start getting redraws.
+ host_impl_->Animate(fake_now);
+ EXPECT_TRUE(did_request_animate_);
+ did_request_animate_ = false;
+ EXPECT_TRUE(did_request_redraw_);
+ did_request_redraw_ = false;
+ EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+ EXPECT_TRUE(animation_task_.Equals(base::Closure()));
- // After a scroll, no fade animation should be scheduled.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
- host_impl_->ScrollEnd();
- did_request_redraw_ = false;
- EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_animate_);
- requested_scrollbar_animation_delay_ = base::TimeDelta();
+ // Setting the scroll offset outside a scroll should also cause the
+ // scrollbar to appear and to schedule a scrollbar animation.
+ host_impl_->InnerViewportScrollLayer()->PushScrollOffsetFromMainThread(
+ gfx::ScrollOffset(5, 5));
+ EXPECT_FALSE(did_request_animate_);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
+ requested_animation_delay_);
+ EXPECT_FALSE(animation_task_.Equals(base::Closure()));
+ requested_animation_delay_ = base::TimeDelta();
+ animation_task_ = base::Closure();
+
+ // Scrollbar animation is not triggered unnecessarily.
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
+ EXPECT_FALSE(did_request_animate_);
+ EXPECT_TRUE(did_request_redraw_);
+ did_request_redraw_ = false;
+ EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+ EXPECT_TRUE(animation_task_.Equals(base::Closure()));
- // We should not see any draw requests.
- fake_now += base::TimeDelta::FromMilliseconds(25);
- EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_animate_);
+ host_impl_->ScrollEnd();
+ EXPECT_FALSE(did_request_animate_);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+ EXPECT_TRUE(animation_task_.Equals(base::Closure()));
- // Make page scale > min so that subsequent scrolls will trigger fades.
- host_impl_->active_tree()->SetPageScaleDelta(1.1f);
+ // Changing page scale triggers scrollbar animation.
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f);
+ host_impl_->SetPageScaleOnActiveTree(1.1f);
+ EXPECT_FALSE(did_request_animate_);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
+ requested_animation_delay_);
+ EXPECT_FALSE(animation_task_.Equals(base::Closure()));
+ requested_animation_delay_ = base::TimeDelta();
+ animation_task_ = base::Closure();
+ }
+};
- // After a scroll, a fade animation should be scheduled about 20ms from now.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
- host_impl_->ScrollEnd();
- did_request_redraw_ = false;
- EXPECT_LT(base::TimeDelta::FromMilliseconds(19),
- requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_animate_);
- requested_scrollbar_animation_delay_ = base::TimeDelta();
- scrollbar_fade_start_.Run();
+TEST_F(LayerTreeHostImplTestScrollbarAnimation, LinearFade) {
+ RunTest(LayerTreeSettings::LINEAR_FADE);
+}
- // After the fade begins, we should start getting redraws instead of a
- // scheduled animation.
- fake_now += base::TimeDelta::FromMilliseconds(25);
- host_impl_->Animate(fake_now);
- EXPECT_TRUE(did_request_animate_);
+TEST_F(LayerTreeHostImplTestScrollbarAnimation, Thinning) {
+ RunTest(LayerTreeSettings::THINNING);
}
void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
@@ -1574,7 +1751,7 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
LayerTreeSettings settings;
settings.scrollbar_fade_delay_ms = 500;
settings.scrollbar_fade_duration_ms = 300;
- settings.scrollbar_animator = LayerTreeSettings::Thinning;
+ settings.scrollbar_animator = LayerTreeSettings::THINNING;
gfx::Size viewport_size(300, 200);
gfx::Size device_viewport_size = gfx::ToFlooredSize(
@@ -1588,11 +1765,12 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
scoped_ptr<LayerImpl> root =
LayerImpl::Create(host_impl_->active_tree(), 1);
root->SetBounds(viewport_size);
+ root->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> scroll =
LayerImpl::Create(host_impl_->active_tree(), 2);
scroll->SetScrollClipLayer(root->id());
- scroll->SetScrollOffset(gfx::ScrollOffset());
+ scroll->PushScrollOffsetFromMainThread(gfx::ScrollOffset());
scroll->SetBounds(content_size);
scroll->SetContentBounds(content_size);
scroll->SetIsContainerForFixedPositionLayers(true);
@@ -1617,7 +1795,8 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
root->AddChild(scrollbar.Pass());
host_impl_->active_tree()->SetRootLayer(root.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
@@ -1663,7 +1842,7 @@ TEST_F(LayerTreeHostImplTest, MouseMoveAtWithDeviceScaleOf2) {
TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f);
DrawFrame();
{
CompositorFrameMetadata metadata =
@@ -1674,11 +1853,13 @@ TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size);
EXPECT_EQ(0.5f, metadata.min_page_scale_factor);
EXPECT_EQ(4.f, metadata.max_page_scale_factor);
+ EXPECT_FALSE(metadata.root_overflow_x_hidden);
+ EXPECT_FALSE(metadata.root_overflow_y_hidden);
}
// Scrolling should update metadata immediately.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
{
CompositorFrameMetadata metadata =
@@ -1692,8 +1873,27 @@ TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
}
+ // Root "overflow: hidden" properties should be reflected on the outer
+ // viewport scroll layer.
+ {
+ host_impl_->active_tree()
+ ->OuterViewportScrollLayer()
+ ->set_user_scrollable_horizontal(false);
+ CompositorFrameMetadata metadata =
+ host_impl_->MakeCompositorFrameMetadata();
+ EXPECT_TRUE(metadata.root_overflow_x_hidden);
+ EXPECT_FALSE(metadata.root_overflow_y_hidden);
+
+ host_impl_->active_tree()
+ ->OuterViewportScrollLayer()
+ ->set_user_scrollable_vertical(false);
+ metadata = host_impl_->MakeCompositorFrameMetadata();
+ EXPECT_TRUE(metadata.root_overflow_x_hidden);
+ EXPECT_TRUE(metadata.root_overflow_y_hidden);
+ }
+
// Page scale should update metadata correctly (shrinking only the viewport).
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(2.f, gfx::Point());
host_impl_->PinchGestureEnd();
@@ -1711,8 +1911,8 @@ TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
// Likewise if set from the main thread.
host_impl_->ProcessScrollDeltas();
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(4.f, 0.5f, 4.f);
- host_impl_->active_tree()->SetPageScaleDelta(1.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(4.f, 0.5f, 4.f);
+ host_impl_->SetPageScaleOnActiveTree(4.f);
{
CompositorFrameMetadata metadata =
host_impl_->MakeCompositorFrameMetadata();
@@ -1739,11 +1939,9 @@ class DidDrawCheckLayer : public LayerImpl {
}
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override {
append_quads_called_ = true;
- LayerImpl::AppendQuads(
- render_pass, occlusion_in_content_space, append_quads_data);
+ LayerImpl::AppendQuads(render_pass, append_quads_data);
}
void DidDraw(ResourceProvider* provider) override {
@@ -1763,6 +1961,16 @@ class DidDrawCheckLayer : public LayerImpl {
did_draw_called_ = false;
}
+ static void IgnoreResult(scoped_ptr<CopyOutputResult> result) {}
+
+ void AddCopyRequest() {
+ ScopedPtrVector<CopyOutputRequest> requests;
+ requests.push_back(
+ CopyOutputRequest::CreateRequest(base::Bind(&IgnoreResult)));
+ SetHasRenderSurface(true);
+ PassCopyRequests(&requests);
+ }
+
protected:
DidDrawCheckLayer(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id),
@@ -1792,13 +2000,14 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) {
host_impl_->active_tree()->root_layer());
root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2));
+ root->SetHasRenderSurface(true);
DidDrawCheckLayer* layer =
static_cast<DidDrawCheckLayer*>(root->children()[0]);
{
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_TRUE(layer->will_draw_called());
@@ -1815,7 +2024,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) {
layer->ClearDidDrawCheck();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_TRUE(layer->will_draw_called());
@@ -1832,7 +2041,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) {
DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>(
host_impl_->active_tree()->root_layer());
root->SetMasksToBounds(true);
-
+ root->SetHasRenderSurface(true);
root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2));
DidDrawCheckLayer* layer =
static_cast<DidDrawCheckLayer*>(root->children()[0]);
@@ -1847,7 +2056,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) {
EXPECT_FALSE(layer->did_draw_called());
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_FALSE(layer->will_draw_called());
@@ -1862,7 +2071,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) {
EXPECT_FALSE(layer->did_draw_called());
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_TRUE(layer->will_draw_called());
@@ -1885,6 +2094,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawNotCalledOnOccludedLayer) {
static_cast<DidDrawCheckLayer*>(root->children()[0]);
root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
+ root->SetHasRenderSurface(true);
DidDrawCheckLayer* top_layer =
static_cast<DidDrawCheckLayer*>(root->children()[1]);
// This layer covers the occluded_layer above. Make this layer large so it can
@@ -1901,7 +2111,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawNotCalledOnOccludedLayer) {
EXPECT_FALSE(top_layer->did_draw_called());
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_FALSE(occluded_layer->will_draw_called());
@@ -1917,6 +2127,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) {
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2));
+ root->SetHasRenderSurface(true);
DidDrawCheckLayer* layer1 =
static_cast<DidDrawCheckLayer*>(root->children()[0]);
@@ -1924,7 +2135,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) {
DidDrawCheckLayer* layer2 =
static_cast<DidDrawCheckLayer*>(layer1->children()[0]);
- layer1->SetOpacity(0.3f);
+ layer1->SetHasRenderSurface(true);
layer1->SetShouldFlattenTransform(true);
EXPECT_FALSE(root->did_draw_called());
@@ -1935,7 +2146,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) {
FakeLayerTreeHostImpl::RecursiveUpdateNumChildren(
host_impl_->active_tree()->root_layer());
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_TRUE(root->did_draw_called());
@@ -1943,7 +2154,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) {
EXPECT_TRUE(layer2->did_draw_called());
EXPECT_NE(root->render_surface(), layer1->render_surface());
- EXPECT_TRUE(!!layer1->render_surface());
+ EXPECT_TRUE(layer1->render_surface());
}
class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
@@ -1963,10 +2174,8 @@ class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
}
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override {
- LayerImpl::AppendQuads(
- render_pass, occlusion_in_content_space, append_quads_data);
+ LayerImpl::AppendQuads(render_pass, append_quads_data);
if (had_incomplete_tile_)
append_quads_data->num_incomplete_tiles++;
if (tile_missing_)
@@ -1991,268 +2200,253 @@ class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
bool had_incomplete_tile_;
};
-TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsOnDefault) {
- host_impl_->active_tree()->SetRootLayer(
- DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
- DidDrawCheckLayer* root =
- static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
-
- bool tile_missing = false;
- bool had_incomplete_tile = false;
- bool is_animating = false;
- root->AddChild(
- MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
- 2,
- tile_missing,
- had_incomplete_tile,
- is_animating,
- host_impl_->resource_provider()));
+struct PrepareToDrawSuccessTestCase {
+ struct State {
+ bool has_missing_tile = false;
+ bool has_incomplete_tile = false;
+ bool is_animating = false;
+ bool has_copy_request = false;
+ };
+ bool high_res_required = false;
+ State layer_before;
+ State layer_between;
+ State layer_after;
+ DrawResult expected_result;
+
+ explicit PrepareToDrawSuccessTestCase(DrawResult result)
+ : expected_result(result) {}
+};
- LayerTreeHostImpl::FrameData frame;
+TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsAndFails) {
+ std::vector<PrepareToDrawSuccessTestCase> cases;
+
+ // 0. Default case.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ // 1. Animated layer first.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_before.is_animating = true;
+ // 2. Animated layer between.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_between.is_animating = true;
+ // 3. Animated layer last.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_after.is_animating = true;
+ // 4. Missing tile first.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_before.has_missing_tile = true;
+ // 5. Missing tile between.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_between.has_missing_tile = true;
+ // 6. Missing tile last.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_after.has_missing_tile = true;
+ // 7. Incomplete tile first.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_before.has_incomplete_tile = true;
+ // 8. Incomplete tile between.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_between.has_incomplete_tile = true;
+ // 9. Incomplete tile last.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_after.has_incomplete_tile = true;
+ // 10. Animation with missing tile.
+ cases.push_back(
+ PrepareToDrawSuccessTestCase(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS));
+ cases.back().layer_between.has_missing_tile = true;
+ cases.back().layer_between.is_animating = true;
+ // 11. Animation with incomplete tile.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_between.has_incomplete_tile = true;
+ cases.back().layer_between.is_animating = true;
+
+ // 12. High res required.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().high_res_required = true;
+ // 13. High res required with incomplete tile.
+ cases.push_back(
+ PrepareToDrawSuccessTestCase(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT));
+ cases.back().high_res_required = true;
+ cases.back().layer_between.has_incomplete_tile = true;
+ // 14. High res required with missing tile.
+ cases.push_back(
+ PrepareToDrawSuccessTestCase(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT));
+ cases.back().high_res_required = true;
+ cases.back().layer_between.has_missing_tile = true;
+
+ // 15. High res required is higher priority than animating missing tiles.
+ cases.push_back(
+ PrepareToDrawSuccessTestCase(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT));
+ cases.back().high_res_required = true;
+ cases.back().layer_between.has_missing_tile = true;
+ cases.back().layer_after.has_missing_tile = true;
+ cases.back().layer_after.is_animating = true;
+ // 16. High res required is higher priority than animating missing tiles.
+ cases.push_back(
+ PrepareToDrawSuccessTestCase(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT));
+ cases.back().high_res_required = true;
+ cases.back().layer_between.has_missing_tile = true;
+ cases.back().layer_before.has_missing_tile = true;
+ cases.back().layer_before.is_animating = true;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
-}
-
-TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWithAnimatedLayer) {
host_impl_->active_tree()->SetRootLayer(
DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
- bool tile_missing = false;
- bool had_incomplete_tile = false;
- bool is_animating = true;
- root->AddChild(
- MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
- 2,
- tile_missing,
- had_incomplete_tile,
- is_animating,
- host_impl_->resource_provider()));
-
- LayerTreeHostImpl::FrameData frame;
-
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
-}
-
-TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWithMissingTiles) {
- host_impl_->active_tree()->SetRootLayer(
- DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
- DidDrawCheckLayer* root =
- static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
-
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- host_impl_->SwapBuffers(frame);
-
- bool tile_missing = true;
- bool had_incomplete_tile = false;
- bool is_animating = false;
- root->AddChild(
- MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
- 4,
- tile_missing,
- had_incomplete_tile,
- is_animating,
- host_impl_->resource_provider()));
- LayerTreeHostImpl::FrameData frame2;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame2));
- host_impl_->DrawLayers(&frame2, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame2);
-}
-
-TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWithIncompleteTile) {
- host_impl_->active_tree()->SetRootLayer(
- DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
- DidDrawCheckLayer* root =
- static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ root->SetHasRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
host_impl_->SwapBuffers(frame);
- bool tile_missing = false;
- bool had_incomplete_tile = true;
- bool is_animating = false;
- root->AddChild(
- MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
- 4,
- tile_missing,
- had_incomplete_tile,
- is_animating,
- host_impl_->resource_provider()));
- LayerTreeHostImpl::FrameData frame2;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame2));
- host_impl_->DrawLayers(&frame2, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame2);
-}
-
-TEST_F(LayerTreeHostImplTest,
- PrepareToDrawFailsWithAnimationAndMissingTilesUsesCheckerboard) {
- host_impl_->active_tree()->SetRootLayer(
- DidDrawCheckLayer::Create(host_impl_->active_tree(), 5));
- DidDrawCheckLayer* root =
- static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ for (size_t i = 0; i < cases.size(); ++i) {
+ const auto& testcase = cases[i];
+ std::vector<LayerImpl*> to_remove;
+ for (auto* child : root->children())
+ to_remove.push_back(child);
+ for (auto* child : to_remove)
+ root->RemoveChild(child);
+
+ std::ostringstream scope;
+ scope << "Test case: " << i;
+ SCOPED_TRACE(scope.str());
+
+ root->AddChild(MissingTextureAnimatingLayer::Create(
+ host_impl_->active_tree(), 2, testcase.layer_before.has_missing_tile,
+ testcase.layer_before.has_incomplete_tile,
+ testcase.layer_before.is_animating, host_impl_->resource_provider()));
+ DidDrawCheckLayer* before =
+ static_cast<DidDrawCheckLayer*>(root->children().back());
+ if (testcase.layer_before.has_copy_request)
+ before->AddCopyRequest();
+
+ root->AddChild(MissingTextureAnimatingLayer::Create(
+ host_impl_->active_tree(), 3, testcase.layer_between.has_missing_tile,
+ testcase.layer_between.has_incomplete_tile,
+ testcase.layer_between.is_animating, host_impl_->resource_provider()));
+ DidDrawCheckLayer* between =
+ static_cast<DidDrawCheckLayer*>(root->children().back());
+ if (testcase.layer_between.has_copy_request)
+ between->AddCopyRequest();
+
+ root->AddChild(MissingTextureAnimatingLayer::Create(
+ host_impl_->active_tree(), 4, testcase.layer_after.has_missing_tile,
+ testcase.layer_after.has_incomplete_tile,
+ testcase.layer_after.is_animating, host_impl_->resource_provider()));
+ DidDrawCheckLayer* after =
+ static_cast<DidDrawCheckLayer*>(root->children().back());
+ if (testcase.layer_after.has_copy_request)
+ after->AddCopyRequest();
+
+ if (testcase.high_res_required)
+ host_impl_->SetRequiresHighResToDraw();
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- host_impl_->SwapBuffers(frame);
-
- bool tile_missing = true;
- bool had_incomplete_tile = false;
- bool is_animating = true;
- root->AddChild(
- MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
- 6,
- tile_missing,
- had_incomplete_tile,
- is_animating,
- host_impl_->resource_provider()));
- LayerTreeHostImpl::FrameData frame2;
- EXPECT_EQ(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS,
- host_impl_->PrepareToDraw(&frame2));
- host_impl_->DrawLayers(&frame2, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame2);
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(testcase.expected_result, host_impl_->PrepareToDraw(&frame));
+ host_impl_->DrawLayers(&frame);
+ host_impl_->DidDrawAllLayers(frame);
+ host_impl_->SwapBuffers(frame);
+ }
}
TEST_F(LayerTreeHostImplTest,
- PrepareToDrawSucceedsWithAnimationAndIncompleteTiles) {
- host_impl_->active_tree()->SetRootLayer(
- DidDrawCheckLayer::Create(host_impl_->active_tree(), 5));
- DidDrawCheckLayer* root =
- static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
-
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- host_impl_->SwapBuffers(frame);
-
- bool tile_missing = false;
- bool had_incomplete_tile = true;
- bool is_animating = true;
- root->AddChild(
- MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
- 6,
- tile_missing,
- had_incomplete_tile,
- is_animating,
- host_impl_->resource_provider()));
- LayerTreeHostImpl::FrameData frame2;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame2));
- host_impl_->DrawLayers(&frame2, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame2);
-}
-
-TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWhenHighResRequired) {
- host_impl_->active_tree()->SetRootLayer(
- DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
- DidDrawCheckLayer* root =
- static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
-
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- host_impl_->SwapBuffers(frame);
-
- bool tile_missing = false;
- bool had_incomplete_tile = false;
- bool is_animating = false;
- root->AddChild(
- MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
- 8,
- tile_missing,
- had_incomplete_tile,
- is_animating,
- host_impl_->resource_provider()));
- host_impl_->SetRequiresHighResToDraw();
- LayerTreeHostImpl::FrameData frame2;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame2));
- host_impl_->DrawLayers(&frame2, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame2);
-}
+ PrepareToDrawWhenDrawAndSwapFullViewportEveryFrame) {
+ CreateHostImpl(DefaultSettings(),
+ FakeOutputSurface::CreateAlwaysDrawAndSwap3d());
+ EXPECT_TRUE(host_impl_->output_surface()
+ ->capabilities()
+ .draw_and_swap_full_viewport_every_frame);
+
+ std::vector<PrepareToDrawSuccessTestCase> cases;
+
+ // 0. Default case.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ // 1. Animation with missing tile.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().layer_between.has_missing_tile = true;
+ cases.back().layer_between.is_animating = true;
+ // 2. High res required with incomplete tile.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().high_res_required = true;
+ cases.back().layer_between.has_incomplete_tile = true;
+ // 3. High res required with missing tile.
+ cases.push_back(PrepareToDrawSuccessTestCase(DRAW_SUCCESS));
+ cases.back().high_res_required = true;
+ cases.back().layer_between.has_missing_tile = true;
-TEST_F(LayerTreeHostImplTest,
- PrepareToDrawFailsWhenHighResRequiredAndIncompleteTiles) {
host_impl_->active_tree()->SetRootLayer(
- DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
+ DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ root->SetHasRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
host_impl_->SwapBuffers(frame);
- bool tile_missing = false;
- bool had_incomplete_tile = true;
- bool is_animating = false;
- root->AddChild(
- MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
- 8,
- tile_missing,
- had_incomplete_tile,
- is_animating,
- host_impl_->resource_provider()));
- host_impl_->SetRequiresHighResToDraw();
- LayerTreeHostImpl::FrameData frame2;
- EXPECT_EQ(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT,
- host_impl_->PrepareToDraw(&frame2));
- host_impl_->DrawLayers(&frame2, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame2);
-}
+ for (size_t i = 0; i < cases.size(); ++i) {
+ const auto& testcase = cases[i];
+ std::vector<LayerImpl*> to_remove;
+ for (auto* child : root->children())
+ to_remove.push_back(child);
+ for (auto* child : to_remove)
+ root->RemoveChild(child);
+
+ std::ostringstream scope;
+ scope << "Test case: " << i;
+ SCOPED_TRACE(scope.str());
+
+ root->AddChild(MissingTextureAnimatingLayer::Create(
+ host_impl_->active_tree(), 2, testcase.layer_before.has_missing_tile,
+ testcase.layer_before.has_incomplete_tile,
+ testcase.layer_before.is_animating, host_impl_->resource_provider()));
+ DidDrawCheckLayer* before =
+ static_cast<DidDrawCheckLayer*>(root->children().back());
+ if (testcase.layer_before.has_copy_request)
+ before->AddCopyRequest();
+
+ root->AddChild(MissingTextureAnimatingLayer::Create(
+ host_impl_->active_tree(), 3, testcase.layer_between.has_missing_tile,
+ testcase.layer_between.has_incomplete_tile,
+ testcase.layer_between.is_animating, host_impl_->resource_provider()));
+ DidDrawCheckLayer* between =
+ static_cast<DidDrawCheckLayer*>(root->children().back());
+ if (testcase.layer_between.has_copy_request)
+ between->AddCopyRequest();
+
+ root->AddChild(MissingTextureAnimatingLayer::Create(
+ host_impl_->active_tree(), 4, testcase.layer_after.has_missing_tile,
+ testcase.layer_after.has_incomplete_tile,
+ testcase.layer_after.is_animating, host_impl_->resource_provider()));
+ DidDrawCheckLayer* after =
+ static_cast<DidDrawCheckLayer*>(root->children().back());
+ if (testcase.layer_after.has_copy_request)
+ after->AddCopyRequest();
+
+ if (testcase.high_res_required)
+ host_impl_->SetRequiresHighResToDraw();
-TEST_F(LayerTreeHostImplTest,
- PrepareToDrawFailsWhenHighResRequiredAndMissingTile) {
- host_impl_->active_tree()->SetRootLayer(
- DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
- DidDrawCheckLayer* root =
- static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
-
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- host_impl_->SwapBuffers(frame);
-
- bool tile_missing = true;
- bool had_incomplete_tile = false;
- bool is_animating = false;
- root->AddChild(
- MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
- 8,
- tile_missing,
- had_incomplete_tile,
- is_animating,
- host_impl_->resource_provider()));
- host_impl_->SetRequiresHighResToDraw();
- LayerTreeHostImpl::FrameData frame2;
- EXPECT_EQ(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT,
- host_impl_->PrepareToDraw(&frame2));
- host_impl_->DrawLayers(&frame2, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame2);
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(testcase.expected_result, host_impl_->PrepareToDraw(&frame));
+ host_impl_->DrawLayers(&frame);
+ host_impl_->DidDrawAllLayers(frame);
+ host_impl_->SwapBuffers(frame);
+ }
}
TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) {
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
root->SetScrollClipLayer(Layer::INVALID_ID);
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
DrawFrame();
// Scroll event is ignored because layer is not scrollable.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_FALSE(did_request_redraw_);
EXPECT_FALSE(did_request_commit_);
}
@@ -2264,14 +2458,23 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest {
// Make the clip size the same as the layer (content) size so the layer is
// non-scrollable.
: layer_size_(10, 10),
- clip_size_(layer_size_) {
- settings_.calculate_top_controls_position = true;
- settings_.top_controls_height = 50;
+ clip_size_(layer_size_),
+ top_controls_height_(50) {
settings_.use_pinch_virtual_viewport = true;
- viewport_size_ =
- gfx::Size(clip_size_.width(),
- clip_size_.height() + settings_.top_controls_height);
+ viewport_size_ = gfx::Size(clip_size_.width(),
+ clip_size_.height() + top_controls_height_);
+ }
+
+ bool CreateHostImpl(const LayerTreeSettings& settings,
+ scoped_ptr<OutputSurface> output_surface) override {
+ bool init =
+ LayerTreeHostImplTest::CreateHostImpl(settings, output_surface.Pass());
+ if (init) {
+ host_impl_->active_tree()->set_top_controls_height(top_controls_height_);
+ host_impl_->active_tree()->SetCurrentTopControlsShownRatio(1.f);
+ }
+ return init;
}
void SetupTopControlsAndScrollLayer() {
@@ -2288,17 +2491,22 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest {
root->SetIsContainerForFixedPositionLayers(true);
int inner_viewport_scroll_layer_id = root->id();
int page_scale_layer_id = root_clip->id();
+ root_clip->SetHasRenderSurface(true);
root_clip->AddChild(root.Pass());
+ root_clip->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
host_impl_->active_tree()->SetViewportLayersFromIds(
- page_scale_layer_id, inner_viewport_scroll_layer_id, Layer::INVALID_ID);
+ Layer::INVALID_ID, page_scale_layer_id, inner_viewport_scroll_layer_id,
+ Layer::INVALID_ID);
// Set a viewport size that is large enough to contain both the top controls
// and some content.
host_impl_->SetViewportSize(viewport_size_);
- host_impl_->SetTopControlsLayoutHeight(
- settings_.top_controls_height);
+ host_impl_->sync_tree()->set_top_controls_shrink_blink_size(true);
+
+ host_impl_->DidChangeTopControlsPosition();
host_impl_->CreatePendingTree();
+ host_impl_->sync_tree()->set_top_controls_height(top_controls_height_);
root =
LayerImpl::Create(host_impl_->sync_tree(), 1);
root_clip =
@@ -2315,12 +2523,13 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest {
root_clip->AddChild(root.Pass());
host_impl_->sync_tree()->SetRootLayer(root_clip.Pass());
host_impl_->sync_tree()->SetViewportLayersFromIds(
- page_scale_layer_id, inner_viewport_scroll_layer_id, Layer::INVALID_ID);
+ Layer::INVALID_ID, page_scale_layer_id, inner_viewport_scroll_layer_id,
+ Layer::INVALID_ID);
// Set a viewport size that is large enough to contain both the top controls
// and some content.
host_impl_->SetViewportSize(viewport_size_);
- host_impl_->sync_tree()->set_top_controls_layout_height(
- settings_.top_controls_height);
+ host_impl_->sync_tree()->set_top_controls_shrink_blink_size(true);
+ host_impl_->DidChangeTopControlsPosition();
}
void SetupTopControlsAndScrollLayerWithVirtualViewport(
@@ -2328,8 +2537,9 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest {
const gfx::Size& outer_viewport_size,
const gfx::Size& scroll_layer_size) {
CreateHostImpl(settings_, CreateOutputSurface());
- host_impl_->SetTopControlsLayoutHeight(
- settings_.top_controls_height);
+ host_impl_->sync_tree()->set_top_controls_shrink_blink_size(true);
+ host_impl_->sync_tree()->set_top_controls_height(top_controls_height_);
+ host_impl_->DidChangeTopControlsPosition();
scoped_ptr<LayerImpl> root =
LayerImpl::Create(host_impl_->active_tree(), 1);
@@ -2350,7 +2560,7 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest {
root->SetPosition(gfx::PointF());
root->SetDrawsContent(false);
root->SetIsContainerForFixedPositionLayers(true);
-
+ root_clip->SetHasRenderSurface(true);
outer_clip->SetBounds(outer_viewport_size);
outer_scroll->SetScrollClipLayer(outer_clip->id());
outer_scroll->SetBounds(scroll_layer_size);
@@ -2370,8 +2580,7 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest {
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
host_impl_->active_tree()->SetViewportLayersFromIds(
- page_scale_layer_id,
- inner_viewport_scroll_layer_id,
+ Layer::INVALID_ID, page_scale_layer_id, inner_viewport_scroll_layer_id,
outer_viewport_scroll_layer_id);
host_impl_->SetViewportSize(inner_viewport_size);
@@ -2383,6 +2592,7 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest {
gfx::Size layer_size_;
gfx::Size clip_size_;
gfx::Size viewport_size_;
+ float top_controls_height_;
LayerTreeSettings settings_;
}; // class LayerTreeHostImplTopControlsTest
@@ -2392,8 +2602,8 @@ TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsByFractionalAmount) {
gfx::Size(10, 10), gfx::Size(10, 10), gfx::Size(10, 10));
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// Make the test scroll delta a fractional amount, to verify that the
// fixed container size delta is (1) non-zero, and (2) fractional, and
@@ -2407,8 +2617,8 @@ TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsByFractionalAmount) {
host_impl_->active_tree()->InnerViewportScrollLayer();
DCHECK(inner_viewport_scroll_layer);
host_impl_->ScrollEnd();
- EXPECT_EQ(top_controls_scroll_delta,
- inner_viewport_scroll_layer->FixedContainerSizeDelta());
+ EXPECT_FLOAT_EQ(top_controls_scroll_delta.y(),
+ inner_viewport_scroll_layer->FixedContainerSizeDelta().y());
}
// In this test, the outer viewport is initially unscrollable. We test that a
@@ -2420,41 +2630,40 @@ TEST_F(LayerTreeHostImplTopControlsTest,
gfx::Size(10, 50), gfx::Size(10, 50), gfx::Size(10, 100));
DrawFrame();
- LayerImpl *inner_scroll =
+ LayerImpl* inner_scroll =
host_impl_->active_tree()->InnerViewportScrollLayer();
- LayerImpl *inner_container =
+ LayerImpl* inner_container =
host_impl_->active_tree()->InnerViewportContainerLayer();
- LayerImpl *outer_scroll =
+ LayerImpl* outer_scroll =
host_impl_->active_tree()->OuterViewportScrollLayer();
- LayerImpl *outer_container =
+ LayerImpl* outer_container =
host_impl_->active_tree()->OuterViewportContainerLayer();
// Need SetDrawsContent so ScrollBegin's hit test finds an actual layer.
outer_scroll->SetDrawsContent(true);
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 1.f, 2.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 1.f, 2.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, 50.f));
// The entire scroll delta should have been used to hide the top controls.
// The viewport layers should be resized back to their full sizes.
- EXPECT_EQ(0.f,
- host_impl_->active_tree()->total_top_controls_content_offset());
- EXPECT_EQ(0.f, inner_scroll->TotalScrollOffset().y());
+ EXPECT_EQ(0.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
+ EXPECT_EQ(0.f, inner_scroll->CurrentScrollOffset().y());
EXPECT_EQ(100.f, inner_container->BoundsForScrolling().height());
EXPECT_EQ(100.f, outer_container->BoundsForScrolling().height());
// The inner viewport should be scrollable by 50px * page_scale.
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, 100.f));
- EXPECT_EQ(50.f, inner_scroll->TotalScrollOffset().y());
- EXPECT_EQ(0.f, outer_scroll->TotalScrollOffset().y());
+ EXPECT_EQ(50.f, inner_scroll->CurrentScrollOffset().y());
+ EXPECT_EQ(0.f, outer_scroll->CurrentScrollOffset().y());
EXPECT_EQ(gfx::ScrollOffset(), outer_scroll->MaxScrollOffset());
host_impl_->ScrollEnd();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll);
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -50.f));
@@ -2462,28 +2671,27 @@ TEST_F(LayerTreeHostImplTopControlsTest,
// The entire scroll delta should have been used to show the top controls.
// The outer viewport should be resized to accomodate and scrolled to the
// bottom of the document to keep the viewport in place.
- EXPECT_EQ(50.f,
- host_impl_->active_tree()->total_top_controls_content_offset());
+ EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
EXPECT_EQ(50.f, outer_container->BoundsForScrolling().height());
EXPECT_EQ(50.f, inner_container->BoundsForScrolling().height());
- EXPECT_EQ(25.f, outer_scroll->TotalScrollOffset().y());
- EXPECT_EQ(25.f, inner_scroll->TotalScrollOffset().y());
+ EXPECT_EQ(25.f, outer_scroll->CurrentScrollOffset().y());
+ EXPECT_EQ(25.f, inner_scroll->CurrentScrollOffset().y());
// Now when we continue scrolling, make sure the outer viewport gets scrolled
// since it wasn't scrollable when the scroll began.
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -20.f));
- EXPECT_EQ(15.f, outer_scroll->TotalScrollOffset().y());
- EXPECT_EQ(25.f, inner_scroll->TotalScrollOffset().y());
+ EXPECT_EQ(15.f, outer_scroll->CurrentScrollOffset().y());
+ EXPECT_EQ(25.f, inner_scroll->CurrentScrollOffset().y());
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -30.f));
- EXPECT_EQ(0.f, outer_scroll->TotalScrollOffset().y());
- EXPECT_EQ(25.f, inner_scroll->TotalScrollOffset().y());
+ EXPECT_EQ(0.f, outer_scroll->CurrentScrollOffset().y());
+ EXPECT_EQ(25.f, inner_scroll->CurrentScrollOffset().y());
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -50.f));
host_impl_->ScrollEnd();
- EXPECT_EQ(0.f, outer_scroll->TotalScrollOffset().y());
- EXPECT_EQ(0.f, inner_scroll->TotalScrollOffset().y());
+ EXPECT_EQ(0.f, outer_scroll->CurrentScrollOffset().y());
+ EXPECT_EQ(0.f, inner_scroll->CurrentScrollOffset().y());
}
// Test that the fixed position container delta is appropriately adjusted
@@ -2494,24 +2702,23 @@ TEST_F(LayerTreeHostImplTopControlsTest, FixedContainerDelta) {
DrawFrame();
float page_scale = 1.5f;
- float top_controls_height = settings_.top_controls_height;
LayerImpl* outer_viewport_scroll_layer =
host_impl_->active_tree()->OuterViewportScrollLayer();
// Zoom in, since the fixed container is the outer viewport, the delta should
// not be scaled.
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale, 1.f, 2.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, 2.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// Scroll down, the top controls hiding should expand the viewport size so
// the delta should be equal to the scroll distance.
gfx::Vector2dF top_controls_scroll_delta(0.f, 20.f);
host_impl_->top_controls_manager()->ScrollBegin();
host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
- EXPECT_EQ(top_controls_height - top_controls_scroll_delta.y(),
- host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_FLOAT_EQ(top_controls_height_ - top_controls_scroll_delta.y(),
+ host_impl_->top_controls_manager()->ContentTopOffset());
EXPECT_VECTOR_EQ(top_controls_scroll_delta,
outer_viewport_scroll_layer->FixedContainerSizeDelta());
host_impl_->ScrollEnd();
@@ -2523,7 +2730,7 @@ TEST_F(LayerTreeHostImplTopControlsTest, FixedContainerDelta) {
host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(0, top_controls_height),
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, top_controls_height_),
outer_viewport_scroll_layer->FixedContainerSizeDelta());
host_impl_->ScrollEnd();
@@ -2533,11 +2740,58 @@ TEST_F(LayerTreeHostImplTopControlsTest, FixedContainerDelta) {
EXPECT_EQ(top_controls_scroll_delta.y(),
host_impl_->top_controls_manager()->ContentTopOffset());
EXPECT_VECTOR_EQ(
- gfx::Vector2dF(0, top_controls_height - top_controls_scroll_delta.y()),
+ gfx::Vector2dF(0, top_controls_height_ - top_controls_scroll_delta.y()),
outer_viewport_scroll_layer->FixedContainerSizeDelta());
host_impl_->top_controls_manager()->ScrollEnd();
}
+// Test that if a scrollable sublayer doesn't consume the scroll,
+// top controls should hide when scrolling down.
+TEST_F(LayerTreeHostImplTopControlsTest, TopControlsScrollableSublayer) {
+ gfx::Size sub_content_size(100, 400);
+ gfx::Size sub_content_layer_size(100, 300);
+ SetupTopControlsAndScrollLayerWithVirtualViewport(
+ gfx::Size(100, 50), gfx::Size(100, 100), gfx::Size(100, 100));
+ DrawFrame();
+
+ // Show top controls
+ EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
+
+ LayerImpl* outer_viewport_scroll_layer =
+ host_impl_->active_tree()->OuterViewportScrollLayer();
+ int id = outer_viewport_scroll_layer->id();
+
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl_->active_tree(), id + 2);
+ scoped_ptr<LayerImpl> child_clip =
+ LayerImpl::Create(host_impl_->active_tree(), id + 3);
+
+ child_clip->SetBounds(sub_content_layer_size);
+ child->SetScrollClipLayer(child_clip->id());
+ child->SetBounds(sub_content_size);
+ child->SetContentBounds(sub_content_size);
+ child->SetPosition(gfx::PointF());
+ child->SetDrawsContent(true);
+ child->SetIsContainerForFixedPositionLayers(true);
+
+ // scroll child to limit
+ child->SetScrollDelta(gfx::Vector2dF(0, 100.f));
+ child_clip->AddChild(child.Pass());
+ outer_viewport_scroll_layer->AddChild(child_clip.Pass());
+
+ // Scroll 25px to hide top controls
+ gfx::Vector2dF scroll_delta(0.f, 25.f);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ host_impl_->ScrollEnd();
+
+ // Top controls should be hidden
+ EXPECT_EQ(scroll_delta.y(),
+ top_controls_height_ -
+ host_impl_->top_controls_manager()->ContentTopOffset());
+}
+
// Ensure setting the top controls position explicitly using the setters on the
// TreeImpl correctly affects the top controls manager and viewport bounds.
TEST_F(LayerTreeHostImplTopControlsTest, PositionTopControlsExplicitly) {
@@ -2545,14 +2799,18 @@ TEST_F(LayerTreeHostImplTopControlsTest, PositionTopControlsExplicitly) {
SetupTopControlsAndScrollLayer();
DrawFrame();
- host_impl_->active_tree()->set_top_controls_delta(0.f);
- host_impl_->active_tree()->set_top_controls_content_offset(30.f);
- EXPECT_EQ(30.f, host_impl_->top_controls_manager()->ContentTopOffset());
- EXPECT_EQ(-20.f, host_impl_->top_controls_manager()->ControlsTopOffset());
+ host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f);
+ host_impl_->active_tree()->top_controls_shown_ratio()->PushFromMainThread(
+ 30.f / top_controls_height_);
+ host_impl_->active_tree()->top_controls_shown_ratio()->PushPendingToActive();
+ EXPECT_FLOAT_EQ(30.f, host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-20.f,
+ host_impl_->top_controls_manager()->ControlsTopOffset());
- host_impl_->active_tree()->set_top_controls_delta(-30.f);
- EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
- EXPECT_EQ(-50.f, host_impl_->top_controls_manager()->ControlsTopOffset());
+ host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f);
+ EXPECT_FLOAT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-50.f,
+ host_impl_->top_controls_manager()->ControlsTopOffset());
host_impl_->DidChangeTopControlsPosition();
@@ -2569,18 +2827,22 @@ TEST_F(LayerTreeHostImplTopControlsTest, ApplyDeltaOnTreeActivation) {
SetupTopControlsAndScrollLayer();
DrawFrame();
- host_impl_->sync_tree()->set_top_controls_content_offset(15.f);
-
- host_impl_->active_tree()->set_top_controls_content_offset(20.f);
- host_impl_->active_tree()->set_top_controls_delta(-20.f);
- host_impl_->active_tree()->set_sent_top_controls_delta(-5.f);
+ host_impl_->active_tree()->top_controls_shown_ratio()->PushFromMainThread(
+ 20.f / top_controls_height_);
+ host_impl_->active_tree()->top_controls_shown_ratio()->PushPendingToActive();
+ host_impl_->active_tree()->SetCurrentTopControlsShownRatio(
+ 15.f / top_controls_height_);
+ host_impl_->active_tree()
+ ->top_controls_shown_ratio()
+ ->PullDeltaForMainThread();
+ host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f);
+ host_impl_->sync_tree()->PushTopControlsFromMainThread(15.f /
+ top_controls_height_);
host_impl_->DidChangeTopControlsPosition();
LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer();
EXPECT_EQ(viewport_size_, root_clip_ptr->bounds());
EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
- EXPECT_EQ(0.f,
- host_impl_->active_tree()->total_top_controls_content_offset());
host_impl_->ActivateSyncTree();
@@ -2588,11 +2850,13 @@ TEST_F(LayerTreeHostImplTopControlsTest, ApplyDeltaOnTreeActivation) {
EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
EXPECT_EQ(viewport_size_, root_clip_ptr->bounds());
- EXPECT_EQ(0.f, host_impl_->active_tree()->sent_top_controls_delta());
- EXPECT_EQ(-15.f, host_impl_->active_tree()->top_controls_delta());
- EXPECT_EQ(15.f, host_impl_->active_tree()->top_controls_content_offset());
- EXPECT_EQ(0.f,
- host_impl_->active_tree()->total_top_controls_content_offset());
+ EXPECT_FLOAT_EQ(
+ -15.f, host_impl_->active_tree()->top_controls_shown_ratio()->Delta() *
+ top_controls_height_);
+ EXPECT_FLOAT_EQ(
+ 15.f,
+ host_impl_->active_tree()->top_controls_shown_ratio()->ActiveBase() *
+ top_controls_height_);
}
// Test that changing the top controls layout height is correctly applied to
@@ -2604,12 +2868,13 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsLayoutHeightChanged) {
SetupTopControlsAndScrollLayer();
DrawFrame();
- host_impl_->sync_tree()->set_top_controls_content_offset(15.f);
- host_impl_->sync_tree()->set_top_controls_layout_height(15.f);
+ host_impl_->sync_tree()->PushTopControlsFromMainThread(1.f);
+ host_impl_->sync_tree()->set_top_controls_shrink_blink_size(true);
- host_impl_->active_tree()->set_top_controls_content_offset(20.f);
- host_impl_->active_tree()->set_top_controls_delta(-20.f);
- host_impl_->active_tree()->set_sent_top_controls_delta(-5.f);
+ host_impl_->active_tree()->top_controls_shown_ratio()->PushFromMainThread(
+ 1.f);
+ host_impl_->active_tree()->top_controls_shown_ratio()->PushPendingToActive();
+ host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f);
host_impl_->DidChangeTopControlsPosition();
LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer();
@@ -2618,7 +2883,7 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsLayoutHeightChanged) {
host_impl_->sync_tree()->root_layer()->SetBounds(
gfx::Size(root_clip_ptr->bounds().width(),
- root_clip_ptr->bounds().height() - 15.f));
+ root_clip_ptr->bounds().height() - 50.f));
host_impl_->ActivateSyncTree();
@@ -2629,14 +2894,16 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsLayoutHeightChanged) {
// account for the difference between the layout height and the current
// top controls offset.
EXPECT_EQ(viewport_size_, root_clip_ptr->bounds());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 15.f), root_clip_ptr->bounds_delta());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 50.f), root_clip_ptr->bounds_delta());
- host_impl_->active_tree()->set_top_controls_delta(0.f);
+ host_impl_->active_tree()->SetCurrentTopControlsShownRatio(1.f);
host_impl_->DidChangeTopControlsPosition();
- EXPECT_EQ(15.f, host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_EQ(1.f, host_impl_->top_controls_manager()->TopControlsShownRatio());
+ EXPECT_EQ(50.f, host_impl_->top_controls_manager()->TopControlsHeight());
+ EXPECT_EQ(50.f, host_impl_->top_controls_manager()->ContentTopOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f), root_clip_ptr->bounds_delta());
- EXPECT_EQ(gfx::Size(viewport_size_.width(), viewport_size_.height()-15.f),
+ EXPECT_EQ(gfx::Size(viewport_size_.width(), viewport_size_.height() - 50.f),
root_clip_ptr->bounds());
}
@@ -2648,8 +2915,7 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsViewportOffsetClamping) {
gfx::Size(100, 100), gfx::Size(200, 200), gfx::Size(200, 400));
DrawFrame();
- EXPECT_EQ(settings_.top_controls_height,
- host_impl_->active_tree()->total_top_controls_content_offset());
+ EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer();
LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer();
@@ -2664,14 +2930,20 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsViewportOffsetClamping) {
// Hide the top controls by 25px.
gfx::Vector2dF scroll_delta(0.f, 25.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+
+ // scrolling down at the max extents no longer hides the top controls
+ EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
+
+ // forcefully hide the top controls by 25px
+ host_impl_->top_controls_manager()->ScrollBy(scroll_delta);
host_impl_->ScrollEnd();
- EXPECT_EQ(scroll_delta.y(),
- settings_.top_controls_height -
- host_impl_->active_tree()->total_top_controls_content_offset());
+ EXPECT_FLOAT_EQ(scroll_delta.y(),
+ top_controls_height_ -
+ host_impl_->top_controls_manager()->ContentTopOffset());
inner_scroll->ClampScrollToMaxScrollOffset();
outer_scroll->ClampScrollToMaxScrollOffset();
@@ -2684,8 +2956,8 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsViewportOffsetClamping) {
// Bring the top controls down by 25px.
scroll_delta = gfx::Vector2dF(0.f, -25.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -2707,18 +2979,18 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsAspectRatio) {
gfx::Size(100, 100), gfx::Size(200, 200), gfx::Size(200, 400));
DrawFrame();
- EXPECT_EQ(settings_.top_controls_height,
- host_impl_->active_tree()->total_top_controls_content_offset());
+ EXPECT_FLOAT_EQ(top_controls_height_,
+ host_impl_->top_controls_manager()->ContentTopOffset());
gfx::Vector2dF scroll_delta(0.f, 25.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
- EXPECT_EQ(scroll_delta.y(),
- settings_.top_controls_height -
- host_impl_->active_tree()->total_top_controls_content_offset());
+ EXPECT_FLOAT_EQ(scroll_delta.y(),
+ top_controls_height_ -
+ host_impl_->top_controls_manager()->ContentTopOffset());
// Top controls were hidden by 25px so the inner viewport should have expanded
// by that much.
@@ -2743,29 +3015,29 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsScrollOuterViewport) {
gfx::Size(100, 100), gfx::Size(200, 200), gfx::Size(200, 400));
DrawFrame();
- EXPECT_EQ(settings_.top_controls_height,
- host_impl_->active_tree()->total_top_controls_content_offset());
+ EXPECT_EQ(top_controls_height_,
+ host_impl_->top_controls_manager()->ContentTopOffset());
// Send a gesture scroll that will scroll the outer viewport, make sure the
// top controls get scrolled.
gfx::Vector2dF scroll_delta(0.f, 15.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(host_impl_->OuterViewportScrollLayer(),
host_impl_->CurrentlyScrollingLayer());
host_impl_->ScrollEnd();
- EXPECT_EQ(scroll_delta.y(),
- settings_.top_controls_height -
- host_impl_->active_tree()->total_top_controls_content_offset());
+ EXPECT_FLOAT_EQ(scroll_delta.y(),
+ top_controls_height_ -
+ host_impl_->top_controls_manager()->ContentTopOffset());
scroll_delta = gfx::Vector2dF(0.f, 50.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
- EXPECT_EQ(0, host_impl_->active_tree()->total_top_controls_content_offset());
+ EXPECT_EQ(0, host_impl_->top_controls_manager()->ContentTopOffset());
EXPECT_EQ(host_impl_->OuterViewportScrollLayer(),
host_impl_->CurrentlyScrollingLayer());
@@ -2777,15 +3049,15 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsScrollOuterViewport) {
host_impl_->InnerViewportScrollLayer()->SetScrollDelta(inner_viewport_offset);
scroll_delta = gfx::Vector2dF(0.f, -65.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
- EXPECT_EQ(settings_.top_controls_height,
- host_impl_->active_tree()->total_top_controls_content_offset());
- EXPECT_EQ(inner_viewport_offset.y() +
- (scroll_delta.y() + settings_.top_controls_height),
- host_impl_->InnerViewportScrollLayer()->ScrollDelta().y());
+ EXPECT_EQ(top_controls_height_,
+ host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_FLOAT_EQ(
+ inner_viewport_offset.y() + (scroll_delta.y() + top_controls_height_),
+ host_impl_->InnerViewportScrollLayer()->ScrollDelta().y());
host_impl_->ScrollEnd();
}
@@ -2796,8 +3068,8 @@ TEST_F(LayerTreeHostImplTopControlsTest,
SetupTopControlsAndScrollLayer();
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->top_controls_manager()->ScrollBegin();
host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f));
@@ -2809,15 +3081,15 @@ TEST_F(LayerTreeHostImplTopControlsTest,
host_impl_->ScrollEnd();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
float scroll_increment_y = -25.f;
host_impl_->top_controls_manager()->ScrollBegin();
host_impl_->top_controls_manager()->ScrollBy(
gfx::Vector2dF(0.f, scroll_increment_y));
- EXPECT_EQ(-scroll_increment_y,
- host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-scroll_increment_y,
+ host_impl_->top_controls_manager()->ContentTopOffset());
// Now that top controls have moved, expect the clip to resize.
EXPECT_EQ(gfx::Size(viewport_size_.width(),
viewport_size_.height() + scroll_increment_y),
@@ -2826,8 +3098,8 @@ TEST_F(LayerTreeHostImplTopControlsTest,
host_impl_->top_controls_manager()->ScrollBy(
gfx::Vector2dF(0.f, scroll_increment_y));
host_impl_->top_controls_manager()->ScrollEnd();
- EXPECT_EQ(-2 * scroll_increment_y,
- host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_FLOAT_EQ(-2 * scroll_increment_y,
+ host_impl_->top_controls_manager()->ContentTopOffset());
// Now that top controls have moved, expect the clip to resize.
EXPECT_EQ(clip_size_, root_clip_ptr->bounds());
@@ -2838,8 +3110,8 @@ TEST_F(LayerTreeHostImplTopControlsTest,
gfx::ScrollOffset(),
host_impl_->active_tree()->InnerViewportScrollLayer()->MaxScrollOffset());
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
}
TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) {
@@ -2869,13 +3141,13 @@ TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) {
scroll_layer->AddChild(content_layer.Pass());
scroll_clip_layer->AddChild(scroll_layer.Pass());
+ scroll_clip_layer->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(scroll_clip_layer.Pass());
host_impl_->SetViewportSize(surface_size);
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
host_impl_->ScrollEnd();
EXPECT_TRUE(did_request_redraw_);
@@ -2889,13 +3161,13 @@ TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) {
root->SetBounds(surface_size);
root->SetContentBounds(contents_size);
root->AddChild(CreateScrollableLayer(2, contents_size, root.get()));
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
host_impl_->SetViewportSize(surface_size);
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
host_impl_->ScrollEnd();
EXPECT_TRUE(did_request_redraw_);
@@ -2906,15 +3178,15 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesChild) {
gfx::Size surface_size(10, 10);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
root->AddChild(CreateScrollableLayer(2, surface_size, root.get()));
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
host_impl_->SetViewportSize(surface_size);
DrawFrame();
// Scroll event is ignored because the input coordinate is outside the layer
// boundaries.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->ScrollBegin(gfx::Point(15, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED,
+ host_impl_->ScrollBegin(gfx::Point(15, 5), InputHandler::WHEEL));
EXPECT_FALSE(did_request_redraw_);
EXPECT_FALSE(did_request_commit_);
}
@@ -2922,6 +3194,7 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesChild) {
TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) {
gfx::Size surface_size(10, 10);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
+ root->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> child =
CreateScrollableLayer(2, surface_size, root.get());
host_impl_->SetViewportSize(surface_size);
@@ -2937,9 +3210,8 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) {
// Scroll event is ignored because the scrollable layer is not facing the
// viewer and there is nothing scrollable behind it.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
EXPECT_FALSE(did_request_redraw_);
EXPECT_FALSE(did_request_commit_);
}
@@ -2959,6 +3231,7 @@ TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) {
CreateScrollableLayer(2, surface_size, clip_layer.get());
scroll_layer->AddChild(content_layer.Pass());
clip_layer->AddChild(scroll_layer.Pass());
+ clip_layer->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(clip_layer.Pass());
host_impl_->SetViewportSize(surface_size);
@@ -2966,9 +3239,8 @@ TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) {
// Scrolling fails because the content layer is asking to be scrolled on the
// main thread.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
@@ -2984,10 +3256,12 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
root_scrolling->SetIsContainerForFixedPositionLayers(true);
root_clip->AddChild(root_scrolling.Pass());
root->AddChild(root_clip.Pass());
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
// The behaviour in this test assumes the page scale is applied at a layer
// above the clip layer.
- host_impl_->active_tree()->SetViewportLayersFromIds(1, 3, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 3,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(viewport_size);
DrawFrame();
@@ -2999,15 +3273,13 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta = scroll_delta;
gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
// Set new page scale from main thread.
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale,
- page_scale,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, page_scale,
page_scale);
scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
@@ -3034,13 +3306,15 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) {
root_scrolling->SetIsContainerForFixedPositionLayers(true);
root_clip->AddChild(root_scrolling.Pass());
root->AddChild(root_clip.Pass());
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
// The behaviour in this test assumes the page scale is applied at a layer
// above the clip layer.
- host_impl_->active_tree()->SetViewportLayersFromIds(1, 3, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 3,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(viewport_size);
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, page_scale);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, page_scale);
DrawFrame();
LayerImpl* root_scroll =
@@ -3050,14 +3324,13 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) {
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta = scroll_delta;
gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
// Set new page scale on impl thread by pinching.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale, gfx::Point());
host_impl_->PinchGestureEnd();
@@ -3072,7 +3345,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) {
EXPECT_EQ(expected_max_scroll, root_scroll->MaxScrollOffset());
// The page scale delta should match the new scale on the impl side.
- EXPECT_EQ(page_scale, host_impl_->active_tree()->total_page_scale_factor());
+ EXPECT_EQ(page_scale, host_impl_->active_tree()->current_page_scale_factor());
}
TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) {
@@ -3099,7 +3372,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) {
LayerImpl* grand_child = child->children()[0];
// Set new page scale on impl thread by pinching.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(new_page_scale, gfx::Point());
host_impl_->PinchGestureEnd();
@@ -3119,7 +3392,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) {
// the page scale delta on the root layer is applied hierarchically.
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_EQ(1.f, root->draw_transform().matrix().getDouble(0, 0));
@@ -3138,6 +3411,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) {
gfx::Size surface_size(30, 30);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
root->SetBounds(gfx::Size(5, 5));
+ root->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> root_scrolling =
LayerImpl::Create(host_impl_->active_tree(), 2);
root_scrolling->SetBounds(surface_size);
@@ -3152,7 +3426,8 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) {
LayerImpl* child = child_scrolling.get();
root_scrolling_ptr->AddChild(child_scrolling.Pass());
host_impl_->active_tree()->SetRootLayer(root.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(surface_size);
DrawFrame();
@@ -3160,15 +3435,13 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) {
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta(scroll_delta);
gfx::ScrollOffset expected_max_scroll(child->MaxScrollOffset());
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
float page_scale = 2.f;
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale,
- 1.f,
+ host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f,
page_scale);
DrawOneFrame();
@@ -3193,7 +3466,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) {
gfx::Size content_size(20, 20);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
root->SetBounds(surface_size);
-
+ root->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> grand_child =
CreateScrollableLayer(3, content_size, root.get());
@@ -3207,15 +3480,14 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) {
host_impl_->active_tree()->SetRootLayer(root.Pass());
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(surface_size);
- grand_child_layer->SetScrollOffset(gfx::ScrollOffset(0, 5));
- child_layer->SetScrollOffset(gfx::ScrollOffset(3, 0));
+ grand_child_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 5));
+ child_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(3, 0));
DrawFrame();
{
gfx::Vector2d scroll_delta(-8, -7);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3238,6 +3510,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
gfx::Size surface_size(20, 20);
gfx::Size viewport_size(10, 10);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
+ root->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> root_scrolling =
CreateScrollableLayer(2, surface_size, root.get());
root_scrolling->SetIsContainerForFixedPositionLayers(true);
@@ -3255,19 +3528,20 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
root->AddChild(root_scrolling.Pass());
EXPECT_EQ(viewport_size, root->bounds());
host_impl_->active_tree()->SetRootLayer(root.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(viewport_size);
- grand_child_layer->SetScrollOffset(gfx::ScrollOffset(0, 2));
- child_layer->SetScrollOffset(gfx::ScrollOffset(0, 3));
+ grand_child_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 2));
+ child_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 3));
DrawFrame();
{
gfx::Vector2d scroll_delta(0, -10);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3285,9 +3559,9 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
// The next time we scroll we should only scroll the parent.
scroll_delta = gfx::Vector2d(0, -3);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
@@ -3304,9 +3578,9 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
// After scrolling the parent, another scroll on the opposite direction
// should still scroll the child.
scroll_delta = gfx::Vector2d(0, 7);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
@@ -3322,13 +3596,13 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
// Scrolling should be adjusted from viewport space.
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 2.f, 2.f);
- host_impl_->active_tree()->SetPageScaleDelta(1.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 2.f, 2.f);
+ host_impl_->SetPageScaleOnActiveTree(2.f);
scroll_delta = gfx::Vector2d(0, -2);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(1, 1),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(grand_child, host_impl_->CurrentlyScrollingLayer());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3346,6 +3620,7 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) {
gfx::Size content_size(20, 20);
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 3);
+ root_clip->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> root =
CreateScrollableLayer(1, content_size, root_clip.get());
// Make 'root' the clip layer for child: since they have the same sizes the
@@ -3361,14 +3636,14 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) {
host_impl_->SetViewportSize(surface_size);
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(3, 2, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 2,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
gfx::Vector2d scroll_delta(0, 4);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3388,9 +3663,11 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
scoped_ptr<LayerImpl> root_scroll =
CreateScrollableLayer(2, surface_size, root_clip.get());
root_scroll->SetIsContainerForFixedPositionLayers(true);
+ root_clip->SetHasRenderSurface(true);
root_clip->AddChild(root_scroll.Pass());
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 2,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(surface_size);
@@ -3404,14 +3681,15 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
CreateScrollableLayer(4, surface_size, root_clip2.get());
root_scroll2->SetIsContainerForFixedPositionLayers(true);
root_clip2->AddChild(root_scroll2.Pass());
+ root_clip2->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root_clip2.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(3, 4, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 4,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
// Scrolling should still work even though we did not draw yet.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) {
@@ -3428,24 +3706,21 @@ TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) {
// Scroll to the right in screen coordinates with a gesture.
gfx::Vector2d gesture_scroll_delta(10, 0);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
host_impl_->ScrollEnd();
// The layer should have scrolled down in its local coordinates.
scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
- ExpectContains(*scroll_info.get(),
- scroll_layer->id(),
+ ExpectContains(*scroll_info.get(), scroll_layer->id(),
gfx::Vector2d(0, gesture_scroll_delta.x()));
// Reset and scroll down with the wheel.
scroll_layer->SetScrollDelta(gfx::Vector2dF());
gfx::Vector2d wheel_scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
host_impl_->ScrollEnd();
@@ -3491,18 +3766,16 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) {
{
// Scroll down in screen coordinates with a gesture.
gfx::Vector2d gesture_scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(1, 1),
- InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(1, 1), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
host_impl_->ScrollEnd();
// The child layer should have scrolled down in its local coordinates an
// amount proportional to the angle between it and the input scroll delta.
gfx::Vector2d expected_scroll_delta(
- 0,
- gesture_scroll_delta.y() *
- std::cos(MathUtil::Deg2Rad(child_layer_angle)));
+ 0, gesture_scroll_delta.y() *
+ std::cos(MathUtil::Deg2Rad(child_layer_angle)));
scoped_ptr<ScrollAndScaleSet> scroll_info =
host_impl_->ProcessScrollDeltas();
ExpectContains(*scroll_info.get(), child_layer_id, expected_scroll_delta);
@@ -3515,18 +3788,16 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) {
// Now reset and scroll the same amount horizontally.
child_ptr->SetScrollDelta(gfx::Vector2dF());
gfx::Vector2d gesture_scroll_delta(10, 0);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(1, 1),
- InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(1, 1), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
host_impl_->ScrollEnd();
// The child layer should have scrolled down in its local coordinates an
// amount proportional to the angle between it and the input scroll delta.
gfx::Vector2d expected_scroll_delta(
- 0,
- -gesture_scroll_delta.x() *
- std::sin(MathUtil::Deg2Rad(child_layer_angle)));
+ 0, -gesture_scroll_delta.x() *
+ std::sin(MathUtil::Deg2Rad(child_layer_angle)));
scoped_ptr<ScrollAndScaleSet> scroll_info =
host_impl_->ProcessScrollDeltas();
ExpectContains(*scroll_info.get(), child_layer_id, expected_scroll_delta);
@@ -3559,8 +3830,8 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) {
// Scroll down in screen coordinates with a gesture.
gfx::Vector2d scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3574,12 +3845,12 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) {
// Reset and scroll down with the wheel.
scroll_layer->SetScrollDelta(gfx::Vector2dF());
gfx::Vector2d wheel_scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
host_impl_->ScrollEnd();
- // The scale should not have been applied to the scroll delta.
+ // It should apply the scale factor to the scroll delta for the wheel event.
scroll_info = host_impl_->ProcessScrollDeltas();
ExpectContains(*scroll_info.get(),
scroll_layer->id(),
@@ -3594,7 +3865,7 @@ TEST_F(LayerTreeHostImplTest, ScrollViewportRounding) {
host_impl_->active_tree()->InnerViewportContainerLayer()->SetBounds(
gfx::Size(width * scale - 1, height * scale));
host_impl_->SetDeviceScaleFactor(scale);
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f);
LayerImpl* inner_viewport_scroll_layer =
host_impl_->active_tree()->InnerViewportScrollLayer();
@@ -3631,6 +3902,8 @@ class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate {
page_scale_factor_ = page_scale_factor;
min_page_scale_factor_ = min_page_scale_factor;
max_page_scale_factor_ = max_page_scale_factor;
+
+ set_getter_return_value(last_set_scroll_offset_);
}
gfx::ScrollOffset last_set_scroll_offset() {
@@ -3680,7 +3953,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
// Setting the delegate results in the current scroll offset being set.
gfx::Vector2dF initial_scroll_delta(10.f, 10.f);
- scroll_layer->SetScrollOffset(gfx::ScrollOffset());
+ scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset());
scroll_layer->SetScrollDelta(initial_scroll_delta);
host_impl_->SetRootLayerScrollOffsetDelegate(&scroll_delegate);
EXPECT_EQ(initial_scroll_delta.ToString(),
@@ -3695,16 +3968,16 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
EXPECT_EQ(0.f, scroll_delegate.max_page_scale_factor());
// Updating page scale immediately updates the delegate.
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 0.5f, 4.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 0.5f, 4.f);
EXPECT_EQ(2.f, scroll_delegate.page_scale_factor());
EXPECT_EQ(0.5f, scroll_delegate.min_page_scale_factor());
EXPECT_EQ(4.f, scroll_delegate.max_page_scale_factor());
- host_impl_->active_tree()->SetPageScaleDelta(1.5f);
+ host_impl_->SetPageScaleOnActiveTree(2.f * 1.5f);
EXPECT_EQ(3.f, scroll_delegate.page_scale_factor());
EXPECT_EQ(0.5f, scroll_delegate.min_page_scale_factor());
EXPECT_EQ(4.f, scroll_delegate.max_page_scale_factor());
- host_impl_->active_tree()->SetPageScaleDelta(1.f);
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
+ host_impl_->SetPageScaleOnActiveTree(2.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f);
EXPECT_EQ(1.f, scroll_delegate.page_scale_factor());
EXPECT_EQ(0.5f, scroll_delegate.min_page_scale_factor());
EXPECT_EQ(4.f, scroll_delegate.max_page_scale_factor());
@@ -3712,7 +3985,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
// The pinch gesture doesn't put the delegate into a state where the scroll
// offset is outside of the scroll range. (this is verified by DCHECKs in the
// delegate).
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(2.f, gfx::Point());
host_impl_->PinchGestureUpdate(.5f, gfx::Point());
@@ -3724,8 +3997,9 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
gfx::ScrollOffset current_offset(7.f, 8.f);
scroll_delegate.set_getter_return_value(current_offset);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ host_impl_->OnRootLayerDelegatedScrollOffsetChanged();
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(ScrollOffsetWithDelta(current_offset, scroll_delta),
@@ -3733,11 +4007,13 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
current_offset = gfx::ScrollOffset(42.f, 41.f);
scroll_delegate.set_getter_return_value(current_offset);
+ host_impl_->OnRootLayerDelegatedScrollOffsetChanged();
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(current_offset + gfx::ScrollOffset(scroll_delta),
scroll_delegate.last_set_scroll_offset());
host_impl_->ScrollEnd();
scroll_delegate.set_getter_return_value(gfx::ScrollOffset());
+ host_impl_->OnRootLayerDelegatedScrollOffsetChanged();
// Forces a full tree synchronization and ensures that the scroll delegate
// sees the correct size of the new tree.
@@ -3751,10 +4027,11 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
// the root scrollable layer.
current_offset = gfx::ScrollOffset(13.f, 12.f);
scroll_delegate.set_getter_return_value(current_offset);
+ host_impl_->OnRootLayerDelegatedScrollOffsetChanged();
host_impl_->SetRootLayerScrollOffsetDelegate(NULL);
EXPECT_EQ(current_offset.ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
}
void CheckLayerScrollDelta(LayerImpl* layer, gfx::Vector2dF scroll_delta) {
@@ -3789,7 +4066,7 @@ TEST_F(LayerTreeHostImplTest,
// Check scroll delta reflected in layer.
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_FALSE(frame.has_no_damage);
CheckLayerScrollDelta(scroll_layer, ScrollOffsetToVector2dF(scroll_offset));
@@ -3801,13 +4078,13 @@ TEST_F(LayerTreeHostImplTest, OverscrollRoot) {
InputHandlerScrollResult scroll_result;
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f);
DrawFrame();
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
// In-bounds scrolling does not affect overscroll.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_TRUE(scroll_result.did_scroll);
EXPECT_FALSE(scroll_result.did_overscroll_root);
@@ -3917,6 +4194,8 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
gfx::Size surface_size(10, 10);
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 4);
+ root_clip->SetHasRenderSurface(true);
+
scoped_ptr<LayerImpl> root =
CreateScrollableLayer(1, surface_size, root_clip.get());
@@ -3931,17 +4210,17 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
LayerImpl* child_layer = child.get();
root->AddChild(child.Pass());
root_clip->AddChild(root.Pass());
- child_layer->SetScrollOffset(gfx::ScrollOffset(0, 3));
- grand_child_layer->SetScrollOffset(gfx::ScrollOffset(0, 2));
+ child_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 3));
+ grand_child_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 2));
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(surface_size);
DrawFrame();
{
gfx::Vector2d scroll_delta(0, -10);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollEnd();
@@ -3949,9 +4228,9 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
// The next time we scroll we should only scroll the parent, but overscroll
// should still not reach the root layer.
scroll_delta = gfx::Vector2d(0, -30);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -3962,9 +4241,9 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
// After scrolling the parent, another scroll on the opposite direction
// should scroll the child.
scroll_delta = gfx::Vector2d(0, 70);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
@@ -3981,6 +4260,8 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) {
gfx::Size content_size(20, 20);
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 3);
+ root_clip->SetHasRenderSurface(true);
+
scoped_ptr<LayerImpl> root =
CreateScrollableLayer(1, content_size, root_clip.get());
root->SetIsContainerForFixedPositionLayers(true);
@@ -3993,14 +4274,14 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) {
host_impl_->SetViewportSize(surface_size);
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 1,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
gfx::Vector2d scroll_delta(0, 8);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -4019,13 +4300,13 @@ TEST_F(LayerTreeHostImplTest, OverscrollAlways) {
LayerImpl* clip_layer = scroll_layer->parent()->parent();
clip_layer->SetBounds(gfx::Size(50, 50));
host_impl_->SetViewportSize(gfx::Size(50, 50));
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f);
DrawFrame();
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
// Even though the layer can't scroll the overscroll still happens.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll());
}
@@ -4036,15 +4317,17 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollOnFractionalDeviceScale) {
float device_scale_factor = 1.5f;
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 3);
+ root_clip->SetHasRenderSurface(true);
+
scoped_ptr<LayerImpl> root =
CreateScrollableLayer(1, content_size, root_clip.get());
root->SetIsContainerForFixedPositionLayers(true);
scoped_ptr<LayerImpl> child =
CreateScrollableLayer(2, content_size, root_clip.get());
root->scroll_clip_layer()->SetBounds(gfx::Size(320, 469));
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(
- 0.326531f, 0.326531f, 5.f);
- host_impl_->active_tree()->SetPageScaleDelta(1.f);
+ host_impl_->active_tree()->PushPageScaleFromMainThread(0.326531f, 0.326531f,
+ 5.f);
+ host_impl_->SetPageScaleOnActiveTree(0.326531f);
child->SetScrollClipLayer(Layer::INVALID_ID);
root->AddChild(child.Pass());
root_clip->AddChild(root.Pass());
@@ -4052,15 +4335,16 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollOnFractionalDeviceScale) {
host_impl_->SetViewportSize(surface_size);
host_impl_->SetDeviceScaleFactor(device_scale_factor);
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 1,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
// Horizontal & Vertical GlowEffect should not be applied when
// content size is less then view port size. For Example Horizontal &
// vertical GlowEffect should not be applied in about:blank page.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, -1));
EXPECT_EQ(gfx::Vector2dF().ToString(),
host_impl_->accumulated_root_overscroll().ToString());
@@ -4074,6 +4358,8 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) {
gfx::Size content_size(200, 200);
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 3);
+ root_clip->SetHasRenderSurface(true);
+
scoped_ptr<LayerImpl> root =
CreateScrollableLayer(1, content_size, root_clip.get());
root->SetIsContainerForFixedPositionLayers(true);
@@ -4086,15 +4372,16 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) {
host_impl_->SetViewportSize(surface_size);
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 1,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
// Edge glow effect should be applicable only upon reaching Edges
// of the content. unnecessary glow effect calls shouldn't be
// called while scrolling up without reaching the edge of the content.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 100));
EXPECT_EQ(gfx::Vector2dF().ToString(),
host_impl_->accumulated_root_overscroll().ToString());
@@ -4104,10 +4391,10 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) {
host_impl_->ScrollEnd();
// unusedrootDelta should be subtracted from applied delta so that
// unwanted glow effect calls are not called.
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(0, 0),
- InputHandler::NonBubblingGesture));
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ InputHandler::NON_BUBBLING_GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 20));
EXPECT_EQ(gfx::Vector2dF(0.000000f, 17.699997f).ToString(),
host_impl_->accumulated_root_overscroll().ToString());
@@ -4118,8 +4405,8 @@ TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) {
host_impl_->ScrollEnd();
// TestCase to check kEpsilon, which prevents minute values to trigger
// gloweffect without reaching edge.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(-0.12f, 0.1f));
EXPECT_EQ(gfx::Vector2dF().ToString(),
host_impl_->accumulated_root_overscroll().ToString());
@@ -4137,7 +4424,6 @@ class BlendStateCheckLayer : public LayerImpl {
}
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override {
quads_appended_ = true;
@@ -4161,6 +4447,7 @@ class BlendStateCheckLayer : public LayerImpl {
resource_id_,
gfx::RectF(0.f, 0.f, 1.f, 1.f),
gfx::Size(1, 1),
+ false,
false);
test_blending_draw_quad->visible_rect = quad_visible_rect_;
EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending());
@@ -4194,7 +4481,7 @@ class BlendStateCheckLayer : public LayerImpl {
resource_id_(resource_provider->CreateResource(
gfx::Size(1, 1),
GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
RGBA_8888)) {
resource_provider->AllocateForTesting(resource_id_);
SetBounds(gfx::Size(10, 10));
@@ -4218,6 +4505,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(root->bounds());
root->SetDrawsContent(false);
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
}
LayerImpl* root = host_impl_->active_tree()->root_layer();
@@ -4237,7 +4525,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetExpectation(false, false);
layer1->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4246,7 +4534,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetExpectation(true, false);
layer1->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4256,7 +4544,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetExpectation(true, false);
layer1->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4266,7 +4554,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetExpectation(true, false);
layer1->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4288,7 +4576,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer2->SetExpectation(false, false);
layer2->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4301,7 +4589,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer2->SetExpectation(false, false);
layer2->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4315,7 +4603,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer2->SetExpectation(false, false);
layer2->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4327,6 +4615,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
// carries the inherited opacity).
layer1->SetContentsOpaque(true);
layer1->SetOpacity(0.5f);
+ layer1->SetHasRenderSurface(true);
layer1->SetExpectation(false, true);
layer1->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
layer2->SetExpectation(false, false);
@@ -4334,10 +4623,11 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
FakeLayerTreeHostImpl::RecursiveUpdateNumChildren(
host_impl_->active_tree()->root_layer());
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
host_impl_->DidDrawAllLayers(frame);
+ layer1->SetHasRenderSurface(false);
// Draw again, but with child non-opaque, to make sure
// layer1 not culled.
@@ -4350,7 +4640,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer2->SetExpectation(true, false);
layer2->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4365,7 +4655,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer2->SetExpectation(true, false);
layer2->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4381,7 +4671,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer2->SetExpectation(false, false);
layer2->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4394,7 +4684,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetExpectation(true, false);
layer1->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4406,7 +4696,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetExpectation(true, false);
layer1->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4418,7 +4708,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetExpectation(true, false);
layer1->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -4431,7 +4721,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetExpectation(false, false);
layer1->SetUpdateRect(gfx::Rect(layer1->content_bounds()));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
}
@@ -4454,6 +4744,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
host_impl_->active_tree()->set_background_color(SK_ColorGRAY);
host_impl_->active_tree()->SetRootLayer(
LayerImpl::Create(host_impl_->active_tree(), 1));
+ host_impl_->active_tree()->root_layer()->SetHasRenderSurface(true);
host_impl_->active_tree()->root_layer()->AddChild(
BlendStateCheckLayer::Create(host_impl_->active_tree(),
2,
@@ -4633,49 +4924,6 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredScaled) {
TestLayerIsLargerThanViewport();
}
-TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredOverhangBitmap) {
- viewport_size_ = gfx::Size(1000, 1000);
-
- bool always_draw = false;
- CreateHostImpl(DefaultSettings(), CreateFakeOutputSurface(always_draw));
-
- host_impl_->SetViewportSize(DipSizeToPixelSize(viewport_size_));
- SetupActiveTreeLayers();
-
- // Specify an overhang bitmap to use.
- bool is_opaque = false;
- UIResourceBitmap ui_resource_bitmap(gfx::Size(2, 2), is_opaque);
- ui_resource_bitmap.SetWrapMode(UIResourceBitmap::REPEAT);
- UIResourceId ui_resource_id = 12345;
- host_impl_->CreateUIResource(ui_resource_id, ui_resource_bitmap);
- host_impl_->SetOverhangUIResource(ui_resource_id, gfx::Size(32, 32));
- set_gutter_quad_material(DrawQuad::TEXTURE_CONTENT);
- set_gutter_texture_size(gfx::Size(32, 32));
-
- TestLayerCoversFullViewport();
- TestEmptyLayer();
- TestLayerInMiddleOfViewport();
- TestLayerIsLargerThanViewport();
-
- // Change the resource size.
- host_impl_->SetOverhangUIResource(ui_resource_id, gfx::Size(128, 16));
- set_gutter_texture_size(gfx::Size(128, 16));
-
- TestLayerCoversFullViewport();
- TestEmptyLayer();
- TestLayerInMiddleOfViewport();
- TestLayerIsLargerThanViewport();
-
- // Change the device scale factor
- host_impl_->SetDeviceScaleFactor(2.f);
- host_impl_->SetViewportSize(DipSizeToPixelSize(viewport_size_));
-
- TestLayerCoversFullViewport();
- TestEmptyLayer();
- TestLayerInMiddleOfViewport();
- TestLayerIsLargerThanViewport();
-}
-
TEST_F(LayerTreeHostImplViewportCoveredTest, ActiveTreeGrowViewportInvalid) {
viewport_size_ = gfx::Size(1000, 1000);
@@ -4744,6 +4992,7 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
root->SetDrawsContent(true);
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
EXPECT_FALSE(provider->TestContext3d()->reshape_called());
provider->TestContext3d()->clear_reshape_called();
@@ -4752,7 +5001,7 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
host_impl_->SetViewportSize(gfx::Size(10, 10));
host_impl_->SetDeviceScaleFactor(1.f);
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(provider->TestContext3d()->reshape_called());
EXPECT_EQ(provider->TestContext3d()->width(), 10);
EXPECT_EQ(provider->TestContext3d()->height(), 10);
@@ -4762,7 +5011,7 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
host_impl_->SetViewportSize(gfx::Size(20, 30));
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(provider->TestContext3d()->reshape_called());
EXPECT_EQ(provider->TestContext3d()->width(), 20);
EXPECT_EQ(provider->TestContext3d()->height(), 30);
@@ -4772,7 +5021,7 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
host_impl_->SetDeviceScaleFactor(2.f);
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
EXPECT_TRUE(provider->TestContext3d()->reshape_called());
EXPECT_EQ(provider->TestContext3d()->width(), 20);
EXPECT_EQ(provider->TestContext3d()->height(), 30);
@@ -4796,22 +5045,17 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
// This test creates its own LayerTreeHostImpl, so
// that we can force partial swap enabled.
LayerTreeSettings settings;
- settings.partial_swap_enabled = true;
- scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
- new TestSharedBitmapManager());
+ settings.renderer_settings.partial_swap_enabled = true;
scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl =
- LayerTreeHostImpl::Create(settings,
- this,
- &proxy_,
- &stats_instrumentation_,
- shared_bitmap_manager.get(),
- NULL,
- 0);
+ LayerTreeHostImpl::Create(
+ settings, this, &proxy_, &stats_instrumentation_,
+ shared_bitmap_manager_.get(), NULL, task_graph_runner_.get(), 0);
layer_tree_host_impl->InitializeRenderer(output_surface.Pass());
layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500));
scoped_ptr<LayerImpl> root =
FakeDrawableLayerImpl::Create(layer_tree_host_impl->active_tree(), 1);
+ root->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> child =
FakeDrawableLayerImpl::Create(layer_tree_host_impl->active_tree(), 2);
child->SetPosition(gfx::PointF(12.f, 13.f));
@@ -4828,7 +5072,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
// First frame, the entire screen should get swapped.
EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame));
- layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
+ layer_tree_host_impl->DrawLayers(&frame);
layer_tree_host_impl->DidDrawAllLayers(frame);
layer_tree_host_impl->SwapBuffers(frame);
gfx::Rect expected_swap_rect(0, 0, 500, 500);
@@ -4842,7 +5086,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
layer_tree_host_impl->active_tree()->root_layer()->children()[0]->SetPosition(
gfx::PointF());
EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame));
- layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
+ layer_tree_host_impl->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
layer_tree_host_impl->SwapBuffers(frame);
@@ -4858,7 +5102,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
layer_tree_host_impl->active_tree()->root_layer()->SetBackgroundColor(
SK_ColorBLACK);
EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame));
- layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
+ layer_tree_host_impl->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
layer_tree_host_impl->SwapBuffers(frame);
@@ -4878,7 +5122,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerDoesntCreateExtraSurface) {
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
root->SetDrawsContent(true);
- root->SetForceRenderSurface(true);
+ root->SetHasRenderSurface(true);
root->AddChild(child.Pass());
host_impl_->active_tree()->SetRootLayer(root.Pass());
@@ -4898,7 +5142,6 @@ class FakeLayerWithQuads : public LayerImpl {
}
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override {
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
@@ -5012,7 +5255,7 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) {
// Run test case
LayerTreeSettings settings = DefaultSettings();
- settings.partial_swap_enabled = false;
+ settings.renderer_settings.partial_swap_enabled = false;
CreateHostImpl(settings,
FakeOutputSurface::Create3d(mock_context_owned.Pass()));
SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1));
@@ -5023,7 +5266,7 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) {
{
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
Mock::VerifyAndClearExpectations(&mock_context);
@@ -5036,7 +5279,7 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) {
{
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
Mock::VerifyAndClearExpectations(&mock_context);
@@ -5048,17 +5291,17 @@ TEST_F(LayerTreeHostImplTest, PartialSwap) {
MockContextHarness harness(mock_context);
LayerTreeSettings settings = DefaultSettings();
- settings.partial_swap_enabled = true;
+ settings.renderer_settings.partial_swap_enabled = true;
CreateHostImpl(settings, FakeOutputSurface::Create3d(context_owned.Pass()));
SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1));
- // The first frame is not a partially-swapped one.
- harness.MustSetScissor(0, 0, 10, 10);
+ // The first frame is not a partially-swapped one. No scissor should be set.
+ harness.MustSetNoScissor();
harness.MustDrawSolidQuad();
{
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
Mock::VerifyAndClearExpectations(&mock_context);
@@ -5073,7 +5316,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwap) {
{
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
Mock::VerifyAndClearExpectations(&mock_context);
@@ -5092,9 +5335,9 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
provider->TestContext3d()->set_have_post_sub_buffer(true);
LayerTreeSettings settings;
- settings.partial_swap_enabled = partial_swap;
+ settings.renderer_settings.partial_swap_enabled = partial_swap;
scoped_ptr<LayerTreeHostImpl> my_host_impl = LayerTreeHostImpl::Create(
- settings, client, proxy, stats_instrumentation, manager, NULL, 0);
+ settings, client, proxy, stats_instrumentation, manager, NULL, NULL, 0);
my_host_impl->InitializeRenderer(output_surface.Pass());
my_host_impl->SetViewportSize(gfx::Size(100, 100));
@@ -5127,7 +5370,7 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
gfx::Rect child_rect(10, 10, 50, 50);
gfx::Rect grand_child_rect(5, 5, 150, 150);
- root->CreateRenderSurface();
+ root->SetHasRenderSurface(true);
root->SetPosition(root_rect.origin());
root->SetBounds(root_rect.size());
root->SetContentBounds(root->bounds());
@@ -5141,7 +5384,7 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
child->SetContentBounds(child->bounds());
child->draw_properties().visible_content_rect = child_rect;
child->SetDrawsContent(false);
- child->SetForceRenderSurface(true);
+ child->SetHasRenderSurface(true);
grand_child->SetPosition(grand_child_rect.origin());
grand_child->SetBounds(grand_child_rect.size());
@@ -5178,7 +5421,7 @@ TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorPartialSwap) {
EXPECT_EQ(DrawQuad::RENDER_PASS,
frame.render_passes[1]->quad_list.front()->material);
- my_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
+ my_host_impl->DrawLayers(&frame);
my_host_impl->DidDrawAllLayers(frame);
}
}
@@ -5205,7 +5448,7 @@ TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorNoPartialSwap) {
EXPECT_EQ(DrawQuad::RENDER_PASS,
frame.render_passes[1]->quad_list.front()->material);
- my_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
+ my_host_impl->DrawLayers(&frame);
my_host_impl->DidDrawAllLayers(frame);
}
}
@@ -5221,6 +5464,7 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
scoped_ptr<LayerImpl> root_layer =
LayerImpl::Create(host_impl_->active_tree(), 1);
root_layer->SetBounds(gfx::Size(10, 10));
+ root_layer->SetHasRenderSurface(true);
scoped_refptr<VideoFrame> softwareFrame =
media::VideoFrame::CreateColorFrame(
@@ -5248,7 +5492,7 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
host_impl_->SwapBuffers(frame);
@@ -5277,7 +5521,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) {
// Run test case
LayerTreeSettings settings = DefaultSettings();
- settings.partial_swap_enabled = false;
+ settings.renderer_settings.partial_swap_enabled = false;
CreateHostImpl(settings,
FakeOutputSurface::Create3d(mock_context_owned.Pass()));
SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1));
@@ -5291,7 +5535,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) {
.Times(1);
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
Mock::VerifyAndClearExpectations(&mock_context);
@@ -5299,7 +5543,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) {
host_impl_->active_tree()->set_has_transparent_background(true);
host_impl_->SetFullRootLayerDamage();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
Mock::VerifyAndClearExpectations(&mock_context);
}
@@ -5365,7 +5609,7 @@ class LayerTreeHostImplTestWithDelegatingRenderer
// Verify the damage rect for the root render pass.
const RenderPass* root_render_pass = frame.render_passes.back();
- EXPECT_RECT_EQ(expected_damage, root_render_pass->damage_rect);
+ EXPECT_EQ(expected_damage, root_render_pass->damage_rect);
// Verify the root and child layers' quads are generated and not being
// culled.
@@ -5373,16 +5617,16 @@ class LayerTreeHostImplTestWithDelegatingRenderer
LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
gfx::RectF expected_child_visible_rect(child->content_bounds());
- EXPECT_RECT_EQ(expected_child_visible_rect,
- root_render_pass->quad_list.front()->visible_rect);
+ EXPECT_EQ(expected_child_visible_rect,
+ root_render_pass->quad_list.front()->visible_rect);
LayerImpl* root = host_impl_->active_tree()->root_layer();
gfx::RectF expected_root_visible_rect(root->content_bounds());
- EXPECT_RECT_EQ(expected_root_visible_rect,
- root_render_pass->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(expected_root_visible_rect,
+ root_render_pass->quad_list.ElementAt(1)->visible_rect);
}
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_EQ(expect_to_draw, host_impl_->SwapBuffers(frame));
}
@@ -5395,6 +5639,7 @@ TEST_F(LayerTreeHostImplTestWithDelegatingRenderer, FrameIncludesDamageRect) {
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
root->SetDrawsContent(true);
+ root->SetHasRenderSurface(true);
// Child layer is in the bottom right corner.
scoped_ptr<SolidColorLayerImpl> child =
@@ -5447,677 +5692,6 @@ class FakeMaskLayerImpl : public LayerImpl {
: LayerImpl(tree_impl, id) {}
};
-TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) {
- LayerTreeSettings settings;
- settings.layer_transforms_should_scale_layer_contents = true;
- CreateHostImpl(settings, CreateOutputSurface());
-
- // Root
- // |
- // +-- Scaling Layer (adds a 2x scale)
- // |
- // +-- Content Layer
- // +--Mask
- scoped_ptr<LayerImpl> scoped_root =
- LayerImpl::Create(host_impl_->active_tree(), 1);
- LayerImpl* root = scoped_root.get();
- host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
-
- scoped_ptr<LayerImpl> scoped_scaling_layer =
- LayerImpl::Create(host_impl_->active_tree(), 2);
- LayerImpl* scaling_layer = scoped_scaling_layer.get();
- root->AddChild(scoped_scaling_layer.Pass());
-
- scoped_ptr<LayerImpl> scoped_content_layer =
- LayerImpl::Create(host_impl_->active_tree(), 3);
- LayerImpl* content_layer = scoped_content_layer.get();
- scaling_layer->AddChild(scoped_content_layer.Pass());
-
- scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
- FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4);
- FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
- content_layer->SetMaskLayer(scoped_mask_layer.Pass());
-
- gfx::Size root_size(100, 100);
- root->SetBounds(root_size);
- root->SetContentBounds(root_size);
- root->SetPosition(gfx::PointF());
-
- gfx::Size scaling_layer_size(50, 50);
- scaling_layer->SetBounds(scaling_layer_size);
- scaling_layer->SetContentBounds(scaling_layer_size);
- scaling_layer->SetPosition(gfx::PointF());
- gfx::Transform scale;
- scale.Scale(2.f, 2.f);
- scaling_layer->SetTransform(scale);
-
- content_layer->SetBounds(scaling_layer_size);
- content_layer->SetContentBounds(scaling_layer_size);
- content_layer->SetPosition(gfx::PointF());
- content_layer->SetDrawsContent(true);
-
- mask_layer->SetBounds(scaling_layer_size);
- mask_layer->SetContentBounds(scaling_layer_size);
- mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetDrawsContent(true);
-
-
- // Check that the tree scaling is correctly taken into account for the mask,
- // that should fully map onto the quad.
- float device_scale_factor = 1.f;
- host_impl_->SetViewportSize(root_size);
- host_impl_->SetDeviceScaleFactor(device_scale_factor);
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- render_pass_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- render_pass_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- render_pass_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-
-
- // Applying a DSF should change the render surface size, but won't affect
- // which part of the mask is used.
- device_scale_factor = 2.f;
- gfx::Size device_viewport =
- gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor));
- host_impl_->SetViewportSize(device_viewport);
- host_impl_->SetDeviceScaleFactor(device_scale_factor);
- host_impl_->active_tree()->set_needs_update_draw_properties();
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
- render_pass_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- render_pass_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- render_pass_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-
-
- // Applying an equivalent content scale on the content layer and the mask
- // should still result in the same part of the mask being used.
- gfx::Size content_bounds =
- gfx::ToRoundedSize(gfx::ScaleSize(scaling_layer_size,
- device_scale_factor));
- content_layer->SetContentBounds(content_bounds);
- content_layer->SetContentsScale(device_scale_factor, device_scale_factor);
- mask_layer->SetContentBounds(content_bounds);
- mask_layer->SetContentsScale(device_scale_factor, device_scale_factor);
- host_impl_->active_tree()->set_needs_update_draw_properties();
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
- render_pass_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- render_pass_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- render_pass_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-}
-
-TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) {
- // The mask layer has bounds 100x100 but is attached to a layer with bounds
- // 50x50.
-
- scoped_ptr<LayerImpl> scoped_root =
- LayerImpl::Create(host_impl_->active_tree(), 1);
- LayerImpl* root = scoped_root.get();
- host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
-
- scoped_ptr<LayerImpl> scoped_content_layer =
- LayerImpl::Create(host_impl_->active_tree(), 3);
- LayerImpl* content_layer = scoped_content_layer.get();
- root->AddChild(scoped_content_layer.Pass());
-
- scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
- FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4);
- FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
- content_layer->SetMaskLayer(scoped_mask_layer.Pass());
-
- gfx::Size root_size(100, 100);
- root->SetBounds(root_size);
- root->SetContentBounds(root_size);
- root->SetPosition(gfx::PointF());
-
- gfx::Size layer_size(50, 50);
- content_layer->SetBounds(layer_size);
- content_layer->SetContentBounds(layer_size);
- content_layer->SetPosition(gfx::PointF());
- content_layer->SetDrawsContent(true);
-
- gfx::Size mask_size(100, 100);
- mask_layer->SetBounds(mask_size);
- mask_layer->SetContentBounds(mask_size);
- mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetDrawsContent(true);
-
- // Check that the mask fills the surface.
- float device_scale_factor = 1.f;
- host_impl_->SetViewportSize(root_size);
- host_impl_->SetDeviceScaleFactor(device_scale_factor);
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
- render_pass_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- render_pass_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- render_pass_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-
- // Applying a DSF should change the render surface size, but won't affect
- // which part of the mask is used.
- device_scale_factor = 2.f;
- gfx::Size device_viewport =
- gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor));
- host_impl_->SetViewportSize(device_viewport);
- host_impl_->SetDeviceScaleFactor(device_scale_factor);
- host_impl_->active_tree()->set_needs_update_draw_properties();
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- render_pass_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- render_pass_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- render_pass_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-
- // Applying an equivalent content scale on the content layer and the mask
- // should still result in the same part of the mask being used.
- gfx::Size layer_size_large =
- gfx::ToRoundedSize(gfx::ScaleSize(layer_size, device_scale_factor));
- content_layer->SetContentBounds(layer_size_large);
- content_layer->SetContentsScale(device_scale_factor, device_scale_factor);
- gfx::Size mask_size_large =
- gfx::ToRoundedSize(gfx::ScaleSize(mask_size, device_scale_factor));
- mask_layer->SetContentBounds(mask_size_large);
- mask_layer->SetContentsScale(device_scale_factor, device_scale_factor);
- host_impl_->active_tree()->set_needs_update_draw_properties();
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- render_pass_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- render_pass_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- render_pass_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-
- // Applying a different contents scale to the mask layer means it will have
- // a larger texture, but it should use the same tex coords to cover the
- // layer it masks.
- mask_layer->SetContentBounds(mask_size);
- mask_layer->SetContentsScale(1.f, 1.f);
- host_impl_->active_tree()->set_needs_update_draw_properties();
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- render_pass_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- render_pass_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- render_pass_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-}
-
-TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) {
- // The replica's mask layer has bounds 100x100 but the replica is of a
- // layer with bounds 50x50.
-
- scoped_ptr<LayerImpl> scoped_root =
- LayerImpl::Create(host_impl_->active_tree(), 1);
- LayerImpl* root = scoped_root.get();
- host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
-
- scoped_ptr<LayerImpl> scoped_content_layer =
- LayerImpl::Create(host_impl_->active_tree(), 3);
- LayerImpl* content_layer = scoped_content_layer.get();
- root->AddChild(scoped_content_layer.Pass());
-
- scoped_ptr<LayerImpl> scoped_replica_layer =
- LayerImpl::Create(host_impl_->active_tree(), 2);
- LayerImpl* replica_layer = scoped_replica_layer.get();
- content_layer->SetReplicaLayer(scoped_replica_layer.Pass());
-
- scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
- FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4);
- FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
- replica_layer->SetMaskLayer(scoped_mask_layer.Pass());
-
- gfx::Size root_size(100, 100);
- root->SetBounds(root_size);
- root->SetContentBounds(root_size);
- root->SetPosition(gfx::PointF());
-
- gfx::Size layer_size(50, 50);
- content_layer->SetBounds(layer_size);
- content_layer->SetContentBounds(layer_size);
- content_layer->SetPosition(gfx::PointF());
- content_layer->SetDrawsContent(true);
-
- gfx::Size mask_size(100, 100);
- mask_layer->SetBounds(mask_size);
- mask_layer->SetContentBounds(mask_size);
- mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetDrawsContent(true);
-
- // Check that the mask fills the surface.
- float device_scale_factor = 1.f;
- host_impl_->SetViewportSize(root_size);
- host_impl_->SetDeviceScaleFactor(device_scale_factor);
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.ElementAt(1)->material);
- const RenderPassDrawQuad* replica_quad = RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.ElementAt(1));
- EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
- replica_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- replica_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- replica_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-
- // Applying a DSF should change the render surface size, but won't affect
- // which part of the mask is used.
- device_scale_factor = 2.f;
- gfx::Size device_viewport =
- gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor));
- host_impl_->SetViewportSize(device_viewport);
- host_impl_->SetDeviceScaleFactor(device_scale_factor);
- host_impl_->active_tree()->set_needs_update_draw_properties();
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.ElementAt(1)->material);
- const RenderPassDrawQuad* replica_quad = RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.ElementAt(1));
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- replica_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- replica_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- replica_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-
- // Applying an equivalent content scale on the content layer and the mask
- // should still result in the same part of the mask being used.
- gfx::Size layer_size_large =
- gfx::ToRoundedSize(gfx::ScaleSize(layer_size, device_scale_factor));
- content_layer->SetContentBounds(layer_size_large);
- content_layer->SetContentsScale(device_scale_factor, device_scale_factor);
- gfx::Size mask_size_large =
- gfx::ToRoundedSize(gfx::ScaleSize(mask_size, device_scale_factor));
- mask_layer->SetContentBounds(mask_size_large);
- mask_layer->SetContentsScale(device_scale_factor, device_scale_factor);
- host_impl_->active_tree()->set_needs_update_draw_properties();
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.ElementAt(1)->material);
- const RenderPassDrawQuad* replica_quad = RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.ElementAt(1));
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- replica_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- replica_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- replica_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-
- // Applying a different contents scale to the mask layer means it will have
- // a larger texture, but it should use the same tex coords to cover the
- // layer it masks.
- mask_layer->SetContentBounds(mask_size);
- mask_layer->SetContentsScale(1.f, 1.f);
- host_impl_->active_tree()->set_needs_update_draw_properties();
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.ElementAt(1)->material);
- const RenderPassDrawQuad* replica_quad = RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.ElementAt(1));
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- replica_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
- replica_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
- replica_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-}
-
-TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerForSurfaceWithUnclippedChild) {
- // The replica is of a layer with bounds 50x50, but it has a child that causes
- // the surface bounds to be larger.
-
- scoped_ptr<LayerImpl> scoped_root =
- LayerImpl::Create(host_impl_->active_tree(), 1);
- LayerImpl* root = scoped_root.get();
- host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
-
- scoped_ptr<LayerImpl> scoped_content_layer =
- LayerImpl::Create(host_impl_->active_tree(), 2);
- LayerImpl* content_layer = scoped_content_layer.get();
- root->AddChild(scoped_content_layer.Pass());
-
- scoped_ptr<LayerImpl> scoped_content_child_layer =
- LayerImpl::Create(host_impl_->active_tree(), 3);
- LayerImpl* content_child_layer = scoped_content_child_layer.get();
- content_layer->AddChild(scoped_content_child_layer.Pass());
-
- scoped_ptr<LayerImpl> scoped_replica_layer =
- LayerImpl::Create(host_impl_->active_tree(), 4);
- LayerImpl* replica_layer = scoped_replica_layer.get();
- content_layer->SetReplicaLayer(scoped_replica_layer.Pass());
-
- scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
- FakeMaskLayerImpl::Create(host_impl_->active_tree(), 5);
- FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
- replica_layer->SetMaskLayer(scoped_mask_layer.Pass());
-
- gfx::Size root_size(100, 100);
- root->SetBounds(root_size);
- root->SetContentBounds(root_size);
- root->SetPosition(gfx::PointF());
-
- gfx::Size layer_size(50, 50);
- content_layer->SetBounds(layer_size);
- content_layer->SetContentBounds(layer_size);
- content_layer->SetPosition(gfx::PointF());
- content_layer->SetDrawsContent(true);
-
- gfx::Size child_size(50, 50);
- content_child_layer->SetBounds(child_size);
- content_child_layer->SetContentBounds(child_size);
- content_child_layer->SetPosition(gfx::Point(50, 0));
- content_child_layer->SetDrawsContent(true);
-
- gfx::Size mask_size(50, 50);
- mask_layer->SetBounds(mask_size);
- mask_layer->SetContentBounds(mask_size);
- mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetDrawsContent(true);
-
- float device_scale_factor = 1.f;
- host_impl_->SetViewportSize(root_size);
- host_impl_->SetDeviceScaleFactor(device_scale_factor);
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
-
- // The surface is 100x50.
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(0, 0, 100, 50).ToString(),
- render_pass_quad->rect.ToString());
-
- // The mask covers the owning layer only.
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.ElementAt(1)->material);
- const RenderPassDrawQuad* replica_quad = RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.ElementAt(1));
- EXPECT_EQ(gfx::Rect(0, 0, 100, 50).ToString(),
- replica_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 2.f, 1.f).ToString(),
- replica_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(2.f, 1.f).ToString(),
- replica_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-
- // Move the child to (-50, 0) instead. Now the mask should be moved to still
- // cover the layer being replicated.
- content_child_layer->SetPosition(gfx::Point(-50, 0));
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
-
- // The surface is 100x50 with its origin at (-50, 0).
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(-50, 0, 100, 50).ToString(),
- render_pass_quad->rect.ToString());
-
- // The mask covers the owning layer only.
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.ElementAt(1)->material);
- const RenderPassDrawQuad* replica_quad = RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.ElementAt(1));
- EXPECT_EQ(gfx::Rect(-50, 0, 100, 50).ToString(),
- replica_quad->rect.ToString());
- EXPECT_EQ(gfx::RectF(-1.f, 0.f, 2.f, 1.f).ToString(),
- replica_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(2.f, 1.f).ToString(),
- replica_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-}
-
-TEST_F(LayerTreeHostImplTest, MaskLayerForSurfaceWithClippedLayer) {
- // The masked layer has bounds 50x50, but it has a child that causes
- // the surface bounds to be larger. It also has a parent that clips the
- // masked layer and its surface.
-
- scoped_ptr<LayerImpl> scoped_root =
- LayerImpl::Create(host_impl_->active_tree(), 1);
- LayerImpl* root = scoped_root.get();
- host_impl_->active_tree()->SetRootLayer(scoped_root.Pass());
-
- scoped_ptr<LayerImpl> scoped_clipping_layer =
- LayerImpl::Create(host_impl_->active_tree(), 2);
- LayerImpl* clipping_layer = scoped_clipping_layer.get();
- root->AddChild(scoped_clipping_layer.Pass());
-
- scoped_ptr<LayerImpl> scoped_content_layer =
- LayerImpl::Create(host_impl_->active_tree(), 3);
- LayerImpl* content_layer = scoped_content_layer.get();
- clipping_layer->AddChild(scoped_content_layer.Pass());
-
- scoped_ptr<LayerImpl> scoped_content_child_layer =
- LayerImpl::Create(host_impl_->active_tree(), 4);
- LayerImpl* content_child_layer = scoped_content_child_layer.get();
- content_layer->AddChild(scoped_content_child_layer.Pass());
-
- scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer =
- FakeMaskLayerImpl::Create(host_impl_->active_tree(), 6);
- FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get();
- content_layer->SetMaskLayer(scoped_mask_layer.Pass());
-
- gfx::Size root_size(100, 100);
- root->SetBounds(root_size);
- root->SetContentBounds(root_size);
- root->SetPosition(gfx::PointF());
-
- gfx::Rect clipping_rect(20, 10, 10, 20);
- clipping_layer->SetBounds(clipping_rect.size());
- clipping_layer->SetContentBounds(clipping_rect.size());
- clipping_layer->SetPosition(clipping_rect.origin());
- clipping_layer->SetMasksToBounds(true);
-
- gfx::Size layer_size(50, 50);
- content_layer->SetBounds(layer_size);
- content_layer->SetContentBounds(layer_size);
- content_layer->SetPosition(gfx::Point() - clipping_rect.OffsetFromOrigin());
- content_layer->SetDrawsContent(true);
-
- gfx::Size child_size(50, 50);
- content_child_layer->SetBounds(child_size);
- content_child_layer->SetContentBounds(child_size);
- content_child_layer->SetPosition(gfx::Point(50, 0));
- content_child_layer->SetDrawsContent(true);
-
- gfx::Size mask_size(100, 100);
- mask_layer->SetBounds(mask_size);
- mask_layer->SetContentBounds(mask_size);
- mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetDrawsContent(true);
-
- float device_scale_factor = 1.f;
- host_impl_->SetViewportSize(root_size);
- host_impl_->SetDeviceScaleFactor(device_scale_factor);
- {
- LayerTreeHostImpl::FrameData frame;
- EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-
- ASSERT_EQ(1u, frame.render_passes.size());
- ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
-
- // The surface is clipped to 10x20.
- ASSERT_EQ(DrawQuad::RENDER_PASS,
- frame.render_passes[0]->quad_list.front()->material);
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(
- frame.render_passes[0]->quad_list.front());
- EXPECT_EQ(gfx::Rect(20, 10, 10, 20).ToString(),
- render_pass_quad->rect.ToString());
- // The masked layer is 50x50, but the surface size is 10x20. So the texture
- // coords in the mask are scaled by 10/50 and 20/50.
- // The surface is clipped to (20,10) so the mask texture coords are offset
- // by 20/50 and 10/50
- EXPECT_EQ(gfx::ScaleRect(gfx::RectF(20.f, 10.f, 10.f, 20.f), 1.f / 50.f)
- .ToString(),
- render_pass_quad->MaskUVRect().ToString());
- EXPECT_EQ(gfx::Vector2dF(10.f / 50.f, 20.f / 50.f).ToString(),
- render_pass_quad->mask_uv_scale.ToString());
-
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
- host_impl_->DidDrawAllLayers(frame);
- }
-}
-
class GLRendererWithSetupQuadForAntialiasing : public GLRenderer {
public:
using GLRenderer::ShouldAntialiasQuad;
@@ -6134,12 +5708,13 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) {
host_impl_->SetViewportSize(device_viewport_size);
host_impl_->CreatePendingTree();
- host_impl_->pending_tree()
- ->SetPageScaleFactorAndLimits(1.f, 1.f / 16.f, 16.f);
+ host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f / 16.f,
+ 16.f);
scoped_ptr<LayerImpl> scoped_root =
LayerImpl::Create(host_impl_->pending_tree(), 1);
LayerImpl* root = scoped_root.get();
+ root->SetHasRenderSurface(true);
host_impl_->pending_tree()->SetRootLayer(scoped_root.Pass());
@@ -6154,7 +5729,8 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) {
pile_tile_size, content_layer_bounds));
scoped_ptr<FakePictureLayerImpl> scoped_content_layer =
- FakePictureLayerImpl::CreateWithPile(host_impl_->pending_tree(), 3, pile);
+ FakePictureLayerImpl::CreateWithRasterSource(host_impl_->pending_tree(),
+ 3, pile);
LayerImpl* content_layer = scoped_content_layer.get();
scrolling_layer->AddChild(scoped_content_layer.Pass());
content_layer->SetBounds(content_layer_bounds);
@@ -6164,11 +5740,12 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) {
gfx::ScrollOffset scroll_offset(100000, 0);
scrolling_layer->SetScrollClipLayer(root->id());
- scrolling_layer->SetScrollOffset(scroll_offset);
+ scrolling_layer->PushScrollOffsetFromMainThread(scroll_offset);
host_impl_->ActivateSyncTree();
- host_impl_->active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_->active_tree()->UpdateDrawProperties(update_lcd_text);
ASSERT_EQ(1u, host_impl_->active_tree()->RenderSurfaceLayerList().size());
LayerTreeHostImpl::FrameData frame;
@@ -6183,7 +5760,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) {
quad->quadTransform(), quad, false);
EXPECT_FALSE(antialiased);
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
@@ -6205,7 +5782,7 @@ TEST_F(CompositorFrameMetadataTest, CompositorFrameAckCountsAsSwapComplete) {
{
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, base::TimeTicks());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
}
CompositorFrameAck ack;
@@ -6234,13 +5811,9 @@ TEST_F(LayerTreeHostImplTest, ForcedDrawToSoftwareDeviceBasicRender) {
// No main thread evictions in resourceless software mode.
set_reduce_memory_result(false);
CountingSoftwareDevice* software_device = new CountingSoftwareDevice();
- bool delegated_rendering = false;
- FakeOutputSurface* output_surface =
- FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(software_device),
- delegated_rendering).release();
- EXPECT_TRUE(CreateHostImpl(DefaultSettings(),
- scoped_ptr<OutputSurface>(output_surface)));
+ EXPECT_TRUE(CreateHostImpl(
+ DefaultSettings(),
+ FakeOutputSurface::CreateSoftware(make_scoped_ptr(software_device))));
host_impl_->SetViewportSize(gfx::Size(50, 50));
SetupScrollAndContentsLayers(gfx::Size(100, 100));
@@ -6264,21 +5837,18 @@ TEST_F(LayerTreeHostImplTest, ForcedDrawToSoftwareDeviceBasicRender) {
EXPECT_EQ(1, software_device->frames_began_);
EXPECT_EQ(1, software_device->frames_ended_);
- // Call other API methods that are likely to hit NULL pointer in this mode.
- EXPECT_TRUE(host_impl_->AsValue().get());
- EXPECT_TRUE(host_impl_->ActivationStateAsValue().get());
+ // Call another API method that is likely to hit nullptr in this mode.
+ scoped_refptr<base::trace_event::TracedValue> state =
+ make_scoped_refptr(new base::trace_event::TracedValue());
+ host_impl_->ActivationStateAsValueInto(state.get());
}
TEST_F(LayerTreeHostImplTest,
ForcedDrawToSoftwareDeviceSkipsUnsupportedLayers) {
set_reduce_memory_result(false);
- bool delegated_rendering = false;
- FakeOutputSurface* output_surface =
- FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new CountingSoftwareDevice()),
- delegated_rendering).release();
EXPECT_TRUE(CreateHostImpl(DefaultSettings(),
- scoped_ptr<OutputSurface>(output_surface)));
+ FakeOutputSurface::CreateSoftware(
+ make_scoped_ptr(new CountingSoftwareDevice))));
const gfx::Transform external_transform;
const gfx::Rect external_viewport;
@@ -6307,105 +5877,21 @@ TEST_F(LayerTreeHostImplTest,
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_EQ(1u, frame.will_draw_layers.size());
EXPECT_EQ(host_impl_->active_tree()->root_layer(), frame.will_draw_layers[0]);
}
-class LayerTreeHostImplTestDeferredInitialize : public LayerTreeHostImplTest {
- protected:
- virtual void SetUp() override {
- LayerTreeHostImplTest::SetUp();
-
- set_reduce_memory_result(false);
-
- bool delegated_rendering = false;
- scoped_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new CountingSoftwareDevice()),
- delegated_rendering));
- output_surface_ = output_surface.get();
-
- EXPECT_TRUE(CreateHostImpl(DefaultSettings(), output_surface.Pass()));
-
- scoped_ptr<SolidColorLayerImpl> root_layer =
- SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
- SetupRootLayerImpl(root_layer.Pass());
-
- onscreen_context_provider_ = TestContextProvider::Create();
- }
-
- void UpdateRendererCapabilitiesOnImplThread() override {
- did_update_renderer_capabilities_ = true;
- }
-
- FakeOutputSurface* output_surface_;
- scoped_refptr<TestContextProvider> onscreen_context_provider_;
- bool did_update_renderer_capabilities_;
-};
-
-
-TEST_F(LayerTreeHostImplTestDeferredInitialize, Success) {
- // Software draw.
- DrawFrame();
-
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
-
- // DeferredInitialize and hardware draw.
- did_update_renderer_capabilities_ = false;
- EXPECT_TRUE(
- output_surface_->InitializeAndSetContext3d(onscreen_context_provider_));
- EXPECT_EQ(onscreen_context_provider_.get(),
- host_impl_->output_surface()->context_provider());
- EXPECT_TRUE(did_update_renderer_capabilities_);
-
- // Defer intialized GL draw.
- DrawFrame();
-
- // Revert back to software.
- did_update_renderer_capabilities_ = false;
- output_surface_->ReleaseGL();
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_TRUE(did_update_renderer_capabilities_);
-
- // Software draw again.
- DrawFrame();
-}
-
-TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails) {
- // Software draw.
- DrawFrame();
-
- // Fail initialization of the onscreen context before the OutputSurface binds
- // it to the thread.
- onscreen_context_provider_->UnboundTestContext3d()->set_context_lost(true);
-
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
-
- // DeferredInitialize fails.
- did_update_renderer_capabilities_ = false;
- EXPECT_FALSE(
- output_surface_->InitializeAndSetContext3d(onscreen_context_provider_));
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(did_update_renderer_capabilities_);
-
- // Software draw again.
- DrawFrame();
-}
-
// Checks that we have a non-0 default allocation if we pass a context that
// doesn't support memory management extensions.
TEST_F(LayerTreeHostImplTest, DefaultMemoryAllocation) {
LayerTreeSettings settings;
- host_impl_ = LayerTreeHostImpl::Create(settings,
- this,
- &proxy_,
- &stats_instrumentation_,
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
- 0);
+ host_impl_ = LayerTreeHostImpl::Create(
+ settings, this, &proxy_, &stats_instrumentation_,
+ shared_bitmap_manager_.get(), gpu_memory_buffer_manager_.get(),
+ task_graph_runner_.get(), 0);
scoped_ptr<OutputSurface> output_surface(
FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create()));
@@ -6445,9 +5931,9 @@ TEST_F(LayerTreeHostImplTest, MemoryPolicy) {
// when visible.
LayerTreeSettings settings;
settings.gpu_rasterization_enabled = true;
- host_impl_ = LayerTreeHostImpl::Create(
- settings, this, &proxy_, &stats_instrumentation_, NULL, NULL, 0);
- host_impl_->SetUseGpuRasterization(true);
+ CreateHostImpl(settings, CreateOutputSurface());
+ host_impl_->SetContentIsSuitableForGpuRasterization(true);
+ host_impl_->SetHasGpuRasterizationTrigger(true);
host_impl_->SetVisible(true);
host_impl_->SetMemoryPolicy(policy1);
EXPECT_EQ(policy1.bytes_limit_when_visible, current_limit_bytes_);
@@ -6489,28 +5975,34 @@ TEST_F(LayerTreeHostImplTest, RequireHighResAfterGpuRasterizationToggles) {
host_impl_->ResetRequiresHighResToDraw();
- host_impl_->SetUseGpuRasterization(false);
+ host_impl_->SetContentIsSuitableForGpuRasterization(true);
+ host_impl_->SetHasGpuRasterizationTrigger(false);
+ host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded();
EXPECT_FALSE(host_impl_->RequiresHighResToDraw());
- host_impl_->SetUseGpuRasterization(true);
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded();
EXPECT_TRUE(host_impl_->RequiresHighResToDraw());
- host_impl_->SetUseGpuRasterization(false);
+ host_impl_->SetHasGpuRasterizationTrigger(false);
+ host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded();
EXPECT_TRUE(host_impl_->RequiresHighResToDraw());
host_impl_->ResetRequiresHighResToDraw();
EXPECT_FALSE(host_impl_->RequiresHighResToDraw());
- host_impl_->SetUseGpuRasterization(true);
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->UpdateTreeResourcesForGpuRasterizationIfNeeded();
EXPECT_TRUE(host_impl_->RequiresHighResToDraw());
}
-class LayerTreeHostImplTestManageTiles : public LayerTreeHostImplTest {
+class LayerTreeHostImplTestPrepareTiles : public LayerTreeHostImplTest {
public:
- virtual void SetUp() override {
+ void SetUp() override {
LayerTreeSettings settings;
settings.impl_side_painting = true;
- fake_host_impl_ = new FakeLayerTreeHostImpl(
- settings, &proxy_, shared_bitmap_manager_.get());
+ fake_host_impl_ = new FakeLayerTreeHostImpl(settings, &proxy_,
+ shared_bitmap_manager_.get(),
+ task_graph_runner_.get());
host_impl_.reset(fake_host_impl_);
host_impl_->InitializeRenderer(CreateOutputSurface());
host_impl_->SetViewportSize(gfx::Size(10, 10));
@@ -6519,11 +6011,11 @@ class LayerTreeHostImplTestManageTiles : public LayerTreeHostImplTest {
FakeLayerTreeHostImpl* fake_host_impl_;
};
-TEST_F(LayerTreeHostImplTestManageTiles, ManageTilesWhenInvisible) {
+TEST_F(LayerTreeHostImplTestPrepareTiles, PrepareTilesWhenInvisible) {
fake_host_impl_->DidModifyTilePriorities();
- EXPECT_TRUE(fake_host_impl_->manage_tiles_needed());
+ EXPECT_TRUE(fake_host_impl_->prepare_tiles_needed());
fake_host_impl_->SetVisible(false);
- EXPECT_FALSE(fake_host_impl_->manage_tiles_needed());
+ EXPECT_FALSE(fake_host_impl_->prepare_tiles_needed());
}
TEST_F(LayerTreeHostImplTest, UIResourceManagement) {
@@ -6617,7 +6109,7 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) {
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
// The CopyOutputResult's callback has a ref on the ContextProvider and a
@@ -6640,6 +6132,8 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) {
gfx::Size content_size(20, 20);
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 3);
+ root_clip->SetHasRenderSurface(true);
+
scoped_ptr<LayerImpl> root =
CreateScrollableLayer(1, content_size, root_clip.get());
root->SetIsContainerForFixedPositionLayers(true);
@@ -6652,16 +6146,15 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) {
host_impl_->SetViewportSize(surface_size);
host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
- host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID);
+ host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 1,
+ Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
gfx::Vector2d scroll_delta(0, 100);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -6683,16 +6176,17 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) {
// the scroll doesn't bubble up to the parent layer.
gfx::Size surface_size(10, 10);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
+ root->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> root_scrolling =
CreateScrollableLayer(2, surface_size, root.get());
scoped_ptr<LayerImpl> grand_child =
CreateScrollableLayer(4, surface_size, root.get());
- grand_child->SetScrollOffset(gfx::ScrollOffset(0, 2));
+ grand_child->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 2));
scoped_ptr<LayerImpl> child =
CreateScrollableLayer(3, surface_size, root.get());
- child->SetScrollOffset(gfx::ScrollOffset(0, 4));
+ child->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 4));
child->AddChild(grand_child.Pass());
root_scrolling->AddChild(child.Pass());
@@ -6708,8 +6202,8 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) {
LayerImpl* grand_child = child->children()[0];
gfx::Vector2d scroll_delta(0, -2);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
// The grand child should have scrolled up to its limit.
@@ -6729,7 +6223,7 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) {
// The first |ScrollBy| after the fling should re-lock the scrolling
// layer to the first layer that scrolled, which is the child.
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
@@ -6753,6 +6247,7 @@ TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) {
gfx::Size content_size(20, 20);
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 3);
+ root_clip->SetHasRenderSurface(true);
scoped_ptr<LayerImpl> root_scroll =
CreateScrollableLayer(1, content_size, root_clip.get());
int root_scroll_id = root_scroll->id();
@@ -6767,11 +6262,10 @@ TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) {
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
gfx::Vector2d scroll_delta(0, 100);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -6790,7 +6284,7 @@ TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) {
TEST_F(LayerTreeHostImplTest, ScrollUnknownNotOnAncestorChain) {
// If we ray cast a scroller that is not on the first layer's ancestor chain,
- // we should return ScrollUnknown.
+ // we should return SCROLL_UNKNOWN.
gfx::Size content_size(100, 100);
SetupScrollAndContentsLayers(content_size);
@@ -6816,14 +6310,14 @@ TEST_F(LayerTreeHostImplTest, ScrollUnknownNotOnAncestorChain) {
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollUnknown,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_UNKNOWN,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollUnknownScrollAncestorMismatch) {
// If we ray cast a scroller this is on the first layer's ancestor chain, but
// is not the first scroller we encounter when walking up from the layer, we
- // should also return ScrollUnknown.
+ // should also return SCROLL_UNKNOWN.
gfx::Size content_size(100, 100);
SetupScrollAndContentsLayers(content_size);
@@ -6855,11 +6349,11 @@ TEST_F(LayerTreeHostImplTest, ScrollUnknownScrollAncestorMismatch) {
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollUnknown,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_UNKNOWN,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
}
-TEST_F(LayerTreeHostImplTest, ScrollInvisibleScroller) {
+TEST_F(LayerTreeHostImplTest, NotScrollInvisibleScroller) {
gfx::Size content_size(100, 100);
SetupScrollAndContentsLayers(content_size);
@@ -6882,14 +6376,51 @@ TEST_F(LayerTreeHostImplTest, ScrollInvisibleScroller) {
// it. The reason for this is that if the scrolling the scroll would not move
// any layer that is a drawn RSLL member, then we can ignore the hit.
//
- // Why ScrollStarted? In this case, it's because we've bubbled out and started
- // overscrolling the inner viewport.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ // Why SCROLL_STARTED? In this case, it's because we've bubbled out and
+ // started scrolling the inner viewport.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_EQ(2, host_impl_->CurrentlyScrollingLayer()->id());
}
+TEST_F(LayerTreeHostImplTest, ScrollInvisibleScrollerWithVisibleDescendent) {
+ gfx::Size content_size(100, 100);
+ SetupScrollAndContentsLayers(content_size);
+
+ LayerImpl* root = host_impl_->active_tree()->LayerById(1);
+ LayerImpl* root_scroll_layer = host_impl_->active_tree()->LayerById(2);
+
+ scoped_ptr<LayerImpl> invisible_scroll_layer =
+ CreateScrollableLayer(7, content_size, root);
+ invisible_scroll_layer->SetDrawsContent(false);
+
+ scoped_ptr<LayerImpl> child_layer =
+ LayerImpl::Create(host_impl_->active_tree(), 8);
+ child_layer->SetDrawsContent(false);
+
+ scoped_ptr<LayerImpl> grand_child_layer =
+ LayerImpl::Create(host_impl_->active_tree(), 9);
+ grand_child_layer->SetDrawsContent(true);
+ grand_child_layer->SetBounds(content_size);
+ grand_child_layer->SetContentBounds(content_size);
+ // Move the grand child so it's not hit by our test point.
+ grand_child_layer->SetPosition(gfx::PointF(10.f, 10.f));
+
+ child_layer->AddChild(grand_child_layer.Pass());
+ invisible_scroll_layer->AddChild(child_layer.Pass());
+ root_scroll_layer->AddChild(invisible_scroll_layer.Pass());
+
+ DrawFrame();
+
+ // We should have scrolled |invisible_scroll_layer| as it was hit and it has
+ // a descendant which is a drawn RSLL member.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
+
+ EXPECT_EQ(7, host_impl_->CurrentlyScrollingLayer()->id());
+}
+
TEST_F(LayerTreeHostImplTest, ScrollInvisibleScrollerWithVisibleScrollChild) {
// This test case is very similar to the one above with one key difference:
// the invisible scroller has a scroll child that is indeed draw contents.
@@ -6935,14 +6466,11 @@ TEST_F(LayerTreeHostImplTest, ScrollInvisibleScrollerWithVisibleScrollChild) {
DrawFrame();
- // We should not have scrolled |child_scroll| even though we technically "hit"
- // it. The reason for this is that if the scrolling the scroll would not move
- // any layer that is a drawn RSLL member, then we can ignore the hit.
- //
- // Why ScrollStarted? In this case, it's because we've bubbled out and started
- // overscrolling the inner viewport.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ // We should have scrolled |child_scroll| even though it is invisible.
+ // The reason for this is that if the scrolling the scroll would move a layer
+ // that is a drawn RSLL member, then we should accept this hit.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_EQ(7, host_impl_->CurrentlyScrollingLayer()->id());
}
@@ -6956,6 +6484,7 @@ TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) {
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
root->SetDrawsContent(true);
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
@@ -6977,7 +6506,7 @@ TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) {
gfx::Rect full_frame_damage(host_impl_->DrawViewportSize());
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_TRUE(host_impl_->SwapBuffers(frame));
@@ -6996,29 +6525,28 @@ TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToCompositorFrameMetadata) {
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
root->SetDrawsContent(true);
+ root->SetHasRenderSurface(true);
host_impl_->active_tree()->SetRootLayer(root.Pass());
// Ensure the default frame selection bounds are empty.
FakeOutputSurface* fake_output_surface =
static_cast<FakeOutputSurface*>(host_impl_->output_surface());
- const ViewportSelectionBound& selection_start_before =
- fake_output_surface->last_sent_frame().metadata.selection_start;
- const ViewportSelectionBound& selection_end_before =
- fake_output_surface->last_sent_frame().metadata.selection_end;
- EXPECT_EQ(ViewportSelectionBound(), selection_start_before);
- EXPECT_EQ(ViewportSelectionBound(), selection_end_before);
+ const ViewportSelection& selection_before =
+ fake_output_surface->last_sent_frame().metadata.selection;
+ EXPECT_EQ(ViewportSelectionBound(), selection_before.start);
+ EXPECT_EQ(ViewportSelectionBound(), selection_before.end);
// Plumb the layer-local selection bounds.
gfx::PointF selection_top(5, 0);
gfx::PointF selection_bottom(5, 5);
- LayerSelectionBound start, end;
- start.type = SELECTION_BOUND_CENTER;
- start.layer_id = root_layer_id;
- start.edge_bottom = selection_bottom;
- start.edge_top = selection_top;
- end = start;
- host_impl_->active_tree()->RegisterSelection(start, end);
+ LayerSelection selection;
+ selection.start.type = SELECTION_BOUND_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();
@@ -7026,21 +6554,19 @@ TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToCompositorFrameMetadata) {
gfx::Rect full_frame_damage(host_impl_->DrawViewportSize());
LayerTreeHostImpl::FrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DrawLayers(&frame);
host_impl_->DidDrawAllLayers(frame);
EXPECT_TRUE(host_impl_->SwapBuffers(frame));
// Ensure the selection bounds have propagated to the frame metadata.
- const ViewportSelectionBound& selection_start_after =
- fake_output_surface->last_sent_frame().metadata.selection_start;
- const ViewportSelectionBound& selection_end_after =
- fake_output_surface->last_sent_frame().metadata.selection_end;
- EXPECT_EQ(start.type, selection_start_after.type);
- EXPECT_EQ(end.type, selection_end_after.type);
- EXPECT_EQ(selection_bottom, selection_start_after.edge_bottom);
- EXPECT_EQ(selection_top, selection_start_after.edge_top);
- EXPECT_TRUE(selection_start_after.visible);
- EXPECT_TRUE(selection_start_after.visible);
+ const ViewportSelection& selection_after =
+ fake_output_surface->last_sent_frame().metadata.selection;
+ EXPECT_EQ(selection.start.type, selection_after.start.type);
+ EXPECT_EQ(selection.end.type, selection_after.end.type);
+ EXPECT_EQ(selection_bottom, selection_after.start.edge_bottom);
+ EXPECT_EQ(selection_top, selection_after.start.edge_top);
+ EXPECT_TRUE(selection_after.start.visible);
+ EXPECT_TRUE(selection_after.start.visible);
}
class SimpleSwapPromiseMonitor : public SwapPromiseMonitor {
@@ -7136,8 +6662,8 @@ TEST_F(LayerTreeHostImplTest, SimpleSwapPromiseMonitor) {
LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
// Scrolling normally should not trigger any forwarding.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_TRUE(
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
host_impl_->ScrollEnd();
@@ -7149,8 +6675,8 @@ TEST_F(LayerTreeHostImplTest, SimpleSwapPromiseMonitor) {
// Scrolling with a scroll handler should defer the swap to the main
// thread.
scroll_layer->SetHaveScrollEventHandlers(true);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_TRUE(
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
host_impl_->ScrollEnd();
@@ -7163,11 +6689,12 @@ TEST_F(LayerTreeHostImplTest, SimpleSwapPromiseMonitor) {
class LayerTreeHostImplWithTopControlsTest : public LayerTreeHostImplTest {
public:
- virtual void SetUp() override {
+ void SetUp() override {
LayerTreeSettings settings = DefaultSettings();
- settings.calculate_top_controls_position = true;
- settings.top_controls_height = top_controls_height_;
CreateHostImpl(settings, CreateOutputSurface());
+ host_impl_->active_tree()->set_top_controls_height(top_controls_height_);
+ host_impl_->sync_tree()->set_top_controls_height(top_controls_height_);
+ host_impl_->active_tree()->SetCurrentTopControlsShownRatio(1.f);
}
protected:
@@ -7178,14 +6705,39 @@ const int LayerTreeHostImplWithTopControlsTest::top_controls_height_ = 50;
TEST_F(LayerTreeHostImplWithTopControlsTest, NoIdleAnimations) {
SetupScrollAndContentsLayers(gfx::Size(100, 100))
- ->SetScrollOffset(gfx::ScrollOffset(0, 10));
+ ->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 10));
host_impl_->Animate(base::TimeTicks());
EXPECT_FALSE(did_request_redraw_);
}
+TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsHeightIsCommitted) {
+ SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ EXPECT_FALSE(did_request_redraw_);
+ host_impl_->CreatePendingTree();
+ host_impl_->sync_tree()->set_top_controls_height(100);
+ host_impl_->ActivateSyncTree();
+ EXPECT_EQ(100, host_impl_->top_controls_manager()->TopControlsHeight());
+}
+
+TEST_F(LayerTreeHostImplWithTopControlsTest,
+ TopControlsStayFullyVisibleOnHeightChange) {
+ SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+ host_impl_->CreatePendingTree();
+ host_impl_->sync_tree()->set_top_controls_height(0);
+ host_impl_->ActivateSyncTree();
+ EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+ host_impl_->CreatePendingTree();
+ host_impl_->sync_tree()->set_top_controls_height(50);
+ host_impl_->ActivateSyncTree();
+ EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ControlsTopOffset());
+}
+
TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationScheduling) {
SetupScrollAndContentsLayers(gfx::Size(100, 100))
- ->SetScrollOffset(gfx::ScrollOffset(0, 10));
+ ->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 10));
host_impl_->DidChangeTopControlsPosition();
EXPECT_TRUE(did_request_animate_);
EXPECT_TRUE(did_request_redraw_);
@@ -7198,20 +6750,21 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) {
BOTH, SHOWN, false);
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
// Scroll just the top controls and verify that the scroll succeeds.
const float residue = 10;
float offset = top_controls_height_ - residue;
EXPECT_TRUE(
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
- EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-offset,
+ host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
// Scroll across the boundary
const float content_scroll = 20;
@@ -7221,7 +6774,7 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) {
EXPECT_EQ(-top_controls_height_,
host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF(0, content_scroll).ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
// Now scroll back to the top of the content
offset = -content_scroll;
@@ -7230,7 +6783,7 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) {
EXPECT_EQ(-top_controls_height_,
host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
// And scroll the top controls completely into view
offset = -top_controls_height_;
@@ -7238,14 +6791,14 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) {
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
// And attempt to scroll past the end
EXPECT_FALSE(
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
host_impl_->ScrollEnd();
}
@@ -7257,20 +6810,21 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAtOrigin) {
BOTH, SHOWN, false);
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
// Scroll the top controls partially.
const float residue = 35;
float offset = top_controls_height_ - residue;
EXPECT_TRUE(
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
- EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-offset,
+ host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
did_request_redraw_ = false;
did_request_animate_ = false;
@@ -7297,7 +6851,7 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAtOrigin) {
animation_time += base::TimeDelta::FromMilliseconds(5);
host_impl_->Animate(animation_time);
EXPECT_EQ(gfx::Vector2dF().ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
float new_offset =
host_impl_->top_controls_manager()->ControlsTopOffset();
@@ -7323,23 +6877,25 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAfterScroll) {
host_impl_->top_controls_manager()->UpdateTopControlsState(
BOTH, SHOWN, false);
float initial_scroll_offset = 50;
- scroll_layer->SetScrollOffset(gfx::ScrollOffset(0, initial_scroll_offset));
+ scroll_layer->PushScrollOffsetFromMainThread(
+ gfx::ScrollOffset(0, initial_scroll_offset));
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
// Scroll the top controls partially.
const float residue = 15;
float offset = top_controls_height_ - residue;
EXPECT_TRUE(
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
- EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+ EXPECT_FLOAT_EQ(-offset,
+ host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
- scroll_layer->TotalScrollOffset().ToString());
+ scroll_layer->CurrentScrollOffset().ToString());
did_request_redraw_ = false;
did_request_animate_ = false;
@@ -7374,6 +6930,132 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAfterScroll) {
}
}
EXPECT_FALSE(host_impl_->top_controls_manager()->animation());
+ EXPECT_EQ(-top_controls_height_,
+ host_impl_->top_controls_manager()->ControlsTopOffset());
+}
+
+TEST_F(LayerTreeHostImplWithTopControlsTest,
+ TopControlsAnimationAfterMainThreadFlingStopped) {
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 200));
+ host_impl_->SetViewportSize(gfx::Size(100, 100));
+ host_impl_->top_controls_manager()->UpdateTopControlsState(BOTH, SHOWN,
+ false);
+ float initial_scroll_offset = 50;
+ scroll_layer->PushScrollOffsetFromMainThread(
+ gfx::ScrollOffset(0, initial_scroll_offset));
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
+ EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
+ scroll_layer->CurrentScrollOffset().ToString());
+
+ // Scroll the top controls partially.
+ const float residue = 15;
+ float offset = top_controls_height_ - residue;
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+ EXPECT_FLOAT_EQ(-offset,
+ host_impl_->top_controls_manager()->ControlsTopOffset());
+ EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
+ scroll_layer->CurrentScrollOffset().ToString());
+
+ did_request_redraw_ = false;
+ did_request_animate_ = false;
+ did_request_commit_ = false;
+
+ // End the fling while the controls are still offset from the limit.
+ host_impl_->MainThreadHasStoppedFlinging();
+ ASSERT_TRUE(host_impl_->top_controls_manager()->animation());
+ EXPECT_TRUE(did_request_animate_);
+ EXPECT_TRUE(did_request_redraw_);
+ EXPECT_FALSE(did_request_commit_);
+
+ // Animate the top controls to the limit.
+ base::TimeTicks animation_time = gfx::FrameTime::Now();
+ while (did_request_animate_) {
+ did_request_redraw_ = false;
+ did_request_animate_ = false;
+ did_request_commit_ = false;
+
+ float old_offset = host_impl_->top_controls_manager()->ControlsTopOffset();
+
+ animation_time += base::TimeDelta::FromMilliseconds(5);
+ host_impl_->Animate(animation_time);
+
+ float new_offset = host_impl_->top_controls_manager()->ControlsTopOffset();
+
+ if (new_offset != old_offset) {
+ EXPECT_TRUE(did_request_redraw_);
+ EXPECT_TRUE(did_request_commit_);
+ }
+ }
+ EXPECT_FALSE(host_impl_->top_controls_manager()->animation());
+ EXPECT_EQ(-top_controls_height_,
+ host_impl_->top_controls_manager()->ControlsTopOffset());
+}
+
+TEST_F(LayerTreeHostImplWithTopControlsTest,
+ TopControlsScrollDeltaInOverScroll) {
+ // test varifies that the overscroll delta should not have accumulated in
+ // the top controls if we do a hide and show without releasing finger.
+
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 200));
+ host_impl_->SetViewportSize(gfx::Size(100, 100));
+ host_impl_->top_controls_manager()->UpdateTopControlsState(BOTH, SHOWN,
+ false);
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+ float offset = 50;
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+ EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ scroll_layer->CurrentScrollOffset().ToString());
+
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+ EXPECT_EQ(gfx::Vector2dF(0, offset).ToString(),
+ scroll_layer->CurrentScrollOffset().ToString());
+
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+
+ // Should have fully scrolled
+ EXPECT_EQ(gfx::Vector2dF(0, scroll_layer->MaxScrollOffset().y()).ToString(),
+ scroll_layer->CurrentScrollOffset().ToString());
+
+ float overscrollamount = 10;
+
+ // Overscroll the content
+ EXPECT_FALSE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, overscrollamount))
+ .did_scroll);
+ EXPECT_EQ(gfx::Vector2dF(0, 2 * offset).ToString(),
+ scroll_layer->CurrentScrollOffset().ToString());
+ EXPECT_EQ(gfx::Vector2dF(0, overscrollamount).ToString(),
+ host_impl_->accumulated_root_overscroll().ToString());
+
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -2 * offset))
+ .did_scroll);
+ EXPECT_EQ(gfx::Vector2dF(0, 0).ToString(),
+ scroll_layer->CurrentScrollOffset().ToString());
+ EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -offset)).did_scroll);
+ EXPECT_EQ(gfx::Vector2dF(0, 0).ToString(),
+ scroll_layer->CurrentScrollOffset().ToString());
+
+ // Top controls should be fully visible
+ EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+ host_impl_->ScrollEnd();
}
class LayerTreeHostImplVirtualViewportTest : public LayerTreeHostImplTest {
@@ -7391,7 +7073,7 @@ class LayerTreeHostImplVirtualViewportTest : public LayerTreeHostImplTest {
scoped_ptr<LayerImpl> inner_scroll =
LayerImpl::Create(layer_tree_impl, kInnerViewportScrollLayerId);
inner_scroll->SetIsContainerForFixedPositionLayers(true);
- inner_scroll->SetScrollOffset(gfx::ScrollOffset());
+ inner_scroll->PushScrollOffsetFromMainThread(gfx::ScrollOffset());
scoped_ptr<LayerImpl> inner_clip =
LayerImpl::Create(layer_tree_impl, kInnerViewportClipLayerId);
@@ -7413,7 +7095,7 @@ class LayerTreeHostImplVirtualViewportTest : public LayerTreeHostImplTest {
scoped_ptr<LayerImpl> outer_scroll =
LayerImpl::Create(layer_tree_impl, kOuterViewportScrollLayerId);
outer_scroll->SetScrollClipLayer(outer_clip->id());
- outer_scroll->SetScrollOffset(gfx::ScrollOffset());
+ outer_scroll->PushScrollOffsetFromMainThread(gfx::ScrollOffset());
outer_scroll->SetBounds(content_size);
outer_scroll->SetContentBounds(content_size);
outer_scroll->SetPosition(gfx::PointF());
@@ -7431,14 +7113,51 @@ class LayerTreeHostImplVirtualViewportTest : public LayerTreeHostImplTest {
page_scale->AddChild(inner_scroll.Pass());
inner_clip->AddChild(page_scale.Pass());
+ inner_clip->SetHasRenderSurface(true);
layer_tree_impl->SetRootLayer(inner_clip.Pass());
- layer_tree_impl->SetViewportLayersFromIds(kPageScaleLayerId,
- kInnerViewportScrollLayerId, kOuterViewportScrollLayerId);
+ layer_tree_impl->SetViewportLayersFromIds(
+ Layer::INVALID_ID, kPageScaleLayerId, kInnerViewportScrollLayerId,
+ kOuterViewportScrollLayerId);
host_impl_->active_tree()->DidBecomeActive();
}
};
+TEST_F(LayerTreeHostImplVirtualViewportTest, ScrollBothInnerAndOuterLayer) {
+ gfx::Size content_size = gfx::Size(100, 160);
+ gfx::Size outer_viewport = gfx::Size(50, 80);
+ gfx::Size inner_viewport = gfx::Size(25, 40);
+
+ SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport);
+
+ TestScrollOffsetDelegate scroll_delegate;
+ host_impl_->SetRootLayerScrollOffsetDelegate(&scroll_delegate);
+
+ LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer();
+ LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer();
+ DrawFrame();
+ {
+ gfx::ScrollOffset inner_expected;
+ gfx::ScrollOffset outer_expected;
+ EXPECT_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
+ EXPECT_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
+
+ gfx::ScrollOffset current_offset(70.f, 100.f);
+
+ scroll_delegate.set_getter_return_value(current_offset);
+ host_impl_->OnRootLayerDelegatedScrollOffsetChanged();
+ EXPECT_EQ(gfx::ScrollOffset(25.f, 40.f), inner_scroll->MaxScrollOffset());
+ EXPECT_EQ(gfx::ScrollOffset(50.f, 80.f), outer_scroll->MaxScrollOffset());
+
+ // Outer viewport scrolls first. Then the rest is applied to the inner
+ // viewport.
+ EXPECT_EQ(gfx::ScrollOffset(20.f, 20.f),
+ inner_scroll->CurrentScrollOffset());
+ EXPECT_EQ(gfx::ScrollOffset(50.f, 80.f),
+ outer_scroll->CurrentScrollOffset());
+ }
+}
+
TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) {
gfx::Size content_size = gfx::Size(100, 160);
gfx::Size outer_viewport = gfx::Size(50, 80);
@@ -7452,13 +7171,13 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) {
{
gfx::Vector2dF inner_expected;
gfx::Vector2dF outer_expected;
- EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset());
- EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
// Make sure the fling goes to the outer viewport first
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
gfx::Vector2d scroll_delta(inner_viewport.width(), inner_viewport.height());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -7466,13 +7185,13 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) {
host_impl_->ScrollEnd();
- EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset());
- EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
// Fling past the outer viewport boundry, make sure inner viewport scrolls.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
outer_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y());
@@ -7482,8 +7201,8 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) {
host_impl_->ScrollEnd();
- EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset());
- EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
}
}
@@ -7501,38 +7220,102 @@ TEST_F(LayerTreeHostImplVirtualViewportTest,
{
gfx::Vector2dF inner_expected;
gfx::Vector2dF outer_expected;
- EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset());
- EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
// Make sure the scroll goes to the outer viewport first.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
+ InputHandler::GESTURE));
// Scroll near the edge of the outer viewport.
gfx::Vector2d scroll_delta(inner_viewport.width(), inner_viewport.height());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
outer_expected += scroll_delta;
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
+ InputHandler::GESTURE));
- EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset());
- EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
// Now diagonal scroll across the outer viewport boundary in a single event.
// The entirety of the scroll should be consumed, as bubbling between inner
// and outer viewport layers is perfect.
host_impl_->ScrollBy(gfx::Point(), gfx::ScaleVector2d(scroll_delta, 2));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
+ InputHandler::GESTURE));
outer_expected += scroll_delta;
inner_expected += scroll_delta;
host_impl_->ScrollEnd();
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(
+ gfx::Point(), InputHandler::GESTURE));
- EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset());
- EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset());
+ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
+ }
+}
+
+TEST_F(LayerTreeHostImplVirtualViewportTest,
+ TouchFlingCanLockToViewportLayerAfterBubbling) {
+ gfx::Size content_size = gfx::Size(100, 160);
+ gfx::Size outer_viewport = gfx::Size(50, 80);
+ gfx::Size inner_viewport = gfx::Size(25, 40);
+
+ SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport);
+
+ LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer();
+ LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer();
+
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(10, outer_viewport, outer_scroll);
+ LayerImpl* child_scroll = child.get();
+ outer_scroll->children()[0]->AddChild(child.Pass());
+
+ DrawFrame();
+ {
+ scoped_ptr<ScrollAndScaleSet> scroll_info;
+
+ gfx::Vector2d scroll_delta(0, inner_viewport.height());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
+ InputHandler::GESTURE));
+
+ // The child should have scrolled up to its limit.
+ scroll_info = host_impl_->ProcessScrollDeltas();
+ ASSERT_EQ(1u, scroll_info->scrolls.size());
+ ExpectContains(*scroll_info, child_scroll->id(), scroll_delta);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll);
+
+ // The first |ScrollBy| after the fling should re-lock the scrolling
+ // layer to the first layer that scrolled, the inner viewport scroll layer.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll);
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
+ InputHandler::GESTURE));
+
+ // The inner viewport should have scrolled up to its limit.
+ scroll_info = host_impl_->ProcessScrollDeltas();
+ ASSERT_EQ(2u, scroll_info->scrolls.size());
+ ExpectContains(*scroll_info, child_scroll->id(), scroll_delta);
+ ExpectContains(*scroll_info, inner_scroll->id(), scroll_delta);
+
+ // As the locked layer is at its limit, no further scrolling can occur.
+ EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll);
+ host_impl_->ScrollEnd();
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(
+ gfx::Point(), InputHandler::GESTURE));
}
}
class LayerTreeHostImplWithImplicitLimitsTest : public LayerTreeHostImplTest {
public:
- virtual void SetUp() override {
+ void SetUp() override {
LayerTreeSettings settings = DefaultSettings();
settings.max_memory_for_prepaint_percentage = 50;
CreateHostImpl(settings, CreateOutputSurface());
@@ -7589,7 +7372,7 @@ TEST_F(LayerTreeHostImplTest, ScrollAnimated) {
base::TimeTicks start_time =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(100);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)));
LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer();
@@ -7597,22 +7380,22 @@ TEST_F(LayerTreeHostImplTest, ScrollAnimated) {
host_impl_->Animate(start_time);
host_impl_->UpdateAnimationState(true);
- EXPECT_EQ(gfx::ScrollOffset(), scrolling_layer->TotalScrollOffset());
+ EXPECT_EQ(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
host_impl_->Animate(start_time + base::TimeDelta::FromMilliseconds(50));
host_impl_->UpdateAnimationState(true);
- float y = scrolling_layer->TotalScrollOffset().y();
+ float y = scrolling_layer->CurrentScrollOffset().y();
EXPECT_TRUE(y > 1 && y < 49);
// Update target.
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)));
host_impl_->Animate(start_time + base::TimeDelta::FromMilliseconds(200));
host_impl_->UpdateAnimationState(true);
- y = scrolling_layer->TotalScrollOffset().y();
+ y = scrolling_layer->CurrentScrollOffset().y();
EXPECT_TRUE(y > 50 && y < 100);
EXPECT_EQ(scrolling_layer, host_impl_->CurrentlyScrollingLayer());
@@ -7620,70 +7403,46 @@ TEST_F(LayerTreeHostImplTest, ScrollAnimated) {
host_impl_->UpdateAnimationState(true);
EXPECT_VECTOR_EQ(gfx::ScrollOffset(0, 100),
- scrolling_layer->TotalScrollOffset());
+ scrolling_layer->CurrentScrollOffset());
EXPECT_EQ(NULL, host_impl_->CurrentlyScrollingLayer());
}
-TEST_F(LayerTreeHostImplTest, GetPictureLayerImplPairs) {
- host_impl_->CreatePendingTree();
- host_impl_->pending_tree()->SetRootLayer(
- PictureLayerImpl::Create(host_impl_->pending_tree(), 10));
-
- LayerTreeImpl* pending_tree = host_impl_->pending_tree();
- LayerImpl* pending_layer = pending_tree->root_layer();
-
- std::vector<PictureLayerImpl::Pair> layer_pairs;
- host_impl_->GetPictureLayerImplPairs(&layer_pairs);
- EXPECT_EQ(1u, layer_pairs.size());
- EXPECT_EQ(pending_layer, layer_pairs[0].pending);
- EXPECT_EQ(nullptr, layer_pairs[0].active);
-
- host_impl_->ActivateSyncTree();
-
- LayerTreeImpl* active_tree = host_impl_->active_tree();
- LayerImpl* active_layer = active_tree->root_layer();
- EXPECT_NE(active_tree, pending_tree);
- EXPECT_NE(active_layer, pending_layer);
- EXPECT_NE(nullptr, active_tree);
- EXPECT_NE(nullptr, active_layer);
-
+TEST_F(LayerTreeHostImplTest, InvalidLayerNotAddedToRasterQueue) {
host_impl_->CreatePendingTree();
- layer_pairs.clear();
- host_impl_->GetPictureLayerImplPairs(&layer_pairs);
- EXPECT_EQ(1u, layer_pairs.size());
- EXPECT_EQ(active_layer, layer_pairs[0].active);
- EXPECT_EQ(pending_layer, layer_pairs[0].pending);
-
- // Activate, the active layer has no twin now.
- host_impl_->ActivateSyncTree();
-
- layer_pairs.clear();
- host_impl_->GetPictureLayerImplPairs(&layer_pairs);
- EXPECT_EQ(1u, layer_pairs.size());
- EXPECT_EQ(active_layer, layer_pairs[0].active);
- EXPECT_EQ(nullptr, layer_pairs[0].pending);
+ Region empty_invalidation;
+ scoped_refptr<RasterSource> pile_with_tiles(
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(
+ gfx::Size(10, 10)));
- // Create another layer in the pending tree that's not in the active tree. We
- // should get two pairs.
- host_impl_->CreatePendingTree();
- host_impl_->pending_tree()->root_layer()->AddChild(
- PictureLayerImpl::Create(host_impl_->pending_tree(), 11));
-
- LayerImpl* new_pending_layer = pending_tree->root_layer()->children()[0];
-
- layer_pairs.clear();
- host_impl_->GetPictureLayerImplPairs(&layer_pairs);
- EXPECT_EQ(2u, layer_pairs.size());
-
- // The pair ordering is flaky, so make it consistent.
- if (layer_pairs[0].active != active_layer)
- std::swap(layer_pairs[0], layer_pairs[1]);
-
- EXPECT_EQ(active_layer, layer_pairs[0].active);
- EXPECT_EQ(pending_layer, layer_pairs[0].pending);
- EXPECT_EQ(new_pending_layer, layer_pairs[1].pending);
- EXPECT_EQ(nullptr, layer_pairs[1].active);
+ scoped_ptr<FakePictureLayerImpl> layer =
+ FakePictureLayerImpl::Create(host_impl_->pending_tree(), 11);
+ layer->SetBounds(gfx::Size(10, 10));
+ layer->set_gpu_raster_max_texture_size(host_impl_->device_viewport_size());
+ layer->SetDrawsContent(true);
+ layer->tilings()->AddTiling(1.0f, pile_with_tiles);
+ layer->UpdateRasterSource(pile_with_tiles, &empty_invalidation, nullptr);
+ layer->tilings()->tiling_at(0)->set_resolution(
+ TileResolution::HIGH_RESOLUTION);
+ layer->tilings()->tiling_at(0)->CreateAllTilesForTesting();
+ layer->tilings()->tiling_at(0)->ComputeTilePriorityRects(
+ gfx::Rect(gfx::Size(10, 10)), 1.f, 1.0, Occlusion());
+ host_impl_->pending_tree()->SetRootLayer(layer.Pass());
+
+ FakePictureLayerImpl* root_layer = static_cast<FakePictureLayerImpl*>(
+ host_impl_->pending_tree()->root_layer());
+
+ root_layer->set_has_valid_tile_priorities(true);
+ scoped_ptr<RasterTilePriorityQueue> non_empty_raster_priority_queue_all =
+ host_impl_->BuildRasterQueue(TreePriority::SAME_PRIORITY_FOR_BOTH_TREES,
+ RasterTilePriorityQueue::Type::ALL);
+ EXPECT_FALSE(non_empty_raster_priority_queue_all->IsEmpty());
+
+ root_layer->set_has_valid_tile_priorities(false);
+ scoped_ptr<RasterTilePriorityQueue> empty_raster_priority_queue_all =
+ host_impl_->BuildRasterQueue(TreePriority::SAME_PRIORITY_FOR_BOTH_TREES,
+ RasterTilePriorityQueue::Type::ALL);
+ EXPECT_TRUE(empty_raster_priority_queue_all->IsEmpty());
}
TEST_F(LayerTreeHostImplTest, DidBecomeActive) {
@@ -7695,7 +7454,6 @@ TEST_F(LayerTreeHostImplTest, DidBecomeActive) {
scoped_ptr<FakePictureLayerImpl> pending_layer =
FakePictureLayerImpl::Create(pending_tree, 10);
- pending_layer->DoPostCommitInitializationIfNeeded();
FakePictureLayerImpl* raw_pending_layer = pending_layer.get();
pending_tree->SetRootLayer(pending_layer.Pass());
ASSERT_EQ(raw_pending_layer, pending_tree->root_layer());
@@ -7706,7 +7464,6 @@ TEST_F(LayerTreeHostImplTest, DidBecomeActive) {
scoped_ptr<FakePictureLayerImpl> mask_layer =
FakePictureLayerImpl::Create(pending_tree, 11);
- mask_layer->DoPostCommitInitializationIfNeeded();
FakePictureLayerImpl* raw_mask_layer = mask_layer.get();
raw_pending_layer->SetMaskLayer(mask_layer.Pass());
ASSERT_EQ(raw_mask_layer, raw_pending_layer->mask_layer());
@@ -7721,7 +7478,6 @@ TEST_F(LayerTreeHostImplTest, DidBecomeActive) {
FakePictureLayerImpl::Create(pending_tree, 12);
scoped_ptr<FakePictureLayerImpl> replica_mask_layer =
FakePictureLayerImpl::Create(pending_tree, 13);
- replica_mask_layer->DoPostCommitInitializationIfNeeded();
FakePictureLayerImpl* raw_replica_mask_layer = replica_mask_layer.get();
replica_layer->SetMaskLayer(replica_mask_layer.Pass());
raw_pending_layer->SetReplicaLayer(replica_layer.Pass());
@@ -7737,6 +7493,42 @@ TEST_F(LayerTreeHostImplTest, DidBecomeActive) {
EXPECT_EQ(1u, raw_replica_mask_layer->did_become_active_call_count());
}
+TEST_F(LayerTreeHostImplTest, WheelScrollWithPageScaleFactorOnInnerLayer) {
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ DrawFrame();
+
+ EXPECT_EQ(scroll_layer, host_impl_->InnerViewportScrollLayer());
+
+ float min_page_scale = 1.f, max_page_scale = 4.f;
+ float page_scale_factor = 1.f;
+
+ // The scroll deltas should have the page scale factor applied.
+ {
+ host_impl_->active_tree()->PushPageScaleFromMainThread(
+ page_scale_factor, min_page_scale, max_page_scale);
+ host_impl_->SetPageScaleOnActiveTree(page_scale_factor);
+ scroll_layer->SetScrollDelta(gfx::Vector2d());
+
+ float page_scale_delta = 2.f;
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
+ host_impl_->PinchGestureBegin();
+ host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
+ host_impl_->PinchGestureEnd();
+ host_impl_->ScrollEnd();
+
+ gfx::Vector2dF scroll_delta(0, 5);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
+
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ host_impl_->ScrollEnd();
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 2.5),
+ scroll_layer->CurrentScrollOffset());
+ }
+}
+
class LayerTreeHostImplCountingLostSurfaces : public LayerTreeHostImplTest {
public:
LayerTreeHostImplCountingLostSurfaces() : num_lost_surfaces_(0) {}
@@ -7757,5 +7549,261 @@ TEST_F(LayerTreeHostImplCountingLostSurfaces, TwiceLostSurface) {
EXPECT_LE(1, num_lost_surfaces_);
}
+TEST_F(LayerTreeHostImplTest, RemoveUnreferencedRenderPass) {
+ LayerTreeHostImpl::FrameData frame;
+ frame.render_passes.push_back(RenderPass::Create());
+ RenderPass* pass3 = frame.render_passes.back();
+ frame.render_passes.push_back(RenderPass::Create());
+ RenderPass* pass2 = frame.render_passes.back();
+ frame.render_passes.push_back(RenderPass::Create());
+ RenderPass* pass1 = frame.render_passes.back();
+
+ pass1->SetNew(RenderPassId(1, 0), gfx::Rect(), gfx::Rect(), gfx::Transform());
+ pass2->SetNew(RenderPassId(2, 0), gfx::Rect(), gfx::Rect(), gfx::Transform());
+ pass3->SetNew(RenderPassId(3, 0), gfx::Rect(), gfx::Rect(), gfx::Transform());
+
+ frame.render_passes_by_id[pass1->id] = pass1;
+ frame.render_passes_by_id[pass2->id] = pass2;
+ frame.render_passes_by_id[pass3->id] = pass3;
+
+ // Add a quad to each pass so they aren't empty.
+ SolidColorDrawQuad* color_quad;
+ color_quad = pass1->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ color_quad->material = DrawQuad::SOLID_COLOR;
+ color_quad = pass2->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ color_quad->material = DrawQuad::SOLID_COLOR;
+ color_quad = pass3->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ color_quad->material = DrawQuad::SOLID_COLOR;
+
+ // pass3 is referenced by pass2.
+ RenderPassDrawQuad* rpdq =
+ pass2->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
+ rpdq->material = DrawQuad::RENDER_PASS;
+ rpdq->render_pass_id = pass3->id;
+
+ // But pass2 is not referenced by pass1. So pass2 and pass3 should be culled.
+ FakeLayerTreeHostImpl::RemoveRenderPasses(&frame);
+ EXPECT_EQ(1u, frame.render_passes_by_id.size());
+ EXPECT_TRUE(frame.render_passes_by_id[RenderPassId(1, 0)]);
+ EXPECT_FALSE(frame.render_passes_by_id[RenderPassId(2, 0)]);
+ EXPECT_FALSE(frame.render_passes_by_id[RenderPassId(3, 0)]);
+ EXPECT_EQ(1u, frame.render_passes.size());
+ EXPECT_EQ(RenderPassId(1, 0), frame.render_passes[0]->id);
+}
+
+TEST_F(LayerTreeHostImplTest, RemoveEmptyRenderPass) {
+ LayerTreeHostImpl::FrameData frame;
+ frame.render_passes.push_back(RenderPass::Create());
+ RenderPass* pass3 = frame.render_passes.back();
+ frame.render_passes.push_back(RenderPass::Create());
+ RenderPass* pass2 = frame.render_passes.back();
+ frame.render_passes.push_back(RenderPass::Create());
+ RenderPass* pass1 = frame.render_passes.back();
+
+ pass1->SetNew(RenderPassId(1, 0), gfx::Rect(), gfx::Rect(), gfx::Transform());
+ pass2->SetNew(RenderPassId(2, 0), gfx::Rect(), gfx::Rect(), gfx::Transform());
+ pass3->SetNew(RenderPassId(3, 0), gfx::Rect(), gfx::Rect(), gfx::Transform());
+
+ frame.render_passes_by_id[pass1->id] = pass1;
+ frame.render_passes_by_id[pass2->id] = pass2;
+ frame.render_passes_by_id[pass3->id] = pass3;
+
+ // pass1 is not empty, but pass2 and pass3 are.
+ SolidColorDrawQuad* color_quad;
+ color_quad = pass1->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ color_quad->material = DrawQuad::SOLID_COLOR;
+
+ // pass3 is referenced by pass2.
+ RenderPassDrawQuad* rpdq =
+ pass2->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
+ rpdq->material = DrawQuad::RENDER_PASS;
+ rpdq->render_pass_id = pass3->id;
+
+ // pass2 is referenced by pass1.
+ rpdq = pass1->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
+ rpdq->material = DrawQuad::RENDER_PASS;
+ rpdq->render_pass_id = pass2->id;
+
+ // Since pass3 is empty it should be removed. Then pass2 is empty too, and
+ // should be removed.
+ FakeLayerTreeHostImpl::RemoveRenderPasses(&frame);
+ EXPECT_EQ(1u, frame.render_passes_by_id.size());
+ EXPECT_TRUE(frame.render_passes_by_id[RenderPassId(1, 0)]);
+ EXPECT_FALSE(frame.render_passes_by_id[RenderPassId(2, 0)]);
+ EXPECT_FALSE(frame.render_passes_by_id[RenderPassId(3, 0)]);
+ EXPECT_EQ(1u, frame.render_passes.size());
+ EXPECT_EQ(RenderPassId(1, 0), frame.render_passes[0]->id);
+ // The RenderPassDrawQuad should be removed from pass1.
+ EXPECT_EQ(1u, pass1->quad_list.size());
+ EXPECT_EQ(DrawQuad::SOLID_COLOR, pass1->quad_list.ElementAt(0)->material);
+}
+
+TEST_F(LayerTreeHostImplTest, DoNotRemoveEmptyRootRenderPass) {
+ LayerTreeHostImpl::FrameData frame;
+ frame.render_passes.push_back(RenderPass::Create());
+ RenderPass* pass3 = frame.render_passes.back();
+ frame.render_passes.push_back(RenderPass::Create());
+ RenderPass* pass2 = frame.render_passes.back();
+ frame.render_passes.push_back(RenderPass::Create());
+ RenderPass* pass1 = frame.render_passes.back();
+
+ pass1->SetNew(RenderPassId(1, 0), gfx::Rect(), gfx::Rect(), gfx::Transform());
+ pass2->SetNew(RenderPassId(2, 0), gfx::Rect(), gfx::Rect(), gfx::Transform());
+ pass3->SetNew(RenderPassId(3, 0), gfx::Rect(), gfx::Rect(), gfx::Transform());
+
+ frame.render_passes_by_id[pass1->id] = pass1;
+ frame.render_passes_by_id[pass2->id] = pass2;
+ frame.render_passes_by_id[pass3->id] = pass3;
+
+ // pass3 is referenced by pass2.
+ RenderPassDrawQuad* rpdq =
+ pass2->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
+ rpdq->material = DrawQuad::RENDER_PASS;
+ rpdq->render_pass_id = pass3->id;
+
+ // pass2 is referenced by pass1.
+ rpdq = pass1->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
+ rpdq->material = DrawQuad::RENDER_PASS;
+ rpdq->render_pass_id = pass2->id;
+
+ // Since pass3 is empty it should be removed. Then pass2 is empty too, and
+ // should be removed. Then pass1 is empty too, but it's the root so it should
+ // not be removed.
+ FakeLayerTreeHostImpl::RemoveRenderPasses(&frame);
+ EXPECT_EQ(1u, frame.render_passes_by_id.size());
+ EXPECT_TRUE(frame.render_passes_by_id[RenderPassId(1, 0)]);
+ EXPECT_FALSE(frame.render_passes_by_id[RenderPassId(2, 0)]);
+ EXPECT_FALSE(frame.render_passes_by_id[RenderPassId(3, 0)]);
+ EXPECT_EQ(1u, frame.render_passes.size());
+ EXPECT_EQ(RenderPassId(1, 0), frame.render_passes[0]->id);
+ // The RenderPassDrawQuad should be removed from pass1.
+ EXPECT_EQ(0u, pass1->quad_list.size());
+}
+
+class FakeVideoFrameController : public VideoFrameController {
+ public:
+ void OnBeginFrame(const BeginFrameArgs& args) override {
+ begin_frame_args_ = args;
+ did_draw_frame_ = false;
+ }
+
+ void DidDrawFrame() override { did_draw_frame_ = true; }
+
+ const BeginFrameArgs& begin_frame_args() const { return begin_frame_args_; }
+
+ bool did_draw_frame() const { return did_draw_frame_; }
+
+ private:
+ BeginFrameArgs begin_frame_args_;
+ bool did_draw_frame_ = false;
+};
+
+TEST_F(LayerTreeHostImplTest, AddVideoFrameControllerInsideFrame) {
+ BeginFrameArgs begin_frame_args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
+ FakeVideoFrameController controller;
+
+ host_impl_->WillBeginImplFrame(begin_frame_args);
+ EXPECT_FALSE(controller.begin_frame_args().IsValid());
+ host_impl_->AddVideoFrameController(&controller);
+ EXPECT_TRUE(controller.begin_frame_args().IsValid());
+ host_impl_->DidFinishImplFrame();
+
+ EXPECT_FALSE(controller.did_draw_frame());
+ LayerTreeHostImpl::FrameData frame;
+ host_impl_->DidDrawAllLayers(frame);
+ EXPECT_TRUE(controller.did_draw_frame());
+
+ controller.OnBeginFrame(begin_frame_args);
+ EXPECT_FALSE(controller.did_draw_frame());
+ host_impl_->RemoveVideoFrameController(&controller);
+ host_impl_->DidDrawAllLayers(frame);
+ EXPECT_FALSE(controller.did_draw_frame());
+}
+
+TEST_F(LayerTreeHostImplTest, AddVideoFrameControllerOutsideFrame) {
+ BeginFrameArgs begin_frame_args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
+ FakeVideoFrameController controller;
+
+ host_impl_->WillBeginImplFrame(begin_frame_args);
+ host_impl_->DidFinishImplFrame();
+
+ EXPECT_FALSE(controller.begin_frame_args().IsValid());
+ host_impl_->AddVideoFrameController(&controller);
+ EXPECT_FALSE(controller.begin_frame_args().IsValid());
+
+ begin_frame_args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
+ EXPECT_FALSE(controller.begin_frame_args().IsValid());
+ host_impl_->WillBeginImplFrame(begin_frame_args);
+ EXPECT_TRUE(controller.begin_frame_args().IsValid());
+
+ EXPECT_FALSE(controller.did_draw_frame());
+ LayerTreeHostImpl::FrameData frame;
+ host_impl_->DidDrawAllLayers(frame);
+ EXPECT_TRUE(controller.did_draw_frame());
+
+ controller.OnBeginFrame(begin_frame_args);
+ EXPECT_FALSE(controller.did_draw_frame());
+ host_impl_->RemoveVideoFrameController(&controller);
+ host_impl_->DidDrawAllLayers(frame);
+ EXPECT_FALSE(controller.did_draw_frame());
+}
+
+TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusModes) {
+ EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->SetContentIsSuitableForGpuRasterization(true);
+ EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+
+ host_impl_->SetHasGpuRasterizationTrigger(false);
+ host_impl_->SetContentIsSuitableForGpuRasterization(true);
+ EXPECT_EQ(GpuRasterizationStatus::OFF_VIEWPORT,
+ host_impl_->gpu_rasterization_status());
+ EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->SetContentIsSuitableForGpuRasterization(false);
+ EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+ host_impl_->gpu_rasterization_status());
+ EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+ EXPECT_FALSE(host_impl_->use_msaa());
+
+ scoped_ptr<TestWebGraphicsContext3D> context_with_msaa =
+ TestWebGraphicsContext3D::Create();
+ context_with_msaa->SetMaxSamples(8);
+
+ LayerTreeSettings msaaSettings = GpuRasterizationEnabledSettings();
+ msaaSettings.gpu_rasterization_msaa_sample_count = 4;
+ EXPECT_TRUE(CreateHostImpl(
+ msaaSettings, FakeOutputSurface::Create3d(context_with_msaa.Pass())));
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->SetContentIsSuitableForGpuRasterization(false);
+ EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT,
+ host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl_->use_msaa());
+
+ LayerTreeSettings settings = DefaultSettings();
+ settings.gpu_rasterization_enabled = false;
+ EXPECT_TRUE(CreateHostImpl(settings, FakeOutputSurface::Create3d()));
+ host_impl_->SetHasGpuRasterizationTrigger(true);
+ host_impl_->SetContentIsSuitableForGpuRasterization(true);
+ EXPECT_EQ(GpuRasterizationStatus::OFF_DEVICE,
+ host_impl_->gpu_rasterization_status());
+ EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+
+ settings.gpu_rasterization_forced = true;
+ EXPECT_TRUE(CreateHostImpl(settings, FakeOutputSurface::Create3d()));
+
+ host_impl_->SetHasGpuRasterizationTrigger(false);
+ host_impl_->SetContentIsSuitableForGpuRasterization(false);
+ EXPECT_EQ(GpuRasterizationStatus::ON_FORCED,
+ host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_perftest.cc b/chromium/cc/trees/layer_tree_host_perftest.cc
index b368c558eb2..c8e2a8c02c1 100644
--- a/chromium/cc/trees/layer_tree_host_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_perftest.cc
@@ -242,13 +242,23 @@ class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader {
TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) {
SetTestName("long_scrollable_page");
ReadTestFile("long_scrollable_page");
+ // TODO(vollick): Remove verify_property_trees setting after
+ // crbug.com/444219 is fixed.
+ bool old_verify_property_trees = verify_property_trees();
+ set_verify_property_trees(false);
RunTest(false, false, false);
+ set_verify_property_trees(old_verify_property_trees);
}
TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) {
SetTestName("long_scrollable_page_threaded_impl_side");
ReadTestFile("long_scrollable_page");
+ // TODO(vollick): Remove verify_property_trees setting after
+ // crbug.com/444219 is fixed.
+ bool old_verify_property_trees = verify_property_trees();
+ set_verify_property_trees(false);
RunTestWithImplSidePainting();
+ set_verify_property_trees(old_verify_property_trees);
}
static void EmptyReleaseCallback(uint32 sync_point, bool lost_resource) {}
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
index 7a9ef212383..b31d3e85395 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/layers/image_layer.h"
+#include "cc/layers/picture_image_layer.h"
#include "cc/layers/solid_color_layer.h"
-#include "cc/test/layer_tree_pixel_test.h"
+#include "cc/test/layer_tree_pixel_resource_test.h"
#include "cc/test/pixel_comparator.h"
#if !defined(OS_ANDROID)
@@ -52,25 +52,31 @@ using RenderPassOptions = uint32;
const uint32 kUseMasks = 1 << 0;
const uint32 kUseAntialiasing = 1 << 1;
const uint32 kUseColorMatrix = 1 << 2;
+const uint32 kForceShaders = 1 << 3;
-class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
+class LayerTreeHostBlendingPixelTest : public LayerTreeHostPixelResourceTest {
public:
- LayerTreeHostBlendingPixelTest() {
+ LayerTreeHostBlendingPixelTest()
+ : force_antialiasing_(false), force_blending_with_shaders_(false) {
pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true));
}
- virtual void InitializeSettings(LayerTreeSettings* settings) override {
- settings->force_antialiasing = force_antialiasing_;
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->renderer_settings.force_antialiasing = force_antialiasing_;
+ settings->renderer_settings.force_blending_with_shaders =
+ force_blending_with_shaders_;
}
protected:
- void RunBlendingWithRootPixelTestType(PixelTestType type) {
- const int kLaneWidth = 15;
- const int kLaneHeight = kBlendModesCount * kLaneWidth;
- const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+ void RunBlendingWithRootPixelTestType(PixelResourceTestCase type) {
+ const int kLaneWidth = 2;
+ const int kLaneHeight = kLaneWidth;
+ const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth;
+ const int kRootHeight = 2 * kLaneWidth + kLaneHeight;
+ InitializeFromTestCase(type);
scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange);
+ CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSOrange);
// Orange child layers will blend with the green background
for (int i = 0; i < kBlendModesCount; ++i) {
@@ -82,21 +88,23 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
green_lane->SetBlendMode(kBlendModes[i]);
}
- RunPixelTest(type,
- background,
- base::FilePath(FILE_PATH_LITERAL("blending_with_root.png")));
+ RunPixelResourceTest(
+ background,
+ base::FilePath(FILE_PATH_LITERAL("blending_with_root.png")));
}
- void RunBlendingWithTransparentPixelTestType(PixelTestType type) {
- const int kLaneWidth = 15;
- const int kLaneHeight = kBlendModesCount * kLaneWidth;
- const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+ void RunBlendingWithTransparentPixelTestType(PixelResourceTestCase type) {
+ const int kLaneWidth = 2;
+ const int kLaneHeight = 3 * kLaneWidth;
+ const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth;
+ const int kRootHeight = 2 * kLaneWidth + kLaneHeight;
+ InitializeFromTestCase(type);
scoped_refptr<SolidColorLayer> root =
- CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSBrown);
+ CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSBrown);
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(0, kLaneWidth * 2, kRootSize, kLaneWidth), kCSSOrange);
+ gfx::Rect(0, kLaneWidth * 2, kRootWidth, kLaneWidth), kCSSOrange);
root->AddChild(background);
background->SetIsRootForIsolatedGroup(true);
@@ -111,9 +119,8 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
green_lane->SetBlendMode(kBlendModes[i]);
}
- RunPixelTest(type,
- root,
- base::FilePath(FILE_PATH_LITERAL("blending_transparent.png")));
+ RunPixelResourceTest(
+ root, base::FilePath(FILE_PATH_LITERAL("blending_transparent.png")));
}
scoped_refptr<Layer> CreateColorfulBackdropLayer(int width, int height) {
@@ -130,7 +137,7 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
canvas.drawRect(
SkRect::MakeXYWH(0, i * kLaneHeight, kLaneWidth, kLaneHeight), paint);
}
- scoped_refptr<ImageLayer> layer = ImageLayer::Create();
+ scoped_refptr<PictureImageLayer> layer = PictureImageLayer::Create();
layer->SetIsDrawable(true);
layer->SetBounds(gfx::Size(width, height));
layer->SetBitmap(backing_store);
@@ -138,9 +145,9 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
}
void SetupMaskLayer(scoped_refptr<Layer> layer) {
- const int kMaskOffset = 5;
+ const int kMaskOffset = 2;
gfx::Size bounds = layer->bounds();
- scoped_refptr<ImageLayer> mask = ImageLayer::Create();
+ scoped_refptr<PictureImageLayer> mask = PictureImageLayer::Create();
mask->SetIsDrawable(true);
mask->SetIsMask(true);
mask->SetBounds(bounds);
@@ -162,23 +169,22 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
void SetupColorMatrix(scoped_refptr<Layer> layer) {
FilterOperations filter_operations;
- filter_operations.Append(FilterOperation::CreateSepiaFilter(1.f));
+ filter_operations.Append(FilterOperation::CreateSepiaFilter(.001f));
layer->SetFilters(filter_operations);
}
- void CreateBlendingColorLayers(int width,
- int height,
+ void CreateBlendingColorLayers(int lane_width,
+ int lane_height,
scoped_refptr<Layer> background,
RenderPassOptions flags) {
const int kLanesCount = kBlendModesCount + 4;
- int lane_width = width / kLanesCount;
const SkColor kMiscOpaqueColor = 0xffc86464;
const SkColor kMiscTransparentColor = 0x80c86464;
const SkXfermode::Mode kCoeffBlendMode = SkXfermode::kScreen_Mode;
const SkXfermode::Mode kShaderBlendMode = SkXfermode::kColorBurn_Mode;
// add vertical lanes with each of the blend modes
for (int i = 0; i < kLanesCount; ++i) {
- gfx::Rect child_rect(i * lane_width, 0, lane_width, height);
+ gfx::Rect child_rect(i * lane_width, 0, lane_width, lane_height);
SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
float opacity = 1.f;
SkColor color = kMiscOpaqueColor;
@@ -213,10 +219,13 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
}
}
- void RunBlendingWithRenderPass(PixelTestType type,
+ void RunBlendingWithRenderPass(PixelResourceTestCase type,
const base::FilePath::CharType* expected_path,
RenderPassOptions flags) {
- const int kRootSize = 400;
+ const int kLaneWidth = 8;
+ const int kLaneHeight = kLaneWidth * kCSSTestColorsCount;
+ const int kRootSize = kLaneHeight;
+ InitializeFromTestCase(type);
scoped_refptr<SolidColorLayer> root =
CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), SK_ColorWHITE);
@@ -226,33 +235,23 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
background->SetIsRootForIsolatedGroup(true);
root->AddChild(background);
- CreateBlendingColorLayers(kRootSize, kRootSize, background.get(), flags);
+ CreateBlendingColorLayers(kLaneWidth, kLaneHeight, background.get(), flags);
- this->impl_side_painting_ = false;
this->force_antialiasing_ = (flags & kUseAntialiasing);
+ this->force_blending_with_shaders_ = (flags & kForceShaders);
- if ((flags & kUseAntialiasing) && (type == PIXEL_TEST_GL)) {
- // Anti aliasing causes differences up to 7 pixels at the edges.
- // Several pixels have 9 units difference on the alpha channel.
- int large_error_allowed = (flags & kUseMasks) ? 7 : 9;
+ if ((flags & kUseAntialiasing) && (test_type_ == PIXEL_TEST_GL)) {
+ // Anti aliasing causes differences up to 8 pixels at the edges.
+ int large_error_allowed = 8;
// Blending results might differ with one pixel.
int small_error_allowed = 1;
// Most of the errors are one pixel errors.
- float percentage_pixels_small_error = (flags & kUseMasks) ? 7.7f : 12.1f;
- // Because of anti-aliasing, around 3% of pixels (at the edges) have
+ float percentage_pixels_small_error = 13.1f;
+ // Because of anti-aliasing, around 10% of pixels (at the edges) have
// bigger errors (from small_error_allowed + 1 to large_error_allowed).
- float percentage_pixels_error = (flags & kUseMasks) ? 12.4f : 15.f;
+ float percentage_pixels_error = 22.5f;
// The average error is still close to 1.
- float average_error_allowed_in_bad_pixels =
- (flags & kUseMasks) ? 1.3f : 1.f;
-
- // The sepia filter generates more small errors, but the number of large
- // errors remains around 3%.
- if (flags & kUseColorMatrix) {
- percentage_pixels_small_error = (flags & kUseMasks) ? 14.0f : 26.f;
- percentage_pixels_error = (flags & kUseMasks) ? 18.5f : 29.f;
- average_error_allowed_in_bad_pixels = (flags & kUseMasks) ? 0.9f : 0.7f;
- }
+ float average_error_allowed_in_bad_pixels = 1.4f;
pixel_comparator_.reset(
new FuzzyPixelComparator(false, // discard_alpha
@@ -261,42 +260,32 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
average_error_allowed_in_bad_pixels,
large_error_allowed,
small_error_allowed));
- } else if ((flags & kUseColorMatrix) && (type == PIXEL_TEST_GL)) {
- float percentage_pixels_error = 100.f;
- float percentage_pixels_small_error = 0.f;
- float average_error_allowed_in_bad_pixels = 1.f;
- int large_error_allowed = 2;
- int small_error_allowed = 0;
- pixel_comparator_.reset(
- new FuzzyPixelComparator(false, // discard_alpha
- percentage_pixels_error,
- percentage_pixels_small_error,
- average_error_allowed_in_bad_pixels,
- large_error_allowed,
- small_error_allowed));
}
- RunPixelTest(type, root, base::FilePath(expected_path));
+ RunPixelResourceTest(root, base::FilePath(expected_path));
}
- bool force_antialiasing_ = false;
+ bool force_antialiasing_;
+ bool force_blending_with_shaders_;
};
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) {
- RunBlendingWithRootPixelTestType(PIXEL_TEST_GL);
+ RunBlendingWithRootPixelTestType(GL_ASYNC_UPLOAD_2D_DRAW);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_Software) {
- RunBlendingWithRootPixelTestType(PIXEL_TEST_SOFTWARE);
+ RunBlendingWithRootPixelTestType(SOFTWARE);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) {
- const int kLaneWidth = 15;
- const int kLaneHeight = kBlendModesCount * kLaneWidth;
- const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+ const int kLaneWidth = 2;
+ const int kLaneHeight = kLaneWidth;
+ const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth;
+ const int kRootHeight = 2 * kLaneWidth + kLaneHeight;
+ InitializeFromTestCase(GL_ASYNC_UPLOAD_2D_DRAW);
scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange);
+ CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSOrange);
// Orange child layers have a background filter set and they will blend with
// the green background
@@ -313,124 +302,194 @@ TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) {
green_lane->SetBlendMode(kBlendModes[i]);
}
- RunPixelTest(PIXEL_TEST_GL,
- background,
- base::FilePath(FILE_PATH_LITERAL("blending_and_filter.png")));
+ RunPixelResourceTest(
+ background, base::FilePath(FILE_PATH_LITERAL("blending_and_filter.png")));
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_GL) {
- RunBlendingWithTransparentPixelTestType(PIXEL_TEST_GL);
+ RunBlendingWithTransparentPixelTestType(GL_ASYNC_UPLOAD_2D_DRAW);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_Software) {
- RunBlendingWithTransparentPixelTestType(PIXEL_TEST_SOFTWARE);
+ RunBlendingWithTransparentPixelTestType(SOFTWARE);
}
// Tests for render passes
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_GL) {
- RunBlendingWithRenderPass(
- PIXEL_TEST_GL, FILE_PATH_LITERAL("blending_render_pass.png"), 0);
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass.png"), 0);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_Software) {
- RunBlendingWithRenderPass(
- PIXEL_TEST_SOFTWARE, FILE_PATH_LITERAL("blending_render_pass.png"), 0);
+ RunBlendingWithRenderPass(SOFTWARE,
+ FILE_PATH_LITERAL("blending_render_pass.png"), 0);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_GL) {
- RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
FILE_PATH_LITERAL("blending_render_pass.png"),
kUseAntialiasing);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_Software) {
- RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
+ RunBlendingWithRenderPass(SOFTWARE,
FILE_PATH_LITERAL("blending_render_pass.png"),
kUseAntialiasing);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMask_GL) {
- RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
FILE_PATH_LITERAL("blending_render_pass_mask.png"),
kUseMasks);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMask_Software) {
- RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
- FILE_PATH_LITERAL("blending_render_pass_mask.png"),
- kUseMasks);
+ RunBlendingWithRenderPass(
+ SOFTWARE, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMaskAA_GL) {
- RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
FILE_PATH_LITERAL("blending_render_pass_mask.png"),
kUseMasks | kUseAntialiasing);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMaskAA_Software) {
- RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
+ RunBlendingWithRenderPass(SOFTWARE,
FILE_PATH_LITERAL("blending_render_pass_mask.png"),
kUseMasks | kUseAntialiasing);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrix_GL) {
- RunBlendingWithRenderPass(PIXEL_TEST_GL,
- FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassColorMatrix_Software) {
- RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
- FILE_PATH_LITERAL("blending_render_pass_cm.png"),
- kUseColorMatrix);
+ RunBlendingWithRenderPass(
+ SOFTWARE, FILE_PATH_LITERAL("blending_render_pass.png"), kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrixAA_GL) {
- RunBlendingWithRenderPass(PIXEL_TEST_GL,
- FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
kUseAntialiasing | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassColorMatrixAA_Software) {
- RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
- FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ RunBlendingWithRenderPass(SOFTWARE,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
kUseAntialiasing | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMaskColorMatrix_GL) {
- RunBlendingWithRenderPass(
- PIXEL_TEST_GL,
- FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
- kUseMasks | kUseColorMatrix);
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMaskColorMatrix_Software) {
- RunBlendingWithRenderPass(
- PIXEL_TEST_SOFTWARE,
- FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
- kUseMasks | kUseColorMatrix);
+ RunBlendingWithRenderPass(SOFTWARE,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMaskColorMatrixAA_GL) {
- RunBlendingWithRenderPass(
- PIXEL_TEST_GL,
- FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
- kUseMasks | kUseAntialiasing | kUseColorMatrix);
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMaskColorMatrixAA_Software) {
+ RunBlendingWithRenderPass(SOFTWARE,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix);
+}
+
+// Tests for render passes forcing shaders for all the blend modes.
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShaders_GL) {
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersAA_GL) {
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseAntialiasing | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMask_GL) {
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMask_GL_TextureRect) {
+ RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMaskAA_GL) {
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMaskAA_GL_TextureRect) {
+ RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersColorMatrix_GL) {
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersColorMatrixAA_GL) {
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseAntialiasing | kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMaskColorMatrix_GL) {
+ RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMaskColorMatrix_GL_TextureRect) {
+ RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMaskColorMatrixAA_GL) {
RunBlendingWithRenderPass(
- PIXEL_TEST_SOFTWARE,
- FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
- kUseMasks | kUseAntialiasing | kUseColorMatrix);
+ GL_ASYNC_UPLOAD_2D_DRAW,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix | kForceShaders);
}
} // namespace
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
index 40fa2c3e454..dd3cf733144 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -97,8 +97,8 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOutsets) {
}
TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) {
- scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(200, 200), SK_ColorWHITE);
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorTRANSPARENT);
// This verifies that the perspective of the clear layer (with black border)
// does not influence the blending of the green box behind it. Also verifies
@@ -136,8 +136,8 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) {
blur->SetBackgroundFilters(filters);
#if defined(OS_WIN)
- // Windows has 153 pixels off by at most 2: crbug.com/225027
- float percentage_pixels_large_error = 0.3825f; // 153px / (200*200)
+ // Windows has 116 pixels off by at most 2: crbug.com/225027
+ float percentage_pixels_large_error = 0.3f; // 116px / (200*200), rounded up
float percentage_pixels_small_error = 0.0f;
float average_error_allowed_in_bad_pixels = 1.f;
int large_error_allowed = 2;
@@ -277,6 +277,180 @@ TEST_F(ImageFilterClippedPixelTest, ImageFilterClipped_Software) {
RunPixelTestType(PIXEL_TEST_SOFTWARE);
}
+TEST_F(LayerTreeHostFiltersPixelTest, ImageFilterScaled_GL) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
+
+ gfx::Rect rect(50, 50, 100, 100);
+
+ const int kInset = 3;
+ for (int i = 0; !rect.IsEmpty(); ++i) {
+ scoped_refptr<SolidColorLayer> layer =
+ CreateSolidColorLayer(rect, (i & 1) ? SK_ColorWHITE : SK_ColorRED);
+
+ gfx::Transform transform;
+ transform.Translate(rect.width() / 2.0, rect.height() / 2.0);
+ transform.RotateAboutZAxis(30.0);
+ transform.Translate(-rect.width() / 2.0, -rect.height() / 2.0);
+ layer->SetTransform(transform);
+
+ background->AddChild(layer);
+
+ rect.Inset(kInset, kInset);
+ }
+
+ scoped_refptr<SolidColorLayer> filter =
+ CreateSolidColorLayer(gfx::Rect(100, 0, 100, 200), SK_ColorTRANSPARENT);
+
+ background->AddChild(filter);
+
+ // Apply a scale to |background| so that we can see any scaling artifacts that
+ // may appear.
+ gfx::Transform background_transform;
+ static float scale = 1.1f;
+ background_transform.Scale(scale, scale);
+ background->SetTransform(background_transform);
+
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateGrayscaleFilter(1.0f));
+ filter->SetBackgroundFilters(filters);
+
+#if defined(OS_WIN)
+ // Windows has 153 pixels off by at most 2: crbug.com/225027
+ float percentage_pixels_large_error = 0.3825f; // 153px / (200*200)
+ float percentage_pixels_small_error = 0.0f;
+ float average_error_allowed_in_bad_pixels = 1.f;
+ int large_error_allowed = 2;
+ int small_error_allowed = 0;
+ pixel_comparator_.reset(new FuzzyPixelComparator(
+ true, // discard_alpha
+ percentage_pixels_large_error, percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels, large_error_allowed,
+ small_error_allowed));
+#endif
+
+ // TODO(hendrikw): Enable test in software as well: crbug.com/432157
+ RunPixelTest(PIXEL_TEST_GL, background,
+ base::FilePath(FILE_PATH_LITERAL("filter_on_scaled_layer.png")));
+}
+
+class ImageScaledRenderSurface : public LayerTreeHostFiltersPixelTest {
+ protected:
+ void RunPixelTestType(PixelTestType test_type, base::FilePath image_name) {
+ // A filter will cause a render surface to be used. Here we force the
+ // render surface on, and scale the result to make sure that we rasterize at
+ // the correct resolution.
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(300, 300), SK_ColorBLUE);
+
+ scoped_refptr<SolidColorLayer> render_surface_layer =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
+
+ gfx::Rect rect(50, 50, 100, 100);
+
+ scoped_refptr<SolidColorLayer> child =
+ CreateSolidColorLayer(rect, SK_ColorRED);
+
+ gfx::Transform transform;
+ transform.Translate(rect.width() / 2.0, rect.height() / 2.0);
+ transform.RotateAboutZAxis(30.0);
+ transform.Translate(-rect.width() / 2.0, -rect.height() / 2.0);
+ child->SetTransform(transform);
+
+ render_surface_layer->AddChild(child);
+
+ gfx::Transform render_surface_transform;
+ render_surface_transform.Scale(1.5f, 1.5f);
+ render_surface_layer->SetTransform(render_surface_transform);
+ render_surface_layer->SetForceRenderSurface(true);
+
+ background->AddChild(render_surface_layer);
+
+ // Software has some huge differences in the AA'd pixels on the different
+ // trybots. See crbug.com/452198.
+ float percentage_pixels_large_error = 0.686f;
+ float percentage_pixels_small_error = 0.0f;
+ float average_error_allowed_in_bad_pixels = 16.f;
+ int large_error_allowed = 17;
+ int small_error_allowed = 0;
+ pixel_comparator_.reset(new FuzzyPixelComparator(
+ true, // discard_alpha
+ percentage_pixels_large_error, percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels, large_error_allowed,
+ small_error_allowed));
+
+ RunPixelTest(test_type, background, image_name);
+ }
+};
+
+TEST_F(ImageScaledRenderSurface, ImageRenderSurfaceScaled_GL) {
+ RunPixelTestType(
+ PIXEL_TEST_GL,
+ base::FilePath(FILE_PATH_LITERAL("scaled_render_surface_layer_gl.png")));
+}
+
+TEST_F(ImageScaledRenderSurface, ImageRenderSurfaceScaled_Software) {
+ RunPixelTestType(
+ PIXEL_TEST_SOFTWARE,
+ base::FilePath(FILE_PATH_LITERAL("scaled_render_surface_layer_sw.png")));
+}
+
+class EnlargedTextureWithAlphaThresholdFilter
+ : public LayerTreeHostFiltersPixelTest {
+ protected:
+ void RunPixelTestType(PixelTestType test_type, base::FilePath image_name) {
+ // Rectangles choosen so that if flipped, the test will fail.
+ gfx::Rect rect1(10, 10, 10, 15);
+ gfx::Rect rect2(20, 25, 70, 65);
+
+ scoped_refptr<SolidColorLayer> child1 =
+ CreateSolidColorLayer(rect1, SK_ColorRED);
+ scoped_refptr<SolidColorLayer> child2 =
+ CreateSolidColorLayer(rect2, SK_ColorGREEN);
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLUE);
+ scoped_refptr<SolidColorLayer> filter_layer =
+ CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
+
+ // Make sure a transformation does not cause misregistration of the filter
+ // and source texture.
+ gfx::Transform filter_transform;
+ filter_transform.Scale(2.f, 2.f);
+ filter_layer->SetTransform(filter_transform);
+ filter_layer->AddChild(child1);
+ filter_layer->AddChild(child2);
+
+ rect1.Inset(-5, -5);
+ rect2.Inset(-5, -5);
+ SkRegion alpha_region;
+ SkIRect rects[2] = {gfx::RectToSkIRect(rect1), gfx::RectToSkIRect(rect2)};
+ alpha_region.setRects(rects, 2);
+ FilterOperations filters;
+ filters.Append(
+ FilterOperation::CreateAlphaThresholdFilter(alpha_region, 0.f, 0.f));
+ filter_layer->SetFilters(filters);
+
+ background->AddChild(filter_layer);
+
+ // Force the allocation a larger textures.
+ set_enlarge_texture_amount(gfx::Vector2d(50, 50));
+
+ RunPixelTest(test_type, background, image_name);
+ }
+};
+
+TEST_F(EnlargedTextureWithAlphaThresholdFilter, GL) {
+ RunPixelTestType(
+ PIXEL_TEST_GL,
+ base::FilePath(FILE_PATH_LITERAL("enlarged_texture_on_threshold.png")));
+}
+
+TEST_F(EnlargedTextureWithAlphaThresholdFilter, Software) {
+ RunPixelTestType(
+ PIXEL_TEST_SOFTWARE,
+ base::FilePath(FILE_PATH_LITERAL("enlarged_texture_on_threshold.png")));
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
index f4f174c4981..0cb6aeaa846 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -24,14 +24,11 @@ class MaskContentLayerClient : public ContentLayerClient {
explicit MaskContentLayerClient(const gfx::Size& bounds) : bounds_(bounds) {}
~MaskContentLayerClient() override {}
- void DidChangeLayerCanUseLCDText() override {}
-
bool FillsBoundsCompletely() const override { return false; }
- void PaintContents(
- SkCanvas* canvas,
- const gfx::Rect& rect,
- ContentLayerClient::GraphicsContextStatus gc_status) override {
+ void PaintContents(SkCanvas* canvas,
+ const gfx::Rect& rect,
+ PaintingControlSetting picture_control) override {
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(SkIntToScalar(2));
@@ -49,19 +46,26 @@ class MaskContentLayerClient : public ContentLayerClient {
}
}
+ void PaintContentsToDisplayList(
+ DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ PaintingControlSetting picture_control) override {
+ NOTIMPLEMENTED();
+ }
+
private:
gfx::Size bounds_;
};
TEST_P(LayerTreeHostMasksPixelTest, MaskOfLayer) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(200, 200), SK_ColorWHITE);
+ gfx::Rect(100, 100), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
- gfx::Rect(50, 50, 100, 100), kCSSGreen, 1, SK_ColorBLACK);
+ gfx::Rect(25, 25, 50, 50), kCSSGreen, 1, SK_ColorBLACK);
background->AddChild(green);
- gfx::Size mask_bounds(100, 100);
+ gfx::Size mask_bounds(50, 50);
MaskContentLayerClient client(mask_bounds);
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
mask->SetBounds(mask_bounds);
@@ -75,9 +79,9 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfLayer) {
TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(200, 200), SK_ColorWHITE);
+ gfx::Rect(100, 100), SK_ColorWHITE);
- gfx::Size mask_bounds(100, 100);
+ gfx::Size mask_bounds(50, 50);
scoped_refptr<PictureImageLayer> mask = PictureImageLayer::Create();
mask->SetIsDrawable(true);
@@ -85,17 +89,16 @@ TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
mask->SetBounds(mask_bounds);
SkBitmap bitmap;
- bitmap.allocN32Pixels(400, 400);
+ bitmap.allocN32Pixels(200, 200);
SkCanvas canvas(bitmap);
canvas.scale(SkIntToScalar(4), SkIntToScalar(4));
MaskContentLayerClient client(mask_bounds);
- client.PaintContents(&canvas,
- gfx::Rect(mask_bounds),
- ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
+ client.PaintContents(&canvas, gfx::Rect(mask_bounds),
+ ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
mask->SetBitmap(bitmap);
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
- gfx::Rect(50, 50, 100, 100), kCSSGreen, 1, SK_ColorBLACK);
+ gfx::Rect(25, 25, 50, 50), kCSSGreen, 1, SK_ColorBLACK);
green->SetMaskLayer(mask.get());
background->AddChild(green);
@@ -105,20 +108,20 @@ TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
TEST_P(LayerTreeHostMasksPixelTest, MaskOfClippedLayer) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(200, 200), SK_ColorWHITE);
+ gfx::Rect(100, 100), SK_ColorWHITE);
// Clip to the top half of the green layer.
scoped_refptr<Layer> clip = Layer::Create();
clip->SetPosition(gfx::Point(0, 0));
- clip->SetBounds(gfx::Size(200, 100));
+ clip->SetBounds(gfx::Size(100, 50));
clip->SetMasksToBounds(true);
background->AddChild(clip);
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
- gfx::Rect(50, 50, 100, 100), kCSSGreen, 1, SK_ColorBLACK);
+ gfx::Rect(25, 25, 50, 50), kCSSGreen, 1, SK_ColorBLACK);
clip->AddChild(green);
- gfx::Size mask_bounds(100, 100);
+ gfx::Size mask_bounds(50, 50);
MaskContentLayerClient client(mask_bounds);
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
mask->SetBounds(mask_bounds);
@@ -133,9 +136,9 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfClippedLayer) {
TEST_P(LayerTreeHostMasksPixelTest, MaskWithReplica) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(200, 200), SK_ColorWHITE);
+ gfx::Rect(100, 100), SK_ColorWHITE);
- gfx::Size mask_bounds(100, 100);
+ gfx::Size mask_bounds(50, 50);
MaskContentLayerClient client(mask_bounds);
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
mask->SetBounds(mask_bounds);
@@ -143,7 +146,7 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskWithReplica) {
mask->SetIsMask(true);
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
- gfx::Rect(0, 0, 100, 100), kCSSGreen, 1, SK_ColorBLACK);
+ gfx::Rect(0, 0, 50, 50), kCSSGreen, 1, SK_ColorBLACK);
background->AddChild(green);
green->SetMaskLayer(mask.get());
@@ -151,8 +154,8 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskWithReplica) {
replica_transform.Rotate(-90.0);
scoped_refptr<Layer> replica = Layer::Create();
- replica->SetTransformOrigin(gfx::Point3F(50.f, 50.f, 0.f));
- replica->SetPosition(gfx::Point(100, 100));
+ replica->SetTransformOrigin(gfx::Point3F(25.f, 25.f, 0.f));
+ replica->SetPosition(gfx::Point(50, 50));
replica->SetTransform(replica_transform);
green->SetReplicaLayer(replica.get());
@@ -162,9 +165,9 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskWithReplica) {
TEST_P(LayerTreeHostMasksPixelTest, MaskWithReplicaOfClippedLayer) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(200, 200), SK_ColorWHITE);
+ gfx::Rect(100, 100), SK_ColorWHITE);
- gfx::Size mask_bounds(100, 100);
+ gfx::Size mask_bounds(50, 50);
MaskContentLayerClient client(mask_bounds);
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
mask->SetBounds(mask_bounds);
@@ -174,13 +177,13 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskWithReplicaOfClippedLayer) {
// Clip to the bottom half of the green layer, and the left half of the
// replica.
scoped_refptr<Layer> clip = Layer::Create();
- clip->SetPosition(gfx::Point(0, 50));
- clip->SetBounds(gfx::Size(150, 150));
+ clip->SetPosition(gfx::Point(0, 25));
+ clip->SetBounds(gfx::Size(75, 75));
clip->SetMasksToBounds(true);
background->AddChild(clip);
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
- gfx::Rect(0, -50, 100, 100), kCSSGreen, 1, SK_ColorBLACK);
+ gfx::Rect(0, -25, 50, 50), kCSSGreen, 1, SK_ColorBLACK);
clip->AddChild(green);
green->SetMaskLayer(mask.get());
@@ -188,8 +191,8 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskWithReplicaOfClippedLayer) {
replica_transform.Rotate(-90.0);
scoped_refptr<Layer> replica = Layer::Create();
- replica->SetTransformOrigin(gfx::Point3F(50.f, 50.f, 0.f));
- replica->SetPosition(gfx::Point(100, 100));
+ replica->SetTransformOrigin(gfx::Point3F(25.f, 25.f, 0.f));
+ replica->SetPosition(gfx::Point(50, 50));
replica->SetTransform(replica_transform);
green->SetReplicaLayer(replica.get());
@@ -200,9 +203,9 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskWithReplicaOfClippedLayer) {
TEST_P(LayerTreeHostMasksPixelTest, MaskOfReplica) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(200, 200), SK_ColorWHITE);
+ gfx::Rect(100, 100), SK_ColorWHITE);
- gfx::Size mask_bounds(100, 100);
+ gfx::Size mask_bounds(50, 50);
MaskContentLayerClient client(mask_bounds);
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
mask->SetBounds(mask_bounds);
@@ -210,19 +213,19 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfReplica) {
mask->SetIsMask(true);
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
- gfx::Rect(50, 0, 100, 100), kCSSGreen, 1, SK_ColorBLACK);
+ gfx::Rect(25, 0, 50, 50), kCSSGreen, 1, SK_ColorBLACK);
background->AddChild(green);
scoped_refptr<SolidColorLayer> orange = CreateSolidColorLayer(
- gfx::Rect(-50, 50, 50, 50), kCSSOrange);
+ gfx::Rect(-25, 25, 25, 25), kCSSOrange);
green->AddChild(orange);
gfx::Transform replica_transform;
replica_transform.Rotate(180.0);
- replica_transform.Translate(100.0, 0.0);
+ replica_transform.Translate(50.0, 0.0);
scoped_refptr<Layer> replica = Layer::Create();
- replica->SetTransformOrigin(gfx::Point3F(100.f, 100.f, 0.f));
+ replica->SetTransformOrigin(gfx::Point3F(50.f, 50.f, 0.f));
replica->SetPosition(gfx::Point());
replica->SetTransform(replica_transform);
replica->SetMaskLayer(mask.get());
@@ -234,9 +237,9 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfReplica) {
TEST_P(LayerTreeHostMasksPixelTest, MaskOfReplicaOfClippedLayer) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(200, 200), SK_ColorWHITE);
+ gfx::Rect(100, 100), SK_ColorWHITE);
- gfx::Size mask_bounds(100, 100);
+ gfx::Size mask_bounds(50, 50);
MaskContentLayerClient client(mask_bounds);
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
mask->SetBounds(mask_bounds);
@@ -245,25 +248,25 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfReplicaOfClippedLayer) {
// Clip to the bottom 3/4 of the green layer, and the top 3/4 of the replica.
scoped_refptr<Layer> clip = Layer::Create();
- clip->SetPosition(gfx::Point(0, 25));
- clip->SetBounds(gfx::Size(200, 150));
+ clip->SetPosition(gfx::Point(0, 12));
+ clip->SetBounds(gfx::Size(100, 75));
clip->SetMasksToBounds(true);
background->AddChild(clip);
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
- gfx::Rect(50, -25, 100, 100), kCSSGreen, 1, SK_ColorBLACK);
+ gfx::Rect(25, -12, 50, 50), kCSSGreen, 1, SK_ColorBLACK);
clip->AddChild(green);
scoped_refptr<SolidColorLayer> orange = CreateSolidColorLayer(
- gfx::Rect(-50, 50, 50, 50), kCSSOrange);
+ gfx::Rect(-25, 25, 25, 25), kCSSOrange);
green->AddChild(orange);
gfx::Transform replica_transform;
replica_transform.Rotate(180.0);
- replica_transform.Translate(100.0, 0.0);
+ replica_transform.Translate(50.0, 0.0);
scoped_refptr<Layer> replica = Layer::Create();
- replica->SetTransformOrigin(gfx::Point3F(100.f, 100.f, 0.f));
+ replica->SetTransformOrigin(gfx::Point3F(50.f, 50.f, 0.f));
replica->SetPosition(gfx::Point());
replica->SetTransform(replica_transform);
replica->SetMaskLayer(mask.get());
@@ -274,7 +277,189 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfReplicaOfClippedLayer) {
"mask_of_replica_of_clipped_layer.png")));
}
+class CheckerContentLayerClient : public ContentLayerClient {
+ public:
+ CheckerContentLayerClient(const gfx::Size& bounds,
+ SkColor color,
+ bool vertical)
+ : bounds_(bounds), color_(color), vertical_(vertical) {}
+ ~CheckerContentLayerClient() override {}
+ bool FillsBoundsCompletely() const override { return false; }
+ void PaintContents(SkCanvas* canvas,
+ const gfx::Rect& rect,
+ PaintingControlSetting picture_control) override {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(4));
+ paint.setColor(color_);
+ canvas->clear(SK_ColorTRANSPARENT);
+ if (vertical_) {
+ for (int i = 4; i < bounds_.width(); i += 16) {
+ canvas->drawLine(i, 0, i, bounds_.height(), paint);
+ }
+ } else {
+ for (int i = 4; i < bounds_.height(); i += 16) {
+ canvas->drawLine(0, i, bounds_.width(), i, paint);
+ }
+ }
+ }
+ void PaintContentsToDisplayList(
+ DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ PaintingControlSetting picture_control) override {
+ NOTIMPLEMENTED();
+ }
+
+ private:
+ gfx::Size bounds_;
+ SkColor color_;
+ bool vertical_;
+};
+
+class CircleContentLayerClient : public ContentLayerClient {
+ public:
+ explicit CircleContentLayerClient(const gfx::Size& bounds)
+ : bounds_(bounds) {}
+ ~CircleContentLayerClient() override {}
+ bool FillsBoundsCompletely() const override { return false; }
+ void PaintContents(SkCanvas* canvas,
+ const gfx::Rect& rect,
+ PaintingControlSetting picture_control) override {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(SK_ColorWHITE);
+ canvas->clear(SK_ColorTRANSPARENT);
+ canvas->drawCircle(bounds_.width() / 2,
+ bounds_.height() / 2,
+ bounds_.width() / 4,
+ paint);
+ }
+ void PaintContentsToDisplayList(
+ DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ PaintingControlSetting picture_control) override {
+ NOTIMPLEMENTED();
+ }
+
+ private:
+ gfx::Size bounds_;
+};
+
+using LayerTreeHostMasksForBackgroundFiltersPixelTest =
+ ParameterizedPixelResourceTest;
+
+INSTANTIATE_TEST_CASE_P(
+ PixelResourceTest,
+ LayerTreeHostMasksForBackgroundFiltersPixelTest,
+ ::testing::Values(
+ // SOFTWARE, Background filters aren't implemented in software
+ GL_GPU_RASTER_2D_DRAW,
+ GL_ONE_COPY_2D_STAGING_2D_DRAW,
+ GL_ONE_COPY_RECT_STAGING_2D_DRAW,
+ GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW,
+ GL_ZERO_COPY_2D_DRAW,
+ GL_ZERO_COPY_RECT_DRAW,
+ GL_ZERO_COPY_EXTERNAL_DRAW,
+ GL_ASYNC_UPLOAD_2D_DRAW));
+
+TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest,
+ MaskOfLayerWithBackgroundFilter) {
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(100, 100), SK_ColorWHITE);
+
+ gfx::Size picture_bounds(100, 100);
+ CheckerContentLayerClient picture_client(picture_bounds, SK_ColorGREEN, true);
+ scoped_refptr<PictureLayer> picture = PictureLayer::Create(&picture_client);
+ picture->SetBounds(picture_bounds);
+ picture->SetIsDrawable(true);
+
+ scoped_refptr<SolidColorLayer> blur = CreateSolidColorLayer(
+ gfx::Rect(100, 100), SK_ColorTRANSPARENT);
+ background->AddChild(picture);
+ background->AddChild(blur);
+
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateBlurFilter(1.5f));
+ blur->SetBackgroundFilters(filters);
+
+ gfx::Size mask_bounds(100, 100);
+ CircleContentLayerClient mask_client(mask_bounds);
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&mask_client);
+ mask->SetBounds(mask_bounds);
+ mask->SetIsDrawable(true);
+ mask->SetIsMask(true);
+ blur->SetMaskLayer(mask.get());
+
+ float percentage_pixels_large_error = 2.5f; // 2.5%, ~250px / (100*100)
+ float percentage_pixels_small_error = 0.0f;
+ float average_error_allowed_in_bad_pixels = 100.0f;
+ int large_error_allowed = 256;
+ int small_error_allowed = 0;
+ pixel_comparator_.reset(new FuzzyPixelComparator(
+ true, // discard_alpha
+ percentage_pixels_large_error,
+ percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels,
+ large_error_allowed,
+ small_error_allowed));
+
+ RunPixelResourceTest(background,
+ base::FilePath(
+ FILE_PATH_LITERAL("mask_of_background_filter.png")));
+}
+
+TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest,
+ MaskOfLayerWithBlend) {
+ scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
+ gfx::Rect(128, 128), SK_ColorWHITE);
+
+ gfx::Size picture_bounds(128, 128);
+ CheckerContentLayerClient picture_client_vertical(
+ picture_bounds, SK_ColorGREEN, true);
+ scoped_refptr<PictureLayer> picture_vertical =
+ PictureLayer::Create(&picture_client_vertical);
+ picture_vertical->SetBounds(picture_bounds);
+ picture_vertical->SetIsDrawable(true);
+
+ CheckerContentLayerClient picture_client_horizontal(
+ picture_bounds, SK_ColorMAGENTA, false);
+ scoped_refptr<PictureLayer> picture_horizontal =
+ PictureLayer::Create(&picture_client_horizontal);
+ picture_horizontal->SetBounds(picture_bounds);
+ picture_horizontal->SetIsDrawable(true);
+ picture_horizontal->SetContentsOpaque(false);
+ picture_horizontal->SetBlendMode(SkXfermode::kMultiply_Mode);
+
+ background->AddChild(picture_vertical);
+ background->AddChild(picture_horizontal);
+
+ gfx::Size mask_bounds(128, 128);
+ CircleContentLayerClient mask_client(mask_bounds);
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&mask_client);
+ mask->SetBounds(mask_bounds);
+ mask->SetIsDrawable(true);
+ mask->SetIsMask(true);
+ picture_horizontal->SetMaskLayer(mask.get());
+
+ float percentage_pixels_large_error = 0.04f; // 0.04%, ~6px / (128*128)
+ float percentage_pixels_small_error = 0.0f;
+ float average_error_allowed_in_bad_pixels = 256.0f;
+ int large_error_allowed = 256;
+ int small_error_allowed = 0;
+ pixel_comparator_.reset(new FuzzyPixelComparator(
+ true, // discard_alpha
+ percentage_pixels_large_error,
+ percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels,
+ large_error_allowed,
+ small_error_allowed));
+
+ RunPixelResourceTest(background,
+ base::FilePath(
+ FILE_PATH_LITERAL("mask_of_layer_with_blend.png")));
+}
+
} // namespace
} // namespace cc
-#endif // OS_ANDROID
+#endif // !defined(OS_ANDROID)
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc b/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
deleted file mode 100644
index d703e22a31c..00000000000
--- a/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/layers/append_quads_data.h"
-#include "cc/layers/content_layer_client.h"
-#include "cc/layers/picture_layer.h"
-#include "cc/layers/picture_layer_impl.h"
-#include "cc/quads/draw_quad.h"
-#include "cc/test/layer_tree_pixel_test.h"
-#include "cc/trees/layer_tree_impl.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-#if !defined(OS_ANDROID)
-
-namespace cc {
-namespace {
-
-class LayerTreeHostOnDemandRasterPixelTest : public LayerTreePixelTest {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->impl_side_painting = true;
- }
-
- void BeginCommitOnThread(LayerTreeHostImpl* impl) override {
- // Not enough memory available. Enforce on-demand rasterization.
- impl->SetMemoryPolicy(
- ManagedMemoryPolicy(1, gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
- 1000));
- }
-
- void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
- // Find the PictureLayerImpl ask it to append quads to check their material.
- // The PictureLayerImpl is assumed to be the first child of the root layer
- // in the active tree.
- PictureLayerImpl* picture_layer = static_cast<PictureLayerImpl*>(
- host_impl->active_tree()->root_layer()->child_at(0));
-
- scoped_ptr<RenderPass> render_pass = RenderPass::Create();
-
- AppendQuadsData data;
- picture_layer->AppendQuads(render_pass.get(), Occlusion(), &data);
-
- for (const auto& quad : render_pass->quad_list)
- EXPECT_EQ(quad->material, DrawQuad::PICTURE_CONTENT);
-
- // Triggers pixel readback and ends the test.
- LayerTreePixelTest::SwapBuffersOnThread(host_impl, result);
- }
-
- void RunOnDemandRasterPixelTest();
-};
-
-class BlueYellowLayerClient : public ContentLayerClient {
- public:
- explicit BlueYellowLayerClient(gfx::Rect layer_rect)
- : layer_rect_(layer_rect) {}
-
- void DidChangeLayerCanUseLCDText() override {}
-
- bool FillsBoundsCompletely() const override { return false; }
-
- void PaintContents(
- SkCanvas* canvas,
- const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus gc_status) override {
- SkPaint paint;
- paint.setColor(SK_ColorBLUE);
- canvas->drawRect(SkRect::MakeWH(layer_rect_.width(),
- layer_rect_.height() / 2),
- paint);
-
- paint.setColor(SK_ColorYELLOW);
- canvas->drawRect(
- SkRect::MakeXYWH(0,
- layer_rect_.height() / 2,
- layer_rect_.width(),
- layer_rect_.height() / 2),
- paint);
- }
-
- private:
- gfx::Rect layer_rect_;
-};
-
-void LayerTreeHostOnDemandRasterPixelTest::RunOnDemandRasterPixelTest() {
- // Use multiple colors in a single layer to prevent bypassing on-demand
- // rasterization if a single solid color is detected in picture analysis.
- gfx::Rect layer_rect(200, 200);
- BlueYellowLayerClient client(layer_rect);
- scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
-
- layer->SetIsDrawable(true);
- layer->SetBounds(layer_rect.size());
- layer->SetPosition(layer_rect.origin());
-
- RunPixelTest(PIXEL_TEST_GL,
- layer,
- base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")));
-}
-
-TEST_F(LayerTreeHostOnDemandRasterPixelTest, RasterPictureLayer) {
- RunOnDemandRasterPixelTest();
-}
-
-class LayerTreeHostOnDemandRasterPixelTestWithGpuRasterizationForced
- : public LayerTreeHostOnDemandRasterPixelTest {
- void InitializeSettings(LayerTreeSettings* settings) override {
- LayerTreeHostOnDemandRasterPixelTest::InitializeSettings(settings);
- settings->gpu_rasterization_forced = true;
- }
-};
-
-TEST_F(LayerTreeHostOnDemandRasterPixelTestWithGpuRasterizationForced,
- RasterPictureLayer) {
- RunOnDemandRasterPixelTest();
-}
-
-} // namespace
-} // namespace cc
-
-#endif // OS_ANDROID
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
index 0a06144e87c..b3729047aa5 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
@@ -19,18 +19,30 @@
namespace cc {
namespace {
-class LayerTreeHostReadbackPixelTest : public LayerTreePixelTest {
+// Can't templatize a class on its own members, so ReadbackType and
+// ReadbackTestConfig are declared here, before LayerTreeHostReadbackPixelTest.
+enum ReadbackType {
+ READBACK_INVALID,
+ READBACK_DEFAULT,
+ READBACK_BITMAP,
+};
+
+struct ReadbackTestConfig {
+ ReadbackTestConfig(LayerTreePixelTest::PixelTestType pixel_test_type_,
+ ReadbackType readback_type_)
+ : pixel_test_type(pixel_test_type_), readback_type(readback_type_) {}
+ LayerTreePixelTest::PixelTestType pixel_test_type;
+ ReadbackType readback_type;
+};
+
+class LayerTreeHostReadbackPixelTest
+ : public LayerTreePixelTest,
+ public testing::WithParamInterface<ReadbackTestConfig> {
protected:
LayerTreeHostReadbackPixelTest()
: readback_type_(READBACK_INVALID),
insert_copy_request_after_frame_count_(0) {}
- enum ReadbackType {
- READBACK_INVALID,
- READBACK_DEFAULT,
- READBACK_BITMAP,
- };
-
void RunReadbackTest(PixelTestType test_type,
ReadbackType readback_type,
scoped_refptr<Layer> content_root,
@@ -124,63 +136,7 @@ class LayerTreeHostReadbackPixelTest : public LayerTreePixelTest {
void IgnoreReadbackResult(scoped_ptr<CopyOutputResult> result) {
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_Software) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- background->AddChild(green);
-
- RunReadbackTest(PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_Software_Bitmap) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- background->AddChild(green);
-
- RunReadbackTest(PIXEL_TEST_SOFTWARE,
- READBACK_BITMAP,
- background,
- base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_GL_Bitmap) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- background->AddChild(green);
-
- RunReadbackTest(PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
- base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- background->AddChild(green);
-
- RunReadbackTest(PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackRootLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -188,18 +144,11 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_Software) {
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
background->AddChild(green);
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
- green->AddChild(blue);
-
- RunReadbackTest(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
+ RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type,
+ background, base::FilePath(FILE_PATH_LITERAL("green.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_GL_Bitmap) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -212,32 +161,11 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_GL_Bitmap) {
green->AddChild(blue);
RunReadbackTest(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- background->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
- green->AddChild(blue);
-
- RunReadbackTest(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -246,62 +174,11 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_Software) {
background->AddChild(green);
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green.png")));
+ GetParam().pixel_test_type, GetParam().readback_type, background,
+ green.get(), base::FilePath(FILE_PATH_LITERAL("green.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_GL_Bitmap) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- background->AddChild(green);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- background->AddChild(green);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer_Software) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
- background->AddChild(green);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer_GL_Bitmap) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -310,52 +187,11 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer_GL_Bitmap) {
background->AddChild(green);
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small.png")));
+ GetParam().pixel_test_type, GetParam().readback_type, background,
+ green.get(), base::FilePath(FILE_PATH_LITERAL("green_small.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
- background->AddChild(green);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
- ReadbackSmallNonRootLayerWithChild_Software) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
- background->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
- green->AddChild(blue);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
- ReadbackSmallNonRootLayerWithChild_GL_Bitmap) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -368,35 +204,12 @@ TEST_F(LayerTreeHostReadbackPixelTest,
green->AddChild(blue);
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
green.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
- background->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
- green->AddChild(blue);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
- ReadbackSubtreeSurroundsTargetLayer_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubtreeSurroundsTargetLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
@@ -414,92 +227,13 @@ TEST_F(LayerTreeHostReadbackPixelTest,
copy_subrect_ = gfx::Rect(0, 0, 100, 100);
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
- ReadbackSubtreeSurroundsLayer_GL_Bitmap) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> target =
- CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorRED);
- background->AddChild(target);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(-100, -100, 300, 300), SK_ColorGREEN);
- target->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
- target->AddChild(blue);
-
- copy_subrect_ = gfx::Rect(0, 0, 100, 100);
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
- target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubtreeSurroundsTargetLayer_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> target =
- CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorRED);
- background->AddChild(target);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(-100, -100, 300, 300), SK_ColorGREEN);
- target->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
- target->AddChild(blue);
-
- copy_subrect_ = gfx::Rect(0, 0, 100, 100);
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
- ReadbackSubtreeExtendsBeyondTargetLayer_Software) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> target =
- CreateSolidColorLayer(gfx::Rect(50, 50, 150, 150), SK_ColorRED);
- background->AddChild(target);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(50, 50, 200, 200), SK_ColorGREEN);
- target->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
- target->AddChild(blue);
-
- copy_subrect_ = gfx::Rect(50, 50, 100, 100);
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
target.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest,
- ReadbackSubtreeExtendsBeyondTargetLayer_GL_Bitmap) {
+TEST_P(LayerTreeHostReadbackPixelTest,
+ ReadbackSubtreeExtendsBeyondTargetLayer) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
@@ -517,40 +251,12 @@ TEST_F(LayerTreeHostReadbackPixelTest,
copy_subrect_ = gfx::Rect(50, 50, 100, 100);
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
target.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest,
- ReadbackSubtreeExtendsBeyondTargetLayer_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> target =
- CreateSolidColorLayer(gfx::Rect(50, 50, 150, 150), SK_ColorRED);
- background->AddChild(target);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(50, 50, 200, 200), SK_ColorGREEN);
- target->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
- target->AddChild(blue);
-
- copy_subrect_ = gfx::Rect(50, 50, 100, 100);
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
@@ -564,57 +270,13 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_Software) {
hidden_target->AddChild(blue);
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
hidden_target.get(),
base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_GL_Bitmap) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
-
- scoped_refptr<SolidColorLayer> hidden_target =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- hidden_target->SetHideLayerAndSubtree(true);
- background->AddChild(hidden_target);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
- hidden_target->AddChild(blue);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
- hidden_target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
-
- scoped_refptr<SolidColorLayer> hidden_target =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- hidden_target->SetHideLayerAndSubtree(true);
- background->AddChild(hidden_target);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
- hidden_target->AddChild(blue);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- hidden_target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
- HiddenSubtreeNotVisibleWhenDrawnForReadback_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest,
+ HiddenSubtreeNotVisibleWhenDrawnForReadback) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
@@ -629,101 +291,11 @@ TEST_F(LayerTreeHostReadbackPixelTest,
hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
base::Bind(&IgnoreReadbackResult)));
- RunReadbackTest(PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- base::FilePath(FILE_PATH_LITERAL("black.png")));
+ RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type,
+ background, base::FilePath(FILE_PATH_LITERAL("black.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest,
- HiddenSubtreeNotVisibleWhenDrawnForReadback_GL_Bitmap) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
-
- scoped_refptr<SolidColorLayer> hidden_target =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- hidden_target->SetHideLayerAndSubtree(true);
- background->AddChild(hidden_target);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
- hidden_target->AddChild(blue);
-
- hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
- base::Bind(&IgnoreReadbackResult)));
- RunReadbackTest(PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
- base::FilePath(FILE_PATH_LITERAL("black.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
- HiddenSubtreeNotVisibleWhenDrawnForReadback_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
-
- scoped_refptr<SolidColorLayer> hidden_target =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- hidden_target->SetHideLayerAndSubtree(true);
- background->AddChild(hidden_target);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
- hidden_target->AddChild(blue);
-
- hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
- base::Bind(&IgnoreReadbackResult)));
- RunReadbackTest(PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- base::FilePath(FILE_PATH_LITERAL("black.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubrect_Software) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- background->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
- green->AddChild(blue);
-
- // Grab the middle of the root layer.
- copy_subrect_ = gfx::Rect(50, 50, 100, 100);
-
- RunReadbackTest(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubrect_GL_Bitmap) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- background->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
- green->AddChild(blue);
-
- // Grab the middle of the root layer.
- copy_subrect_ = gfx::Rect(50, 50, 100, 100);
-
- RunReadbackTest(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubrect_GL) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubrect) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -739,13 +311,11 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubrect_GL) {
copy_subrect_ = gfx::Rect(50, 50, 100, 100);
RunReadbackTest(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -761,60 +331,12 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect_Software) {
copy_subrect_ = gfx::Rect(25, 25, 100, 100);
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
green.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect_GL_Bitmap) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(25, 25, 150, 150), SK_ColorGREEN);
- background->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(75, 75, 50, 50), SK_ColorBLUE);
- green->AddChild(blue);
-
- // Grab the middle of the green layer.
- copy_subrect_ = gfx::Rect(25, 25, 100, 100);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(25, 25, 150, 150), SK_ColorGREEN);
- background->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(75, 75, 50, 50), SK_ColorBLUE);
- green->AddChild(blue);
-
- // Grab the middle of the green layer.
- copy_subrect_ = gfx::Rect(25, 25, 100, 100);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
@@ -832,23 +354,22 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_Software) {
insert_copy_request_after_frame_count_ = 1;
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
target.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_GL_Bitmap) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackOutsideViewportWhenNoDamage) {
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> parent =
- CreateSolidColorLayer(gfx::Rect(0, 0, 150, 150), SK_ColorRED);
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
+ EXPECT_FALSE(parent->masks_to_bounds());
background->AddChild(parent);
scoped_refptr<SolidColorLayer> target =
- CreateSolidColorLayer(gfx::Rect(0, 0, 100, 100), SK_ColorGREEN);
+ CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
parent->AddChild(target);
scoped_refptr<SolidColorLayer> blue =
@@ -857,117 +378,80 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_GL_Bitmap) {
insert_copy_request_after_frame_count_ = 1;
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
target.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_GL) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerOutsideViewport) {
scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> parent =
- CreateSolidColorLayer(gfx::Rect(0, 0, 150, 150), SK_ColorRED);
- background->AddChild(parent);
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
- scoped_refptr<SolidColorLayer> target =
- CreateSolidColorLayer(gfx::Rect(0, 0, 100, 100), SK_ColorGREEN);
- parent->AddChild(target);
+ scoped_refptr<SolidColorLayer> green =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+ // Only the top left quarter of the layer is inside the viewport, so the
+ // blue layer is entirely outside.
+ green->SetPosition(gfx::Point(100, 100));
+ background->AddChild(green);
scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
- target->AddChild(blue);
+ CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ green->AddChild(blue);
- insert_copy_request_after_frame_count_ = 1;
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+ GetParam().pixel_test_type, GetParam().readback_type, background,
+ green.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest,
- ReadbackOutsideViewportWhenNoDamage_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootOrFirstLayer) {
+ // This test has 3 render passes with the copy request on the render pass in
+ // the middle. This test caught an issue where copy requests on non-root
+ // non-first render passes were being treated differently from the first
+ // render pass.
scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> parent =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
- EXPECT_FALSE(parent->masks_to_bounds());
- background->AddChild(parent);
-
- scoped_refptr<SolidColorLayer> target =
- CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
- parent->AddChild(target);
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
- target->AddChild(blue);
+ CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ blue->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(&IgnoreReadbackResult)));
+ background->AddChild(blue);
- insert_copy_request_after_frame_count_ = 1;
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+ GetParam().pixel_test_type, GetParam().readback_type, background,
+ background.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest,
- ReadbackOutsideViewportWhenNoDamage_GL_Bitmap) {
+TEST_P(LayerTreeHostReadbackPixelTest, MultipleReadbacksOnLayer) {
+ // This test has 2 copy requests on the background layer. One is added in the
+ // test body, another is added in RunReadbackTestWithReadbackTarget. For every
+ // copy request after the first, state must be restored via a call to
+ // UseRenderPass (see http://crbug.com/99393). This test ensures that the
+ // renderer correctly handles cases where UseRenderPass is called multiple
+ // times for a single layer.
scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> parent =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
- EXPECT_FALSE(parent->masks_to_bounds());
- background->AddChild(parent);
-
- scoped_refptr<SolidColorLayer> target =
- CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
- parent->AddChild(target);
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
- target->AddChild(blue);
+ background->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(&IgnoreReadbackResult)));
- insert_copy_request_after_frame_count_ = 1;
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_BITMAP,
- background,
- target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+ GetParam().pixel_test_type, GetParam().readback_type, background,
+ background.get(), base::FilePath(FILE_PATH_LITERAL("green.png")));
}
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackOutsideViewportWhenNoDamage_GL) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> parent =
- CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
- EXPECT_FALSE(parent->masks_to_bounds());
- background->AddChild(parent);
-
- scoped_refptr<SolidColorLayer> target =
- CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
- parent->AddChild(target);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
- target->AddChild(blue);
-
- insert_copy_request_after_frame_count_ = 1;
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- target.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
+INSTANTIATE_TEST_CASE_P(
+ LayerTreeHostReadbackPixelTests,
+ LayerTreeHostReadbackPixelTest,
+ ::testing::Values(
+ ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_SOFTWARE,
+ READBACK_DEFAULT),
+ ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
+ READBACK_DEFAULT),
+ ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
+ READBACK_BITMAP)));
class LayerTreeHostReadbackDeviceScalePixelTest
: public LayerTreeHostReadbackPixelTest {
@@ -999,36 +483,7 @@ class LayerTreeHostReadbackDeviceScalePixelTest
SolidColorContentLayerClient blue_client_;
};
-TEST_F(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackSubrect_Software) {
- scoped_refptr<FakePictureLayer> background =
- FakePictureLayer::Create(&white_client_);
- background->SetBounds(gfx::Size(100, 100));
- background->SetIsDrawable(true);
-
- scoped_refptr<FakePictureLayer> green =
- FakePictureLayer::Create(&green_client_);
- green->SetBounds(gfx::Size(100, 100));
- green->SetIsDrawable(true);
- background->AddChild(green);
-
- scoped_refptr<FakePictureLayer> blue =
- FakePictureLayer::Create(&blue_client_);
- blue->SetPosition(gfx::Point(50, 50));
- blue->SetBounds(gfx::Size(25, 25));
- blue->SetIsDrawable(true);
- green->AddChild(blue);
-
- // Grab the middle of the root layer.
- copy_subrect_ = gfx::Rect(25, 25, 50, 50);
- device_scale_factor_ = 2.f;
- RunReadbackTest(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackSubrect_GL) {
+TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackSubrect) {
scoped_refptr<FakePictureLayer> background =
FakePictureLayer::Create(&white_client_);
background->SetBounds(gfx::Size(100, 100));
@@ -1051,14 +506,11 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackSubrect_GL) {
copy_subrect_ = gfx::Rect(25, 25, 50, 50);
device_scale_factor_ = 2.f;
RunReadbackTest(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
- ReadbackNonRootLayerSubrect_Software) {
+TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackNonRootLayerSubrect) {
scoped_refptr<FakePictureLayer> background =
FakePictureLayer::Create(&white_client_);
background->SetBounds(gfx::Size(100, 100));
@@ -1082,67 +534,21 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
copy_subrect_ = gfx::Rect(25, 25, 50, 50);
device_scale_factor_ = 2.f;
RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_SOFTWARE,
- READBACK_DEFAULT,
- background,
+ GetParam().pixel_test_type, GetParam().readback_type, background,
green.get(),
base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
}
-TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
- ReadbackNonRootLayerSubrect_GL) {
- scoped_refptr<FakePictureLayer> background =
- FakePictureLayer::Create(&white_client_);
- background->SetBounds(gfx::Size(100, 100));
- background->SetIsDrawable(true);
-
- scoped_refptr<FakePictureLayer> green =
- FakePictureLayer::Create(&green_client_);
- green->SetPosition(gfx::Point(10, 20));
- green->SetBounds(gfx::Size(90, 80));
- green->SetIsDrawable(true);
- background->AddChild(green);
-
- scoped_refptr<FakePictureLayer> blue =
- FakePictureLayer::Create(&blue_client_);
- blue->SetPosition(gfx::Point(50, 50));
- blue->SetBounds(gfx::Size(25, 25));
- blue->SetIsDrawable(true);
- green->AddChild(blue);
-
- // Grab the green layer's content with blue in the bottom right.
- copy_subrect_ = gfx::Rect(25, 25, 50, 50);
- device_scale_factor_ = 2.f;
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerOutsideViewport) {
- scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
- scoped_refptr<SolidColorLayer> green =
- CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
- // Only the top left quarter of the layer is inside the viewport, so the
- // blue layer is entirely outside.
- green->SetPosition(gfx::Point(100, 100));
- background->AddChild(green);
-
- scoped_refptr<SolidColorLayer> blue =
- CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
- green->AddChild(blue);
-
- RunReadbackTestWithReadbackTarget(
- PIXEL_TEST_GL,
- READBACK_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
-}
+INSTANTIATE_TEST_CASE_P(
+ LayerTreeHostReadbackDeviceScalePixelTests,
+ LayerTreeHostReadbackDeviceScalePixelTest,
+ ::testing::Values(
+ ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_SOFTWARE,
+ READBACK_DEFAULT),
+ ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
+ READBACK_DEFAULT),
+ ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
+ READBACK_BITMAP)));
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc
index c22075f7682..7dd6d7d856d 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc
@@ -44,6 +44,36 @@ TEST_F(LayerTreeHostSynchronousPixelTest, OneContentLayer) {
PIXEL_TEST_GL, root, base::FilePath(FILE_PATH_LITERAL("green.png")));
}
+class LayerTreeHostSynchronousGPUPixelTest : public LayerTreePixelTest {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ LayerTreePixelTest::InitializeSettings(settings);
+ settings->single_thread_proxy_scheduler = false;
+ settings->gpu_rasterization_enabled = true;
+ settings->gpu_rasterization_forced = true;
+ }
+
+ void BeginTest() override {
+ LayerTreePixelTest::BeginTest();
+ PostCompositeImmediatelyToMainThread();
+ }
+};
+
+TEST_F(LayerTreeHostSynchronousGPUPixelTest, OneContentLayer) {
+ gfx::Size bounds(200, 200);
+
+ FakeContentLayerClient client;
+ SkPaint green_paint;
+ green_paint.setColor(SkColorSetARGB(255, 0, 255, 0));
+ client.add_draw_rect(gfx::RectF(bounds), green_paint);
+ scoped_refptr<PictureLayer> root = PictureLayer::Create(&client);
+ root->SetBounds(bounds);
+ root->SetIsDrawable(true);
+
+ RunSingleThreadedPixelTest(PIXEL_TEST_GL, root,
+ base::FilePath(FILE_PATH_LITERAL("green.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 aedd0d937a4..98ac5a11d6e 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -7,9 +7,11 @@
#include <algorithm>
#include "base/auto_reset.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/animation/timing_function.h"
-#include "cc/base/swap_promise.h"
#include "cc/debug/frame_rate_counter.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/content_layer_client.h"
@@ -24,8 +26,11 @@
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/output/output_surface.h"
+#include "cc/output/swap_promise.h"
#include "cc/quads/draw_quad.h"
#include "cc/quads/io_surface_draw_quad.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/tile_draw_quad.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/resource_update_queue.h"
@@ -37,10 +42,12 @@
#include "cc/test/fake_painted_scrollbar_layer.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/fake_picture_layer_impl.h"
+#include "cc/test/fake_picture_pile.h"
#include "cc/test/fake_proxy.h"
#include "cc/test/fake_scoped_ui_resource.h"
#include "cc/test/fake_video_frame_provider.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
@@ -67,7 +74,226 @@ using testing::Mock;
namespace cc {
namespace {
-class LayerTreeHostTest : public LayerTreeTest {};
+class LayerTreeHostTest : public LayerTreeTest {
+ public:
+ LayerTreeHostTest() : contents_texture_manager_(nullptr) {}
+
+ void DidInitializeOutputSurface() override {
+ contents_texture_manager_ = layer_tree_host()->contents_texture_manager();
+ }
+
+ protected:
+ PrioritizedResourceManager* contents_texture_manager_;
+};
+
+class LayerTreeHostTestHasImplThreadTest : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestHasImplThreadTest() : threaded_(false) {}
+
+ void RunTest(bool threaded,
+ bool delegating_renderer,
+ bool impl_side_painting) override {
+ threaded_ = threaded;
+ LayerTreeHostTest::RunTest(threaded, delegating_renderer,
+ impl_side_painting);
+ }
+
+ void BeginTest() override {
+ EXPECT_EQ(threaded_, HasImplThread());
+ EndTest();
+ }
+
+ void AfterTest() override { EXPECT_EQ(threaded_, HasImplThread()); }
+
+ private:
+ bool threaded_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestHasImplThreadTest);
+
+class LayerTreeHostTestSetNeedsCommitInsideLayout : public LayerTreeHostTest {
+ protected:
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void Layout() override {
+ // This shouldn't cause a second commit to happen.
+ layer_tree_host()->SetNeedsCommit();
+ }
+
+ void DidCommit() override {
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ EndTest();
+ }
+
+ void AfterTest() override {}
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
+ LayerTreeHostTestSetNeedsCommitInsideLayout);
+
+class LayerTreeHostTestSetNeedsUpdateInsideLayout : public LayerTreeHostTest {
+ protected:
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void Layout() override {
+ // This shouldn't cause a second commit to happen.
+ layer_tree_host()->SetNeedsUpdateLayers();
+ }
+
+ void DidCommit() override {
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ EndTest();
+ }
+
+ void AfterTest() override {}
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
+ LayerTreeHostTestSetNeedsUpdateInsideLayout);
+
+// Test if the LTHI receives ReadyToActivate notifications from the TileManager
+// when no raster tasks get scheduled.
+class LayerTreeHostTestReadyToActivateEmpty : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestReadyToActivateEmpty()
+ : did_notify_ready_to_activate_(false),
+ all_tiles_required_for_activation_are_ready_to_draw_(false),
+ required_for_activation_count_(0) {}
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
+ const std::vector<PictureLayerImpl*>& layers =
+ impl->sync_tree()->picture_layers();
+ required_for_activation_count_ = 0;
+ for (const auto& layer : layers) {
+ FakePictureLayerImpl* fake_layer =
+ static_cast<FakePictureLayerImpl*>(layer);
+ required_for_activation_count_ +=
+ fake_layer->CountTilesRequiredForActivation();
+ }
+ }
+
+ void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override {
+ did_notify_ready_to_activate_ = true;
+ all_tiles_required_for_activation_are_ready_to_draw_ =
+ impl->tile_manager()->IsReadyToActivate();
+ EndTest();
+ }
+
+ void AfterTest() override {
+ EXPECT_TRUE(did_notify_ready_to_activate_);
+ EXPECT_TRUE(all_tiles_required_for_activation_are_ready_to_draw_);
+ EXPECT_EQ(size_t(0), required_for_activation_count_);
+ }
+
+ protected:
+ bool did_notify_ready_to_activate_;
+ bool all_tiles_required_for_activation_are_ready_to_draw_;
+ size_t required_for_activation_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToActivateEmpty);
+
+// Test if the LTHI receives ReadyToActivate notifications from the TileManager
+// when some raster tasks flagged as REQUIRED_FOR_ACTIVATION got scheduled.
+class LayerTreeHostTestReadyToActivateNonEmpty
+ : public LayerTreeHostTestReadyToActivateEmpty {
+ public:
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+ scoped_refptr<FakePictureLayer> root_layer =
+ FakePictureLayer::Create(&client_);
+ root_layer->SetBounds(gfx::Size(1024, 1024));
+ root_layer->SetIsDrawable(true);
+
+ layer_tree_host()->SetRootLayer(root_layer);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void AfterTest() override {
+ EXPECT_TRUE(did_notify_ready_to_activate_);
+ EXPECT_TRUE(all_tiles_required_for_activation_are_ready_to_draw_);
+ EXPECT_LE(size_t(1), required_for_activation_count_);
+ }
+
+ private:
+ FakeContentLayerClient client_;
+};
+
+// Multi-thread only because in single thread the commit goes directly to the
+// active tree, so notify ready to activate is skipped.
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToActivateNonEmpty);
+
+// Test if the LTHI receives ReadyToDraw notifications from the TileManager when
+// no raster tasks get scheduled.
+class LayerTreeHostTestReadyToDrawEmpty : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestReadyToDrawEmpty()
+ : did_notify_ready_to_draw_(false),
+ all_tiles_required_for_draw_are_ready_to_draw_(false),
+ required_for_draw_count_(0) {}
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void NotifyReadyToDrawOnThread(LayerTreeHostImpl* impl) override {
+ did_notify_ready_to_draw_ = true;
+ const std::vector<PictureLayerImpl*>& layers =
+ impl->active_tree()->picture_layers();
+ all_tiles_required_for_draw_are_ready_to_draw_ =
+ impl->tile_manager()->IsReadyToDraw();
+ for (const auto& layer : layers) {
+ FakePictureLayerImpl* fake_layer =
+ static_cast<FakePictureLayerImpl*>(layer);
+ required_for_draw_count_ += fake_layer->CountTilesRequiredForDraw();
+ }
+
+ EndTest();
+ }
+
+ void AfterTest() override {
+ EXPECT_TRUE(did_notify_ready_to_draw_);
+ EXPECT_TRUE(all_tiles_required_for_draw_are_ready_to_draw_);
+ EXPECT_EQ(size_t(0), required_for_draw_count_);
+ }
+
+ protected:
+ bool did_notify_ready_to_draw_;
+ bool all_tiles_required_for_draw_are_ready_to_draw_;
+ size_t required_for_draw_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToDrawEmpty);
+
+// Test if the LTHI receives ReadyToDraw notifications from the TileManager when
+// some raster tasks flagged as REQUIRED_FOR_DRAW got scheduled.
+class LayerTreeHostTestReadyToDrawNonEmpty
+ : public LayerTreeHostTestReadyToDrawEmpty {
+ public:
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+ scoped_refptr<FakePictureLayer> root_layer =
+ FakePictureLayer::Create(&client_);
+ root_layer->SetBounds(gfx::Size(1024, 1024));
+ root_layer->SetIsDrawable(true);
+
+ layer_tree_host()->SetRootLayer(root_layer);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void AfterTest() override {
+ EXPECT_TRUE(did_notify_ready_to_draw_);
+ EXPECT_TRUE(all_tiles_required_for_draw_are_ready_to_draw_);
+ EXPECT_LE(size_t(1), required_for_draw_count_);
+ }
+
+ private:
+ FakeContentLayerClient client_;
+};
+
+// Note: With this test setup, we only get tiles flagged as REQUIRED_FOR_DRAW in
+// single threaded mode.
+SINGLE_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToDrawNonEmpty);
// Two setNeedsCommits in a row should lead to at least 1 commit and at least 1
// draw with frame 0.
@@ -143,6 +369,7 @@ class LayerTreeHostTestPushPropertiesTo : public LayerTreeHostTest {
protected:
void SetupTree() override {
scoped_refptr<Layer> root = Layer::Create();
+ root->CreateRenderSurface();
root->SetBounds(gfx::Size(10, 10));
layer_tree_host()->SetRootLayer(root);
LayerTreeHostTest::SetupTree();
@@ -272,12 +499,13 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsRedraw);
class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
public:
LayerTreeHostTestSetNeedsRedrawRect()
- : num_draws_(0),
- bounds_(50, 50),
- invalid_rect_(10, 10, 20, 20),
- root_layer_(ContentLayer::Create(&client_)) {}
+ : num_draws_(0), bounds_(50, 50), invalid_rect_(10, 10, 20, 20) {}
void BeginTest() override {
+ if (layer_tree_host()->settings().impl_side_painting)
+ root_layer_ = FakePictureLayer::Create(&client_);
+ else
+ root_layer_ = ContentLayer::Create(&client_);
root_layer_->SetIsDrawable(true);
root_layer_->SetBounds(bounds_);
layer_tree_host()->SetRootLayer(root_layer_);
@@ -296,7 +524,7 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
if (!num_draws_) {
// If this is the first frame, expect full frame damage.
- EXPECT_RECT_EQ(root_damage_rect, gfx::Rect(bounds_));
+ EXPECT_EQ(root_damage_rect, gfx::Rect(bounds_));
} else {
// Check that invalid_rect_ is indeed repainted.
EXPECT_TRUE(root_damage_rect.Contains(invalid_rect_));
@@ -321,11 +549,91 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
const gfx::Size bounds_;
const gfx::Rect invalid_rect_;
FakeContentLayerClient client_;
- scoped_refptr<ContentLayer> root_layer_;
+ scoped_refptr<Layer> root_layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsRedrawRect);
+// Ensure the texture size of the pending and active trees are identical when a
+// layer is not in the viewport and a resize happens on the viewport
+class LayerTreeHostTestGpuRasterDeviceSizeChanged : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestGpuRasterDeviceSizeChanged()
+ : num_draws_(0), bounds_(500, 64), invalid_rect_(10, 10, 20, 20) {}
+
+ void BeginTest() override {
+ client_.set_fill_with_nonsolid_color(true);
+ root_layer_ = FakePictureLayer::Create(&client_);
+ root_layer_->SetIsDrawable(true);
+ gfx::Transform transform;
+ // Translate the layer out of the viewport to force it to not update its
+ // tile size via PushProperties.
+ transform.Translate(10000.0, 10000.0);
+ root_layer_->SetTransform(transform);
+ root_layer_->SetBounds(bounds_);
+ layer_tree_host()->SetRootLayer(root_layer_);
+ layer_tree_host()->SetViewportSize(bounds_);
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->gpu_rasterization_enabled = true;
+ settings->gpu_rasterization_forced = true;
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ // Perform 2 commits.
+ if (!num_draws_) {
+ PostSetNeedsRedrawRectToMainThread(invalid_rect_);
+ } else {
+ EndTest();
+ }
+ num_draws_++;
+ }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ if (num_draws_ == 2) {
+ auto pending_tree = host_impl->pending_tree();
+ auto pending_layer_impl =
+ static_cast<FakePictureLayerImpl*>(pending_tree->root_layer());
+ EXPECT_NE(pending_layer_impl, nullptr);
+
+ auto active_tree = host_impl->pending_tree();
+ auto active_layer_impl =
+ static_cast<FakePictureLayerImpl*>(active_tree->root_layer());
+ EXPECT_NE(pending_layer_impl, nullptr);
+
+ auto active_tiling_set = active_layer_impl->picture_layer_tiling_set();
+ auto active_tiling = active_tiling_set->tiling_at(0);
+ auto pending_tiling_set = pending_layer_impl->picture_layer_tiling_set();
+ auto pending_tiling = pending_tiling_set->tiling_at(0);
+ EXPECT_EQ(
+ pending_tiling->TilingDataForTesting().max_texture_size().width(),
+ active_tiling->TilingDataForTesting().max_texture_size().width());
+ }
+ }
+
+ void DidCommitAndDrawFrame() override {
+ // On the second commit, resize the viewport.
+ if (num_draws_ == 1) {
+ layer_tree_host()->SetViewportSize(gfx::Size(400, 64));
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ int num_draws_;
+ const gfx::Size bounds_;
+ const gfx::Rect invalid_rect_;
+ FakeContentLayerClient client_;
+ scoped_refptr<FakePictureLayer> root_layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
+ LayerTreeHostTestGpuRasterDeviceSizeChanged);
+
class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest {
public:
void InitializeSettings(LayerTreeSettings* settings) override {
@@ -335,8 +643,12 @@ class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest {
void SetupTree() override {
root_layer_ = Layer::Create();
root_layer_->SetBounds(gfx::Size(10, 20));
+ root_layer_->CreateRenderSurface();
- scaled_layer_ = FakeContentLayer::Create(&client_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ scaled_layer_ = FakePictureLayer::Create(&client_);
+ else
+ scaled_layer_ = FakeContentLayer::Create(&client_);
scaled_layer_->SetBounds(gfx::Size(1, 1));
root_layer_->AddChild(scaled_layer_);
@@ -354,10 +666,8 @@ class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest {
void DidCommit() override {
switch (layer_tree_host()->source_frame_number()) {
case 1:
- // Changing the device scale factor causes a commit. It also changes
- // the content bounds of |scaled_layer_|, which should not generate
- // a second commit as a result.
- layer_tree_host()->SetDeviceScaleFactor(4.f);
+ // SetBounds grows the layer and exposes new content.
+ scaled_layer_->SetBounds(gfx::Size(4, 4));
break;
default:
// No extra commits.
@@ -366,14 +676,13 @@ class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest {
}
void AfterTest() override {
- EXPECT_EQ(gfx::Size(4, 4).ToString(),
- scaled_layer_->content_bounds().ToString());
+ EXPECT_EQ(gfx::Size(4, 4).ToString(), scaled_layer_->bounds().ToString());
}
private:
FakeContentLayerClient client_;
scoped_refptr<Layer> root_layer_;
- scoped_refptr<FakeContentLayer> scaled_layer_;
+ scoped_refptr<Layer> scaled_layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoExtraCommitFromInvalidate);
@@ -388,6 +697,7 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate
void SetupTree() override {
root_layer_ = Layer::Create();
root_layer_->SetBounds(gfx::Size(10, 20));
+ root_layer_->CreateRenderSurface();
bool paint_scrollbar = true;
bool has_thumb = false;
@@ -420,12 +730,11 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate
default:
// No extra commits.
EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ break;
}
}
void AfterTest() override {
- EXPECT_EQ(gfx::Size(40, 40).ToString(),
- scrollbar_->content_bounds().ToString());
}
private:
@@ -440,12 +749,13 @@ SINGLE_AND_MULTI_THREAD_TEST_F(
class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
public:
LayerTreeHostTestSetNextCommitForcesRedraw()
- : num_draws_(0),
- bounds_(50, 50),
- invalid_rect_(10, 10, 20, 20),
- root_layer_(ContentLayer::Create(&client_)) {}
+ : num_draws_(0), bounds_(50, 50), invalid_rect_(10, 10, 20, 20) {}
void BeginTest() override {
+ if (layer_tree_host()->settings().impl_side_painting)
+ root_layer_ = FakePictureLayer::Create(&client_);
+ else
+ root_layer_ = ContentLayer::Create(&client_);
root_layer_->SetIsDrawable(true);
root_layer_->SetBounds(bounds_);
layer_tree_host()->SetRootLayer(root_layer_);
@@ -469,17 +779,17 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
switch (num_draws_) {
case 0:
- EXPECT_RECT_EQ(gfx::Rect(bounds_), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(bounds_), root_damage_rect);
break;
case 1:
case 2:
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root_damage_rect);
break;
case 3:
- EXPECT_RECT_EQ(invalid_rect_, root_damage_rect);
+ EXPECT_EQ(invalid_rect_, root_damage_rect);
break;
case 4:
- EXPECT_RECT_EQ(gfx::Rect(bounds_), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(bounds_), root_damage_rect);
break;
default:
NOTREACHED();
@@ -522,7 +832,7 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
const gfx::Size bounds_;
const gfx::Rect invalid_rect_;
FakeContentLayerClient client_;
- scoped_refptr<ContentLayer> root_layer_;
+ scoped_refptr<Layer> root_layer_;
};
SINGLE_AND_MULTI_THREAD_BLOCKNOTIFY_TEST_F(
@@ -532,22 +842,38 @@ SINGLE_AND_MULTI_THREAD_BLOCKNOTIFY_TEST_F(
// its damage is preserved until the next time it is drawn.
class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
public:
- LayerTreeHostTestUndrawnLayersDamageLater()
- : root_layer_(ContentLayer::Create(&client_)) {}
+ LayerTreeHostTestUndrawnLayersDamageLater() {}
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ // If we don't set the minimum contents scale, it's harder to verify whether
+ // the damage we get is correct. For other scale amounts, please see
+ // LayerTreeHostTestDamageWithScale.
+ settings->minimum_contents_scale = 1.f;
+ }
void SetupTree() override {
+ if (layer_tree_host()->settings().impl_side_painting)
+ root_layer_ = FakePictureLayer::Create(&client_);
+ else
+ root_layer_ = ContentLayer::Create(&client_);
root_layer_->SetIsDrawable(true);
root_layer_->SetBounds(gfx::Size(50, 50));
layer_tree_host()->SetRootLayer(root_layer_);
// The initially transparent layer has a larger child layer, which is
// not initially drawn because of the this (parent) layer.
- parent_layer_ = FakeContentLayer::Create(&client_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ parent_layer_ = FakePictureLayer::Create(&client_);
+ else
+ parent_layer_ = FakeContentLayer::Create(&client_);
parent_layer_->SetBounds(gfx::Size(15, 15));
parent_layer_->SetOpacity(0.0f);
root_layer_->AddChild(parent_layer_);
- child_layer_ = FakeContentLayer::Create(&client_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ child_layer_ = FakePictureLayer::Create(&client_);
+ else
+ child_layer_ = FakeContentLayer::Create(&client_);
child_layer_->SetBounds(gfx::Size(25, 25));
parent_layer_->AddChild(child_layer_);
@@ -572,12 +898,12 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
// box.
switch (host_impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_RECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect);
break;
case 1:
case 2:
case 3:
- EXPECT_RECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect);
break;
default:
NOTREACHED();
@@ -612,13 +938,121 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
private:
FakeContentLayerClient client_;
- scoped_refptr<ContentLayer> root_layer_;
- scoped_refptr<FakeContentLayer> parent_layer_;
- scoped_refptr<FakeContentLayer> child_layer_;
+ scoped_refptr<Layer> root_layer_;
+ scoped_refptr<Layer> parent_layer_;
+ scoped_refptr<Layer> child_layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater);
+// Tests that if a layer is not drawn because of some reason in the parent then
+// its damage is preserved until the next time it is drawn.
+class LayerTreeHostTestDamageWithScale : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestDamageWithScale() {}
+
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_ptr<FakePicturePile> pile(
+ new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+ ImplSidePaintingSettings().default_tile_grid_size));
+ root_layer_ =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ root_layer_->SetBounds(gfx::Size(50, 50));
+
+ pile.reset(
+ new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+ ImplSidePaintingSettings().default_tile_grid_size));
+ child_layer_ =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ child_layer_->SetBounds(gfx::Size(25, 25));
+ child_layer_->SetIsDrawable(true);
+ child_layer_->SetContentsOpaque(true);
+ root_layer_->AddChild(child_layer_);
+
+ layer_tree_host()->SetRootLayer(root_layer_);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ // Force the layer to have a tiling at 1.3f scale. Note that if we simply
+ // add tiling, it will be gone by the time we draw because of aggressive
+ // cleanup. AddTilingUntilNextDraw ensures that it remains there during
+ // damage calculation.
+ FakePictureLayerImpl* child_layer_impl = static_cast<FakePictureLayerImpl*>(
+ host_impl->active_tree()->LayerById(child_layer_->id()));
+ child_layer_impl->AddTilingUntilNextDraw(1.3f);
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
+
+ gfx::RectF root_damage_rect;
+ if (!frame_data->render_passes.empty())
+ root_damage_rect = frame_data->render_passes.back()->damage_rect;
+
+ // The first time, the whole view needs be drawn.
+ // Afterwards, just the opacity of surface_layer1 is changed a few times,
+ // and each damage should be the bounding box of it and its child. If this
+ // was working improperly, the damage might not include its childs bounding
+ // box.
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ EXPECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect);
+ break;
+ case 1: {
+ FakePictureLayerImpl* child_layer_impl =
+ static_cast<FakePictureLayerImpl*>(
+ host_impl->active_tree()->LayerById(child_layer_->id()));
+ // We remove tilings pretty aggressively if they are not ideal. Add this
+ // back in so that we can compare
+ // child_layer_impl->GetEnclosingRectInTargetSpace to the damage.
+ child_layer_impl->AddTilingUntilNextDraw(1.3f);
+
+ EXPECT_EQ(gfx::Rect(26, 26), root_damage_rect);
+ EXPECT_EQ(child_layer_impl->GetEnclosingRectInTargetSpace(),
+ root_damage_rect);
+ EXPECT_TRUE(child_layer_impl->GetEnclosingRectInTargetSpace().Contains(
+ gfx::Rect(child_layer_->bounds())));
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+
+ return draw_result;
+ }
+
+ void DidCommitAndDrawFrame() override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1: {
+ // Test not owning the surface.
+ child_layer_->SetOpacity(0.5f);
+ break;
+ }
+ case 2:
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ FakeContentLayerClient client_;
+ scoped_refptr<Layer> root_layer_;
+ scoped_refptr<Layer> child_layer_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestDamageWithScale);
+
// Tests that if a layer is not drawn because of some reason in the parent,
// causing its content bounds to not be computed, then when it is later drawn,
// its content bounds get pushed.
@@ -629,6 +1063,7 @@ class LayerTreeHostTestUndrawnLayersPushContentBoundsLater
: root_layer_(Layer::Create()) {}
void SetupTree() override {
+ root_layer_->CreateRenderSurface();
root_layer_->SetIsDrawable(true);
root_layer_->SetBounds(gfx::Size(20, 20));
layer_tree_host()->SetRootLayer(root_layer_);
@@ -687,7 +1122,7 @@ class LayerTreeHostTestUndrawnLayersPushContentBoundsLater
scoped_refptr<Layer> child_layer_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(
+SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
LayerTreeHostTestUndrawnLayersPushContentBoundsLater);
// This test verifies that properties on the layer tree host are commited
@@ -836,14 +1271,9 @@ class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest {
void SetupTree() override {
LayerTreeHostTest::SetupTree();
- if (layer_tree_host()->settings().impl_side_painting) {
- scoped_refptr<FakePictureLayer> layer =
- FakePictureLayer::Create(&client_);
- layer->set_always_update_resources(true);
- scroll_layer_ = layer;
- } else {
- scroll_layer_ = FakeContentLayer::Create(&client_);
- }
+ scoped_refptr<FakePictureLayer> layer = FakePictureLayer::Create(&client_);
+ layer->set_always_update_resources(true);
+ scroll_layer_ = layer;
Layer* root_layer = layer_tree_host()->root_layer();
scroll_layer_->SetScrollClipLayerId(root_layer->id());
@@ -854,8 +1284,8 @@ class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest {
layer_tree_host()->root_layer()->AddChild(scroll_layer_);
// This test requires the page_scale and inner viewport layers to be
// identified.
- layer_tree_host()->RegisterViewportLayers(
- root_layer, scroll_layer_.get(), NULL);
+ layer_tree_host()->RegisterViewportLayers(NULL, root_layer,
+ scroll_layer_.get(), NULL);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 2.f);
}
@@ -875,14 +1305,14 @@ class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest {
// until the second draw.
switch (impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_EQ(1.f, impl->active_tree()->page_scale_factor());
+ EXPECT_EQ(1.f, impl->active_tree()->current_page_scale_factor());
// We'll start an animation when we get back to the main thread.
break;
case 1:
- EXPECT_EQ(1.f, impl->active_tree()->page_scale_factor());
+ EXPECT_EQ(1.f, impl->active_tree()->current_page_scale_factor());
break;
case 2:
- EXPECT_EQ(1.25f, impl->active_tree()->page_scale_factor());
+ EXPECT_EQ(1.25f, impl->active_tree()->current_page_scale_factor());
EndTest();
break;
default:
@@ -905,7 +1335,7 @@ class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest {
scoped_refptr<Layer> scroll_layer_;
};
-MULTI_THREAD_TEST_F(LayerTreeHostTestStartPageScaleAnimation);
+MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestStartPageScaleAnimation);
class LayerTreeHostTestSetVisible : public LayerTreeHostTest {
public:
@@ -940,15 +1370,19 @@ class TestOpacityChangeLayerDelegate : public ContentLayerClient {
void SetTestLayer(Layer* test_layer) { test_layer_ = test_layer; }
- void PaintContents(
- SkCanvas* canvas,
- const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus gc_status) override {
+ void PaintContents(SkCanvas* canvas,
+ const gfx::Rect& clip,
+ PaintingControlSetting picture_control) override {
// Set layer opacity to 0.
if (test_layer_)
test_layer_->SetOpacity(0.f);
}
- void DidChangeLayerCanUseLCDText() override {}
+ void PaintContentsToDisplayList(
+ DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ PaintingControlSetting picture_control) override {
+ NOTIMPLEMENTED();
+ }
bool FillsBoundsCompletely() const override { return false; }
private:
@@ -987,16 +1421,27 @@ class ContentLayerWithUpdateTracking : public ContentLayer {
// from being updated during commit.
class LayerTreeHostTestOpacityChange : public LayerTreeHostTest {
public:
- LayerTreeHostTestOpacityChange()
- : test_opacity_change_delegate_(),
- update_check_layer_(ContentLayerWithUpdateTracking::Create(
- &test_opacity_change_delegate_)) {
- test_opacity_change_delegate_.SetTestLayer(update_check_layer_.get());
- }
+ LayerTreeHostTestOpacityChange() : test_opacity_change_delegate_() {}
void BeginTest() override {
+ if (layer_tree_host()->settings().impl_side_painting) {
+ update_check_picture_layer_ =
+ FakePictureLayer::Create(&test_opacity_change_delegate_);
+ test_opacity_change_delegate_.SetTestLayer(
+ update_check_picture_layer_.get());
+ is_impl_paint_ = true;
+ } else {
+ update_check_content_layer_ = ContentLayerWithUpdateTracking::Create(
+ &test_opacity_change_delegate_);
+ test_opacity_change_delegate_.SetTestLayer(
+ update_check_content_layer_.get());
+ is_impl_paint_ = false;
+ }
layer_tree_host()->SetViewportSize(gfx::Size(10, 10));
- layer_tree_host()->root_layer()->AddChild(update_check_layer_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ layer_tree_host()->root_layer()->AddChild(update_check_picture_layer_);
+ else
+ layer_tree_host()->root_layer()->AddChild(update_check_content_layer_);
PostSetNeedsCommitToMainThread();
}
@@ -1005,47 +1450,36 @@ class LayerTreeHostTestOpacityChange : public LayerTreeHostTest {
void AfterTest() override {
// Update() should have been called once.
- EXPECT_EQ(1, update_check_layer_->PaintContentsCount());
+ if (is_impl_paint_)
+ EXPECT_EQ(1u, update_check_picture_layer_->update_count());
+ else
+ EXPECT_EQ(1, update_check_content_layer_->PaintContentsCount());
}
private:
TestOpacityChangeLayerDelegate test_opacity_change_delegate_;
- scoped_refptr<ContentLayerWithUpdateTracking> update_check_layer_;
+ scoped_refptr<ContentLayerWithUpdateTracking> update_check_content_layer_;
+ scoped_refptr<FakePictureLayer> update_check_picture_layer_;
+ bool is_impl_paint_;
};
MULTI_THREAD_TEST_F(LayerTreeHostTestOpacityChange);
-class NoScaleContentLayer : public ContentLayer {
- public:
- static scoped_refptr<NoScaleContentLayer> Create(ContentLayerClient* client) {
- return make_scoped_refptr(new NoScaleContentLayer(client));
- }
-
- void CalculateContentsScale(float ideal_contents_scale,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* contentBounds) override {
- // Skip over the ContentLayer's method to the base Layer class.
- Layer::CalculateContentsScale(ideal_contents_scale,
- contents_scale_x,
- contents_scale_y,
- contentBounds);
- }
-
- private:
- explicit NoScaleContentLayer(ContentLayerClient* client)
- : ContentLayer(client) {}
- ~NoScaleContentLayer() override {}
-};
-
class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
: public LayerTreeHostTest {
public:
- LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers()
- : root_layer_(NoScaleContentLayer::Create(&client_)),
- child_layer_(ContentLayer::Create(&client_)) {}
+ LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers() {}
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ // PictureLayer can only be used with impl side painting enabled.
+ settings->impl_side_painting = true;
+ }
void BeginTest() override {
+ client_.set_fill_with_nonsolid_color(true);
+ root_layer_ = FakePictureLayer::Create(&client_);
+ child_layer_ = FakePictureLayer::Create(&client_);
+
layer_tree_host()->SetViewportSize(gfx::Size(60, 60));
layer_tree_host()->SetDeviceScaleFactor(1.5);
EXPECT_EQ(gfx::Size(60, 60), layer_tree_host()->device_viewport_size());
@@ -1076,8 +1510,10 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
// Device viewport is scaled.
EXPECT_EQ(gfx::Size(60, 60), impl->DrawViewportSize());
- LayerImpl* root = impl->active_tree()->root_layer();
- LayerImpl* child = impl->active_tree()->root_layer()->children()[0];
+ FakePictureLayerImpl* root =
+ static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
+ FakePictureLayerImpl* child = static_cast<FakePictureLayerImpl*>(
+ impl->active_tree()->root_layer()->children()[0]);
// Positions remain in layout pixels.
EXPECT_EQ(gfx::Point(0, 0), root->position());
@@ -1098,13 +1534,10 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
ASSERT_EQ(2u, root->render_surface()->layer_list().size());
// The root render surface is the size of the viewport.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 60, 60),
- root->render_surface()->content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 60, 60), root->render_surface()->content_rect());
- // The content bounds of the child should be scaled.
- gfx::Size child_bounds_scaled =
- gfx::ToCeiledSize(gfx::ScaleSize(child->bounds(), 1.5));
- EXPECT_EQ(child_bounds_scaled, child->content_bounds());
+ // The max tiling scale of the child should be scaled.
+ EXPECT_FLOAT_EQ(1.5f, child->MaximumTilingContentsScale());
gfx::Transform scale_transform;
scale_transform.Scale(impl->device_scale_factor(),
@@ -1118,13 +1551,13 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
EXPECT_EQ(root_screen_space_transform, root->screen_space_transform());
// The child is at position 2,2, which is transformed to 3,3 after the scale
- gfx::Transform child_screen_space_transform;
- child_screen_space_transform.Translate(3.f, 3.f);
- gfx::Transform child_draw_transform = child_screen_space_transform;
+ gfx::Transform child_transform;
+ child_transform.Translate(3.f, 3.f);
+ child_transform.Scale(child->MaximumTilingContentsScale(),
+ child->MaximumTilingContentsScale());
- EXPECT_TRANSFORMATION_MATRIX_EQ(child_draw_transform,
- child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(child_screen_space_transform,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(child_transform, child->draw_transform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(child_transform,
child->screen_space_transform());
EndTest();
@@ -1134,21 +1567,22 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
private:
FakeContentLayerClient client_;
- scoped_refptr<NoScaleContentLayer> root_layer_;
- scoped_refptr<ContentLayer> child_layer_;
+ scoped_refptr<FakePictureLayer> root_layer_;
+ scoped_refptr<FakePictureLayer> child_layer_;
};
MULTI_THREAD_TEST_F(LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers);
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
// Verify atomicity of commits and reuse of textures.
class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
public:
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->texture_id_allocation_chunk_size = 1;
+ settings->renderer_settings.texture_id_allocation_chunk_size = 1;
// Make sure partial texture updates are turned off.
settings->max_partial_texture_updates = 0;
// Linear fade animator prevents scrollbars from drawing immediately.
- settings->scrollbar_animator = LayerTreeSettings::NoAnimator;
+ settings->scrollbar_animator = LayerTreeSettings::NO_ANIMATOR;
}
void SetupTree() override {
@@ -1174,7 +1608,7 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
}
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
+ ASSERT_EQ(0u, impl->settings().max_partial_texture_updates);
TestWebGraphicsContext3D* context = TestContext();
@@ -1248,11 +1682,12 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
LayerTreeHostTestDirectRendererAtomicCommit);
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
class LayerTreeHostTestDelegatingRendererAtomicCommit
: public LayerTreeHostTestDirectRendererAtomicCommit {
public:
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
+ ASSERT_EQ(0u, impl->settings().max_partial_texture_updates);
TestWebGraphicsContext3D* context = TestContext();
@@ -1265,7 +1700,6 @@ class LayerTreeHostTestDelegatingRendererAtomicCommit
// Verify that used texture is correct.
EXPECT_TRUE(context->UsedTexture(context->TextureAt(0)));
EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
- context->ResetUsedTextures();
break;
case 1:
// Number of textures should be doubled as the first context layer
@@ -1283,7 +1717,6 @@ class LayerTreeHostTestDelegatingRendererAtomicCommit
// New textures should have been used.
EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
EXPECT_TRUE(context->UsedTexture(context->TextureAt(3)));
- context->ResetUsedTextures();
break;
case 2:
EndTest();
@@ -1315,11 +1748,12 @@ static void SetLayerPropertiesForTesting(Layer* layer,
layer->SetContentsOpaque(opaque);
}
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
class LayerTreeHostTestAtomicCommitWithPartialUpdate
: public LayerTreeHostTest {
public:
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->texture_id_allocation_chunk_size = 1;
+ settings->renderer_settings.texture_id_allocation_chunk_size = 1;
// Allow one partial texture update.
settings->max_partial_texture_updates = 1;
// No partial updates when impl side painting is enabled.
@@ -1370,7 +1804,7 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate
}
void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
- ASSERT_EQ(1u, layer_tree_host()->settings().max_partial_texture_updates);
+ ASSERT_EQ(1u, impl->settings().max_partial_texture_updates);
TestWebGraphicsContext3D* context = TestContext();
@@ -1488,6 +1922,7 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
LayerTreeHostTestAtomicCommitWithPartialUpdate);
+// TODO(sohanjg) : Make it work with impl-side painting.
class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
: public LayerTreeHostTest {
protected:
@@ -1622,7 +2057,6 @@ class EvictionTestLayerImpl : public LayerImpl {
~EvictionTestLayerImpl() override {}
void AppendQuads(RenderPass* render_pass,
- const Occlusion& occlusion_in_content_space,
AppendQuadsData* append_quads_data) override {
ASSERT_TRUE(has_texture_);
ASSERT_NE(0u, layer_tree_impl()->resource_provider()->num_resources());
@@ -1808,11 +2242,15 @@ class LayerTreeHostTestContinuousInvalidate : public LayerTreeHostTest {
layer_tree_host()->SetViewportSize(gfx::Size(10, 10));
layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10));
- content_layer_ = ContentLayer::Create(&client_);
- content_layer_->SetBounds(gfx::Size(10, 10));
- content_layer_->SetPosition(gfx::PointF(0.f, 0.f));
- content_layer_->SetIsDrawable(true);
- layer_tree_host()->root_layer()->AddChild(content_layer_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ layer_ = FakePictureLayer::Create(&client_);
+ else
+ layer_ = FakeContentLayer::Create(&client_);
+
+ layer_->SetBounds(gfx::Size(10, 10));
+ layer_->SetPosition(gfx::PointF(0.f, 0.f));
+ layer_->SetIsDrawable(true);
+ layer_tree_host()->root_layer()->AddChild(layer_);
PostSetNeedsCommitToMainThread();
}
@@ -1820,7 +2258,7 @@ class LayerTreeHostTestContinuousInvalidate : public LayerTreeHostTest {
void DidCommitAndDrawFrame() override {
if (num_draw_layers_ == 2)
return;
- content_layer_->SetNeedsDisplay();
+ layer_->SetNeedsDisplay();
}
void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
@@ -1841,32 +2279,50 @@ class LayerTreeHostTestContinuousInvalidate : public LayerTreeHostTest {
private:
FakeContentLayerClient client_;
- scoped_refptr<Layer> content_layer_;
+ scoped_refptr<Layer> layer_;
int num_commit_complete_;
int num_draw_layers_;
};
-MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestContinuousInvalidate);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousInvalidate);
class LayerTreeHostTestDeferCommits : public LayerTreeHostTest {
public:
LayerTreeHostTestDeferCommits()
- : num_commits_deferred_(0), num_complete_commits_(0) {}
+ : num_will_begin_impl_frame_(0),
+ num_send_begin_main_frame_(0) {}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
- void DidDeferCommit() override {
- num_commits_deferred_++;
- layer_tree_host()->SetDeferCommits(false);
+ void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
+ const BeginFrameArgs& args) override {
+ num_will_begin_impl_frame_++;
+ switch (num_will_begin_impl_frame_) {
+ case 1:
+ break;
+ case 2:
+ case 3:
+ case 4:
+ // Post a number of frames to increase the chance that, if there exist
+ // bugs, an unexpected BeginMainFrame will be issued.
+ PostSetNeedsCommitToMainThread();
+ PostSetNeedsRedrawToMainThread();
+ break;
+ case 5:
+ PostSetDeferCommitsToMainThread(false);
+ break;
+ default:
+ // Sometimes |num_will_begin_impl_frame_| will be greater than 5 if the
+ // main thread is slow to respond.
+ break;
+ }
}
- void DidCommit() override {
- num_complete_commits_++;
- switch (num_complete_commits_) {
+ void ScheduledActionSendBeginMainFrame() override {
+ num_send_begin_main_frame_++;
+ switch (num_send_begin_main_frame_) {
case 1:
- EXPECT_EQ(0, num_commits_deferred_);
- layer_tree_host()->SetDeferCommits(true);
- PostSetNeedsCommitToMainThread();
+ PostSetDeferCommitsToMainThread(true);
break;
case 2:
EndTest();
@@ -1878,23 +2334,92 @@ class LayerTreeHostTestDeferCommits : public LayerTreeHostTest {
}
void AfterTest() override {
- EXPECT_EQ(1, num_commits_deferred_);
- EXPECT_EQ(2, num_complete_commits_);
+ EXPECT_GE(num_will_begin_impl_frame_, 5);
+ EXPECT_EQ(2, num_send_begin_main_frame_);
}
private:
- int num_commits_deferred_;
- int num_complete_commits_;
+ int num_will_begin_impl_frame_;
+ int num_send_begin_main_frame_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeferCommits);
+class LayerTreeHostTestCompositeImmediatelyStateTransitions
+ : public LayerTreeHostTest {
+ public:
+ enum {
+ kInvalid,
+ kStartedTest,
+ kStartedImplFrame,
+ kStartedMainFrame,
+ kStartedCommit,
+ kCompletedCommit,
+ kCompletedMainFrame,
+ kCompletedImplFrame,
+ };
+
+ LayerTreeHostTestCompositeImmediatelyStateTransitions()
+ : current_state_(kInvalid), current_begin_frame_args_() {}
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->single_thread_proxy_scheduler = false;
+ }
+
+ void BeginTest() override {
+ current_state_ = kStartedTest;
+ PostCompositeImmediatelyToMainThread();
+ }
+
+ void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
+ const BeginFrameArgs& args) override {
+ EXPECT_EQ(current_state_, kStartedTest);
+ current_state_ = kStartedImplFrame;
+
+ EXPECT_FALSE(current_begin_frame_args_.IsValid());
+ EXPECT_TRUE(args.IsValid());
+ current_begin_frame_args_ = args;
+ }
+ void WillBeginMainFrame() override {
+ EXPECT_EQ(current_state_, kStartedImplFrame);
+ current_state_ = kStartedMainFrame;
+ }
+ void BeginMainFrame(const BeginFrameArgs& args) override {
+ EXPECT_EQ(current_state_, kStartedMainFrame);
+ EXPECT_EQ(args.frame_time, current_begin_frame_args_.frame_time);
+ }
+ void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
+ EXPECT_EQ(current_state_, kStartedMainFrame);
+ current_state_ = kStartedCommit;
+ }
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ EXPECT_EQ(current_state_, kStartedCommit);
+ current_state_ = kCompletedCommit;
+ }
+ void DidBeginMainFrame() override {
+ EXPECT_EQ(current_state_, kCompletedCommit);
+ current_state_ = kCompletedMainFrame;
+ }
+ void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) override {
+ EXPECT_EQ(current_state_, kCompletedMainFrame);
+ current_state_ = kCompletedImplFrame;
+ EndTest();
+ }
+ void AfterTest() override { EXPECT_EQ(current_state_, kCompletedImplFrame); }
+
+ private:
+ int current_state_;
+ BeginFrameArgs current_begin_frame_args_;
+};
+
+SINGLE_THREAD_TEST_F(LayerTreeHostTestCompositeImmediatelyStateTransitions);
+
class LayerTreeHostWithProxy : public LayerTreeHost {
public:
LayerTreeHostWithProxy(FakeLayerTreeHostClient* client,
- const LayerTreeSettings& settings,
- scoped_ptr<FakeProxy> proxy)
- : LayerTreeHost(client, NULL, NULL, settings) {
+ scoped_ptr<FakeProxy> proxy,
+ LayerTreeHost::InitParams* params)
+ : LayerTreeHost(params) {
proxy->SetLayerTreeHost(this);
client->SetLayerTreeHost(this);
InitializeForTesting(proxy.Pass());
@@ -1911,10 +2436,13 @@ TEST(LayerTreeHostTest, LimitPartialUpdates) {
proxy->SetMaxPartialTextureUpdates(5);
LayerTreeSettings settings;
+ settings.impl_side_painting = false;
settings.max_partial_texture_updates = 10;
- LayerTreeHostWithProxy host(&client, settings, proxy.Pass());
- host.OnCreateAndInitializeOutputSurfaceAttempted(true);
+ LayerTreeHost::InitParams params;
+ params.client = &client;
+ params.settings = &settings;
+ LayerTreeHostWithProxy host(&client, proxy.Pass(), &params);
EXPECT_EQ(0u, host.MaxPartialTextureUpdates());
}
@@ -1929,10 +2457,13 @@ TEST(LayerTreeHostTest, LimitPartialUpdates) {
proxy->SetMaxPartialTextureUpdates(5);
LayerTreeSettings settings;
+ settings.impl_side_painting = false;
settings.max_partial_texture_updates = 10;
- LayerTreeHostWithProxy host(&client, settings, proxy.Pass());
- host.OnCreateAndInitializeOutputSurfaceAttempted(true);
+ LayerTreeHost::InitParams params;
+ params.client = &client;
+ params.settings = &settings;
+ LayerTreeHostWithProxy host(&client, proxy.Pass(), &params);
EXPECT_EQ(5u, host.MaxPartialTextureUpdates());
}
@@ -1947,10 +2478,13 @@ TEST(LayerTreeHostTest, LimitPartialUpdates) {
proxy->SetMaxPartialTextureUpdates(20);
LayerTreeSettings settings;
+ settings.impl_side_painting = false;
settings.max_partial_texture_updates = 10;
- LayerTreeHostWithProxy host(&client, settings, proxy.Pass());
- host.OnCreateAndInitializeOutputSurfaceAttempted(true);
+ LayerTreeHost::InitParams params;
+ params.client = &client;
+ params.settings = &settings;
+ LayerTreeHostWithProxy host(&client, proxy.Pass(), &params);
EXPECT_EQ(10u, host.MaxPartialTextureUpdates());
}
@@ -1962,16 +2496,17 @@ TEST(LayerTreeHostTest, PartialUpdatesWithGLRenderer) {
LayerTreeSettings settings;
settings.max_partial_texture_updates = 4;
settings.single_thread_proxy_scheduler = false;
+ settings.impl_side_painting = false;
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
+ LayerTreeHost::InitParams params;
+ params.client = &client;
+ params.shared_bitmap_manager = shared_bitmap_manager.get();
+ params.settings = &settings;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client,
- &client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current());
+ LayerTreeHost::CreateSingleThreaded(&client, &params);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -1984,16 +2519,17 @@ TEST(LayerTreeHostTest, PartialUpdatesWithSoftwareRenderer) {
LayerTreeSettings settings;
settings.max_partial_texture_updates = 4;
settings.single_thread_proxy_scheduler = false;
+ settings.impl_side_painting = false;
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
+ LayerTreeHost::InitParams params;
+ params.client = &client;
+ params.shared_bitmap_manager = shared_bitmap_manager.get();
+ params.settings = &settings;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client,
- &client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current());
+ LayerTreeHost::CreateSingleThreaded(&client, &params);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -2006,16 +2542,17 @@ TEST(LayerTreeHostTest, PartialUpdatesWithDelegatingRendererAndGLContent) {
LayerTreeSettings settings;
settings.max_partial_texture_updates = 4;
settings.single_thread_proxy_scheduler = false;
+ settings.impl_side_painting = false;
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
+ LayerTreeHost::InitParams params;
+ params.client = &client;
+ params.shared_bitmap_manager = shared_bitmap_manager.get();
+ params.settings = &settings;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client,
- &client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current());
+ LayerTreeHost::CreateSingleThreaded(&client, &params);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -2029,22 +2566,24 @@ TEST(LayerTreeHostTest,
LayerTreeSettings settings;
settings.max_partial_texture_updates = 4;
settings.single_thread_proxy_scheduler = false;
+ settings.impl_side_painting = false;
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
+ LayerTreeHost::InitParams params;
+ params.client = &client;
+ params.shared_bitmap_manager = shared_bitmap_manager.get();
+ params.settings = &settings;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client,
- &client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current());
+ LayerTreeHost::CreateSingleThreaded(&client, &params);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
}
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
: public LayerTreeHostTest {
public:
@@ -2069,12 +2608,10 @@ class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
bool visible) override {
if (visible) {
// One backing should remain unevicted.
- EXPECT_EQ(
- 100u * 100u * 4u * 1u,
- layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+ EXPECT_EQ(100u * 100u * 4u * 1u,
+ contents_texture_manager_->MemoryUseBytes());
} else {
- EXPECT_EQ(
- 0u, layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+ EXPECT_EQ(0u, contents_texture_manager_->MemoryUseBytes());
}
// Make sure that contents textures are marked as having been
@@ -2089,9 +2626,9 @@ class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
switch (num_commits_) {
case 1:
// All three backings should have memory.
- EXPECT_EQ(
- 100u * 100u * 4u * 3u,
- layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+ EXPECT_EQ(100u * 100u * 4u * 3u,
+ contents_texture_manager_->MemoryUseBytes());
+
// Set a new policy that will kick out 1 of the 3 resources.
// Because a resource was evicted, a commit will be kicked off.
host_impl->SetMemoryPolicy(
@@ -2101,9 +2638,8 @@ class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
break;
case 2:
// Only two backings should have memory.
- EXPECT_EQ(
- 100u * 100u * 4u * 2u,
- layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+ EXPECT_EQ(100u * 100u * 4u * 2u,
+ contents_texture_manager_->MemoryUseBytes());
// Become backgrounded, which will cause 1 more resource to be
// evicted.
PostSetVisibleToMainThread(false);
@@ -2129,105 +2665,99 @@ class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted);
-class LayerTreeHostTestLCDNotification : public LayerTreeHostTest {
+class LayerTreeHostTestLCDChange : public LayerTreeHostTest {
public:
- class NotificationClient : public ContentLayerClient {
- public:
- NotificationClient()
- : layer_(0), paint_count_(0), lcd_notification_count_(0) {}
-
- void set_layer(Layer* layer) { layer_ = layer; }
- int paint_count() const { return paint_count_; }
- int lcd_notification_count() const { return lcd_notification_count_; }
-
- void PaintContents(
- SkCanvas* canvas,
- const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus gc_status) override {
- ++paint_count_;
- }
- void DidChangeLayerCanUseLCDText() override {
- ++lcd_notification_count_;
- layer_->SetNeedsDisplay();
- }
- bool FillsBoundsCompletely() const override { return false; }
-
- private:
- Layer* layer_;
- int paint_count_;
- int lcd_notification_count_;
- };
-
void SetupTree() override {
- scoped_refptr<Layer> root_layer;
- if (layer_tree_host()->settings().impl_side_painting)
- root_layer = PictureLayer::Create(&client_);
- else
- root_layer = ContentLayer::Create(&client_);
+ num_tiles_rastered_ = 0;
+
+ scoped_refptr<Layer> root_layer = PictureLayer::Create(&client_);
+ client_.set_fill_with_nonsolid_color(true);
root_layer->SetIsDrawable(true);
- root_layer->SetBounds(gfx::Size(1, 1));
+ root_layer->SetBounds(gfx::Size(10, 10));
+ root_layer->SetContentsOpaque(true);
layer_tree_host()->SetRootLayer(root_layer);
- client_.set_layer(root_layer.get());
- // The expecations are based on the assumption that the default
+ // The expectations are based on the assumption that the default
// LCD settings are:
EXPECT_TRUE(layer_tree_host()->settings().can_use_lcd_text);
- EXPECT_FALSE(root_layer->can_use_lcd_text());
LayerTreeHostTest::SetupTree();
}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
- void AfterTest() override {}
- void DidCommit() override {
+ void DidCommitAndDrawFrame() override {
switch (layer_tree_host()->source_frame_number()) {
case 1:
- // The first update consists of one LCD notification and one paint.
- EXPECT_EQ(1, client_.lcd_notification_count());
- EXPECT_EQ(1, client_.paint_count());
- // LCD text must have been enabled on the layer.
- EXPECT_TRUE(layer_tree_host()->root_layer()->can_use_lcd_text());
PostSetNeedsCommitToMainThread();
break;
case 2:
- // Since nothing changed on layer, there should be no notification
- // or paint on the second update.
- EXPECT_EQ(1, client_.lcd_notification_count());
- EXPECT_EQ(1, client_.paint_count());
- // LCD text must not have changed.
- EXPECT_TRUE(layer_tree_host()->root_layer()->can_use_lcd_text());
- // Change layer opacity that should trigger lcd notification.
+ // Change layer opacity that should trigger lcd change.
layer_tree_host()->root_layer()->SetOpacity(.5f);
- // No need to request a commit - setting opacity will do it.
break;
- default:
- // Verify that there is no extra commit due to layer invalidation.
- EXPECT_EQ(3, layer_tree_host()->source_frame_number());
- // LCD notification count should have incremented due to
- // change in layer opacity.
- EXPECT_EQ(2, client_.lcd_notification_count());
- // Paint count should be incremented due to invalidation.
- EXPECT_EQ(2, client_.paint_count());
- // LCD text must have been disabled on the layer due to opacity.
- EXPECT_FALSE(layer_tree_host()->root_layer()->can_use_lcd_text());
+ case 3:
+ // Change layer opacity that should not trigger lcd change.
+ layer_tree_host()->root_layer()->SetOpacity(1.f);
+ break;
+ case 4:
EndTest();
break;
}
}
+ void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+ const Tile* tile) override {
+ ++num_tiles_rastered_;
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ PictureLayerImpl* root_layer =
+ static_cast<PictureLayerImpl*>(host_impl->active_tree()->root_layer());
+ bool can_use_lcd_text =
+ host_impl->active_tree()->root_layer()->can_use_lcd_text();
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // The first draw.
+ EXPECT_EQ(1, num_tiles_rastered_);
+ EXPECT_TRUE(can_use_lcd_text);
+ EXPECT_TRUE(root_layer->RasterSourceUsesLCDText());
+ break;
+ case 1:
+ // Nothing changed on the layer.
+ EXPECT_EQ(1, num_tiles_rastered_);
+ EXPECT_TRUE(can_use_lcd_text);
+ EXPECT_TRUE(root_layer->RasterSourceUsesLCDText());
+ break;
+ case 2:
+ // LCD text was disabled; it should be re-rastered with LCD text off.
+ EXPECT_EQ(2, num_tiles_rastered_);
+ EXPECT_FALSE(can_use_lcd_text);
+ EXPECT_FALSE(root_layer->RasterSourceUsesLCDText());
+ break;
+ case 3:
+ // LCD text was enabled, but it's sticky and stays off.
+ EXPECT_EQ(2, num_tiles_rastered_);
+ EXPECT_TRUE(can_use_lcd_text);
+ EXPECT_FALSE(root_layer->RasterSourceUsesLCDText());
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
private:
- NotificationClient client_;
+ FakeContentLayerClient client_;
+ int num_tiles_rastered_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLCDNotification);
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestLCDChange);
// Verify that the BeginFrame notification is used to initiate rendering.
class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest {
public:
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->begin_frame_scheduling_enabled = true;
+ settings->use_external_begin_frame_source = true;
}
void BeginTest() override {
@@ -2255,7 +2785,7 @@ class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled
: public LayerTreeHostTest {
public:
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->begin_frame_scheduling_enabled = true;
+ settings->use_external_begin_frame_source = true;
settings->using_synchronous_renderer_compositor = true;
}
@@ -2282,7 +2812,7 @@ class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
: commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {}
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->begin_frame_scheduling_enabled = true;
+ settings->use_external_begin_frame_source = true;
}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
@@ -2298,7 +2828,7 @@ class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
}
void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
- bool did_handle) override {
+ CommitEarlyOutReason reason) override {
commit_abort_count_++;
// Initiate another abortable commit.
host_impl->SetNeedsCommit();
@@ -2327,10 +2857,26 @@ class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
class LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor
: public LayerTreeHostTestAbortedCommitDoesntStall {
+ protected:
void InitializeSettings(LayerTreeSettings* settings) override {
LayerTreeHostTestAbortedCommitDoesntStall::InitializeSettings(settings);
settings->using_synchronous_renderer_compositor = true;
}
+
+ void ScheduledActionInvalidateOutputSurface() override {
+ ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor::
+ CallOnDraw,
+ base::Unretained(this)));
+ }
+
+ void CallOnDraw() {
+ // Synchronous compositor does not draw unless told to do so by the output
+ // surface.
+ output_surface()->client()->OnDraw();
+ }
};
MULTI_THREAD_TEST_F(
@@ -2385,14 +2931,18 @@ class LayerTreeHostTestChangeLayerPropertiesInPaintContents
void set_layer(Layer* layer) { layer_ = layer; }
- void PaintContents(
- SkCanvas* canvas,
- const gfx::Rect& clip,
- ContentLayerClient::GraphicsContextStatus gc_status) override {
+ void PaintContents(SkCanvas* canvas,
+ const gfx::Rect& clip,
+ PaintingControlSetting picture_control) override {
layer_->SetBounds(gfx::Size(2, 2));
}
- void DidChangeLayerCanUseLCDText() override {}
+ void PaintContentsToDisplayList(
+ DisplayItemList* display_list,
+ const gfx::Rect& clip,
+ PaintingControlSetting picture_control) override {
+ NOTIMPLEMENTED();
+ }
bool FillsBoundsCompletely() const override { return false; }
@@ -2426,10 +2976,10 @@ class LayerTreeHostTestChangeLayerPropertiesInPaintContents
num_commits_++;
if (num_commits_ == 1) {
LayerImpl* root_layer = host_impl->active_tree()->root_layer();
- EXPECT_SIZE_EQ(gfx::Size(1, 1), root_layer->bounds());
+ EXPECT_EQ(gfx::Size(1, 1), root_layer->bounds());
} else {
LayerImpl* root_layer = host_impl->active_tree()->root_layer();
- EXPECT_SIZE_EQ(gfx::Size(2, 2), root_layer->bounds());
+ EXPECT_EQ(gfx::Size(2, 2), root_layer->bounds());
EndTest();
}
}
@@ -2449,9 +2999,7 @@ class MockIOSurfaceWebGraphicsContext3D : public TestWebGraphicsContext3D {
test_capabilities_.gpu.texture_rectangle = true;
}
- virtual GLuint createTexture() override {
- return 1;
- }
+ GLuint createTexture() override { return 1; }
MOCK_METHOD1(activeTexture, void(GLenum texture));
MOCK_METHOD2(bindTexture, void(GLenum target,
GLuint texture_id));
@@ -2468,14 +3016,13 @@ class MockIOSurfaceWebGraphicsContext3D : public TestWebGraphicsContext3D {
GLenum type,
GLintptr offset));
MOCK_METHOD1(deleteTexture, void(GLenum texture));
- MOCK_METHOD2(produceTextureCHROMIUM,
- void(GLenum target, const GLbyte* mailbox));
+ MOCK_METHOD3(produceTextureDirectCHROMIUM,
+ void(GLuint texture, GLenum target, const GLbyte* mailbox));
};
class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest {
protected:
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
scoped_ptr<MockIOSurfaceWebGraphicsContext3D> mock_context_owned(
new MockIOSurfaceWebGraphicsContext3D);
mock_context_ = mock_context_owned.get();
@@ -2554,18 +3101,16 @@ class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest {
CHECK_EQ(DrawQuad::IO_SURFACE_CONTENT, quad->material);
const IOSurfaceDrawQuad* io_surface_draw_quad =
IOSurfaceDrawQuad::MaterialCast(quad);
- EXPECT_SIZE_EQ(io_surface_size_, io_surface_draw_quad->io_surface_size);
+ EXPECT_EQ(io_surface_size_, io_surface_draw_quad->io_surface_size);
EXPECT_NE(0u, io_surface_draw_quad->io_surface_resource_id);
EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_RECTANGLE_ARB),
resource_provider->TargetForTesting(
io_surface_draw_quad->io_surface_resource_id));
- EXPECT_CALL(*mock_context_, bindTexture(GL_TEXTURE_RECTANGLE_ARB, 1))
- .Times(1);
if (delegating_renderer()) {
// The io surface layer's resource should be sent to the parent.
- EXPECT_CALL(*mock_context_,
- produceTextureCHROMIUM(GL_TEXTURE_RECTANGLE_ARB, _)).Times(1);
+ EXPECT_CALL(*mock_context_, produceTextureDirectCHROMIUM(
+ _, GL_TEXTURE_RECTANGLE_ARB, _)).Times(1);
} else {
// The io surface layer's texture is drawn.
EXPECT_CALL(*mock_context_, activeTexture(GL_TEXTURE0)).Times(AtLeast(1));
@@ -2646,138 +3191,96 @@ TEST_F(LayerTreeHostTestNumFramesPending, DISABLED_GLRenderer) {
RunTest(true, false, true);
}
-class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest {
+class LayerTreeHostTestResourcelessSoftwareDraw : public LayerTreeHostTest {
public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- // PictureLayer can only be used with impl side painting enabled.
- settings->impl_side_painting = true;
- }
-
void SetupTree() override {
- layer_ = FakePictureLayer::Create(&client_);
- // Force commits to not be aborted so new frames get drawn, otherwise
- // the renderer gets deferred initialized but nothing new needs drawing.
- layer_->set_always_update_resources(true);
- layer_tree_host()->SetRootLayer(layer_);
- LayerTreeHostTest::SetupTree();
- }
-
- void BeginTest() override {
- did_initialize_gl_ = false;
- did_release_gl_ = false;
- last_source_frame_number_drawn_ = -1; // Never drawn.
- PostSetNeedsCommitToMainThread();
- }
+ root_layer_ = FakePictureLayer::Create(&client_);
+ root_layer_->SetIsDrawable(true);
+ root_layer_->SetBounds(gfx::Size(50, 50));
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
- scoped_ptr<TestWebGraphicsContext3D> context3d(
- TestWebGraphicsContext3D::Create());
+ parent_layer_ = FakePictureLayer::Create(&client_);
+ parent_layer_->SetIsDrawable(true);
+ parent_layer_->SetBounds(gfx::Size(50, 50));
+ parent_layer_->SetForceRenderSurface(true);
- return FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice),
- delegating_renderer());
- }
+ child_layer_ = FakePictureLayer::Create(&client_);
+ child_layer_->SetIsDrawable(true);
+ child_layer_->SetBounds(gfx::Size(50, 50));
- void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
- ASSERT_TRUE(host_impl->RootLayer());
- FakePictureLayerImpl* layer_impl =
- static_cast<FakePictureLayerImpl*>(host_impl->RootLayer());
-
- // The same frame can be draw multiple times if new visible tiles are
- // rasterized. But we want to make sure we only post DeferredInitialize
- // and ReleaseGL once, so early out if the same frame is drawn again.
- if (last_source_frame_number_drawn_ ==
- host_impl->active_tree()->source_frame_number())
- return;
+ root_layer_->AddChild(parent_layer_);
+ parent_layer_->AddChild(child_layer_);
+ layer_tree_host()->SetRootLayer(root_layer_);
- last_source_frame_number_drawn_ =
- host_impl->active_tree()->source_frame_number();
-
- if (!did_initialize_gl_) {
- EXPECT_LE(1u, layer_impl->append_quads_count());
- ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(
- &LayerTreeHostTestDeferredInitialize::DeferredInitializeAndRedraw,
- base::Unretained(this),
- base::Unretained(host_impl)));
- } else if (did_initialize_gl_ && !did_release_gl_) {
- EXPECT_LE(2u, layer_impl->append_quads_count());
- ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&LayerTreeHostTestDeferredInitialize::ReleaseGLAndRedraw,
- base::Unretained(this),
- base::Unretained(host_impl)));
- } else if (did_initialize_gl_ && did_release_gl_) {
- EXPECT_LE(3u, layer_impl->append_quads_count());
- EndTest();
- }
+ LayerTreeHostTest::SetupTree();
}
- void DeferredInitializeAndRedraw(LayerTreeHostImpl* host_impl) {
- EXPECT_FALSE(did_initialize_gl_);
- // SetAndInitializeContext3D calls SetNeedsCommit.
- FakeOutputSurface* fake_output_surface =
- static_cast<FakeOutputSurface*>(host_impl->output_surface());
- scoped_refptr<TestContextProvider> context_provider =
- TestContextProvider::Create(); // Not bound to thread.
- EXPECT_TRUE(
- fake_output_surface->InitializeAndSetContext3d(context_provider));
- did_initialize_gl_ = true;
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
+ if (delegating_renderer()) {
+ return FakeOutputSurface::CreateDelegatingSoftware(
+ make_scoped_ptr(new SoftwareOutputDevice));
+ } else {
+ return FakeOutputSurface::CreateSoftware(
+ make_scoped_ptr(new SoftwareOutputDevice));
+ }
}
- void ReleaseGLAndRedraw(LayerTreeHostImpl* host_impl) {
- EXPECT_TRUE(did_initialize_gl_);
- EXPECT_FALSE(did_release_gl_);
- // ReleaseGL calls SetNeedsCommit.
- static_cast<FakeOutputSurface*>(host_impl->output_surface())->ReleaseGL();
- did_release_gl_ = true;
+ void BeginTest() override {
+ PostSetNeedsCommitToMainThread();
+ swap_count_ = 0;
}
- void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
- ASSERT_TRUE(result);
- DelegatedFrameData* delegated_frame_data =
- output_surface()->last_sent_frame().delegated_frame_data.get();
- if (!delegated_frame_data)
- return;
-
- // Return all resources immediately.
- TransferableResourceArray resources_to_return =
- output_surface()->resources_held_by_parent();
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ if (host_impl->GetDrawMode() == DRAW_MODE_RESOURCELESS_SOFTWARE) {
+ EXPECT_EQ(1u, frame_data->render_passes.size());
+ // Has at least 3 quads for each layer.
+ RenderPass* render_pass = frame_data->render_passes[0];
+ EXPECT_GE(render_pass->quad_list.size(), 3u);
+ } else {
+ EXPECT_EQ(2u, frame_data->render_passes.size());
- CompositorFrameAck ack;
- for (size_t i = 0; i < resources_to_return.size(); ++i)
- output_surface()->ReturnResource(resources_to_return[i].id, &ack);
- host_impl->ReclaimResources(&ack);
+ // At least root layer quad in root render pass.
+ EXPECT_GE(frame_data->render_passes[0]->quad_list.size(), 1u);
+ // At least parent and child layer quads in parent render pass.
+ EXPECT_GE(frame_data->render_passes[1]->quad_list.size(), 2u);
+ }
+ return draw_result;
}
- void AfterTest() override {
- EXPECT_TRUE(did_initialize_gl_);
- EXPECT_TRUE(did_release_gl_);
+ void SwapBuffersCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ swap_count_++;
+ switch (swap_count_) {
+ case 1: {
+ gfx::Transform identity;
+ gfx::Rect empty_rect;
+ bool resourceless_software_draw = true;
+ host_impl->SetExternalDrawConstraints(identity, empty_rect, empty_rect,
+ empty_rect, identity,
+ resourceless_software_draw);
+ host_impl->SetFullRootLayerDamage();
+ host_impl->SetNeedsRedraw();
+ break;
+ }
+ case 2:
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ }
}
+ void AfterTest() override {}
+
private:
FakeContentLayerClient client_;
- scoped_refptr<FakePictureLayer> layer_;
- bool did_initialize_gl_;
- bool did_release_gl_;
- int last_source_frame_number_drawn_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostTestDeferredInitialize);
-
-class LayerTreeHostTestDeferredInitializeWithGpuRasterization
- : public LayerTreeHostTestDeferredInitialize {
- void InitializeSettings(LayerTreeSettings* settings) override {
- // PictureLayer can only be used with impl side painting enabled.
- settings->impl_side_painting = true;
- settings->gpu_rasterization_enabled = true;
- settings->gpu_rasterization_forced = true;
- }
+ scoped_refptr<Layer> root_layer_;
+ scoped_refptr<Layer> parent_layer_;
+ scoped_refptr<Layer> child_layer_;
+ int swap_count_;
};
-MULTI_THREAD_TEST_F(LayerTreeHostTestDeferredInitializeWithGpuRasterization);
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestResourcelessSoftwareDraw);
// Test for UI Resource management.
class LayerTreeHostTestUIResource : public LayerTreeHostTest {
@@ -2785,7 +3288,7 @@ class LayerTreeHostTestUIResource : public LayerTreeHostTest {
LayerTreeHostTestUIResource() : num_ui_resources_(0) {}
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->texture_id_allocation_chunk_size = 1;
+ settings->renderer_settings.texture_id_allocation_chunk_size = 1;
}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
@@ -2852,12 +3355,12 @@ class LayerTreeHostTestUIResource : public LayerTreeHostTest {
}
void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
- if (!layer_tree_host()->settings().impl_side_painting)
+ if (!impl->settings().impl_side_painting)
PerformTest(impl);
}
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- if (layer_tree_host()->settings().impl_side_painting)
+ if (impl->settings().impl_side_painting)
PerformTest(impl);
}
@@ -2928,6 +3431,9 @@ class PushPropertiesCountingLayer : public Layer {
needs_push_properties_ = true;
}
+ // Something to make this layer push properties, but no other layer.
+ void MakePushProperties() { SetContentsOpaque(!contents_opaque()); }
+
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override {
return PushPropertiesCountingLayerImpl::Create(tree_impl, id());
}
@@ -2967,6 +3473,7 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest {
void SetupTree() override {
root_ = PushPropertiesCountingLayer::Create();
+ root_->CreateRenderSurface();
child_ = PushPropertiesCountingLayer::Create();
child2_ = PushPropertiesCountingLayer::Create();
grandchild_ = PushPropertiesCountingLayer::Create();
@@ -2979,24 +3486,31 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest {
child2_->AddChild(leaf_always_pushing_layer_);
other_root_ = PushPropertiesCountingLayer::Create();
+ other_root_->CreateRenderSurface();
// Don't set the root layer here.
LayerTreeHostTest::SetupTree();
}
void DidCommitAndDrawFrame() override {
- ++num_commits_;
-
- EXPECT_EQ(expected_push_properties_root_, root_->push_properties_count());
- EXPECT_EQ(expected_push_properties_child_, child_->push_properties_count());
+ EXPECT_EQ(expected_push_properties_root_, root_->push_properties_count())
+ << "num_commits: " << num_commits_;
+ EXPECT_EQ(expected_push_properties_child_, child_->push_properties_count())
+ << "num_commits: " << num_commits_;
EXPECT_EQ(expected_push_properties_grandchild_,
- grandchild_->push_properties_count());
+ grandchild_->push_properties_count())
+ << "num_commits: " << num_commits_;
EXPECT_EQ(expected_push_properties_child2_,
- child2_->push_properties_count());
+ child2_->push_properties_count())
+ << "num_commits: " << num_commits_;
EXPECT_EQ(expected_push_properties_other_root_,
- other_root_->push_properties_count());
+ other_root_->push_properties_count())
+ << "num_commits: " << num_commits_;
EXPECT_EQ(expected_push_properties_leaf_layer_,
- leaf_always_pushing_layer_->push_properties_count());
+ leaf_always_pushing_layer_->push_properties_count())
+ << "num_commits: " << num_commits_;
+
+ ++num_commits_;
// The scrollbar layer always needs to be pushed.
if (root_->layer_tree_host()) {
@@ -3086,12 +3600,12 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest {
// No layers need commit.
break;
case 12:
- child_->SetPosition(gfx::Point(1, 1));
+ child_->MakePushProperties();
// The modified layer needs commit
++expected_push_properties_child_;
break;
case 13:
- child2_->SetPosition(gfx::Point(1, 1));
+ child2_->MakePushProperties();
// The modified layer needs commit
++expected_push_properties_child2_;
break;
@@ -3103,7 +3617,7 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest {
++expected_push_properties_grandchild_;
break;
case 15:
- grandchild_->SetPosition(gfx::Point(1, 1));
+ grandchild_->MakePushProperties();
// The modified layer needs commit
++expected_push_properties_grandchild_;
break;
@@ -3351,6 +3865,7 @@ class LayerTreeHostTestPropertyChangesDuringUpdateArePushed
void SetupTree() override {
root_ = Layer::Create();
+ root_->CreateRenderSurface();
root_->SetBounds(gfx::Size(1, 1));
bool paint_scrollbar = true;
@@ -3407,6 +3922,7 @@ class LayerTreeHostTestSetDrawableCausesCommit : public LayerTreeHostTest {
void SetupTree() override {
root_ = PushPropertiesCountingLayer::Create();
+ root_->CreateRenderSurface();
child_ = PushPropertiesCountingLayer::Create();
root_->AddChild(child_);
@@ -3468,6 +3984,7 @@ class LayerTreeHostTestCasePushPropertiesThreeGrandChildren
void SetupTree() override {
root_ = PushPropertiesCountingLayer::Create();
+ root_->CreateRenderSurface();
child_ = PushPropertiesCountingLayer::Create();
grandchild1_ = PushPropertiesCountingLayer::Create();
grandchild2_ = PushPropertiesCountingLayer::Create();
@@ -3936,7 +4453,7 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
LayerInvalidateCausesDraw() : num_commits_(0), num_draws_(0) {}
void BeginTest() override {
- ASSERT_TRUE(!!invalidate_layer_.get())
+ ASSERT_TRUE(invalidate_layer_)
<< "Derived tests must set this in SetupTree";
// One initial commit.
@@ -4021,6 +4538,7 @@ class LayerTreeHostTestPushHiddenLayer : public LayerTreeHostTest {
protected:
void SetupTree() override {
root_layer_ = Layer::Create();
+ root_layer_->CreateRenderSurface();
root_layer_->SetPosition(gfx::Point());
root_layer_->SetBounds(gfx::Size(10, 10));
@@ -4129,6 +4647,7 @@ class LayerTreeHostTestAbortEvictedTextures : public LayerTreeHostTest {
scoped_refptr<SolidColorLayer> root_layer = SolidColorLayer::Create();
root_layer->SetBounds(gfx::Size(200, 200));
root_layer->SetIsDrawable(true);
+ root_layer->CreateRenderSurface();
layer_tree_host()->SetRootLayer(root_layer);
LayerTreeHostTest::SetupTree();
@@ -4188,8 +4707,7 @@ class LayerTreeHostTestMaxTransferBufferUsageBytes : public LayerTreeHostTest {
settings->use_one_copy = false;
}
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
scoped_refptr<TestContextProvider> context_provider =
TestContextProvider::Create();
context_provider->SetMaxTransferBufferUsageBytes(512 * 512);
@@ -4330,8 +4848,7 @@ class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
: first_output_surface_memory_limit_(4321234),
second_output_surface_memory_limit_(1234321) {}
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
if (!first_context_provider_.get()) {
first_context_provider_ = TestContextProvider::Create();
} else {
@@ -4357,7 +4874,10 @@ class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
}
void SetupTree() override {
- root_ = FakeContentLayer::Create(&client_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ root_ = FakePictureLayer::Create(&client_);
+ else
+ root_ = FakeContentLayer::Create(&client_);
root_->SetBounds(gfx::Size(20, 20));
layer_tree_host()->SetRootLayer(root_);
LayerTreeHostTest::SetupTree();
@@ -4399,20 +4919,21 @@ class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
size_t first_output_surface_memory_limit_;
size_t second_output_surface_memory_limit_;
FakeContentLayerClient client_;
- scoped_refptr<FakeContentLayer> root_;
+ scoped_refptr<Layer> root_;
};
-// No output to copy for delegated renderers.
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface);
struct TestSwapPromiseResult {
TestSwapPromiseResult()
- : did_swap_called(false),
+ : did_activate_called(false),
+ did_swap_called(false),
did_not_swap_called(false),
dtor_called(false),
- reason(SwapPromise::DID_NOT_SWAP_UNKNOWN) {}
+ reason(SwapPromise::COMMIT_FAILS) {}
+ bool did_activate_called;
bool did_swap_called;
bool did_not_swap_called;
bool dtor_called;
@@ -4429,8 +4950,17 @@ class TestSwapPromise : public SwapPromise {
result_->dtor_called = true;
}
+ void DidActivate() override {
+ base::AutoLock lock(result_->lock);
+ EXPECT_FALSE(result_->did_activate_called);
+ EXPECT_FALSE(result_->did_swap_called);
+ EXPECT_FALSE(result_->did_not_swap_called);
+ result_->did_activate_called = true;
+ }
+
void DidSwap(CompositorFrameMetadata* metadata) override {
base::AutoLock lock(result_->lock);
+ EXPECT_TRUE(result_->did_activate_called);
EXPECT_FALSE(result_->did_swap_called);
EXPECT_FALSE(result_->did_not_swap_called);
result_->did_swap_called = true;
@@ -4440,6 +4970,8 @@ class TestSwapPromise : public SwapPromise {
base::AutoLock lock(result_->lock);
EXPECT_FALSE(result_->did_swap_called);
EXPECT_FALSE(result_->did_not_swap_called);
+ EXPECT_FALSE(result_->did_activate_called &&
+ reason != DidNotSwapReason::SWAP_FAILS);
result_->did_not_swap_called = true;
result_->reason = reason;
}
@@ -4473,6 +5005,22 @@ class LayerTreeHostTestBreakSwapPromise : public LayerTreeHostTest {
}
}
+ void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->pending_tree()) {
+ int frame = host_impl->pending_tree()->source_frame_number();
+ base::AutoLock lock(swap_promise_result_[frame].lock);
+ EXPECT_FALSE(swap_promise_result_[frame].did_activate_called);
+ EXPECT_FALSE(swap_promise_result_[frame].did_swap_called);
+ }
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ int frame = host_impl->active_tree()->source_frame_number();
+ base::AutoLock lock(swap_promise_result_[frame].lock);
+ EXPECT_TRUE(swap_promise_result_[frame].did_activate_called);
+ EXPECT_FALSE(swap_promise_result_[frame].did_swap_called);
+ }
+
void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
commit_complete_count_++;
if (commit_complete_count_ == 1) {
@@ -4500,6 +5048,7 @@ class LayerTreeHostTestBreakSwapPromise : public LayerTreeHostTest {
{
// The second commit is aborted since it contains no updates.
base::AutoLock lock(swap_promise_result_[1].lock);
+ EXPECT_FALSE(swap_promise_result_[1].did_activate_called);
EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
EXPECT_EQ(SwapPromise::COMMIT_NO_UPDATE, swap_promise_result_[1].reason);
@@ -4510,6 +5059,7 @@ class LayerTreeHostTestBreakSwapPromise : public LayerTreeHostTest {
// The last commit completes but it does not cause swap buffer because
// there is no damage in the frame data.
base::AutoLock lock(swap_promise_result_[2].lock);
+ EXPECT_TRUE(swap_promise_result_[2].did_activate_called);
EXPECT_FALSE(swap_promise_result_[2].did_swap_called);
EXPECT_TRUE(swap_promise_result_[2].did_not_swap_called);
EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[2].reason);
@@ -4524,32 +5074,126 @@ class LayerTreeHostTestBreakSwapPromise : public LayerTreeHostTest {
MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromise);
-class LayerTreeHostTestBreakSwapPromiseForVisibilityAbortedCommit
- : public LayerTreeHostTest {
- protected:
- void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+class LayerTreeHostTestKeepSwapPromise : public LayerTreeTest {
+ public:
+ LayerTreeHostTestKeepSwapPromise() {}
+
+ void BeginTest() override {
+ layer_ = SolidColorLayer::Create();
+ layer_->SetIsDrawable(true);
+ layer_->SetBounds(gfx::Size(10, 10));
+ layer_tree_host()->SetRootLayer(layer_);
+ gfx::Size bounds(100, 100);
+ layer_tree_host()->SetViewportSize(bounds);
+ PostSetNeedsCommitToMainThread();
+ }
void DidCommit() override {
- layer_tree_host()->SetDeferCommits(true);
- layer_tree_host()->SetNeedsCommit();
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&LayerTreeHostTestKeepSwapPromise::ChangeFrame,
+ base::Unretained(this)));
+ }
+
+ void ChangeFrame() {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ layer_->SetBounds(gfx::Size(10, 11));
+ layer_tree_host()->QueueSwapPromise(
+ make_scoped_ptr(new TestSwapPromise(&swap_promise_result_)));
+ break;
+ case 2:
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
}
- void DidDeferCommit() override {
+ void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->pending_tree()) {
+ if (host_impl->pending_tree()->source_frame_number() == 1) {
+ base::AutoLock lock(swap_promise_result_.lock);
+ EXPECT_FALSE(swap_promise_result_.did_activate_called);
+ EXPECT_FALSE(swap_promise_result_.did_swap_called);
+ SetCallback(true);
+ } else {
+ SetCallback(false);
+ }
+ }
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->active_tree()->source_frame_number() == 1) {
+ base::AutoLock lock(swap_promise_result_.lock);
+ EXPECT_TRUE(swap_promise_result_.did_activate_called);
+ EXPECT_FALSE(swap_promise_result_.did_swap_called);
+ }
+ }
+
+ void ActivationCallback() {
+ // DidActivate needs to happen before the tree activation callback.
+ base::AutoLock lock(swap_promise_result_.lock);
+ EXPECT_TRUE(swap_promise_result_.did_activate_called);
+ }
+
+ void SetCallback(bool enable) {
+ output_surface()->SetTreeActivationCallback(
+ enable
+ ? base::Bind(&LayerTreeHostTestKeepSwapPromise::ActivationCallback,
+ base::Unretained(this))
+ : base::Closure());
+ }
+
+ void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
+ EXPECT_TRUE(result);
+ if (host_impl->active_tree()->source_frame_number() >= 1) {
+ // The commit changes layers so it should cause a swap.
+ base::AutoLock lock(swap_promise_result_.lock);
+ EXPECT_TRUE(swap_promise_result_.did_swap_called);
+ EXPECT_FALSE(swap_promise_result_.did_not_swap_called);
+ EXPECT_TRUE(swap_promise_result_.dtor_called);
+ EndTest();
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ scoped_refptr<Layer> layer_;
+ TestSwapPromiseResult swap_promise_result_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestKeepSwapPromise);
+
+class LayerTreeHostTestBreakSwapPromiseForVisibility
+ : public LayerTreeHostTest {
+ protected:
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void SetVisibleFalseAndQueueSwapPromise() {
layer_tree_host()->SetVisible(false);
scoped_ptr<SwapPromise> swap_promise(
new TestSwapPromise(&swap_promise_result_));
layer_tree_host()->QueueSwapPromise(swap_promise.Pass());
- layer_tree_host()->SetDeferCommits(false);
+ }
+
+ void ScheduledActionWillSendBeginMainFrame() override {
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&LayerTreeHostTestBreakSwapPromiseForVisibility
+ ::SetVisibleFalseAndQueueSwapPromise,
+ base::Unretained(this)));
}
void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
- bool did_handle) override {
+ CommitEarlyOutReason reason) override {
EndTest();
}
void AfterTest() override {
{
base::AutoLock lock(swap_promise_result_.lock);
+ EXPECT_FALSE(swap_promise_result_.did_activate_called);
EXPECT_FALSE(swap_promise_result_.did_swap_called);
EXPECT_TRUE(swap_promise_result_.did_not_swap_called);
EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_.reason);
@@ -4560,47 +5204,46 @@ class LayerTreeHostTestBreakSwapPromiseForVisibilityAbortedCommit
TestSwapPromiseResult swap_promise_result_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostTestBreakSwapPromiseForVisibilityAbortedCommit);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromiseForVisibility);
-class LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit
- : public LayerTreeHostTest {
+class LayerTreeHostTestBreakSwapPromiseForContext : public LayerTreeHostTest {
protected:
- void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
- void DidCommit() override {
- if (TestEnded())
- return;
- layer_tree_host()->SetDeferCommits(true);
- layer_tree_host()->SetNeedsCommit();
+ LayerTreeHostTestBreakSwapPromiseForContext()
+ : output_surface_lost_triggered_(false) {
}
- void DidDeferCommit() override {
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void LoseOutputSurfaceAndQueueSwapPromise() {
layer_tree_host()->DidLoseOutputSurface();
scoped_ptr<SwapPromise> swap_promise(
new TestSwapPromise(&swap_promise_result_));
layer_tree_host()->QueueSwapPromise(swap_promise.Pass());
- layer_tree_host()->SetDeferCommits(false);
}
- void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
- bool did_handle) override {
- EndTest();
- // This lets the test finally commit and exit.
+ void ScheduledActionWillSendBeginMainFrame() override {
+ if (output_surface_lost_triggered_)
+ return;
+ output_surface_lost_triggered_ = true;
+
MainThreadTaskRunner()->PostTask(
FROM_HERE,
- base::Bind(&LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit::
- FindOutputSurface,
+ base::Bind(&LayerTreeHostTestBreakSwapPromiseForContext
+ ::LoseOutputSurfaceAndQueueSwapPromise,
base::Unretained(this)));
}
- void FindOutputSurface() {
- layer_tree_host()->OnCreateAndInitializeOutputSurfaceAttempted(true);
+ void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
+ CommitEarlyOutReason reason) override {
+ // This is needed so that the impl-thread state matches main-thread state.
+ host_impl->DidLoseOutputSurface();
+ EndTest();
}
void AfterTest() override {
{
base::AutoLock lock(swap_promise_result_.lock);
+ EXPECT_FALSE(swap_promise_result_.did_activate_called);
EXPECT_FALSE(swap_promise_result_.did_swap_called);
EXPECT_TRUE(swap_promise_result_.did_not_swap_called);
EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_.reason);
@@ -4608,11 +5251,12 @@ class LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit
}
}
+ bool output_surface_lost_triggered_;
TestSwapPromiseResult swap_promise_result_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit);
+ LayerTreeHostTestBreakSwapPromiseForContext);
class SimpleSwapPromiseMonitor : public SwapPromiseMonitor {
public:
@@ -4763,19 +5407,17 @@ class LayerTreeHostTestGpuRasterizationDefault : public LayerTreeHostTest {
void BeginTest() override {
Layer* root = layer_tree_host()->root_layer();
PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
- PicturePile* pile = layer->GetPicturePileForTesting();
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
// Verify default values.
EXPECT_TRUE(root->IsSuitableForGpuRasterization());
EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
- EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
- EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
// Setting gpu rasterization trigger does not enable gpu rasterization.
layer_tree_host()->SetHasGpuRasterizationTrigger(true);
EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
- EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
PostSetNeedsCommitToMainThread();
}
@@ -4819,23 +5461,21 @@ class LayerTreeHostTestGpuRasterizationEnabled : public LayerTreeHostTest {
void BeginTest() override {
Layer* root = layer_tree_host()->root_layer();
PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
- PicturePile* pile = layer->GetPicturePileForTesting();
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
// Verify default values.
EXPECT_TRUE(root->IsSuitableForGpuRasterization());
EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
- EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
- EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
// Gpu rasterization trigger is relevant.
layer_tree_host()->SetHasGpuRasterizationTrigger(true);
EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
- EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
// Content-based veto is relevant as well.
- pile->SetUnsuitableForGpuRasterizationForTesting();
- EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+ recording_source->SetUnsuitableForGpuRasterizationForTesting();
+ EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
// Veto will take effect when layers are updated.
// The results will be verified after commit is completed below.
@@ -4866,7 +5506,7 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationEnabled);
class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest {
protected:
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->impl_side_painting = true;
+ ASSERT_TRUE(settings->impl_side_painting);
EXPECT_FALSE(settings->gpu_rasterization_forced);
settings->gpu_rasterization_forced = true;
@@ -4875,7 +5515,8 @@ class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest {
void SetupTree() override {
LayerTreeHostTest::SetupTree();
- scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+ scoped_refptr<FakePictureLayer> layer =
+ FakePictureLayer::Create(&layer_client_);
layer->SetBounds(gfx::Size(10, 10));
layer->SetIsDrawable(true);
layer_tree_host()->root_layer()->AddChild(layer);
@@ -4884,23 +5525,21 @@ class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest {
void BeginTest() override {
Layer* root = layer_tree_host()->root_layer();
PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
- PicturePile* pile = layer->GetPicturePileForTesting();
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
// Verify default values.
EXPECT_TRUE(root->IsSuitableForGpuRasterization());
EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
- EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
// With gpu rasterization forced, gpu rasterization trigger is irrelevant.
- EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
layer_tree_host()->SetHasGpuRasterizationTrigger(true);
EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
- EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
// Content-based veto is irrelevant as well.
- pile->SetUnsuitableForGpuRasterizationForTesting();
- EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+ recording_source->SetUnsuitableForGpuRasterizationForTesting();
+ EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
// Veto will take effect when layers are updated.
// The results will be verified after commit is completed below.
@@ -4911,7 +5550,7 @@ class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest {
}
void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
- EXPECT_TRUE(host_impl->pending_tree()->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl->sync_tree()->use_gpu_rasterization());
EXPECT_TRUE(host_impl->use_gpu_rasterization());
}
@@ -4926,7 +5565,7 @@ class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest {
FakeContentLayerClient layer_client_;
};
-MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationForced);
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestGpuRasterizationForced);
class LayerTreeHostTestContinuousPainting : public LayerTreeHostTest {
public:
@@ -4939,6 +5578,7 @@ class LayerTreeHostTestContinuousPainting : public LayerTreeHostTest {
void SetupTree() override {
scoped_refptr<Layer> root_layer = Layer::Create();
root_layer->SetBounds(bounds_);
+ root_layer->CreateRenderSurface();
if (layer_tree_host()->settings().impl_side_painting) {
picture_layer_ = FakePictureLayer::Create(&client_);
@@ -4964,7 +5604,7 @@ class LayerTreeHostTestContinuousPainting : public LayerTreeHostTest {
base::Unretained(this)));
// Wait 50x longer than expected.
double milliseconds_per_frame =
- 1000.0 / layer_tree_host()->settings().refresh_rate;
+ 1000.0 / layer_tree_host()->settings().renderer_settings.refresh_rate;
MainThreadTaskRunner()->PostDelayedTask(
FROM_HERE,
base::Bind(
@@ -5021,6 +5661,132 @@ class LayerTreeHostTestContinuousPainting : public LayerTreeHostTest {
MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousPainting);
+class LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame
+ : public LayerTreeHostTest {
+ public:
+ enum { kExpectedNumImplFrames = 10 };
+
+ LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame()
+ : will_begin_impl_frame_count_(0), did_finish_impl_frame_count_(0) {}
+
+ void BeginTest() override {
+ // Kick off the test with a commit.
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
+ const BeginFrameArgs& args) override {
+ EXPECT_EQ(will_begin_impl_frame_count_, did_finish_impl_frame_count_);
+ EXPECT_FALSE(TestEnded());
+ will_begin_impl_frame_count_++;
+ }
+
+ void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) override {
+ did_finish_impl_frame_count_++;
+ EXPECT_EQ(will_begin_impl_frame_count_, did_finish_impl_frame_count_);
+
+ // Request a number of commits to cause multiple impl frames. We expect to
+ // get one more impl frames than the number of commits requested because
+ // after a commit it takes one frame to become idle.
+ if (did_finish_impl_frame_count_ < kExpectedNumImplFrames - 1)
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void SendBeginMainFrameNotExpectedSoon() override { EndTest(); }
+
+ void AfterTest() override {
+ EXPECT_GT(will_begin_impl_frame_count_, 0);
+ EXPECT_GT(did_finish_impl_frame_count_, 0);
+ EXPECT_EQ(will_begin_impl_frame_count_, did_finish_impl_frame_count_);
+
+ // TODO(mithro): Figure out why the multithread version of this test
+ // sometimes has one more frame then expected. Possibly related to
+ // http://crbug.com/443185
+ if (!HasImplThread()) {
+ EXPECT_EQ(will_begin_impl_frame_count_, kExpectedNumImplFrames);
+ EXPECT_EQ(did_finish_impl_frame_count_, kExpectedNumImplFrames);
+ }
+ }
+
+ private:
+ int will_begin_impl_frame_count_;
+ int did_finish_impl_frame_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame);
+
+class LayerTreeHostTestSendBeginFramesToChildren : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestSendBeginFramesToChildren()
+ : begin_frame_sent_to_children_(false) {
+ }
+
+ void BeginTest() override {
+ // Kick off the test with a commit.
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void SendBeginFramesToChildren(const BeginFrameArgs& args) override {
+ begin_frame_sent_to_children_ = true;
+ EndTest();
+ }
+
+ void DidBeginMainFrame() override {
+ // Children requested BeginFrames.
+ layer_tree_host()->SetChildrenNeedBeginFrames(true);
+ }
+
+ void AfterTest() override {
+ // Ensure that BeginFrame message is sent to children during parent
+ // scheduler handles its BeginFrame.
+ EXPECT_TRUE(begin_frame_sent_to_children_);
+ }
+
+ private:
+ bool begin_frame_sent_to_children_;
+};
+
+SINGLE_THREAD_TEST_F(LayerTreeHostTestSendBeginFramesToChildren);
+
+class LayerTreeHostTestSendBeginFramesToChildrenWithExternalBFS
+ : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestSendBeginFramesToChildrenWithExternalBFS()
+ : begin_frame_sent_to_children_(false) {
+ }
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->use_external_begin_frame_source = true;
+ }
+
+ void BeginTest() override {
+ // Kick off the test with a commit.
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void SendBeginFramesToChildren(const BeginFrameArgs& args) override {
+ begin_frame_sent_to_children_ = true;
+ EndTest();
+ }
+
+ void DidBeginMainFrame() override {
+ // Children requested BeginFrames.
+ layer_tree_host()->SetChildrenNeedBeginFrames(true);
+ }
+
+ void AfterTest() override {
+ // Ensure that BeginFrame message is sent to children during parent
+ // scheduler handles its BeginFrame.
+ EXPECT_TRUE(begin_frame_sent_to_children_);
+ }
+
+ private:
+ bool begin_frame_sent_to_children_;
+};
+
+SINGLE_THREAD_TEST_F(LayerTreeHostTestSendBeginFramesToChildrenWithExternalBFS);
+
class LayerTreeHostTestActivateOnInvisible : public LayerTreeHostTest {
public:
LayerTreeHostTestActivateOnInvisible()
@@ -5131,6 +5897,7 @@ class LayerTreeHostTestSynchronousCompositeSwapPromise
// Second swap promise fails to swap.
{
base::AutoLock lock(swap_promise_result_[1].lock);
+ EXPECT_TRUE(swap_promise_result_[1].did_activate_called);
EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
@@ -5140,6 +5907,7 @@ class LayerTreeHostTestSynchronousCompositeSwapPromise
// Third swap promises also fails to swap (and draw).
{
base::AutoLock lock(swap_promise_result_[2].lock);
+ EXPECT_TRUE(swap_promise_result_[2].did_activate_called);
EXPECT_FALSE(swap_promise_result_[2].did_swap_called);
EXPECT_TRUE(swap_promise_result_[2].did_not_swap_called);
EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[2].reason);
@@ -5177,11 +5945,11 @@ class LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer
EndTest();
}
- void ApplyViewportDeltas(
- const gfx::Vector2d& inner,
- const gfx::Vector2d& outer,
- float scale_delta,
- float top_controls_delta) override {
+ void ApplyViewportDeltas(const gfx::Vector2dF& inner,
+ const gfx::Vector2dF& outer,
+ const gfx::Vector2dF& elastic_overscroll_delta,
+ float scale_delta,
+ float top_controls_delta) override {
EXPECT_EQ(info_.page_scale_delta, scale_delta);
EXPECT_EQ(info_.top_controls_delta, top_controls_delta);
deltas_sent_to_client_ = true;
@@ -5205,4 +5973,1293 @@ class LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer
};
MULTI_THREAD_TEST_F(LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer);
+
+class LayerTreeHostTestCrispUpAfterPinchEnds : public LayerTreeHostTest {
+ protected:
+ LayerTreeHostTestCrispUpAfterPinchEnds()
+ : playback_allowed_event_(true, true) {}
+
+ void SetupTree() override {
+ frame_ = 1;
+ posted_ = false;
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(500, 500));
+
+ scoped_refptr<Layer> pinch = Layer::Create();
+ pinch->SetBounds(gfx::Size(500, 500));
+ pinch->SetScrollClipLayerId(root->id());
+ pinch->SetIsContainerForFixedPositionLayers(true);
+ root->AddChild(pinch);
+
+ scoped_ptr<FakePicturePile> pile(
+ new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+ ImplSidePaintingSettings().default_tile_grid_size));
+ pile->SetPlaybackAllowedEvent(&playback_allowed_event_);
+ scoped_refptr<FakePictureLayer> layer =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ layer->SetBounds(gfx::Size(500, 500));
+ layer->SetContentsOpaque(true);
+ // Avoid LCD text on the layer so we don't cause extra commits when we
+ // pinch.
+ layer->disable_lcd_text();
+ pinch->AddChild(layer);
+
+ layer_tree_host()->RegisterViewportLayers(NULL, root, pinch, pinch);
+ layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ // Returns the delta scale of all quads in the frame's root pass from their
+ // ideal, or 0 if they are not all the same.
+ float FrameQuadScaleDeltaFromIdeal(LayerTreeHostImpl::FrameData* frame_data) {
+ if (frame_data->has_no_damage)
+ return 0.f;
+ float frame_scale = 0.f;
+ RenderPass* root_pass = frame_data->render_passes.back();
+ for (const auto& draw_quad : root_pass->quad_list) {
+ // Checkerboards mean an incomplete frame.
+ if (draw_quad->material != DrawQuad::TILED_CONTENT)
+ return 0.f;
+ const TileDrawQuad* quad = TileDrawQuad::MaterialCast(draw_quad);
+ float quad_scale =
+ quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width());
+ float transform_scale =
+ SkMScalarToFloat(quad->quadTransform().matrix().get(0, 0));
+ float scale = quad_scale / transform_scale;
+ if (frame_scale != 0.f && frame_scale != scale)
+ return 0.f;
+ frame_scale = scale;
+ }
+ return frame_scale;
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ float quad_scale_delta = FrameQuadScaleDeltaFromIdeal(frame_data);
+ switch (frame_) {
+ case 1:
+ // Drew at page scale 1 before any pinching.
+ EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ PostNextAfterDraw(host_impl);
+ break;
+ case 2:
+ if (quad_scale_delta != 1.f)
+ break;
+ // Drew at page scale 1.5 after pinching in.
+ EXPECT_EQ(1.5f, host_impl->active_tree()->current_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ PostNextAfterDraw(host_impl);
+ break;
+ case 3:
+ // By pinching out, we will create a new tiling and raster it. This may
+ // cause some additional draws, though we should still be drawing with
+ // the old 1.5 tiling.
+ if (frame_data->has_no_damage)
+ break;
+ // Drew at page scale 1 with the 1.5 tiling while pinching out.
+ EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor());
+ EXPECT_EQ(1.5f, quad_scale_delta);
+ // We don't PostNextAfterDraw here, instead we wait for the new tiling
+ // to finish rastering so we don't get any noise in further steps.
+ break;
+ case 4:
+ // Drew at page scale 1 with the 1.5 tiling after pinching out completed
+ // while waiting for texture uploads to complete.
+ EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor());
+ // This frame will not have any damage, since it's actually the same as
+ // the last frame, and should contain no incomplete tiles. We just want
+ // to make sure we drew here at least once after the pinch ended to be
+ // sure that drawing after pinch doesn't leave us at the wrong scale
+ EXPECT_TRUE(frame_data->has_no_damage);
+ PostNextAfterDraw(host_impl);
+ break;
+ case 5:
+ if (quad_scale_delta != 1.f)
+ break;
+ // Drew at scale 1 after texture uploads are done.
+ EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ EndTest();
+ break;
+ }
+ return draw_result;
+ }
+
+ void PostNextAfterDraw(LayerTreeHostImpl* host_impl) {
+ if (posted_)
+ return;
+ posted_ = true;
+ ImplThreadTaskRunner()->PostDelayedTask(
+ FROM_HERE, base::Bind(&LayerTreeHostTestCrispUpAfterPinchEnds::Next,
+ base::Unretained(this), host_impl),
+ // Use a delay to allow raster/upload to happen in between frames. This
+ // should cause flakiness if we fail to block raster/upload when
+ // desired.
+ base::TimeDelta::FromMilliseconds(16 * 4));
+ }
+
+ void Next(LayerTreeHostImpl* host_impl) {
+ ++frame_;
+ posted_ = false;
+ switch (frame_) {
+ case 2:
+ // Pinch zoom in.
+ host_impl->PinchGestureBegin();
+ host_impl->PinchGestureUpdate(1.5f, gfx::Point(100, 100));
+ host_impl->PinchGestureEnd();
+ break;
+ case 3:
+ // Pinch zoom back to 1.f but don't end it.
+ host_impl->PinchGestureBegin();
+ host_impl->PinchGestureUpdate(1.f / 1.5f, gfx::Point(100, 100));
+ break;
+ case 4:
+ // End the pinch, but delay tile production.
+ playback_allowed_event_.Reset();
+ host_impl->PinchGestureEnd();
+ break;
+ case 5:
+ // Let tiles complete.
+ playback_allowed_event_.Signal();
+ break;
+ }
+ }
+
+ void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+ const Tile* tile) override {
+ if (frame_ == 3) {
+ // On frame 3, we will have a lower res tile complete for the pinch-out
+ // gesture even though it's not displayed. We wait for it here to prevent
+ // flakiness.
+ EXPECT_EQ(0.75f, tile->contents_scale());
+ PostNextAfterDraw(host_impl);
+ }
+ // On frame_ == 4, we are preventing texture uploads from completing,
+ // so this verifies they are not completing before frame_ == 5.
+ // Flaky failures here indicate we're failing to prevent uploads from
+ // completing.
+ EXPECT_NE(4, frame_) << tile->contents_scale();
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+ int frame_;
+ bool posted_;
+ base::WaitableEvent playback_allowed_event_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestCrispUpAfterPinchEnds);
+
+class LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy
+ : public LayerTreeHostTestCrispUpAfterPinchEnds {
+ protected:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->use_one_copy = true;
+ }
+
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
+ scoped_ptr<TestWebGraphicsContext3D> context3d =
+ TestWebGraphicsContext3D::Create();
+ context3d->set_support_image(true);
+ context3d->set_support_sync_query(true);
+#if defined(OS_MACOSX)
+ context3d->set_support_texture_rectangle(true);
+#endif
+
+ if (delegating_renderer())
+ return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
+ else
+ return FakeOutputSurface::Create3d(context3d.Pass());
+ }
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy);
+
+class RasterizeWithGpuRasterizationCreatesResources : public LayerTreeHostTest {
+ protected:
+ RasterizeWithGpuRasterizationCreatesResources() {}
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->impl_side_painting = true;
+ settings->gpu_rasterization_forced = true;
+ }
+
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(500, 500));
+
+ scoped_ptr<FakePicturePile> pile(
+ new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+ ImplSidePaintingSettings().default_tile_grid_size));
+ scoped_refptr<FakePictureLayer> layer =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ layer->SetBounds(gfx::Size(500, 500));
+ layer->SetContentsOpaque(true);
+ root->AddChild(layer);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_NE(0u, host_impl->resource_provider()->num_resources());
+ EndTest();
+ return draw_result;
+ }
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(RasterizeWithGpuRasterizationCreatesResources);
+
+class GpuRasterizationRasterizesBorderTiles : public LayerTreeHostTest {
+ protected:
+ GpuRasterizationRasterizesBorderTiles() : viewport_size_(1024, 2048) {}
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->impl_side_painting = true;
+ settings->gpu_rasterization_enabled = true;
+ settings->gpu_rasterization_forced = true;
+ }
+
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_ptr<FakePicturePile> pile(
+ new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+ ImplSidePaintingSettings().default_tile_grid_size));
+ scoped_refptr<FakePictureLayer> root =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ root->SetBounds(gfx::Size(10000, 10000));
+ root->SetContentsOpaque(true);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostTest::SetupTree();
+ layer_tree_host()->SetViewportSize(viewport_size_);
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(10u, host_impl->resource_provider()->num_resources());
+ EndTest();
+ return draw_result;
+ }
+
+ void AfterTest() override {}
+
+ private:
+ FakeContentLayerClient client_;
+ gfx::Size viewport_size_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(GpuRasterizationRasterizesBorderTiles);
+
+class LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles
+ : public LayerTreeHostTest {
+ protected:
+ LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles()
+ : playback_allowed_event_(true, true) {}
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->impl_side_painting = true;
+ }
+
+ void SetupTree() override {
+ step_ = 1;
+ continuous_draws_ = 0;
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(500, 500));
+
+ scoped_refptr<Layer> pinch = Layer::Create();
+ pinch->SetBounds(gfx::Size(500, 500));
+ pinch->SetScrollClipLayerId(root->id());
+ pinch->SetIsContainerForFixedPositionLayers(true);
+ root->AddChild(pinch);
+
+ scoped_ptr<FakePicturePile> pile(
+ new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+ ImplSidePaintingSettings().default_tile_grid_size));
+ pile->SetPlaybackAllowedEvent(&playback_allowed_event_);
+ scoped_refptr<FakePictureLayer> layer =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ layer->SetBounds(gfx::Size(500, 500));
+ layer->SetContentsOpaque(true);
+ // Avoid LCD text on the layer so we don't cause extra commits when we
+ // pinch.
+ layer->disable_lcd_text();
+ pinch->AddChild(layer);
+
+ layer_tree_host()->RegisterViewportLayers(NULL, root, pinch, pinch);
+ layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ // Returns the delta scale of all quads in the frame's root pass from their
+ // ideal, or 0 if they are not all the same.
+ float FrameQuadScaleDeltaFromIdeal(LayerTreeHostImpl::FrameData* frame_data) {
+ if (frame_data->has_no_damage)
+ return 0.f;
+ float frame_scale = 0.f;
+ RenderPass* root_pass = frame_data->render_passes.back();
+ for (const auto& draw_quad : root_pass->quad_list) {
+ const TileDrawQuad* quad = TileDrawQuad::MaterialCast(draw_quad);
+ float quad_scale =
+ quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width());
+ float transform_scale =
+ SkMScalarToFloat(quad->quadTransform().matrix().get(0, 0));
+ float scale = quad_scale / transform_scale;
+ if (frame_scale != 0.f && frame_scale != scale)
+ return 0.f;
+ frame_scale = scale;
+ }
+ return frame_scale;
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ float quad_scale_delta = FrameQuadScaleDeltaFromIdeal(frame_data);
+ switch (step_) {
+ case 1:
+ // Drew at scale 1 before any pinching.
+ EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ break;
+ case 2:
+ if (quad_scale_delta != 1.f / 1.5f)
+ break;
+ // Drew at scale 1 still though the ideal is 1.5.
+ EXPECT_EQ(1.5f, host_impl->active_tree()->current_page_scale_factor());
+ EXPECT_EQ(1.f / 1.5f, quad_scale_delta);
+ break;
+ case 3:
+ // Continuous draws are attempted.
+ EXPECT_EQ(1.5f, host_impl->active_tree()->current_page_scale_factor());
+ if (!frame_data->has_no_damage)
+ EXPECT_EQ(1.f / 1.5f, quad_scale_delta);
+ break;
+ case 4:
+ if (quad_scale_delta != 1.f)
+ break;
+ // Drew at scale 1.5 when all the tiles completed.
+ EXPECT_EQ(1.5f, host_impl->active_tree()->current_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ break;
+ case 5:
+ // TODO(danakj): We get more draws before the NotifyReadyToDraw
+ // because it is asynchronous from the previous draw and happens late.
+ break;
+ case 6:
+ // NotifyReadyToDraw happened. If we were already inside a frame, we may
+ // try to draw once more.
+ break;
+ case 7:
+ NOTREACHED() << "No draws should happen once we have a complete frame.";
+ break;
+ }
+ return draw_result;
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ switch (step_) {
+ case 1:
+ // Delay tile production.
+ playback_allowed_event_.Reset();
+ // Pinch zoom in to cause new tiles to be required.
+ host_impl->PinchGestureBegin();
+ host_impl->PinchGestureUpdate(1.5f, gfx::Point(100, 100));
+ host_impl->PinchGestureEnd();
+ ++step_;
+ break;
+ case 2:
+ ++step_;
+ break;
+ case 3:
+ // We should continue to try draw while there are incomplete visible
+ // tiles.
+ if (++continuous_draws_ > 5) {
+ // Allow the tiles to complete.
+ playback_allowed_event_.Signal();
+ ++step_;
+ }
+ break;
+ case 4:
+ ++step_;
+ break;
+ case 5:
+ // Waiting for NotifyReadyToDraw.
+ break;
+ case 6:
+ // NotifyReadyToDraw happened.
+ ++step_;
+ break;
+ }
+ }
+
+ void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) override {
+ if (step_ == 5) {
+ ++step_;
+ // NotifyReadyToDraw has happened, we may draw once more, but should not
+ // get any more draws after that. End the test after a timeout to watch
+ // for any extraneous draws.
+ // TODO(brianderson): We could remove this delay and instead wait until
+ // the BeginFrameSource decides it doesn't need to send frames anymore,
+ // or test that it already doesn't here.
+ EndTestAfterDelayMs(16 * 4);
+ }
+ }
+
+ void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+ const Tile* tile) override {
+ // On step_ == 2, we are preventing texture uploads from completing,
+ // so this verifies they are not completing before step_ == 3.
+ // Flaky failures here indicate we're failing to prevent uploads from
+ // completing.
+ EXPECT_NE(2, step_);
+ }
+
+ void AfterTest() override { EXPECT_GT(continuous_draws_, 5); }
+
+ FakeContentLayerClient client_;
+ int step_;
+ int continuous_draws_;
+ base::WaitableEvent playback_allowed_event_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles);
+
+class LayerTreeHostTestOneActivatePerPrepareTiles : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestOneActivatePerPrepareTiles()
+ : notify_ready_to_activate_count_(0u),
+ scheduled_prepare_tiles_count_(0) {}
+
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+ scoped_refptr<FakePictureLayer> root_layer =
+ FakePictureLayer::Create(&client_);
+ root_layer->SetBounds(gfx::Size(1500, 1500));
+ root_layer->SetIsDrawable(true);
+
+ layer_tree_host()->SetRootLayer(root_layer);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void BeginTest() override {
+ layer_tree_host()->SetViewportSize(gfx::Size(16, 16));
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
+ bool success) override {
+ ASSERT_TRUE(success);
+ host_impl->tile_manager()->SetScheduledRasterTaskLimitForTesting(1);
+ }
+
+ void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override {
+ ++notify_ready_to_activate_count_;
+ EndTestAfterDelayMs(100);
+ }
+
+ void ScheduledActionPrepareTiles() override {
+ ++scheduled_prepare_tiles_count_;
+ }
+
+ void AfterTest() override {
+ // Expect at most a notification for each scheduled prepare tiles, plus one
+ // for the initial commit (which doesn't go through scheduled actions).
+ // The reason this is not an equality is because depending on timing, we
+ // might get a prepare tiles but not yet get a notification that we're
+ // ready to activate. The intent of a test is to ensure that we don't
+ // get more than one notification per prepare tiles, so this is OK.
+ EXPECT_LE(notify_ready_to_activate_count_,
+ 1u + scheduled_prepare_tiles_count_);
+ }
+
+ protected:
+ FakeContentLayerClient client_;
+ size_t notify_ready_to_activate_count_;
+ size_t scheduled_prepare_tiles_count_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestOneActivatePerPrepareTiles);
+
+class LayerTreeHostTestFrameTimingRequestsSaveTimestamps
+ : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestFrameTimingRequestsSaveTimestamps()
+ : check_results_on_commit_(false) {}
+
+ void SetupTree() override {
+ scoped_refptr<FakePictureLayer> root_layer =
+ FakePictureLayer::Create(&client_);
+ root_layer->SetBounds(gfx::Size(200, 200));
+ root_layer->SetIsDrawable(true);
+
+ scoped_refptr<FakePictureLayer> child_layer =
+ FakePictureLayer::Create(&client_);
+ child_layer->SetBounds(gfx::Size(1500, 1500));
+ child_layer->SetIsDrawable(true);
+
+ std::vector<FrameTimingRequest> requests;
+ requests.push_back(FrameTimingRequest(1, gfx::Rect(0, 0, 100, 100)));
+ requests.push_back(FrameTimingRequest(2, gfx::Rect(300, 0, 100, 100)));
+ child_layer->SetFrameTimingRequests(requests);
+
+ root_layer->AddChild(child_layer);
+ layer_tree_host()->SetRootLayer(root_layer);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
+ if (!check_results_on_commit_)
+ return;
+
+ // Since in reality, the events will be read by LayerTreeHost during commit,
+ // we check the requests here to ensure that they are correct at the next
+ // commit time (as opposed to checking in DrawLayers for instance).
+ // TODO(vmpstr): Change this to read things from the main thread when this
+ // information is propagated to the main thread (not yet implemented).
+ FrameTimingTracker* tracker = host_impl->frame_timing_tracker();
+
+ // Check composite events.
+ {
+ scoped_ptr<FrameTimingTracker::CompositeTimingSet> timing_set =
+ tracker->GroupCompositeCountsByRectId();
+ EXPECT_EQ(1u, timing_set->size());
+ auto rect_1_it = timing_set->find(1);
+ EXPECT_TRUE(rect_1_it != timing_set->end());
+ const auto& timing_events = rect_1_it->second;
+ EXPECT_EQ(1u, timing_events.size());
+ EXPECT_EQ(host_impl->active_tree()->source_frame_number(),
+ timing_events[0].frame_id);
+ EXPECT_GT(timing_events[0].timestamp, base::TimeTicks());
+ }
+
+ // Check main frame events.
+ {
+ scoped_ptr<FrameTimingTracker::MainFrameTimingSet> timing_set =
+ tracker->GroupMainFrameCountsByRectId();
+ EXPECT_EQ(2u, timing_set->size());
+ auto rect_1_it = timing_set->find(1);
+ EXPECT_TRUE(rect_1_it != timing_set->end());
+ const auto& timing_events = rect_1_it->second;
+ EXPECT_EQ(1u, timing_events.size());
+ EXPECT_EQ(host_impl->active_tree()->source_frame_number(),
+ timing_events[0].frame_id);
+ EXPECT_GT(timing_events[0].timestamp, base::TimeTicks());
+ EXPECT_GT(timing_events[0].end_time, timing_events[0].timestamp);
+ }
+
+ EndTest();
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ check_results_on_commit_ = true;
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void AfterTest() override {}
+
+ private:
+ FakeContentLayerClient client_;
+ bool check_results_on_commit_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestFrameTimingRequestsSaveTimestamps);
+
+class LayerTreeHostTestActivationCausesPrepareTiles : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestActivationCausesPrepareTiles()
+ : scheduled_prepare_tiles_count_(0) {}
+
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+ scoped_refptr<FakePictureLayer> root_layer =
+ FakePictureLayer::Create(&client_);
+ root_layer->SetBounds(gfx::Size(150, 150));
+ root_layer->SetIsDrawable(true);
+
+ layer_tree_host()->SetRootLayer(root_layer);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override {
+ // Ensure we've already activated.
+ EXPECT_FALSE(impl->pending_tree());
+
+ // After activating, we either need to prepare tiles, or we've already
+ // called a scheduled prepare tiles. This is done because activation might
+ // cause us to have to memory available (old active tree is gone), so we
+ // need to ensure we will get a PrepareTiles call.
+ if (!impl->prepare_tiles_needed())
+ EXPECT_GE(scheduled_prepare_tiles_count_, 1);
+ EndTest();
+ }
+
+ void ScheduledActionPrepareTiles() override {
+ ++scheduled_prepare_tiles_count_;
+ }
+
+ void AfterTest() override {}
+
+ protected:
+ FakeContentLayerClient client_;
+ int scheduled_prepare_tiles_count_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestActivationCausesPrepareTiles);
+
+// This tests an assertion that DidCommit and WillCommit happen in the same
+// stack frame with no tasks that run between them. Various embedders of
+// cc depend on this logic. ui::Compositor holds a compositor lock between
+// these events and the inspector timeline wants begin/end CompositeLayers
+// to be properly nested with other begin/end events.
+class LayerTreeHostTestNoTasksBetweenWillAndDidCommit
+ : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestNoTasksBetweenWillAndDidCommit() : did_commit_(false) {}
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void WillCommit() override {
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&LayerTreeHostTestNoTasksBetweenWillAndDidCommit::
+ EndTestShouldRunAfterDidCommit,
+ base::Unretained(this)));
+ }
+
+ void EndTestShouldRunAfterDidCommit() {
+ EXPECT_TRUE(did_commit_);
+ EndTest();
+ }
+
+ void DidCommit() override {
+ EXPECT_FALSE(did_commit_);
+ did_commit_ = true;
+ }
+
+ void AfterTest() override { EXPECT_TRUE(did_commit_); }
+
+ private:
+ bool did_commit_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoTasksBetweenWillAndDidCommit);
+
+// Verify that if a LayerImpl holds onto a copy request for multiple
+// frames that it will continue to have a render surface through
+// multiple commits, even though the Layer itself has no reason
+// to have a render surface.
+class LayerPreserveRenderSurfaceFromOutputRequests : public LayerTreeHostTest {
+ protected:
+ void SetupTree() override {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->CreateRenderSurface();
+ root->SetBounds(gfx::Size(10, 10));
+ child_ = Layer::Create();
+ child_->SetBounds(gfx::Size(20, 20));
+ root->AddChild(child_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ static void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {}
+
+ void BeginTest() override {
+ child_->RequestCopyOfOutput(
+ CopyOutputRequest::CreateBitmapRequest(base::Bind(CopyOutputCallback)));
+ EXPECT_TRUE(child_->HasCopyRequest());
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void DidCommit() override { EXPECT_FALSE(child_->HasCopyRequest()); }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ LayerImpl* child_impl = host_impl->sync_tree()->LayerById(child_->id());
+
+ switch (host_impl->sync_tree()->source_frame_number()) {
+ case 0:
+ EXPECT_TRUE(child_impl->HasCopyRequest());
+ EXPECT_TRUE(child_impl->render_surface());
+ break;
+ case 1:
+ if (host_impl->proxy()->CommitToActiveTree()) {
+ EXPECT_TRUE(child_impl->HasCopyRequest());
+ EXPECT_TRUE(child_impl->render_surface());
+ } else {
+ EXPECT_FALSE(child_impl->HasCopyRequest());
+ EXPECT_FALSE(child_impl->render_surface());
+ }
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ LayerImpl* child_impl = host_impl->active_tree()->LayerById(child_->id());
+ EXPECT_TRUE(child_impl->HasCopyRequest());
+ EXPECT_TRUE(child_impl->render_surface());
+
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // Lose output surface to prevent drawing and cause another commit.
+ host_impl->DidLoseOutputSurface();
+ break;
+ case 1:
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ scoped_refptr<Layer> child_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerPreserveRenderSurfaceFromOutputRequests);
+
+class LayerTreeHostTestUpdateCopyRequests : public LayerTreeHostTest {
+ protected:
+ void SetupTree() override {
+ root = Layer::Create();
+ child = Layer::Create();
+ root->AddChild(child);
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ static void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {}
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void DidCommit() override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(CopyOutputCallback)));
+ EXPECT_TRUE(
+ root->draw_properties().layer_or_descendant_has_copy_request);
+ break;
+ case 2:
+ EXPECT_FALSE(
+ root->draw_properties().layer_or_descendant_has_copy_request);
+ EndTest();
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ scoped_refptr<Layer> root;
+ scoped_refptr<Layer> child;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUpdateCopyRequests);
+
+class LayerTreeTestMaskLayerForSurfaceWithClippedLayer : public LayerTreeTest {
+ protected:
+ void SetupTree() override {
+ // The masked layer has bounds 50x50, but it has a child that causes
+ // the surface bounds to be larger. It also has a parent that clips the
+ // masked layer and its surface.
+
+ scoped_refptr<Layer> root = Layer::Create();
+
+ scoped_refptr<Layer> clipping_layer = Layer::Create();
+ root->AddChild(clipping_layer);
+
+ scoped_refptr<FakePictureLayer> content_layer =
+ FakePictureLayer::Create(&client_);
+ clipping_layer->AddChild(content_layer);
+
+ scoped_refptr<FakePictureLayer> content_child_layer =
+ FakePictureLayer::Create(&client_);
+ content_layer->AddChild(content_child_layer);
+
+ scoped_refptr<FakePictureLayer> mask_layer =
+ FakePictureLayer::Create(&client_);
+ content_layer->SetMaskLayer(mask_layer.get());
+
+ gfx::Size root_size(100, 100);
+ root->SetBounds(root_size);
+
+ gfx::Rect clipping_rect(20, 10, 10, 20);
+ clipping_layer->SetBounds(clipping_rect.size());
+ clipping_layer->SetPosition(clipping_rect.origin());
+ clipping_layer->SetMasksToBounds(true);
+
+ gfx::Size layer_size(50, 50);
+ content_layer->SetBounds(layer_size);
+ content_layer->SetPosition(gfx::Point() - clipping_rect.OffsetFromOrigin());
+
+ gfx::Size child_size(50, 50);
+ content_child_layer->SetBounds(child_size);
+ content_child_layer->SetPosition(gfx::Point(20, 0));
+
+ gfx::Size mask_size(100, 100);
+ mask_layer->SetBounds(mask_size);
+ mask_layer->SetIsMask(true);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(2u, frame_data->render_passes.size());
+ RenderPass* root_pass = frame_data->render_passes.back();
+ EXPECT_EQ(2u, root_pass->quad_list.size());
+
+ // There's a solid color quad under everything.
+ EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+
+ // The surface is clipped to 10x20.
+ EXPECT_EQ(DrawQuad::RENDER_PASS, root_pass->quad_list.front()->material);
+ const RenderPassDrawQuad* render_pass_quad =
+ RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
+ EXPECT_EQ(gfx::Rect(20, 10, 10, 20).ToString(),
+ render_pass_quad->rect.ToString());
+ // The masked layer is 50x50, but the surface size is 10x20. So the texture
+ // coords in the mask are scaled by 10/50 and 20/50.
+ // The surface is clipped to (20,10) so the mask texture coords are offset
+ // by 20/50 and 10/50
+ EXPECT_EQ(gfx::ScaleRect(gfx::RectF(20.f, 10.f, 10.f, 20.f), 1.f / 50.f)
+ .ToString(),
+ render_pass_quad->MaskUVRect().ToString());
+ EXPECT_EQ(gfx::Vector2dF(10.f / 50.f, 20.f / 50.f).ToString(),
+ render_pass_quad->mask_uv_scale.ToString());
+ EndTest();
+ return draw_result;
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeTestMaskLayerForSurfaceWithClippedLayer);
+
+class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest {
+ protected:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->layer_transforms_should_scale_layer_contents = true;
+ }
+
+ void SetupTree() override {
+ // Root
+ // |
+ // +-- Scaling Layer (adds a 2x scale)
+ // |
+ // +-- Content Layer
+ // +--Mask
+
+ scoped_refptr<Layer> root = Layer::Create();
+
+ scoped_refptr<Layer> scaling_layer = Layer::Create();
+ root->AddChild(scaling_layer);
+
+ scoped_refptr<FakePictureLayer> content_layer =
+ FakePictureLayer::Create(&client_);
+ scaling_layer->AddChild(content_layer);
+
+ scoped_refptr<FakePictureLayer> mask_layer =
+ FakePictureLayer::Create(&client_);
+ content_layer->SetMaskLayer(mask_layer.get());
+
+ gfx::Size root_size(100, 100);
+ root->SetBounds(root_size);
+
+ gfx::Size scaling_layer_size(50, 50);
+ scaling_layer->SetBounds(scaling_layer_size);
+ gfx::Transform scale;
+ scale.Scale(2.f, 2.f);
+ scaling_layer->SetTransform(scale);
+
+ content_layer->SetBounds(scaling_layer_size);
+
+ mask_layer->SetBounds(scaling_layer_size);
+ mask_layer->SetIsMask(true);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(2u, frame_data->render_passes.size());
+ RenderPass* root_pass = frame_data->render_passes.back();
+ EXPECT_EQ(2u, root_pass->quad_list.size());
+
+ // There's a solid color quad under everything.
+ EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+
+ EXPECT_EQ(DrawQuad::RENDER_PASS, root_pass->quad_list.front()->material);
+ const RenderPassDrawQuad* render_pass_quad =
+ RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // Check that the tree scaling is correctly taken into account for the
+ // mask, that should fully map onto the quad.
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
+ render_pass_quad->rect.ToString());
+ EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
+ render_pass_quad->MaskUVRect().ToString());
+ EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
+ render_pass_quad->mask_uv_scale.ToString());
+ break;
+ case 1:
+ // Applying a DSF should change the render surface size, but won't
+ // affect which part of the mask is used.
+ EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(),
+ render_pass_quad->rect.ToString());
+ EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
+ render_pass_quad->MaskUVRect().ToString());
+ EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
+ render_pass_quad->mask_uv_scale.ToString());
+ EndTest();
+ break;
+ }
+ return draw_result;
+ }
+
+ void DidCommit() override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ gfx::Size double_root_size(200, 200);
+ layer_tree_host()->SetViewportSize(double_root_size);
+ layer_tree_host()->SetDeviceScaleFactor(2.f);
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskLayerWithScaling);
+
+class LayerTreeTestMaskLayerWithDifferentBounds : public LayerTreeTest {
+ protected:
+ void SetupTree() override {
+ // The mask layer has bounds 100x100 but is attached to a layer with bounds
+ // 50x50.
+
+ scoped_refptr<Layer> root = Layer::Create();
+
+ scoped_refptr<FakePictureLayer> content_layer =
+ FakePictureLayer::Create(&client_);
+ root->AddChild(content_layer);
+
+ scoped_refptr<FakePictureLayer> mask_layer =
+ FakePictureLayer::Create(&client_);
+ content_layer->SetMaskLayer(mask_layer.get());
+
+ gfx::Size root_size(100, 100);
+ root->SetBounds(root_size);
+
+ gfx::Size layer_size(50, 50);
+ content_layer->SetBounds(layer_size);
+
+ gfx::Size mask_size(100, 100);
+ mask_layer->SetBounds(mask_size);
+ mask_layer->SetIsMask(true);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(2u, frame_data->render_passes.size());
+ RenderPass* root_pass = frame_data->render_passes.back();
+ EXPECT_EQ(2u, root_pass->quad_list.size());
+
+ // There's a solid color quad under everything.
+ EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+
+ EXPECT_EQ(DrawQuad::RENDER_PASS, root_pass->quad_list.front()->material);
+ const RenderPassDrawQuad* render_pass_quad =
+ RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // Check that the mask fills the surface.
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
+ render_pass_quad->rect.ToString());
+ EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
+ render_pass_quad->MaskUVRect().ToString());
+ EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
+ render_pass_quad->mask_uv_scale.ToString());
+ break;
+ case 1:
+ // Applying a DSF should change the render surface size, but won't
+ // affect which part of the mask is used.
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
+ render_pass_quad->rect.ToString());
+ EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
+ render_pass_quad->MaskUVRect().ToString());
+ EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
+ render_pass_quad->mask_uv_scale.ToString());
+ EndTest();
+ break;
+ }
+ return draw_result;
+ }
+
+ void DidCommit() override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ gfx::Size double_root_size(200, 200);
+ layer_tree_host()->SetViewportSize(double_root_size);
+ layer_tree_host()->SetDeviceScaleFactor(2.f);
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskLayerWithDifferentBounds);
+
+class LayerTreeTestReflectionMaskLayerWithDifferentBounds
+ : public LayerTreeTest {
+ protected:
+ void SetupTree() override {
+ // The replica's mask layer has bounds 100x100 but the replica is of a
+ // layer with bounds 50x50.
+
+ scoped_refptr<Layer> root = Layer::Create();
+
+ scoped_refptr<FakePictureLayer> content_layer =
+ FakePictureLayer::Create(&client_);
+ root->AddChild(content_layer);
+
+ scoped_refptr<Layer> replica_layer = Layer::Create();
+ content_layer->SetReplicaLayer(replica_layer.get());
+
+ scoped_refptr<FakePictureLayer> mask_layer =
+ FakePictureLayer::Create(&client_);
+ replica_layer->SetMaskLayer(mask_layer.get());
+
+ gfx::Size root_size(100, 100);
+ root->SetBounds(root_size);
+
+ gfx::Size layer_size(50, 50);
+ content_layer->SetBounds(layer_size);
+
+ gfx::Size mask_size(100, 100);
+ mask_layer->SetBounds(mask_size);
+ mask_layer->SetIsMask(true);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(2u, frame_data->render_passes.size());
+ RenderPass* root_pass = frame_data->render_passes.back();
+ EXPECT_EQ(3u, root_pass->quad_list.size());
+
+ // There's a solid color quad under everything.
+ EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+
+ EXPECT_EQ(DrawQuad::RENDER_PASS,
+ root_pass->quad_list.ElementAt(1)->material);
+ const RenderPassDrawQuad* render_pass_quad =
+ RenderPassDrawQuad::MaterialCast(root_pass->quad_list.ElementAt(1));
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // Check that the mask fills the surface.
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(),
+ render_pass_quad->rect.ToString());
+ EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
+ render_pass_quad->MaskUVRect().ToString());
+ EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
+ render_pass_quad->mask_uv_scale.ToString());
+ break;
+ case 1:
+ // Applying a DSF should change the render surface size, but won't
+ // affect which part of the mask is used.
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
+ render_pass_quad->rect.ToString());
+ EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(),
+ render_pass_quad->MaskUVRect().ToString());
+ EXPECT_EQ(gfx::Vector2dF(1.f, 1.f).ToString(),
+ render_pass_quad->mask_uv_scale.ToString());
+ EndTest();
+ break;
+ }
+ return draw_result;
+ }
+
+ void DidCommit() override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ gfx::Size double_root_size(200, 200);
+ layer_tree_host()->SetViewportSize(double_root_size);
+ layer_tree_host()->SetDeviceScaleFactor(2.f);
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeTestReflectionMaskLayerWithDifferentBounds);
+
+class LayerTreeTestReflectionMaskLayerForSurfaceWithUnclippedChild
+ : public LayerTreeTest {
+ protected:
+ void SetupTree() override {
+ // The replica is of a layer with bounds 50x50, but it has a child that
+ // causes the surface bounds to be larger.
+
+ scoped_refptr<Layer> root = Layer::Create();
+
+ scoped_refptr<FakePictureLayer> content_layer =
+ FakePictureLayer::Create(&client_);
+ root->AddChild(content_layer);
+
+ content_child_layer_ = FakePictureLayer::Create(&client_);
+ content_layer->AddChild(content_child_layer_);
+
+ scoped_refptr<Layer> replica_layer = Layer::Create();
+ content_layer->SetReplicaLayer(replica_layer.get());
+
+ scoped_refptr<FakePictureLayer> mask_layer =
+ FakePictureLayer::Create(&client_);
+ replica_layer->SetMaskLayer(mask_layer.get());
+
+ gfx::Size root_size(100, 100);
+ root->SetBounds(root_size);
+
+ gfx::Size layer_size(50, 50);
+ content_layer->SetBounds(layer_size);
+ content_child_layer_->SetBounds(layer_size);
+ content_child_layer_->SetPosition(gfx::PointF(50.f, 0.f));
+
+ gfx::Size mask_size(100, 100);
+ mask_layer->SetBounds(mask_size);
+ mask_layer->SetIsMask(true);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(2u, frame_data->render_passes.size());
+ RenderPass* root_pass = frame_data->render_passes.back();
+ EXPECT_EQ(3u, root_pass->quad_list.size());
+
+ // There's a solid color quad under everything.
+ EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+
+ EXPECT_EQ(DrawQuad::RENDER_PASS,
+ root_pass->quad_list.ElementAt(1)->material);
+ const RenderPassDrawQuad* replica_quad =
+ RenderPassDrawQuad::MaterialCast(root_pass->quad_list.ElementAt(1));
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // The surface is 100x50.
+ // The mask covers the owning layer only.
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 50).ToString(),
+ replica_quad->rect.ToString());
+ EXPECT_EQ(gfx::RectF(0.f, 0.f, 2.f, 1.f).ToString(),
+ replica_quad->MaskUVRect().ToString());
+ EXPECT_EQ(gfx::Vector2dF(2.f, 1.f).ToString(),
+ replica_quad->mask_uv_scale.ToString());
+ break;
+ case 1:
+ // The surface is 100x50 with its origin at (-50, 0).
+ // The mask covers the owning layer only.
+ EXPECT_EQ(gfx::Rect(-50, 0, 100, 50).ToString(),
+ replica_quad->rect.ToString());
+ EXPECT_EQ(gfx::RectF(-1.f, 0.f, 2.f, 1.f).ToString(),
+ replica_quad->MaskUVRect().ToString());
+ EXPECT_EQ(gfx::Vector2dF(2.f, 1.f).ToString(),
+ replica_quad->mask_uv_scale.ToString());
+ EndTest();
+ break;
+ }
+ return draw_result;
+ }
+
+ void DidCommit() override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ // Move the child to (-50, 0) instead. Now the mask should be moved to
+ // still cover the layer being replicated.
+ content_child_layer_->SetPosition(gfx::PointF(-50.f, 0.f));
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
+ scoped_refptr<FakePictureLayer> content_child_layer_;
+ FakeContentLayerClient client_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeTestReflectionMaskLayerForSurfaceWithUnclippedChild);
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation.cc b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
index cfd8a1489af..ed27a03a2f8 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
@@ -8,6 +8,7 @@
#include "cc/animation/layer_animation_controller.h"
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/timing_function.h"
+#include "cc/base/time_util.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/test/animation_test_common.h"
@@ -101,17 +102,16 @@ class LayerTreeHostAnimationTestSetNeedsAnimateInsideAnimationCallback
int num_begin_frames_;
};
-MULTI_THREAD_TEST_F(
+SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostAnimationTestSetNeedsAnimateInsideAnimationCallback);
// Add a layer animation and confirm that
-// LayerTreeHostImpl::updateAnimationState does get called and continues to
-// get called.
+// LayerTreeHostImpl::UpdateAnimationState does get called.
class LayerTreeHostAnimationTestAddAnimation
: public LayerTreeHostAnimationTest {
public:
LayerTreeHostAnimationTestAddAnimation()
- : num_begin_frames_(0), received_animation_started_notification_(false) {}
+ : update_animation_state_was_called_(false) {}
void BeginTest() override {
PostAddInstantAnimationToMainThread(layer_tree_host()->root_layer());
@@ -119,53 +119,28 @@ class LayerTreeHostAnimationTestAddAnimation
void UpdateAnimationState(LayerTreeHostImpl* host_impl,
bool has_unfinished_animation) override {
- if (!num_begin_frames_) {
- // The animation had zero duration so LayerTreeHostImpl should no
- // longer need to animate its layers.
- EXPECT_FALSE(has_unfinished_animation);
- num_begin_frames_++;
- return;
- }
-
- if (received_animation_started_notification_) {
- EXPECT_LT(base::TimeTicks(), start_time_);
-
- LayerAnimationController* controller_impl =
- host_impl->active_tree()->root_layer()->layer_animation_controller();
- Animation* animation_impl =
- controller_impl->GetAnimation(Animation::Opacity);
- if (animation_impl)
- controller_impl->RemoveAnimation(animation_impl->id());
-
- EndTest();
- }
+ EXPECT_FALSE(has_unfinished_animation);
+ update_animation_state_was_called_ = true;
}
void NotifyAnimationStarted(base::TimeTicks monotonic_time,
Animation::TargetProperty target_property,
int group) override {
- received_animation_started_notification_ = true;
- start_time_ = monotonic_time;
- if (num_begin_frames_) {
- EXPECT_LT(base::TimeTicks(), start_time_);
-
- LayerAnimationController* controller =
- layer_tree_host()->root_layer()->layer_animation_controller();
- Animation* animation =
- controller->GetAnimation(Animation::Opacity);
- if (animation)
- controller->RemoveAnimation(animation->id());
+ EXPECT_LT(base::TimeTicks(), monotonic_time);
- EndTest();
- }
+ LayerAnimationController* controller =
+ layer_tree_host()->root_layer()->layer_animation_controller();
+ Animation* animation = controller->GetAnimation(Animation::OPACITY);
+ if (animation)
+ controller->RemoveAnimation(animation->id());
+
+ EndTest();
}
- void AfterTest() override {}
+ void AfterTest() override { EXPECT_TRUE(update_animation_state_was_called_); }
private:
- int num_begin_frames_;
- bool received_animation_started_notification_;
- base::TimeTicks start_time_;
+ bool update_animation_state_was_called_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAddAnimation);
@@ -220,8 +195,9 @@ class LayerTreeHostAnimationTestAnimationsGetDeleted
void AnimateLayers(LayerTreeHostImpl* host_impl,
base::TimeTicks monotonic_time) override {
- bool have_animations = !host_impl->animation_registrar()->
- active_animation_controllers().empty();
+ bool have_animations = !host_impl->animation_registrar()
+ ->active_animation_controllers_for_testing()
+ .empty();
if (!started_animating_ && have_animations) {
started_animating_ = true;
return;
@@ -247,236 +223,6 @@ class LayerTreeHostAnimationTestAnimationsGetDeleted
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimationsGetDeleted);
-// Ensures that animations continue to be ticked when we are backgrounded.
-class LayerTreeHostAnimationTestTickAnimationWhileBackgrounded
- : public LayerTreeHostAnimationTest {
- public:
- LayerTreeHostAnimationTestTickAnimationWhileBackgrounded()
- : num_begin_frames_(0) {}
-
- void BeginTest() override {
- PostAddLongAnimationToMainThread(layer_tree_host()->root_layer());
- }
-
- // Use WillAnimateLayers to set visible false before the animation runs and
- // causes a commit, so we block the second visible animate in single-thread
- // mode.
- void WillAnimateLayers(LayerTreeHostImpl* host_impl,
- base::TimeTicks monotonic_time) override {
- // Verify that the host can draw, it's just not visible.
- EXPECT_TRUE(host_impl->CanDraw());
- if (num_begin_frames_ < 2) {
- if (!num_begin_frames_) {
- // We have a long animation running. It should continue to tick even
- // if we are not visible.
- PostSetVisibleToMainThread(false);
- }
- num_begin_frames_++;
- return;
- }
- EndTest();
- }
-
- void AfterTest() override {}
-
- private:
- int num_begin_frames_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostAnimationTestTickAnimationWhileBackgrounded);
-
-// Ensures that animation time remains monotonic when we switch from foreground
-// to background ticking and back, even if we're skipping draws due to
-// checkerboarding when in the foreground.
-class LayerTreeHostAnimationTestAnimationTickTimeIsMonotonic
- : public LayerTreeHostAnimationTest {
- public:
- LayerTreeHostAnimationTestAnimationTickTimeIsMonotonic()
- : has_background_ticked_(false), num_foreground_animates_(0) {}
-
- void InitializeSettings(LayerTreeSettings* settings) override {
- // Make sure that drawing many times doesn't cause a checkerboarded
- // animation to start so we avoid flake in this test.
- settings->timeout_and_draw_when_animation_checkerboards = false;
- }
-
- void BeginTest() override {
- PostAddLongAnimationToMainThread(layer_tree_host()->root_layer());
- }
-
- void AnimateLayers(LayerTreeHostImpl* host_impl,
- base::TimeTicks monotonic_time) override {
- EXPECT_GE(monotonic_time, last_tick_time_);
- last_tick_time_ = monotonic_time;
- if (host_impl->visible()) {
- num_foreground_animates_++;
- if (num_foreground_animates_ > 1 && !has_background_ticked_)
- PostSetVisibleToMainThread(false);
- else if (has_background_ticked_)
- EndTest();
- } else {
- has_background_ticked_ = true;
- PostSetVisibleToMainThread(true);
- }
- }
-
- DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame,
- DrawResult draw_result) override {
- if (TestEnded())
- return draw_result;
- return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
- }
-
- void AfterTest() override {}
-
- private:
- bool has_background_ticked_;
- int num_foreground_animates_;
- base::TimeTicks last_tick_time_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostAnimationTestAnimationTickTimeIsMonotonic);
-
-// Ensures that animations do not tick when we are backgrounded and
-// and we have an empty active tree.
-class LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree
- : public LayerTreeHostAnimationTest {
- protected:
- LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree()
- : active_tree_was_animated_(false) {}
-
- base::TimeDelta LowFrequencyAnimationInterval() const override {
- return base::TimeDelta::FromMilliseconds(4);
- }
-
- void BeginTest() override {
- PostAddAnimationToMainThread(layer_tree_host()->root_layer());
- }
-
- void NotifyAnimationFinished(base::TimeTicks monotonic_time,
- Animation::TargetProperty target_property,
- int group) override {
- // Replace animated commits with an empty tree.
- layer_tree_host()->SetRootLayer(make_scoped_refptr<Layer>(NULL));
- }
-
- void DidCommit() override {
- // This alternates setting an empty tree and a non-empty tree with an
- // animation.
- switch (layer_tree_host()->source_frame_number()) {
- case 1:
- // Wait for NotifyAnimationFinished to commit an empty tree.
- break;
- case 2:
- SetupTree();
- AddOpacityTransitionToLayer(
- layer_tree_host()->root_layer(), 0.000001, 0, 0.5, true);
- break;
- case 3:
- // Wait for NotifyAnimationFinished to commit an empty tree.
- break;
- case 4:
- EndTest();
- break;
- }
- }
-
- void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
- // At the start of every commit, block activations and make sure
- // we are backgrounded.
- if (host_impl->settings().impl_side_painting)
- host_impl->BlockNotifyReadyToActivateForTesting(true);
- PostSetVisibleToMainThread(false);
- }
-
- void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
- if (!host_impl->settings().impl_side_painting) {
- // There are no activations to block if we're not impl-side-painting,
- // so just advance the test immediately.
- if (host_impl->active_tree()->source_frame_number() < 3)
- UnblockActivations(host_impl);
- return;
- }
-
- // We block activation for several ticks to make sure that, even though
- // there is a pending tree with animations, we still do not background
- // tick if the active tree is empty.
- if (host_impl->pending_tree()->source_frame_number() < 3) {
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(
- &LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree::
- UnblockActivations,
- base::Unretained(this),
- host_impl),
- 4 * LowFrequencyAnimationInterval());
- }
- }
-
- virtual void UnblockActivations(LayerTreeHostImpl* host_impl) {
- if (host_impl->settings().impl_side_painting)
- host_impl->BlockNotifyReadyToActivateForTesting(false);
- }
-
- void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
- active_tree_was_animated_ = false;
-
- // Verify that commits are actually alternating with empty / non-empty
- // trees.
- int frame_number = host_impl->active_tree()->source_frame_number();
- switch (frame_number) {
- case 0:
- case 2:
- EXPECT_TRUE(host_impl->active_tree()->root_layer())
- << "frame: " << frame_number;
- break;
- case 1:
- case 3:
- EXPECT_FALSE(host_impl->active_tree()->root_layer())
- << "frame: " << frame_number;
- break;
- }
-
- if (host_impl->active_tree()->source_frame_number() < 3) {
- // Initiate the next commit after a delay to give us a chance to
- // background tick if the active tree isn't empty.
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(
- &LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree::
- InitiateNextCommit,
- base::Unretained(this),
- host_impl),
- 4 * LowFrequencyAnimationInterval());
- }
- }
-
- void WillAnimateLayers(LayerTreeHostImpl* host_impl,
- base::TimeTicks monotonic_time) override {
- EXPECT_TRUE(host_impl->active_tree()->root_layer());
- active_tree_was_animated_ = true;
- }
-
- void InitiateNextCommit(LayerTreeHostImpl* host_impl) {
- // Verify that we actually animated when we should have.
- bool has_active_tree = host_impl->active_tree()->root_layer();
- EXPECT_EQ(has_active_tree, active_tree_was_animated_);
-
- // The next commit is blocked until we become visible again.
- PostSetVisibleToMainThread(true);
- }
-
- void AfterTest() override {}
-
- bool active_tree_was_animated_;
-};
-
-SINGLE_AND_MULTI_THREAD_BLOCKNOTIFY_TEST_F(
- LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree);
-
// Ensure that an animation's timing function is respected.
class LayerTreeHostAnimationTestAddAnimationWithTimingFunction
: public LayerTreeHostAnimationTest {
@@ -497,18 +243,17 @@ class LayerTreeHostAnimationTestAddAnimationWithTimingFunction
LayerAnimationController* controller_impl =
host_impl->active_tree()->root_layer()->children()[0]->
layer_animation_controller();
- Animation* animation =
- controller_impl->GetAnimation(Animation::Opacity);
+ Animation* animation = controller_impl->GetAnimation(Animation::OPACITY);
if (!animation)
return;
const FloatAnimationCurve* curve =
animation->curve()->ToFloatAnimationCurve();
- float start_opacity = curve->GetValue(0.0);
+ float start_opacity = curve->GetValue(base::TimeDelta());
float end_opacity = curve->GetValue(curve->Duration());
float linearly_interpolated_opacity =
0.25f * end_opacity + 0.75f * start_opacity;
- double time = curve->Duration() * 0.25;
+ base::TimeDelta time = TimeUtil::Scale(curve->Duration(), 0.25f);
// If the linear timing function associated with this animation was not
// picked up, then the linearly interpolated opacity would be different
// because of the default ease timing function.
@@ -531,9 +276,7 @@ SINGLE_AND_MULTI_THREAD_TEST_F(
class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
: public LayerTreeHostAnimationTest {
public:
- LayerTreeHostAnimationTestSynchronizeAnimationStartTimes()
- : main_start_time_(-1.0),
- impl_start_time_(-1.0) {}
+ LayerTreeHostAnimationTestSynchronizeAnimationStartTimes() {}
void SetupTree() override {
LayerTreeHostAnimationTest::SetupTree();
@@ -551,14 +294,10 @@ class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
LayerAnimationController* controller =
layer_tree_host()->root_layer()->children()[0]->
layer_animation_controller();
- Animation* animation =
- controller->GetAnimation(Animation::Opacity);
- main_start_time_ =
- (animation->start_time() - base::TimeTicks()).InSecondsF();
+ Animation* animation = controller->GetAnimation(Animation::OPACITY);
+ main_start_time_ = animation->start_time();
controller->RemoveAnimation(animation->id());
-
- if (impl_start_time_ > 0.0)
- EndTest();
+ EndTest();
}
void UpdateAnimationState(LayerTreeHostImpl* impl_host,
@@ -566,26 +305,21 @@ class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
LayerAnimationController* controller =
impl_host->active_tree()->root_layer()->children()[0]->
layer_animation_controller();
- Animation* animation =
- controller->GetAnimation(Animation::Opacity);
+ Animation* animation = controller->GetAnimation(Animation::OPACITY);
if (!animation)
return;
- impl_start_time_ =
- (animation->start_time() - base::TimeTicks()).InSecondsF();
- controller->RemoveAnimation(animation->id());
-
- if (main_start_time_ > 0.0)
- EndTest();
+ impl_start_time_ = animation->start_time();
}
void AfterTest() override {
- EXPECT_FLOAT_EQ(impl_start_time_, main_start_time_);
+ EXPECT_EQ(impl_start_time_, main_start_time_);
+ EXPECT_LT(base::TimeTicks(), impl_start_time_);
}
private:
- double main_start_time_;
- double impl_start_time_;
+ base::TimeTicks main_start_time_;
+ base::TimeTicks impl_start_time_;
FakeContentLayerClient client_;
scoped_refptr<FakeContentLayer> content_;
};
@@ -608,8 +342,7 @@ class LayerTreeHostAnimationTestAnimationFinishedEvents
int group) override {
LayerAnimationController* controller =
layer_tree_host()->root_layer()->layer_animation_controller();
- Animation* animation =
- controller->GetAnimation(Animation::Opacity);
+ Animation* animation = controller->GetAnimation(Animation::OPACITY);
if (animation)
controller->RemoveAnimation(animation->id());
EndTest();
@@ -644,7 +377,7 @@ class LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity
LayerAnimationController* controller_impl =
host_impl->active_tree()->root_layer()->layer_animation_controller();
Animation* animation_impl =
- controller_impl->GetAnimation(Animation::Opacity);
+ controller_impl->GetAnimation(Animation::OPACITY);
controller_impl->RemoveAnimation(animation_impl->id());
EndTest();
}
@@ -683,8 +416,7 @@ class LayerTreeHostAnimationTestLayerAddedWithAnimation
// Any valid AnimationCurve will do here.
scoped_ptr<AnimationCurve> curve(new FakeFloatAnimationCurve());
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 1,
- Animation::Opacity));
+ Animation::Create(curve.Pass(), 1, 1, Animation::OPACITY));
layer->layer_animation_controller()->AddAnimation(animation.Pass());
// We add the animation *before* attaching the layer to the tree.
@@ -860,58 +592,6 @@ class LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw);
-// Make sure the main thread can still execute animations when the renderer is
-// backgrounded.
-class LayerTreeHostAnimationTestRunAnimationWhenNotVisible
- : public LayerTreeHostAnimationTest {
- public:
- LayerTreeHostAnimationTestRunAnimationWhenNotVisible() : started_times_(0) {}
-
- void SetupTree() override {
- LayerTreeHostAnimationTest::SetupTree();
- content_ = FakeContentLayer::Create(&client_);
- content_->SetBounds(gfx::Size(4, 4));
- content_->set_layer_animation_delegate(this);
- layer_tree_host()->root_layer()->AddChild(content_);
- }
-
- void BeginTest() override {
- visible_ = true;
- PostAddAnimationToMainThread(content_.get());
- }
-
- void DidCommit() override {
- visible_ = false;
- layer_tree_host()->SetVisible(false);
- }
-
- void NotifyAnimationStarted(base::TimeTicks monotonic_time,
- Animation::TargetProperty target_property,
- int group) override {
- EXPECT_FALSE(visible_);
- started_times_++;
- }
-
- void NotifyAnimationFinished(base::TimeTicks monotonic_time,
- Animation::TargetProperty target_property,
- int group) override {
- EXPECT_FALSE(visible_);
- EXPECT_EQ(1, started_times_);
- EndTest();
- }
-
- void AfterTest() override {}
-
- private:
- bool visible_;
- int started_times_;
- FakeContentLayerClient client_;
- scoped_refptr<FakeContentLayer> content_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostAnimationTestRunAnimationWhenNotVisible);
-
// Animations should not be started when frames are being skipped due to
// checkerboard.
class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations
@@ -1021,7 +701,7 @@ class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated
gfx::ScrollOffset(500.f, 550.f),
EaseInOutTimingFunction::Create()));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
animation->set_needs_synchronized_start_time(true);
bool animation_added = scroll_layer_->AddAnimation(animation.Pass());
bool impl_scrolling_supported =
@@ -1048,6 +728,120 @@ class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostAnimationTestScrollOffsetChangesArePropagated);
+// Verifies that when the main thread removes a scroll animation and sets a new
+// scroll position, the active tree takes on exactly this new scroll position
+// after activation, and the main thread doesn't receive a spurious scroll
+// delta.
+class LayerTreeHostAnimationTestScrollOffsetAnimationRemoval
+ : public LayerTreeHostAnimationTest {
+ public:
+ LayerTreeHostAnimationTestScrollOffsetAnimationRemoval()
+ : final_postion_(50.0, 100.0) {}
+
+ void SetupTree() override {
+ LayerTreeHostAnimationTest::SetupTree();
+
+ scroll_layer_ = FakeContentLayer::Create(&client_);
+ scroll_layer_->SetScrollClipLayerId(layer_tree_host()->root_layer()->id());
+ scroll_layer_->SetBounds(gfx::Size(10000, 10000));
+ scroll_layer_->SetScrollOffset(gfx::ScrollOffset(100.0, 200.0));
+ layer_tree_host()->root_layer()->AddChild(scroll_layer_);
+
+ scoped_ptr<ScrollOffsetAnimationCurve> curve(
+ ScrollOffsetAnimationCurve::Create(gfx::ScrollOffset(6500.f, 7500.f),
+ EaseInOutTimingFunction::Create()));
+ scoped_ptr<Animation> animation(
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
+ animation->set_needs_synchronized_start_time(true);
+ scroll_layer_->AddAnimation(animation.Pass());
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void BeginMainFrame(const BeginFrameArgs& args) override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 0:
+ break;
+ case 1: {
+ Animation* animation =
+ scroll_layer_->layer_animation_controller()->GetAnimation(
+ Animation::SCROLL_OFFSET);
+ scroll_layer_->layer_animation_controller()->RemoveAnimation(
+ animation->id());
+ scroll_layer_->SetScrollOffset(final_postion_);
+ break;
+ }
+ default:
+ EXPECT_EQ(final_postion_, scroll_layer_->scroll_offset());
+ }
+ }
+
+ void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->settings().impl_side_painting)
+ host_impl->BlockNotifyReadyToActivateForTesting(true);
+ }
+
+ void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
+ const BeginFrameArgs& args) override {
+ if (!host_impl->pending_tree())
+ return;
+
+ if (!host_impl->active_tree()->root_layer()) {
+ host_impl->BlockNotifyReadyToActivateForTesting(false);
+ return;
+ }
+
+ LayerImpl* scroll_layer_impl =
+ host_impl->active_tree()->root_layer()->children()[0];
+ Animation* animation =
+ scroll_layer_impl->layer_animation_controller()->GetAnimation(
+ Animation::SCROLL_OFFSET);
+
+ if (!animation || animation->run_state() != Animation::RUNNING) {
+ host_impl->BlockNotifyReadyToActivateForTesting(false);
+ return;
+ }
+
+ // Block activation until the running animation has a chance to produce a
+ // scroll delta.
+ gfx::Vector2dF scroll_delta = scroll_layer_impl->ScrollDelta();
+ if (scroll_delta.x() < 1.f || scroll_delta.y() < 1.f)
+ return;
+
+ host_impl->BlockNotifyReadyToActivateForTesting(false);
+ }
+
+ void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ if (!host_impl->settings().impl_side_painting)
+ return;
+ if (host_impl->pending_tree()->source_frame_number() != 1)
+ return;
+ LayerImpl* scroll_layer_impl =
+ host_impl->pending_tree()->root_layer()->children()[0];
+ EXPECT_EQ(final_postion_, scroll_layer_impl->CurrentScrollOffset());
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->active_tree()->source_frame_number() != 1)
+ return;
+ LayerImpl* scroll_layer_impl =
+ host_impl->active_tree()->root_layer()->children()[0];
+ EXPECT_EQ(final_postion_, scroll_layer_impl->CurrentScrollOffset());
+ EndTest();
+ }
+
+ void AfterTest() override {
+ EXPECT_EQ(final_postion_, scroll_layer_->scroll_offset());
+ }
+
+ private:
+ FakeContentLayerClient client_;
+ scoped_refptr<FakeContentLayer> scroll_layer_;
+ const gfx::ScrollOffset final_postion_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationRemoval);
+
// When animations are simultaneously added to an existing layer and to a new
// layer, they should start at the same time, even when there's already a
// running animation on the existing layer.
@@ -1108,20 +902,20 @@ class LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers
LayerAnimationController* root_controller_impl =
host_impl->active_tree()->root_layer()->layer_animation_controller();
Animation* root_animation =
- root_controller_impl->GetAnimation(Animation::Opacity);
- if (!root_animation || root_animation->run_state() != Animation::Running)
+ root_controller_impl->GetAnimation(Animation::OPACITY);
+ if (!root_animation || root_animation->run_state() != Animation::RUNNING)
return;
LayerAnimationController* child_controller_impl =
host_impl->active_tree()->root_layer()->children()
[0]->layer_animation_controller();
Animation* child_animation =
- child_controller_impl->GetAnimation(Animation::Opacity);
- EXPECT_EQ(Animation::Running, child_animation->run_state());
+ child_controller_impl->GetAnimation(Animation::OPACITY);
+ EXPECT_EQ(Animation::RUNNING, child_animation->run_state());
EXPECT_EQ(root_animation->start_time(), child_animation->start_time());
- root_controller_impl->AbortAnimations(Animation::Opacity);
- root_controller_impl->AbortAnimations(Animation::Transform);
- child_controller_impl->AbortAnimations(Animation::Opacity);
+ root_controller_impl->AbortAnimations(Animation::OPACITY);
+ root_controller_impl->AbortAnimations(Animation::TRANSFORM);
+ child_controller_impl->AbortAnimations(Animation::OPACITY);
EndTest();
}
@@ -1167,21 +961,19 @@ class LayerTreeHostAnimationTestAddAnimationAfterAnimating
// After both animations have started, verify that they have valid
// start times.
num_swap_buffers_++;
- AnimationRegistrar::AnimationControllerMap copy =
- host_impl->animation_registrar()->active_animation_controllers();
- if (copy.size() == 2u) {
+ AnimationRegistrar::AnimationControllerMap controllers_copy =
+ host_impl->animation_registrar()
+ ->active_animation_controllers_for_testing();
+ if (controllers_copy.size() == 2u) {
EndTest();
EXPECT_GE(num_swap_buffers_, 3);
- for (AnimationRegistrar::AnimationControllerMap::iterator iter =
- copy.begin();
- iter != copy.end();
- ++iter) {
- int id = ((*iter).second->id());
+ for (auto& it : controllers_copy) {
+ int id = it.first;
if (id == host_impl->RootLayer()->id()) {
- Animation* anim = (*iter).second->GetAnimation(Animation::Transform);
+ Animation* anim = it.second->GetAnimation(Animation::TRANSFORM);
EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
} else if (id == host_impl->RootLayer()->children()[0]->id()) {
- Animation* anim = (*iter).second->GetAnimation(Animation::Opacity);
+ Animation* anim = it.second->GetAnimation(Animation::OPACITY);
EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
}
}
diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc
index b12a8da62cb..a2f06113f03 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_context.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc
@@ -19,6 +19,7 @@
#include "cc/layers/video_layer_impl.h"
#include "cc/output/filter_operations.h"
#include "cc/resources/single_release_callback.h"
+#include "cc/test/failure_output_surface.h"
#include "cc/test/fake_content_layer.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_content_layer_impl.h"
@@ -81,12 +82,11 @@ class LayerTreeHostContextTest : public LayerTreeTest {
return TestWebGraphicsContext3D::Create();
}
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
if (times_to_fail_create_) {
--times_to_fail_create_;
ExpectCreateToFail();
- return nullptr;
+ return make_scoped_ptr(new FailureOutputSurface(delegating_renderer()));
}
scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
@@ -110,7 +110,7 @@ class LayerTreeHostContextTest : public LayerTreeTest {
// Only valid for single-threaded impl-side painting, which activates
// immediately and will try to draw again when content has finished.
DCHECK(!host_impl->proxy()->HasImplThread());
- DCHECK(layer_tree_host()->settings().impl_side_painting);
+ DCHECK(host_impl->settings().impl_side_painting);
return draw_result;
}
EXPECT_EQ(DRAW_SUCCESS, draw_result);
@@ -140,7 +140,7 @@ class LayerTreeHostContextTest : public LayerTreeTest {
void DidFailToInitializeOutputSurface() override { ++times_create_failed_; }
- virtual void TearDown() override {
+ void TearDown() override {
LayerTreeTest::TearDown();
EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
}
@@ -174,22 +174,22 @@ class LayerTreeHostContextTestLostContextSucceeds
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
- void RequestNewOutputSurface(bool fallback) override {
+ void RequestNewOutputSurface() override {
if (async_output_surface_creation_) {
MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
- CreateAndSetOutputSurface,
- base::Unretained(this),
- fallback));
+ FROM_HERE, base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
+ CreateAndSetOutputSurface,
+ base::Unretained(this)));
} else {
- CreateAndSetOutputSurface(fallback);
+ CreateAndSetOutputSurface();
}
}
- void CreateAndSetOutputSurface(bool fallback) {
- layer_tree_host()->SetOutputSurface(
- LayerTreeHostContextTest::CreateOutputSurface(fallback));
+ void CreateAndSetOutputSurface() {
+ scoped_ptr<OutputSurface> surface(
+ LayerTreeHostContextTest::CreateOutputSurface());
+ CHECK(surface);
+ layer_tree_host()->SetOutputSurface(surface.Pass());
}
void DidInitializeOutputSurface() override {
@@ -364,7 +364,7 @@ class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
EndTest();
}
- scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override {
+ scoped_ptr<OutputSurface> CreateOutputSurface() override {
EXPECT_TRUE(false);
return nullptr;
}
@@ -387,7 +387,7 @@ class MultipleCompositeDoesNotCreateOutputSurface
settings->single_thread_proxy_scheduler = false;
}
- void RequestNewOutputSurface(bool fallback) override {
+ void RequestNewOutputSurface() override {
EXPECT_GE(1, ++request_count_);
EndTest();
}
@@ -397,7 +397,7 @@ class MultipleCompositeDoesNotCreateOutputSurface
layer_tree_host()->Composite(base::TimeTicks());
}
- scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override {
+ scoped_ptr<OutputSurface> CreateOutputSurface() override {
EXPECT_TRUE(false);
return nullptr;
}
@@ -411,40 +411,56 @@ class MultipleCompositeDoesNotCreateOutputSurface
SINGLE_THREAD_NOIMPL_TEST_F(MultipleCompositeDoesNotCreateOutputSurface);
+// This test makes sure that once a SingleThreadProxy issues a
+// DidFailToInitializeOutputSurface, that future Composite calls will not
+// trigger additional requests for output surfaces.
class FailedCreateDoesNotCreateExtraOutputSurface
: public LayerTreeHostContextTest {
public:
FailedCreateDoesNotCreateExtraOutputSurface()
- : LayerTreeHostContextTest(), request_count_(0) {}
+ : LayerTreeHostContextTest(), num_requests_(0), has_failed_(false) {}
void InitializeSettings(LayerTreeSettings* settings) override {
settings->single_thread_proxy_scheduler = false;
}
- void RequestNewOutputSurface(bool fallback) override {
- if (request_count_ == 0) {
- ExpectCreateToFail();
- layer_tree_host()->SetOutputSurface(nullptr);
- }
- EXPECT_GE(2, ++request_count_);
- EndTest();
+ void RequestNewOutputSurface() override {
+ num_requests_++;
+ // There should be one initial request and then one request from
+ // the LayerTreeTest test hooks DidFailToInitializeOutputSurface (which is
+ // hard to skip). This second request is just ignored and is test cruft.
+ EXPECT_LE(num_requests_, 2);
+ if (num_requests_ > 1)
+ return;
+ ExpectCreateToFail();
+ layer_tree_host()->SetOutputSurface(
+ make_scoped_ptr(new FailureOutputSurface(false)));
}
void BeginTest() override {
+ // First composite tries to create a surface.
layer_tree_host()->Composite(base::TimeTicks());
- layer_tree_host()->Composite(base::TimeTicks());
- }
+ EXPECT_EQ(num_requests_, 2);
+ EXPECT_TRUE(has_failed_);
- scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override {
- EXPECT_TRUE(false);
- return nullptr;
+ // Second composite should not request or fail.
+ layer_tree_host()->Composite(base::TimeTicks());
+ EXPECT_EQ(num_requests_, 2);
+ EndTest();
}
void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
+ void DidFailToInitializeOutputSurface() override {
+ LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
+ EXPECT_FALSE(has_failed_);
+ has_failed_ = true;
+ }
+
void AfterTest() override {}
- int request_count_;
+ int num_requests_;
+ bool has_failed_;
};
SINGLE_THREAD_NOIMPL_TEST_F(FailedCreateDoesNotCreateExtraOutputSurface);
@@ -459,19 +475,18 @@ class LayerTreeHostContextTestCommitAfterDelayedOutputSurface
settings->single_thread_proxy_scheduler = false;
}
- void RequestNewOutputSurface(bool fallback) override {
+ void RequestNewOutputSurface() override {
MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
CreateAndSetOutputSurface,
- base::Unretained(this),
- fallback));
+ base::Unretained(this)));
}
- void CreateAndSetOutputSurface(bool fallback) {
+ void CreateAndSetOutputSurface() {
creating_output_ = true;
layer_tree_host()->SetOutputSurface(
- LayerTreeHostContextTest::CreateOutputSurface(fallback));
+ LayerTreeHostContextTest::CreateOutputSurface());
}
void BeginTest() override { layer_tree_host()->Composite(base::TimeTicks()); }
@@ -499,9 +514,9 @@ class LayerTreeHostContextTestAvoidUnnecessaryComposite
settings->single_thread_proxy_scheduler = false;
}
- void RequestNewOutputSurface(bool fallback) override {
+ void RequestNewOutputSurface() override {
layer_tree_host()->SetOutputSurface(
- LayerTreeHostContextTest::CreateOutputSurface(fallback));
+ LayerTreeHostContextTest::CreateOutputSurface());
EndTest();
}
@@ -565,7 +580,10 @@ class LayerTreeHostContextTestLostContextSucceedsWithContent
} else {
FakePictureLayerImpl* picture_impl = static_cast<FakePictureLayerImpl*>(
host_impl->active_tree()->root_layer()->children()[0]);
- EXPECT_TRUE(picture_impl->HighResTiling()->TileAt(0, 0)->IsReadyToDraw());
+ EXPECT_TRUE(picture_impl->HighResTiling()
+ ->TileAt(0, 0)
+ ->draw_info()
+ .IsReadyToDraw());
}
}
@@ -579,35 +597,16 @@ class LayerTreeHostContextTestLostContextSucceedsWithContent
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostContextTestLostContextSucceedsWithContent);
-class LayerTreeHostContextTestCreateOutputSurfaceFails
+class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
: public LayerTreeHostContextTest {
public:
- // Run a test that initially fails OutputSurface creation |times_to_fail|
- // times. If |expect_fallback_attempt| is |true|, an attempt to create a
- // fallback/software OutputSurface is expected to occur.
- LayerTreeHostContextTestCreateOutputSurfaceFails(int times_to_fail,
- bool expect_fallback_attempt)
- : times_to_fail_(times_to_fail),
- expect_fallback_attempt_(expect_fallback_attempt),
- did_attempt_fallback_(false),
- times_initialized_(0) {
+ LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
+ : times_to_fail_(1), times_initialized_(0) {
times_to_fail_create_ = times_to_fail_;
}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
- scoped_ptr<FakeOutputSurface> surface =
- LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
-
- if (surface)
- EXPECT_EQ(times_to_fail_, times_create_failed_);
-
- did_attempt_fallback_ = fallback;
- return surface.Pass();
- }
-
void DidInitializeOutputSurface() override { times_initialized_++; }
void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { EndTest(); }
@@ -615,38 +614,16 @@ class LayerTreeHostContextTestCreateOutputSurfaceFails
void AfterTest() override {
EXPECT_EQ(times_to_fail_, times_create_failed_);
EXPECT_NE(0, times_initialized_);
- EXPECT_EQ(expect_fallback_attempt_, did_attempt_fallback_);
}
private:
int times_to_fail_;
- bool expect_fallback_attempt_;
- bool did_attempt_fallback_;
int times_initialized_;
};
-class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
- : public LayerTreeHostContextTestCreateOutputSurfaceFails {
- public:
- LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
- : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false) {}
-};
-
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
-// After 4 failures we expect an attempt to create a fallback/software
-// OutputSurface.
-class LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback
- : public LayerTreeHostContextTestCreateOutputSurfaceFails {
- public:
- LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback()
- : LayerTreeHostContextTestCreateOutputSurfaceFails(4, true) {}
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
-
class LayerTreeHostContextTestLostContextAndEvictTextures
: public LayerTreeHostContextTest {
public:
@@ -723,7 +700,10 @@ class LayerTreeHostContextTestLostContextAndEvictTextures
if (impl->settings().impl_side_painting) {
FakePictureLayerImpl* picture_impl =
static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
- EXPECT_TRUE(picture_impl->HighResTiling()->TileAt(0, 0)->IsReadyToDraw());
+ EXPECT_TRUE(picture_impl->HighResTiling()
+ ->TileAt(0, 0)
+ ->draw_info()
+ .IsReadyToDraw());
} else {
FakeContentLayerImpl* content_impl =
static_cast<FakeContentLayerImpl*>(impl->active_tree()->root_layer());
@@ -909,7 +889,7 @@ class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
FakeContentLayerImpl* child_content = NULL;
FakeContentLayerImpl* grandchild_content = NULL;
- if (layer_tree_host()->settings().impl_side_painting) {
+ if (host_impl->settings().impl_side_painting) {
root_picture = static_cast<FakePictureLayerImpl*>(
host_impl->active_tree()->root_layer());
child_picture =
@@ -929,7 +909,7 @@ class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
++num_commits_;
switch (num_commits_) {
case 1:
- if (layer_tree_host()->settings().impl_side_painting) {
+ if (host_impl->settings().impl_side_painting) {
EXPECT_EQ(0u, root_picture->release_resources_count());
EXPECT_EQ(0u, child_picture->release_resources_count());
EXPECT_EQ(0u, grandchild_picture->release_resources_count());
@@ -944,7 +924,7 @@ class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
times_to_fail_create_ = 1;
break;
case 2:
- if (layer_tree_host()->settings().impl_side_painting) {
+ if (host_impl->settings().impl_side_painting) {
EXPECT_TRUE(root_picture->release_resources_count());
EXPECT_TRUE(child_picture->release_resources_count());
EXPECT_TRUE(grandchild_picture->release_resources_count());
@@ -1026,10 +1006,8 @@ class LayerTreeHostContextTestDontUseLostResources
ResourceProvider::ResourceId resource =
child_resource_provider_->CreateResource(
- gfx::Size(4, 4),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
+ gfx::Size(4, 4), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
resource);
@@ -1103,24 +1081,16 @@ class LayerTreeHostContextTestDontUseLostResources
color_video_frame_ = VideoFrame::CreateColorFrame(
gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
- hw_video_frame_ =
- VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
- mailbox, GL_TEXTURE_2D, sync_point)),
- media::VideoFrame::ReleaseMailboxCB(),
- gfx::Size(4, 4),
- gfx::Rect(0, 0, 4, 4),
- gfx::Size(4, 4),
- base::TimeDelta(),
- VideoFrame::ReadPixelsCB());
- scaled_hw_video_frame_ =
- VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
- mailbox, GL_TEXTURE_2D, sync_point)),
- media::VideoFrame::ReleaseMailboxCB(),
- gfx::Size(4, 4),
- gfx::Rect(0, 0, 3, 2),
- gfx::Size(4, 4),
- base::TimeDelta(),
- VideoFrame::ReadPixelsCB());
+ hw_video_frame_ = VideoFrame::WrapNativeTexture(
+ gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
+ media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
+ gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4), base::TimeDelta(),
+ false /* allow_overlay */, true /* has_alpha */);
+ scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
+ gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, sync_point),
+ media::VideoFrame::ReleaseMailboxCB(), gfx::Size(4, 4),
+ gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4), base::TimeDelta(),
+ false /* allow_overlay */, true /* has_alpha */);
color_frame_provider_.set_frame(color_video_frame_);
hw_frame_provider_.set_frame(hw_video_frame_);
@@ -1176,15 +1146,14 @@ class LayerTreeHostContextTestDontUseLostResources
return draw_result;
}
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
// This will get called twice:
// First when we create the initial output surface...
if (layer_tree_host()->source_frame_number() > 0) {
// ... and then again after we forced the context to be lost.
lost_context_ = true;
}
- return LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
+ return LayerTreeHostContextTest::CreateFakeOutputSurface();
}
void DidCommitAndDrawFrame() override {
@@ -1313,7 +1282,7 @@ class UIResourceLostTest : public LayerTreeHostContextTest {
public:
UIResourceLostTest() : time_step_(0) {}
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->texture_id_allocation_chunk_size = 1;
+ settings->renderer_settings.texture_id_allocation_chunk_size = 1;
}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
void AfterTest() override {}
@@ -1364,7 +1333,7 @@ class UIResourceLostTestSimple : public UIResourceLostTest {
virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
- if (!layer_tree_host()->settings().impl_side_painting) {
+ if (!impl->settings().impl_side_painting) {
StepCompleteOnImplThread(impl);
PostStepCompleteToMainThread();
++time_step_;
@@ -1372,7 +1341,7 @@ class UIResourceLostTestSimple : public UIResourceLostTest {
}
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- if (layer_tree_host()->settings().impl_side_painting) {
+ if (impl->settings().impl_side_painting) {
StepCompleteOnImplThread(impl);
PostStepCompleteToMainThread();
++time_step_;
@@ -1803,12 +1772,7 @@ class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
deferred_ = true;
// Defer commits before the BeginFrame arrives, causing it to be delayed.
- MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
- DeferCommitsOnMainThread,
- base::Unretained(this),
- true));
+ PostSetDeferCommitsToMainThread(true);
// Meanwhile, lose the context while we are in defer commits.
ImplThreadTaskRunner()->PostTask(
FROM_HERE,
@@ -1821,16 +1785,7 @@ class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
LoseContext();
// After losing the context, stop deferring commits.
- MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
- DeferCommitsOnMainThread,
- base::Unretained(this),
- false));
- }
-
- void DeferCommitsOnMainThread(bool defer_commits) {
- layer_tree_host()->SetDeferCommits(defer_commits);
+ PostSetDeferCommitsToMainThread(false);
}
void WillBeginMainFrame() override {
diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 1b68ccae1d6..5766a192106 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "cc/layers/layer_iterator.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/test/fake_content_layer.h"
@@ -103,8 +104,7 @@ class LayerTreeHostCopyRequestTestMultipleRequests
void AfterTest() override { EXPECT_EQ(4u, callbacks_.size()); }
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
if (use_gl_renderer_)
return FakeOutputSurface::Create3d();
return FakeOutputSurface::CreateSoftware(
@@ -119,8 +119,9 @@ class LayerTreeHostCopyRequestTestMultipleRequests
};
// Readback can't be done with a delegating renderer.
+// Disabled due to flake: http://crbug.com/448521
TEST_F(LayerTreeHostCopyRequestTestMultipleRequests,
- GLRenderer_RunSingleThread) {
+ DISABLED_GLRenderer_RunSingleThread) {
use_gl_renderer_ = true;
RunTest(false, false, false);
}
@@ -534,8 +535,7 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
class LayerTreeHostCopyRequestTestLostOutputSurface
: public LayerTreeHostCopyRequestTest {
protected:
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
if (!first_context_provider_.get()) {
first_context_provider_ = TestContextProvider::Create();
return FakeOutputSurface::Create3d(first_context_provider_);
@@ -663,8 +663,7 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
class LayerTreeHostCopyRequestTestCountTextures
: public LayerTreeHostCopyRequestTest {
protected:
- scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
- bool fallback) override {
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
context_provider_ = TestContextProvider::Create();
return FakeOutputSurface::Create3d(context_provider_);
}
@@ -968,5 +967,121 @@ class LayerTreeHostCopyRequestTestShutdownBeforeCopy
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
LayerTreeHostCopyRequestTestShutdownBeforeCopy);
+class LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest
+ : public LayerTreeHostCopyRequestTest {
+ protected:
+ void SetupTree() override {
+ scoped_refptr<FakeContentLayer> root = FakeContentLayer::Create(&client_);
+ root->SetBounds(gfx::Size(20, 20));
+
+ child_ = FakeContentLayer::Create(&client_);
+ child_->SetBounds(gfx::Size(10, 10));
+ root->AddChild(child_);
+ child_->SetHideLayerAndSubtree(true);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostCopyRequestTest::SetupTree();
+ }
+
+ void BeginTest() override {
+ num_draws_ = 0;
+ copy_happened_ = false;
+ draw_happened_ = false;
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void DidCommitAndDrawFrame() override {
+ // Send a copy request after the first commit.
+ if (layer_tree_host()->source_frame_number() == 1) {
+ child_->RequestCopyOfOutput(
+ CopyOutputRequest::CreateBitmapRequest(base::Bind(
+ &LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest::
+ CopyOutputCallback,
+ base::Unretained(this))));
+ }
+ }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ LayerImpl* root = host_impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+
+ bool saw_root = false;
+ bool saw_child = false;
+ for (LayerIterator<LayerImpl> it = LayerIterator<LayerImpl>::Begin(
+ frame_data->render_surface_layer_list);
+ it != LayerIterator<LayerImpl>::End(
+ frame_data->render_surface_layer_list);
+ ++it) {
+ if (it.represents_itself()) {
+ if (*it == root)
+ saw_root = true;
+ else if (*it == child)
+ saw_child = true;
+ else
+ NOTREACHED();
+ }
+ }
+
+ ++num_draws_;
+ // The first draw has no copy request. The 2nd draw has a copy request, the
+ // 3rd should not again.
+ switch (num_draws_) {
+ case 1:
+ // Only the root layer draws, the child is hidden.
+ EXPECT_TRUE(saw_root);
+ EXPECT_FALSE(saw_child);
+ break;
+ case 2:
+ // Copy happening here, the child will draw.
+ EXPECT_TRUE(saw_root);
+ EXPECT_TRUE(saw_child);
+ // Make another draw happen after doing the copy request.
+ host_impl->SetNeedsRedrawRect(gfx::Rect(1, 1));
+ break;
+ case 3:
+ // If LayerTreeHostImpl does the wrong thing, it will try to draw the
+ // layer which had a copy request. But only the root should draw.
+ EXPECT_TRUE(saw_root);
+ EXPECT_FALSE(saw_child);
+
+ // End the test! Don't race with copy request callbacks, so post the end
+ // to the main thread.
+ draw_happened_ = true;
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest::
+ TryEndTest,
+ base::Unretained(this)));
+ break;
+ }
+ return draw_result;
+ }
+
+ void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
+ EXPECT_FALSE(TestEnded());
+ copy_happened_ = true;
+ TryEndTest();
+ }
+
+ void TryEndTest() {
+ if (draw_happened_ && copy_happened_)
+ EndTest();
+ }
+
+ void AfterTest() override {}
+
+ scoped_refptr<FakeContentLayer> child_;
+ FakeContentLayerClient client_;
+ int num_draws_;
+ bool copy_happened_;
+ bool draw_happened_;
+};
+
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+ LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_damage.cc b/chromium/cc/trees/layer_tree_host_unittest_damage.cc
index d541751e146..daff40beb2d 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_damage.cc
@@ -434,7 +434,8 @@ class LayerTreeHostDamageTestScrollbarDoesDamage
// Test that modifying the position of the content layer (not
// scrolling) won't damage the scrollbar.
scroll_layer->SetPosition(gfx::Point(1, 1));
- scroll_layer->SetScrollOffset(scroll_layer->scroll_offset());
+ scroll_layer->PushScrollOffsetFromMainThread(
+ scroll_layer->BaseScrollOffset());
host_impl->SetNeedsRedraw();
break;
case 2:
@@ -529,98 +530,5 @@ class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage
MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarCommitDoesNoDamage);
-class LayerTreeHostDamageTestVisibleTilesStillTriggerDraws
- : public LayerTreeHostDamageTest {
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->impl_side_painting = true;
- }
-
- void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
- void SetupTree() override {
- scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_);
- root->SetBounds(gfx::Size(500, 500));
- layer_tree_host()->SetRootLayer(root);
- LayerTreeHostDamageTest::SetupTree();
-
- swap_count_ = 0;
- prepare_to_draw_count_ = 0;
- update_visible_tile_count_ = 0;
- }
-
- DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- DrawResult draw_result) override {
- EXPECT_EQ(DRAW_SUCCESS, draw_result);
- prepare_to_draw_count_++;
- switch (prepare_to_draw_count_) {
- case 1:
- // Detect that we have an incomplete tile, during the first frame.
- // The first frame should have damage.
- frame_data->contains_incomplete_tile = true;
- DCHECK(!frame_data->has_no_damage);
- break;
- case 2:
- // Make a no-damage frame. We early out and can't detect
- // incomplete tiles, even if they still exist.
- frame_data->contains_incomplete_tile = false;
- frame_data->has_no_damage = true;
- break;
- case 3:
- // Trigger the last swap for the completed tile.
- frame_data->contains_incomplete_tile = false;
- frame_data->has_no_damage = false;
- EndTest();
- break;
- default:
- NOTREACHED();
- break;
- }
-
- return draw_result;
- }
-
- void UpdateVisibleTilesOnThread(LayerTreeHostImpl* host_impl) override {
- // Simulate creating some visible tiles (that trigger prepare-to-draws).
- // The first we make into a no-damage-frame during prepare-to-draw (see
- // above). This is to ensure we still get UpdateVisibleTiles calls after
- // a no-damage or aborted frame.
- update_visible_tile_count_++;
- switch (update_visible_tile_count_) {
- case 3:
- case 6:
- host_impl->DidInitializeVisibleTileForTesting();
- break;
- case 7:
- NOTREACHED();
- break;
- }
- }
-
- void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
- bool didSwap) override {
- if (!didSwap)
- return;
- ++swap_count_;
- }
-
- void AfterTest() override {
- // We should keep getting update-visible-tiles calls
- // until we report there are no more incomplete-tiles.
- EXPECT_EQ(update_visible_tile_count_, 6);
- // First frame, plus two triggered by DidInitializeVisibleTile()
- EXPECT_EQ(prepare_to_draw_count_, 3);
- // First swap, plus final swap (contained damage).
- EXPECT_EQ(swap_count_, 2);
- }
-
- FakeContentLayerClient client_;
- int swap_count_;
- int prepare_to_draw_count_;
- int update_visible_tile_count_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostDamageTestVisibleTilesStillTriggerDraws);
-
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_delegated.cc b/chromium/cc/trees/layer_tree_host_unittest_delegated.cc
index 3aabeffd142..2864eb82ad6 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_delegated.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_delegated.cc
@@ -113,6 +113,7 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
SkColor background_color = 0;
float vertex_opacity[4] = {1.f, 1.f, 1.f, 1.f};
bool flipped = false;
+ bool nearest_neighbor = false;
TextureDrawQuad* invalid_draw_quad =
root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -126,7 +127,8 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
uv_bottom_right,
background_color,
vertex_opacity,
- flipped);
+ flipped,
+ nearest_neighbor);
frame->render_pass_list.push_back(root_pass.Pass());
return frame.Pass();
@@ -162,6 +164,7 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
gfx::PointF(1.f, 1.f),
SK_ColorTRANSPARENT,
vertex_opacity,
+ false,
false);
}
@@ -240,6 +243,24 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
output_surface()->ReturnResource(resources_to_return[i], &ack);
host_impl->ReclaimResources(&ack);
}
+
+ void ReturnAllResourcesFromParent(LayerTreeHostImpl* host_impl) {
+ DelegatedFrameData* delegated_frame_data =
+ output_surface()->last_sent_frame().delegated_frame_data.get();
+ if (!delegated_frame_data)
+ return;
+
+ const TransferableResourceArray& resources_held_by_parent =
+ output_surface()->resources_held_by_parent();
+
+ if (resources_held_by_parent.empty())
+ return;
+
+ CompositorFrameAck ack;
+ for (size_t i = 0; i < resources_held_by_parent.size(); ++i)
+ output_surface()->ReturnResource(resources_held_by_parent[i].id, &ack);
+ host_impl->ReclaimResources(&ack);
+ }
};
class LayerTreeHostDelegatedTestCaseSingleDelegatedLayer
@@ -383,6 +404,37 @@ class LayerTreeHostDelegatedTestCreateChildId
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestCreateChildId);
+class LayerTreeHostDelegatedTestDontUseLostChildIdAfterCommit
+ : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
+ protected:
+ void BeginTest() override {
+ SetFrameData(CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)));
+ LayerTreeHostDelegatedTestCaseSingleDelegatedLayer::BeginTest();
+ }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ // Act like the context was lost while the layer is in the pending tree.
+ LayerImpl* root_impl = host_impl->sync_tree()->root_layer();
+ FakeDelegatedRendererLayerImpl* delegated_impl =
+ static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]);
+ delegated_impl->ReleaseResources();
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ LayerImpl* root_impl = host_impl->active_tree()->root_layer();
+ FakeDelegatedRendererLayerImpl* delegated_impl =
+ static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]);
+
+ // Should not try to activate a frame without a child id. If we did try to
+ // activate we would crash.
+ EXPECT_FALSE(delegated_impl->ChildId());
+ EndTest();
+ }
+};
+
+MULTI_THREAD_IMPL_TEST_F(
+ LayerTreeHostDelegatedTestDontUseLostChildIdAfterCommit);
+
// Test that we can gracefully handle invalid frames after the context was lost.
// For example, we might be trying to use the previous frame in that case and
// have to make sure we don't crash because our resource accounting goes wrong.
@@ -467,10 +519,6 @@ SINGLE_AND_MULTI_THREAD_TEST_F(
class LayerTreeHostDelegatedTestLayerUsesFrameDamage
: public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
public:
- LayerTreeHostDelegatedTestLayerUsesFrameDamage()
- : LayerTreeHostDelegatedTestCaseSingleDelegatedLayer(),
- first_draw_for_source_frame_(true) {}
-
void DidCommit() override {
int next_source_frame_number = layer_tree_host()->source_frame_number();
switch (next_source_frame_number) {
@@ -578,7 +626,6 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage
CreateFrameData(gfx::Rect(0, 0, 10, 10), gfx::Rect(3, 3, 1, 1)));
break;
}
- first_draw_for_source_frame_ = true;
}
DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
@@ -586,9 +633,6 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage
DrawResult draw_result) override {
EXPECT_EQ(DRAW_SUCCESS, draw_result);
- if (!first_draw_for_source_frame_)
- return draw_result;
-
gfx::Rect damage_rect;
if (!frame->has_no_damage) {
damage_rect = frame->render_passes.back()->damage_rect;
@@ -666,7 +710,6 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage
protected:
scoped_refptr<DelegatedRendererLayer> delegated_copy_;
- bool first_draw_for_source_frame_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestLayerUsesFrameDamage);
@@ -1231,7 +1274,7 @@ class LayerTreeHostDelegatedTestBadFrame
switch (host_impl->active_tree()->source_frame_number()) {
case 1: {
- // We have the first good frame with just 990 and 555 in it.
+ // We have the first good frame with just 999 and 555 in it.
// layer.
EXPECT_EQ(2u, map.size());
EXPECT_EQ(1u, map.count(999));
@@ -1299,7 +1342,7 @@ class LayerTreeHostDelegatedTestUnnamedResource
public:
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
- void DidCommit() override {
+ void DidCommitAndDrawFrame() override {
scoped_ptr<DelegatedFrameData> frame;
ReturnedResourceArray resources;
@@ -2171,5 +2214,81 @@ class LayerTreeHostDelegatedTestRemoveAndChangeResources
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostDelegatedTestRemoveAndChangeResources);
+class LayerTreeHostDelegatedTestActiveFrameIsValid
+ : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
+ public:
+ LayerTreeHostDelegatedTestActiveFrameIsValid()
+ : drew_with_pending_tree_(false) {}
+
+ void DidCommitAndDrawFrame() override {
+ scoped_ptr<DelegatedFrameData> frame;
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ // This frame goes to the active tree.
+ frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
+ AddTextureQuad(frame.get(), 999);
+ AddTransferableResource(frame.get(), 999);
+ SetFrameData(frame.Pass());
+ break;
+ case 2:
+ // This frame stops in the pending tree while we redraw the active tree.
+ frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
+ AddTextureQuad(frame.get(), 555);
+ AddTransferableResource(frame.get(), 555);
+ SetFrameData(frame.Pass());
+ break;
+ }
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->active_tree()->source_frame_number() < 1)
+ return;
+
+ LayerImpl* root_impl = host_impl->active_tree()->root_layer();
+ FakeDelegatedRendererLayerImpl* delegated_impl =
+ static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]);
+ const ResourceProvider::ResourceIdMap& map =
+ host_impl->resource_provider()->GetChildToParentMap(
+ delegated_impl->ChildId());
+
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 1:
+ if (!host_impl->pending_tree()) {
+ // Frame 2 is blocked from activating until another draw happens with
+ // Frame 1. This ensures we draw a different active frame from
+ // what's in the pending tree.
+ host_impl->BlockNotifyReadyToActivateForTesting(true);
+ host_impl->SetNeedsRedrawRect(gfx::Rect(1, 1));
+ break;
+ }
+
+ // The resources in the active tree should be valid.
+ EXPECT_EQ(1u, map.count(999));
+
+ host_impl->BlockNotifyReadyToActivateForTesting(false);
+ drew_with_pending_tree_ = true;
+ break;
+ case 2:
+ EXPECT_TRUE(drew_with_pending_tree_);
+
+ // The resources in the active tree should be valid.
+ EXPECT_EQ(1u, map.count(555));
+ EndTest();
+ break;
+ }
+ }
+
+ void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
+ // Return everything so that we can reliably delete resources that lose
+ // their references. This would happen if the tab was backgrounded or
+ // the parent decided to drop all resources for some reason.
+ ReturnAllResourcesFromParent(host_impl);
+ }
+
+ bool drew_with_pending_tree_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostDelegatedTestActiveFrameIsValid);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/chromium/cc/trees/layer_tree_host_unittest_no_message_loop.cc
index aa5a5080928..ef948f70240 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_no_message_loop.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
#include "base/threading/simple_thread.h"
#include "cc/layers/delegated_frame_provider.h"
#include "cc/layers/delegated_frame_resource_collection.h"
@@ -13,6 +13,7 @@
#include "cc/output/output_surface.h"
#include "cc/output/output_surface_client.h"
#include "cc/resources/resource_provider.h"
+#include "cc/scheduler/begin_frame_source.h"
#include "cc/test/fake_delegated_renderer_layer.h"
#include "cc/test/test_context_provider.h"
#include "cc/trees/layer_tree_host.h"
@@ -50,31 +51,35 @@ class LayerTreeHostNoMessageLoopTest
did_commit_and_draw_frame_(false),
size_(100, 100),
no_loop_thread_(this, "LayerTreeHostNoMessageLoopTest") {}
- virtual ~LayerTreeHostNoMessageLoopTest() {}
+ ~LayerTreeHostNoMessageLoopTest() override {}
// LayerTreeHostClient overrides.
- void WillBeginMainFrame(int frame_id) override {}
+ void WillBeginMainFrame() override {}
void BeginMainFrame(const BeginFrameArgs& args) override {}
+ void BeginMainFrameNotExpectedSoon() override {}
void DidBeginMainFrame() override {}
void Layout() override {}
- void ApplyViewportDeltas(const gfx::Vector2d& inner_delta,
- const gfx::Vector2d& outer_delta,
+ void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta,
+ const gfx::Vector2dF& outer_delta,
+ const gfx::Vector2dF& elastic_overscroll_delta,
float page_scale,
float top_controls_delta) override {}
void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta,
float page_scale,
float top_controls_delta) override {}
- void RequestNewOutputSurface(bool fallback) override {
+ void RequestNewOutputSurface() override {
layer_tree_host_->SetOutputSurface(
make_scoped_ptr<OutputSurface>(new NoMessageLoopOutputSurface));
}
void DidInitializeOutputSurface() override {
did_initialize_output_surface_ = true;
}
+ void DidFailToInitializeOutputSurface() override {}
void WillCommit() override {}
void DidCommit() override { did_commit_ = true; }
void DidCommitAndDrawFrame() override { did_commit_and_draw_frame_ = true; }
void DidCompleteSwapBuffers() override {}
+ void DidCompletePageScaleAnimation() override {}
// LayerTreeHostSingleThreadClient overrides.
void DidPostSwapBuffers() override {}
@@ -87,9 +92,9 @@ class LayerTreeHostNoMessageLoopTest
// base::DelegateSimpleThread::Delegate override.
void Run() override {
- ASSERT_FALSE(base::MessageLoopProxy::current().get());
+ ASSERT_FALSE(base::ThreadTaskRunnerHandle::IsSet());
RunTestWithoutMessageLoop();
- EXPECT_FALSE(base::MessageLoopProxy::current().get());
+ EXPECT_FALSE(base::ThreadTaskRunnerHandle::IsSet());
}
protected:
@@ -98,8 +103,13 @@ class LayerTreeHostNoMessageLoopTest
void SetupLayerTreeHost() {
LayerTreeSettings settings;
settings.single_thread_proxy_scheduler = false;
- layer_tree_host_ = LayerTreeHost::CreateSingleThreaded(
- this, this, NULL, NULL, settings, NULL);
+ settings.verify_property_trees = true;
+ settings.raster_enabled = false;
+
+ LayerTreeHost::InitParams params;
+ params.client = this;
+ params.settings = &settings;
+ layer_tree_host_ = LayerTreeHost::CreateSingleThreaded(this, &params);
layer_tree_host_->SetViewportSize(size_);
layer_tree_host_->SetRootLayer(root_layer_);
}
diff --git a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
index fe87e44d667..9974ae4066b 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
@@ -5,623 +5,266 @@
#include "cc/trees/layer_tree_host.h"
#include "cc/layers/layer.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/copy_output_result.h"
+#include "cc/layers/picture_layer.h"
+#include "cc/test/fake_content_layer_client.h"
#include "cc/test/layer_tree_test.h"
-#include "cc/test/test_occlusion_tracker.h"
+#include "cc/trees/layer_tree_impl.h"
namespace cc {
namespace {
-class TestLayer : public Layer {
- public:
- static scoped_refptr<TestLayer> Create() {
- return make_scoped_refptr(new TestLayer());
- }
-
- bool Update(ResourceUpdateQueue* update_queue,
- const OcclusionTracker<Layer>* occlusion) override {
- if (!occlusion)
- return false;
-
- const TestOcclusionTracker<Layer>* test_occlusion =
- static_cast<const TestOcclusionTracker<Layer>*>(occlusion);
- occlusion_ = UnionSimpleEnclosedRegions(
- test_occlusion->occlusion_from_inside_target(),
- test_occlusion->occlusion_from_outside_target());
- return false;
- }
-
- const SimpleEnclosedRegion& occlusion() const { return occlusion_; }
- const SimpleEnclosedRegion& expected_occlusion() const {
- return expected_occlusion_;
- }
- void set_expected_occlusion(const gfx::Rect& occlusion) {
- expected_occlusion_ = SimpleEnclosedRegion(occlusion);
- }
-
- private:
- TestLayer() : Layer() {
- SetIsDrawable(true);
- }
- ~TestLayer() override {}
-
- SimpleEnclosedRegion occlusion_;
- SimpleEnclosedRegion expected_occlusion_;
-};
+#define EXPECT_OCCLUSION_EQ(expected, actual) \
+ EXPECT_TRUE(expected.IsEqual(actual)) \
+ << " Expected: " << expected.ToString() << std::endl \
+ << " Actual: " << actual.ToString();
class LayerTreeHostOcclusionTest : public LayerTreeTest {
- public:
- LayerTreeHostOcclusionTest()
- : root_(TestLayer::Create()),
- child_(TestLayer::Create()),
- child2_(TestLayer::Create()),
- grand_child_(TestLayer::Create()),
- mask_(TestLayer::Create()) {
- }
-
- void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
- void DidCommit() override {
- TestLayer* root = static_cast<TestLayer*>(layer_tree_host()->root_layer());
- VerifyOcclusion(root);
-
- EndTest();
- }
-
- void AfterTest() override {}
-
- void VerifyOcclusion(TestLayer* layer) const {
- EXPECT_EQ(layer->expected_occlusion().ToString(),
- layer->occlusion().ToString());
-
- for (size_t i = 0; i < layer->children().size(); ++i) {
- TestLayer* child = static_cast<TestLayer*>(layer->children()[i].get());
- VerifyOcclusion(child);
- }
- }
-
- void SetLayerPropertiesForTesting(TestLayer* layer,
- TestLayer* parent,
- const gfx::Transform& transform,
- const gfx::PointF& position,
- const gfx::Size& bounds,
- bool opaque) const {
- layer->RemoveAllChildren();
- if (parent)
- parent->AddChild(layer);
- layer->SetTransform(transform);
- layer->SetPosition(position);
- layer->SetBounds(bounds);
- layer->SetContentsOpaque(opaque);
- }
-
protected:
void InitializeSettings(LayerTreeSettings* settings) override {
settings->minimum_occlusion_tracking_size = gfx::Size();
}
-
- scoped_refptr<TestLayer> root_;
- scoped_refptr<TestLayer> child_;
- scoped_refptr<TestLayer> child2_;
- scoped_refptr<TestLayer> grand_child_;
- scoped_refptr<TestLayer> mask_;
-
- gfx::Transform identity_matrix_;
};
-
-class LayerTreeHostOcclusionTestOcclusionSurfaceClipping
+// Verify occlusion is set on the layer draw properties.
+class LayerTreeHostOcclusionTestDrawPropertiesOnLayer
: public LayerTreeHostOcclusionTest {
public:
void SetupTree() override {
- // The child layer is a surface and the grand_child is opaque, but clipped
- // to the child and root
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), false);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
- root_->set_expected_occlusion(gfx::Rect(10, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+ root->SetIsDrawable(true);
+
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetBounds(gfx::Size(50, 60));
+ child->SetPosition(gfx::PointF(10.f, 5.5f));
+ child->SetContentsOpaque(true);
+ child->SetIsDrawable(true);
+ root->AddChild(child);
+
+ layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionSurfaceClipping);
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-class LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer is opaque, then it adds to the occlusion seen by the
- // root_.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
- root_->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+
+ // Verify the draw properties are valid.
+ EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(child->draw_transform(), SimpleEnclosedRegion(),
+ SimpleEnclosedRegion()),
+ child->draw_properties().occlusion_in_content_space);
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(root->draw_transform(), SimpleEnclosedRegion(),
+ SimpleEnclosedRegion(gfx::Rect(10, 6, 50, 59))),
+ root->draw_properties().occlusion_in_content_space);
+ EndTest();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque);
-
-class LayerTreeHostOcclusionTestOcclusionTwoChildren
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // Add a second child to the root layer and the regions should merge
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), false);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
-
- grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
- child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
- root_->set_expected_occlusion(gfx::Rect(10, 10, 20, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
+ void AfterTest() override {}
};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionTwoChildren);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestDrawPropertiesOnLayer);
-class LayerTreeHostOcclusionTestOcclusionMask
+// Verify occlusion is set on the render surfaces.
+class LayerTreeHostOcclusionTestDrawPropertiesOnSurface
: public LayerTreeHostOcclusionTest {
public:
void SetupTree() override {
- // If the child layer has a mask on it, then it shouldn't contribute to
- // occlusion on stuff below it.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 20.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(500, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
- child_->SetMaskLayer(mask_.get());
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 180, 180));
- root_->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
-
- layer_tree_host()->SetRootLayer(root_);
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+ root->SetIsDrawable(true);
+
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetBounds(gfx::Size(1, 1));
+ child->SetPosition(gfx::PointF(10.f, 5.5f));
+ child->SetIsDrawable(true);
+ child->SetForceRenderSurface(true);
+ root->AddChild(child);
+
+ scoped_refptr<Layer> child2 = Layer::Create();
+ child2->SetBounds(gfx::Size(10, 12));
+ child2->SetPosition(gfx::PointF(13.f, 8.5f));
+ child2->SetContentsOpaque(true);
+ child2->SetIsDrawable(true);
+ root->AddChild(child2);
+
+ layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionMask);
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-class LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer with a mask is below child2, then child2 should
- // contribute to occlusion on everything, and child shouldn't contribute
- // to the root_.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
- child_->SetMaskLayer(mask_.get());
-
- grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
- child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
-};
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+ RenderSurfaceImpl* surface = child->render_surface();
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion);
+ // Verify the draw properties are valid.
+ EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_EQ(child, child->render_target());
-class LayerTreeHostOcclusionTestOcclusionOpacity
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer has a non-opaque opacity, then it shouldn't
- // contribute to occlusion on stuff below it
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
- child_->SetOpacity(0.5f);
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(surface->draw_transform(), SimpleEnclosedRegion(),
+ SimpleEnclosedRegion(gfx::Rect(13, 9, 10, 11))),
+ surface->occlusion_in_content_space());
+ EndTest();
}
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionOpacity);
-class LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer with non-opaque opacity is below child2, then
- // child2 should contribute to occlusion on everything, and child shouldn't
- // contribute to the root_.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetForceRenderSurface(true);
- child_->SetOpacity(0.5f);
-
- grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
- child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
+ void AfterTest() override {}
};
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion);
+ LayerTreeHostOcclusionTestDrawPropertiesOnSurface);
-class LayerTreeHostOcclusionTestOcclusionBlending
+// Verify occlusion is set on mask layers.
+class LayerTreeHostOcclusionTestDrawPropertiesOnMask
: public LayerTreeHostOcclusionTest {
public:
void SetupTree() override {
- // If the child layer has a blend mode, then it shouldn't
- // contribute to occlusion on stuff below it
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetBlendMode(SkXfermode::kMultiply_Mode);
- child_->SetForceRenderSurface(true);
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+ root->SetIsDrawable(true);
+
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetBounds(gfx::Size(30, 40));
+ child->SetPosition(gfx::PointF(10.f, 5.5f));
+ child->SetIsDrawable(true);
+ root->AddChild(child);
+
+ scoped_refptr<Layer> make_surface_bigger = Layer::Create();
+ make_surface_bigger->SetBounds(gfx::Size(100, 100));
+ make_surface_bigger->SetPosition(gfx::PointF(-10.f, -15.f));
+ make_surface_bigger->SetIsDrawable(true);
+ child->AddChild(make_surface_bigger);
+
+ scoped_refptr<Layer> mask = PictureLayer::Create(&client_);
+ mask->SetBounds(gfx::Size(30, 40));
+ mask->SetIsDrawable(true);
+ child->SetMaskLayer(mask.get());
+
+ scoped_refptr<Layer> child2 = Layer::Create();
+ child2->SetBounds(gfx::Size(10, 12));
+ child2->SetPosition(gfx::PointF(13.f, 8.5f));
+ child2->SetContentsOpaque(true);
+ child2->SetIsDrawable(true);
+ root->AddChild(child2);
+
+ layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionBlending);
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-class LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer with a blend mode is below child2, then
- // child2 should contribute to occlusion on everything, and child shouldn't
- // contribute to the root_.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetBlendMode(SkXfermode::kMultiply_Mode);
-
- grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
- child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
- root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
-};
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+ RenderSurfaceImpl* surface = child->render_surface();
+ LayerImpl* mask = child->mask_layer();
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion);
+ // Verify the draw properties are valid.
+ EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_EQ(child, child->render_target());
-class LayerTreeHostOcclusionTestOcclusionOpacityFilter
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- FilterOperations filters;
- filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
-
- // If the child layer has a filter that changes alpha values, and is below
- // child2, then child2 should contribute to occlusion on everything,
- // and child shouldn't contribute to the root
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(child_.get(),
- root_.get(),
- identity_matrix_,
- gfx::PointF(0.f, 0.f),
- gfx::Size(500, 500),
- true);
- SetLayerPropertiesForTesting(grand_child_.get(),
- child_.get(),
- identity_matrix_,
- gfx::PointF(0.f, 0.f),
- gfx::Size(500, 500),
- true);
- SetLayerPropertiesForTesting(child2_.get(),
- root_.get(),
- identity_matrix_,
- gfx::PointF(10.f, 10.f),
- gfx::Size(30, 30),
- true);
-
- child_->SetMasksToBounds(true);
- child_->SetFilters(filters);
-
- // child2_ occludes grand_child_, showing it does occlude inside child_'s
- // subtree.
- grand_child_->set_expected_occlusion(gfx::Rect(10, 10, 30, 30));
- // grand_child_ occludes child_, showing there is more occlusion in
- // child_'s subtree.
- child_->set_expected_occlusion(gfx::Rect(0, 0, 200, 200));
- // child2_'s occlusion reaches the root, but child_'s subtree does not.
- root_->set_expected_occlusion(gfx::Rect(10, 10, 30, 30));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
+ gfx::Transform transform = surface->draw_transform();
+ transform.PreconcatTransform(child->draw_transform());
+
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(transform, SimpleEnclosedRegion(),
+ SimpleEnclosedRegion(gfx::Rect(13, 9, 10, 11))),
+ mask->draw_properties().occlusion_in_content_space);
+ EndTest();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionOpacityFilter);
+ void AfterTest() override {}
-class LayerTreeHostOcclusionTestOcclusionBlurFilter
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- gfx::Transform child_transform;
- child_transform.Translate(250.0, 250.0);
- child_transform.Rotate(90.0);
- child_transform.Translate(-250.0, -250.0);
-
- FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(10.f));
-
- // If the child layer has a filter that moves pixels/changes alpha, and is
- // below child2, then child should not inherit occlusion from outside its
- // subtree, and should not contribute to the root
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), child_transform,
- gfx::PointF(30.f, 30.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(10.f, 70.f), gfx::Size(500, 500), true);
-
- child_->SetMasksToBounds(true);
- child_->SetFilters(filters);
-
- child_->set_expected_occlusion(gfx::Rect(10, 330, 160, 170));
- root_->set_expected_occlusion(gfx::Rect(10, 70, 190, 130));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
- }
+ FakeContentLayerClient client_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostOcclusionTestOcclusionBlurFilter);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestDrawPropertiesOnMask);
-class LayerTreeHostOcclusionTestOcclusionCopyRequest
+// Verify occlusion is set to empty inside the subtree of a replica. This is
+// done because the tile system does not know about replicas, and so would not
+// know that something is unoccluded on the replica even though it's occluded on
+// the original.
+class LayerTreeHostOcclusionTestDrawPropertiesInsideReplica
: public LayerTreeHostOcclusionTest {
public:
- static void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {}
-
void SetupTree() override {
- // If the child layer has copy request, and is below child2,
- // then child should not inherit occlusion from outside its subtree.
- // The child layer will still receive occlusion from inside, and
- // the root layer will recive occlusion from child.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(), gfx::Size(100, 100), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(), gfx::Size(75, 75), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(), gfx::Size(75, 50), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(0.f, 25.f), gfx::Size(75, 75), true);
-
- child_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
- base::Bind(&CopyOutputCallback)));
- EXPECT_TRUE(child_->HasCopyRequest());
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 75, 50));
- root_->set_expected_occlusion(gfx::Rect(0, 0, 75, 100));
-
- layer_tree_host()->SetRootLayer(root_);
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+ root->SetIsDrawable(true);
+
+ scoped_refptr<Layer> child = Layer::Create();
+ child->SetBounds(gfx::Size(1, 1));
+ child->SetPosition(gfx::PointF(10.f, 5.5f));
+ child->SetIsDrawable(true);
+ child->SetForceRenderSurface(true);
+ root->AddChild(child);
+
+ scoped_refptr<Layer> replica = Layer::Create();
+ gfx::Transform translate;
+ translate.Translate(20.f, 4.f);
+ replica->SetTransform(translate);
+ child->SetReplicaLayer(replica.get());
+
+ scoped_refptr<Layer> mask = PictureLayer::Create(&client_);
+ mask->SetBounds(gfx::Size(30, 40));
+ mask->SetIsDrawable(true);
+ child->SetMaskLayer(mask.get());
+
+ scoped_refptr<Layer> child2 = Layer::Create();
+ child2->SetBounds(gfx::Size(10, 12));
+ child2->SetPosition(gfx::PointF(13.f, 8.5f));
+ child2->SetContentsOpaque(true);
+ child2->SetIsDrawable(true);
+ root->AddChild(child2);
+
+ layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionCopyRequest);
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-class LayerTreeHostOcclusionTestOcclusionReplica
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // If the child layer has copy request, and is below child2,
- // then child should not inherit occlusion from outside its subtree.
- // The child layer will still receive occlusion from inside, and
- // the root layer will recive occlusion from child.
- SetLayerPropertiesForTesting(
- root_.get(), NULL, identity_matrix_,
- gfx::PointF(), gfx::Size(100, 100), true);
- SetLayerPropertiesForTesting(
- child_.get(), root_.get(), identity_matrix_,
- gfx::PointF(), gfx::Size(75, 75), true);
- SetLayerPropertiesForTesting(
- grand_child_.get(), child_.get(), identity_matrix_,
- gfx::PointF(), gfx::Size(75, 50), true);
- SetLayerPropertiesForTesting(
- child2_.get(), root_.get(), identity_matrix_,
- gfx::PointF(0.f, 25.f), gfx::Size(75, 75), true);
-
- scoped_refptr<Layer> replica_layer(Layer::Create());
- child_->SetReplicaLayer(replica_layer.get());
- EXPECT_TRUE(child_->has_replica());
-
- child_->set_expected_occlusion(gfx::Rect(0, 0, 75, 50));
- root_->set_expected_occlusion(gfx::Rect(0, 0, 75, 100));
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeTest::SetupTree();
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+ RenderSurfaceImpl* surface = child->render_surface();
+ LayerImpl* mask = child->mask_layer();
+
+ // Verify the draw properties are valid.
+ EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+ EXPECT_EQ(child, child->render_target());
+
+ // No occlusion from on child, which is part of the replica.
+ EXPECT_OCCLUSION_EQ(Occlusion(),
+ child->draw_properties().occlusion_in_content_space);
+ // Occlusion on the surface is okay.
+ EXPECT_OCCLUSION_EQ(
+ Occlusion(surface->draw_transform(), SimpleEnclosedRegion(),
+ SimpleEnclosedRegion(gfx::Rect(13, 9, 10, 11))),
+ surface->occlusion_in_content_space());
+ // No occlusion on the replica'd mask.
+ EXPECT_OCCLUSION_EQ(Occlusion(),
+ mask->draw_properties().occlusion_in_content_space);
+ EndTest();
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionReplica);
+ void AfterTest() override {}
-class LayerTreeHostOcclusionTestManySurfaces
- : public LayerTreeHostOcclusionTest {
- public:
- void SetupTree() override {
- // We create enough RenderSurfaces that it will trigger Vector reallocation
- // while computing occlusion.
- std::vector<scoped_refptr<TestLayer>> layers;
- int num_surfaces = 200;
- int root_width = 400;
- int root_height = 400;
-
- for (int i = 0; i < num_surfaces; ++i) {
- layers.push_back(TestLayer::Create());
- if (i == 0) {
- SetLayerPropertiesForTesting(
- layers.back().get(), NULL, identity_matrix_,
- gfx::PointF(0.f, 0.f),
- gfx::Size(root_width, root_height), true);
- } else {
- SetLayerPropertiesForTesting(
- layers.back().get(), layers[layers.size() - 2].get(),
- identity_matrix_,
- gfx::PointF(1.f, 1.f),
- gfx::Size(root_width-i, root_height-i), true);
- layers.back()->SetForceRenderSurface(true);
- }
- }
-
- for (int i = 1; i < num_surfaces; ++i) {
- scoped_refptr<TestLayer> child = TestLayer::Create();
- SetLayerPropertiesForTesting(
- child.get(), layers[i].get(), identity_matrix_,
- gfx::PointF(0.f, 0.f), gfx::Size(root_width, root_height), false);
- }
-
- for (int i = 0; i < num_surfaces-1; ++i) {
- gfx::Rect expected_occlusion(1, 1, root_width-i-1, root_height-i-1);
- layers[i]->set_expected_occlusion(expected_occlusion);
- }
-
- layer_tree_host()->SetRootLayer(layers[0]);
- LayerTreeTest::SetupTree();
- }
+ FakeContentLayerClient client_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestManySurfaces);
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostOcclusionTestDrawPropertiesInsideReplica);
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_picture.cc b/chromium/cc/trees/layer_tree_host_unittest_picture.cc
index 2d485b40f50..6f222f71e71 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_picture.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_picture.cc
@@ -16,20 +16,25 @@ namespace {
// These tests deal with picture layers.
class LayerTreeHostPictureTest : public LayerTreeTest {
protected:
- void InitializeSettings(LayerTreeSettings* settings) override {
- // PictureLayer can only be used with impl side painting enabled.
- settings->impl_side_painting = true;
+ void SetupTreeWithSinglePictureLayer(const gfx::Size& size) {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(size);
+
+ root_picture_layer_ = FakePictureLayer::Create(&client_);
+ root_picture_layer_->SetBounds(size);
+ root->AddChild(root_picture_layer_);
+
+ layer_tree_host()->SetRootLayer(root);
}
+
+ scoped_refptr<FakePictureLayer> root_picture_layer_;
+ FakeContentLayerClient client_;
};
class LayerTreeHostPictureTestTwinLayer
: public LayerTreeHostPictureTest {
void SetupTree() override {
- LayerTreeHostPictureTest::SetupTree();
-
- scoped_refptr<FakePictureLayer> picture =
- FakePictureLayer::Create(&client_);
- layer_tree_host()->root_layer()->AddChild(picture);
+ SetupTreeWithSinglePictureLayer(gfx::Size(1, 1));
}
void BeginTest() override {
@@ -39,16 +44,30 @@ class LayerTreeHostPictureTestTwinLayer
void DidCommit() override {
switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ // Activate while there are pending and active twins in place.
+ layer_tree_host()->SetNeedsCommit();
+ break;
case 2:
- // Drop the picture layer from the tree.
+ // Drop the picture layer from the tree so the activate will have an
+ // active layer without a pending twin.
layer_tree_host()->root_layer()->children()[0]->RemoveFromParent();
break;
- case 3:
- // Add a new picture layer.
+ case 3: {
+ // Add a new picture layer so the activate will have a pending layer
+ // without an active twin.
scoped_refptr<FakePictureLayer> picture =
FakePictureLayer::Create(&client_);
layer_tree_host()->root_layer()->AddChild(picture);
break;
+ }
+ case 4:
+ // Active while there are pending and active twins again.
+ layer_tree_host()->SetNeedsCommit();
+ break;
+ case 5:
+ EndTest();
+ break;
}
}
@@ -82,7 +101,7 @@ class LayerTreeHostPictureTestTwinLayer
// After the first activation, when we commit again, we'll have a pending
// and active layer. Then we recreate a picture layer in the 4th activate
// and the next commit will have a pending and active twin again.
- EXPECT_TRUE(activates_ == 1 || activates_ == 4);
+ EXPECT_TRUE(activates_ == 1 || activates_ == 4) << activates_;
EXPECT_EQ(pending_picture_impl,
active_picture_impl->GetPendingOrActiveTwinLayer());
@@ -109,19 +128,447 @@ class LayerTreeHostPictureTestTwinLayer
}
++activates_;
- if (activates_ <= 4)
- PostSetNeedsCommitToMainThread();
- else
+ }
+
+ void AfterTest() override { EXPECT_EQ(5, activates_); }
+
+ int activates_;
+};
+
+// There is no pending layers in single thread mode.
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestTwinLayer);
+
+class LayerTreeHostPictureTestResizeViewportWithGpuRaster
+ : public LayerTreeHostPictureTest {
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->gpu_rasterization_forced = true;
+ }
+
+ void SetupTree() override {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(768, 960));
+
+ client_.set_fill_with_nonsolid_color(true);
+ picture_ = FakePictureLayer::Create(&client_);
+ picture_->SetBounds(gfx::Size(768, 960));
+ root->AddChild(picture_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostPictureTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* child = impl->sync_tree()->root_layer()->children()[0];
+ FakePictureLayerImpl* picture_impl =
+ static_cast<FakePictureLayerImpl*>(child);
+ gfx::Size tile_size =
+ picture_impl->HighResTiling()->TileAt(0, 0)->content_rect().size();
+
+ switch (impl->sync_tree()->source_frame_number()) {
+ case 0:
+ tile_size_ = tile_size;
+ // GPU Raster picks a tile size based on the viewport size.
+ EXPECT_EQ(gfx::Size(768, 256), tile_size);
+ break;
+ case 1:
+ // When the viewport changed size, the new frame's tiles should change
+ // along with it.
+ EXPECT_NE(gfx::Size(768, 256), tile_size);
+ }
+ }
+
+ void DidCommit() override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ // Change the picture layer's size along with the viewport, so it will
+ // consider picking a new tile size.
+ picture_->SetBounds(gfx::Size(768, 1056));
+ layer_tree_host()->SetViewportSize(gfx::Size(768, 1056));
+ break;
+ case 2:
+ EndTest();
+ }
+ }
+
+ void AfterTest() override {}
+
+ gfx::Size tile_size_;
+ FakeContentLayerClient client_;
+ scoped_refptr<FakePictureLayer> picture_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
+ LayerTreeHostPictureTestResizeViewportWithGpuRaster);
+
+class LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree
+ : public LayerTreeHostPictureTest {
+ void SetupTree() override {
+ frame_ = 0;
+ did_post_commit_ = false;
+
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+
+ // The layer is big enough that the live tiles rect won't cover the full
+ // layer.
+ client_.set_fill_with_nonsolid_color(true);
+ picture_ = FakePictureLayer::Create(&client_);
+ picture_->SetBounds(gfx::Size(100, 100000));
+ root->AddChild(picture_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostPictureTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* child = impl->active_tree()->root_layer()->children()[0];
+ FakePictureLayerImpl* picture_impl =
+ static_cast<FakePictureLayerImpl*>(child);
+ FakePictureLayerImpl* recycled_impl = static_cast<FakePictureLayerImpl*>(
+ picture_impl->GetRecycledTwinLayer());
+
+ switch (++frame_) {
+ case 1: {
+ PictureLayerTiling* tiling = picture_impl->HighResTiling();
+ PictureLayerTiling* recycled_tiling = recycled_impl->HighResTiling();
+ int num_tiles_y = tiling->TilingDataForTesting().num_tiles_y();
+
+ // There should be tiles at the top of the picture layer but not at the
+ // bottom.
+ EXPECT_TRUE(tiling->TileAt(0, 0));
+ EXPECT_FALSE(tiling->TileAt(0, num_tiles_y));
+
+ // The recycled tiling has no tiles.
+ EXPECT_FALSE(recycled_tiling->TileAt(0, 0));
+ EXPECT_FALSE(recycled_tiling->TileAt(0, num_tiles_y));
+
+ // The live tiles rect matches on the recycled tree.
+ EXPECT_EQ(tiling->live_tiles_rect(),
+ recycled_tiling->live_tiles_rect());
+
+ // Make the bottom of the layer visible.
+ picture_impl->SetPosition(gfx::PointF(0.f, -100000.f + 100.f));
+ impl->SetNeedsRedraw();
+ break;
+ }
+ case 2: {
+ PictureLayerTiling* tiling = picture_impl->HighResTiling();
+ PictureLayerTiling* recycled_tiling = recycled_impl->HighResTiling();
+
+ // There not be tiles at the top of the layer now.
+ EXPECT_FALSE(tiling->TileAt(0, 0));
+
+ // The recycled twin tiling should not have unshared tiles at the top
+ // either.
+ EXPECT_FALSE(recycled_tiling->TileAt(0, 0));
+
+ // Make the top of the layer visible again.
+ picture_impl->SetPosition(gfx::PointF());
+ impl->SetNeedsRedraw();
+ break;
+ }
+ case 3: {
+ PictureLayerTiling* tiling = picture_impl->HighResTiling();
+ PictureLayerTiling* recycled_tiling = recycled_impl->HighResTiling();
+ int num_tiles_y = tiling->TilingDataForTesting().num_tiles_y();
+
+ // There should be tiles at the top of the picture layer again.
+ EXPECT_TRUE(tiling->TileAt(0, 0));
+ EXPECT_FALSE(tiling->TileAt(0, num_tiles_y));
+
+ // The recycled tiling should have no tiles.
+ EXPECT_FALSE(recycled_tiling->TileAt(0, 0));
+ EXPECT_FALSE(recycled_tiling->TileAt(0, num_tiles_y));
+
+ // The live tiles rect matches on the recycled tree.
+ EXPECT_EQ(tiling->live_tiles_rect(),
+ recycled_tiling->live_tiles_rect());
+
+ // Make a new main frame without changing the picture layer at all, so
+ // it won't need to update or push properties.
+ did_post_commit_ = true;
+ PostSetNeedsCommitToMainThread();
+ break;
+ }
+ }
+ }
+
+ void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* child = impl->sync_tree()->root_layer()->children()[0];
+ FakePictureLayerImpl* picture_impl =
+ static_cast<FakePictureLayerImpl*>(child);
+ PictureLayerTiling* tiling = picture_impl->HighResTiling();
+ int num_tiles_y = tiling->TilingDataForTesting().num_tiles_y();
+
+ if (!impl->active_tree()->root_layer()) {
+ // If active tree doesn't have the layer, then pending tree should have
+ // all needed tiles.
+ EXPECT_TRUE(tiling->TileAt(0, 0));
+ } else {
+ // Since there was no invalidation, the pending tree shouldn't have any
+ // tiles.
+ EXPECT_FALSE(tiling->TileAt(0, 0));
+ }
+ EXPECT_FALSE(tiling->TileAt(0, num_tiles_y));
+
+ if (did_post_commit_)
EndTest();
}
void AfterTest() override {}
+ int frame_;
+ bool did_post_commit_;
FakeContentLayerClient client_;
- int activates_;
+ scoped_refptr<FakePictureLayer> picture_;
+};
+
+// Multi-thread only since there is no recycle tree in single thread.
+MULTI_THREAD_IMPL_TEST_F(
+ LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree);
+
+class LayerTreeHostPictureTestRSLLMembership : public LayerTreeHostPictureTest {
+ void SetupTree() override {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+
+ child_ = Layer::Create();
+ root->AddChild(child_);
+
+ // Don't be solid color so the layer has tilings/tiles.
+ client_.set_fill_with_nonsolid_color(true);
+ picture_ = FakePictureLayer::Create(&client_);
+ picture_->SetBounds(gfx::Size(100, 100));
+ child_->AddChild(picture_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostPictureTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->sync_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+ LayerImpl* gchild = child->children()[0];
+ FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
+
+ switch (impl->sync_tree()->source_frame_number()) {
+ case 0:
+ // On 1st commit the layer has tilings.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ break;
+ case 1:
+ // On 2nd commit, the layer is transparent, but its tilings are left
+ // there.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ break;
+ case 2:
+ // On 3rd commit, the layer is visible again, so has tilings.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ }
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = root->children()[0];
+ LayerImpl* gchild = child->children()[0];
+ FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
+
+ switch (impl->active_tree()->source_frame_number()) {
+ case 0:
+ // On 1st commit the layer has tilings.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ break;
+ case 1:
+ // On 2nd commit, the layer is transparent, but its tilings are left
+ // there.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ break;
+ case 2:
+ // On 3rd commit, the layer is visible again, so has tilings.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ EndTest();
+ }
+ }
+
+ void DidCommit() override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ // For the 2nd commit, change opacity to 0 so that the layer will not be
+ // part of the visible frame.
+ child_->SetOpacity(0.f);
+ break;
+ case 2:
+ // For the 3rd commit, change opacity to 1 so that the layer will again
+ // be part of the visible frame.
+ child_->SetOpacity(1.f);
+ }
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+ scoped_refptr<Layer> child_;
+ scoped_refptr<FakePictureLayer> picture_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestRSLLMembership);
+
+class LayerTreeHostPictureTestRSLLMembershipWithScale
+ : public LayerTreeHostPictureTest {
+ void SetupTree() override {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(100, 100));
+
+ pinch_ = Layer::Create();
+ pinch_->SetBounds(gfx::Size(500, 500));
+ pinch_->SetScrollClipLayerId(root->id());
+ pinch_->SetIsContainerForFixedPositionLayers(true);
+ root->AddChild(pinch_);
+
+ // Don't be solid color so the layer has tilings/tiles.
+ client_.set_fill_with_nonsolid_color(true);
+ picture_ = FakePictureLayer::Create(&client_);
+ picture_->SetBounds(gfx::Size(100, 100));
+ pinch_->AddChild(picture_);
+
+ layer_tree_host()->RegisterViewportLayers(NULL, root, pinch_, pinch_);
+ layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostPictureTest::SetupTree();
+ }
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->layer_transforms_should_scale_layer_contents = true;
+ }
+
+ void BeginTest() override {
+ frame_ = 0;
+ draws_in_frame_ = 0;
+ last_frame_drawn_ = -1;
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->sync_tree()->root_layer();
+ LayerImpl* pinch = root->children()[0];
+ LayerImpl* gchild = pinch->children()[0];
+ FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
+
+ switch (frame_) {
+ case 0:
+ // On 1st commit the layer has tilings.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ break;
+ case 1:
+ // On 2nd commit, the layer is transparent, so does not have tilings.
+ EXPECT_EQ(0u, picture->tilings()->num_tilings());
+ break;
+ case 2:
+ // On 3rd commit, the layer is visible again, so has tilings.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ }
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* pinch = root->children()[0];
+ LayerImpl* gchild = pinch->children()[0];
+ FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
+
+ if (frame_ != last_frame_drawn_)
+ draws_in_frame_ = 0;
+ ++draws_in_frame_;
+ last_frame_drawn_ = frame_;
+
+ switch (frame_) {
+ case 0:
+ if (draws_in_frame_ == 1) {
+ // On 1st commit the layer has tilings.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ EXPECT_EQ(1.f, picture->HighResTiling()->contents_scale());
+
+ // Pinch zoom in to change the scale on the active tree.
+ impl->PinchGestureBegin();
+ impl->PinchGestureUpdate(2.f, gfx::Point(1, 1));
+ impl->PinchGestureEnd();
+ } else if (picture->tilings()->num_tilings() == 1) {
+ // If the pinch gesture caused a commit we could get here with a
+ // pending tree.
+ EXPECT_FALSE(impl->pending_tree());
+ // The active layer now has only a 2.f scale tiling, which means the
+ // recycled layer's tiling is destroyed.
+ EXPECT_EQ(2.f, picture->HighResTiling()->contents_scale());
+ EXPECT_EQ(0u, picture->GetRecycledTwinLayer()
+ ->picture_layer_tiling_set()
+ ->num_tilings());
+
+ ++frame_;
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &LayerTreeHostPictureTestRSLLMembershipWithScale::NextStep,
+ base::Unretained(this)));
+ }
+ break;
+ case 1:
+ EXPECT_EQ(1, draws_in_frame_);
+ // On 2nd commit, the layer is transparent, so does not create
+ // tilings. Since the 1.f tiling was destroyed in the recycle tree, it
+ // has no tilings left. This is propogated to the active tree.
+ EXPECT_EQ(0u, picture->picture_layer_tiling_set()->num_tilings());
+ EXPECT_EQ(0u, picture->GetRecycledTwinLayer()
+ ->picture_layer_tiling_set()
+ ->num_tilings());
+ ++frame_;
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &LayerTreeHostPictureTestRSLLMembershipWithScale::NextStep,
+ base::Unretained(this)));
+ break;
+ case 2:
+ EXPECT_EQ(1, draws_in_frame_);
+ // On 3rd commit, the layer is visible again, so has tilings.
+ EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+ EndTest();
+ }
+ }
+
+ void NextStep() {
+ switch (frame_) {
+ case 1:
+ // For the 2nd commit, change opacity to 0 so that the layer will not be
+ // part of the visible frame.
+ pinch_->SetOpacity(0.f);
+ break;
+ case 2:
+ // For the 3rd commit, change opacity to 1 so that the layer will again
+ // be part of the visible frame.
+ pinch_->SetOpacity(1.f);
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+ scoped_refptr<Layer> pinch_;
+ scoped_refptr<FakePictureLayer> picture_;
+ int frame_;
+ int draws_in_frame_;
+ int last_frame_drawn_;
};
-MULTI_THREAD_TEST_F(LayerTreeHostPictureTestTwinLayer);
+// Multi-thread only because in single thread you can't pinch zoom on the
+// compositor thread.
+// Disabled due to flakiness. See http://crbug.com/460581
+// MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestRSLLMembershipWithScale);
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_proxy.cc b/chromium/cc/trees/layer_tree_host_unittest_proxy.cc
index f27b553a625..313510371e7 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_proxy.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_proxy.cc
@@ -28,7 +28,7 @@ namespace cc {
class ProxyTest : public LayerTreeTest {
protected:
ProxyTest() {}
- virtual ~ProxyTest() {}
+ ~ProxyTest() override {}
void Run(bool threaded, bool impl_side_painting) {
// We don't need to care about delegating mode.
@@ -67,7 +67,7 @@ class ProxyTestScheduledActionsBasic : public ProxyTest {
ProxyTestScheduledActionsBasic() : action_phase_(0) {
}
- virtual ~ProxyTestScheduledActionsBasic() {}
+ ~ProxyTestScheduledActionsBasic() override {}
private:
int action_phase_;
@@ -80,7 +80,7 @@ PROXY_TEST_SCHEDULED_ACTION(ProxyTestScheduledActionsBasic);
class ThreadProxyTest : public ProxyTest {
protected:
ThreadProxyTest() {}
- virtual ~ThreadProxyTest() {}
+ ~ThreadProxyTest() override {}
const ThreadProxy::MainThreadOnly& ThreadProxyMainOnly() const {
DCHECK(proxy());
@@ -101,7 +101,7 @@ class ThreadProxyTest : public ProxyTest {
class ThreadProxyTestSetNeedsCommit : public ThreadProxyTest {
protected:
ThreadProxyTestSetNeedsCommit() {}
- virtual ~ThreadProxyTestSetNeedsCommit() {}
+ ~ThreadProxyTestSetNeedsCommit() override {}
void BeginTest() override {
EXPECT_FALSE(ThreadProxyMainOnly().commit_requested);
diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
index 8e7d220d1ae..4e77a2d245f 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -4,10 +4,14 @@
#include "cc/trees/layer_tree_host.h"
+#include "base/location.h"
#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer.h"
+#include "cc/scheduler/begin_frame_source.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_picture_layer.h"
@@ -44,7 +48,8 @@ class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest {
scroll_layer->SetIsContainerForFixedPositionLayers(true);
scroll_layer->SetScrollClipLayerId(root_layer->id());
scroll_layer->SetScrollOffset(initial_scroll_);
- layer_tree_host()->RegisterViewportLayers(root_layer, scroll_layer, NULL);
+ layer_tree_host()->RegisterViewportLayers(NULL, root_layer, scroll_layer,
+ NULL);
PostSetNeedsCommitToMainThread();
}
@@ -75,12 +80,12 @@ class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest {
switch (impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->BaseScrollOffset());
EXPECT_VECTOR_EQ(scroll_amount_, scroll_layer->ScrollDelta());
PostSetNeedsCommitToMainThread();
break;
case 1:
- EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), second_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), second_scroll_);
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), scroll_amount_);
EndTest();
break;
@@ -121,7 +126,8 @@ class LayerTreeHostScrollTestScrollMultipleRedraw
scroll_layer_->SetIsContainerForFixedPositionLayers(true);
scroll_layer_->SetScrollClipLayerId(root_layer->id());
scroll_layer_->SetScrollOffset(initial_scroll_);
- layer_tree_host()->RegisterViewportLayers(root_layer, scroll_layer_, NULL);
+ layer_tree_host()->RegisterViewportLayers(NULL, root_layer, scroll_layer_,
+ NULL);
PostSetNeedsCommitToMainThread();
}
@@ -154,7 +160,7 @@ class LayerTreeHostScrollTestScrollMultipleRedraw
scroll_layer->ScrollBy(scroll_amount_);
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), scroll_amount_);
- EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), initial_scroll_);
PostSetNeedsRedrawToMainThread();
} else if (impl->active_tree()->source_frame_number() == 0 &&
impl->SourceAnimationFrameNumber() == 2) {
@@ -223,8 +229,8 @@ class LayerTreeHostScrollTestScrollAbortedCommit
root_scroll_layer->SetIsContainerForFixedPositionLayers(true);
root_layer->AddChild(root_scroll_layer);
- layer_tree_host()->RegisterViewportLayers(
- root_layer, root_scroll_layer, NULL);
+ layer_tree_host()->RegisterViewportLayers(NULL, root_layer,
+ root_scroll_layer, NULL);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
}
@@ -300,13 +306,13 @@ class LayerTreeHostScrollTestScrollAbortedCommit
EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d());
root_scroll_layer->ScrollBy(impl_scroll_);
EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), impl_scroll_);
- EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(root_scroll_layer->BaseScrollOffset(), initial_scroll_);
EXPECT_EQ(1.f, impl->active_tree()->page_scale_delta());
- EXPECT_EQ(1.f, impl->active_tree()->total_page_scale_factor());
- impl->active_tree()->SetPageScaleDelta(impl_scale_);
+ EXPECT_EQ(1.f, impl->active_tree()->current_page_scale_factor());
+ impl->SetPageScaleOnActiveTree(impl_scale_);
EXPECT_EQ(impl_scale_, impl->active_tree()->page_scale_delta());
- EXPECT_EQ(impl_scale_, impl->active_tree()->total_page_scale_factor());
+ EXPECT_EQ(impl_scale_, impl->active_tree()->current_page_scale_factor());
// To simplify the testing flow, don't redraw here, just commit.
impl->SetNeedsCommit();
@@ -319,15 +325,15 @@ class LayerTreeHostScrollTestScrollAbortedCommit
root_scroll_layer->ScrollBy(impl_scroll_);
EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), impl_scroll_);
EXPECT_VECTOR_EQ(
- root_scroll_layer->scroll_offset(),
+ root_scroll_layer->BaseScrollOffset(),
gfx::ScrollOffsetWithDelta(initial_scroll_, impl_scroll_));
EXPECT_EQ(1.f, impl->active_tree()->page_scale_delta());
- EXPECT_EQ(impl_scale_, impl->active_tree()->total_page_scale_factor());
- impl->active_tree()->SetPageScaleDelta(impl_scale_);
+ EXPECT_EQ(impl_scale_, impl->active_tree()->current_page_scale_factor());
+ impl->SetPageScaleOnActiveTree(impl_scale_ * impl_scale_);
EXPECT_EQ(impl_scale_, impl->active_tree()->page_scale_delta());
EXPECT_EQ(impl_scale_ * impl_scale_,
- impl->active_tree()->total_page_scale_factor());
+ impl->active_tree()->current_page_scale_factor());
impl->SetNeedsCommit();
} else if (impl->active_tree()->source_frame_number() == 1) {
@@ -341,7 +347,7 @@ class LayerTreeHostScrollTestScrollAbortedCommit
impl->SetNeedsCommit();
EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), impl_scroll_);
gfx::Vector2dF delta = impl_scroll_ + impl_scroll_ + second_main_scroll_;
- EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(),
+ EXPECT_VECTOR_EQ(root_scroll_layer->BaseScrollOffset(),
gfx::ScrollOffsetWithDelta(initial_scroll_, delta));
} else if (impl->active_tree()->source_frame_number() == 2 &&
impl->SourceAnimationFrameNumber() == 4) {
@@ -349,7 +355,7 @@ class LayerTreeHostScrollTestScrollAbortedCommit
EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d());
gfx::Vector2dF delta =
impl_scroll_ + impl_scroll_ + impl_scroll_ + second_main_scroll_;
- EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(),
+ EXPECT_VECTOR_EQ(root_scroll_layer->BaseScrollOffset(),
gfx::ScrollOffsetWithDelta(initial_scroll_, delta));
EndTest();
} else {
@@ -406,8 +412,8 @@ class LayerTreeHostScrollTestFractionalScroll : public LayerTreeHostScrollTest {
root_scroll_layer->SetIsContainerForFixedPositionLayers(true);
root_layer->AddChild(root_scroll_layer);
- layer_tree_host()->RegisterViewportLayers(
- root_layer, root_scroll_layer, NULL);
+ layer_tree_host()->RegisterViewportLayers(NULL, root_layer,
+ root_scroll_layer, NULL);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
}
@@ -421,12 +427,12 @@ class LayerTreeHostScrollTestFractionalScroll : public LayerTreeHostScrollTest {
// multiple commits.
switch (impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), gfx::Vector2d(0, 0));
+ EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), gfx::Vector2d(0, 0));
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d(0, 0));
PostSetNeedsCommitToMainThread();
break;
case 1:
- EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(),
+ EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(),
gfx::ToFlooredVector2d(scroll_amount_));
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(),
gfx::Vector2dF(fmod(scroll_amount_.x(), 1.0f), 0.0f));
@@ -434,7 +440,7 @@ class LayerTreeHostScrollTestFractionalScroll : public LayerTreeHostScrollTest {
break;
case 2:
EXPECT_VECTOR_EQ(
- scroll_layer->scroll_offset(),
+ scroll_layer->BaseScrollOffset(),
gfx::ToFlooredVector2d(scroll_amount_ + scroll_amount_));
EXPECT_VECTOR_EQ(
scroll_layer->ScrollDelta(),
@@ -509,8 +515,8 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest {
expected_scroll_layer_->SetScrollOffset(initial_offset_);
layer_tree_host()->SetRootLayer(root_layer);
- layer_tree_host()->RegisterViewportLayers(
- root_layer, root_scroll_layer_, NULL);
+ layer_tree_host()->RegisterViewportLayers(NULL, root_layer,
+ root_scroll_layer_, NULL);
LayerTreeHostScrollTest::SetupTree();
}
@@ -584,44 +590,44 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest {
EXPECT_EQ(device_scale_factor_, impl->active_tree()->device_scale_factor());
switch (impl->active_tree()->source_frame_number()) {
case 0: {
- // Gesture scroll on impl thread.
+ // GESTURE scroll on impl thread.
InputHandler::ScrollStatus status = impl->ScrollBegin(
gfx::ToCeiledPoint(expected_scroll_layer_impl->position() -
gfx::Vector2dF(0.5f, 0.5f)),
- InputHandler::Gesture);
- EXPECT_EQ(InputHandler::ScrollStarted, status);
+ InputHandler::GESTURE);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, status);
impl->ScrollBy(gfx::Point(), scroll_amount_);
impl->ScrollEnd();
// Check the scroll is applied as a delta.
EXPECT_VECTOR_EQ(initial_offset_,
- expected_scroll_layer_impl->scroll_offset());
+ expected_scroll_layer_impl->BaseScrollOffset());
EXPECT_VECTOR_EQ(scroll_amount_,
expected_scroll_layer_impl->ScrollDelta());
break;
}
case 1: {
- // Wheel scroll on impl thread.
+ // WHEEL scroll on impl thread.
InputHandler::ScrollStatus status = impl->ScrollBegin(
gfx::ToCeiledPoint(expected_scroll_layer_impl->position() +
gfx::Vector2dF(0.5f, 0.5f)),
- InputHandler::Wheel);
- EXPECT_EQ(InputHandler::ScrollStarted, status);
+ InputHandler::WHEEL);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, status);
impl->ScrollBy(gfx::Point(), scroll_amount_);
impl->ScrollEnd();
// Check the scroll is applied as a delta.
EXPECT_VECTOR_EQ(javascript_scroll_,
- expected_scroll_layer_impl->scroll_offset());
+ expected_scroll_layer_impl->BaseScrollOffset());
EXPECT_VECTOR_EQ(scroll_amount_,
expected_scroll_layer_impl->ScrollDelta());
break;
}
case 2:
- EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(javascript_scroll_,
- scroll_amount_),
- expected_scroll_layer_impl->scroll_offset());
+ EXPECT_VECTOR_EQ(
+ gfx::ScrollOffsetWithDelta(javascript_scroll_, scroll_amount_),
+ expected_scroll_layer_impl->BaseScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2d(),
expected_scroll_layer_impl->ScrollDelta());
@@ -778,8 +784,8 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest {
root_scroll_layer->SetIsContainerForFixedPositionLayers(true);
root_layer->AddChild(root_scroll_layer);
- layer_tree_host()->RegisterViewportLayers(
- root_layer, root_scroll_layer, NULL);
+ layer_tree_host()->RegisterViewportLayers(NULL, root_layer,
+ root_scroll_layer, NULL);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
}
@@ -825,9 +831,8 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest {
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d());
scroll_layer->ScrollBy(impl_thread_scroll1_);
- EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), initial_scroll_);
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll1_);
- EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d());
PostSetNeedsCommitToMainThread();
// CommitCompleteOnThread will trigger this function again
@@ -838,31 +843,26 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest {
EXPECT_EQ(impl->pending_tree()->source_frame_number(), 1);
scroll_layer->ScrollBy(impl_thread_scroll2_);
- EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), initial_scroll_);
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(),
impl_thread_scroll1_ + impl_thread_scroll2_);
- EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(),
- impl_thread_scroll1_);
LayerImpl* pending_scroll_layer = pending_root->children()[0];
EXPECT_VECTOR_EQ(
- pending_scroll_layer->scroll_offset(),
+ pending_scroll_layer->BaseScrollOffset(),
gfx::ScrollOffsetWithDelta(
initial_scroll_, main_thread_scroll_ + impl_thread_scroll1_));
EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(),
impl_thread_scroll2_);
- EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(),
- gfx::Vector2d());
}
break;
case 1:
EXPECT_FALSE(impl->pending_tree());
EXPECT_VECTOR_EQ(
- scroll_layer->scroll_offset(),
+ scroll_layer->BaseScrollOffset(),
gfx::ScrollOffsetWithDelta(
initial_scroll_, main_thread_scroll_ + impl_thread_scroll1_));
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll2_);
- EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d());
EndTest();
break;
}
@@ -894,7 +894,7 @@ class ImplSidePaintingScrollTestImplOnlyScroll
: public ImplSidePaintingScrollTest {
public:
ImplSidePaintingScrollTestImplOnlyScroll()
- : initial_scroll_(20, 10), impl_thread_scroll_(-2, 3) {}
+ : initial_scroll_(20, 10), impl_thread_scroll_(-2, 3), impl_scale_(2.f) {}
void SetupTree() override {
LayerTreeHostScrollTest::SetupTree();
@@ -909,8 +909,8 @@ class ImplSidePaintingScrollTestImplOnlyScroll
root_scroll_layer->SetIsContainerForFixedPositionLayers(true);
root_layer->AddChild(root_scroll_layer);
- layer_tree_host()->RegisterViewportLayers(
- root_layer, root_scroll_layer, NULL);
+ layer_tree_host()->RegisterViewportLayers(NULL, root_layer,
+ root_scroll_layer, NULL);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
}
@@ -940,6 +940,7 @@ class ImplSidePaintingScrollTestImplOnlyScroll
ASSERT_TRUE(active_root);
ASSERT_TRUE(active_scroll_layer);
active_scroll_layer->ScrollBy(impl_thread_scroll_);
+ impl->SetPageScaleOnActiveTree(impl_scale_);
}
}
@@ -956,38 +957,30 @@ class ImplSidePaintingScrollTestImplOnlyScroll
ASSERT_TRUE(pending_scroll_layer);
switch (impl->pending_tree()->source_frame_number()) {
case 0:
- EXPECT_VECTOR_EQ(pending_scroll_layer->scroll_offset(),
+ EXPECT_VECTOR_EQ(pending_scroll_layer->BaseScrollOffset(),
initial_scroll_);
EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), gfx::Vector2d());
- EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(),
- gfx::Vector2d());
EXPECT_FALSE(active_root);
break;
case 1:
// Even though the scroll happened during the commit, both layers
// should have the appropriate scroll delta.
- EXPECT_VECTOR_EQ(pending_scroll_layer->scroll_offset(),
+ EXPECT_VECTOR_EQ(pending_scroll_layer->BaseScrollOffset(),
initial_scroll_);
EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(),
impl_thread_scroll_);
- EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(),
- gfx::Vector2d());
ASSERT_TRUE(active_root);
- EXPECT_VECTOR_EQ(active_scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(active_scroll_layer->BaseScrollOffset(),
+ initial_scroll_);
EXPECT_VECTOR_EQ(active_scroll_layer->ScrollDelta(),
impl_thread_scroll_);
- EXPECT_VECTOR_EQ(active_scroll_layer->sent_scroll_delta(),
- gfx::Vector2d());
break;
case 2:
// On the next commit, this delta should have been sent and applied.
- EXPECT_VECTOR_EQ(pending_scroll_layer->scroll_offset(),
- gfx::ScrollOffsetWithDelta(initial_scroll_,
- impl_thread_scroll_));
+ EXPECT_VECTOR_EQ(
+ pending_scroll_layer->BaseScrollOffset(),
+ gfx::ScrollOffsetWithDelta(initial_scroll_, impl_thread_scroll_));
EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), gfx::Vector2d());
- EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(),
- gfx::Vector2d());
- EndTest();
break;
}
}
@@ -1000,17 +993,26 @@ class ImplSidePaintingScrollTestImplOnlyScroll
switch (impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), initial_scroll_);
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d());
- EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_EQ(1.f, impl->active_tree()->page_scale_delta());
+ EXPECT_EQ(1.f, impl->active_tree()->current_page_scale_factor());
PostSetNeedsCommitToMainThread();
break;
case 1:
- EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), initial_scroll_);
EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll_);
- EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_EQ(impl_scale_, impl->active_tree()->page_scale_delta());
+ EXPECT_EQ(impl_scale_,
+ impl->active_tree()->current_page_scale_factor());
PostSetNeedsCommitToMainThread();
break;
+ case 2:
+ EXPECT_EQ(1.f, impl->active_tree()->page_scale_delta());
+ EXPECT_EQ(impl_scale_,
+ impl->active_tree()->current_page_scale_factor());
+ EndTest();
+ break;
}
}
@@ -1019,6 +1021,7 @@ class ImplSidePaintingScrollTestImplOnlyScroll
private:
gfx::ScrollOffset initial_scroll_;
gfx::Vector2dF impl_thread_scroll_;
+ float impl_scale_;
};
MULTI_THREAD_TEST_F(ImplSidePaintingScrollTestImplOnlyScroll);
@@ -1044,21 +1047,24 @@ class LayerTreeHostScrollTestScrollZeroMaxScrollOffset
// Set max_scroll_offset = (100, 100).
scroll_layer->SetBounds(
gfx::Size(root->bounds().width() + 100, root->bounds().height() + 100));
- EXPECT_EQ(InputHandler::ScrollStarted,
- scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f),
- InputHandler::Gesture));
+ EXPECT_EQ(
+ InputHandler::SCROLL_STARTED,
+ scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
// Set max_scroll_offset = (0, 0).
scroll_layer->SetBounds(root->bounds());
- EXPECT_EQ(InputHandler::ScrollIgnored,
- scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f),
- InputHandler::Gesture));
+ EXPECT_EQ(
+ InputHandler::SCROLL_IGNORED,
+ scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
// Set max_scroll_offset = (-100, -100).
scroll_layer->SetBounds(gfx::Size());
- EXPECT_EQ(InputHandler::ScrollIgnored,
- scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f),
- InputHandler::Gesture));
+ EXPECT_EQ(
+ InputHandler::SCROLL_IGNORED,
+ scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
EndTest();
}
@@ -1091,6 +1097,13 @@ class ThreadCheckingInputHandlerClient : public InputHandlerClient {
*received_stop_flinging_ = true;
}
+ void ReconcileElasticOverscrollAndRootScroll() override {
+ if (!task_runner_->BelongsToCurrentThread()) {
+ ADD_FAILURE() << "ReconcileElasticOverscrollAndRootScroll called on "
+ << "wrong thread";
+ }
+ }
+
private:
base::SingleThreadTaskRunner* task_runner_;
bool* received_stop_flinging_;
@@ -1110,23 +1123,23 @@ TEST(LayerTreeHostFlingTest, DidStopFlingingThread) {
LayerTreeSettings settings;
ThreadCheckingInputHandlerClient input_handler_client(
- impl_thread.message_loop_proxy().get(), &received_stop_flinging);
+ impl_thread.task_runner().get(), &received_stop_flinging);
FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
- ASSERT_TRUE(impl_thread.message_loop_proxy().get());
+ ASSERT_TRUE(impl_thread.task_runner().get());
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
+
+ LayerTreeHost::InitParams params;
+ params.client = &client;
+ params.shared_bitmap_manager = shared_bitmap_manager.get();
+ params.settings = &settings;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
scoped_ptr<LayerTreeHost> layer_tree_host =
- LayerTreeHost::CreateThreaded(&client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current(),
- impl_thread.message_loop_proxy());
-
- impl_thread.message_loop_proxy()
- ->PostTask(FROM_HERE,
- base::Bind(&BindInputHandlerOnCompositorThread,
+ LayerTreeHost::CreateThreaded(impl_thread.task_runner(), &params);
+
+ impl_thread.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&BindInputHandlerOnCompositorThread,
layer_tree_host->GetInputHandler(),
base::Unretained(&input_handler_client)));
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index 6b2b37f2c5f..01a4cfd19ec 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -4,19 +4,22 @@
#include "cc/trees/layer_tree_impl.h"
+#include <algorithm>
#include <limits>
#include <set>
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
#include "cc/animation/keyframed_animation_curve.h"
#include "cc/animation/scrollbar_animation_controller.h"
#include "cc/animation/scrollbar_animation_controller_linear_fade.h"
#include "cc/animation/scrollbar_animation_controller_thinning.h"
#include "cc/base/math_util.h"
+#include "cc/base/synced_property.h"
#include "cc/base/util.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/traced_value.h"
+#include "cc/input/layer_scroll_offset_delegate.h"
#include "cc/input/page_scale_animation.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/layer.h"
@@ -33,46 +36,11 @@
namespace cc {
-// This class exists to split the LayerScrollOffsetDelegate between the
-// InnerViewportScrollLayer and the OuterViewportScrollLayer in a manner
-// that never requires the embedder or LayerImpl to know about.
-class LayerScrollOffsetDelegateProxy : public LayerImpl::ScrollOffsetDelegate {
- public:
- LayerScrollOffsetDelegateProxy(LayerImpl* layer,
- LayerScrollOffsetDelegate* delegate,
- LayerTreeImpl* layer_tree)
- : layer_(layer), delegate_(delegate), layer_tree_impl_(layer_tree) {}
- virtual ~LayerScrollOffsetDelegateProxy() {}
-
- gfx::ScrollOffset last_set_scroll_offset() const {
- return last_set_scroll_offset_;
- }
-
- // LayerScrollOffsetDelegate implementation.
- void SetTotalScrollOffset(const gfx::ScrollOffset& new_offset) override {
- last_set_scroll_offset_ = new_offset;
- }
-
- gfx::ScrollOffset GetTotalScrollOffset() override {
- return layer_tree_impl_->GetDelegatedScrollOffset(layer_);
- }
-
- bool IsExternalFlingActive() const override {
- return delegate_->IsExternalFlingActive();
- }
-
- void Update() const override {
- layer_tree_impl_->UpdateScrollOffsetDelegate();
- }
-
- private:
- LayerImpl* layer_;
- LayerScrollOffsetDelegate* delegate_;
- LayerTreeImpl* layer_tree_impl_;
- gfx::ScrollOffset last_set_scroll_offset_;
-};
-
-LayerTreeImpl::LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl)
+LayerTreeImpl::LayerTreeImpl(
+ LayerTreeHostImpl* layer_tree_host_impl,
+ scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
+ scoped_refptr<SyncedTopControls> top_controls_shown_ratio,
+ scoped_refptr<SyncedElasticOverscroll> elastic_overscroll)
: layer_tree_host_impl_(layer_tree_host_impl),
source_frame_number_(-1),
hud_layer_(0),
@@ -80,14 +48,14 @@ LayerTreeImpl::LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl)
root_layer_scroll_offset_delegate_(NULL),
background_color_(0),
has_transparent_background_(false),
+ overscroll_elasticity_layer_(NULL),
page_scale_layer_(NULL),
inner_viewport_scroll_layer_(NULL),
outer_viewport_scroll_layer_(NULL),
- page_scale_factor_(1),
- page_scale_delta_(1),
- sent_page_scale_delta_(1),
+ page_scale_factor_(page_scale_factor),
min_page_scale_factor_(0),
max_page_scale_factor_(0),
+ elastic_overscroll_(elastic_overscroll),
scrolling_layer_id_from_previous_tree_(0),
contents_textures_purged_(false),
viewport_size_invalid_(false),
@@ -96,14 +64,14 @@ LayerTreeImpl::LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl)
next_activation_forces_redraw_(false),
has_ever_been_drawn_(false),
render_surface_layer_list_id_(0),
- top_controls_layout_height_(0),
- top_controls_content_offset_(0),
- top_controls_delta_(0),
- sent_top_controls_delta_(0) {
+ top_controls_shrink_blink_size_(false),
+ top_controls_height_(0),
+ top_controls_shown_ratio_(top_controls_shown_ratio) {
}
LayerTreeImpl::~LayerTreeImpl() {
- BreakSwapPromises(SwapPromise::SWAP_FAILS);
+ BreakSwapPromises(IsActiveTree() ? SwapPromise::SWAP_FAILS
+ : SwapPromise::ACTIVATION_FAILS);
// Need to explicitly clear the tree prior to destroying this so that
// the LayerTreeImpl pointer is still valid in the LayerImpl dtor.
@@ -116,18 +84,56 @@ void LayerTreeImpl::Shutdown() {
}
void LayerTreeImpl::ReleaseResources() {
- if (root_layer_)
- ReleaseResourcesRecursive(root_layer_.get());
+ if (root_layer_) {
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ root_layer_.get(), [](LayerImpl* layer) { layer->ReleaseResources(); });
+ }
}
-void LayerTreeImpl::SetRootLayer(scoped_ptr<LayerImpl> layer) {
- if (inner_viewport_scroll_layer_)
- inner_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL);
- if (outer_viewport_scroll_layer_)
- outer_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL);
- inner_viewport_scroll_delegate_proxy_ = nullptr;
- outer_viewport_scroll_delegate_proxy_ = nullptr;
+void LayerTreeImpl::RecreateResources() {
+ if (root_layer_) {
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ root_layer_.get(),
+ [](LayerImpl* layer) { layer->RecreateResources(); });
+ }
+}
+
+void LayerTreeImpl::GatherFrameTimingRequestIds(
+ std::vector<int64_t>* request_ids) {
+ if (!root_layer_)
+ return;
+
+ // TODO(vmpstr): Early out if there are no requests on any of the layers. For
+ // that, we need to inform LayerTreeImpl whenever there are requests when we
+ // get them.
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ root_layer_.get(), [request_ids](LayerImpl* layer) {
+ layer->GatherFrameTimingRequestIds(request_ids);
+ });
+}
+
+bool LayerTreeImpl::IsExternalFlingActive() const {
+ return root_layer_scroll_offset_delegate_ &&
+ root_layer_scroll_offset_delegate_->IsExternalFlingActive();
+}
+void LayerTreeImpl::DidUpdateScrollOffset(int layer_id) {
+ int inner_layer_id = InnerViewportScrollLayer()
+ ? InnerViewportScrollLayer()->id()
+ : Layer::INVALID_ID;
+ int outer_layer_id = OuterViewportScrollLayer()
+ ? OuterViewportScrollLayer()->id()
+ : Layer::INVALID_ID;
+ if (layer_id != outer_layer_id && layer_id != inner_layer_id)
+ return;
+
+ if (!root_layer_scroll_offset_delegate_)
+ return;
+
+ UpdateRootScrollOffsetDelegate();
+}
+
+void LayerTreeImpl::SetRootLayer(scoped_ptr<LayerImpl> layer) {
root_layer_ = layer.Pass();
currently_scrolling_layer_ = NULL;
inner_viewport_scroll_layer_ = NULL;
@@ -149,10 +155,10 @@ gfx::ScrollOffset LayerTreeImpl::TotalScrollOffset() const {
gfx::ScrollOffset offset;
if (inner_viewport_scroll_layer_)
- offset += inner_viewport_scroll_layer_->TotalScrollOffset();
+ offset += inner_viewport_scroll_layer_->CurrentScrollOffset();
if (outer_viewport_scroll_layer_)
- offset += outer_viewport_scroll_layer_->TotalScrollOffset();
+ offset += outer_viewport_scroll_layer_->CurrentScrollOffset();
return offset;
}
@@ -168,26 +174,11 @@ gfx::ScrollOffset LayerTreeImpl::TotalMaxScrollOffset() const {
return offset;
}
-gfx::Vector2dF LayerTreeImpl::TotalScrollDelta() const {
- DCHECK(inner_viewport_scroll_layer_);
- gfx::Vector2dF delta = inner_viewport_scroll_layer_->ScrollDelta();
-
- if (outer_viewport_scroll_layer_)
- delta += outer_viewport_scroll_layer_->ScrollDelta();
-
- return delta;
-}
scoped_ptr<LayerImpl> LayerTreeImpl::DetachLayerTree() {
// Clear all data structures that have direct references to the layer tree.
scrolling_layer_id_from_previous_tree_ =
currently_scrolling_layer_ ? currently_scrolling_layer_->id() : 0;
- if (inner_viewport_scroll_layer_)
- inner_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL);
- if (outer_viewport_scroll_layer_)
- outer_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL);
- inner_viewport_scroll_delegate_proxy_ = nullptr;
- outer_viewport_scroll_delegate_proxy_ = nullptr;
inner_viewport_scroll_layer_ = NULL;
outer_viewport_scroll_layer_ = NULL;
page_scale_layer_ = NULL;
@@ -202,6 +193,8 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
// The request queue should have been processed and does not require a push.
DCHECK_EQ(ui_resource_request_queue_.size(), 0u);
+ target_tree->SetPropertyTrees(property_trees_);
+
if (next_activation_forces_redraw_) {
target_tree->ForceRedrawNextActivation();
next_activation_forces_redraw_ = false;
@@ -209,31 +202,32 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->PassSwapPromises(&swap_promise_list_);
- target_tree->top_controls_layout_height_ = top_controls_layout_height_;
- target_tree->top_controls_content_offset_ = top_controls_content_offset_;
- target_tree->top_controls_delta_ =
- target_tree->top_controls_delta_ -
- target_tree->sent_top_controls_delta_;
- target_tree->sent_top_controls_delta_ = 0.f;
+ target_tree->set_top_controls_shrink_blink_size(
+ top_controls_shrink_blink_size_);
+ target_tree->set_top_controls_height(top_controls_height_);
+ target_tree->PushTopControls(nullptr);
- target_tree->SetPageScaleValues(
- page_scale_factor(), min_page_scale_factor(), max_page_scale_factor(),
- target_tree->page_scale_delta() / target_tree->sent_page_scale_delta());
- target_tree->set_sent_page_scale_delta(1);
+ // Active tree already shares the page_scale_factor object with pending
+ // tree so only the limits need to be provided.
+ target_tree->PushPageScaleFactorAndLimits(nullptr, min_page_scale_factor(),
+ max_page_scale_factor());
+ target_tree->elastic_overscroll()->PushPendingToActive();
- target_tree->page_scale_animation_ = page_scale_animation_.Pass();
+ target_tree->pending_page_scale_animation_ =
+ pending_page_scale_animation_.Pass();
if (page_scale_layer_ && inner_viewport_scroll_layer_) {
target_tree->SetViewportLayersFromIds(
- page_scale_layer_->id(),
- inner_viewport_scroll_layer_->id(),
+ overscroll_elasticity_layer_ ? overscroll_elasticity_layer_->id()
+ : Layer::INVALID_ID,
+ page_scale_layer_->id(), inner_viewport_scroll_layer_->id(),
outer_viewport_scroll_layer_ ? outer_viewport_scroll_layer_->id()
: Layer::INVALID_ID);
} else {
target_tree->ClearViewportLayers();
}
- target_tree->RegisterSelection(selection_start_, selection_end_);
+ target_tree->RegisterSelection(selection_);
// This should match the property synchronization in
// LayerTreeHost::finishCommitOnImplThread().
@@ -310,64 +304,148 @@ void ForceScrollbarParameterUpdateAfterScaleChange(LayerImpl* current_layer) {
} // namespace
-void LayerTreeImpl::SetPageScaleFactorAndLimits(float page_scale_factor,
- float min_page_scale_factor, float max_page_scale_factor) {
- SetPageScaleValues(page_scale_factor, min_page_scale_factor,
- max_page_scale_factor, page_scale_delta_);
+float LayerTreeImpl::ClampPageScaleFactorToLimits(
+ float page_scale_factor) const {
+ if (min_page_scale_factor_ && page_scale_factor < min_page_scale_factor_)
+ page_scale_factor = min_page_scale_factor_;
+ else if (max_page_scale_factor_ && page_scale_factor > max_page_scale_factor_)
+ page_scale_factor = max_page_scale_factor_;
+ return page_scale_factor;
}
-void LayerTreeImpl::SetPageScaleDelta(float delta) {
- SetPageScaleValues(page_scale_factor_, min_page_scale_factor_,
- max_page_scale_factor_, delta);
-}
+void LayerTreeImpl::SetPageScaleOnActiveTree(float active_page_scale) {
+ DCHECK(IsActiveTree());
+ if (page_scale_factor()->SetCurrent(
+ ClampPageScaleFactorToLimits(active_page_scale)))
+ DidUpdatePageScale();
+}
+
+void LayerTreeImpl::PushPageScaleFromMainThread(float page_scale_factor,
+ float min_page_scale_factor,
+ float max_page_scale_factor) {
+ PushPageScaleFactorAndLimits(&page_scale_factor, min_page_scale_factor,
+ max_page_scale_factor);
+}
+
+void LayerTreeImpl::PushPageScaleFactorAndLimits(const float* page_scale_factor,
+ float min_page_scale_factor,
+ float max_page_scale_factor) {
+ DCHECK(page_scale_factor || IsActiveTree());
+ bool changed_page_scale = false;
+ if (page_scale_factor) {
+ DCHECK(!IsActiveTree() || !layer_tree_host_impl_->pending_tree());
+ changed_page_scale |=
+ page_scale_factor_->PushFromMainThread(*page_scale_factor);
+ }
+ if (IsActiveTree())
+ changed_page_scale |= page_scale_factor_->PushPendingToActive();
+ changed_page_scale |=
+ SetPageScaleFactorLimits(min_page_scale_factor, max_page_scale_factor);
-void LayerTreeImpl::SetPageScaleValues(float page_scale_factor,
- float min_page_scale_factor, float max_page_scale_factor,
- float page_scale_delta) {
- bool page_scale_changed =
- min_page_scale_factor != min_page_scale_factor_ ||
- max_page_scale_factor != max_page_scale_factor_ ||
- page_scale_factor != page_scale_factor_;
+ if (changed_page_scale)
+ DidUpdatePageScale();
+}
- min_page_scale_factor_ = min_page_scale_factor;
- max_page_scale_factor_ = max_page_scale_factor;
- page_scale_factor_ = page_scale_factor;
+void LayerTreeImpl::set_top_controls_shrink_blink_size(bool shrink) {
+ if (top_controls_shrink_blink_size_ == shrink)
+ return;
- float total = page_scale_factor_ * page_scale_delta;
- if (min_page_scale_factor_ && total < min_page_scale_factor_)
- page_scale_delta = min_page_scale_factor_ / page_scale_factor_;
- else if (max_page_scale_factor_ && total > max_page_scale_factor_)
- page_scale_delta = max_page_scale_factor_ / page_scale_factor_;
+ top_controls_shrink_blink_size_ = shrink;
+ if (IsActiveTree())
+ layer_tree_host_impl_->UpdateViewportContainerSizes();
+}
- if (page_scale_delta_ == page_scale_delta && !page_scale_changed)
+void LayerTreeImpl::set_top_controls_height(float top_controls_height) {
+ if (top_controls_height_ == top_controls_height)
return;
- if (page_scale_delta_ != page_scale_delta) {
- page_scale_delta_ = page_scale_delta;
+ top_controls_height_ = top_controls_height;
+ if (IsActiveTree())
+ layer_tree_host_impl_->UpdateViewportContainerSizes();
+}
- if (IsActiveTree()) {
- LayerTreeImpl* pending_tree = layer_tree_host_impl_->pending_tree();
- if (pending_tree) {
- DCHECK_EQ(1, pending_tree->sent_page_scale_delta());
- pending_tree->SetPageScaleDelta(
- page_scale_delta_ / sent_page_scale_delta_);
- }
- }
+bool LayerTreeImpl::SetCurrentTopControlsShownRatio(float ratio) {
+ ratio = std::max(ratio, 0.f);
+ ratio = std::min(ratio, 1.f);
+ return top_controls_shown_ratio_->SetCurrent(ratio);
+}
+
+void LayerTreeImpl::PushTopControlsFromMainThread(
+ float top_controls_shown_ratio) {
+ PushTopControls(&top_controls_shown_ratio);
+}
+
+void LayerTreeImpl::PushTopControls(const float* top_controls_shown_ratio) {
+ DCHECK(top_controls_shown_ratio || IsActiveTree());
- set_needs_update_draw_properties();
+ if (top_controls_shown_ratio) {
+ DCHECK(!IsActiveTree() || !layer_tree_host_impl_->pending_tree());
+ top_controls_shown_ratio_->PushFromMainThread(*top_controls_shown_ratio);
}
+ if (IsActiveTree()) {
+ if (top_controls_shown_ratio_->PushPendingToActive())
+ layer_tree_host_impl_->DidChangeTopControlsPosition();
+ }
+}
+
+bool LayerTreeImpl::SetPageScaleFactorLimits(float min_page_scale_factor,
+ float max_page_scale_factor) {
+ if (min_page_scale_factor == min_page_scale_factor_ &&
+ max_page_scale_factor == max_page_scale_factor_)
+ return false;
+
+ min_page_scale_factor_ = min_page_scale_factor;
+ max_page_scale_factor_ = max_page_scale_factor;
+
+ return true;
+}
+
+void LayerTreeImpl::DidUpdatePageScale() {
+ if (IsActiveTree())
+ page_scale_factor()->SetCurrent(
+ ClampPageScaleFactorToLimits(current_page_scale_factor()));
+
+ set_needs_update_draw_properties();
if (root_layer_scroll_offset_delegate_) {
root_layer_scroll_offset_delegate_->UpdateRootLayerState(
- TotalScrollOffset(),
- TotalMaxScrollOffset(),
- ScrollableSize(),
- total_page_scale_factor(),
- min_page_scale_factor_,
+ TotalScrollOffset(), TotalMaxScrollOffset(), ScrollableSize(),
+ current_page_scale_factor(), min_page_scale_factor_,
max_page_scale_factor_);
}
ForceScrollbarParameterUpdateAfterScaleChange(page_scale_layer());
+
+ HideInnerViewportScrollbarsIfNearMinimumScale();
+}
+
+void LayerTreeImpl::HideInnerViewportScrollbarsIfNearMinimumScale() {
+ if (!InnerViewportContainerLayer())
+ return;
+
+ LayerImpl::ScrollbarSet* scrollbars =
+ InnerViewportContainerLayer()->scrollbars();
+
+ if (!scrollbars)
+ return;
+
+ for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin();
+ it != scrollbars->end();
+ ++it) {
+ ScrollbarLayerImplBase* scrollbar = *it;
+ float minimum_scale_to_show_at =
+ min_page_scale_factor() * settings().scrollbar_show_scale_threshold;
+ scrollbar->SetHideLayerAndSubtree(
+ current_page_scale_factor() < minimum_scale_to_show_at);
+ }
+}
+
+SyncedProperty<ScaleGroup>* LayerTreeImpl::page_scale_factor() {
+ return page_scale_factor_.get();
+}
+
+const SyncedProperty<ScaleGroup>* LayerTreeImpl::page_scale_factor() const {
+ return page_scale_factor_.get();
}
gfx::SizeF LayerTreeImpl::ScrollableViewportSize() const {
@@ -375,7 +453,7 @@ gfx::SizeF LayerTreeImpl::ScrollableViewportSize() const {
return gfx::SizeF();
return gfx::ScaleSize(InnerViewportContainerLayer()->BoundsForScrolling(),
- 1.0f / total_page_scale_factor());
+ 1.0f / current_page_scale_factor());
}
gfx::Rect LayerTreeImpl::RootScrollLayerDeviceViewportBounds() const {
@@ -389,45 +467,28 @@ gfx::Rect LayerTreeImpl::RootScrollLayerDeviceViewportBounds() const {
gfx::Rect(layer->content_bounds()));
}
-static void ApplySentScrollDeltasFromAbortedCommitTo(LayerImpl* layer) {
- layer->ApplySentScrollDeltasFromAbortedCommit();
-}
-
void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit() {
DCHECK(IsActiveTree());
- page_scale_factor_ *= sent_page_scale_delta_;
- page_scale_delta_ /= sent_page_scale_delta_;
- sent_page_scale_delta_ = 1.f;
-
- top_controls_content_offset_ += sent_top_controls_delta_;
- top_controls_delta_ -= sent_top_controls_delta_;
- sent_top_controls_delta_ = 0.f;
-
- if (!root_layer())
- return;
-
- LayerTreeHostCommon::CallFunctionForSubtree(
- root_layer(), base::Bind(&ApplySentScrollDeltasFromAbortedCommitTo));
-}
-
-static void ApplyScrollDeltasSinceBeginMainFrameTo(LayerImpl* layer) {
- layer->ApplyScrollDeltasSinceBeginMainFrame();
-}
+ page_scale_factor()->AbortCommit();
+ top_controls_shown_ratio()->AbortCommit();
+ elastic_overscroll()->AbortCommit();
-void LayerTreeImpl::ApplyScrollDeltasSinceBeginMainFrame() {
- DCHECK(IsPendingTree());
if (!root_layer())
return;
LayerTreeHostCommon::CallFunctionForSubtree(
- root_layer(), base::Bind(&ApplyScrollDeltasSinceBeginMainFrameTo));
+ root_layer(), [](LayerImpl* layer) {
+ layer->ApplySentScrollDeltasFromAbortedCommit();
+ });
}
void LayerTreeImpl::SetViewportLayersFromIds(
+ int overscroll_elasticity_layer_id,
int page_scale_layer_id,
int inner_viewport_scroll_layer_id,
int outer_viewport_scroll_layer_id) {
+ overscroll_elasticity_layer_ = LayerById(overscroll_elasticity_layer_id);
page_scale_layer_ = LayerById(page_scale_layer_id);
DCHECK(page_scale_layer_);
@@ -440,19 +501,7 @@ void LayerTreeImpl::SetViewportLayersFromIds(
DCHECK(outer_viewport_scroll_layer_ ||
outer_viewport_scroll_layer_id == Layer::INVALID_ID);
- if (!root_layer_scroll_offset_delegate_)
- return;
-
- inner_viewport_scroll_delegate_proxy_ = make_scoped_ptr(
- new LayerScrollOffsetDelegateProxy(inner_viewport_scroll_layer_,
- root_layer_scroll_offset_delegate_,
- this));
-
- if (outer_viewport_scroll_layer_)
- outer_viewport_scroll_delegate_proxy_ = make_scoped_ptr(
- new LayerScrollOffsetDelegateProxy(outer_viewport_scroll_layer_,
- root_layer_scroll_offset_delegate_,
- this));
+ HideInnerViewportScrollbarsIfNearMinimumScale();
}
void LayerTreeImpl::ClearViewportLayers() {
@@ -461,27 +510,31 @@ void LayerTreeImpl::ClearViewportLayers() {
outer_viewport_scroll_layer_ = NULL;
}
-bool LayerTreeImpl::UpdateDrawProperties() {
+bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) {
if (!needs_update_draw_properties_)
return true;
- // For max_texture_size.
+ // Calling UpdateDrawProperties must clear this flag, so there can be no
+ // early outs before this.
+ needs_update_draw_properties_ = false;
+
+ // For max_texture_size. When the renderer is re-created in
+ // CreateAndSetRenderer, the needs update draw properties flag is set
+ // again.
if (!layer_tree_host_impl_->renderer())
return false;
+ // Clear this after the renderer early out, as it should still be
+ // possible to hit test even without a renderer.
+ render_surface_layer_list_.clear();
+
if (!root_layer())
return false;
- needs_update_draw_properties_ = false;
- render_surface_layer_list_.clear();
-
{
- TRACE_EVENT2("cc",
- "LayerTreeImpl::UpdateDrawProperties",
- "IsActive",
- IsActiveTree(),
- "SourceFrameNumber",
- source_frame_number_);
+ TRACE_EVENT2(
+ "cc", "LayerTreeImpl::UpdateDrawProperties::CalculateDrawProperties",
+ "IsActive", IsActiveTree(), "SourceFrameNumber", source_frame_number_);
LayerImpl* page_scale_layer =
page_scale_layer_ ? page_scale_layer_ : InnerViewportContainerLayer();
bool can_render_to_separate_surface =
@@ -489,83 +542,133 @@ bool LayerTreeImpl::UpdateDrawProperties() {
DRAW_MODE_RESOURCELESS_SOFTWARE);
++render_surface_layer_list_id_;
+
LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
- root_layer(),
- DrawViewportSize(),
- layer_tree_host_impl_->DrawTransform(),
- device_scale_factor(),
- total_page_scale_factor(),
- page_scale_layer,
- resource_provider()->max_texture_size(),
- settings().can_use_lcd_text,
+ root_layer(), DrawViewportSize(),
+ layer_tree_host_impl_->DrawTransform(), device_scale_factor(),
+ current_page_scale_factor(), page_scale_layer,
+ elastic_overscroll()->Current(IsActiveTree()),
+ overscroll_elasticity_layer_, resource_provider()->max_texture_size(),
+ settings().can_use_lcd_text, settings().layers_always_allowed_lcd_text,
can_render_to_separate_surface,
settings().layer_transforms_should_scale_layer_contents,
- &render_surface_layer_list_,
- render_surface_layer_list_id_);
+ settings().verify_property_trees, &render_surface_layer_list_,
+ render_surface_layer_list_id_, &property_trees_);
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
}
{
- TRACE_EVENT_BEGIN2("cc", "LayerTreeImpl::UpdateTilePriorities", "IsActive",
- IsActiveTree(), "SourceFrameNumber",
- source_frame_number_);
- scoped_ptr<OcclusionTracker<LayerImpl>> occlusion_tracker;
- if (settings().use_occlusion_for_tile_prioritization) {
- occlusion_tracker.reset(new OcclusionTracker<LayerImpl>(
- root_layer()->render_surface()->content_rect()));
- occlusion_tracker->set_minimum_tracking_size(
- settings().minimum_occlusion_tracking_size);
- }
-
- bool resourceless_software_draw = (layer_tree_host_impl_->GetDrawMode() ==
- DRAW_MODE_RESOURCELESS_SOFTWARE);
+ TRACE_EVENT2("cc", "LayerTreeImpl::UpdateDrawProperties::Occlusion",
+ "IsActive", IsActiveTree(), "SourceFrameNumber",
+ source_frame_number_);
+ OcclusionTracker<LayerImpl> occlusion_tracker(
+ root_layer()->render_surface()->content_rect());
+ occlusion_tracker.set_minimum_tracking_size(
+ settings().minimum_occlusion_tracking_size);
// LayerIterator is used here instead of CallFunctionForSubtree to only
// UpdateTilePriorities on layers that will be visible (and thus have valid
// draw properties) and not because any ordering is required.
- typedef LayerIterator<LayerImpl> LayerIteratorType;
- LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list_);
- size_t layers_updated_count = 0;
- for (LayerIteratorType it =
- LayerIteratorType::Begin(&render_surface_layer_list_);
- it != end;
- ++it) {
- if (occlusion_tracker)
- occlusion_tracker->EnterLayer(it);
-
- LayerImpl* layer = *it;
- const Occlusion& occlusion_in_content_space =
- occlusion_tracker ? occlusion_tracker->GetCurrentOcclusionForLayer(
- layer->draw_transform())
- : Occlusion();
+ auto end = LayerIterator<LayerImpl>::End(&render_surface_layer_list_);
+ for (auto it = LayerIterator<LayerImpl>::Begin(&render_surface_layer_list_);
+ it != end; ++it) {
+ occlusion_tracker.EnterLayer(it);
+
+ // There are very few render targets so this should be cheap to do for
+ // each layer instead of something more complicated.
+ bool inside_replica = false;
+ LayerImpl* layer = it->render_target();
+ while (layer && !inside_replica) {
+ if (layer->render_target()->has_replica())
+ inside_replica = true;
+ layer = layer->render_target()->parent();
+ }
+
+ // Don't use occlusion if a layer will appear in a replica, since the
+ // tile raster code does not know how to look for the replica and would
+ // consider it occluded even though the replica is visible.
+ // Since occlusion is only used for browser compositor (i.e.
+ // use_occlusion_for_tile_prioritization) and it won't use replicas,
+ // this should matter not.
if (it.represents_itself()) {
- layer->UpdateTiles(occlusion_in_content_space,
- resourceless_software_draw);
- ++layers_updated_count;
+ Occlusion occlusion =
+ inside_replica ? Occlusion()
+ : occlusion_tracker.GetCurrentOcclusionForLayer(
+ it->draw_transform());
+ it->draw_properties().occlusion_in_content_space = occlusion;
}
- if (!it.represents_contributing_render_surface()) {
- if (occlusion_tracker)
- occlusion_tracker->LeaveLayer(it);
- continue;
+ if (it.represents_contributing_render_surface()) {
+ // Surfaces aren't used by the tile raster code, so they can have
+ // occlusion regardless of replicas.
+ Occlusion occlusion =
+ occlusion_tracker.GetCurrentOcclusionForContributingSurface(
+ it->render_surface()->draw_transform());
+ it->render_surface()->set_occlusion_in_content_space(occlusion);
+ // Masks are used to draw the contributing surface, so should have
+ // the same occlusion as the surface (nothing inside the surface
+ // occludes them).
+ if (LayerImpl* mask = it->mask_layer()) {
+ Occlusion mask_occlusion =
+ inside_replica
+ ? Occlusion()
+ : occlusion_tracker.GetCurrentOcclusionForContributingSurface(
+ it->render_surface()->draw_transform() *
+ it->draw_transform());
+ mask->draw_properties().occlusion_in_content_space = mask_occlusion;
+ }
+ if (LayerImpl* replica = it->replica_layer()) {
+ if (LayerImpl* mask = replica->mask_layer())
+ mask->draw_properties().occlusion_in_content_space = Occlusion();
+ }
}
- if (layer->mask_layer()) {
- layer->mask_layer()->UpdateTiles(occlusion_in_content_space,
- resourceless_software_draw);
- ++layers_updated_count;
- }
- if (layer->replica_layer() && layer->replica_layer()->mask_layer()) {
- layer->replica_layer()->mask_layer()->UpdateTiles(
- occlusion_in_content_space, resourceless_software_draw);
- ++layers_updated_count;
- }
+ occlusion_tracker.LeaveLayer(it);
+ }
- if (occlusion_tracker)
- occlusion_tracker->LeaveLayer(it);
+ unoccluded_screen_space_region_ =
+ occlusion_tracker.ComputeVisibleRegionInScreen();
+ }
+
+ // It'd be ideal if this could be done earlier, but when the raster source
+ // is updated from the main thread during push properties, update draw
+ // properties has not occurred yet and so it's not clear whether or not the
+ // layer can or cannot use lcd text. So, this is the cleanup pass to
+ // determine if the raster source needs to be replaced with a non-lcd
+ // raster source due to draw properties.
+ if (update_lcd_text) {
+ // TODO(enne): Make LTHI::sync_tree return this value.
+ LayerTreeImpl* sync_tree =
+ layer_tree_host_impl_->proxy()->CommitToActiveTree()
+ ? layer_tree_host_impl_->active_tree()
+ : layer_tree_host_impl_->pending_tree();
+ // If this is not the sync tree, then it is not safe to update lcd text
+ // as it causes invalidations and the tiles may be in use.
+ DCHECK_EQ(this, sync_tree);
+ for (const auto& layer : picture_layers_)
+ layer->UpdateCanUseLCDTextAfterCommit();
+ }
+
+ {
+ TRACE_EVENT_BEGIN2("cc", "LayerTreeImpl::UpdateDrawProperties::UpdateTiles",
+ "IsActive", IsActiveTree(), "SourceFrameNumber",
+ source_frame_number_);
+ const bool resourceless_software_draw =
+ (layer_tree_host_impl_->GetDrawMode() ==
+ DRAW_MODE_RESOURCELESS_SOFTWARE);
+ size_t layers_updated_count = 0;
+ bool tile_priorities_updated = false;
+ for (PictureLayerImpl* layer : picture_layers_) {
+ if (!layer->IsDrawnRenderSurfaceLayerListMember())
+ continue;
+ ++layers_updated_count;
+ tile_priorities_updated |= layer->UpdateTiles(resourceless_software_draw);
}
+ if (tile_priorities_updated)
+ DidModifyTilePriorities();
+
TRACE_EVENT_END1("cc", "LayerTreeImpl::UpdateTilePriorities",
"layers_updated_count", layers_updated_count);
}
@@ -581,6 +684,13 @@ const LayerImplList& LayerTreeImpl::RenderSurfaceLayerList() const {
return render_surface_layer_list_;
}
+const Region& LayerTreeImpl::UnoccludedScreenSpaceRegion() const {
+ // If this assert triggers, then the render_surface_layer_list_ is dirty, so
+ // the unoccluded_screen_space_region_ is not valid anymore.
+ DCHECK(!needs_update_draw_properties_);
+ return unoccluded_screen_space_region_;
+}
+
gfx::Size LayerTreeImpl::ScrollableSize() const {
LayerImpl* root_scroll_layer = OuterViewportScrollLayer()
? OuterViewportScrollLayer()
@@ -615,17 +725,6 @@ void LayerTreeImpl::PushPersistedState(LayerTreeImpl* pending_tree) {
currently_scrolling_layer_ ? currently_scrolling_layer_->id() : 0));
}
-static void DidBecomeActiveRecursive(LayerImpl* layer) {
- layer->DidBecomeActive();
- if (layer->mask_layer())
- layer->mask_layer()->DidBecomeActive();
- if (layer->replica_layer() && layer->replica_layer()->mask_layer())
- layer->replica_layer()->mask_layer()->DidBecomeActive();
-
- for (size_t i = 0; i < layer->children().size(); ++i)
- DidBecomeActiveRecursive(layer->children()[i]);
-}
-
void LayerTreeImpl::DidBecomeActive() {
if (next_activation_forces_redraw_) {
layer_tree_host_impl_->SetFullRootLayerDamage();
@@ -641,9 +740,13 @@ void LayerTreeImpl::DidBecomeActive() {
// if we were in a good state.
layer_tree_host_impl_->ResetRequiresHighResToDraw();
- if (root_layer())
- DidBecomeActiveRecursive(root_layer());
+ if (root_layer()) {
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ root_layer(), [](LayerImpl* layer) { layer->DidBecomeActive(); });
+ }
+ for (auto* swap_promise : swap_promise_list_)
+ swap_promise->DidActivate();
devtools_instrumentation::DidActivateLayerTree(layer_tree_host_impl_->id(),
source_frame_number_);
}
@@ -692,6 +795,10 @@ const LayerTreeSettings& LayerTreeImpl::settings() const {
return layer_tree_host_impl_->settings();
}
+const LayerTreeDebugState& LayerTreeImpl::debug_state() const {
+ return layer_tree_host_impl_->debug_state();
+}
+
const RendererCapabilitiesImpl& LayerTreeImpl::GetRendererCapabilities() const {
return layer_tree_host_impl_->GetRendererCapabilities();
}
@@ -728,6 +835,14 @@ gfx::Size LayerTreeImpl::device_viewport_size() const {
return layer_tree_host_impl_->device_viewport_size();
}
+float LayerTreeImpl::device_scale_factor() const {
+ return layer_tree_host_impl_->device_scale_factor();
+}
+
+DebugRectHistory* LayerTreeImpl::debug_rect_history() const {
+ return layer_tree_host_impl_->debug_rect_history();
+}
+
bool LayerTreeImpl::IsActiveTree() const {
return layer_tree_host_impl_->active_tree() == this;
}
@@ -740,6 +855,10 @@ bool LayerTreeImpl::IsRecycleTree() const {
return layer_tree_host_impl_->recycle_tree() == this;
}
+bool LayerTreeImpl::IsSyncTree() const {
+ return layer_tree_host_impl_->sync_tree() == this;
+}
+
LayerImpl* LayerTreeImpl::FindActiveTreeLayerById(int id) {
LayerTreeImpl* tree = layer_tree_host_impl_->active_tree();
if (!tree)
@@ -793,7 +912,7 @@ LayerTreeImpl::CreateScrollbarAnimationController(LayerImpl* scrolling_layer) {
base::TimeDelta duration =
base::TimeDelta::FromMilliseconds(settings().scrollbar_fade_duration_ms);
switch (settings().scrollbar_animator) {
- case LayerTreeSettings::LinearFade: {
+ case LayerTreeSettings::LINEAR_FADE: {
return ScrollbarAnimationControllerLinearFade::Create(
scrolling_layer,
layer_tree_host_impl_,
@@ -801,14 +920,14 @@ LayerTreeImpl::CreateScrollbarAnimationController(LayerImpl* scrolling_layer) {
resize_delay,
duration);
}
- case LayerTreeSettings::Thinning: {
+ case LayerTreeSettings::THINNING: {
return ScrollbarAnimationControllerThinning::Create(scrolling_layer,
layer_tree_host_impl_,
delay,
resize_delay,
duration);
}
- case LayerTreeSettings::NoAnimator:
+ case LayerTreeSettings::NO_ANIMATOR:
NOTREACHED();
break;
}
@@ -823,6 +942,10 @@ bool LayerTreeImpl::use_gpu_rasterization() const {
return layer_tree_host_impl_->use_gpu_rasterization();
}
+GpuRasterizationStatus LayerTreeImpl::GetGpuRasterizationStatus() const {
+ return layer_tree_host_impl_->gpu_rasterization_status();
+}
+
bool LayerTreeImpl::create_low_res_tiling() const {
return layer_tree_host_impl_->create_low_res_tiling();
}
@@ -831,23 +954,12 @@ void LayerTreeImpl::SetNeedsRedraw() {
layer_tree_host_impl_->SetNeedsRedraw();
}
-const LayerTreeDebugState& LayerTreeImpl::debug_state() const {
- return layer_tree_host_impl_->debug_state();
-}
-
-float LayerTreeImpl::device_scale_factor() const {
- return layer_tree_host_impl_->device_scale_factor();
-}
-
-DebugRectHistory* LayerTreeImpl::debug_rect_history() const {
- return layer_tree_host_impl_->debug_rect_history();
-}
-
-AnimationRegistrar* LayerTreeImpl::animationRegistrar() const {
+AnimationRegistrar* LayerTreeImpl::GetAnimationRegistrar() const {
return layer_tree_host_impl_->animation_registrar();
}
-void LayerTreeImpl::GetAllTilesForTracing(std::set<const Tile*>* tiles) const {
+void LayerTreeImpl::GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const {
typedef LayerIterator<LayerImpl> LayerIteratorType;
LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list_);
for (LayerIteratorType it =
@@ -857,11 +969,11 @@ void LayerTreeImpl::GetAllTilesForTracing(std::set<const Tile*>* tiles) const {
if (!it.represents_itself())
continue;
LayerImpl* layer_impl = *it;
- layer_impl->GetAllTilesForTracing(tiles);
+ layer_impl->GetAllPrioritizedTilesForTracing(prioritized_tiles);
}
}
-void LayerTreeImpl::AsValueInto(base::debug::TracedValue* state) const {
+void LayerTreeImpl::AsValueInto(base::trace_event::TracedValue* state) const {
TracedValue::MakeDictIntoImplicitSnapshot(state, "cc::LayerTreeImpl", this);
state->SetInteger("source_frame_number", source_frame_number_);
@@ -881,8 +993,8 @@ void LayerTreeImpl::AsValueInto(base::debug::TracedValue* state) const {
state->EndArray();
state->BeginArray("swap_promise_trace_ids");
- for (size_t i = 0; i < swap_promise_list_.size(); i++)
- state->AppendDouble(swap_promise_list_[i]->TraceId());
+ for (auto* swap_promise : swap_promise_list_)
+ state->AppendDouble(swap_promise->TraceId());
state->EndArray();
}
@@ -891,119 +1003,69 @@ void LayerTreeImpl::SetRootLayerScrollOffsetDelegate(
if (root_layer_scroll_offset_delegate_ == root_layer_scroll_offset_delegate)
return;
- if (!root_layer_scroll_offset_delegate) {
- // Make sure we remove the proxies from their layers before
- // releasing them.
- if (InnerViewportScrollLayer())
- InnerViewportScrollLayer()->SetScrollOffsetDelegate(NULL);
- if (OuterViewportScrollLayer())
- OuterViewportScrollLayer()->SetScrollOffsetDelegate(NULL);
- inner_viewport_scroll_delegate_proxy_ = nullptr;
- outer_viewport_scroll_delegate_proxy_ = nullptr;
- }
-
root_layer_scroll_offset_delegate_ = root_layer_scroll_offset_delegate;
if (root_layer_scroll_offset_delegate_) {
root_layer_scroll_offset_delegate_->UpdateRootLayerState(
- TotalScrollOffset(),
- TotalMaxScrollOffset(),
- ScrollableSize(),
- total_page_scale_factor(),
- min_page_scale_factor(),
+ TotalScrollOffset(), TotalMaxScrollOffset(), ScrollableSize(),
+ current_page_scale_factor(), min_page_scale_factor(),
max_page_scale_factor());
- if (inner_viewport_scroll_layer_) {
- inner_viewport_scroll_delegate_proxy_ = make_scoped_ptr(
- new LayerScrollOffsetDelegateProxy(InnerViewportScrollLayer(),
- root_layer_scroll_offset_delegate_,
- this));
- inner_viewport_scroll_layer_->SetScrollOffsetDelegate(
- inner_viewport_scroll_delegate_proxy_.get());
- }
-
- if (outer_viewport_scroll_layer_) {
- outer_viewport_scroll_delegate_proxy_ = make_scoped_ptr(
- new LayerScrollOffsetDelegateProxy(OuterViewportScrollLayer(),
- root_layer_scroll_offset_delegate_,
- this));
- outer_viewport_scroll_layer_->SetScrollOffsetDelegate(
- outer_viewport_scroll_delegate_proxy_.get());
- }
-
- if (inner_viewport_scroll_layer_)
- UpdateScrollOffsetDelegate();
- }
-}
-
-void LayerTreeImpl::OnRootLayerDelegatedScrollOffsetChanged() {
- DCHECK(root_layer_scroll_offset_delegate_);
- if (inner_viewport_scroll_layer_) {
- inner_viewport_scroll_layer_->DidScroll();
- }
- if (outer_viewport_scroll_layer_) {
- outer_viewport_scroll_layer_->DidScroll();
+ DistributeRootScrollOffset();
}
}
-void LayerTreeImpl::UpdateScrollOffsetDelegate() {
- DCHECK(InnerViewportScrollLayer());
- DCHECK(!OuterViewportScrollLayer() || outer_viewport_scroll_delegate_proxy_);
+void LayerTreeImpl::UpdateRootScrollOffsetDelegate() {
DCHECK(root_layer_scroll_offset_delegate_);
- gfx::ScrollOffset offset =
- inner_viewport_scroll_delegate_proxy_->last_set_scroll_offset();
+ gfx::ScrollOffset offset = InnerViewportScrollLayer()->CurrentScrollOffset();
if (OuterViewportScrollLayer())
- offset += outer_viewport_scroll_delegate_proxy_->last_set_scroll_offset();
+ offset += OuterViewportScrollLayer()->CurrentScrollOffset();
root_layer_scroll_offset_delegate_->UpdateRootLayerState(
- offset,
- TotalMaxScrollOffset(),
- ScrollableSize(),
- total_page_scale_factor(),
- min_page_scale_factor(),
+ offset, TotalMaxScrollOffset(), ScrollableSize(),
+ current_page_scale_factor(), min_page_scale_factor(),
max_page_scale_factor());
}
-gfx::ScrollOffset LayerTreeImpl::GetDelegatedScrollOffset(LayerImpl* layer) {
- DCHECK(root_layer_scroll_offset_delegate_);
- DCHECK(InnerViewportScrollLayer());
- if (layer == InnerViewportScrollLayer() && !OuterViewportScrollLayer())
- return root_layer_scroll_offset_delegate_->GetTotalScrollOffset();
+void LayerTreeImpl::DistributeRootScrollOffset() {
+ if (!root_layer_scroll_offset_delegate_)
+ return;
+
+ gfx::ScrollOffset root_offset =
+ root_layer_scroll_offset_delegate_->GetTotalScrollOffset();
+
+ if (!InnerViewportScrollLayer())
+ return;
+
+ DCHECK(OuterViewportScrollLayer());
// If we get here, we have both inner/outer viewports, and need to distribute
// the scroll offset between them.
- DCHECK(inner_viewport_scroll_delegate_proxy_);
- DCHECK(outer_viewport_scroll_delegate_proxy_);
gfx::ScrollOffset inner_viewport_offset =
- inner_viewport_scroll_delegate_proxy_->last_set_scroll_offset();
+ InnerViewportScrollLayer()->CurrentScrollOffset();
gfx::ScrollOffset outer_viewport_offset =
- outer_viewport_scroll_delegate_proxy_->last_set_scroll_offset();
+ OuterViewportScrollLayer()->CurrentScrollOffset();
// It may be nothing has changed.
- gfx::ScrollOffset delegate_offset =
- root_layer_scroll_offset_delegate_->GetTotalScrollOffset();
- if (inner_viewport_offset + outer_viewport_offset == delegate_offset) {
- if (layer == InnerViewportScrollLayer())
- return inner_viewport_offset;
- else
- return outer_viewport_offset;
- }
+ if (inner_viewport_offset + outer_viewport_offset == root_offset)
+ return;
gfx::ScrollOffset max_outer_viewport_scroll_offset =
OuterViewportScrollLayer()->MaxScrollOffset();
- outer_viewport_offset = delegate_offset - inner_viewport_offset;
+ outer_viewport_offset = root_offset - inner_viewport_offset;
outer_viewport_offset.SetToMin(max_outer_viewport_scroll_offset);
outer_viewport_offset.SetToMax(gfx::ScrollOffset());
- if (layer == OuterViewportScrollLayer())
- return outer_viewport_offset;
-
- inner_viewport_offset = delegate_offset - outer_viewport_offset;
+ OuterViewportScrollLayer()->SetCurrentScrollOffsetFromDelegate(
+ outer_viewport_offset);
+ inner_viewport_offset = root_offset - outer_viewport_offset;
+ InnerViewportScrollLayer()->SetCurrentScrollOffsetFromDelegate(
+ inner_viewport_offset);
- return inner_viewport_offset;
+ UpdateRootScrollOffsetDelegate();
}
void LayerTreeImpl::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) {
@@ -1013,20 +1075,20 @@ void LayerTreeImpl::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) {
void LayerTreeImpl::PassSwapPromises(
ScopedPtrVector<SwapPromise>* new_swap_promise) {
- swap_promise_list_.insert_and_take(swap_promise_list_.end(),
- new_swap_promise);
- new_swap_promise->clear();
+ // Any left over promises have failed to swap before the next frame.
+ BreakSwapPromises(SwapPromise::SWAP_FAILS);
+ swap_promise_list_.swap(*new_swap_promise);
}
void LayerTreeImpl::FinishSwapPromises(CompositorFrameMetadata* metadata) {
- for (size_t i = 0; i < swap_promise_list_.size(); i++)
- swap_promise_list_[i]->DidSwap(metadata);
+ for (auto* swap_promise : swap_promise_list_)
+ swap_promise->DidSwap(metadata);
swap_promise_list_.clear();
}
void LayerTreeImpl::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) {
- for (size_t i = 0; i < swap_promise_list_.size(); i++)
- swap_promise_list_[i]->DidNotSwap(reason);
+ for (auto* swap_promise : swap_promise_list_)
+ swap_promise->DidNotSwap(reason);
swap_promise_list_.clear();
}
@@ -1049,22 +1111,20 @@ bool LayerTreeImpl::IsUIResourceOpaque(UIResourceId uid) const {
}
void LayerTreeImpl::ProcessUIResourceRequestQueue() {
- while (ui_resource_request_queue_.size() > 0) {
- UIResourceRequest req = ui_resource_request_queue_.front();
- ui_resource_request_queue_.pop_front();
-
+ for (const auto& req : ui_resource_request_queue_) {
switch (req.GetType()) {
- case UIResourceRequest::UIResourceCreate:
+ case UIResourceRequest::UI_RESOURCE_CREATE:
layer_tree_host_impl_->CreateUIResource(req.GetId(), req.GetBitmap());
break;
- case UIResourceRequest::UIResourceDelete:
+ case UIResourceRequest::UI_RESOURCE_DELETE:
layer_tree_host_impl_->DeleteUIResource(req.GetId());
break;
- case UIResourceRequest::UIResourceInvalidRequest:
+ case UIResourceRequest::UI_RESOURCE_INVALID_REQUEST:
NOTREACHED();
break;
}
}
+ ui_resource_request_queue_.clear();
// If all UI resource evictions were not recreated by processing this queue,
// then another commit is required.
@@ -1072,6 +1132,19 @@ void LayerTreeImpl::ProcessUIResourceRequestQueue() {
layer_tree_host_impl_->SetNeedsCommit();
}
+void LayerTreeImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
+ DCHECK(std::find(picture_layers_.begin(), picture_layers_.end(), layer) ==
+ picture_layers_.end());
+ picture_layers_.push_back(layer);
+}
+
+void LayerTreeImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
+ std::vector<PictureLayerImpl*>::iterator it =
+ std::find(picture_layers_.begin(), picture_layers_.end(), layer);
+ DCHECK(it != picture_layers_.end());
+ picture_layers_.erase(it);
+}
+
void LayerTreeImpl::AddLayerWithCopyOutputRequest(LayerImpl* layer) {
// Only the active tree needs to know about layers with copy requests, as
// they are aborted if not serviced during draw.
@@ -1116,17 +1189,6 @@ const std::vector<LayerImpl*>& LayerTreeImpl::LayersWithCopyOutputRequest()
return layers_with_copy_output_request_;
}
-void LayerTreeImpl::ReleaseResourcesRecursive(LayerImpl* current) {
- DCHECK(current);
- current->ReleaseResources();
- if (current->mask_layer())
- ReleaseResourcesRecursive(current->mask_layer());
- if (current->replica_layer())
- ReleaseResourcesRecursive(current->replica_layer());
- for (size_t i = 0; i < current->children().size(); ++i)
- ReleaseResourcesRecursive(current->children()[i]);
-}
-
template <typename LayerType>
static inline bool LayerClipsSubtree(LayerType* layer) {
return layer->masks_to_bounds() || layer->mask_layer();
@@ -1296,15 +1358,16 @@ static void FindClosestMatchingLayer(
static bool ScrollsAnyDrawnRenderSurfaceLayerListMember(LayerImpl* layer) {
if (!layer->scrollable())
return false;
- if (layer->IsDrawnRenderSurfaceLayerListMember())
+ if (layer->draw_properties().layer_or_descendant_is_drawn)
return true;
+
if (!layer->scroll_children())
return false;
for (std::set<LayerImpl*>::const_iterator it =
layer->scroll_children()->begin();
it != layer->scroll_children()->end();
++it) {
- if ((*it)->IsDrawnRenderSurfaceLayerListMember())
+ if ((*it)->draw_properties().layer_or_descendant_is_drawn)
return true;
}
return false;
@@ -1339,7 +1402,8 @@ LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPoint(
const gfx::PointF& screen_space_point) {
if (!root_layer())
return NULL;
- if (!UpdateDrawProperties())
+ bool update_lcd_text = false;
+ if (!UpdateDrawProperties(update_lcd_text))
return NULL;
FindClosestMatchingLayerDataForRecursion data_for_recursion;
FindClosestMatchingLayer(screen_space_point,
@@ -1371,6 +1435,26 @@ static bool LayerHasTouchEventHandlersAt(const gfx::PointF& screen_space_point,
return true;
}
+struct FindWheelEventLayerFunctor {
+ bool operator()(LayerImpl* layer) const {
+ return layer->have_wheel_event_handlers();
+ }
+};
+
+LayerImpl* LayerTreeImpl::FindLayerWithWheelHandlerThatIsHitByPoint(
+ const gfx::PointF& screen_space_point) {
+ if (!root_layer())
+ return NULL;
+ bool update_lcd_text = false;
+ if (!UpdateDrawProperties(update_lcd_text))
+ return NULL;
+ FindWheelEventLayerFunctor func;
+ FindClosestMatchingLayerDataForRecursion data_for_recursion;
+ FindClosestMatchingLayer(screen_space_point, root_layer(), func,
+ &data_for_recursion);
+ return data_for_recursion.closest_match;
+}
+
struct FindTouchEventLayerFunctor {
bool operator()(LayerImpl* layer) const {
return LayerHasTouchEventHandlersAt(screen_space_point, layer);
@@ -1382,7 +1466,8 @@ LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion(
const gfx::PointF& screen_space_point) {
if (!root_layer())
return NULL;
- if (!UpdateDrawProperties())
+ bool update_lcd_text = false;
+ if (!UpdateDrawProperties(update_lcd_text))
return NULL;
FindTouchEventLayerFunctor func = {screen_space_point};
FindClosestMatchingLayerDataForRecursion data_for_recursion;
@@ -1391,13 +1476,11 @@ LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion(
return data_for_recursion.closest_match;
}
-void LayerTreeImpl::RegisterSelection(const LayerSelectionBound& start,
- const LayerSelectionBound& end) {
- selection_start_ = start;
- selection_end_ = end;
+void LayerTreeImpl::RegisterSelection(const LayerSelection& selection) {
+ selection_ = selection;
}
-static ViewportSelectionBound ComputeViewportSelection(
+static ViewportSelectionBound ComputeViewportSelectionBound(
const LayerSelectionBound& layer_bound,
LayerImpl* layer,
float device_scale_factor) {
@@ -1444,34 +1527,26 @@ static ViewportSelectionBound ComputeViewportSelection(
return viewport_bound;
}
-void LayerTreeImpl::GetViewportSelection(ViewportSelectionBound* start,
- ViewportSelectionBound* end) {
- DCHECK(start);
- DCHECK(end);
+void LayerTreeImpl::GetViewportSelection(ViewportSelection* selection) {
+ DCHECK(selection);
- *start = ComputeViewportSelection(
- selection_start_,
- selection_start_.layer_id ? LayerById(selection_start_.layer_id) : NULL,
+ selection->start = ComputeViewportSelectionBound(
+ selection_.start,
+ selection_.start.layer_id ? LayerById(selection_.start.layer_id) : NULL,
device_scale_factor());
- if (start->type == SELECTION_BOUND_CENTER ||
- start->type == SELECTION_BOUND_EMPTY) {
- *end = *start;
+ selection->is_editable = selection_.is_editable;
+ selection->is_empty_text_form_control = selection_.is_empty_text_form_control;
+ if (selection->start.type == SELECTION_BOUND_CENTER ||
+ selection->start.type == SELECTION_BOUND_EMPTY) {
+ selection->end = selection->start;
} else {
- *end = ComputeViewportSelection(
- selection_end_,
- selection_end_.layer_id ? LayerById(selection_end_.layer_id) : NULL,
+ selection->end = ComputeViewportSelectionBound(
+ selection_.end,
+ selection_.end.layer_id ? LayerById(selection_.end.layer_id) : NULL,
device_scale_factor());
}
}
-void LayerTreeImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
- layer_tree_host_impl_->RegisterPictureLayerImpl(layer);
-}
-
-void LayerTreeImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
- layer_tree_host_impl_->UnregisterPictureLayerImpl(layer);
-}
-
void LayerTreeImpl::InputScrollAnimationFinished() {
layer_tree_host_impl_->ScrollEnd();
}
@@ -1484,45 +1559,19 @@ BlockingTaskRunner* LayerTreeImpl::BlockingMainThreadTaskRunner() const {
return proxy()->blocking_main_thread_task_runner();
}
-void LayerTreeImpl::SetPageScaleAnimation(
- const gfx::Vector2d& target_offset,
- bool anchor_point,
- float page_scale,
- base::TimeDelta duration) {
- if (!InnerViewportScrollLayer())
- return;
+VideoFrameControllerClient* LayerTreeImpl::GetVideoFrameControllerClient()
+ const {
+ return layer_tree_host_impl_;
+}
- gfx::ScrollOffset scroll_total = TotalScrollOffset();
- gfx::SizeF scaled_scrollable_size = ScrollableSize();
- gfx::SizeF viewport_size = InnerViewportContainerLayer()->bounds();
-
- // Easing constants experimentally determined.
- scoped_ptr<TimingFunction> timing_function =
- CubicBezierTimingFunction::Create(.8, 0, .3, .9);
-
- // TODO(miletus) : Pass in ScrollOffset.
- page_scale_animation_ =
- PageScaleAnimation::Create(ScrollOffsetToVector2dF(scroll_total),
- total_page_scale_factor(),
- viewport_size,
- scaled_scrollable_size,
- timing_function.Pass());
-
- if (anchor_point) {
- gfx::Vector2dF anchor(target_offset);
- page_scale_animation_->ZoomWithAnchor(anchor,
- page_scale,
- duration.InSecondsF());
- } else {
- gfx::Vector2dF scaled_target_offset = target_offset;
- page_scale_animation_->ZoomTo(scaled_target_offset,
- page_scale,
- duration.InSecondsF());
- }
+void LayerTreeImpl::SetPendingPageScaleAnimation(
+ scoped_ptr<PendingPageScaleAnimation> pending_animation) {
+ pending_page_scale_animation_ = pending_animation.Pass();
}
-scoped_ptr<PageScaleAnimation> LayerTreeImpl::TakePageScaleAnimation() {
- return page_scale_animation_.Pass();
+scoped_ptr<PendingPageScaleAnimation>
+ LayerTreeImpl::TakePendingPageScaleAnimation() {
+ return pending_page_scale_animation_.Pass();
}
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index 57e6ca129ca..9c1b5b942db 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -5,7 +5,6 @@
#ifndef CC_TREES_LAYER_TREE_IMPL_H_
#define CC_TREES_LAYER_TREE_IMPL_H_
-#include <list>
#include <set>
#include <string>
#include <vector>
@@ -13,13 +12,18 @@
#include "base/containers/hash_tables.h"
#include "base/values.h"
#include "cc/base/scoped_ptr_vector.h"
-#include "cc/base/swap_promise.h"
+#include "cc/base/synced_property.h"
+#include "cc/input/layer_selection_bound.h"
#include "cc/layers/layer_impl.h"
+#include "cc/output/begin_frame_args.h"
#include "cc/output/renderer.h"
+#include "cc/output/swap_promise.h"
#include "cc/resources/ui_resource_client.h"
+#include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/property_tree.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
}
@@ -30,9 +34,9 @@ class ContextProvider;
class DebugRectHistory;
class FrameRateCounter;
class HeadsUpDisplayLayerImpl;
-class LayerScrollOffsetDelegateProxy;
+class LayerExternalScrollOffsetListener;
+class LayerScrollOffsetDelegate;
class LayerTreeDebugState;
-class LayerTreeHostImpl;
class LayerTreeImpl;
class LayerTreeSettings;
class MemoryHistory;
@@ -44,25 +48,35 @@ class Proxy;
class ResourceProvider;
class TileManager;
class UIResourceRequest;
+class VideoFrameControllerClient;
+struct PendingPageScaleAnimation;
struct RendererCapabilities;
-struct SelectionHandle;
-typedef std::list<UIResourceRequest> UIResourceRequestQueue;
+typedef std::vector<UIResourceRequest> UIResourceRequestQueue;
+typedef SyncedProperty<AdditionGroup<float>> SyncedTopControls;
+typedef SyncedProperty<AdditionGroup<gfx::Vector2dF>> SyncedElasticOverscroll;
class CC_EXPORT LayerTreeImpl {
public:
static scoped_ptr<LayerTreeImpl> create(
- LayerTreeHostImpl* layer_tree_host_impl) {
- return make_scoped_ptr(new LayerTreeImpl(layer_tree_host_impl));
+ LayerTreeHostImpl* layer_tree_host_impl,
+ scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
+ scoped_refptr<SyncedTopControls> top_controls_shown_ratio,
+ scoped_refptr<SyncedElasticOverscroll> elastic_overscroll) {
+ return make_scoped_ptr(
+ new LayerTreeImpl(layer_tree_host_impl, page_scale_factor,
+ top_controls_shown_ratio, elastic_overscroll));
}
virtual ~LayerTreeImpl();
void Shutdown();
void ReleaseResources();
+ void RecreateResources();
// Methods called by the layer tree that pass-through or access LTHI.
// ---------------------------------------------------------------------------
const LayerTreeSettings& settings() const;
+ const LayerTreeDebugState& debug_state() const;
const RendererCapabilitiesImpl& GetRendererCapabilities() const;
ContextProvider* context_provider() const;
OutputSurface* output_surface() const;
@@ -72,9 +86,12 @@ class CC_EXPORT LayerTreeImpl {
PaintTimeCounter* paint_time_counter() const;
MemoryHistory* memory_history() const;
gfx::Size device_viewport_size() const;
+ float device_scale_factor() const;
+ DebugRectHistory* debug_rect_history() const;
bool IsActiveTree() const;
bool IsPendingTree() const;
bool IsRecycleTree() const;
+ bool IsSyncTree() const;
LayerImpl* FindActiveTreeLayerById(int id);
LayerImpl* FindPendingTreeLayerById(int id);
bool PinchGestureActive() const;
@@ -89,22 +106,22 @@ class CC_EXPORT LayerTreeImpl {
void DidAnimateScrollOffset();
void InputScrollAnimationFinished();
bool use_gpu_rasterization() const;
+ GpuRasterizationStatus GetGpuRasterizationStatus() const;
bool create_low_res_tiling() const;
BlockingTaskRunner* BlockingMainThreadTaskRunner() const;
bool RequiresHighResToDraw() const;
bool SmoothnessTakesPriority() const;
+ VideoFrameControllerClient* GetVideoFrameControllerClient() const;
// Tree specific methods exposed to layer-impl tree.
// ---------------------------------------------------------------------------
void SetNeedsRedraw();
- // TODO(nduca): These are implemented in cc files temporarily, but will become
- // trivial accessors in a followup patch.
- const LayerTreeDebugState& debug_state() const;
- float device_scale_factor() const;
- DebugRectHistory* debug_rect_history() const;
- void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
- void AsValueInto(base::debug::TracedValue* dict) const;
+ // Tracing methods.
+ // ---------------------------------------------------------------------------
+ void GetAllPrioritizedTilesForTracing(
+ std::vector<PrioritizedTile>* prioritized_tiles) const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
// Other public methods
// ---------------------------------------------------------------------------
@@ -112,6 +129,10 @@ class CC_EXPORT LayerTreeImpl {
void SetRootLayer(scoped_ptr<LayerImpl>);
scoped_ptr<LayerImpl> DetachLayerTree();
+ void SetPropertyTrees(const PropertyTrees& property_trees) {
+ property_trees_ = property_trees;
+ }
+
void PushPropertiesTo(LayerTreeImpl* tree_impl);
int source_frame_number() const { return source_frame_number_; }
@@ -129,7 +150,6 @@ class CC_EXPORT LayerTreeImpl {
LayerImpl* OuterViewportScrollLayer() const;
gfx::ScrollOffset TotalScrollOffset() const;
gfx::ScrollOffset TotalMaxScrollOffset() const;
- gfx::Vector2dF TotalScrollDelta() const;
LayerImpl* InnerViewportContainerLayer() const;
LayerImpl* OuterViewportContainerLayer() const;
@@ -137,13 +157,16 @@ class CC_EXPORT LayerTreeImpl {
void SetCurrentlyScrollingLayer(LayerImpl* layer);
void ClearCurrentlyScrollingLayer();
- void SetViewportLayersFromIds(int page_scale_layer_id,
+ void SetViewportLayersFromIds(int overscroll_elasticity_layer,
+ int page_scale_layer_id,
int inner_viewport_scroll_layer_id,
int outer_viewport_scroll_layer_id);
void ClearViewportLayers();
+ LayerImpl* overscroll_elasticity_layer() {
+ return overscroll_elasticity_layer_;
+ }
LayerImpl* page_scale_layer() { return page_scale_layer_; }
void ApplySentScrollAndScaleDeltasFromAbortedCommit();
- void ApplyScrollDeltasSinceBeginMainFrame();
SkColor background_color() const { return background_color_; }
void set_background_color(SkColor color) { background_color_ = color; }
@@ -155,27 +178,39 @@ class CC_EXPORT LayerTreeImpl {
has_transparent_background_ = transparent;
}
- void SetPageScaleFactorAndLimits(float page_scale_factor,
- float min_page_scale_factor, float max_page_scale_factor);
- void SetPageScaleDelta(float delta);
- void SetPageScaleValues(float page_scale_factor,
- float min_page_scale_factor, float max_page_scale_factor,
- float page_scale_delta);
- float total_page_scale_factor() const {
- return page_scale_factor_ * page_scale_delta_;
+ void SetPageScaleOnActiveTree(float active_page_scale);
+ void PushPageScaleFromMainThread(float page_scale_factor,
+ float min_page_scale_factor,
+ float max_page_scale_factor);
+ float current_page_scale_factor() const {
+ return page_scale_factor()->Current(IsActiveTree());
}
- float page_scale_factor() const { return page_scale_factor_; }
float min_page_scale_factor() const { return min_page_scale_factor_; }
float max_page_scale_factor() const { return max_page_scale_factor_; }
- float page_scale_delta() const { return page_scale_delta_; }
- void set_sent_page_scale_delta(float delta) {
- sent_page_scale_delta_ = delta;
+
+ float page_scale_delta() const { return page_scale_factor()->Delta(); }
+
+ SyncedProperty<ScaleGroup>* page_scale_factor();
+ const SyncedProperty<ScaleGroup>* page_scale_factor() const;
+
+ SyncedElasticOverscroll* elastic_overscroll() {
+ return elastic_overscroll_.get();
+ }
+ const SyncedElasticOverscroll* elastic_overscroll() const {
+ return elastic_overscroll_.get();
+ }
+
+ SyncedTopControls* top_controls_shown_ratio() {
+ return top_controls_shown_ratio_.get();
+ }
+ const SyncedTopControls* top_controls_shown_ratio() const {
+ return top_controls_shown_ratio_.get();
}
- float sent_page_scale_delta() const { return sent_page_scale_delta_; }
// Updates draw properties and render surface layer list, as well as tile
- // priorities. Returns false if it was unable to update.
- bool UpdateDrawProperties();
+ // priorities. Returns false if it was unable to update. Updating lcd
+ // text may cause invalidations, so should only be done after a commit.
+ bool UpdateDrawProperties(bool update_lcd_text);
void set_needs_update_draw_properties() {
needs_update_draw_properties_ = true;
@@ -197,6 +232,7 @@ class CC_EXPORT LayerTreeImpl {
void set_ui_resource_request_queue(const UIResourceRequestQueue& queue);
const LayerImplList& RenderSurfaceLayerList() const;
+ const Region& UnoccludedScreenSpaceRegion() const;
// These return the size of the root scrollable area and the size of
// the user-visible scrolling viewport, in CSS layout coordinates.
@@ -213,7 +249,7 @@ class CC_EXPORT LayerTreeImpl {
size_t NumLayers();
- AnimationRegistrar* animationRegistrar() const;
+ AnimationRegistrar* GetAnimationRegistrar() const;
void PushPersistedState(LayerTreeImpl* pending_tree);
@@ -234,9 +270,10 @@ class CC_EXPORT LayerTreeImpl {
void SetRootLayerScrollOffsetDelegate(
LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate);
- void OnRootLayerDelegatedScrollOffsetChanged();
- void UpdateScrollOffsetDelegate();
- gfx::ScrollOffset GetDelegatedScrollOffset(LayerImpl* layer);
+ void UpdateRootScrollOffsetDelegate();
+ // Distribute the rool scroll between outer and inner viewport scroll layer.
+ // The outer viewport scroll layer scrolls first.
+ void DistributeRootScrollOffset();
// Call this function when you expect there to be a swap buffer.
// See swap_promise.h for how to use SwapPromise.
@@ -254,6 +291,12 @@ class CC_EXPORT LayerTreeImpl {
bool IsUIResourceOpaque(UIResourceId uid) const;
+ void RegisterPictureLayerImpl(PictureLayerImpl* layer);
+ void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
+ const std::vector<PictureLayerImpl*>& picture_layers() const {
+ return picture_layers_;
+ }
+
void AddLayerWithCopyOutputRequest(LayerImpl* layer);
void RemoveLayerWithCopyOutputRequest(LayerImpl* layer);
const std::vector<LayerImpl*>& LayersWithCopyOutputRequest() const;
@@ -267,89 +310,81 @@ class CC_EXPORT LayerTreeImpl {
LayerImpl* FindLayerThatIsHitByPoint(const gfx::PointF& screen_space_point);
+ LayerImpl* FindLayerWithWheelHandlerThatIsHitByPoint(
+ const gfx::PointF& screen_space_point);
+
LayerImpl* FindLayerThatIsHitByPointInTouchHandlerRegion(
const gfx::PointF& screen_space_point);
- void RegisterSelection(const LayerSelectionBound& start,
- const LayerSelectionBound& end);
+ void RegisterSelection(const LayerSelection& selection);
// Compute the current selection handle location and visbility with respect to
// the viewport.
- void GetViewportSelection(ViewportSelectionBound* start,
- ViewportSelectionBound* end);
+ void GetViewportSelection(ViewportSelection* selection);
- void RegisterPictureLayerImpl(PictureLayerImpl* layer);
- void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
-
- void set_top_controls_layout_height(float height) {
- top_controls_layout_height_ = height;
- }
- void set_top_controls_content_offset(float offset) {
- top_controls_content_offset_ = offset;
- }
- void set_top_controls_delta(float delta) {
- top_controls_delta_ = delta;
+ void set_top_controls_shrink_blink_size(bool shrink);
+ bool top_controls_shrink_blink_size() const {
+ return top_controls_shrink_blink_size_;
}
- void set_sent_top_controls_delta(float sent_delta) {
- sent_top_controls_delta_ = sent_delta;
+ bool SetCurrentTopControlsShownRatio(float ratio);
+ float CurrentTopControlsShownRatio() const {
+ return top_controls_shown_ratio_->Current(IsActiveTree());
}
+ void set_top_controls_height(float top_controls_height);
+ float top_controls_height() const { return top_controls_height_; }
+ void PushTopControlsFromMainThread(float top_controls_shown_ratio);
- float top_controls_layout_height() const {
- return top_controls_layout_height_;
- }
- float top_controls_content_offset() const {
- return top_controls_content_offset_;
- }
- float top_controls_delta() const {
- return top_controls_delta_;
- }
- float sent_top_controls_delta() const {
- return sent_top_controls_delta_;
- }
- float total_top_controls_content_offset() const {
- return top_controls_content_offset_ + top_controls_delta_;
- }
+ void SetPendingPageScaleAnimation(
+ scoped_ptr<PendingPageScaleAnimation> pending_animation);
+ scoped_ptr<PendingPageScaleAnimation> TakePendingPageScaleAnimation();
- void SetPageScaleAnimation(
- const gfx::Vector2d& target_offset,
- bool anchor_point,
- float page_scale,
- base::TimeDelta duration);
- scoped_ptr<PageScaleAnimation> TakePageScaleAnimation();
+ void GatherFrameTimingRequestIds(std::vector<int64_t>* request_ids);
- protected:
- explicit LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl);
- void ReleaseResourcesRecursive(LayerImpl* current);
+ bool IsExternalFlingActive() const;
+ void DidUpdateScrollOffset(int layer_id);
+ protected:
+ explicit LayerTreeImpl(
+ LayerTreeHostImpl* layer_tree_host_impl,
+ scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
+ scoped_refptr<SyncedTopControls> top_controls_shown_ratio,
+ scoped_refptr<SyncedElasticOverscroll> elastic_overscroll);
+ float ClampPageScaleFactorToLimits(float page_scale_factor) const;
+ void PushPageScaleFactorAndLimits(const float* page_scale_factor,
+ float min_page_scale_factor,
+ float max_page_scale_factor);
+ bool SetPageScaleFactorLimits(float min_page_scale_factor,
+ float max_page_scale_factor);
+ void DidUpdatePageScale();
+ void HideInnerViewportScrollbarsIfNearMinimumScale();
+ void PushTopControls(const float* top_controls_shown_ratio);
LayerTreeHostImpl* layer_tree_host_impl_;
int source_frame_number_;
scoped_ptr<LayerImpl> root_layer_;
HeadsUpDisplayLayerImpl* hud_layer_;
+ PropertyTrees property_trees_;
LayerImpl* currently_scrolling_layer_;
LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate_;
- scoped_ptr<LayerScrollOffsetDelegateProxy>
- inner_viewport_scroll_delegate_proxy_;
- scoped_ptr<LayerScrollOffsetDelegateProxy>
- outer_viewport_scroll_delegate_proxy_;
SkColor background_color_;
bool has_transparent_background_;
+ LayerImpl* overscroll_elasticity_layer_;
LayerImpl* page_scale_layer_;
LayerImpl* inner_viewport_scroll_layer_;
LayerImpl* outer_viewport_scroll_layer_;
- LayerSelectionBound selection_start_;
- LayerSelectionBound selection_end_;
+ LayerSelection selection_;
- float page_scale_factor_;
- float page_scale_delta_;
- float sent_page_scale_delta_;
+ scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor_;
float min_page_scale_factor_;
float max_page_scale_factor_;
+ scoped_refptr<SyncedElasticOverscroll> elastic_overscroll_;
+
typedef base::hash_map<int, LayerImpl*> LayerIdMap;
LayerIdMap layer_id_map_;
+ std::vector<PictureLayerImpl*> picture_layers_;
std::vector<LayerImpl*> layers_with_copy_output_request_;
// Persisted state for non-impl-side-painting.
@@ -357,6 +392,9 @@ class CC_EXPORT LayerTreeImpl {
// List of visible layers for the most recently prepared frame.
LayerImplList render_surface_layer_list_;
+ // After drawing the |render_surface_layer_list_| the areas in this region
+ // would not be fully covered by opaque content.
+ Region unoccluded_screen_space_region_;
bool contents_textures_purged_;
bool viewport_size_invalid_;
@@ -376,18 +414,17 @@ class CC_EXPORT LayerTreeImpl {
int render_surface_layer_list_id_;
- // The top controls content offset at the time of the last layout (and thus,
- // viewport resize) in Blink. i.e. How much the viewport was shrunk by the top
- // controls.
- float top_controls_layout_height_;
+ // Whether or not Blink's viewport size was shrunk by the height of the top
+ // controls at the time of the last layout.
+ bool top_controls_shrink_blink_size_;
+
+ float top_controls_height_;
- // The up-to-date content offset of the top controls, i.e. the amount that the
- // web contents have been shifted down from the top of the device viewport.
- float top_controls_content_offset_;
- float top_controls_delta_;
- float sent_top_controls_delta_;
+ // The amount that the top controls are shown from 0 (hidden) to 1 (fully
+ // shown).
+ scoped_refptr<SyncedTopControls> top_controls_shown_ratio_;
- scoped_ptr<PageScaleAnimation> page_scale_animation_;
+ scoped_ptr<PendingPageScaleAnimation> pending_page_scale_animation_;
private:
DISALLOW_COPY_AND_ASSIGN(LayerTreeImpl);
diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc
index f8de8b06862..04c108f1bdf 100644
--- a/chromium/cc/trees/layer_tree_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_impl_unittest.cc
@@ -6,12 +6,14 @@
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/layer.h"
+#include "cc/layers/solid_color_scrollbar_layer_impl.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_host_common_test.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -23,8 +25,9 @@ class LayerTreeImplTest : public LayerTreeHostCommonTest {
LayerTreeImplTest() {
LayerTreeSettings settings;
settings.layer_transforms_should_scale_layer_contents = true;
- host_impl_.reset(
- new FakeLayerTreeHostImpl(settings, &proxy_, &shared_bitmap_manager_));
+ settings.scrollbar_show_scale_threshold = 1.1f;
+ host_impl_.reset(new FakeLayerTreeHostImpl(
+ settings, &proxy_, &shared_bitmap_manager_, &task_graph_runner_));
EXPECT_TRUE(host_impl_->InitializeRenderer(FakeOutputSurface::Create3d()));
}
@@ -38,6 +41,7 @@ class LayerTreeImplTest : public LayerTreeHostCommonTest {
private:
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeImplProxy proxy_;
scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
};
@@ -50,13 +54,8 @@ TEST_F(LayerTreeImplTest, HitTestingForSingleLayer) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
host_impl().SetViewportSize(root->bounds());
@@ -102,24 +101,14 @@ TEST_F(LayerTreeImplTest, HitTestingForSingleLayerAndHud) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
// Create hud and add it as a child of root.
gfx::Size hud_bounds(200, 200);
- SetLayerPropertiesForTesting(hud.get(),
- identity_matrix,
- transform_origin,
- position,
- hud_bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(hud.get(), identity_matrix, transform_origin,
+ position, hud_bounds, true, false, false);
hud->SetDrawsContent(true);
host_impl().active_tree()->set_hud_layer(hud.get());
@@ -174,13 +163,9 @@ TEST_F(LayerTreeImplTest, HitTestingForUninvertibleTransform) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- uninvertible_transform,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), uninvertible_transform,
+ transform_origin, position, bounds, true, false,
+ true);
root->SetDrawsContent(true);
host_impl().SetViewportSize(root->bounds());
@@ -240,13 +225,8 @@ TEST_F(LayerTreeImplTest, HitTestingForSinglePositionedLayer) {
// layer is located.
gfx::PointF position(50.f, 50.f);
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
host_impl().SetViewportSize(root->bounds());
@@ -296,13 +276,9 @@ TEST_F(LayerTreeImplTest, HitTestingForSingleRotatedLayer) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- rotation45_degrees_about_center,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), rotation45_degrees_about_center,
+ transform_origin, position, bounds, true, false,
+ true);
root->SetDrawsContent(true);
host_impl().SetViewportSize(root->bounds());
@@ -365,13 +341,8 @@ TEST_F(LayerTreeImplTest, HitTestingForSinglePerspectiveLayer) {
gfx::PointF position;
gfx::Size bounds(100, 100);
SetLayerPropertiesForTesting(
- root.get(),
- perspective_projection_about_center * translation_by_z,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ root.get(), perspective_projection_about_center * translation_by_z,
+ transform_origin, position, bounds, true, false, true);
root->SetDrawsContent(true);
host_impl().SetViewportSize(root->bounds());
@@ -426,25 +397,17 @@ TEST_F(LayerTreeImplTest, HitTestingForSingleLayerWithScaledContents) {
gfx::Transform identity_matrix;
gfx::Point3F transform_origin;
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- gfx::PointF(),
- gfx::Size(100, 100),
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ gfx::PointF(), gfx::Size(100, 100), true, false,
+ true);
{
gfx::PointF position(25.f, 25.f);
gfx::Size bounds(50, 50);
scoped_ptr<LayerImpl> test_layer =
LayerImpl::Create(host_impl().active_tree(), 12345);
- SetLayerPropertiesForTesting(test_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(test_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
// override content bounds and contents scale
test_layer->SetContentBounds(gfx::Size(100, 100));
@@ -463,7 +426,7 @@ TEST_F(LayerTreeImplTest, HitTestingForSingleLayerWithScaledContents) {
// its layout size is 50x50, positioned at 25x25.
LayerImpl* test_layer =
host_impl().active_tree()->root_layer()->children()[0];
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
ASSERT_EQ(1u, RenderSurfaceLayerList().size());
ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
@@ -506,13 +469,9 @@ TEST_F(LayerTreeImplTest, HitTestingForSimpleClippedLayer) {
gfx::Point3F transform_origin;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- gfx::PointF(),
- gfx::Size(100, 100),
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ gfx::PointF(), gfx::Size(100, 100), true, false,
+ true);
{
scoped_ptr<LayerImpl> clipping_layer =
LayerImpl::Create(host_impl().active_tree(), 123);
@@ -520,26 +479,17 @@ TEST_F(LayerTreeImplTest, HitTestingForSimpleClippedLayer) {
// layer is located.
gfx::PointF position(25.f, 25.f);
gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(clipping_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(clipping_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
clipping_layer->SetMasksToBounds(true);
scoped_ptr<LayerImpl> child =
LayerImpl::Create(host_impl().active_tree(), 456);
position = gfx::PointF(-50.f, -50.f);
bounds = gfx::Size(300, 300);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, false);
child->SetDrawsContent(true);
clipping_layer->AddChild(child.Pass());
root->AddChild(clipping_layer.Pass());
@@ -601,13 +551,8 @@ TEST_F(LayerTreeImplTest, HitTestingForMultiClippedRotatedLayer) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetMasksToBounds(true);
{
scoped_ptr<LayerImpl> child =
@@ -619,13 +564,8 @@ TEST_F(LayerTreeImplTest, HitTestingForMultiClippedRotatedLayer) {
position = gfx::PointF(10.f, 10.f);
bounds = gfx::Size(80, 80);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, false);
child->SetMasksToBounds(true);
gfx::Transform rotation45_degrees_about_corner;
@@ -636,13 +576,9 @@ TEST_F(LayerTreeImplTest, HitTestingForMultiClippedRotatedLayer) {
position = gfx::PointF();
bounds =
gfx::Size(200, 200); // to ensure it covers at least sqrt(2) * 100.
- SetLayerPropertiesForTesting(grand_child.get(),
- rotation45_degrees_about_corner,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(
+ grand_child.get(), rotation45_degrees_about_corner, transform_origin,
+ position, bounds, true, false, false);
grand_child->SetMasksToBounds(true);
// Rotates about the center of the layer
@@ -656,13 +592,9 @@ TEST_F(LayerTreeImplTest, HitTestingForMultiClippedRotatedLayer) {
rotated_leaf_transform.Translate(-50.0, -50.0);
position = gfx::PointF();
bounds = gfx::Size(100, 100);
- SetLayerPropertiesForTesting(rotated_leaf.get(),
- rotated_leaf_transform,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(rotated_leaf.get(), rotated_leaf_transform,
+ transform_origin, position, bounds, true,
+ false, false);
rotated_leaf->SetDrawsContent(true);
grand_child->AddChild(rotated_leaf.Pass());
@@ -674,27 +606,6 @@ TEST_F(LayerTreeImplTest, HitTestingForMultiClippedRotatedLayer) {
host_impl().active_tree()->SetRootLayer(root.Pass());
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
- // Sanity check the scenario we just created.
- // The grand_child is expected to create a render surface because it
- // MasksToBounds and is not axis aligned.
- ASSERT_EQ(2u, RenderSurfaceLayerList().size());
- ASSERT_EQ(
- 1u,
- RenderSurfaceLayerList().at(0)->render_surface()->layer_list().size());
- ASSERT_EQ(789,
- RenderSurfaceLayerList()
- .at(0)
- ->render_surface()
- ->layer_list()
- .at(0)
- ->id()); // grand_child's surface.
- ASSERT_EQ(
- 1u,
- RenderSurfaceLayerList().at(1)->render_surface()->layer_list().size());
- ASSERT_EQ(
- 2468,
- RenderSurfaceLayerList()[1]->render_surface()->layer_list().at(0)->id());
-
// (11, 89) is close to the the bottom left corner within the clip, but it is
// not inside the layer.
gfx::Point test_point(11, 89);
@@ -749,13 +660,9 @@ TEST_F(LayerTreeImplTest, HitTestingForNonClippingIntermediateLayer) {
gfx::Point3F transform_origin;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- gfx::PointF(),
- gfx::Size(100, 100),
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ gfx::PointF(), gfx::Size(100, 100), true, false,
+ true);
{
scoped_ptr<LayerImpl> intermediate_layer =
LayerImpl::Create(host_impl().active_tree(), 123);
@@ -763,13 +670,9 @@ TEST_F(LayerTreeImplTest, HitTestingForNonClippingIntermediateLayer) {
// layer is located.
gfx::PointF position(10.f, 10.f);
gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(intermediate_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(intermediate_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
// Sanity check the intermediate layer should not clip.
ASSERT_FALSE(intermediate_layer->masks_to_bounds());
ASSERT_FALSE(intermediate_layer->mask_layer());
@@ -781,13 +684,8 @@ TEST_F(LayerTreeImplTest, HitTestingForNonClippingIntermediateLayer) {
LayerImpl::Create(host_impl().active_tree(), 456);
position = gfx::PointF(60.f, 60.f); // 70, 70 in screen space
bounds = gfx::Size(20, 20);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, false);
child->SetDrawsContent(true);
intermediate_layer->AddChild(child.Pass());
root->AddChild(intermediate_layer.Pass());
@@ -834,13 +732,8 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayers) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
{
// child 1 and child2 are initialized to overlap between x=50 and x=60.
@@ -858,24 +751,16 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayers) {
position = gfx::PointF(10.f, 10.f);
bounds = gfx::Size(50, 50);
- SetLayerPropertiesForTesting(child1.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child1.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
child1->SetDrawsContent(true);
position = gfx::PointF(50.f, 10.f);
bounds = gfx::Size(50, 50);
- SetLayerPropertiesForTesting(child2.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child2.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
child2->SetDrawsContent(true);
// Remember that grand_child is positioned with respect to its parent (i.e.
@@ -883,13 +768,9 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayers) {
// 100 x 50.
position = gfx::PointF(0.f, 40.f);
bounds = gfx::Size(100, 50);
- SetLayerPropertiesForTesting(grand_child1.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(grand_child1.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
grand_child1->SetDrawsContent(true);
child1->AddChild(grand_child1.Pass());
@@ -973,13 +854,8 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayersAtVaryingDepths) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
root->SetShouldFlattenTransform(false);
root->Set3dSortingContextId(1);
@@ -999,13 +875,9 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayersAtVaryingDepths) {
position = gfx::PointF(10.f, 10.f);
bounds = gfx::Size(50, 50);
- SetLayerPropertiesForTesting(child1.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child1.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
child1->SetDrawsContent(true);
child1->SetShouldFlattenTransform(false);
child1->Set3dSortingContextId(1);
@@ -1014,13 +886,8 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayersAtVaryingDepths) {
bounds = gfx::Size(50, 50);
gfx::Transform translate_z;
translate_z.Translate3d(0, 0, -10.f);
- SetLayerPropertiesForTesting(child2.get(),
- translate_z,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child2.get(), translate_z, transform_origin,
+ position, bounds, true, false, false);
child2->SetDrawsContent(true);
child2->SetShouldFlattenTransform(false);
child2->Set3dSortingContextId(1);
@@ -1030,13 +897,9 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayersAtVaryingDepths) {
// 100 x 50.
position = gfx::PointF(0.f, 40.f);
bounds = gfx::Size(100, 50);
- SetLayerPropertiesForTesting(grand_child1.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(grand_child1.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
grand_child1->SetDrawsContent(true);
grand_child1->SetShouldFlattenTransform(false);
@@ -1059,14 +922,6 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayersAtVaryingDepths) {
ASSERT_TRUE(grand_child1);
ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- RenderSurfaceImpl* root_render_surface =
- host_impl().active_tree()->root_layer()->render_surface();
- ASSERT_EQ(4u, root_render_surface->layer_list().size());
- ASSERT_EQ(3, root_render_surface->layer_list().at(0)->id());
- ASSERT_EQ(1, root_render_surface->layer_list().at(1)->id());
- ASSERT_EQ(2, root_render_surface->layer_list().at(2)->id());
- ASSERT_EQ(4, root_render_surface->layer_list().at(3)->id());
-
// Nothing overlaps the root_layer at (1, 1), so hit testing there should find
// the root layer.
gfx::Point test_point = gfx::Point(1, 1);
@@ -1122,13 +977,8 @@ TEST_F(LayerTreeImplTest, HitTestingRespectsClipParents) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
{
scoped_ptr<LayerImpl> child =
@@ -1138,27 +988,18 @@ TEST_F(LayerTreeImplTest, HitTestingRespectsClipParents) {
position = gfx::PointF(10.f, 10.f);
bounds = gfx::Size(1, 1);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, false);
child->SetDrawsContent(true);
child->SetMasksToBounds(true);
position = gfx::PointF(0.f, 40.f);
bounds = gfx::Size(100, 50);
- SetLayerPropertiesForTesting(grand_child.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(grand_child.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
grand_child->SetDrawsContent(true);
- grand_child->SetForceRenderSurface(true);
+ grand_child->SetHasRenderSurface(true);
// This should let |grand_child| "escape" |child|'s clip.
grand_child->SetClipParent(root.get());
@@ -1184,13 +1025,8 @@ TEST_F(LayerTreeImplTest, HitTestingRespectsScrollParents) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
{
scoped_ptr<LayerImpl> child =
@@ -1202,40 +1038,27 @@ TEST_F(LayerTreeImplTest, HitTestingRespectsScrollParents) {
position = gfx::PointF(10.f, 10.f);
bounds = gfx::Size(1, 1);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, false);
child->SetDrawsContent(true);
child->SetMasksToBounds(true);
position = gfx::PointF();
bounds = gfx::Size(200, 200);
- SetLayerPropertiesForTesting(scroll_child.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(scroll_child.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
scroll_child->SetDrawsContent(true);
// This should cause scroll child and its descendants to be affected by
// |child|'s clip.
scroll_child->SetScrollParent(child.get());
- SetLayerPropertiesForTesting(grand_child.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(grand_child.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
grand_child->SetDrawsContent(true);
- grand_child->SetForceRenderSurface(true);
+ grand_child->SetHasRenderSurface(true);
scroll_child->AddChild(grand_child.Pass());
root->AddChild(scroll_child.Pass());
@@ -1265,13 +1088,8 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayerLists) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
{
// child 1 and child2 are initialized to overlap between x=50 and x=60.
@@ -1289,42 +1107,30 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayerLists) {
position = gfx::PointF(10.f, 10.f);
bounds = gfx::Size(50, 50);
- SetLayerPropertiesForTesting(child1.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child1.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
child1->SetDrawsContent(true);
- child1->SetForceRenderSurface(true);
+ child1->SetHasRenderSurface(true);
position = gfx::PointF(50.f, 10.f);
bounds = gfx::Size(50, 50);
- SetLayerPropertiesForTesting(child2.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child2.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
child2->SetDrawsContent(true);
- child2->SetForceRenderSurface(true);
+ child2->SetHasRenderSurface(true);
// Remember that grand_child is positioned with respect to its parent (i.e.
// child1). In screen space, the intended position is (10, 50), with size
// 100 x 50.
position = gfx::PointF(0.f, 40.f);
bounds = gfx::Size(100, 50);
- SetLayerPropertiesForTesting(grand_child1.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(grand_child1.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
grand_child1->SetDrawsContent(true);
- grand_child1->SetForceRenderSurface(true);
+ grand_child1->SetHasRenderSurface(true);
child1->AddChild(grand_child1.Pass());
root->AddChild(child1.Pass());
@@ -1416,13 +1222,8 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSingleLayer) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
host_impl().SetViewportSize(root->bounds());
@@ -1504,13 +1305,9 @@ TEST_F(LayerTreeImplTest,
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- uninvertible_transform,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), uninvertible_transform,
+ transform_origin, position, bounds, true, false,
+ true);
root->SetDrawsContent(true);
root->SetTouchEventHandlerRegion(touch_handler_region);
@@ -1570,6 +1367,73 @@ TEST_F(LayerTreeImplTest,
EXPECT_FALSE(result_layer);
}
+TEST_F(LayerTreeImplTest, MakeScrollbarsInvisibleNearMinPageScale) {
+ const int kThumbThickness = 10;
+ const int kTrackStart = 0;
+ const bool kIsLeftSideVerticalScrollbar = false;
+ const bool kIsOverlayScrollbar = true;
+
+ LayerTreeImpl* active_tree = host_impl().active_tree();
+
+ scoped_ptr<LayerImpl> scroll_layer = LayerImpl::Create(active_tree, 1);
+ scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer =
+ SolidColorScrollbarLayerImpl::Create(active_tree,
+ 2,
+ VERTICAL,
+ kThumbThickness,
+ kTrackStart,
+ kIsLeftSideVerticalScrollbar,
+ kIsOverlayScrollbar);
+ scoped_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer =
+ SolidColorScrollbarLayerImpl::Create(active_tree,
+ 3,
+ HORIZONTAL,
+ kThumbThickness,
+ kTrackStart,
+ kIsLeftSideVerticalScrollbar,
+ kIsOverlayScrollbar);
+
+ scoped_ptr<LayerImpl> clip_layer = LayerImpl::Create(active_tree, 4);
+ scoped_ptr<LayerImpl> page_scale_layer = LayerImpl::Create(active_tree, 5);
+
+ scroll_layer->SetScrollClipLayer(clip_layer->id());
+
+ LayerImpl* scroll_layer_ptr = scroll_layer.get();
+ LayerImpl* page_scale_layer_ptr = page_scale_layer.get();
+
+ clip_layer->AddChild(page_scale_layer.Pass());
+ page_scale_layer_ptr->AddChild(scroll_layer.Pass());
+
+ vertical_scrollbar_layer->SetScrollLayerAndClipLayerByIds(
+ scroll_layer_ptr->id(),
+ clip_layer->id());
+ horizontal_scrollbar_layer->SetScrollLayerAndClipLayerByIds(
+ scroll_layer_ptr->id(),
+ clip_layer->id());
+
+ active_tree->PushPageScaleFromMainThread(1.0f, 1.0f, 4.0f);
+ active_tree->SetViewportLayersFromIds(
+ Layer::INVALID_ID, // Overscroll
+ page_scale_layer_ptr->id(),
+ scroll_layer_ptr->id(),
+ Layer::INVALID_ID); // Outer Scroll
+
+ EXPECT_TRUE(vertical_scrollbar_layer->hide_layer_and_subtree());
+ EXPECT_TRUE(horizontal_scrollbar_layer->hide_layer_and_subtree());
+
+ active_tree->PushPageScaleFromMainThread(1.05f, 1.0f, 4.0f);
+ EXPECT_TRUE(vertical_scrollbar_layer->hide_layer_and_subtree());
+ EXPECT_TRUE(horizontal_scrollbar_layer->hide_layer_and_subtree());
+
+ active_tree->PushPageScaleFromMainThread(1.1f, 1.0f, 4.0f);
+ EXPECT_FALSE(vertical_scrollbar_layer->hide_layer_and_subtree());
+ EXPECT_FALSE(horizontal_scrollbar_layer->hide_layer_and_subtree());
+
+ active_tree->PushPageScaleFromMainThread(1.5f, 1.0f, 4.0f);
+ EXPECT_FALSE(vertical_scrollbar_layer->hide_layer_and_subtree());
+ EXPECT_FALSE(horizontal_scrollbar_layer->hide_layer_and_subtree());
+}
+
TEST_F(LayerTreeImplTest,
HitCheckingTouchHandlerRegionsForSinglePositionedLayer) {
scoped_ptr<LayerImpl> root =
@@ -1582,13 +1446,8 @@ TEST_F(LayerTreeImplTest,
// layer is located.
gfx::PointF position(50.f, 50.f);
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
root->SetTouchEventHandlerRegion(touch_handler_region);
@@ -1658,26 +1517,18 @@ TEST_F(LayerTreeImplTest,
gfx::Transform identity_matrix;
gfx::Point3F transform_origin;
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- gfx::PointF(),
- gfx::Size(100, 100),
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ gfx::PointF(), gfx::Size(100, 100), true, false,
+ true);
{
Region touch_handler_region(gfx::Rect(10, 10, 30, 30));
gfx::PointF position(25.f, 25.f);
gfx::Size bounds(50, 50);
scoped_ptr<LayerImpl> test_layer =
LayerImpl::Create(host_impl().active_tree(), 12345);
- SetLayerPropertiesForTesting(test_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(test_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
// override content bounds and contents scale
test_layer->SetContentBounds(gfx::Size(100, 100));
@@ -1697,7 +1548,7 @@ TEST_F(LayerTreeImplTest,
// its layout size is 50x50, positioned at 25x25.
LayerImpl* test_layer =
host_impl().active_tree()->root_layer()->children()[0];
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
ASSERT_EQ(1u, RenderSurfaceLayerList().size());
ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
@@ -1762,26 +1613,18 @@ TEST_F(LayerTreeImplTest,
gfx::Transform identity_matrix;
gfx::Point3F transform_origin;
// Set the bounds of the root layer big enough to fit the child when scaled.
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- gfx::PointF(),
- gfx::Size(100, 100),
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ gfx::PointF(), gfx::Size(100, 100), true, false,
+ true);
{
Region touch_handler_region(gfx::Rect(10, 10, 30, 30));
gfx::PointF position(25.f, 25.f);
gfx::Size bounds(50, 50);
scoped_ptr<LayerImpl> test_layer =
LayerImpl::Create(host_impl().active_tree(), 12345);
- SetLayerPropertiesForTesting(test_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(test_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
test_layer->SetDrawsContent(true);
test_layer->SetTouchEventHandlerRegion(touch_handler_region);
@@ -1795,10 +1638,12 @@ TEST_F(LayerTreeImplTest,
host_impl().SetViewportSize(scaled_bounds_for_root);
host_impl().SetDeviceScaleFactor(device_scale_factor);
- host_impl().active_tree()->SetPageScaleFactorAndLimits(
+ host_impl().active_tree()->PushPageScaleFromMainThread(
page_scale_factor, page_scale_factor, page_scale_factor);
+ host_impl().SetPageScaleOnActiveTree(page_scale_factor);
host_impl().active_tree()->SetRootLayer(root.Pass());
- host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID);
+ host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 1,
+ Layer::INVALID_ID);
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
@@ -1810,8 +1655,8 @@ TEST_F(LayerTreeImplTest,
ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
// Check whether the child layer fits into the root after scaled.
- EXPECT_RECT_EQ(gfx::Rect(test_layer->content_bounds()),
- test_layer->visible_content_rect());
+ EXPECT_EQ(gfx::Rect(test_layer->content_bounds()),
+ test_layer->visible_content_rect());
// Hit checking for a point outside the layer should return a null pointer
// (the root layer does not draw content, so it will not be tested either).
@@ -1886,13 +1731,9 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSimpleClippedLayer) {
gfx::Point3F transform_origin;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- gfx::PointF(),
- gfx::Size(100, 100),
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ gfx::PointF(), gfx::Size(100, 100), true, false,
+ true);
{
scoped_ptr<LayerImpl> clipping_layer =
LayerImpl::Create(host_impl().active_tree(), 123);
@@ -1900,13 +1741,9 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSimpleClippedLayer) {
// layer is located.
gfx::PointF position(25.f, 25.f);
gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(clipping_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(clipping_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
clipping_layer->SetMasksToBounds(true);
scoped_ptr<LayerImpl> child =
@@ -1914,13 +1751,8 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSimpleClippedLayer) {
Region touch_handler_region(gfx::Rect(10, 10, 50, 50));
position = gfx::PointF(-50.f, -50.f);
bounds = gfx::Size(300, 300);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, false);
child->SetDrawsContent(true);
child->SetTouchEventHandlerRegion(touch_handler_region);
clipping_layer->AddChild(child.Pass());
@@ -1981,13 +1813,9 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerOverlappingRegions) {
gfx::Point3F transform_origin;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- gfx::PointF(),
- gfx::Size(100, 100),
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ gfx::PointF(), gfx::Size(100, 100), true, false,
+ true);
{
scoped_ptr<LayerImpl> touch_layer =
LayerImpl::Create(host_impl().active_tree(), 123);
@@ -1995,13 +1823,9 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerOverlappingRegions) {
// layer is located.
gfx::PointF position;
gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(touch_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(touch_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
touch_layer->SetDrawsContent(true);
touch_layer->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50));
root->AddChild(touch_layer.Pass());
@@ -2014,13 +1838,9 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerOverlappingRegions) {
// layer is located.
gfx::PointF position(0, 25);
gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(notouch_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(notouch_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
notouch_layer->SetDrawsContent(true);
root->AddChild(notouch_layer.Pass());
}
@@ -2078,13 +1898,8 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
root->SetDrawsContent(true);
host_impl().SetViewportSize(root->bounds());
@@ -2095,51 +1910,59 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) {
ASSERT_EQ(1u, RenderSurfaceLayerList().size());
ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
- LayerSelectionBound left_input;
- left_input.type = SELECTION_BOUND_LEFT;
- left_input.edge_top = gfx::PointF(10, 10);
- left_input.edge_bottom = gfx::PointF(10, 20);
- left_input.layer_id = root_layer_id;
+ LayerSelection input;
+
+ input.start.type = SELECTION_BOUND_LEFT;
+ input.start.edge_top = gfx::PointF(10, 10);
+ input.start.edge_bottom = gfx::PointF(10, 20);
+ input.start.layer_id = root_layer_id;
- LayerSelectionBound right_input;
- right_input.type = SELECTION_BOUND_RIGHT;
- right_input.edge_top = gfx::PointF(50, 10);
- right_input.edge_bottom = gfx::PointF(50, 30);
- right_input.layer_id = root_layer_id;
+ input.end.type = SELECTION_BOUND_RIGHT;
+ input.end.edge_top = gfx::PointF(50, 10);
+ input.end.edge_bottom = gfx::PointF(50, 30);
+ input.end.layer_id = root_layer_id;
- ViewportSelectionBound left_output, right_output;
+ ViewportSelection output;
// Empty input bounds should produce empty output bounds.
- host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
- EXPECT_EQ(ViewportSelectionBound(), left_output);
- EXPECT_EQ(ViewportSelectionBound(), right_output);
+ host_impl().active_tree()->GetViewportSelection(&output);
+ EXPECT_EQ(ViewportSelectionBound(), output.start);
+ EXPECT_EQ(ViewportSelectionBound(), output.end);
// Selection bounds should produce distinct left and right bounds.
- host_impl().active_tree()->RegisterSelection(left_input, right_input);
- host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
- EXPECT_EQ(left_input.type, left_output.type);
- EXPECT_EQ(left_input.edge_bottom, left_output.edge_bottom);
- EXPECT_EQ(left_input.edge_top, left_output.edge_top);
- EXPECT_TRUE(left_output.visible);
- EXPECT_EQ(right_input.type, right_output.type);
- EXPECT_EQ(right_input.edge_bottom, right_output.edge_bottom);
- EXPECT_EQ(right_input.edge_top, right_output.edge_top);
- EXPECT_TRUE(right_output.visible);
+ host_impl().active_tree()->RegisterSelection(input);
+ host_impl().active_tree()->GetViewportSelection(&output);
+ EXPECT_EQ(input.start.type, output.start.type);
+ EXPECT_EQ(input.start.edge_bottom, output.start.edge_bottom);
+ EXPECT_EQ(input.start.edge_top, output.start.edge_top);
+ EXPECT_TRUE(output.start.visible);
+ EXPECT_EQ(input.end.type, output.end.type);
+ EXPECT_EQ(input.end.edge_bottom, output.end.edge_bottom);
+ EXPECT_EQ(input.end.edge_top, output.end.edge_top);
+ EXPECT_TRUE(output.end.visible);
+ EXPECT_EQ(input.is_editable, output.is_editable);
+ EXPECT_EQ(input.is_empty_text_form_control,
+ output.is_empty_text_form_control);
// Insertion bounds should produce identical left and right bounds.
- LayerSelectionBound insertion_input;
- insertion_input.type = SELECTION_BOUND_CENTER;
- insertion_input.edge_top = gfx::PointF(15, 10);
- insertion_input.edge_bottom = gfx::PointF(15, 30);
- insertion_input.layer_id = root_layer_id;
- host_impl().active_tree()->RegisterSelection(insertion_input,
- LayerSelectionBound());
- host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
- EXPECT_EQ(insertion_input.type, left_output.type);
- EXPECT_EQ(insertion_input.edge_bottom, left_output.edge_bottom);
- EXPECT_EQ(insertion_input.edge_top, left_output.edge_top);
- EXPECT_TRUE(left_output.visible);
- EXPECT_EQ(left_output, right_output);
+ LayerSelection insertion_input;
+ insertion_input.start.type = SELECTION_BOUND_CENTER;
+ insertion_input.start.edge_top = gfx::PointF(15, 10);
+ insertion_input.start.edge_bottom = gfx::PointF(15, 30);
+ insertion_input.start.layer_id = root_layer_id;
+ insertion_input.is_editable = true;
+ insertion_input.is_empty_text_form_control = true;
+ insertion_input.end = insertion_input.start;
+ host_impl().active_tree()->RegisterSelection(insertion_input);
+ host_impl().active_tree()->GetViewportSelection(&output);
+ EXPECT_EQ(insertion_input.start.type, output.start.type);
+ EXPECT_EQ(insertion_input.start.edge_bottom, output.start.edge_bottom);
+ EXPECT_EQ(insertion_input.start.edge_top, output.start.edge_top);
+ EXPECT_EQ(insertion_input.is_editable, output.is_editable);
+ EXPECT_EQ(insertion_input.is_empty_text_form_control,
+ output.is_empty_text_form_control);
+ EXPECT_TRUE(output.start.visible);
+ EXPECT_EQ(output.start, output.end);
}
TEST_F(LayerTreeImplTest, SelectionBoundsForPartialOccludedLayers) {
@@ -2154,13 +1977,8 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForPartialOccludedLayers) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
gfx::Vector2dF clipping_offset(10, 10);
{
@@ -2169,26 +1987,18 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForPartialOccludedLayers) {
// The clipping layer should occlude the right selection bound.
gfx::PointF position = gfx::PointF() + clipping_offset;
gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(clipping_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(clipping_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
clipping_layer->SetMasksToBounds(true);
scoped_ptr<LayerImpl> clipped_layer =
LayerImpl::Create(host_impl().active_tree(), clipped_layer_id);
position = gfx::PointF();
bounds = gfx::Size(100, 100);
- SetLayerPropertiesForTesting(clipped_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(clipped_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
clipped_layer->SetDrawsContent(true);
clipping_layer->AddChild(clipped_layer.Pass());
root->AddChild(clipping_layer.Pass());
@@ -2201,58 +2011,57 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForPartialOccludedLayers) {
// Sanity check the scenario we just created.
ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- LayerSelectionBound left_input;
- left_input.type = SELECTION_BOUND_LEFT;
- left_input.edge_top = gfx::PointF(25, 10);
- left_input.edge_bottom = gfx::PointF(25, 30);
- left_input.layer_id = clipped_layer_id;
+ LayerSelection input;
+ input.start.type = SELECTION_BOUND_LEFT;
+ input.start.edge_top = gfx::PointF(25, 10);
+ input.start.edge_bottom = gfx::PointF(25, 30);
+ input.start.layer_id = clipped_layer_id;
- LayerSelectionBound right_input;
- right_input.type = SELECTION_BOUND_RIGHT;
- right_input.edge_top = gfx::PointF(75, 10);
- right_input.edge_bottom = gfx::PointF(75, 30);
- right_input.layer_id = clipped_layer_id;
- host_impl().active_tree()->RegisterSelection(left_input, right_input);
+ input.end.type = SELECTION_BOUND_RIGHT;
+ input.end.edge_top = gfx::PointF(75, 10);
+ input.end.edge_bottom = gfx::PointF(75, 30);
+ input.end.layer_id = clipped_layer_id;
+ host_impl().active_tree()->RegisterSelection(input);
// The left bound should be occluded by the clip layer.
- ViewportSelectionBound left_output, right_output;
- host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
- EXPECT_EQ(left_input.type, left_output.type);
- gfx::PointF expected_left_output_top = left_input.edge_top;
- gfx::PointF expected_left_output_bottom = left_input.edge_bottom;
- expected_left_output_top.Offset(clipping_offset.x(), clipping_offset.y());
- expected_left_output_bottom.Offset(clipping_offset.x(), clipping_offset.y());
- EXPECT_EQ(expected_left_output_top, left_output.edge_top);
- EXPECT_EQ(expected_left_output_bottom, left_output.edge_bottom);
- EXPECT_TRUE(left_output.visible);
- EXPECT_EQ(right_input.type, right_output.type);
- gfx::PointF expected_right_output_top = right_input.edge_top;
- gfx::PointF expected_right_output_bottom = right_input.edge_bottom;
- expected_right_output_bottom.Offset(clipping_offset.x(), clipping_offset.y());
- expected_right_output_top.Offset(clipping_offset.x(), clipping_offset.y());
- EXPECT_EQ(expected_right_output_top, right_output.edge_top);
- EXPECT_EQ(expected_right_output_bottom, right_output.edge_bottom);
- EXPECT_FALSE(right_output.visible);
+ ViewportSelection output;
+ host_impl().active_tree()->GetViewportSelection(&output);
+ EXPECT_EQ(input.start.type, output.start.type);
+ gfx::PointF expected_output_start_top = input.start.edge_top;
+ gfx::PointF expected_output_edge_botom = input.start.edge_bottom;
+ expected_output_start_top.Offset(clipping_offset.x(), clipping_offset.y());
+ expected_output_edge_botom.Offset(clipping_offset.x(), clipping_offset.y());
+ EXPECT_EQ(expected_output_start_top, output.start.edge_top);
+ EXPECT_EQ(expected_output_edge_botom, output.start.edge_bottom);
+ EXPECT_TRUE(output.start.visible);
+ EXPECT_EQ(input.end.type, output.end.type);
+ gfx::PointF expected_output_end_top = input.end.edge_top;
+ gfx::PointF expected_output_end_bottom = input.end.edge_bottom;
+ expected_output_end_bottom.Offset(clipping_offset.x(), clipping_offset.y());
+ expected_output_end_top.Offset(clipping_offset.x(), clipping_offset.y());
+ EXPECT_EQ(expected_output_end_top, output.end.edge_top);
+ EXPECT_EQ(expected_output_end_bottom, output.end.edge_bottom);
+ EXPECT_FALSE(output.end.visible);
// Handles outside the viewport bounds should be marked invisible.
- left_input.edge_top = gfx::PointF(-25, 0);
- left_input.edge_bottom = gfx::PointF(-25, 20);
- host_impl().active_tree()->RegisterSelection(left_input, right_input);
- host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
- EXPECT_FALSE(left_output.visible);
-
- left_input.edge_top = gfx::PointF(0, -25);
- left_input.edge_bottom = gfx::PointF(0, -5);
- host_impl().active_tree()->RegisterSelection(left_input, right_input);
- host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
- EXPECT_FALSE(left_output.visible);
+ input.start.edge_top = gfx::PointF(-25, 0);
+ input.start.edge_bottom = gfx::PointF(-25, 20);
+ host_impl().active_tree()->RegisterSelection(input);
+ host_impl().active_tree()->GetViewportSelection(&output);
+ EXPECT_FALSE(output.start.visible);
+
+ input.start.edge_top = gfx::PointF(0, -25);
+ input.start.edge_bottom = gfx::PointF(0, -5);
+ host_impl().active_tree()->RegisterSelection(input);
+ host_impl().active_tree()->GetViewportSelection(&output);
+ EXPECT_FALSE(output.start.visible);
// If the handle bottom is partially visible, the handle is marked visible.
- left_input.edge_top = gfx::PointF(0, -20);
- left_input.edge_bottom = gfx::PointF(0, 1);
- host_impl().active_tree()->RegisterSelection(left_input, right_input);
- host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
- EXPECT_TRUE(left_output.visible);
+ input.start.edge_top = gfx::PointF(0, -20);
+ input.start.edge_bottom = gfx::PointF(0, 1);
+ host_impl().active_tree()->RegisterSelection(input);
+ host_impl().active_tree()->GetViewportSelection(&output);
+ EXPECT_TRUE(output.start.visible);
}
TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) {
@@ -2266,13 +2075,8 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) {
gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin,
+ position, bounds, true, false, true);
gfx::Vector2dF sub_layer_offset(10, 0);
{
@@ -2280,13 +2084,9 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) {
LayerImpl::Create(host_impl().active_tree(), sub_layer_id);
gfx::PointF position = gfx::PointF() + sub_layer_offset;
gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(sub_layer.get(),
- identity_matrix,
- transform_origin,
- position,
- bounds,
- true,
- false);
+ SetLayerPropertiesForTesting(sub_layer.get(), identity_matrix,
+ transform_origin, position, bounds, true,
+ false, false);
sub_layer->SetDrawsContent(true);
root->AddChild(sub_layer.Pass());
}
@@ -2298,52 +2098,52 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) {
host_impl().SetViewportSize(scaled_bounds_for_root);
host_impl().SetDeviceScaleFactor(device_scale_factor);
- host_impl().active_tree()->SetPageScaleFactorAndLimits(
+ host_impl().active_tree()->PushPageScaleFromMainThread(
page_scale_factor, page_scale_factor, page_scale_factor);
+ host_impl().SetPageScaleOnActiveTree(page_scale_factor);
host_impl().active_tree()->SetRootLayer(root.Pass());
- host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID);
+ host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 1,
+ Layer::INVALID_ID);
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- LayerSelectionBound left_input;
- left_input.type = SELECTION_BOUND_LEFT;
- left_input.edge_top = gfx::PointF(10, 10);
- left_input.edge_bottom = gfx::PointF(10, 30);
- left_input.layer_id = root_layer_id;
+ LayerSelection input;
+ input.start.type = SELECTION_BOUND_LEFT;
+ input.start.edge_top = gfx::PointF(10, 10);
+ input.start.edge_bottom = gfx::PointF(10, 30);
+ input.start.layer_id = root_layer_id;
- LayerSelectionBound right_input;
- right_input.type = SELECTION_BOUND_RIGHT;
- right_input.edge_top = gfx::PointF(0, 0);
- right_input.edge_bottom = gfx::PointF(0, 20);
- right_input.layer_id = sub_layer_id;
- host_impl().active_tree()->RegisterSelection(left_input, right_input);
+ input.end.type = SELECTION_BOUND_RIGHT;
+ input.end.edge_top = gfx::PointF(0, 0);
+ input.end.edge_bottom = gfx::PointF(0, 20);
+ input.end.layer_id = sub_layer_id;
+ host_impl().active_tree()->RegisterSelection(input);
// The viewport bounds should be properly scaled by the page scale, but should
// remain in DIP coordinates.
- ViewportSelectionBound left_output, right_output;
- host_impl().active_tree()->GetViewportSelection(&left_output, &right_output);
- EXPECT_EQ(left_input.type, left_output.type);
- gfx::PointF expected_left_output_top = left_input.edge_top;
- gfx::PointF expected_left_output_bottom = left_input.edge_bottom;
- expected_left_output_top.Scale(page_scale_factor);
- expected_left_output_bottom.Scale(page_scale_factor);
- EXPECT_EQ(left_input.edge_top, left_output.edge_top);
- EXPECT_EQ(left_input.edge_bottom, left_output.edge_bottom);
- EXPECT_TRUE(left_output.visible);
- EXPECT_EQ(right_input.type, right_output.type);
-
- gfx::PointF expected_right_output_top = right_input.edge_top;
- gfx::PointF expected_right_output_bottom = right_input.edge_bottom;
- expected_right_output_top.Offset(sub_layer_offset.x(), sub_layer_offset.y());
- expected_right_output_bottom.Offset(sub_layer_offset.x(),
- sub_layer_offset.y());
- expected_right_output_top.Scale(page_scale_factor);
- expected_right_output_bottom.Scale(page_scale_factor);
- EXPECT_EQ(expected_right_output_top, right_output.edge_top);
- EXPECT_EQ(expected_right_output_bottom, right_output.edge_bottom);
- EXPECT_TRUE(right_output.visible);
+ ViewportSelection output;
+ host_impl().active_tree()->GetViewportSelection(&output);
+ EXPECT_EQ(input.start.type, output.start.type);
+ gfx::PointF expected_output_start_top = input.start.edge_top;
+ gfx::PointF expected_output_edge_botom = input.start.edge_bottom;
+ expected_output_start_top.Scale(page_scale_factor);
+ expected_output_edge_botom.Scale(page_scale_factor);
+ EXPECT_EQ(input.start.edge_top, output.start.edge_top);
+ EXPECT_EQ(input.start.edge_bottom, output.start.edge_bottom);
+ EXPECT_TRUE(output.start.visible);
+ EXPECT_EQ(input.end.type, output.end.type);
+
+ gfx::PointF expected_output_end_top = input.end.edge_top;
+ gfx::PointF expected_output_end_bottom = input.end.edge_bottom;
+ expected_output_end_top.Offset(sub_layer_offset.x(), sub_layer_offset.y());
+ expected_output_end_bottom.Offset(sub_layer_offset.x(), sub_layer_offset.y());
+ expected_output_end_top.Scale(page_scale_factor);
+ expected_output_end_bottom.Scale(page_scale_factor);
+ EXPECT_EQ(expected_output_end_top, output.end.edge_top);
+ EXPECT_EQ(expected_output_end_bottom, output.end.edge_bottom);
+ EXPECT_TRUE(output.end.visible);
}
TEST_F(LayerTreeImplTest, NumLayersTestOne) {
diff --git a/chromium/cc/trees/layer_tree_settings.cc b/chromium/cc/trees/layer_tree_settings.cc
index 1d5cf1bb2eb..d2c3bda2b9c 100644
--- a/chromium/cc/trees/layer_tree_settings.cc
+++ b/chromium/cc/trees/layer_tree_settings.cc
@@ -4,6 +4,7 @@
#include "cc/trees/layer_tree_settings.h"
+#include <GLES2/gl2.h>
#include <limits>
#include "base/command_line.h"
@@ -14,64 +15,84 @@ namespace cc {
LayerTreeSettings::LayerTreeSettings()
: impl_side_painting(false),
- allow_antialiasing(true),
- force_antialiasing(false),
+ raster_enabled(true),
throttle_frame_production(true),
single_thread_proxy_scheduler(true),
- begin_frame_scheduling_enabled(false),
+ use_external_begin_frame_source(false),
main_frame_before_activation_enabled(false),
using_synchronous_renderer_compositor(false),
- disable_hi_res_timer_tasks_on_battery(false),
report_overscroll_only_for_scrollable_axes(false),
per_tile_painting_enabled(false),
- partial_swap_enabled(false),
accelerated_animation_enabled(true),
can_use_lcd_text(true),
use_distance_field_text(false),
- should_clear_root_render_pass(true),
gpu_rasterization_enabled(false),
gpu_rasterization_forced(false),
+ gpu_rasterization_msaa_sample_count(0),
+ gpu_rasterization_skewport_target_time_in_seconds(0.2f),
create_low_res_tiling(false),
- scrollbar_animator(NoAnimator),
+ scrollbar_animator(NO_ANIMATOR),
scrollbar_fade_delay_ms(0),
scrollbar_fade_resize_delay_ms(0),
scrollbar_fade_duration_ms(0),
+ scrollbar_show_scale_threshold(1.0f),
solid_color_scrollbar_color(SK_ColorWHITE),
- calculate_top_controls_position(false),
timeout_and_draw_when_animation_checkerboards(true),
maximum_number_of_failed_draws_before_draw_is_forced_(3),
layer_transforms_should_scale_layer_contents(false),
+ layers_always_allowed_lcd_text(false),
minimum_contents_scale(0.0625f),
low_res_contents_scale_factor(0.25f),
- top_controls_height(0.f),
top_controls_show_threshold(0.5f),
top_controls_hide_threshold(0.5f),
- refresh_rate(60.0),
+ background_animation_rate(1.0),
max_partial_texture_updates(std::numeric_limits<size_t>::max()),
default_tile_size(gfx::Size(256, 256)),
max_untiled_layer_size(gfx::Size(512, 512)),
default_tile_grid_size(gfx::Size(256, 256)),
minimum_occlusion_tracking_size(gfx::Size(160, 160)),
- use_pinch_zoom_scrollbars(false),
use_pinch_virtual_viewport(false),
- // At 256x256 tiles, 128 tiles cover an area of 2048x4096 pixels.
- max_tiles_for_interest_area(128),
- skewport_target_time_multiplier(1.0f),
+ tiling_interest_area_viewport_multiplier(9.0f),
+ skewport_target_time_in_seconds(1.0f),
skewport_extrapolation_limit_in_content_pixels(2000),
max_unused_resource_memory_percentage(100),
max_memory_for_prepaint_percentage(100),
- highp_threshold_min(0),
strict_layer_property_change_checking(false),
use_one_copy(false),
use_zero_copy(false),
+ enable_elastic_overscroll(false),
+ use_image_texture_target(GL_TEXTURE_2D),
ignore_root_layer_flings(false),
- use_rgba_4444_textures(false),
- texture_id_allocation_chunk_size(64),
scheduled_raster_task_limit(32),
use_occlusion_for_tile_prioritization(false),
- record_full_layer(false) {
+ record_full_layer(false),
+ use_display_lists(false),
+ use_cached_picture_in_display_list(true),
+ verify_property_trees(false),
+ gather_pixel_refs(false),
+ use_compositor_animation_timelines(false) {
}
LayerTreeSettings::~LayerTreeSettings() {}
+SchedulerSettings LayerTreeSettings::ToSchedulerSettings() const {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source =
+ use_external_begin_frame_source;
+ scheduler_settings.main_frame_before_activation_enabled =
+ main_frame_before_activation_enabled;
+ scheduler_settings.impl_side_painting = impl_side_painting;
+ scheduler_settings.timeout_and_draw_when_animation_checkerboards =
+ timeout_and_draw_when_animation_checkerboards;
+ scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ =
+ maximum_number_of_failed_draws_before_draw_is_forced_;
+ scheduler_settings.using_synchronous_renderer_compositor =
+ using_synchronous_renderer_compositor;
+ scheduler_settings.throttle_frame_production = throttle_frame_production;
+ scheduler_settings.main_thread_should_always_be_low_latency = false;
+ scheduler_settings.background_frame_interval =
+ base::TimeDelta::FromSecondsD(1.0 / background_animation_rate);
+ return scheduler_settings;
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h
index 74a3b0c85bb..0e1819b0d95 100644
--- a/chromium/cc/trees/layer_tree_settings.h
+++ b/chromium/cc/trees/layer_tree_settings.h
@@ -8,6 +8,8 @@
#include "base/basictypes.h"
#include "cc/base/cc_export.h"
#include "cc/debug/layer_tree_debug_state.h"
+#include "cc/output/renderer_settings.h"
+#include "cc/scheduler/scheduler_settings.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/size.h"
@@ -18,70 +20,74 @@ class CC_EXPORT LayerTreeSettings {
LayerTreeSettings();
~LayerTreeSettings();
+ RendererSettings renderer_settings;
bool impl_side_painting;
- bool allow_antialiasing;
- bool force_antialiasing;
+ bool raster_enabled;
bool throttle_frame_production;
bool single_thread_proxy_scheduler;
- bool begin_frame_scheduling_enabled;
+ bool use_external_begin_frame_source;
bool main_frame_before_activation_enabled;
bool using_synchronous_renderer_compositor;
- bool disable_hi_res_timer_tasks_on_battery;
bool report_overscroll_only_for_scrollable_axes;
bool per_tile_painting_enabled;
- bool partial_swap_enabled;
bool accelerated_animation_enabled;
bool can_use_lcd_text;
bool use_distance_field_text;
- bool should_clear_root_render_pass;
bool gpu_rasterization_enabled;
bool gpu_rasterization_forced;
+ int gpu_rasterization_msaa_sample_count;
+ float gpu_rasterization_skewport_target_time_in_seconds;
bool create_low_res_tiling;
enum ScrollbarAnimator {
- NoAnimator,
- LinearFade,
- Thinning,
+ NO_ANIMATOR,
+ LINEAR_FADE,
+ THINNING,
};
ScrollbarAnimator scrollbar_animator;
int scrollbar_fade_delay_ms;
int scrollbar_fade_resize_delay_ms;
int scrollbar_fade_duration_ms;
+ float scrollbar_show_scale_threshold;
SkColor solid_color_scrollbar_color;
- bool calculate_top_controls_position;
bool timeout_and_draw_when_animation_checkerboards;
int maximum_number_of_failed_draws_before_draw_is_forced_;
bool layer_transforms_should_scale_layer_contents;
+ bool layers_always_allowed_lcd_text;
float minimum_contents_scale;
float low_res_contents_scale_factor;
- float top_controls_height;
float top_controls_show_threshold;
float top_controls_hide_threshold;
- double refresh_rate;
+ double background_animation_rate;
size_t max_partial_texture_updates;
gfx::Size default_tile_size;
gfx::Size max_untiled_layer_size;
gfx::Size default_tile_grid_size;
gfx::Size minimum_occlusion_tracking_size;
- bool use_pinch_zoom_scrollbars;
bool use_pinch_virtual_viewport;
- size_t max_tiles_for_interest_area;
- float skewport_target_time_multiplier;
+ float tiling_interest_area_viewport_multiplier;
+ float skewport_target_time_in_seconds;
int skewport_extrapolation_limit_in_content_pixels;
size_t max_unused_resource_memory_percentage;
size_t max_memory_for_prepaint_percentage;
- int highp_threshold_min;
bool strict_layer_property_change_checking;
bool use_one_copy;
bool use_zero_copy;
+ bool enable_elastic_overscroll;
+ unsigned use_image_texture_target;
bool ignore_root_layer_flings;
- bool use_rgba_4444_textures;
- size_t texture_id_allocation_chunk_size;
size_t scheduled_raster_task_limit;
bool use_occlusion_for_tile_prioritization;
bool record_full_layer;
+ bool use_display_lists;
+ bool use_cached_picture_in_display_list;
+ bool verify_property_trees;
+ bool gather_pixel_refs;
+ bool use_compositor_animation_timelines;
LayerTreeDebugState initial_debug_state;
+
+ SchedulerSettings ToSchedulerSettings() const;
};
} // namespace cc
diff --git a/chromium/cc/trees/occlusion.cc b/chromium/cc/trees/occlusion.cc
index 14168f9699f..6a714962747 100644
--- a/chromium/cc/trees/occlusion.cc
+++ b/chromium/cc/trees/occlusion.cc
@@ -85,4 +85,16 @@ gfx::Rect Occlusion::GetUnoccludedRectInTargetSurface(
return unoccluded_rect_in_target_surface;
}
+bool Occlusion::IsEqual(const Occlusion& other) const {
+ return draw_transform_ == other.draw_transform_ &&
+ occlusion_from_inside_target_ == other.occlusion_from_inside_target_ &&
+ occlusion_from_outside_target_ == other.occlusion_from_outside_target_;
+}
+
+std::string Occlusion::ToString() const {
+ return draw_transform_.ToString() + "outside(" +
+ occlusion_from_outside_target_.ToString() + ") inside(" +
+ occlusion_from_inside_target_.ToString() + ")";
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/occlusion.h b/chromium/cc/trees/occlusion.h
index 56f9962df8b..fec4915e2db 100644
--- a/chromium/cc/trees/occlusion.h
+++ b/chromium/cc/trees/occlusion.h
@@ -5,6 +5,8 @@
#ifndef CC_TREES_OCCLUSION_H_
#define CC_TREES_OCCLUSION_H_
+#include <string>
+
#include "base/basictypes.h"
#include "cc/base/cc_export.h"
#include "cc/base/simple_enclosed_region.h"
@@ -26,6 +28,9 @@ class CC_EXPORT Occlusion {
bool IsOccluded(const gfx::Rect& content_rect) const;
gfx::Rect GetUnoccludedContentRect(const gfx::Rect& content_rect) const;
+ bool IsEqual(const Occlusion& other) const;
+ std::string ToString() const;
+
private:
gfx::Rect GetUnoccludedRectInTargetSurface(
const gfx::Rect& content_rect) const;
diff --git a/chromium/cc/trees/occlusion_tracker.cc b/chromium/cc/trees/occlusion_tracker.cc
index bce1fd514e8..0f0ce158400 100644
--- a/chromium/cc/trees/occlusion_tracker.cc
+++ b/chromium/cc/trees/occlusion_tracker.cc
@@ -20,12 +20,12 @@ namespace cc {
template <typename LayerType>
OcclusionTracker<LayerType>::OcclusionTracker(
const gfx::Rect& screen_space_clip_rect)
- : screen_space_clip_rect_(screen_space_clip_rect),
- occluding_screen_space_rects_(NULL),
- non_occluding_screen_space_rects_(NULL) {}
+ : screen_space_clip_rect_(screen_space_clip_rect) {
+}
template <typename LayerType>
-OcclusionTracker<LayerType>::~OcclusionTracker() {}
+OcclusionTracker<LayerType>::~OcclusionTracker() {
+}
template <typename LayerType>
Occlusion OcclusionTracker<LayerType>::GetCurrentOcclusionForLayer(
@@ -38,6 +38,21 @@ Occlusion OcclusionTracker<LayerType>::GetCurrentOcclusionForLayer(
}
template <typename LayerType>
+Occlusion
+OcclusionTracker<LayerType>::GetCurrentOcclusionForContributingSurface(
+ const gfx::Transform& draw_transform) const {
+ DCHECK(!stack_.empty());
+ if (stack_.size() < 2)
+ return Occlusion();
+ // A contributing surface doesn't get occluded by things inside its own
+ // surface, so only things outside the surface can occlude it. That occlusion
+ // is found just below the top of the stack (if it exists).
+ const StackObject& second_last = stack_[stack_.size() - 2];
+ return Occlusion(draw_transform, second_last.occlusion_from_outside_target,
+ second_last.occlusion_from_inside_target);
+}
+
+template <typename LayerType>
void OcclusionTracker<LayerType>::EnterLayer(
const LayerIteratorPosition<LayerType>& layer_iterator) {
LayerType* render_target = layer_iterator.target_render_surface_layer;
@@ -140,7 +155,7 @@ static inline bool LayerIsInUnsorted3dRenderingContext(const Layer* layer) {
return layer->Is3dSorted();
}
static inline bool LayerIsInUnsorted3dRenderingContext(const LayerImpl* layer) {
- return false;
+ return layer->Is3dSorted();
}
template <typename LayerType>
@@ -340,12 +355,15 @@ void OcclusionTracker<LayerType>::LeaveToRenderTarget(
gfx::Rect unoccluded_surface_rect;
gfx::Rect unoccluded_replica_rect;
if (old_target->background_filters().HasFilterThatMovesPixels()) {
- unoccluded_surface_rect = UnoccludedContributingSurfaceContentRect(
- old_surface->content_rect(), old_surface->draw_transform());
+ Occlusion surface_occlusion = GetCurrentOcclusionForContributingSurface(
+ old_surface->draw_transform());
+ unoccluded_surface_rect =
+ surface_occlusion.GetUnoccludedContentRect(old_surface->content_rect());
if (old_target->has_replica()) {
- unoccluded_replica_rect = UnoccludedContributingSurfaceContentRect(
- old_surface->content_rect(),
+ Occlusion replica_occlusion = GetCurrentOcclusionForContributingSurface(
old_surface->replica_draw_transform());
+ unoccluded_replica_rect = replica_occlusion.GetUnoccludedContentRect(
+ old_surface->content_rect());
}
}
@@ -447,96 +465,7 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer(
transformed_rect.height() < minimum_tracking_size_.height())
continue;
stack_.back().occlusion_from_inside_target.Union(transformed_rect);
-
- if (!occluding_screen_space_rects_)
- continue;
-
- // Save the occluding area in screen space for debug visualization.
- bool clipped;
- gfx::QuadF screen_space_quad = MathUtil::MapQuad(
- layer->render_target()->render_surface()->screen_space_transform(),
- gfx::QuadF(transformed_rect), &clipped);
- // TODO(danakj): Store the quad in the debug info instead of the bounding
- // box.
- gfx::Rect screen_space_rect =
- gfx::ToEnclosedRect(screen_space_quad.BoundingBox());
- occluding_screen_space_rects_->push_back(screen_space_rect);
}
-
- if (!non_occluding_screen_space_rects_)
- return;
-
- Region non_opaque_contents(gfx::Rect(layer->content_bounds()));
- non_opaque_contents.Subtract(opaque_contents);
-
- for (Region::Iterator non_opaque_content_rects(non_opaque_contents);
- non_opaque_content_rects.has_rect();
- non_opaque_content_rects.next()) {
- gfx::Rect transformed_rect =
- MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
- layer->draw_transform(), non_opaque_content_rects.rect());
- transformed_rect.Intersect(clip_rect_in_target);
- if (transformed_rect.IsEmpty())
- continue;
-
- bool clipped;
- gfx::QuadF screen_space_quad = MathUtil::MapQuad(
- layer->render_target()->render_surface()->screen_space_transform(),
- gfx::QuadF(transformed_rect),
- &clipped);
- // TODO(danakj): Store the quad in the debug info instead of the bounding
- // box.
- gfx::Rect screen_space_rect =
- gfx::ToEnclosedRect(screen_space_quad.BoundingBox());
- non_occluding_screen_space_rects_->push_back(screen_space_rect);
- }
-}
-
-template <typename LayerType>
-gfx::Rect OcclusionTracker<LayerType>::UnoccludedContributingSurfaceContentRect(
- const gfx::Rect& content_rect,
- const gfx::Transform& draw_transform) const {
- if (content_rect.IsEmpty())
- return content_rect;
-
- // A contributing surface doesn't get occluded by things inside its own
- // surface, so only things outside the surface can occlude it. That occlusion
- // is found just below the top of the stack (if it exists).
- bool has_occlusion = stack_.size() > 1;
- if (!has_occlusion)
- return content_rect;
-
- const StackObject& second_last = stack_[stack_.size() - 2];
- if (second_last.occlusion_from_inside_target.IsEmpty() &&
- second_last.occlusion_from_outside_target.IsEmpty())
- return content_rect;
-
- gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
- bool ok = draw_transform.GetInverse(&inverse_draw_transform);
- DCHECK(ok);
-
- // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
- // partial pixels in the resulting Rect.
- gfx::Rect unoccluded_rect_in_target_surface =
- MathUtil::MapEnclosingClippedRect(draw_transform, content_rect);
- DCHECK_LE(second_last.occlusion_from_inside_target.GetRegionComplexity(), 1u);
- DCHECK_LE(second_last.occlusion_from_outside_target.GetRegionComplexity(),
- 1u);
- // These subtract operations are more lossy than if we did both operations at
- // once.
- unoccluded_rect_in_target_surface.Subtract(
- second_last.occlusion_from_inside_target.bounds());
- unoccluded_rect_in_target_surface.Subtract(
- second_last.occlusion_from_outside_target.bounds());
-
- if (unoccluded_rect_in_target_surface.IsEmpty())
- return gfx::Rect();
-
- gfx::Rect unoccluded_rect = MathUtil::ProjectEnclosingClippedRect(
- inverse_draw_transform, unoccluded_rect_in_target_surface);
- unoccluded_rect.Intersect(content_rect);
-
- return unoccluded_rect;
}
template <typename LayerType>
diff --git a/chromium/cc/trees/occlusion_tracker.h b/chromium/cc/trees/occlusion_tracker.h
index 4d6555a91e7..ff6f18dda9c 100644
--- a/chromium/cc/trees/occlusion_tracker.h
+++ b/chromium/cc/trees/occlusion_tracker.h
@@ -40,6 +40,8 @@ class CC_EXPORT OcclusionTracker {
// and can be used outside of a layer walk to check occlusion.
Occlusion GetCurrentOcclusionForLayer(
const gfx::Transform& draw_transform) const;
+ Occlusion GetCurrentOcclusionForContributingSurface(
+ const gfx::Transform& draw_transform) const;
// Called at the beginning of each step in the LayerIterator's front-to-back
// traversal.
@@ -48,13 +50,6 @@ class CC_EXPORT OcclusionTracker {
// traversal.
void LeaveLayer(const LayerIteratorPosition<LayerType>& layer_iterator);
- // Gives an unoccluded sub-rect of |content_rect| in the content space of the
- // render_target owned by the layer. Used when considering occlusion for a
- // contributing surface that is rendering into another target.
- gfx::Rect UnoccludedContributingSurfaceContentRect(
- const gfx::Rect& content_rect,
- const gfx::Transform& draw_transform) const;
-
// Gives the region of the screen that is not occluded by something opaque.
Region ComputeVisibleRegionInScreen() const;
@@ -62,16 +57,6 @@ class CC_EXPORT OcclusionTracker {
minimum_tracking_size_ = size;
}
- // The following is used for visualization purposes.
- void set_occluding_screen_space_rects_container(
- std::vector<gfx::Rect>* rects) {
- occluding_screen_space_rects_ = rects;
- }
- void set_non_occluding_screen_space_rects_container(
- std::vector<gfx::Rect>* rects) {
- non_occluding_screen_space_rects_ = rects;
- }
-
protected:
struct StackObject {
StackObject() : target(0) {}
@@ -120,10 +105,6 @@ class CC_EXPORT OcclusionTracker {
gfx::Rect screen_space_clip_rect_;
gfx::Size minimum_tracking_size_;
- // This is used for visualizing the occlusion tracking process.
- std::vector<gfx::Rect>* occluding_screen_space_rects_;
- std::vector<gfx::Rect>* non_occluding_screen_space_rects_;
-
DISALLOW_COPY_AND_ASSIGN(OcclusionTracker);
};
diff --git a/chromium/cc/trees/occlusion_tracker_perftest.cc b/chromium/cc/trees/occlusion_tracker_perftest.cc
index 7346f2594de..854dacdb5f0 100644
--- a/chromium/cc/trees/occlusion_tracker_perftest.cc
+++ b/chromium/cc/trees/occlusion_tracker_perftest.cc
@@ -36,16 +36,13 @@ class OcclusionTrackerPerfTest : public testing::Test {
void CreateHost() {
LayerTreeSettings settings;
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
- host_impl_ = LayerTreeHostImpl::Create(settings,
- &client_,
- &proxy_,
- &stats_,
- shared_bitmap_manager_.get(),
- NULL,
- 1);
+ host_impl_ =
+ LayerTreeHostImpl::Create(settings, &client_, &proxy_, &stats_,
+ shared_bitmap_manager_.get(), NULL, NULL, 1);
host_impl_->InitializeRenderer(FakeOutputSurface::Create3d());
scoped_ptr<LayerImpl> root_layer = LayerImpl::Create(active_tree(), 1);
+ root_layer->SetHasRenderSurface(true);
active_tree()->SetRootLayer(root_layer.Pass());
}
@@ -92,7 +89,8 @@ TEST_F(OcclusionTrackerPerfTest, UnoccludedContentRect_FullyOccluded) {
opaque_layer->SetContentBounds(viewport_rect.size());
active_tree()->root_layer()->AddChild(opaque_layer.Pass());
- active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ active_tree()->UpdateDrawProperties(update_lcd_text);
const LayerImplList& rsll = active_tree()->RenderSurfaceLayerList();
ASSERT_EQ(1u, rsll.size());
EXPECT_EQ(1u, rsll[0]->render_surface()->layer_list().size());
@@ -163,7 +161,8 @@ TEST_F(OcclusionTrackerPerfTest, UnoccludedContentRect_10OpaqueLayers) {
active_tree()->root_layer()->AddChild(opaque_layer.Pass());
}
- active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ active_tree()->UpdateDrawProperties(update_lcd_text);
const LayerImplList& rsll = active_tree()->RenderSurfaceLayerList();
ASSERT_EQ(1u, rsll.size());
EXPECT_EQ(static_cast<size_t>(kNumOpaqueLayers),
diff --git a/chromium/cc/trees/occlusion_tracker_unittest.cc b/chromium/cc/trees/occlusion_tracker_unittest.cc
index 75cd2438a7b..f3f218570eb 100644
--- a/chromium/cc/trees/occlusion_tracker_unittest.cc
+++ b/chromium/cc/trees/occlusion_tracker_unittest.cc
@@ -101,8 +101,9 @@ class TestOcclusionTrackerWithClip : public TestOcclusionTracker<LayerType> {
gfx::Rect UnoccludedSurfaceContentRect(const LayerType* layer,
const gfx::Rect& content_rect) const {
typename LayerType::RenderSurfaceType* surface = layer->render_surface();
- return this->UnoccludedContributingSurfaceContentRect(
- content_rect, surface->draw_transform());
+ return this->GetCurrentOcclusionForContributingSurface(
+ surface->draw_transform())
+ .GetUnoccludedContentRect(content_rect);
}
};
@@ -127,6 +128,9 @@ struct OcclusionTrackerTestMainThreadTypes {
*layer = NULL;
return ref;
}
+ static void SetForceRenderSurface(LayerType* layer, bool force) {
+ layer->SetForceRenderSurface(force);
+ }
static void DestroyLayer(LayerPtrType* layer) { *layer = NULL; }
@@ -156,6 +160,9 @@ struct OcclusionTrackerTestImplThreadTypes {
return layer->Pass();
}
+ static void SetForceRenderSurface(LayerType* layer, bool force) {
+ layer->SetHasRenderSurface(force);
+ }
static void DestroyLayer(LayerPtrType* layer) { layer->reset(); }
static void RecursiveUpdateNumChildren(LayerType* layer) {
@@ -174,7 +181,7 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
virtual void RunMyTest() = 0;
- virtual void TearDown() { DestroyLayers(); }
+ void TearDown() override { DestroyLayers(); }
typename Types::HostType* GetHost();
@@ -189,6 +196,7 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
DCHECK(!root_.get());
root_ = Types::PassLayerPtr(&layer);
+ Types::SetForceRenderSurface(layer_ptr, true);
SetRootLayerOnMainThread(layer_ptr);
return layer_ptr;
@@ -211,7 +219,7 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
const gfx::Size& bounds) {
typename Types::LayerType* layer =
CreateLayer(parent, transform, position, bounds);
- layer->SetForceRenderSurface(true);
+ Types::SetForceRenderSurface(layer, true);
return layer;
}
@@ -272,7 +280,7 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
bool opaque) {
typename Types::ContentLayerType* layer =
CreateDrawingLayer(parent, transform, position, bounds, opaque);
- layer->SetForceRenderSurface(true);
+ Types::SetForceRenderSurface(layer, true);
return layer;
}
@@ -300,12 +308,12 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
CopyOutputRequest::CreateBitmapRequest(base::Bind(
&OcclusionTrackerTest<Types>::CopyOutputCallback,
base::Unretained(this))));
+ layer->SetHasRenderSurface(true);
layer->PassCopyRequests(&requests);
}
void CalcDrawEtc(TestContentLayerImpl* root) {
DCHECK(root == root_.get());
- DCHECK(!root->render_surface());
Types::RecursiveUpdateNumChildren(root);
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
@@ -517,7 +525,7 @@ class OcclusionTrackerTestIdentityTransforms
explicit OcclusionTrackerTestIdentityTransforms(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* root = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(200, 200));
typename Types::ContentLayerType* parent = this->CreateDrawingLayer(
@@ -551,7 +559,7 @@ class OcclusionTrackerTestRotatedChild : public OcclusionTrackerTest<Types> {
protected:
explicit OcclusionTrackerTestRotatedChild(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform layer_transform;
layer_transform.Translate(250.0, 250.0);
layer_transform.Rotate(90.0);
@@ -590,7 +598,7 @@ class OcclusionTrackerTestTranslatedChild : public OcclusionTrackerTest<Types> {
protected:
explicit OcclusionTrackerTestTranslatedChild(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform layer_transform;
layer_transform.Translate(20.0, 20.0);
@@ -628,7 +636,7 @@ class OcclusionTrackerTestChildInRotatedChild
protected:
explicit OcclusionTrackerTestChildInRotatedChild(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform child_transform;
child_transform.Translate(250.0, 250.0);
child_transform.Rotate(90.0);
@@ -726,7 +734,7 @@ class OcclusionTrackerTestScaledRenderSurface
explicit OcclusionTrackerTestScaledRenderSurface(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(200, 200));
@@ -734,7 +742,7 @@ class OcclusionTrackerTestScaledRenderSurface
layer1_matrix.Scale(2.0, 2.0);
typename Types::ContentLayerType* layer1 = this->CreateDrawingLayer(
parent, layer1_matrix, gfx::PointF(), gfx::Size(100, 100), true);
- layer1->SetForceRenderSurface(true);
+ Types::SetForceRenderSurface(layer1, true);
gfx::Transform layer2_matrix;
layer2_matrix.Translate(25.0, 25.0);
@@ -769,7 +777,7 @@ class OcclusionTrackerTestVisitTargetTwoTimes
protected:
explicit OcclusionTrackerTestVisitTargetTwoTimes(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* root = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(200, 200));
typename Types::LayerType* surface = this->CreateSurface(
@@ -835,7 +843,7 @@ class OcclusionTrackerTestSurfaceRotatedOffAxis
protected:
explicit OcclusionTrackerTestSurfaceRotatedOffAxis(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform child_transform;
child_transform.Translate(250.0, 250.0);
child_transform.Rotate(95.0);
@@ -848,9 +856,8 @@ class OcclusionTrackerTestSurfaceRotatedOffAxis
this->identity_matrix, gfx::PointF(), gfx::Size(1000, 1000));
typename Types::ContentLayerType* parent = this->CreateDrawingLayer(
root, this->identity_matrix, gfx::PointF(), gfx::Size(100, 100), true);
- typename Types::LayerType* child = this->CreateLayer(
+ typename Types::LayerType* child = this->CreateSurface(
parent, child_transform, gfx::PointF(30.f, 30.f), gfx::Size(500, 500));
- child->SetMasksToBounds(true);
typename Types::ContentLayerType* layer = this->CreateDrawingLayer(
child, layer_transform, gfx::PointF(), gfx::Size(500, 500), true);
this->CalcDrawEtc(root);
@@ -887,7 +894,7 @@ class OcclusionTrackerTestSurfaceWithTwoOpaqueChildren
protected:
explicit OcclusionTrackerTestSurfaceWithTwoOpaqueChildren(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform child_transform;
child_transform.Translate(250.0, 250.0);
child_transform.Rotate(90.0);
@@ -975,7 +982,7 @@ class OcclusionTrackerTestOverlappingSurfaceSiblings
protected:
explicit OcclusionTrackerTestOverlappingSurfaceSiblings(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(100, 100));
parent->SetMasksToBounds(true);
@@ -1035,7 +1042,7 @@ class OcclusionTrackerTestOverlappingSurfaceSiblingsWithTwoTransforms
explicit OcclusionTrackerTestOverlappingSurfaceSiblingsWithTwoTransforms(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform child1_transform;
child1_transform.Translate(250.0, 250.0);
child1_transform.Rotate(-90.0);
@@ -1141,7 +1148,7 @@ class OcclusionTrackerTestFilters : public OcclusionTrackerTest<Types> {
protected:
explicit OcclusionTrackerTestFilters(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform layer_transform;
layer_transform.Translate(250.0, 250.0);
layer_transform.Rotate(90.0);
@@ -1169,14 +1176,17 @@ class OcclusionTrackerTestFilters : public OcclusionTrackerTest<Types> {
gfx::Size(500, 500),
true);
+ Types::SetForceRenderSurface(blur_layer, true);
FilterOperations filters;
filters.Append(FilterOperation::CreateBlurFilter(10.f));
blur_layer->SetFilters(filters);
+ Types::SetForceRenderSurface(opaque_layer, true);
filters.Clear();
filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
opaque_layer->SetFilters(filters);
+ Types::SetForceRenderSurface(opacity_layer, true);
filters.Clear();
filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
opacity_layer->SetFilters(filters);
@@ -1241,7 +1251,7 @@ class OcclusionTrackerTestReplicaDoesOcclude
protected:
explicit OcclusionTrackerTestReplicaDoesOcclude(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(100, 200));
typename Types::LayerType* surface = this->CreateDrawingSurface(
@@ -1275,7 +1285,7 @@ class OcclusionTrackerTestReplicaWithClipping
protected:
explicit OcclusionTrackerTestReplicaWithClipping(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(100, 170));
parent->SetMasksToBounds(true);
@@ -1317,7 +1327,7 @@ class OcclusionTrackerTestReplicaWithMask : public OcclusionTrackerTest<Types> {
protected:
explicit OcclusionTrackerTestReplicaWithMask(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(100, 200));
typename Types::LayerType* surface =
@@ -1357,7 +1367,7 @@ class OcclusionTrackerTestOpaqueContentsRegionEmpty
protected:
explicit OcclusionTrackerTestOpaqueContentsRegionEmpty(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(300, 300));
typename Types::ContentLayerType* layer =
@@ -1392,7 +1402,7 @@ class OcclusionTrackerTestOpaqueContentsRegionNonEmpty
protected:
explicit OcclusionTrackerTestOpaqueContentsRegionNonEmpty(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(300, 300));
typename Types::ContentLayerType* layer =
@@ -1449,7 +1459,7 @@ class OcclusionTrackerTestUnsorted3dLayers
protected:
explicit OcclusionTrackerTestUnsorted3dLayers(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
// Currently, The main thread layer iterator does not iterate over 3d items
// in sorted order, because layer sorting is not performed on the main
// thread. Because of this, the occlusion tracker cannot assume that a 3d
@@ -1502,7 +1512,7 @@ class OcclusionTrackerTestLayerBehindCameraDoesNotOcclude
explicit OcclusionTrackerTestLayerBehindCameraDoesNotOcclude(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform transform;
transform.Translate(50.0, 50.0);
transform.ApplyPerspectiveDepth(100.0);
@@ -1530,63 +1540,13 @@ class OcclusionTrackerTestLayerBehindCameraDoesNotOcclude
}
};
-// This test requires accumulating occlusion of 3d layers, which are skipped by
-// the occlusion tracker on the main thread. So this test should run on the impl
-// thread.
-IMPL_THREAD_TEST(OcclusionTrackerTestLayerBehindCameraDoesNotOcclude);
-
-template <class Types>
-class OcclusionTrackerTestLargePixelsOccludeInsideClipRect
- : public OcclusionTrackerTest<Types> {
- protected:
- explicit OcclusionTrackerTestLargePixelsOccludeInsideClipRect(
- bool opaque_layers)
- : OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
- gfx::Transform transform;
- transform.Translate(50.0, 50.0);
- transform.ApplyPerspectiveDepth(100.0);
- transform.Translate3d(0.0, 0.0, 99.0);
- transform.Translate(-50.0, -50.0);
-
- typename Types::ContentLayerType* parent = this->CreateRoot(
- this->identity_matrix, gfx::PointF(), gfx::Size(100, 100));
- parent->SetMasksToBounds(true);
- typename Types::ContentLayerType* layer = this->CreateDrawingLayer(
- parent, transform, gfx::PointF(), gfx::Size(100, 100), true);
- parent->SetShouldFlattenTransform(false);
- parent->Set3dSortingContextId(1);
- layer->SetShouldFlattenTransform(false);
- layer->Set3dSortingContextId(1);
- this->CalcDrawEtc(parent);
-
- TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
- gfx::Rect(0, 0, 1000, 1000));
-
- // This is very close to the camera, so pixels in its visible_content_rect()
- // will actually go outside of the layer's clip rect. Ensure that those
- // pixels don't occlude things outside the clip rect.
- this->VisitLayer(layer, &occlusion);
- this->EnterLayer(parent, &occlusion);
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- occlusion.occlusion_from_inside_target().ToString());
- EXPECT_EQ(gfx::Rect().ToString(),
- occlusion.occlusion_from_outside_target().ToString());
- }
-};
-
-// This test requires accumulating occlusion of 3d layers, which are skipped by
-// the occlusion tracker on the main thread. So this test should run on the impl
-// thread.
-IMPL_THREAD_TEST(OcclusionTrackerTestLargePixelsOccludeInsideClipRect);
-
template <class Types>
class OcclusionTrackerTestAnimationOpacity1OnMainThread
: public OcclusionTrackerTest<Types> {
protected:
explicit OcclusionTrackerTestAnimationOpacity1OnMainThread(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
// parent
// +--layer
// +--surface
@@ -1705,7 +1665,7 @@ class OcclusionTrackerTestAnimationOpacity0OnMainThread
protected:
explicit OcclusionTrackerTestAnimationOpacity0OnMainThread(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(300, 300));
typename Types::ContentLayerType* layer =
@@ -1816,7 +1776,7 @@ class OcclusionTrackerTestAnimationTranslateOnMainThread
explicit OcclusionTrackerTestAnimationTranslateOnMainThread(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(300, 300));
typename Types::ContentLayerType* layer =
@@ -1946,7 +1906,7 @@ class OcclusionTrackerTestSurfaceOcclusionTranslatesToParent
explicit OcclusionTrackerTestSurfaceOcclusionTranslatesToParent(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform surface_transform;
surface_transform.Translate(300.0, 300.0);
surface_transform.Scale(2.0, 2.0);
@@ -2001,7 +1961,7 @@ class OcclusionTrackerTestSurfaceOcclusionTranslatesWithClipping
explicit OcclusionTrackerTestSurfaceOcclusionTranslatesWithClipping(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(300, 300));
parent->SetMasksToBounds(true);
@@ -2036,7 +1996,7 @@ class OcclusionTrackerTestSurfaceWithReplicaUnoccluded
protected:
explicit OcclusionTrackerTestSurfaceWithReplicaUnoccluded(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* parent = this->CreateRoot(
this->identity_matrix, gfx::PointF(), gfx::Size(100, 200));
typename Types::LayerType* surface =
@@ -2096,7 +2056,7 @@ class OcclusionTrackerTestSurfaceChildOfSurface
protected:
explicit OcclusionTrackerTestSurfaceChildOfSurface(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
// This test verifies that the surface cliprect does not end up empty and
// clip away the entire unoccluded rect.
@@ -2194,7 +2154,7 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter
explicit OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform scale_by_half;
scale_by_half.Scale(0.5, 0.5);
@@ -2229,8 +2189,8 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter
gfx::PointF(50.f, 50.f),
gfx::Size(100, 100),
false);
+ Types::SetForceRenderSurface(filtered_surface, true);
filtered_surface->SetBackgroundFilters(filters);
-
gfx::Rect occlusion_rect;
switch (i) {
case LEFT:
@@ -2318,7 +2278,7 @@ class OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice
explicit OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform scale_by_half;
scale_by_half.Scale(0.5, 0.5);
@@ -2341,6 +2301,8 @@ class OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice
true);
// Filters make the layers own surfaces.
+ Types::SetForceRenderSurface(filtered_surface1, true);
+ Types::SetForceRenderSurface(filtered_surface2, true);
FilterOperations filters;
filters.Append(FilterOperation::CreateBlurFilter(1.f));
filtered_surface1->SetBackgroundFilters(filters);
@@ -2393,7 +2355,7 @@ class OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter
explicit OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform scale_by_half;
scale_by_half.Scale(0.5, 0.5);
@@ -2427,6 +2389,7 @@ class OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter
gfx::Size());
// Filters make the layer own a surface.
+ Types::SetForceRenderSurface(filtered_surface, true);
FilterOperations filters;
filters.Append(FilterOperation::CreateBlurFilter(3.f));
filtered_surface->SetBackgroundFilters(filters);
@@ -2477,7 +2440,7 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded
explicit OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform scale_by_half;
scale_by_half.Scale(0.5, 0.5);
@@ -2501,6 +2464,7 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded
true);
// Filters make the layer own a surface.
+ Types::SetForceRenderSurface(filtered_surface, true);
FilterOperations filters;
filters.Append(FilterOperation::CreateBlurFilter(3.f));
filtered_surface->SetBackgroundFilters(filters);
@@ -2550,7 +2514,7 @@ class OcclusionTrackerTestReduceOcclusionWhenBackgroundFilterIsPartiallyOccluded
OcclusionTrackerTestReduceOcclusionWhenBackgroundFilterIsPartiallyOccluded(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform scale_by_half;
scale_by_half.Scale(0.5, 0.5);
@@ -2597,6 +2561,7 @@ class OcclusionTrackerTestReduceOcclusionWhenBackgroundFilterIsPartiallyOccluded
true);
// Filters make the layer own a surface.
+ Types::SetForceRenderSurface(filtered_surface, true);
FilterOperations filters;
filters.Append(FilterOperation::CreateBlurFilter(3.f));
filtered_surface->SetBackgroundFilters(filters);
@@ -2657,12 +2622,59 @@ ALL_OCCLUSIONTRACKER_TEST(
OcclusionTrackerTestReduceOcclusionWhenBackgroundFilterIsPartiallyOccluded);
template <class Types>
+class OcclusionTrackerTestBlendModeDoesNotOcclude
+ : public OcclusionTrackerTest<Types> {
+ protected:
+ explicit OcclusionTrackerTestBlendModeDoesNotOcclude(bool opaque_layers)
+ : OcclusionTrackerTest<Types>(opaque_layers) {}
+ void RunMyTest() override {
+ typename Types::ContentLayerType* parent = this->CreateRoot(
+ this->identity_matrix, gfx::PointF(), gfx::Size(100, 100));
+ typename Types::LayerType* blend_mode_layer = this->CreateDrawingLayer(
+ parent, this->identity_matrix, gfx::PointF(0.f, 0.f),
+ gfx::Size(100, 100), true);
+ typename Types::LayerType* top_layer = this->CreateDrawingLayer(
+ parent, this->identity_matrix, gfx::PointF(10.f, 12.f),
+ gfx::Size(20, 22), true);
+
+ // Blend mode makes the layer own a surface.
+ Types::SetForceRenderSurface(blend_mode_layer, true);
+ blend_mode_layer->SetBlendMode(SkXfermode::kMultiply_Mode);
+
+ this->CalcDrawEtc(parent);
+
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
+ gfx::Rect(0, 0, 1000, 1000));
+
+ this->VisitLayer(top_layer, &occlusion);
+ // |top_layer| occludes.
+ EXPECT_EQ(gfx::Rect(10, 12, 20, 22).ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
+ EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty());
+
+ this->VisitLayer(blend_mode_layer, &occlusion);
+ // |top_layer| occludes but not |blend_mode_layer|.
+ EXPECT_EQ(gfx::Rect(10, 12, 20, 22).ToString(),
+ occlusion.occlusion_from_outside_target().ToString());
+ EXPECT_TRUE(occlusion.occlusion_from_inside_target().IsEmpty());
+
+ this->VisitContributingSurface(blend_mode_layer, &occlusion);
+ // |top_layer| occludes but not |blend_mode_layer|.
+ EXPECT_EQ(gfx::Rect(10, 12, 20, 22).ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
+ EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty());
+ }
+};
+
+ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestBlendModeDoesNotOcclude);
+
+template <class Types>
class OcclusionTrackerTestMinimumTrackingSize
: public OcclusionTrackerTest<Types> {
protected:
explicit OcclusionTrackerTestMinimumTrackingSize(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Size tracking_size(100, 100);
gfx::Size below_tracking_size(99, 99);
@@ -2708,7 +2720,7 @@ class OcclusionTrackerTestScaledLayerIsClipped
protected:
explicit OcclusionTrackerTestScaledLayerIsClipped(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform scale_transform;
scale_transform.Scale(512.0, 512.0);
@@ -2745,7 +2757,7 @@ class OcclusionTrackerTestScaledLayerInSurfaceIsClipped
protected:
explicit OcclusionTrackerTestScaledLayerInSurfaceIsClipped(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform scale_transform;
scale_transform.Scale(512.0, 512.0);
@@ -2786,7 +2798,7 @@ class OcclusionTrackerTestCopyRequestDoesOcclude
protected:
explicit OcclusionTrackerTestCopyRequestDoesOcclude(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* root = this->CreateRoot(
this->identity_matrix, gfx::Point(), gfx::Size(400, 400));
typename Types::ContentLayerType* parent = this->CreateDrawingLayer(
@@ -2802,12 +2814,22 @@ class OcclusionTrackerTestCopyRequestDoesOcclude
gfx::PointF(),
gfx::Size(200, 400),
true);
+ typename Types::LayerType* top_layer =
+ this->CreateDrawingLayer(root, this->identity_matrix,
+ gfx::PointF(50, 0), gfx::Size(50, 400), true);
this->CalcDrawEtc(root);
TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
+ this->VisitLayer(top_layer, &occlusion);
+ EXPECT_EQ(gfx::Rect().ToString(),
+ occlusion.occlusion_from_outside_target().ToString());
+ EXPECT_EQ(gfx::Rect(50, 0, 50, 400).ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
+
this->VisitLayer(copy_child, &occlusion);
+ // Layers outside the copy request do not occlude.
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
EXPECT_EQ(gfx::Rect(200, 400).ToString(),
@@ -2819,7 +2841,7 @@ class OcclusionTrackerTestCopyRequestDoesOcclude
// The occlusion from the copy should be kept.
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
- EXPECT_EQ(gfx::Rect(100, 0, 200, 400).ToString(),
+ EXPECT_EQ(gfx::Rect(50, 0, 250, 400).ToString(),
occlusion.occlusion_from_inside_target().ToString());
}
};
@@ -2833,7 +2855,7 @@ class OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude
explicit OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude(
bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
typename Types::ContentLayerType* root = this->CreateRoot(
this->identity_matrix, gfx::Point(), gfx::Size(400, 400));
typename Types::ContentLayerType* parent = this->CreateDrawingLayer(
@@ -2879,7 +2901,7 @@ class OcclusionTrackerTestOccludedLayer : public OcclusionTrackerTest<Types> {
protected:
explicit OcclusionTrackerTestOccludedLayer(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform translate;
translate.Translate(10.0, 20.0);
typename Types::ContentLayerType* root = this->CreateRoot(
@@ -2970,7 +2992,7 @@ class OcclusionTrackerTestUnoccludedLayerQuery
protected:
explicit OcclusionTrackerTestUnoccludedLayerQuery(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform translate;
translate.Translate(10.0, 20.0);
typename Types::ContentLayerType* root = this->CreateRoot(
@@ -3136,7 +3158,7 @@ class OcclusionTrackerTestUnoccludedSurfaceQuery
protected:
explicit OcclusionTrackerTestUnoccludedSurfaceQuery(bool opaque_layers)
: OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
+ void RunMyTest() override {
gfx::Transform translate;
translate.Translate(10.0, 20.0);
typename Types::ContentLayerType* root = this->CreateRoot(
diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc
new file mode 100644
index 00000000000..d369ad91060
--- /dev/null
+++ b/chromium/cc/trees/property_tree.cc
@@ -0,0 +1,388 @@
+// Copyright 2014 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 <set>
+#include <vector>
+
+#include "base/logging.h"
+#include "cc/base/math_util.h"
+#include "cc/trees/property_tree.h"
+
+namespace cc {
+
+template <typename T>
+PropertyTree<T>::PropertyTree()
+ : needs_update_(false) {
+ nodes_.push_back(T());
+ back()->id = 0;
+ back()->parent_id = -1;
+}
+
+template <typename T>
+PropertyTree<T>::~PropertyTree() {
+}
+
+template <typename T>
+int PropertyTree<T>::Insert(const T& tree_node, int parent_id) {
+ DCHECK_GT(nodes_.size(), 0u);
+ nodes_.push_back(tree_node);
+ T& node = nodes_.back();
+ node.parent_id = parent_id;
+ node.id = static_cast<int>(nodes_.size()) - 1;
+ return node.id;
+}
+
+template <typename T>
+void PropertyTree<T>::clear() {
+ nodes_.clear();
+ nodes_.push_back(T());
+ back()->id = 0;
+ back()->parent_id = -1;
+}
+
+template class PropertyTree<TransformNode>;
+template class PropertyTree<ClipNode>;
+template class PropertyTree<OpacityNode>;
+
+TransformNodeData::TransformNodeData()
+ : target_id(-1),
+ content_target_id(-1),
+ source_node_id(-1),
+ needs_local_transform_update(true),
+ is_invertible(true),
+ ancestors_are_invertible(true),
+ is_animated(false),
+ to_screen_is_animated(false),
+ flattens_inherited_transform(false),
+ node_and_ancestors_are_flat(true),
+ scrolls(false),
+ needs_sublayer_scale(false),
+ layer_scale_factor(1.0f) {
+}
+
+TransformNodeData::~TransformNodeData() {
+}
+
+void TransformNodeData::update_pre_local_transform(
+ const gfx::Point3F& transform_origin) {
+ pre_local.MakeIdentity();
+ pre_local.Translate3d(-transform_origin.x(), -transform_origin.y(),
+ -transform_origin.z());
+}
+
+void TransformNodeData::update_post_local_transform(
+ const gfx::PointF& position,
+ const gfx::Point3F& transform_origin) {
+ post_local.MakeIdentity();
+ post_local.Scale(post_local_scale_factor, post_local_scale_factor);
+ post_local.Translate3d(
+ position.x() + source_offset.x() + transform_origin.x(),
+ position.y() + source_offset.y() + transform_origin.y(),
+ transform_origin.z());
+}
+
+ClipNodeData::ClipNodeData() : transform_id(-1), target_id(-1) {
+}
+
+bool TransformTree::ComputeTransform(int source_id,
+ int dest_id,
+ gfx::Transform* transform) const {
+ transform->MakeIdentity();
+
+ if (source_id == dest_id)
+ return true;
+
+ if (source_id > dest_id) {
+ return CombineTransformsBetween(source_id, dest_id, transform);
+ }
+
+ return CombineInversesBetween(source_id, dest_id, transform);
+}
+
+bool TransformTree::ComputeTransformWithDestinationSublayerScale(
+ int source_id,
+ int dest_id,
+ gfx::Transform* transform) const {
+ bool success = ComputeTransform(source_id, dest_id, transform);
+
+ const TransformNode* dest_node = Node(dest_id);
+ if (!dest_node->data.needs_sublayer_scale)
+ return success;
+
+ transform->matrix().postScale(dest_node->data.sublayer_scale.x(),
+ dest_node->data.sublayer_scale.y(), 1.f);
+ return success;
+}
+
+bool TransformTree::ComputeTransformWithSourceSublayerScale(
+ int source_id,
+ int dest_id,
+ gfx::Transform* transform) const {
+ bool success = ComputeTransform(source_id, dest_id, transform);
+
+ const TransformNode* source_node = Node(source_id);
+ if (!source_node->data.needs_sublayer_scale)
+ return success;
+
+ transform->Scale(1.f / source_node->data.sublayer_scale.x(),
+ 1.f / source_node->data.sublayer_scale.y());
+ return success;
+}
+
+bool TransformTree::Are2DAxisAligned(int source_id, int dest_id) const {
+ gfx::Transform transform;
+ return ComputeTransform(source_id, dest_id, &transform) &&
+ transform.Preserves2dAxisAlignment();
+}
+
+void TransformTree::UpdateTransforms(int id) {
+ TransformNode* node = Node(id);
+ TransformNode* parent_node = parent(node);
+ TransformNode* target_node = Node(node->data.target_id);
+ if (node->data.needs_local_transform_update ||
+ node->parent_id != node->data.source_node_id)
+ UpdateLocalTransform(node);
+ UpdateScreenSpaceTransform(node, parent_node, target_node);
+ UpdateSublayerScale(node);
+ UpdateTargetSpaceTransform(node, target_node);
+ UpdateIsAnimated(node, parent_node);
+ UpdateSnapping(node);
+}
+
+bool TransformTree::IsDescendant(int desc_id, int source_id) const {
+ while (desc_id != source_id) {
+ if (desc_id < 0)
+ return false;
+ desc_id = Node(desc_id)->parent_id;
+ }
+ return true;
+}
+
+bool TransformTree::CombineTransformsBetween(int source_id,
+ int dest_id,
+ gfx::Transform* transform) const {
+ DCHECK(source_id > dest_id);
+ const TransformNode* current = Node(source_id);
+ const TransformNode* dest = Node(dest_id);
+ // Combine transforms to and from the screen when possible. Since flattening
+ // is a non-linear operation, we cannot use this approach when there is
+ // non-trivial flattening between the source and destination nodes. For
+ // example, consider the tree R->A->B->C, where B flattens its inherited
+ // transform, and A has a non-flat transform. Suppose C is the source and A is
+ // the destination. The expected result is C * B. But C's to_screen
+ // transform is C * B * flattened(A * R), and A's from_screen transform is
+ // R^{-1} * A^{-1}. If at least one of A and R isn't flat, the inverse of
+ // flattened(A * R) won't be R^{-1} * A{-1}, so multiplying C's to_screen and
+ // A's from_screen will not produce the correct result.
+ if (!dest || (dest->data.ancestors_are_invertible &&
+ dest->data.node_and_ancestors_are_flat)) {
+ transform->ConcatTransform(current->data.to_screen);
+ if (dest)
+ transform->ConcatTransform(dest->data.from_screen);
+ return true;
+ }
+
+ // Flattening is defined in a way that requires it to be applied while
+ // traversing downward in the tree. We first identify nodes that are on the
+ // path from the source to the destination (this is traversing upward), and
+ // then we visit these nodes in reverse order, flattening as needed. We
+ // early-out if we get to a node whose target node is the destination, since
+ // we can then re-use the target space transform stored at that node.
+ std::vector<int> source_to_destination;
+ source_to_destination.push_back(current->id);
+ current = parent(current);
+ for (; current && current->id > dest_id; current = parent(current)) {
+ if (current->data.target_id == dest_id &&
+ current->data.content_target_id == dest_id)
+ break;
+ source_to_destination.push_back(current->id);
+ }
+
+ gfx::Transform combined_transform;
+ if (current->id > dest_id) {
+ combined_transform = current->data.to_target;
+ // The stored target space transform has sublayer scale baked in, but we
+ // need the unscaled transform.
+ combined_transform.Scale(1.0f / dest->data.sublayer_scale.x(),
+ 1.0f / dest->data.sublayer_scale.y());
+ } else if (current->id < dest_id) {
+ // We have reached the lowest common ancestor of the source and destination
+ // nodes. This case can occur when we are transforming between a node
+ // corresponding to a fixed-position layer (or its descendant) and the node
+ // corresponding to the layer's render target. For example, consider the
+ // layer tree R->T->S->F where F is fixed-position, S owns a render surface,
+ // and T has a significant transform. This will yield the following
+ // transform tree:
+ // R
+ // |
+ // T
+ // /|
+ // S F
+ // In this example, T will have id 2, S will have id 3, and F will have id
+ // 4. When walking up the ancestor chain from F, the first node with a
+ // smaller id than S will be T, the lowest common ancestor of these nodes.
+ // We compute the transform from T to S here, and then from F to T in the
+ // loop below.
+ DCHECK(IsDescendant(dest_id, current->id));
+ CombineInversesBetween(current->id, dest_id, &combined_transform);
+ DCHECK(combined_transform.IsApproximatelyIdentityOrTranslation(
+ SkDoubleToMScalar(1e-4)));
+ }
+
+ for (int i = source_to_destination.size() - 1; i >= 0; i--) {
+ const TransformNode* node = Node(source_to_destination[i]);
+ if (node->data.flattens_inherited_transform)
+ combined_transform.FlattenTo2d();
+ combined_transform.PreconcatTransform(node->data.to_parent);
+ }
+
+ transform->ConcatTransform(combined_transform);
+ return true;
+}
+
+bool TransformTree::CombineInversesBetween(int source_id,
+ int dest_id,
+ gfx::Transform* transform) const {
+ DCHECK(source_id < dest_id);
+ const TransformNode* current = Node(dest_id);
+ const TransformNode* dest = Node(source_id);
+ // Just as in CombineTransformsBetween, we can use screen space transforms in
+ // this computation only when there isn't any non-trivial flattening
+ // involved.
+ if (current->data.ancestors_are_invertible &&
+ current->data.node_and_ancestors_are_flat) {
+ transform->PreconcatTransform(current->data.from_screen);
+ if (dest)
+ transform->PreconcatTransform(dest->data.to_screen);
+ return true;
+ }
+
+ // Inverting a flattening is not equivalent to flattening an inverse. This
+ // means we cannot, for example, use the inverse of each node's to_parent
+ // transform, flattening where needed. Instead, we must compute the transform
+ // from the destination to the source, with flattening, and then invert the
+ // result.
+ gfx::Transform dest_to_source;
+ CombineTransformsBetween(dest_id, source_id, &dest_to_source);
+ gfx::Transform source_to_dest;
+ bool all_are_invertible = dest_to_source.GetInverse(&source_to_dest);
+ transform->PreconcatTransform(source_to_dest);
+ return all_are_invertible;
+}
+
+void TransformTree::UpdateLocalTransform(TransformNode* node) {
+ gfx::Transform transform = node->data.post_local;
+ gfx::Vector2dF source_to_parent;
+ if (node->parent_id != node->data.source_node_id) {
+ gfx::Transform to_parent;
+ ComputeTransform(node->data.source_node_id, node->parent_id, &to_parent);
+ source_to_parent = to_parent.To2dTranslation();
+ }
+ transform.Translate(source_to_parent.x() - node->data.scroll_offset.x(),
+ source_to_parent.y() - node->data.scroll_offset.y());
+ transform.PreconcatTransform(node->data.local);
+ transform.PreconcatTransform(node->data.pre_local);
+ node->data.set_to_parent(transform);
+ node->data.needs_local_transform_update = false;
+}
+
+void TransformTree::UpdateScreenSpaceTransform(TransformNode* node,
+ TransformNode* parent_node,
+ TransformNode* target_node) {
+ if (!parent_node) {
+ node->data.to_screen = node->data.to_parent;
+ node->data.ancestors_are_invertible = true;
+ node->data.to_screen_is_animated = false;
+ node->data.node_and_ancestors_are_flat = node->data.to_parent.IsFlat();
+ } else {
+ node->data.to_screen = parent_node->data.to_screen;
+ if (node->data.flattens_inherited_transform)
+ node->data.to_screen.FlattenTo2d();
+ node->data.to_screen.PreconcatTransform(node->data.to_parent);
+ node->data.ancestors_are_invertible =
+ parent_node->data.ancestors_are_invertible;
+ node->data.node_and_ancestors_are_flat =
+ parent_node->data.node_and_ancestors_are_flat &&
+ node->data.to_parent.IsFlat();
+ }
+
+ if (!node->data.to_screen.GetInverse(&node->data.from_screen))
+ node->data.ancestors_are_invertible = false;
+}
+
+void TransformTree::UpdateSublayerScale(TransformNode* node) {
+ // The sublayer scale depends on the screen space transform, so update it too.
+ node->data.sublayer_scale =
+ node->data.needs_sublayer_scale
+ ? MathUtil::ComputeTransform2dScaleComponents(
+ node->data.to_screen, node->data.layer_scale_factor)
+ : gfx::Vector2dF(1.0f, 1.0f);
+}
+
+void TransformTree::UpdateTargetSpaceTransform(TransformNode* node,
+ TransformNode* target_node) {
+ if (node->data.needs_sublayer_scale) {
+ node->data.to_target.MakeIdentity();
+ node->data.to_target.Scale(node->data.sublayer_scale.x(),
+ node->data.sublayer_scale.y());
+ } else {
+ const bool target_is_root_surface = target_node->id == 1;
+ // In order to include the root transform for the root surface, we walk up
+ // to the root of the transform tree in ComputeTransform.
+ int target_id = target_is_root_surface ? 0 : target_node->id;
+ ComputeTransformWithDestinationSublayerScale(node->id, target_id,
+ &node->data.to_target);
+ }
+
+ if (!node->data.to_target.GetInverse(&node->data.from_target))
+ node->data.ancestors_are_invertible = false;
+}
+
+void TransformTree::UpdateIsAnimated(TransformNode* node,
+ TransformNode* parent_node) {
+ if (parent_node) {
+ node->data.to_screen_is_animated =
+ node->data.is_animated || parent_node->data.to_screen_is_animated;
+ }
+}
+
+void TransformTree::UpdateSnapping(TransformNode* node) {
+ if (!node->data.scrolls || node->data.to_screen_is_animated ||
+ !node->data.to_target.IsScaleOrTranslation()) {
+ return;
+ }
+
+ // Scroll snapping must be done in target space (the pixels we care about).
+ // This means we effectively snap the target space transform. If TT is the
+ // target space transform and TT' is TT with its translation components
+ // rounded, then what we're after is the scroll delta X, where TT * X = TT'.
+ // I.e., we want a transform that will realize our scroll snap. It follows
+ // that X = TT^-1 * TT'. We cache TT and TT^-1 to make this more efficient.
+ gfx::Transform rounded = node->data.to_target;
+ rounded.RoundTranslationComponents();
+ gfx::Transform delta = node->data.from_target;
+ delta *= rounded;
+
+ DCHECK(delta.IsApproximatelyIdentityOrTranslation(SkDoubleToMScalar(1e-4)))
+ << delta.ToString();
+
+ gfx::Vector2dF translation = delta.To2dTranslation();
+
+ // Now that we have our scroll delta, we must apply it to each of our
+ // combined, to/from matrices.
+ node->data.to_parent.Translate(translation.x(), translation.y());
+ node->data.to_target.Translate(translation.x(), translation.y());
+ node->data.from_target.matrix().postTranslate(-translation.x(),
+ -translation.y(), 0);
+ node->data.to_screen.Translate(translation.x(), translation.y());
+ node->data.from_screen.matrix().postTranslate(-translation.x(),
+ -translation.y(), 0);
+
+ node->data.scroll_snap = translation;
+}
+
+PropertyTrees::PropertyTrees() : needs_rebuild(true), sequence_number(0) {
+}
+
+} // namespace cc
diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h
new file mode 100644
index 00000000000..caa819c6c6d
--- /dev/null
+++ b/chromium/cc/trees/property_tree.h
@@ -0,0 +1,261 @@
+// Copyright 2014 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_PROPERTY_TREE_H_
+#define CC_TREES_PROPERTY_TREE_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "cc/base/cc_export.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+
+template <typename T>
+struct CC_EXPORT TreeNode {
+ TreeNode() : id(-1), parent_id(-1), owner_id(-1), data() {}
+ int id;
+ int parent_id;
+ int owner_id;
+ T data;
+};
+
+struct CC_EXPORT TransformNodeData {
+ TransformNodeData();
+ ~TransformNodeData();
+
+ // The local transform information is combined to form to_parent (ignoring
+ // snapping) as follows:
+ //
+ // to_parent = M_post_local * T_scroll * M_local * M_pre_local.
+ //
+ // The pre/post may seem odd when read LTR, but we multiply our points from
+ // the right, so the pre_local matrix affects the result "first". This lines
+ // up with the notions of pre/post used in skia and gfx::Transform.
+ //
+ // TODO(vollick): The values labeled with "will be moved..." take up a lot of
+ // space, but are only necessary for animated or scrolled nodes (otherwise
+ // we'll just use the baked to_parent). These values will be ultimately stored
+ // directly on the transform/scroll display list items when that's possible,
+ // or potentially in a scroll tree.
+ //
+ // TODO(vollick): will be moved when accelerated effects are implemented.
+ gfx::Transform pre_local;
+ gfx::Transform local;
+ gfx::Transform post_local;
+
+ gfx::Transform to_parent;
+
+ gfx::Transform to_target;
+ gfx::Transform from_target;
+
+ gfx::Transform to_screen;
+ gfx::Transform from_screen;
+
+ int target_id;
+ // This id is used for all content that draws into a render surface associated
+ // with this transform node.
+ int content_target_id;
+
+ // This is the node with respect to which source_offset is defined. This will
+ // not be needed once layerization moves to cc, but is needed in order to
+ // efficiently update the transform tree for changes to position in the layer
+ // tree.
+ int source_node_id;
+
+ // TODO(vollick): will be moved when accelerated effects are implemented.
+ bool needs_local_transform_update;
+
+ bool is_invertible;
+ bool ancestors_are_invertible;
+
+ bool is_animated;
+ bool to_screen_is_animated;
+
+ // Flattening, when needed, is only applied to a node's inherited transform,
+ // never to its local transform.
+ bool flattens_inherited_transform;
+
+ // This is true if the to_parent transform at every node on the path to the
+ // root is flat.
+ bool node_and_ancestors_are_flat;
+
+ bool scrolls;
+
+ bool needs_sublayer_scale;
+ // This is used as a fallback when we either cannot adjust raster scale or if
+ // the raster scale cannot be extracted from the screen space transform.
+ float layer_scale_factor;
+
+ // TODO(vollick): will be moved when accelerated effects are implemented.
+ float post_local_scale_factor;
+
+ gfx::Vector2dF sublayer_scale;
+
+ // TODO(vollick): will be moved when accelerated effects are implemented.
+ gfx::Vector2dF scroll_offset;
+
+ // We scroll snap where possible, but this has an effect on scroll
+ // compensation: the snap is yet more scrolling that must be compensated for.
+ // This value stores the snapped amount for this purpose.
+ gfx::Vector2dF scroll_snap;
+
+ // TODO(vollick): will be moved when accelerated effects are implemented.
+ gfx::Vector2dF source_offset;
+
+ void set_to_parent(const gfx::Transform& transform) {
+ to_parent = transform;
+ is_invertible = to_parent.IsInvertible();
+ }
+
+ void update_pre_local_transform(const gfx::Point3F& transform_origin);
+
+ void update_post_local_transform(const gfx::PointF& position,
+ const gfx::Point3F& transform_origin);
+};
+
+typedef TreeNode<TransformNodeData> TransformNode;
+
+struct CC_EXPORT ClipNodeData {
+ ClipNodeData();
+
+ gfx::RectF clip;
+ gfx::RectF combined_clip;
+ int transform_id;
+ int target_id;
+};
+
+typedef TreeNode<ClipNodeData> ClipNode;
+
+typedef TreeNode<float> OpacityNode;
+
+template <typename T>
+class CC_EXPORT PropertyTree {
+ public:
+ PropertyTree();
+ virtual ~PropertyTree();
+
+ int Insert(const T& tree_node, int parent_id);
+
+ T* Node(int i) {
+ // TODO(vollick): remove this.
+ CHECK(i < static_cast<int>(nodes_.size()));
+ return i > -1 ? &nodes_[i] : nullptr;
+ }
+ const T* Node(int i) const {
+ // TODO(vollick): remove this.
+ CHECK(i < static_cast<int>(nodes_.size()));
+ return i > -1 ? &nodes_[i] : nullptr;
+ }
+
+ T* parent(const T* t) { return Node(t->parent_id); }
+ const T* parent(const T* t) const { return Node(t->parent_id); }
+
+ T* back() { return size() ? &nodes_[nodes_.size() - 1] : nullptr; }
+ const T* back() const {
+ return size() ? &nodes_[nodes_.size() - 1] : nullptr;
+ }
+
+ void clear();
+ size_t size() const { return nodes_.size(); }
+
+ void set_needs_update(bool needs_update) { needs_update_ = needs_update; }
+ bool needs_update() const { return needs_update_; }
+
+ private:
+ // Copy and assign are permitted. This is how we do tree sync.
+ std::vector<T> nodes_;
+
+ bool needs_update_;
+};
+
+class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
+ public:
+ // Computes the change of basis transform from node |source_id| to |dest_id|.
+ // The function returns false iff the inverse of a singular transform was
+ // used (and the result should, therefore, not be trusted). Transforms may
+ // be computed between any pair of nodes that have an ancestor/descendant
+ // relationship. Transforms between other pairs of nodes may only be computed
+ // if the following condition holds: let id1 the larger id and let id2 be the
+ // other id; then the nearest ancestor of node id1 whose id is smaller than
+ // id2 is the lowest common ancestor of the pair of nodes, and the transform
+ // from this lowest common ancestor to node id2 is only a 2d translation.
+ bool ComputeTransform(int source_id,
+ int dest_id,
+ gfx::Transform* transform) const;
+
+ // Computes the change of basis transform from node |source_id| to |dest_id|,
+ // including any sublayer scale at |dest_id|. The function returns false iff
+ // the inverse of a singular transform was used (and the result should,
+ // therefore, not be trusted).
+ bool ComputeTransformWithDestinationSublayerScale(
+ int source_id,
+ int dest_id,
+ gfx::Transform* transform) const;
+
+ // Computes the change of basis transform from node |source_id| to |dest_id|,
+ // including any sublayer scale at |source_id|. The function returns false
+ // iff the inverse of a singular transform was used (and the result should,
+ // therefore, not be trusted).
+ bool ComputeTransformWithSourceSublayerScale(int source_id,
+ int dest_id,
+ gfx::Transform* transform) const;
+
+ // Returns true iff the nodes indexed by |source_id| and |dest_id| are 2D axis
+ // aligned with respect to one another.
+ bool Are2DAxisAligned(int source_id, int dest_id) const;
+
+ // Updates the parent, target, and screen space transforms and snapping.
+ void UpdateTransforms(int id);
+
+ private:
+ // Returns true iff the node at |desc_id| is a descendant of the node at
+ // |anc_id|.
+ bool IsDescendant(int desc_id, int anc_id) const;
+
+ // Computes the combined transform between |source_id| and |dest_id| and
+ // returns false if the inverse of a singular transform was used. These two
+ // nodes must be on the same ancestor chain.
+ bool CombineTransformsBetween(int source_id,
+ int dest_id,
+ gfx::Transform* transform) const;
+
+ // Computes the combined inverse transform between |source_id| and |dest_id|
+ // and returns false if the inverse of a singular transform was used. These
+ // two nodes must be on the same ancestor chain.
+ bool CombineInversesBetween(int source_id,
+ int dest_id,
+ gfx::Transform* transform) const;
+
+ void UpdateLocalTransform(TransformNode* node);
+ void UpdateScreenSpaceTransform(TransformNode* node,
+ TransformNode* parent_node,
+ TransformNode* target_node);
+ void UpdateSublayerScale(TransformNode* node);
+ void UpdateTargetSpaceTransform(TransformNode* node,
+ TransformNode* target_node);
+ void UpdateIsAnimated(TransformNode* node, TransformNode* parent_node);
+ void UpdateSnapping(TransformNode* node);
+};
+
+class CC_EXPORT ClipTree final : public PropertyTree<ClipNode> {};
+
+class CC_EXPORT OpacityTree final : public PropertyTree<OpacityNode> {};
+
+class CC_EXPORT PropertyTrees final {
+ public:
+ PropertyTrees();
+
+ TransformTree transform_tree;
+ OpacityTree opacity_tree;
+ ClipTree clip_tree;
+ bool needs_rebuild;
+ int sequence_number;
+};
+
+} // namespace cc
+
+#endif // CC_TREES_PROPERTY_TREE_H_
diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc
new file mode 100644
index 00000000000..815692db211
--- /dev/null
+++ b/chromium/cc/trees/property_tree_builder.cc
@@ -0,0 +1,459 @@
+// Copyright 2014 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/property_tree_builder.h"
+
+#include <map>
+#include <set>
+
+#include "cc/base/math_util.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/layer_impl.h"
+#include "cc/trees/layer_tree_host.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
+
+namespace cc {
+
+class LayerTreeHost;
+
+namespace {
+
+template <typename LayerType>
+struct DataForRecursion {
+ TransformTree* transform_tree;
+ ClipTree* clip_tree;
+ OpacityTree* opacity_tree;
+ LayerType* transform_tree_parent;
+ LayerType* transform_fixed_parent;
+ LayerType* render_target;
+ int clip_tree_parent;
+ int opacity_tree_parent;
+ const LayerType* page_scale_layer;
+ float page_scale_factor;
+ float device_scale_factor;
+ bool in_subtree_of_page_scale_application_layer;
+ bool should_flatten;
+ bool ancestor_clips_subtree;
+ const gfx::Transform* device_transform;
+ gfx::Vector2dF scroll_compensation_adjustment;
+ int sequence_number;
+};
+
+template <typename LayerType>
+static LayerType* GetTransformParent(const DataForRecursion<LayerType>& data,
+ LayerType* layer) {
+ return layer->position_constraint().is_fixed_position()
+ ? data.transform_fixed_parent
+ : data.transform_tree_parent;
+}
+
+template <typename LayerType>
+static ClipNode* GetClipParent(const DataForRecursion<LayerType>& data,
+ LayerType* layer) {
+ const bool inherits_clip = !layer->parent() || !layer->clip_parent();
+ const int id = inherits_clip ? data.clip_tree_parent
+ : layer->clip_parent()->clip_tree_index();
+ return data.clip_tree->Node(id);
+}
+
+template <typename LayerType>
+static bool HasPotentiallyRunningAnimation(LayerType* layer,
+ Animation::TargetProperty property) {
+ if (Animation* animation =
+ layer->layer_animation_controller()->GetAnimation(property)) {
+ return !animation->is_finished();
+ }
+ return false;
+}
+
+template <typename LayerType>
+static bool RequiresClipNode(LayerType* layer,
+ const DataForRecursion<LayerType>& data,
+ int parent_transform_id,
+ bool is_clipped) {
+ const bool render_surface_applies_clip =
+ layer->render_surface() && is_clipped;
+ const bool render_surface_may_grow_due_to_clip_children =
+ layer->render_surface() && layer->num_unclipped_descendants() > 0;
+
+ if (!layer->parent() || layer->masks_to_bounds() || layer->mask_layer() ||
+ render_surface_may_grow_due_to_clip_children)
+ return true;
+
+ if (!render_surface_applies_clip)
+ return false;
+
+ bool axis_aligned_with_respect_to_parent =
+ data.transform_tree->Are2DAxisAligned(layer->transform_tree_index(),
+ parent_transform_id);
+
+ return !axis_aligned_with_respect_to_parent;
+}
+
+template <typename LayerType>
+static bool LayerClipsSubtree(LayerType* layer) {
+ return layer->masks_to_bounds() || layer->mask_layer();
+}
+
+template <typename LayerType>
+void AddClipNodeIfNeeded(const DataForRecursion<LayerType>& data_from_ancestor,
+ LayerType* layer,
+ bool created_transform_node,
+ DataForRecursion<LayerType>* data_for_children) {
+ ClipNode* parent = GetClipParent(data_from_ancestor, layer);
+ int parent_id = parent->id;
+
+ bool ancestor_clips_subtree =
+ data_from_ancestor.ancestor_clips_subtree || layer->clip_parent();
+
+ data_for_children->ancestor_clips_subtree = false;
+ bool has_unclipped_surface = false;
+
+ if (layer->has_render_surface()) {
+ if (ancestor_clips_subtree && layer->num_unclipped_descendants() > 0)
+ data_for_children->ancestor_clips_subtree = true;
+ else if (!ancestor_clips_subtree && !layer->num_unclipped_descendants())
+ has_unclipped_surface = true;
+ } else {
+ data_for_children->ancestor_clips_subtree = ancestor_clips_subtree;
+ }
+
+ if (LayerClipsSubtree(layer))
+ data_for_children->ancestor_clips_subtree = true;
+
+ if (has_unclipped_surface)
+ parent_id = 0;
+
+ if (!RequiresClipNode(layer, data_from_ancestor, parent->data.transform_id,
+ data_for_children->ancestor_clips_subtree)) {
+ // Unclipped surfaces reset the clip rect.
+ data_for_children->clip_tree_parent = parent_id;
+ } else if (layer->parent()) {
+ // Note the root clip gets handled elsewhere.
+ LayerType* transform_parent = data_for_children->transform_tree_parent;
+ if (layer->position_constraint().is_fixed_position() &&
+ !created_transform_node) {
+ transform_parent = data_for_children->transform_fixed_parent;
+ }
+ ClipNode node;
+ node.data.clip = gfx::RectF(
+ gfx::PointF() + layer->offset_to_transform_parent(), layer->bounds());
+ node.data.transform_id = transform_parent->transform_tree_index();
+ node.data.target_id =
+ data_for_children->render_target->transform_tree_index();
+ node.owner_id = layer->id();
+
+ data_for_children->clip_tree_parent =
+ data_for_children->clip_tree->Insert(node, parent_id);
+ }
+
+ layer->SetClipTreeIndex(
+ has_unclipped_surface ? 0 : data_for_children->clip_tree_parent);
+
+ // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the
+ // clip for all children since we may need to draw. We need to figure out a
+ // better way, since we will need both the clipped and unclipped versions.
+}
+
+template <typename LayerType>
+bool AddTransformNodeIfNeeded(
+ const DataForRecursion<LayerType>& data_from_ancestor,
+ LayerType* layer,
+ DataForRecursion<LayerType>* data_for_children) {
+ const bool is_root = !layer->parent();
+ const bool is_page_scale_application_layer =
+ layer->parent() && layer->parent() == data_from_ancestor.page_scale_layer;
+ const bool is_scrollable = layer->scrollable();
+ const bool is_fixed = layer->position_constraint().is_fixed_position();
+
+ const bool has_significant_transform =
+ !layer->transform().IsIdentityOr2DTranslation();
+
+ const bool has_potentially_animated_transform =
+ HasPotentiallyRunningAnimation(layer, Animation::TRANSFORM);
+
+ const bool has_animated_transform =
+ layer->layer_animation_controller()->IsAnimatingProperty(
+ Animation::TRANSFORM);
+
+ const bool has_surface = !!layer->render_surface();
+
+ bool requires_node = is_root || is_scrollable || has_significant_transform ||
+ has_potentially_animated_transform || has_surface ||
+ is_fixed || is_page_scale_application_layer;
+
+ LayerType* transform_parent = GetTransformParent(data_from_ancestor, layer);
+
+ int parent_index = 0;
+ if (transform_parent)
+ parent_index = transform_parent->transform_tree_index();
+
+ int source_index = parent_index;
+
+ gfx::Vector2dF source_offset;
+ if (transform_parent) {
+ if (layer->scroll_parent()) {
+ LayerType* source = layer->parent();
+ source_offset += source->offset_to_transform_parent();
+ source_index = source->transform_tree_index();
+ } else if (!is_fixed) {
+ source_offset = transform_parent->offset_to_transform_parent();
+ } else {
+ if (data_from_ancestor.transform_tree_parent !=
+ data_from_ancestor.transform_fixed_parent) {
+ source_offset = data_from_ancestor.transform_tree_parent
+ ->offset_to_transform_parent();
+ source_index =
+ data_from_ancestor.transform_tree_parent->transform_tree_index();
+ }
+ source_offset += data_from_ancestor.scroll_compensation_adjustment;
+ }
+ }
+
+ if (layer->IsContainerForFixedPositionLayers() || is_root)
+ data_for_children->transform_fixed_parent = layer;
+ data_for_children->transform_tree_parent = layer;
+
+ if (layer->IsContainerForFixedPositionLayers() || is_fixed)
+ data_for_children->scroll_compensation_adjustment = gfx::Vector2dF();
+
+ if (!requires_node) {
+ data_for_children->should_flatten |= layer->should_flatten_transform();
+ gfx::Vector2dF local_offset = layer->position().OffsetFromOrigin() +
+ layer->transform().To2dTranslation();
+ gfx::Vector2dF source_to_parent;
+ if (source_index != parent_index) {
+ gfx::Transform to_parent;
+ data_from_ancestor.transform_tree->ComputeTransform(
+ source_index, parent_index, &to_parent);
+ source_to_parent = to_parent.To2dTranslation();
+ }
+ layer->set_offset_to_transform_parent(source_offset + source_to_parent +
+ local_offset);
+ layer->set_should_flatten_transform_from_property_tree(
+ data_from_ancestor.should_flatten);
+ layer->SetTransformTreeIndex(parent_index);
+ return false;
+ }
+
+ data_for_children->transform_tree->Insert(TransformNode(), parent_index);
+
+ TransformNode* node = data_for_children->transform_tree->back();
+ layer->SetTransformTreeIndex(node->id);
+
+ node->data.scrolls = is_scrollable;
+ node->data.flattens_inherited_transform = data_for_children->should_flatten;
+
+ // Surfaces inherently flatten transforms.
+ data_for_children->should_flatten =
+ layer->should_flatten_transform() || has_surface;
+ node->data.target_id =
+ data_from_ancestor.render_target->transform_tree_index();
+ node->data.content_target_id =
+ data_for_children->render_target->transform_tree_index();
+ DCHECK_NE(node->data.target_id, -1);
+ node->data.is_animated = has_animated_transform;
+
+ float post_local_scale_factor = 1.0f;
+ if (is_root) {
+ node->data.post_local = *data_from_ancestor.device_transform;
+ post_local_scale_factor = data_from_ancestor.device_scale_factor;
+ }
+
+ if (is_page_scale_application_layer)
+ post_local_scale_factor *= data_from_ancestor.page_scale_factor;
+
+ if (has_surface && !is_root) {
+ node->data.needs_sublayer_scale = true;
+ node->data.layer_scale_factor = data_from_ancestor.device_scale_factor;
+ if (data_from_ancestor.in_subtree_of_page_scale_application_layer)
+ node->data.layer_scale_factor *= data_from_ancestor.page_scale_factor;
+ }
+
+ if (is_root) {
+ node->data.post_local.Scale(post_local_scale_factor,
+ post_local_scale_factor);
+ } else {
+ node->data.post_local_scale_factor = post_local_scale_factor;
+ node->data.source_offset = source_offset;
+ node->data.source_node_id = source_index;
+ node->data.update_post_local_transform(layer->position(),
+ layer->transform_origin());
+ }
+
+ if (!layer->scroll_parent()) {
+ node->data.scroll_offset =
+ gfx::ScrollOffsetToVector2dF(layer->CurrentScrollOffset());
+ }
+
+ node->data.local = layer->transform();
+ node->data.update_pre_local_transform(layer->transform_origin());
+
+ node->data.needs_local_transform_update = true;
+ data_from_ancestor.transform_tree->UpdateTransforms(node->id);
+
+ layer->set_offset_to_transform_parent(gfx::Vector2dF());
+
+ // Flattening (if needed) will be handled by |node|.
+ layer->set_should_flatten_transform_from_property_tree(false);
+
+ data_for_children->scroll_compensation_adjustment +=
+ layer->ScrollCompensationAdjustment() - node->data.scroll_snap;
+
+ node->owner_id = layer->id();
+
+ return true;
+}
+
+bool IsAnimatingOpacity(Layer* layer) {
+ return HasPotentiallyRunningAnimation(layer, Animation::OPACITY) ||
+ layer->OpacityCanAnimateOnImplThread();
+}
+
+bool IsAnimatingOpacity(LayerImpl* layer) {
+ return HasPotentiallyRunningAnimation(layer, Animation::OPACITY);
+}
+
+template <typename LayerType>
+void AddOpacityNodeIfNeeded(
+ const DataForRecursion<LayerType>& data_from_ancestor,
+ LayerType* layer,
+ DataForRecursion<LayerType>* data_for_children) {
+ const bool is_root = !layer->parent();
+ const bool has_transparency = layer->opacity() != 1.f;
+ const bool has_animated_opacity = IsAnimatingOpacity(layer);
+ bool requires_node = is_root || has_transparency || has_animated_opacity;
+
+ int parent_id = data_from_ancestor.opacity_tree_parent;
+
+ if (!requires_node) {
+ layer->SetOpacityTreeIndex(parent_id);
+ data_for_children->opacity_tree_parent = parent_id;
+ return;
+ }
+
+ OpacityNode node;
+ node.owner_id = layer->id();
+ node.data = layer->opacity();
+ data_for_children->opacity_tree_parent =
+ data_for_children->opacity_tree->Insert(node, parent_id);
+ layer->SetOpacityTreeIndex(data_for_children->opacity_tree_parent);
+}
+
+template <typename LayerType>
+void BuildPropertyTreesInternal(
+ LayerType* layer,
+ const DataForRecursion<LayerType>& data_from_parent) {
+ layer->set_property_tree_sequence_number(data_from_parent.sequence_number);
+ DataForRecursion<LayerType> data_for_children(data_from_parent);
+ if (layer->render_surface())
+ data_for_children.render_target = layer;
+
+ bool created_transform_node =
+ AddTransformNodeIfNeeded(data_from_parent, layer, &data_for_children);
+ AddClipNodeIfNeeded(data_from_parent, layer, created_transform_node,
+ &data_for_children);
+
+ if (data_from_parent.opacity_tree)
+ AddOpacityNodeIfNeeded(data_from_parent, layer, &data_for_children);
+
+ if (layer == data_from_parent.page_scale_layer)
+ data_for_children.in_subtree_of_page_scale_application_layer = true;
+
+ for (size_t i = 0; i < layer->children().size(); ++i) {
+ if (!layer->child_at(i)->scroll_parent())
+ BuildPropertyTreesInternal(layer->child_at(i), data_for_children);
+ }
+
+ if (layer->scroll_children()) {
+ for (LayerType* scroll_child : *layer->scroll_children()) {
+ BuildPropertyTreesInternal(scroll_child, data_for_children);
+ }
+ }
+
+ if (layer->has_replica())
+ BuildPropertyTreesInternal(layer->replica_layer(), data_for_children);
+}
+
+} // namespace
+
+template <typename LayerType>
+void BuildPropertyTreesTopLevelInternal(LayerType* root_layer,
+ const LayerType* page_scale_layer,
+ float page_scale_factor,
+ float device_scale_factor,
+ const gfx::Rect& viewport,
+ const gfx::Transform& device_transform,
+ PropertyTrees* property_trees) {
+ property_trees->sequence_number++;
+
+ DataForRecursion<LayerType> data_for_recursion;
+ data_for_recursion.transform_tree = &property_trees->transform_tree;
+ data_for_recursion.clip_tree = &property_trees->clip_tree;
+ data_for_recursion.opacity_tree = &property_trees->opacity_tree;
+ data_for_recursion.transform_tree_parent = nullptr;
+ data_for_recursion.transform_fixed_parent = nullptr;
+ data_for_recursion.render_target = root_layer;
+ data_for_recursion.clip_tree_parent = 0;
+ data_for_recursion.opacity_tree_parent = -1;
+ data_for_recursion.page_scale_layer = page_scale_layer;
+ data_for_recursion.page_scale_factor = page_scale_factor;
+ data_for_recursion.device_scale_factor = device_scale_factor;
+ data_for_recursion.in_subtree_of_page_scale_application_layer = false;
+ data_for_recursion.should_flatten = false;
+ data_for_recursion.ancestor_clips_subtree = true;
+ data_for_recursion.device_transform = &device_transform;
+
+ data_for_recursion.transform_tree->clear();
+ data_for_recursion.clip_tree->clear();
+ data_for_recursion.opacity_tree->clear();
+ data_for_recursion.sequence_number = property_trees->sequence_number;
+
+ ClipNode root_clip;
+ root_clip.data.clip = viewport;
+ root_clip.data.transform_id = 0;
+ data_for_recursion.clip_tree_parent =
+ data_for_recursion.clip_tree->Insert(root_clip, 0);
+ BuildPropertyTreesInternal(root_layer, data_for_recursion);
+ property_trees->needs_rebuild = false;
+
+ // The transform tree is kept up-to-date as it is built, but the
+ // combined_clips stored in the clip tree aren't computed during tree
+ // building.
+ property_trees->transform_tree.set_needs_update(false);
+ property_trees->clip_tree.set_needs_update(true);
+}
+
+void PropertyTreeBuilder::BuildPropertyTrees(
+ Layer* root_layer,
+ const Layer* page_scale_layer,
+ float page_scale_factor,
+ float device_scale_factor,
+ const gfx::Rect& viewport,
+ const gfx::Transform& device_transform,
+ PropertyTrees* property_trees) {
+ // TODO(enne): hoist this out of here
+ if (!property_trees->needs_rebuild)
+ return;
+
+ BuildPropertyTreesTopLevelInternal(
+ root_layer, page_scale_layer, page_scale_factor, device_scale_factor,
+ viewport, device_transform, property_trees);
+}
+
+void PropertyTreeBuilder::BuildPropertyTrees(
+ LayerImpl* root_layer,
+ const LayerImpl* page_scale_layer,
+ float page_scale_factor,
+ float device_scale_factor,
+ const gfx::Rect& viewport,
+ const gfx::Transform& device_transform,
+ PropertyTrees* property_trees) {
+ BuildPropertyTreesTopLevelInternal(
+ root_layer, page_scale_layer, page_scale_factor, device_scale_factor,
+ viewport, device_transform, property_trees);
+}
+
+} // namespace cc
diff --git a/chromium/cc/trees/property_tree_builder.h b/chromium/cc/trees/property_tree_builder.h
new file mode 100644
index 00000000000..15f326ef15c
--- /dev/null
+++ b/chromium/cc/trees/property_tree_builder.h
@@ -0,0 +1,39 @@
+// Copyright 2014 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_PROPERTY_TREE_BUILDER_H_
+#define CC_TREES_PROPERTY_TREE_BUILDER_H_
+
+#include <vector>
+
+#include "cc/trees/layer_tree_host_common.h"
+#include "cc/trees/property_tree.h"
+
+namespace cc {
+
+class LayerTreeHost;
+
+class PropertyTreeBuilder {
+ public:
+ // Building an opacity tree is optional, and can be skipped by passing
+ // in a null |opacity_tree|.
+ static void BuildPropertyTrees(Layer* root_layer,
+ const Layer* page_scale_layer,
+ float page_scale_factor,
+ float device_scale_factor,
+ const gfx::Rect& viewport,
+ const gfx::Transform& device_transform,
+ PropertyTrees* property_trees);
+ static void BuildPropertyTrees(LayerImpl* root_layer,
+ const LayerImpl* page_scale_layer,
+ float page_scale_factor,
+ float device_scale_factor,
+ const gfx::Rect& viewport,
+ const gfx::Transform& device_transform,
+ PropertyTrees* property_trees);
+};
+
+} // namespace cc
+
+#endif // CC_TREES_PROPERTY_TREE_BUILDER_H_
diff --git a/chromium/cc/trees/property_tree_unittest.cc b/chromium/cc/trees/property_tree_unittest.cc
new file mode 100644
index 00000000000..7e179388b5f
--- /dev/null
+++ b/chromium/cc/trees/property_tree_unittest.cc
@@ -0,0 +1,467 @@
+// Copyright 2014 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/property_tree.h"
+
+#include "cc/test/geometry_test_utils.h"
+#include "cc/trees/draw_property_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+
+TEST(PropertyTreeTest, ComputeTransformRoot) {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ gfx::Transform expected;
+ gfx::Transform transform;
+ bool success = tree.ComputeTransform(0, 0, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.Translate(2, 2);
+ success = tree.ComputeTransform(0, -1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-2, -2);
+ success = tree.ComputeTransform(-1, 0, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+}
+
+TEST(PropertyTreeTest, ComputeTransformChild) {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode child;
+ child.data.local.Translate(3, 3);
+ child.data.target_id = 0;
+ child.data.source_node_id = 0;
+
+ tree.Insert(child, 0);
+ tree.UpdateTransforms(1);
+
+ gfx::Transform expected;
+ gfx::Transform transform;
+
+ expected.Translate(3, 3);
+ bool success = tree.ComputeTransform(1, 0, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-3, -3);
+ success = tree.ComputeTransform(0, 1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(5, 5);
+ success = tree.ComputeTransform(1, -1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-5, -5);
+ success = tree.ComputeTransform(-1, 1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+}
+
+TEST(PropertyTreeTest, ComputeTransformSibling) {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode child;
+ child.data.local.Translate(3, 3);
+ child.data.source_node_id = 0;
+ child.data.target_id = 0;
+
+ TransformNode sibling;
+ sibling.data.local.Translate(7, 7);
+ sibling.data.source_node_id = 0;
+ sibling.data.target_id = 0;
+
+ tree.Insert(child, 0);
+ tree.Insert(sibling, 0);
+
+ tree.UpdateTransforms(1);
+ tree.UpdateTransforms(2);
+
+ gfx::Transform expected;
+ gfx::Transform transform;
+
+ expected.Translate(4, 4);
+ bool success = tree.ComputeTransform(2, 1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-4, -4);
+ success = tree.ComputeTransform(1, 2, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+}
+
+TEST(PropertyTreeTest, ComputeTransformSiblingSingularAncestor) {
+ // In this test, we have the following tree:
+ // root
+ // + singular
+ // + child
+ // + sibling
+ // Since the lowest common ancestor of |child| and |sibling| has a singular
+ // transform, we cannot use screen space transforms to compute change of basis
+ // transforms between these nodes.
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode singular;
+ singular.data.local.matrix().set(2, 2, 0.0);
+ singular.data.source_node_id = 0;
+ singular.data.target_id = 0;
+
+ TransformNode child;
+ child.data.local.Translate(3, 3);
+ child.data.source_node_id = 1;
+ child.data.target_id = 0;
+
+ TransformNode sibling;
+ sibling.data.local.Translate(7, 7);
+ sibling.data.source_node_id = 1;
+ sibling.data.target_id = 0;
+
+ tree.Insert(singular, 0);
+ tree.Insert(child, 1);
+ tree.Insert(sibling, 1);
+
+ tree.UpdateTransforms(1);
+ tree.UpdateTransforms(2);
+ tree.UpdateTransforms(3);
+
+ gfx::Transform expected;
+ gfx::Transform transform;
+
+ expected.Translate(4, 4);
+ bool success = tree.ComputeTransform(3, 2, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-4, -4);
+ success = tree.ComputeTransform(2, 3, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+}
+
+TEST(PropertyTreeTest, TransformsWithFlattening) {
+ TransformTree tree;
+
+ int grand_parent = tree.Insert(TransformNode(), 0);
+ tree.Node(grand_parent)->data.content_target_id = grand_parent;
+ tree.Node(grand_parent)->data.target_id = grand_parent;
+ tree.Node(grand_parent)->data.source_node_id = 0;
+
+ gfx::Transform rotation_about_x;
+ rotation_about_x.RotateAboutXAxis(15);
+
+ int parent = tree.Insert(TransformNode(), grand_parent);
+ tree.Node(parent)->data.needs_sublayer_scale = true;
+ tree.Node(parent)->data.target_id = grand_parent;
+ tree.Node(parent)->data.content_target_id = parent;
+ tree.Node(parent)->data.source_node_id = grand_parent;
+ tree.Node(parent)->data.local = rotation_about_x;
+
+ int child = tree.Insert(TransformNode(), parent);
+ tree.Node(child)->data.target_id = parent;
+ tree.Node(child)->data.content_target_id = parent;
+ tree.Node(child)->data.source_node_id = parent;
+ tree.Node(child)->data.flattens_inherited_transform = true;
+ tree.Node(child)->data.local = rotation_about_x;
+
+ int grand_child = tree.Insert(TransformNode(), child);
+ tree.Node(grand_child)->data.target_id = parent;
+ tree.Node(grand_child)->data.content_target_id = parent;
+ tree.Node(grand_child)->data.source_node_id = child;
+ tree.Node(grand_child)->data.flattens_inherited_transform = true;
+ tree.Node(grand_child)->data.local = rotation_about_x;
+
+ tree.set_needs_update(true);
+ ComputeTransforms(&tree);
+
+ gfx::Transform flattened_rotation_about_x = rotation_about_x;
+ flattened_rotation_about_x.FlattenTo2d();
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x,
+ tree.Node(child)->data.to_target);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x * rotation_about_x,
+ tree.Node(child)->data.to_screen);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x * rotation_about_x,
+ tree.Node(grand_child)->data.to_target);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x *
+ flattened_rotation_about_x *
+ rotation_about_x,
+ tree.Node(grand_child)->data.to_screen);
+
+ gfx::Transform grand_child_to_child;
+ bool success =
+ tree.ComputeTransform(grand_child, child, &grand_child_to_child);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x, grand_child_to_child);
+
+ // Remove flattening at grand_child, and recompute transforms.
+ tree.Node(grand_child)->data.flattens_inherited_transform = false;
+ tree.set_needs_update(true);
+ ComputeTransforms(&tree);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x * rotation_about_x,
+ tree.Node(grand_child)->data.to_target);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ flattened_rotation_about_x * rotation_about_x * rotation_about_x,
+ tree.Node(grand_child)->data.to_screen);
+
+ success = tree.ComputeTransform(grand_child, child, &grand_child_to_child);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x, grand_child_to_child);
+}
+
+TEST(PropertyTreeTest, MultiplicationOrder) {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode child;
+ child.data.local.Scale(2, 2);
+ child.data.target_id = 0;
+ child.data.source_node_id = 0;
+
+ tree.Insert(child, 0);
+ tree.UpdateTransforms(1);
+
+ gfx::Transform expected;
+ expected.Translate(2, 2);
+ expected.Scale(2, 2);
+
+ gfx::Transform transform;
+ gfx::Transform inverse;
+
+ bool success = tree.ComputeTransform(1, -1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ success = tree.ComputeTransform(-1, 1, &inverse);
+ EXPECT_TRUE(success);
+
+ transform = transform * inverse;
+ expected.MakeIdentity();
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+}
+
+TEST(PropertyTreeTest, ComputeTransformWithUninvertibleTransform) {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode child;
+ child.data.local.Scale(0, 0);
+ child.data.target_id = 0;
+ child.data.source_node_id = 0;
+
+ tree.Insert(child, 0);
+ tree.UpdateTransforms(1);
+
+ gfx::Transform expected;
+ expected.Scale(0, 0);
+
+ gfx::Transform transform;
+ gfx::Transform inverse;
+
+ bool success = tree.ComputeTransform(1, 0, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ // To compute this would require inverting the 0 matrix, so we cannot
+ // succeed.
+ success = tree.ComputeTransform(0, 1, &inverse);
+ EXPECT_FALSE(success);
+}
+
+TEST(PropertyTreeTest, ComputeTransformWithSublayerScale) {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode grand_parent;
+ grand_parent.data.local.Scale(2.f, 2.f);
+ grand_parent.data.target_id = 0;
+ grand_parent.data.source_node_id = 0;
+ grand_parent.data.needs_sublayer_scale = true;
+ int grand_parent_id = tree.Insert(grand_parent, 0);
+ tree.UpdateTransforms(grand_parent_id);
+
+ TransformNode parent;
+ parent.data.local.Translate(15.f, 15.f);
+ parent.data.target_id = grand_parent_id;
+ parent.data.source_node_id = grand_parent_id;
+ int parent_id = tree.Insert(parent, grand_parent_id);
+ tree.UpdateTransforms(parent_id);
+
+ TransformNode child;
+ child.data.local.Scale(3.f, 3.f);
+ child.data.target_id = grand_parent_id;
+ child.data.source_node_id = parent_id;
+ int child_id = tree.Insert(child, parent_id);
+ tree.UpdateTransforms(child_id);
+
+ TransformNode grand_child;
+ grand_child.data.local.Scale(5.f, 5.f);
+ grand_child.data.target_id = grand_parent_id;
+ grand_child.data.source_node_id = child_id;
+ grand_child.data.needs_sublayer_scale = true;
+ int grand_child_id = tree.Insert(grand_child, child_id);
+ tree.UpdateTransforms(grand_child_id);
+
+ EXPECT_EQ(gfx::Vector2dF(2.f, 2.f),
+ tree.Node(grand_parent_id)->data.sublayer_scale);
+ EXPECT_EQ(gfx::Vector2dF(30.f, 30.f),
+ tree.Node(grand_child_id)->data.sublayer_scale);
+
+ // Compute transform from grand_parent to grand_child.
+ gfx::Transform expected_transform_without_sublayer_scale;
+ expected_transform_without_sublayer_scale.Scale(1.f / 15.f, 1.f / 15.f);
+ expected_transform_without_sublayer_scale.Translate(-15.f, -15.f);
+
+ gfx::Transform expected_transform_with_dest_sublayer_scale;
+ expected_transform_with_dest_sublayer_scale.Scale(30.f, 30.f);
+ expected_transform_with_dest_sublayer_scale.Scale(1.f / 15.f, 1.f / 15.f);
+ expected_transform_with_dest_sublayer_scale.Translate(-15.f, -15.f);
+
+ gfx::Transform expected_transform_with_source_sublayer_scale;
+ expected_transform_with_source_sublayer_scale.Scale(1.f / 15.f, 1.f / 15.f);
+ expected_transform_with_source_sublayer_scale.Translate(-15.f, -15.f);
+ expected_transform_with_source_sublayer_scale.Scale(0.5f, 0.5f);
+
+ gfx::Transform transform;
+ bool success =
+ tree.ComputeTransform(grand_parent_id, grand_child_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_without_sublayer_scale,
+ transform);
+
+ success = tree.ComputeTransformWithDestinationSublayerScale(
+ grand_parent_id, grand_child_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_dest_sublayer_scale,
+ transform);
+
+ success = tree.ComputeTransformWithSourceSublayerScale(
+ grand_parent_id, grand_child_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_source_sublayer_scale,
+ transform);
+
+ // Now compute transform from grand_child to grand_parent.
+ expected_transform_without_sublayer_scale.MakeIdentity();
+ expected_transform_without_sublayer_scale.Translate(15.f, 15.f);
+ expected_transform_without_sublayer_scale.Scale(15.f, 15.f);
+
+ expected_transform_with_dest_sublayer_scale.MakeIdentity();
+ expected_transform_with_dest_sublayer_scale.Scale(2.f, 2.f);
+ expected_transform_with_dest_sublayer_scale.Translate(15.f, 15.f);
+ expected_transform_with_dest_sublayer_scale.Scale(15.f, 15.f);
+
+ expected_transform_with_source_sublayer_scale.MakeIdentity();
+ expected_transform_with_source_sublayer_scale.Translate(15.f, 15.f);
+ expected_transform_with_source_sublayer_scale.Scale(15.f, 15.f);
+ expected_transform_with_source_sublayer_scale.Scale(1.f / 30.f, 1.f / 30.f);
+
+ success = tree.ComputeTransform(grand_child_id, grand_parent_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_without_sublayer_scale,
+ transform);
+
+ success = tree.ComputeTransformWithDestinationSublayerScale(
+ grand_child_id, grand_parent_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_dest_sublayer_scale,
+ transform);
+
+ success = tree.ComputeTransformWithSourceSublayerScale(
+ grand_child_id, grand_parent_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_source_sublayer_scale,
+ transform);
+}
+
+TEST(PropertyTreeTest, FlatteningWhenDestinationHasOnlyFlatAncestors) {
+ // This tests that flattening is performed correctly when
+ // destination and its ancestors are flat, but there are 3d transforms
+ // and flattening between the source and destination.
+ TransformTree tree;
+
+ int parent = tree.Insert(TransformNode(), 0);
+ tree.Node(parent)->data.content_target_id = parent;
+ tree.Node(parent)->data.target_id = parent;
+ tree.Node(parent)->data.source_node_id = 0;
+ tree.Node(parent)->data.local.Translate(2, 2);
+
+ gfx::Transform rotation_about_x;
+ rotation_about_x.RotateAboutXAxis(15);
+
+ int child = tree.Insert(TransformNode(), parent);
+ tree.Node(child)->data.content_target_id = child;
+ tree.Node(child)->data.target_id = child;
+ tree.Node(child)->data.source_node_id = parent;
+ tree.Node(child)->data.local = rotation_about_x;
+
+
+ int grand_child = tree.Insert(TransformNode(), child);
+ tree.Node(grand_child)->data.content_target_id = grand_child;
+ tree.Node(grand_child)->data.target_id = grand_child;
+ tree.Node(grand_child)->data.source_node_id = child;
+ tree.Node(grand_child)->data.flattens_inherited_transform = true;
+
+ tree.set_needs_update(true);
+ ComputeTransforms(&tree);
+
+ gfx::Transform flattened_rotation_about_x = rotation_about_x;
+ flattened_rotation_about_x.FlattenTo2d();
+
+ gfx::Transform grand_child_to_parent;
+ bool success =
+ tree.ComputeTransform(grand_child, parent, &grand_child_to_parent);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x,
+ grand_child_to_parent);
+}
+
+} // namespace cc
diff --git a/chromium/cc/trees/proxy.cc b/chromium/cc/trees/proxy.cc
index e981a722cad..eb81e2e6735 100644
--- a/chromium/cc/trees/proxy.cc
+++ b/chromium/cc/trees/proxy.cc
@@ -21,7 +21,7 @@ base::SingleThreadTaskRunner* Proxy::ImplThreadTaskRunner() const {
}
bool Proxy::IsMainThread() const {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
if (impl_thread_is_overridden_)
return false;
@@ -36,7 +36,7 @@ bool Proxy::IsMainThread() const {
}
bool Proxy::IsImplThread() const {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
if (impl_thread_is_overridden_)
return true;
if (!impl_task_runner_.get())
@@ -47,21 +47,21 @@ bool Proxy::IsImplThread() const {
#endif
}
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
void Proxy::SetCurrentThreadIsImplThread(bool is_impl_thread) {
impl_thread_is_overridden_ = is_impl_thread;
}
#endif
bool Proxy::IsMainThreadBlocked() const {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
return is_main_thread_blocked_;
#else
return true;
#endif
}
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
void Proxy::SetMainThreadBlocked(bool is_main_thread_blocked) {
is_main_thread_blocked_ = is_main_thread_blocked;
}
@@ -69,7 +69,7 @@ void Proxy::SetMainThreadBlocked(bool is_main_thread_blocked) {
Proxy::Proxy(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
-#if !DCHECK_IS_ON
+#if !DCHECK_IS_ON()
: main_task_runner_(main_task_runner),
impl_task_runner_(impl_task_runner),
blocking_main_thread_task_runner_(
diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h
index feeab43b507..55e54beb6ae 100644
--- a/chromium/cc/trees/proxy.h
+++ b/chromium/cc/trees/proxy.h
@@ -17,7 +17,7 @@
#include "cc/base/cc_export.h"
namespace base {
-namespace debug {
+namespace trace_event {
class TracedValue;
}
class SingleThreadTaskRunner;
@@ -46,7 +46,7 @@ class CC_EXPORT Proxy {
bool IsMainThread() const;
bool IsImplThread() const;
bool IsMainThreadBlocked() const;
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
void SetMainThreadBlocked(bool is_main_thread_blocked);
void SetCurrentThreadIsImplThread(bool is_impl_thread);
#endif
@@ -56,6 +56,7 @@ class CC_EXPORT Proxy {
virtual void FinishAllRendering() = 0;
virtual bool IsStarted() const = 0;
+ virtual bool CommitToActiveTree() const = 0;
// Will call LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted
// with the result of this function.
@@ -67,6 +68,8 @@ class CC_EXPORT Proxy {
virtual void SetVisible(bool visible) = 0;
+ virtual void SetThrottleFrameProduction(bool throttle) = 0;
+
virtual const RendererCapabilities& GetRendererCapabilities() const = 0;
virtual void SetNeedsAnimate() = 0;
@@ -77,9 +80,8 @@ class CC_EXPORT Proxy {
virtual void NotifyInputThrottledUntilCommit() = 0;
- // Defers commits until it is reset. It is only supported when in threaded
- // mode. It's an error to make a sync call like CompositeAndReadback while
- // commits are deferred.
+ // Defers commits until it is reset. It is only supported when using a
+ // scheduler.
virtual void SetDeferCommits(bool defer_commits) = 0;
virtual void MainThreadHasStoppedFlinging() = 0;
@@ -100,10 +102,13 @@ class CC_EXPORT Proxy {
virtual bool SupportsImplScrolling() const = 0;
- virtual void AsValueInto(base::debug::TracedValue* value) const = 0;
-
virtual void SetDebugState(const LayerTreeDebugState& debug_state) = 0;
+ virtual void SetChildrenNeedBeginFrames(bool children_need_begin_frames) = 0;
+
+ virtual void SetAuthoritativeVSyncInterval(
+ const base::TimeDelta& interval) = 0;
+
// Testing hooks
virtual bool MainFrameWillHappenForTesting() = 0;
@@ -123,7 +128,7 @@ class CC_EXPORT Proxy {
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
scoped_ptr<BlockingTaskRunner> blocking_main_thread_task_runner_;
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
const base::PlatformThreadId main_thread_id_;
bool impl_thread_is_overridden_;
bool is_main_thread_blocked_;
@@ -132,7 +137,7 @@ class CC_EXPORT Proxy {
DISALLOW_COPY_AND_ASSIGN(Proxy);
};
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
class DebugScopedSetMainThreadBlocked {
public:
explicit DebugScopedSetMainThreadBlocked(Proxy* proxy) : proxy_(proxy) {
diff --git a/chromium/cc/trees/proxy_timing_history.cc b/chromium/cc/trees/proxy_timing_history.cc
index 9020ad51ef1..90abad1632f 100644
--- a/chromium/cc/trees/proxy_timing_history.cc
+++ b/chromium/cc/trees/proxy_timing_history.cc
@@ -43,11 +43,11 @@ base::TimeDelta ProxyTimingHistory::CommitToActivateDurationEstimate() const {
}
void ProxyTimingHistory::DidBeginMainFrame() {
- begin_main_frame_sent_time_ = base::TimeTicks::HighResNow();
+ begin_main_frame_sent_time_ = base::TimeTicks::Now();
}
void ProxyTimingHistory::DidCommit() {
- commit_complete_time_ = base::TimeTicks::HighResNow();
+ commit_complete_time_ = base::TimeTicks::Now();
base::TimeDelta begin_main_frame_to_commit_duration =
commit_complete_time_ - begin_main_frame_sent_time_;
@@ -64,7 +64,7 @@ void ProxyTimingHistory::DidCommit() {
void ProxyTimingHistory::DidActivateSyncTree() {
base::TimeDelta commit_to_activate_duration =
- base::TimeTicks::HighResNow() - commit_complete_time_;
+ base::TimeTicks::Now() - commit_complete_time_;
// Before adding the new data point to the timing history, see what we would
// have predicted for this frame. This allows us to keep track of the accuracy
@@ -77,12 +77,11 @@ void ProxyTimingHistory::DidActivateSyncTree() {
}
void ProxyTimingHistory::DidStartDrawing() {
- start_draw_time_ = base::TimeTicks::HighResNow();
+ start_draw_time_ = base::TimeTicks::Now();
}
void ProxyTimingHistory::DidFinishDrawing() {
- base::TimeDelta draw_duration =
- base::TimeTicks::HighResNow() - start_draw_time_;
+ base::TimeDelta draw_duration = base::TimeTicks::Now() - start_draw_time_;
// Before adding the new data point to the timing history, see what we would
// have predicted for this frame. This allows us to keep track of the accuracy
diff --git a/chromium/cc/trees/scoped_abort_remaining_swap_promises.h b/chromium/cc/trees/scoped_abort_remaining_swap_promises.h
index f8dfc017e72..e35fbf91541 100644
--- a/chromium/cc/trees/scoped_abort_remaining_swap_promises.h
+++ b/chromium/cc/trees/scoped_abort_remaining_swap_promises.h
@@ -5,7 +5,7 @@
#ifndef CC_TREES_SCOPED_ABORT_REMAINING_SWAP_PROMISES_H_
#define CC_TREES_SCOPED_ABORT_REMAINING_SWAP_PROMISES_H_
-#include "cc/base/swap_promise.h"
+#include "cc/output/swap_promise.h"
#include "cc/trees/layer_tree_host.h"
namespace cc {
diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc
index 1af657a3d0e..f05a9a6a529 100644
--- a/chromium/cc/trees/single_thread_proxy.cc
+++ b/chromium/cc/trees/single_thread_proxy.cc
@@ -5,13 +5,16 @@
#include "cc/trees/single_thread_proxy.h"
#include "base/auto_reset.h"
-#include "base/debug/trace_event.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/trace_event/trace_event.h"
#include "cc/debug/benchmark_instrumentation.h"
+#include "cc/debug/devtools_instrumentation.h"
#include "cc/output/context_provider.h"
#include "cc/output/output_surface.h"
#include "cc/quads/draw_quad.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/resource_update_controller.h"
+#include "cc/scheduler/commit_earlyout_reason.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_single_thread_client.h"
#include "cc/trees/layer_tree_impl.h"
@@ -23,23 +26,31 @@ namespace cc {
scoped_ptr<Proxy> SingleThreadProxy::Create(
LayerTreeHost* layer_tree_host,
LayerTreeHostSingleThreadClient* client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
- return make_scoped_ptr(
- new SingleThreadProxy(layer_tree_host, client, main_task_runner));
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+ return make_scoped_ptr(new SingleThreadProxy(
+ layer_tree_host,
+ client,
+ main_task_runner,
+ external_begin_frame_source.Pass()));
}
SingleThreadProxy::SingleThreadProxy(
LayerTreeHost* layer_tree_host,
LayerTreeHostSingleThreadClient* client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source)
: Proxy(main_task_runner, NULL),
layer_tree_host_(layer_tree_host),
client_(client),
timing_history_(layer_tree_host->rendering_stats_instrumentation()),
next_frame_is_newly_committed_frame_(false),
+#if DCHECK_IS_ON()
+ inside_impl_frame_(false),
+#endif
inside_draw_(false),
defer_commits_(false),
- commit_was_deferred_(false),
+ animate_requested_(false),
commit_requested_(false),
inside_synchronous_composite_(false),
output_surface_creation_requested_(false),
@@ -47,6 +58,17 @@ SingleThreadProxy::SingleThreadProxy(
TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
DCHECK(Proxy::IsMainThread());
DCHECK(layer_tree_host);
+
+ if (layer_tree_host->settings().single_thread_proxy_scheduler &&
+ !scheduler_on_impl_thread_) {
+ SchedulerSettings scheduler_settings(
+ layer_tree_host->settings().ToSchedulerSettings());
+ // SingleThreadProxy should run in main thread low latency mode.
+ scheduler_settings.main_thread_should_always_be_low_latency = true;
+ scheduler_on_impl_thread_ = Scheduler::Create(
+ this, scheduler_settings, layer_tree_host_->id(),
+ MainThreadTaskRunner(), external_begin_frame_source.Pass());
+ }
}
void SingleThreadProxy::Start() {
@@ -75,33 +97,39 @@ bool SingleThreadProxy::IsStarted() const {
return layer_tree_host_impl_;
}
+bool SingleThreadProxy::CommitToActiveTree() const {
+ // With SingleThreadProxy we skip the pending tree and commit directly to the
+ // active tree.
+ return true;
+}
+
void SingleThreadProxy::SetLayerTreeHostClientReady() {
TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
// Scheduling is controlled by the embedder in the single thread case, so
// nothing to do.
DCHECK(Proxy::IsMainThread());
DebugScopedSetImplThread impl(this);
- if (layer_tree_host_->settings().single_thread_proxy_scheduler &&
- !scheduler_on_impl_thread_) {
- SchedulerSettings scheduler_settings(layer_tree_host_->settings());
- scheduler_on_impl_thread_ = Scheduler::Create(this,
- scheduler_settings,
- layer_tree_host_->id(),
- MainThreadTaskRunner(),
- base::PowerMonitor::Get());
+ if (scheduler_on_impl_thread_) {
scheduler_on_impl_thread_->SetCanStart();
scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
}
}
void SingleThreadProxy::SetVisible(bool visible) {
- TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible");
+ TRACE_EVENT1("cc", "SingleThreadProxy::SetVisible", "visible", visible);
DebugScopedSetImplThread impl(this);
layer_tree_host_impl_->SetVisible(visible);
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
// Changing visibility could change ShouldComposite().
- UpdateBackgroundAnimateTicking();
+}
+
+void SingleThreadProxy::SetThrottleFrameProduction(bool throttle) {
+ TRACE_EVENT1("cc", "SingleThreadProxy::SetThrottleFrameProduction",
+ "throttle", throttle);
+ DebugScopedSetImplThread impl(this);
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->SetThrottleFrameProduction(throttle);
}
void SingleThreadProxy::RequestNewOutputSurface() {
@@ -118,11 +146,11 @@ void SingleThreadProxy::SetOutputSurface(
scoped_ptr<OutputSurface> output_surface) {
DCHECK(Proxy::IsMainThread());
DCHECK(layer_tree_host_->output_surface_lost());
- output_surface_creation_requested_ = false;
+ DCHECK(output_surface_creation_requested_);
renderer_capabilities_for_main_thread_ = RendererCapabilities();
- bool success = !!output_surface;
- if (success) {
+ bool success;
+ {
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
DebugScopedSetImplThread impl(this);
layer_tree_host_->DeleteContentsTexturesOnImplThread(
@@ -130,15 +158,17 @@ void SingleThreadProxy::SetOutputSurface(
success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
}
- layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
-
if (success) {
+ layer_tree_host_->DidInitializeOutputSurface();
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface();
else if (!inside_synchronous_composite_)
SetNeedsCommit();
- } else if (Proxy::MainThreadTaskRunner()) {
- ScheduleRequestNewOutputSurface();
+ output_surface_creation_requested_ = false;
+ } else {
+ // DidFailToInitializeOutputSurface is treated as a RequestNewOutputSurface,
+ // and so output_surface_creation_requested remains true.
+ layer_tree_host_->DidFailToInitializeOutputSurface();
}
}
@@ -152,7 +182,12 @@ void SingleThreadProxy::SetNeedsAnimate() {
TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
DCHECK(Proxy::IsMainThread());
client_->ScheduleAnimation();
- SetNeedsCommit();
+ if (animate_requested_)
+ return;
+ animate_requested_ = true;
+ DebugScopedSetImplThread impl(this);
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->SetNeedsCommit();
}
void SingleThreadProxy::SetNeedsUpdateLayers() {
@@ -161,15 +196,43 @@ void SingleThreadProxy::SetNeedsUpdateLayers() {
SetNeedsCommit();
}
+void SingleThreadProxy::DoAnimate() {
+ // Don't animate if there is no root layer.
+ // TODO(mithro): Both Animate and UpdateAnimationState already have a
+ // "!active_tree_->root_layer()" check?
+ if (!layer_tree_host_impl_->active_tree()->root_layer()) {
+ return;
+ }
+
+ layer_tree_host_impl_->Animate(
+ layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
+
+ // If animations are not visible, update the animation state now as it
+ // won't happen in DoComposite.
+ if (!layer_tree_host_impl_->AnimationsAreVisible()) {
+ layer_tree_host_impl_->UpdateAnimationState(true);
+ }
+}
+
void SingleThreadProxy::DoCommit() {
TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
DCHECK(Proxy::IsMainThread());
- commit_requested_ = false;
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("461509 SingleThreadProxy::DoCommit1"));
layer_tree_host_->WillCommit();
+ devtools_instrumentation::ScopedCommitTrace commit_task(
+ layer_tree_host_->id());
// Commit immediately.
{
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit2"));
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
DebugScopedSetImplThread impl(this);
@@ -183,28 +246,50 @@ void SingleThreadProxy::DoCommit() {
if (PrioritizedResourceManager* contents_texture_manager =
layer_tree_host_->contents_texture_manager()) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit3"));
contents_texture_manager->PushTexturePrioritiesToBackings();
}
layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit4"));
scoped_ptr<ResourceUpdateController> update_controller =
ResourceUpdateController::Create(
NULL,
MainThreadTaskRunner(),
queue_for_commit_.Pass(),
layer_tree_host_impl_->resource_provider());
+
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile5(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit5"));
update_controller->Finalize();
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile6(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit6"));
if (layer_tree_host_impl_->EvictedUIResourcesExist())
layer_tree_host_->RecreateUIResources();
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile7(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit7"));
layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
- layer_tree_host_impl_->CommitComplete();
-
- UpdateBackgroundAnimateTicking();
-
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
// In the single-threaded case, the scale and scroll deltas should never be
// touched on the impl layer tree.
scoped_ptr<ScrollAndScaleSet> scroll_info =
@@ -213,23 +298,26 @@ void SingleThreadProxy::DoCommit() {
DCHECK_EQ(1.f, scroll_info->page_scale_delta);
#endif
- RenderingStatsInstrumentation* stats_instrumentation =
- layer_tree_host_->rendering_stats_instrumentation();
- benchmark_instrumentation::IssueMainThreadRenderingStatsEvent(
- stats_instrumentation->main_thread_rendering_stats());
- stats_instrumentation->AccumulateAndClearMainThreadStats();
- }
-
- if (layer_tree_host_->settings().impl_side_painting) {
- // TODO(enne): just commit directly to the active tree.
- //
- // Synchronously activate during commit to satisfy any potential
- // SetNextCommitWaitsForActivation calls. Unfortunately, the tree
- // might not be ready to draw, so DidActivateSyncTree must set
- // the flag to force the tree to not draw until textures are ready.
- NotifyReadyToActivate();
- } else {
- CommitComplete();
+ if (layer_tree_host_->settings().impl_side_painting) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile8(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit8"));
+ // Commit goes directly to the active tree, but we need to synchronously
+ // "activate" the tree still during commit to satisfy any potential
+ // SetNextCommitWaitsForActivation calls. Unfortunately, the tree
+ // might not be ready to draw, so DidActivateSyncTree must set
+ // the flag to force the tree to not draw until textures are ready.
+ NotifyReadyToActivate();
+ } else {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile9(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit9"));
+ CommitComplete();
+ }
}
}
@@ -238,6 +326,10 @@ void SingleThreadProxy::CommitComplete() {
<< "Activation is expected to have synchronously occurred by now.";
DCHECK(commit_blocking_task_runner_);
+ // Notify commit complete on the impl side after activate to satisfy any
+ // SetNextCommitWaitsForActivation calls.
+ layer_tree_host_impl_->CommitComplete();
+
DebugScopedSetMainThread main(this);
commit_blocking_task_runner_.reset();
layer_tree_host_->CommitComplete();
@@ -249,11 +341,13 @@ void SingleThreadProxy::CommitComplete() {
void SingleThreadProxy::SetNeedsCommit() {
DCHECK(Proxy::IsMainThread());
- DebugScopedSetImplThread impl(this);
client_->ScheduleComposite();
+ if (commit_requested_)
+ return;
+ commit_requested_ = true;
+ DebugScopedSetImplThread impl(this);
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->SetNeedsCommit();
- commit_requested_ = true;
}
void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
@@ -283,10 +377,7 @@ void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this);
defer_commits_ = defer_commits;
- if (!defer_commits_ && commit_was_deferred_) {
- commit_was_deferred_ = false;
- BeginMainFrame();
- }
+ scheduler_on_impl_thread_->SetDeferCommits(defer_commits);
}
bool SingleThreadProxy::CommitRequested() const {
@@ -328,7 +419,6 @@ void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
TRACE_EVENT1(
"cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
DCHECK(Proxy::IsImplThread());
- UpdateBackgroundAnimateTicking();
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->SetCanDraw(can_draw);
}
@@ -340,6 +430,13 @@ void SingleThreadProxy::NotifyReadyToActivate() {
scheduler_on_impl_thread_->NotifyReadyToActivate();
}
+void SingleThreadProxy::NotifyReadyToDraw() {
+ TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToDraw");
+ DebugScopedSetImplThread impl(this);
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->NotifyReadyToDraw();
+}
+
void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
client_->ScheduleComposite();
if (scheduler_on_impl_thread_)
@@ -347,13 +444,15 @@ void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
}
void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
- SetNeedsRedrawOnImplThread();
+ client_->ScheduleComposite();
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->SetNeedsAnimate();
}
-void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
- TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsManageTilesOnImplThread");
+void SingleThreadProxy::SetNeedsPrepareTilesOnImplThread() {
+ TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsPrepareTilesOnImplThread");
if (scheduler_on_impl_thread_)
- scheduler_on_impl_thread_->SetNeedsManageTiles();
+ scheduler_on_impl_thread_->SetNeedsPrepareTiles();
}
void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
@@ -362,18 +461,20 @@ void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
SetNeedsRedrawOnImplThread();
}
-void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
- TRACE_EVENT0("cc", "SingleThreadProxy::DidInitializeVisibleTileOnImplThread");
- if (scheduler_on_impl_thread_)
- scheduler_on_impl_thread_->SetNeedsRedraw();
-}
-
void SingleThreadProxy::SetNeedsCommitOnImplThread() {
client_->ScheduleComposite();
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->SetNeedsCommit();
}
+void SingleThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) {
+ TRACE_EVENT1("cc", "SingleThreadProxy::SetVideoNeedsBeginFrames",
+ "needs_begin_frames", needs_begin_frames);
+ // In tests the layer tree is destroyed after the scheduler is.
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->SetVideoNeedsBeginFrames(needs_begin_frames);
+}
+
void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
scoped_ptr<AnimationEventsVector> events) {
TRACE_EVENT0(
@@ -406,29 +507,29 @@ void SingleThreadProxy::DidActivateSyncTree() {
// Non-impl-side painting finishes commit in DoCommit. Impl-side painting
// defers until here to simulate SetNextCommitWaitsForActivation.
if (layer_tree_host_impl_->settings().impl_side_painting) {
- // This is required because NotifyReadyToActivate gets called when
- // the pending tree is not actually ready in the SingleThreadProxy.
- layer_tree_host_impl_->SetRequiresHighResToDraw();
-
- // Since activation could cause tasks to run, post CommitComplete
- // separately so that it runs after these tasks. This is the loose
- // equivalent of blocking commit until activation and also running
- // all tasks posted during commit/activation before CommitComplete.
- MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&SingleThreadProxy::CommitComplete,
- weak_factory_.GetWeakPtr()));
+ // This is required because NotifyReadyToActivate gets called immediately
+ // after commit since single thread commits directly to the active tree.
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->SetWaitForReadyToDraw();
+
+ // Synchronously call to CommitComplete. Resetting
+ // |commit_blocking_task_runner| would make sure all tasks posted during
+ // commit/activation before CommitComplete.
+ CommitComplete();
}
- UpdateBackgroundAnimateTicking();
timing_history_.DidActivateSyncTree();
}
-void SingleThreadProxy::DidManageTiles() {
+void SingleThreadProxy::DidPrepareTiles() {
DCHECK(layer_tree_host_impl_->settings().impl_side_painting);
DCHECK(Proxy::IsImplThread());
if (scheduler_on_impl_thread_)
- scheduler_on_impl_thread_->DidManageTiles();
+ scheduler_on_impl_thread_->DidPrepareTiles();
+}
+
+void SingleThreadProxy::DidCompletePageScaleAnimationOnImplThread() {
+ layer_tree_host_->DidCompletePageScaleAnimation();
}
void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
@@ -450,6 +551,22 @@ void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
scheduler_on_impl_thread_->DidLoseOutputSurface();
}
+void SingleThreadProxy::CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->CommitVSyncParameters(timebase, interval);
+}
+
+void SingleThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->SetEstimatedParentDrawTime(draw_time);
+}
+
+void SingleThreadProxy::SetMaxSwapsPendingOnImplThread(int max) {
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->SetMaxSwapsPending(max);
+}
+
void SingleThreadProxy::DidSwapBuffersOnImplThread() {
TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersOnImplThread");
if (scheduler_on_impl_thread_)
@@ -458,15 +575,23 @@ void SingleThreadProxy::DidSwapBuffersOnImplThread() {
}
void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() {
- TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
+ TRACE_EVENT0("cc,benchmark",
+ "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->DidSwapBuffersComplete();
layer_tree_host_->DidCompleteSwapBuffers();
}
+void SingleThreadProxy::OnDrawForOutputSurface() {
+ NOTREACHED() << "Implemented by ThreadProxy for synchronous compositor.";
+}
+
void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
- TRACE_EVENT0("cc", "SingleThreadProxy::CompositeImmediately");
+ TRACE_EVENT0("cc,benchmark", "SingleThreadProxy::CompositeImmediately");
DCHECK(Proxy::IsMainThread());
+#if DCHECK_IS_ON()
+ DCHECK(!inside_impl_frame_);
+#endif
base::AutoReset<bool> inside_composite(&inside_synchronous_composite_, true);
if (layer_tree_host_->output_surface_lost()) {
@@ -477,11 +602,21 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
return;
}
+ BeginFrameArgs begin_frame_args(BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, frame_begin_time, base::TimeTicks(),
+ BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL));
+
+ // Start the impl frame.
+ {
+ DebugScopedSetImplThread impl(this);
+ WillBeginImplFrame(begin_frame_args);
+ }
+
+ // Run the "main thread" and get it to commit.
{
- BeginFrameArgs begin_frame_args(
- BeginFrameArgs::Create(frame_begin_time,
- base::TimeTicks(),
- BeginFrameArgs::DefaultInterval()));
+#if DCHECK_IS_ON()
+ DCHECK(inside_impl_frame_);
+#endif
DoBeginMainFrame(begin_frame_args);
DoCommit();
@@ -489,34 +624,29 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
<< "Commit should always succeed and transfer promises.";
}
+ // Finish the impl frame.
{
- DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this));
+ DebugScopedSetImplThread impl(this);
if (layer_tree_host_impl_->settings().impl_side_painting) {
layer_tree_host_impl_->ActivateSyncTree();
- layer_tree_host_impl_->active_tree()->UpdateDrawProperties();
- layer_tree_host_impl_->ManageTiles();
+ DCHECK(!layer_tree_host_impl_->active_tree()
+ ->needs_update_draw_properties());
+ layer_tree_host_impl_->PrepareTiles();
layer_tree_host_impl_->SynchronouslyInitializeAllTiles();
}
+ DoAnimate();
+
LayerTreeHostImpl::FrameData frame;
- DoComposite(frame_begin_time, &frame);
+ DoComposite(&frame);
// DoComposite could abort, but because this is a synchronous composite
// another draw will never be scheduled, so break remaining promises.
layer_tree_host_impl_->active_tree()->BreakSwapPromises(
SwapPromise::SWAP_FAILS);
- }
-}
-
-void SingleThreadProxy::AsValueInto(base::debug::TracedValue* state) const {
- // The following line casts away const modifiers because it is just
- // setting debug state. We still want the AsValue() function and its
- // call chain to be const throughout.
- DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this));
- state->BeginDictionary("layer_tree_host_impl");
- layer_tree_host_impl_->AsValueInto(state);
- state->EndDictionary();
+ DidFinishImplFrame();
+ }
}
void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
@@ -539,12 +669,6 @@ bool SingleThreadProxy::ShouldComposite() const {
layer_tree_host_impl_->CanDraw();
}
-void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
- DCHECK(Proxy::IsImplThread());
- layer_tree_host_impl_->UpdateBackgroundAnimateTicking(
- !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer());
-}
-
void SingleThreadProxy::ScheduleRequestNewOutputSurface() {
if (output_surface_creation_callback_.IsCancelled() &&
!output_surface_creation_requested_) {
@@ -556,8 +680,7 @@ void SingleThreadProxy::ScheduleRequestNewOutputSurface() {
}
}
-DrawResult SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time,
- LayerTreeHostImpl::FrameData* frame) {
+DrawResult SingleThreadProxy::DoComposite(LayerTreeHostImpl::FrameData* frame) {
TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
DCHECK(!layer_tree_host_->output_surface_lost());
@@ -567,31 +690,57 @@ DrawResult SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time,
DebugScopedSetImplThread impl(this);
base::AutoReset<bool> mark_inside(&inside_draw_, true);
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite1"));
+
// We guard PrepareToDraw() with CanDraw() because it always returns a valid
// frame, so can only be used when such a frame is possible. Since
// DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
// CanDraw() as well.
if (!ShouldComposite()) {
- UpdateBackgroundAnimateTicking();
return DRAW_ABORTED_CANT_DRAW;
}
timing_history_.DidStartDrawing();
- layer_tree_host_impl_->Animate(
- layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
- UpdateBackgroundAnimateTicking();
-
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite2"));
draw_result = layer_tree_host_impl_->PrepareToDraw(frame);
draw_frame = draw_result == DRAW_SUCCESS;
- if (draw_frame)
- layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);
+ if (draw_frame) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite3"));
+ layer_tree_host_impl_->DrawLayers(frame);
+ }
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite4"));
layer_tree_host_impl_->DidDrawAllLayers(*frame);
bool start_ready_animations = draw_frame;
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile5(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite5"));
layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
- layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile7(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite7"));
timing_history_.DidFinishDrawing();
}
@@ -610,8 +759,18 @@ DrawResult SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time,
BlockingTaskRunner::CapturePostTasks blocked(
blocking_main_thread_task_runner());
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile8(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite8"));
layer_tree_host_impl_->SwapBuffers(*frame);
}
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile9(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite9"));
DidCommitAndDrawFrame();
return draw_result;
@@ -626,14 +785,30 @@ void SingleThreadProxy::DidCommitAndDrawFrame() {
}
bool SingleThreadProxy::MainFrameWillHappenForTesting() {
- return false;
+ if (layer_tree_host_->output_surface_lost())
+ return false;
+ if (!scheduler_on_impl_thread_)
+ return false;
+ return scheduler_on_impl_thread_->MainFrameForTestingWillHappen();
+}
+
+void SingleThreadProxy::SetChildrenNeedBeginFrames(
+ bool children_need_begin_frames) {
+ scheduler_on_impl_thread_->SetChildrenNeedBeginFrames(
+ children_need_begin_frames);
}
-BeginFrameSource* SingleThreadProxy::ExternalBeginFrameSource() {
- return layer_tree_host_impl_.get();
+void SingleThreadProxy::SetAuthoritativeVSyncInterval(
+ const base::TimeDelta& interval) {
+ scheduler_on_impl_thread_->SetAuthoritativeVSyncInterval(interval);
}
void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
+#if DCHECK_IS_ON()
+ DCHECK(!inside_impl_frame_)
+ << "WillBeginImplFrame called while already inside an impl frame!";
+ inside_impl_frame_ = true;
+#endif
layer_tree_host_impl_->WillBeginImplFrame(args);
}
@@ -646,17 +821,31 @@ void SingleThreadProxy::ScheduledActionSendBeginMainFrame() {
// fall on the next. Doing it asynchronously instead matches the semantics of
// ThreadProxy::SetNeedsCommit where SetNeedsCommit will not cause a
// synchronous commit.
+#if DCHECK_IS_ON()
+ DCHECK(inside_impl_frame_)
+ << "BeginMainFrame should only be sent inside a BeginImplFrame";
+#endif
+ const BeginFrameArgs& begin_frame_args =
+ layer_tree_host_impl_->CurrentBeginFrameArgs();
+
MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&SingleThreadProxy::BeginMainFrame,
- weak_factory_.GetWeakPtr()));
+ FROM_HERE, base::Bind(&SingleThreadProxy::BeginMainFrame,
+ weak_factory_.GetWeakPtr(), begin_frame_args));
}
-void SingleThreadProxy::BeginMainFrame() {
+void SingleThreadProxy::SendBeginMainFrameNotExpectedSoon() {
+ layer_tree_host_->BeginMainFrameNotExpectedSoon();
+}
+
+void SingleThreadProxy::BeginMainFrame(const BeginFrameArgs& begin_frame_args) {
+ commit_requested_ = false;
+ animate_requested_ = false;
+
if (defer_commits_) {
- DCHECK(!commit_was_deferred_);
- commit_was_deferred_ = true;
- layer_tree_host_->DidDeferCommit();
+ TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
+ TRACE_EVENT_SCOPE_THREAD);
+ BeginMainFrameAbortedOnImplThread(
+ CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT);
return;
}
@@ -666,19 +855,24 @@ void SingleThreadProxy::BeginMainFrame() {
if (!layer_tree_host_->visible()) {
TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
- BeginMainFrameAbortedOnImplThread();
+ BeginMainFrameAbortedOnImplThread(
+ CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
return;
}
if (layer_tree_host_->output_surface_lost()) {
TRACE_EVENT_INSTANT0(
"cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD);
- BeginMainFrameAbortedOnImplThread();
+ BeginMainFrameAbortedOnImplThread(
+ CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST);
return;
}
- const BeginFrameArgs& begin_frame_args =
- layer_tree_host_impl_->CurrentBeginFrameArgs();
+ // Prevent new commits from being requested inside DoBeginMainFrame.
+ // Note: We do not want to prevent SetNeedsAnimate from requesting
+ // a commit here.
+ commit_requested_ = true;
+
DoBeginMainFrame(begin_frame_args);
}
@@ -701,33 +895,36 @@ void SingleThreadProxy::DoBeginMainFrame(
DCHECK(!queue_for_commit_);
queue_for_commit_ = make_scoped_ptr(new ResourceUpdateQueue);
+ // New commits requested inside UpdateLayers should be respected.
+ commit_requested_ = false;
+
layer_tree_host_->UpdateLayers(queue_for_commit_.get());
timing_history_.DidBeginMainFrame();
+ // TODO(enne): SingleThreadProxy does not support cancelling commits yet,
+ // search for CommitEarlyOutReason::FINISHED_NO_UPDATES inside
+ // thread_proxy.cc
if (scheduler_on_impl_thread_) {
scheduler_on_impl_thread_->NotifyBeginMainFrameStarted();
scheduler_on_impl_thread_->NotifyReadyToCommit();
}
}
-void SingleThreadProxy::BeginMainFrameAbortedOnImplThread() {
+void SingleThreadProxy::BeginMainFrameAbortedOnImplThread(
+ CommitEarlyOutReason reason) {
DebugScopedSetImplThread impl(this);
DCHECK(scheduler_on_impl_thread_->CommitPending());
DCHECK(!layer_tree_host_impl_->pending_tree());
- // TODO(enne): SingleThreadProxy does not support cancelling commits yet so
- // did_handle is always false.
- bool did_handle = false;
- layer_tree_host_impl_->BeginMainFrameAborted(did_handle);
- scheduler_on_impl_thread_->BeginMainFrameAborted(did_handle);
+ layer_tree_host_impl_->BeginMainFrameAborted(reason);
+ scheduler_on_impl_thread_->BeginMainFrameAborted(reason);
}
DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
DebugScopedSetImplThread impl(this);
LayerTreeHostImpl::FrameData frame;
- return DoComposite(layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time,
- &frame);
+ return DoComposite(&frame);
}
DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapForced() {
@@ -742,13 +939,8 @@ void SingleThreadProxy::ScheduledActionCommit() {
void SingleThreadProxy::ScheduledActionAnimate() {
TRACE_EVENT0("cc", "ScheduledActionAnimate");
- layer_tree_host_impl_->Animate(
- layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
-}
-
-void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() {
DebugScopedSetImplThread impl(this);
- layer_tree_host_impl_->UpdateVisibleTiles();
+ DoAnimate();
}
void SingleThreadProxy::ScheduledActionActivateSyncTree() {
@@ -770,11 +962,15 @@ void SingleThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
}
}
-void SingleThreadProxy::ScheduledActionManageTiles() {
- TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionManageTiles");
+void SingleThreadProxy::ScheduledActionPrepareTiles() {
+ TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionPrepareTiles");
DCHECK(layer_tree_host_impl_->settings().impl_side_painting);
DebugScopedSetImplThread impl(this);
- layer_tree_host_impl_->ManageTiles();
+ layer_tree_host_impl_->PrepareTiles();
+}
+
+void SingleThreadProxy::ScheduledActionInvalidateOutputSurface() {
+ NOTREACHED();
}
void SingleThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) {
@@ -792,8 +988,17 @@ base::TimeDelta SingleThreadProxy::CommitToActivateDurationEstimate() {
return timing_history_.CommitToActivateDurationEstimate();
}
-void SingleThreadProxy::DidBeginImplFrameDeadline() {
- layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
+void SingleThreadProxy::DidFinishImplFrame() {
+ layer_tree_host_impl_->DidFinishImplFrame();
+#if DCHECK_IS_ON()
+ DCHECK(inside_impl_frame_)
+ << "DidFinishImplFrame called while not inside an impl frame!";
+ inside_impl_frame_ = false;
+#endif
+}
+
+void SingleThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) {
+ layer_tree_host_->SendBeginFramesToChildren(args);
}
} // namespace cc
diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h
index 5b3766bce18..98ac5e5c7d4 100644
--- a/chromium/cc/trees/single_thread_proxy.h
+++ b/chromium/cc/trees/single_thread_proxy.h
@@ -19,9 +19,11 @@
namespace cc {
+class BeginFrameSource;
class ContextProvider;
class LayerTreeHost;
class LayerTreeHostSingleThreadClient;
+class ResourceUpdateQueue;
class CC_EXPORT SingleThreadProxy : public Proxy,
NON_EXPORTED_BASE(LayerTreeHostImplClient),
@@ -30,15 +32,18 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
static scoped_ptr<Proxy> Create(
LayerTreeHost* layer_tree_host,
LayerTreeHostSingleThreadClient* client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
~SingleThreadProxy() override;
// Proxy implementation
void FinishAllRendering() override;
bool IsStarted() const override;
+ bool CommitToActiveTree() const override;
void SetOutputSurface(scoped_ptr<OutputSurface>) override;
void SetLayerTreeHostClientReady() override;
void SetVisible(bool visible) override;
+ void SetThrottleFrameProduction(bool throttle) override;
const RendererCapabilities& GetRendererCapabilities() const override;
void SetNeedsAnimate() override;
void SetNeedsUpdateLayers() override;
@@ -55,54 +60,60 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
size_t MaxPartialTextureUpdates() const override;
void ForceSerializeOnSwapBuffers() override;
bool SupportsImplScrolling() const override;
- void AsValueInto(base::debug::TracedValue* state) const override;
bool MainFrameWillHappenForTesting() override;
+ void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override;
+ void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) override;
// SchedulerClient implementation
- BeginFrameSource* ExternalBeginFrameSource() override;
void WillBeginImplFrame(const BeginFrameArgs& args) override;
+ void DidFinishImplFrame() override;
void ScheduledActionSendBeginMainFrame() override;
DrawResult ScheduledActionDrawAndSwapIfPossible() override;
DrawResult ScheduledActionDrawAndSwapForced() override;
void ScheduledActionCommit() override;
void ScheduledActionAnimate() override;
- void ScheduledActionUpdateVisibleTiles() override;
void ScheduledActionActivateSyncTree() override;
void ScheduledActionBeginOutputSurfaceCreation() override;
- void ScheduledActionManageTiles() override;
+ void ScheduledActionPrepareTiles() override;
+ void ScheduledActionInvalidateOutputSurface() override;
void DidAnticipatedDrawTimeChange(base::TimeTicks time) override;
base::TimeDelta DrawDurationEstimate() override;
base::TimeDelta BeginMainFrameToCommitDurationEstimate() override;
base::TimeDelta CommitToActivateDurationEstimate() override;
- void DidBeginImplFrameDeadline() override;
+ void SendBeginFramesToChildren(const BeginFrameArgs& args) override;
+ void SendBeginMainFrameNotExpectedSoon() override;
// LayerTreeHostImplClient implementation
void UpdateRendererCapabilitiesOnImplThread() override;
void DidLoseOutputSurfaceOnImplThread() override;
void CommitVSyncParameters(base::TimeTicks timebase,
- base::TimeDelta interval) override {}
- void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override {}
- void SetMaxSwapsPendingOnImplThread(int max) override {}
+ base::TimeDelta interval) override;
+ void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override;
+ void SetMaxSwapsPendingOnImplThread(int max) override;
void DidSwapBuffersOnImplThread() override;
void DidSwapBuffersCompleteOnImplThread() override;
void OnCanDrawStateChanged(bool can_draw) override;
void NotifyReadyToActivate() override;
+ void NotifyReadyToDraw() override;
void SetNeedsRedrawOnImplThread() override;
void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
void SetNeedsAnimateOnImplThread() override;
- void SetNeedsManageTilesOnImplThread() override;
- void DidInitializeVisibleTileOnImplThread() override;
+ void SetNeedsPrepareTilesOnImplThread() override;
void SetNeedsCommitOnImplThread() override;
+ void SetVideoNeedsBeginFrames(bool needs_begin_frames) override;
void PostAnimationEventsToMainThreadOnImplThread(
scoped_ptr<AnimationEventsVector> events) override;
bool ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes,
int priority_cutoff) override;
bool IsInsideDraw() override;
void RenewTreePriority() override {}
- void PostDelayedScrollbarFadeOnImplThread(const base::Closure& start_fade,
+ void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
base::TimeDelta delay) override {}
void DidActivateSyncTree() override;
- void DidManageTiles() override;
+ void DidPrepareTiles() override;
+ void DidCompletePageScaleAnimationOnImplThread() override;
+ void OnDrawForOutputSurface() override;
+
void SetDebugState(const LayerTreeDebugState& debug_state) override {}
void RequestNewOutputSurface();
@@ -110,24 +121,25 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
// Called by the legacy path where RenderWidget does the scheduling.
void CompositeImmediately(base::TimeTicks frame_begin_time);
- private:
+ protected:
SingleThreadProxy(
LayerTreeHost* layer_tree_host,
LayerTreeHostSingleThreadClient* client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
- void BeginMainFrame();
- void BeginMainFrameAbortedOnImplThread();
+ private:
+ void BeginMainFrame(const BeginFrameArgs& begin_frame_args);
+ void BeginMainFrameAbortedOnImplThread(CommitEarlyOutReason reason);
+ void DoAnimate();
void DoBeginMainFrame(const BeginFrameArgs& begin_frame_args);
void DoCommit();
- DrawResult DoComposite(base::TimeTicks frame_begin_time,
- LayerTreeHostImpl::FrameData* frame);
+ DrawResult DoComposite(LayerTreeHostImpl::FrameData* frame);
void DoSwap();
void DidCommitAndDrawFrame();
void CommitComplete();
bool ShouldComposite() const;
- void UpdateBackgroundAnimateTicking();
void ScheduleRequestNewOutputSurface();
// Accessed on main thread only.
@@ -147,9 +159,12 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
scoped_ptr<ResourceUpdateQueue> queue_for_commit_;
bool next_frame_is_newly_committed_frame_;
+#if DCHECK_IS_ON()
+ bool inside_impl_frame_;
+#endif
bool inside_draw_;
bool defer_commits_;
- bool commit_was_deferred_;
+ bool animate_requested_;
bool commit_requested_;
bool inside_synchronous_composite_;
@@ -170,13 +185,13 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
class DebugScopedSetImplThread {
public:
explicit DebugScopedSetImplThread(Proxy* proxy) : proxy_(proxy) {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
previous_value_ = proxy_->impl_thread_is_overridden_;
proxy_->SetCurrentThreadIsImplThread(true);
#endif
}
~DebugScopedSetImplThread() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
proxy_->SetCurrentThreadIsImplThread(previous_value_);
#endif
}
@@ -193,13 +208,13 @@ class DebugScopedSetImplThread {
class DebugScopedSetMainThread {
public:
explicit DebugScopedSetMainThread(Proxy* proxy) : proxy_(proxy) {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
previous_value_ = proxy_->impl_thread_is_overridden_;
proxy_->SetCurrentThreadIsImplThread(false);
#endif
}
~DebugScopedSetMainThread() {
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
proxy_->SetCurrentThreadIsImplThread(previous_value_);
#endif
}
diff --git a/chromium/cc/base/swap_promise_monitor.cc b/chromium/cc/trees/swap_promise_monitor.cc
index 0c04f35ebc4..84d8a9feb94 100644
--- a/chromium/cc/base/swap_promise_monitor.cc
+++ b/chromium/cc/trees/swap_promise_monitor.cc
@@ -3,9 +3,9 @@
// found in the LICENSE file.
#include "base/logging.h"
-#include "cc/base/swap_promise_monitor.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/swap_promise_monitor.h"
namespace cc {
diff --git a/chromium/cc/base/swap_promise_monitor.h b/chromium/cc/trees/swap_promise_monitor.h
index cf06bee2449..d163af58df3 100644
--- a/chromium/cc/base/swap_promise_monitor.h
+++ b/chromium/cc/trees/swap_promise_monitor.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_BASE_SWAP_PROMISE_MONITOR_H_
-#define CC_BASE_SWAP_PROMISE_MONITOR_H_
+#ifndef CC_TREES_SWAP_PROMISE_MONITOR_H_
+#define CC_TREES_SWAP_PROMISE_MONITOR_H_
#include "cc/base/cc_export.h"
@@ -42,4 +42,4 @@ class CC_EXPORT SwapPromiseMonitor {
} // namespace cc
-#endif // CC_BASE_SWAP_PROMISE_MONITOR_H_
+#endif // CC_TREES_SWAP_PROMISE_MONITOR_H_
diff --git a/chromium/cc/trees/thread_proxy.cc b/chromium/cc/trees/thread_proxy.cc
index 14e218194e0..3010fba95c3 100644
--- a/chromium/cc/trees/thread_proxy.cc
+++ b/chromium/cc/trees/thread_proxy.cc
@@ -9,17 +9,18 @@
#include "base/auto_reset.h"
#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/debug/trace_event_argument.h"
-#include "base/debug/trace_event_synthetic_delay.h"
-#include "cc/base/swap_promise.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
#include "cc/debug/benchmark_instrumentation.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/input/input_handler.h"
#include "cc/output/context_provider.h"
#include "cc/output/output_surface.h"
+#include "cc/output/swap_promise.h"
#include "cc/quads/draw_quad.h"
#include "cc/resources/prioritized_resource_manager.h"
+#include "cc/scheduler/commit_earlyout_reason.h"
#include "cc/scheduler/delay_based_time_source.h"
#include "cc/scheduler/scheduler.h"
#include "cc/trees/blocking_task_runner.h"
@@ -48,22 +49,27 @@ struct ThreadProxy::SchedulerStateRequest {
scoped_ptr<Proxy> ThreadProxy::Create(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
- return make_scoped_ptr(
- new ThreadProxy(layer_tree_host, main_task_runner, impl_task_runner));
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+ return make_scoped_ptr(new ThreadProxy(layer_tree_host,
+ main_task_runner,
+ impl_task_runner,
+ external_begin_frame_source.Pass()));
}
ThreadProxy::ThreadProxy(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source)
: Proxy(main_task_runner, impl_task_runner),
main_thread_only_vars_unsafe_(this, layer_tree_host->id()),
main_thread_or_blocked_vars_unsafe_(layer_tree_host),
compositor_thread_vars_unsafe_(
this,
layer_tree_host->id(),
- layer_tree_host->rendering_stats_instrumentation()) {
+ layer_tree_host->rendering_stats_instrumentation(),
+ external_begin_frame_source.Pass()) {
TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy");
DCHECK(IsMainThread());
DCHECK(this->layer_tree_host());
@@ -76,10 +82,11 @@ ThreadProxy::MainThreadOnly::MainThreadOnly(ThreadProxy* proxy,
commit_requested(false),
commit_request_sent_to_impl_thread(false),
started(false),
- manage_tiles_pending(false),
+ prepare_tiles_pending(false),
can_cancel_commit(true),
defer_commits(false),
- weak_factory(proxy) {}
+ weak_factory(proxy) {
+}
ThreadProxy::MainThreadOnly::~MainThreadOnly() {}
@@ -99,7 +106,8 @@ ThreadProxy::MainThreadOrBlockedMainThread::contents_texture_manager() {
ThreadProxy::CompositorThreadOnly::CompositorThreadOnly(
ThreadProxy* proxy,
int layer_tree_host_id,
- RenderingStatsInstrumentation* rendering_stats_instrumentation)
+ RenderingStatsInstrumentation* rendering_stats_instrumentation,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source)
: layer_tree_host_id(layer_tree_host_id),
contents_texture_manager(NULL),
commit_completion_event(NULL),
@@ -113,6 +121,7 @@ ThreadProxy::CompositorThreadOnly::CompositorThreadOnly(
base::TimeDelta::FromMilliseconds(
kSmoothnessTakesPriorityExpirationDelay * 1000)),
timing_history(rendering_stats_instrumentation),
+ external_begin_frame_source(external_begin_frame_source.Pass()),
weak_factory(proxy) {
}
@@ -144,6 +153,12 @@ bool ThreadProxy::IsStarted() const {
return main().started;
}
+bool ThreadProxy::CommitToActiveTree() const {
+ // With ThreadProxy and impl-side painting, we use a pending tree and activate
+ // it once it's ready to draw.
+ return !impl().layer_tree_host_impl->settings().impl_side_painting;
+}
+
void ThreadProxy::SetLayerTreeHostClientReady() {
TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReady");
Proxy::ImplThreadTaskRunner()->PostTask(
@@ -158,7 +173,7 @@ void ThreadProxy::SetLayerTreeHostClientReadyOnImplThread() {
}
void ThreadProxy::SetVisible(bool visible) {
- TRACE_EVENT0("cc", "ThreadProxy::SetVisible");
+ TRACE_EVENT1("cc", "ThreadProxy::SetVisible", "visible", visible);
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
CompletionEvent completion;
@@ -173,19 +188,25 @@ void ThreadProxy::SetVisible(bool visible) {
void ThreadProxy::SetVisibleOnImplThread(CompletionEvent* completion,
bool visible) {
- TRACE_EVENT0("cc", "ThreadProxy::SetVisibleOnImplThread");
+ TRACE_EVENT1("cc", "ThreadProxy::SetVisibleOnImplThread", "visible", visible);
impl().layer_tree_host_impl->SetVisible(visible);
impl().scheduler->SetVisible(visible);
- UpdateBackgroundAnimateTicking();
completion->Signal();
}
-void ThreadProxy::UpdateBackgroundAnimateTicking() {
- bool should_background_tick =
- !impl().scheduler->WillDrawIfNeeded() &&
- impl().layer_tree_host_impl->active_tree()->root_layer();
- impl().layer_tree_host_impl->UpdateBackgroundAnimateTicking(
- should_background_tick);
+void ThreadProxy::SetThrottleFrameProduction(bool throttle) {
+ TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProduction", "throttle",
+ throttle);
+ Proxy::ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::SetThrottleFrameProductionOnImplThread,
+ impl_thread_weak_ptr_, throttle));
+}
+
+void ThreadProxy::SetThrottleFrameProductionOnImplThread(bool throttle) {
+ TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProductionOnImplThread",
+ "throttle", throttle);
+ impl().scheduler->SetThrottleFrameProduction(throttle);
}
void ThreadProxy::DidLoseOutputSurface() {
@@ -216,16 +237,10 @@ void ThreadProxy::RequestNewOutputSurface() {
}
void ThreadProxy::SetOutputSurface(scoped_ptr<OutputSurface> output_surface) {
- if (output_surface) {
- Proxy::ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread,
- impl_thread_weak_ptr_,
- base::Passed(&output_surface)));
- return;
- }
-
- DidInitializeOutputSurface(false, RendererCapabilities());
+ Proxy::ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread,
+ impl_thread_weak_ptr_, base::Passed(&output_surface)));
}
void ThreadProxy::DidInitializeOutputSurface(
@@ -233,15 +248,13 @@ void ThreadProxy::DidInitializeOutputSurface(
const RendererCapabilities& capabilities) {
TRACE_EVENT0("cc", "ThreadProxy::DidInitializeOutputSurface");
DCHECK(IsMainThread());
- main().renderer_capabilities_main_thread_copy = capabilities;
- layer_tree_host()->OnCreateAndInitializeOutputSurfaceAttempted(success);
if (!success) {
- Proxy::MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::RequestNewOutputSurface,
- main_thread_weak_ptr_));
+ layer_tree_host()->DidFailToInitializeOutputSurface();
+ return;
}
+ main().renderer_capabilities_main_thread_copy = capabilities;
+ layer_tree_host()->DidInitializeOutputSurface();
}
void ThreadProxy::SetRendererCapabilitiesMainThreadCopy(
@@ -260,6 +273,11 @@ void ThreadProxy::SendCommitRequestToImplThreadIfNeeded() {
impl_thread_weak_ptr_));
}
+void ThreadProxy::DidCompletePageScaleAnimation() {
+ DCHECK(IsMainThread());
+ layer_tree_host()->DidCompletePageScaleAnimation();
+}
+
const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const {
DCHECK(IsMainThread());
DCHECK(!layer_tree_host()->output_surface_lost());
@@ -337,7 +355,8 @@ void ThreadProxy::DidSwapBuffersOnImplThread() {
}
void ThreadProxy::DidSwapBuffersCompleteOnImplThread() {
- TRACE_EVENT0("cc", "ThreadProxy::DidSwapBuffersCompleteOnImplThread");
+ TRACE_EVENT0("cc,benchmark",
+ "ThreadProxy::DidSwapBuffersCompleteOnImplThread");
DCHECK(IsImplThread());
impl().scheduler->DidSwapBuffersComplete();
Proxy::MainThreadTaskRunner()->PostTask(
@@ -345,12 +364,18 @@ void ThreadProxy::DidSwapBuffersCompleteOnImplThread() {
base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_));
}
-BeginFrameSource* ThreadProxy::ExternalBeginFrameSource() {
- return impl().layer_tree_host_impl.get();
-}
-
void ThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
impl().layer_tree_host_impl->WillBeginImplFrame(args);
+ if (impl().last_processed_begin_main_frame_args.IsValid()) {
+ // Last processed begin main frame args records the frame args that we sent
+ // to the main thread for the last frame that we've processed. If that is
+ // set, that means the current frame is one past the frame in which we've
+ // finished the processing.
+ impl().layer_tree_host_impl->RecordMainFrameTiming(
+ impl().last_processed_begin_main_frame_args,
+ impl().layer_tree_host_impl->CurrentBeginFrameArgs());
+ impl().last_processed_begin_main_frame_args = BeginFrameArgs();
+ }
}
void ThreadProxy::OnCanDrawStateChanged(bool can_draw) {
@@ -358,7 +383,6 @@ void ThreadProxy::OnCanDrawStateChanged(bool can_draw) {
"cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
DCHECK(IsImplThread());
impl().scheduler->SetCanDraw(can_draw);
- UpdateBackgroundAnimateTicking();
}
void ThreadProxy::NotifyReadyToActivate() {
@@ -366,12 +390,26 @@ void ThreadProxy::NotifyReadyToActivate() {
impl().scheduler->NotifyReadyToActivate();
}
+void ThreadProxy::NotifyReadyToDraw() {
+ TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToDraw");
+ impl().scheduler->NotifyReadyToDraw();
+}
+
void ThreadProxy::SetNeedsCommitOnImplThread() {
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread");
DCHECK(IsImplThread());
impl().scheduler->SetNeedsCommit();
}
+void ThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) {
+ TRACE_EVENT1("cc", "ThreadProxy::SetVideoNeedsBeginFrames",
+ "needs_begin_frames", needs_begin_frames);
+ DCHECK(IsImplThread());
+ // In tests the layer tree is destroyed after the scheduler is.
+ if (impl().scheduler)
+ impl().scheduler->SetVideoNeedsBeginFrames(needs_begin_frames);
+}
+
void ThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
scoped_ptr<AnimationEventsVector> events) {
TRACE_EVENT0("cc",
@@ -439,13 +477,16 @@ void ThreadProxy::SetDeferCommits(bool defer_commits) {
else
TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::SetDeferCommits", this);
- if (!main().defer_commits && main().pending_deferred_commit) {
- Proxy::MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::BeginMainFrame,
- main_thread_weak_ptr_,
- base::Passed(&main().pending_deferred_commit)));
- }
+ Proxy::ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::SetDeferCommitsOnImplThread,
+ impl_thread_weak_ptr_,
+ defer_commits));
+}
+
+void ThreadProxy::SetDeferCommitsOnImplThread(bool defer_commits) const {
+ DCHECK(IsImplThread());
+ impl().scheduler->SetDeferCommits(defer_commits);
}
bool ThreadProxy::CommitRequested() const {
@@ -470,9 +511,9 @@ void ThreadProxy::SetNeedsAnimateOnImplThread() {
impl().scheduler->SetNeedsAnimate();
}
-void ThreadProxy::SetNeedsManageTilesOnImplThread() {
+void ThreadProxy::SetNeedsPrepareTilesOnImplThread() {
DCHECK(IsImplThread());
- impl().scheduler->SetNeedsManageTiles();
+ impl().scheduler->SetNeedsPrepareTiles();
}
void ThreadProxy::SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) {
@@ -481,23 +522,6 @@ void ThreadProxy::SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) {
SetNeedsRedrawOnImplThread();
}
-void ThreadProxy::SetSwapUsedIncompleteTileOnImplThread(
- bool used_incomplete_tile) {
- DCHECK(IsImplThread());
- if (used_incomplete_tile) {
- TRACE_EVENT_INSTANT0("cc",
- "ThreadProxy::SetSwapUsedIncompleteTileOnImplThread",
- TRACE_EVENT_SCOPE_THREAD);
- }
- impl().scheduler->SetSwapUsedIncompleteTile(used_incomplete_tile);
-}
-
-void ThreadProxy::DidInitializeVisibleTileOnImplThread() {
- TRACE_EVENT0("cc", "ThreadProxy::DidInitializeVisibleTileOnImplThread");
- DCHECK(IsImplThread());
- impl().scheduler->SetNeedsRedraw();
-}
-
void ThreadProxy::MainThreadHasStoppedFlinging() {
DCHECK(IsMainThread());
Proxy::ImplThreadTaskRunner()->PostTask(
@@ -686,6 +710,10 @@ void ThreadProxy::ScheduledActionSendBeginMainFrame() {
impl().layer_tree_host_impl->memory_allocation_priority_cutoff();
begin_main_frame_state->evicted_ui_resources =
impl().layer_tree_host_impl->EvictedUIResourcesExist();
+ // TODO(vmpstr): This needs to be fixed if
+ // main_frame_before_activation_enabled is set, since we might run this code
+ // twice before recording a duration. crbug.com/469824
+ impl().last_begin_main_frame_args = begin_main_frame_state->begin_frame_args;
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::BeginMainFrame,
@@ -696,6 +724,12 @@ void ThreadProxy::ScheduledActionSendBeginMainFrame() {
impl().timing_history.DidBeginMainFrame();
}
+void ThreadProxy::SendBeginMainFrameNotExpectedSoon() {
+ Proxy::MainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameNotExpectedSoon,
+ main_thread_weak_ptr_));
+}
+
void ThreadProxy::BeginMainFrame(
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
@@ -705,10 +739,12 @@ void ThreadProxy::BeginMainFrame(
DCHECK(IsMainThread());
if (main().defer_commits) {
- main().pending_deferred_commit = begin_main_frame_state.Pass();
- layer_tree_host()->DidDeferCommit();
- TRACE_EVENT_INSTANT0(
- "cc", "EarlyOut_DeferCommits", TRACE_EVENT_SCOPE_THREAD);
+ TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
+ TRACE_EVENT_SCOPE_THREAD);
+ Proxy::ImplThreadTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
+ impl_thread_weak_ptr_,
+ CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT));
return;
}
@@ -723,24 +759,21 @@ void ThreadProxy::BeginMainFrame(
if (!layer_tree_host()->visible()) {
TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
- bool did_handle = false;
Proxy::ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
- impl_thread_weak_ptr_,
- did_handle));
+ FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
+ impl_thread_weak_ptr_,
+ CommitEarlyOutReason::ABORTED_NOT_VISIBLE));
return;
}
if (layer_tree_host()->output_surface_lost()) {
TRACE_EVENT_INSTANT0(
"cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD);
- bool did_handle = false;
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
impl_thread_weak_ptr_,
- did_handle));
+ CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST));
return;
}
@@ -798,6 +831,8 @@ void ThreadProxy::BeginMainFrame(
bool updated = layer_tree_host()->UpdateLayers(queue.get());
layer_tree_host()->WillCommit();
+ devtools_instrumentation::ScopedCommitTrace commit_task(
+ layer_tree_host()->id());
// Before calling animate, we set main().animate_requested to false. If it is
// true now, it means SetNeedAnimate was called again, but during a state when
@@ -812,12 +847,10 @@ void ThreadProxy::BeginMainFrame(
if (!updated && can_cancel_this_commit) {
TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD);
- bool did_handle = true;
Proxy::ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
- impl_thread_weak_ptr_,
- did_handle));
+ FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
+ impl_thread_weak_ptr_,
+ CommitEarlyOutReason::FINISHED_NO_UPDATES));
// Although the commit is internally aborted, this is because it has been
// detected to be a no-op. From the perspective of an embedder, this commit
@@ -851,18 +884,18 @@ void ThreadProxy::BeginMainFrame(
&completion,
queue.release()));
completion.Wait();
-
- RenderingStatsInstrumentation* stats_instrumentation =
- layer_tree_host()->rendering_stats_instrumentation();
- benchmark_instrumentation::IssueMainThreadRenderingStatsEvent(
- stats_instrumentation->main_thread_rendering_stats());
- stats_instrumentation->AccumulateAndClearMainThreadStats();
}
layer_tree_host()->CommitComplete();
layer_tree_host()->DidBeginMainFrame();
}
+void ThreadProxy::BeginMainFrameNotExpectedSoon() {
+ TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameNotExpectedSoon");
+ DCHECK(IsMainThread());
+ layer_tree_host()->BeginMainFrameNotExpectedSoon();
+}
+
void ThreadProxy::StartCommitOnImplThread(CompletionEvent* completion,
ResourceUpdateQueue* raw_queue) {
TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread");
@@ -916,26 +949,44 @@ void ThreadProxy::StartCommitOnImplThread(CompletionEvent* completion,
impl().scheduler->AnticipatedDrawTime());
}
-void ThreadProxy::BeginMainFrameAbortedOnImplThread(bool did_handle) {
- TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread");
+void ThreadProxy::BeginMainFrameAbortedOnImplThread(
+ CommitEarlyOutReason reason) {
+ TRACE_EVENT1("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread", "reason",
+ CommitEarlyOutReasonToString(reason));
DCHECK(IsImplThread());
DCHECK(impl().scheduler);
DCHECK(impl().scheduler->CommitPending());
DCHECK(!impl().layer_tree_host_impl->pending_tree());
- if (did_handle)
+ if (CommitEarlyOutHandledCommit(reason)) {
SetInputThrottledUntilCommitOnImplThread(false);
- impl().layer_tree_host_impl->BeginMainFrameAborted(did_handle);
- impl().scheduler->BeginMainFrameAborted(did_handle);
+ impl().last_processed_begin_main_frame_args =
+ impl().last_begin_main_frame_args;
+ }
+ impl().layer_tree_host_impl->BeginMainFrameAborted(reason);
+ impl().scheduler->BeginMainFrameAborted(reason);
}
void ThreadProxy::ScheduledActionAnimate() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionAnimate");
DCHECK(IsImplThread());
+ // Don't animate if there is no root layer.
+ // TODO(mithro): Both Animate and UpdateAnimationState already have a
+ // "!active_tree_->root_layer()" check?
+ if (!impl().layer_tree_host_impl->active_tree()->root_layer()) {
+ return;
+ }
+
impl().animation_time =
impl().layer_tree_host_impl->CurrentBeginFrameArgs().frame_time;
impl().layer_tree_host_impl->Animate(impl().animation_time);
+
+ // If animations are not visible, update the state now as
+ // ScheduledActionDrawAndSwapIfPossible will never be called.
+ if (!impl().layer_tree_host_impl->AnimationsAreVisible()) {
+ impl().layer_tree_host_impl->UpdateAnimationState(true);
+ }
}
void ThreadProxy::ScheduledActionCommit() {
@@ -979,19 +1030,11 @@ void ThreadProxy::ScheduledActionCommit() {
SetInputThrottledUntilCommitOnImplThread(false);
- UpdateBackgroundAnimateTicking();
-
impl().next_frame_is_newly_committed_frame = true;
impl().timing_history.DidCommit();
}
-void ThreadProxy::ScheduledActionUpdateVisibleTiles() {
- TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionUpdateVisibleTiles");
- DCHECK(IsImplThread());
- impl().layer_tree_host_impl->UpdateVisibleTiles();
-}
-
void ThreadProxy::ScheduledActionActivateSyncTree() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivateSyncTree");
DCHECK(IsImplThread());
@@ -1016,8 +1059,11 @@ DrawResult ThreadProxy::DrawSwapInternal(bool forced_draw) {
impl().timing_history.DidStartDrawing();
base::AutoReset<bool> mark_inside(&impl().inside_draw, true);
- if (impl().layer_tree_host_impl->pending_tree())
- impl().layer_tree_host_impl->pending_tree()->UpdateDrawProperties();
+ if (impl().layer_tree_host_impl->pending_tree()) {
+ bool update_lcd_text = false;
+ impl().layer_tree_host_impl->pending_tree()->UpdateDrawProperties(
+ update_lcd_text);
+ }
// This method is called on a forced draw, regardless of whether we are able
// to produce a frame, as the calling site on main thread is blocked until its
@@ -1041,8 +1087,7 @@ DrawResult ThreadProxy::DrawSwapInternal(bool forced_draw) {
}
if (draw_frame) {
- impl().layer_tree_host_impl->DrawLayers(
- &frame, impl().scheduler->LastBeginImplFrameTime());
+ impl().layer_tree_host_impl->DrawLayers(&frame);
result = DRAW_SUCCESS;
} else {
DCHECK_NE(DRAW_SUCCESS, result);
@@ -1052,15 +1097,8 @@ DrawResult ThreadProxy::DrawSwapInternal(bool forced_draw) {
bool start_ready_animations = draw_frame;
impl().layer_tree_host_impl->UpdateAnimationState(start_ready_animations);
- if (draw_frame) {
- bool did_request_swap = impl().layer_tree_host_impl->SwapBuffers(frame);
-
- // We don't know if we have incomplete tiles if we didn't actually swap.
- if (did_request_swap) {
- DCHECK(!frame.has_no_damage);
- SetSwapUsedIncompleteTileOnImplThread(frame.contains_incomplete_tile);
- }
- }
+ if (draw_frame)
+ impl().layer_tree_host_impl->SwapBuffers(frame);
// Tell the main thread that the the newly-commited frame was drawn.
if (impl().next_frame_is_newly_committed_frame) {
@@ -1077,10 +1115,10 @@ DrawResult ThreadProxy::DrawSwapInternal(bool forced_draw) {
return result;
}
-void ThreadProxy::ScheduledActionManageTiles() {
- TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionManageTiles");
+void ThreadProxy::ScheduledActionPrepareTiles() {
+ TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionPrepareTiles");
DCHECK(impl().layer_tree_host_impl->settings().impl_side_painting);
- impl().layer_tree_host_impl->ManageTiles();
+ impl().layer_tree_host_impl->PrepareTiles();
}
DrawResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
@@ -1101,6 +1139,12 @@ DrawResult ThreadProxy::ScheduledActionDrawAndSwapForced() {
return DrawSwapInternal(forced_draw);
}
+void ThreadProxy::ScheduledActionInvalidateOutputSurface() {
+ TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionInvalidateOutputSurface");
+ DCHECK(impl().layer_tree_host_impl->output_surface());
+ impl().layer_tree_host_impl->output_surface()->Invalidate();
+}
+
void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) {
if (impl().current_resource_update_controller)
impl().current_resource_update_controller->PerformMoreUpdates(time);
@@ -1118,8 +1162,17 @@ base::TimeDelta ThreadProxy::CommitToActivateDurationEstimate() {
return impl().timing_history.CommitToActivateDurationEstimate();
}
-void ThreadProxy::DidBeginImplFrameDeadline() {
- impl().layer_tree_host_impl->ResetCurrentBeginFrameArgsForNextFrame();
+void ThreadProxy::DidFinishImplFrame() {
+ impl().layer_tree_host_impl->DidFinishImplFrame();
+}
+
+void ThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) {
+ NOTREACHED() << "Only used by SingleThreadProxy";
+}
+
+void ThreadProxy::SetAuthoritativeVSyncInterval(
+ const base::TimeDelta& interval) {
+ NOTREACHED() << "Only used by SingleThreadProxy";
}
void ThreadProxy::ReadyToFinalizeTextureUpdates() {
@@ -1148,14 +1201,15 @@ void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) {
DCHECK(IsImplThread());
impl().layer_tree_host_impl =
layer_tree_host()->CreateLayerTreeHostImpl(this);
- SchedulerSettings scheduler_settings(layer_tree_host()->settings());
- impl().scheduler = Scheduler::Create(this,
- scheduler_settings,
- impl().layer_tree_host_id,
- ImplThreadTaskRunner(),
- base::PowerMonitor::Get());
+ SchedulerSettings scheduler_settings(
+ layer_tree_host()->settings().ToSchedulerSettings());
+ impl().scheduler = Scheduler::Create(
+ this,
+ scheduler_settings,
+ impl().layer_tree_host_id,
+ ImplThreadTaskRunner(),
+ impl().external_begin_frame_source.Pass());
impl().scheduler->SetVisible(impl().layer_tree_host_impl->visible());
-
impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr();
completion->Signal();
}
@@ -1213,7 +1267,6 @@ void ThreadProxy::LayerTreeHostClosedOnImplThread(CompletionEvent* completion) {
layer_tree_host()->DeleteContentsTexturesOnImplThread(
impl().layer_tree_host_impl->resource_provider());
impl().current_resource_update_controller = nullptr;
- impl().layer_tree_host_impl->SetNeedsBeginFrames(false);
impl().scheduler = nullptr;
impl().layer_tree_host_impl = nullptr;
impl().weak_factory.InvalidateWeakPtrs();
@@ -1236,30 +1289,6 @@ ThreadProxy::BeginMainFrameAndCommitState::BeginMainFrameAndCommitState()
ThreadProxy::BeginMainFrameAndCommitState::~BeginMainFrameAndCommitState() {}
-void ThreadProxy::AsValueInto(base::debug::TracedValue* state) const {
- CompletionEvent completion;
- {
- DebugScopedSetMainThreadBlocked main_thread_blocked(
- const_cast<ThreadProxy*>(this));
- scoped_refptr<base::debug::TracedValue> state_refptr(state);
- Proxy::ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::AsValueOnImplThread,
- impl_thread_weak_ptr_,
- &completion,
- state_refptr));
- completion.Wait();
- }
-}
-
-void ThreadProxy::AsValueOnImplThread(CompletionEvent* completion,
- base::debug::TracedValue* state) const {
- state->BeginDictionary("layer_tree_host_impl");
- impl().layer_tree_host_impl->AsValueInto(state);
- state->EndDictionary();
- completion->Signal();
-}
-
bool ThreadProxy::MainFrameWillHappenForTesting() {
DCHECK(IsMainThread());
CompletionEvent completion;
@@ -1277,6 +1306,10 @@ bool ThreadProxy::MainFrameWillHappenForTesting() {
return main_frame_will_happen;
}
+void ThreadProxy::SetChildrenNeedBeginFrames(bool children_need_begin_frames) {
+ NOTREACHED() << "Only used by SingleThreadProxy";
+}
+
void ThreadProxy::MainFrameWillHappenOnImplThreadForTesting(
CompletionEvent* completion,
bool* main_frame_will_happen) {
@@ -1340,10 +1373,10 @@ void ThreadProxy::RenewTreePriority() {
}
}
-void ThreadProxy::PostDelayedScrollbarFadeOnImplThread(
- const base::Closure& start_fade,
+void ThreadProxy::PostDelayedAnimationTaskOnImplThread(
+ const base::Closure& task,
base::TimeDelta delay) {
- Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, start_fade, delay);
+ Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, task, delay);
}
void ThreadProxy::DidActivateSyncTree() {
@@ -1358,14 +1391,26 @@ void ThreadProxy::DidActivateSyncTree() {
impl().completion_event_for_commit_held_on_tree_activation = NULL;
}
- UpdateBackgroundAnimateTicking();
-
impl().timing_history.DidActivateSyncTree();
+ impl().last_processed_begin_main_frame_args =
+ impl().last_begin_main_frame_args;
+}
+
+void ThreadProxy::DidPrepareTiles() {
+ DCHECK(IsImplThread());
+ impl().scheduler->DidPrepareTiles();
+}
+
+void ThreadProxy::DidCompletePageScaleAnimationOnImplThread() {
+ DCHECK(IsImplThread());
+ Proxy::MainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadProxy::DidCompletePageScaleAnimation,
+ main_thread_weak_ptr_));
}
-void ThreadProxy::DidManageTiles() {
+void ThreadProxy::OnDrawForOutputSurface() {
DCHECK(IsImplThread());
- impl().scheduler->DidManageTiles();
+ impl().scheduler->OnDrawForOutputSurface();
}
} // namespace cc
diff --git a/chromium/cc/trees/thread_proxy.h b/chromium/cc/trees/thread_proxy.h
index 2f3e7c56a67..f4f1f283c77 100644
--- a/chromium/cc/trees/thread_proxy.h
+++ b/chromium/cc/trees/thread_proxy.h
@@ -14,6 +14,7 @@
#include "cc/base/completion_event.h"
#include "cc/base/delayed_unique_notifier.h"
#include "cc/resources/resource_update_controller.h"
+#include "cc/scheduler/commit_earlyout_reason.h"
#include "cc/scheduler/scheduler.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/proxy.h"
@@ -25,9 +26,11 @@ class SingleThreadTaskRunner;
namespace cc {
+class BeginFrameSource;
class ContextProvider;
class InputHandlerClient;
class LayerTreeHost;
+class PrioritizedResourceManager;
class ResourceUpdateQueue;
class Scheduler;
class ScopedThreadProxy;
@@ -40,7 +43,8 @@ class CC_EXPORT ThreadProxy : public Proxy,
static scoped_ptr<Proxy> Create(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
~ThreadProxy() override;
@@ -70,13 +74,12 @@ class CC_EXPORT ThreadProxy : public Proxy,
bool commit_request_sent_to_impl_thread;
bool started;
- bool manage_tiles_pending;
+ bool prepare_tiles_pending;
bool can_cancel_commit;
bool defer_commits;
RendererCapabilities renderer_capabilities_main_thread_copy;
- scoped_ptr<BeginMainFrameAndCommitState> pending_deferred_commit;
base::WeakPtrFactory<ThreadProxy> weak_factory;
};
@@ -96,7 +99,8 @@ class CC_EXPORT ThreadProxy : public Proxy,
CompositorThreadOnly(
ThreadProxy* proxy,
int layer_tree_host_id,
- RenderingStatsInstrumentation* rendering_stats_instrumentation);
+ RenderingStatsInstrumentation* rendering_stats_instrumentation,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
~CompositorThreadOnly();
const int layer_tree_host_id;
@@ -137,6 +141,12 @@ class CC_EXPORT ThreadProxy : public Proxy,
ProxyTimingHistory timing_history;
+ scoped_ptr<BeginFrameSource> external_begin_frame_source;
+
+ // Values used to keep track of frame durations. Used only in frame timing.
+ BeginFrameArgs last_begin_main_frame_args;
+ BeginFrameArgs last_processed_begin_main_frame_args;
+
scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl;
base::WeakPtrFactory<ThreadProxy> weak_factory;
};
@@ -148,9 +158,11 @@ class CC_EXPORT ThreadProxy : public Proxy,
// Proxy implementation
void FinishAllRendering() override;
bool IsStarted() const override;
+ bool CommitToActiveTree() const override;
void SetOutputSurface(scoped_ptr<OutputSurface>) override;
void SetLayerTreeHostClientReady() override;
void SetVisible(bool visible) override;
+ void SetThrottleFrameProduction(bool throttle) override;
const RendererCapabilities& GetRendererCapabilities() const override;
void SetNeedsAnimate() override;
void SetNeedsUpdateLayers() override;
@@ -168,8 +180,9 @@ class CC_EXPORT ThreadProxy : public Proxy,
void ForceSerializeOnSwapBuffers() override;
bool SupportsImplScrolling() const override;
void SetDebugState(const LayerTreeDebugState& debug_state) override;
- void AsValueInto(base::debug::TracedValue* value) const override;
bool MainFrameWillHappenForTesting() override;
+ void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override;
+ void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) override;
// LayerTreeHostImplClient implementation
void UpdateRendererCapabilitiesOnImplThread() override;
@@ -182,51 +195,57 @@ class CC_EXPORT ThreadProxy : public Proxy,
void DidSwapBuffersCompleteOnImplThread() override;
void OnCanDrawStateChanged(bool can_draw) override;
void NotifyReadyToActivate() override;
+ void NotifyReadyToDraw() override;
// Please call these 3 functions through
// LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
// SetNeedsAnimate().
void SetNeedsRedrawOnImplThread() override;
void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
void SetNeedsAnimateOnImplThread() override;
- void SetNeedsManageTilesOnImplThread() override;
- void DidInitializeVisibleTileOnImplThread() override;
+ void SetNeedsPrepareTilesOnImplThread() override;
void SetNeedsCommitOnImplThread() override;
+ void SetVideoNeedsBeginFrames(bool needs_begin_frames) override;
void PostAnimationEventsToMainThreadOnImplThread(
scoped_ptr<AnimationEventsVector> queue) override;
bool ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes,
int priority_cutoff) override;
bool IsInsideDraw() override;
void RenewTreePriority() override;
- void PostDelayedScrollbarFadeOnImplThread(const base::Closure& start_fade,
+ void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
base::TimeDelta delay) override;
void DidActivateSyncTree() override;
- void DidManageTiles() override;
+ void DidPrepareTiles() override;
+ void DidCompletePageScaleAnimationOnImplThread() override;
+ void OnDrawForOutputSurface() override;
// SchedulerClient implementation
- BeginFrameSource* ExternalBeginFrameSource() override;
void WillBeginImplFrame(const BeginFrameArgs& args) override;
+ void DidFinishImplFrame() override;
void ScheduledActionSendBeginMainFrame() override;
DrawResult ScheduledActionDrawAndSwapIfPossible() override;
DrawResult ScheduledActionDrawAndSwapForced() override;
void ScheduledActionAnimate() override;
void ScheduledActionCommit() override;
- void ScheduledActionUpdateVisibleTiles() override;
void ScheduledActionActivateSyncTree() override;
void ScheduledActionBeginOutputSurfaceCreation() override;
- void ScheduledActionManageTiles() override;
+ void ScheduledActionPrepareTiles() override;
+ void ScheduledActionInvalidateOutputSurface() override;
void DidAnticipatedDrawTimeChange(base::TimeTicks time) override;
base::TimeDelta DrawDurationEstimate() override;
base::TimeDelta BeginMainFrameToCommitDurationEstimate() override;
base::TimeDelta CommitToActivateDurationEstimate() override;
- void DidBeginImplFrameDeadline() override;
+ void SendBeginFramesToChildren(const BeginFrameArgs& args) override;
+ void SendBeginMainFrameNotExpectedSoon() override;
// ResourceUpdateControllerClient implementation
void ReadyToFinalizeTextureUpdates() override;
protected:
- ThreadProxy(LayerTreeHost* layer_tree_host,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+ ThreadProxy(
+ LayerTreeHost* layer_tree_host,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
private:
// Called on main thread.
@@ -234,6 +253,7 @@ class CC_EXPORT ThreadProxy : public Proxy,
const RendererCapabilities& capabilities);
void BeginMainFrame(
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state);
+ void BeginMainFrameNotExpectedSoon();
void DidCommitAndDrawFrame();
void DidCompleteSwapBuffers();
void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue);
@@ -242,18 +262,19 @@ class CC_EXPORT ThreadProxy : public Proxy,
void DidInitializeOutputSurface(bool success,
const RendererCapabilities& capabilities);
void SendCommitRequestToImplThreadIfNeeded();
+ void DidCompletePageScaleAnimation();
// Called on impl thread.
struct SchedulerStateRequest;
void StartCommitOnImplThread(CompletionEvent* completion,
ResourceUpdateQueue* queue);
- void BeginMainFrameAbortedOnImplThread(bool did_handle);
+ void BeginMainFrameAbortedOnImplThread(CommitEarlyOutReason reason);
void FinishAllRenderingOnImplThread(CompletionEvent* completion);
void InitializeImplOnImplThread(CompletionEvent* completion);
void SetLayerTreeHostClientReadyOnImplThread();
void SetVisibleOnImplThread(CompletionEvent* completion, bool visible);
- void UpdateBackgroundAnimateTicking();
+ void SetThrottleFrameProductionOnImplThread(bool throttle);
void HasInitializedOutputSurfaceOnImplThread(
CompletionEvent* completion,
bool* has_initialized_output_surface);
@@ -266,12 +287,11 @@ class CC_EXPORT ThreadProxy : public Proxy,
void ForceSerializeOnSwapBuffersOnImplThread(CompletionEvent* completion);
void MainFrameWillHappenOnImplThreadForTesting(CompletionEvent* completion,
bool* main_frame_will_happen);
- void AsValueOnImplThread(CompletionEvent* completion,
- base::debug::TracedValue* state) const;
void SetSwapUsedIncompleteTileOnImplThread(bool used_incomplete_tile);
void MainThreadHasStoppedFlingingOnImplThread();
void SetInputThrottledUntilCommitOnImplThread(bool is_throttled);
void SetDebugStateOnImplThread(const LayerTreeDebugState& debug_state);
+ void SetDeferCommitsOnImplThread(bool defer_commits) const;
LayerTreeHost* layer_tree_host();
const LayerTreeHost* layer_tree_host() const;
diff --git a/chromium/cc/trees/tree_synchronizer.cc b/chromium/cc/trees/tree_synchronizer.cc
index d17f0175b9d..8fe23077a41 100644
--- a/chromium/cc/trees/tree_synchronizer.cc
+++ b/chromium/cc/trees/tree_synchronizer.cc
@@ -8,8 +8,8 @@
#include "base/containers/hash_tables.h"
#include "base/containers/scoped_ptr_hash_map.h"
-#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "cc/animation/scrollbar_animation_controller.h"
#include "cc/input/scrollbar.h"
#include "cc/layers/layer.h"
@@ -19,7 +19,8 @@
namespace cc {
-typedef base::ScopedPtrHashMap<int, LayerImpl> ScopedPtrLayerImplMap;
+typedef base::ScopedPtrHashMap<int, scoped_ptr<LayerImpl>>
+ ScopedPtrLayerImplMap;
typedef base::hash_map<int, LayerImpl*> RawPtrLayerImplMap;
void CollectExistingLayerImplRecursive(ScopedPtrLayerImplMap* old_layers,
@@ -297,7 +298,7 @@ void TreeSynchronizer::PushProperties(Layer* layer,
size_t num_dependents_need_push_properties = 0;
PushPropertiesInternal(
layer, layer_impl, &num_dependents_need_push_properties);
-#if DCHECK_IS_ON
+#if DCHECK_IS_ON()
CheckScrollAndClipPointersRecursive(layer, layer_impl);
#endif
}
diff --git a/chromium/cc/trees/tree_synchronizer_unittest.cc b/chromium/cc/trees/tree_synchronizer_unittest.cc
index d48f8213c70..a17bec8e53b 100644
--- a/chromium/cc/trees/tree_synchronizer_unittest.cc
+++ b/chromium/cc/trees/tree_synchronizer_unittest.cc
@@ -556,13 +556,8 @@ TEST_F(TreeSynchronizerTest, SynchronizeAnimations) {
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> host_impl =
- LayerTreeHostImpl::Create(settings,
- NULL,
- &proxy,
- &stats_instrumentation,
- shared_bitmap_manager.get(),
- NULL,
- 0);
+ LayerTreeHostImpl::Create(settings, NULL, &proxy, &stats_instrumentation,
+ shared_bitmap_manager.get(), NULL, NULL, 0);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
host_->SetRootLayer(layer_tree_root);
@@ -595,13 +590,8 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollParent) {
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> host_impl =
- LayerTreeHostImpl::Create(settings,
- NULL,
- &proxy,
- &stats_instrumentation,
- shared_bitmap_manager.get(),
- NULL,
- 0);
+ LayerTreeHostImpl::Create(settings, NULL, &proxy, &stats_instrumentation,
+ shared_bitmap_manager.get(), NULL, NULL, 0);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_parent = Layer::Create();
@@ -668,13 +658,8 @@ TEST_F(TreeSynchronizerTest, SynchronizeClipParent) {
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> host_impl =
- LayerTreeHostImpl::Create(settings,
- NULL,
- &proxy,
- &stats_instrumentation,
- shared_bitmap_manager.get(),
- NULL,
- 0);
+ LayerTreeHostImpl::Create(settings, NULL, &proxy, &stats_instrumentation,
+ shared_bitmap_manager.get(), NULL, NULL, 0);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> clip_parent = Layer::Create();