diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-10-13 13:24:50 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-10-14 10:57:25 +0000 |
commit | af3d4809763ef308f08ced947a73b624729ac7ea (patch) | |
tree | 4402b911e30383f6c6dace1e8cf3b8e85355db3a /chromium/cc | |
parent | 0e8ff63a407fe323e215bb1a2c423c09a4747c8a (diff) | |
download | qtwebengine-chromium-af3d4809763ef308f08ced947a73b624729ac7ea.tar.gz |
BASELINE: Update Chromium to 47.0.2526.14
Also adding in sources needed for spellchecking.
Change-Id: Idd44170fa1616f26315188970a8d5ba7d472b18a
Reviewed-by: Michael BrĂ¼ning <michael.bruning@theqtcompany.com>
Diffstat (limited to 'chromium/cc')
405 files changed, 21521 insertions, 21357 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn index 5cd45c2749c..854111b811e 100644 --- a/chromium/cc/BUILD.gn +++ b/chromium/cc/BUILD.gn @@ -75,12 +75,8 @@ component("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", "debug/rasterize_and_record_benchmark.h", "debug/rasterize_and_record_benchmark_impl.cc", @@ -92,8 +88,6 @@ component("cc") { "debug/ring_buffer.h", "debug/traced_display_item_list.cc", "debug/traced_display_item_list.h", - "debug/traced_picture.cc", - "debug/traced_picture.h", "debug/traced_value.cc", "debug/traced_value.h", "debug/unittest_only_benchmark.cc", @@ -108,6 +102,8 @@ component("cc") { "input/page_scale_animation.h", "input/scroll_elasticity_helper.cc", "input/scroll_elasticity_helper.h", + "input/scroll_state.cc", + "input/scroll_state.h", "input/selection.h", "input/selection_bound_type.h", "input/top_controls_manager.cc", @@ -123,6 +119,7 @@ component("cc") { "layers/delegated_renderer_layer.h", "layers/delegated_renderer_layer_impl.cc", "layers/delegated_renderer_layer_impl.h", + "layers/draw_properties.cc", "layers/draw_properties.h", "layers/heads_up_display_layer.cc", "layers/heads_up_display_layer.h", @@ -138,7 +135,6 @@ component("cc") { "layers/layer_impl.cc", "layers/layer_impl.h", "layers/layer_iterator.h", - "layers/layer_lists.cc", "layers/layer_lists.h", "layers/layer_position_constraint.cc", "layers/layer_position_constraint.h", @@ -162,8 +158,8 @@ component("cc") { "layers/picture_layer_impl.cc", "layers/picture_layer_impl.h", "layers/render_pass_sink.h", - "layers/render_surface.cc", - "layers/render_surface.h", + "layers/render_surface_draw_properties.cc", + "layers/render_surface_draw_properties.h", "layers/render_surface_impl.cc", "layers/render_surface_impl.h", "layers/scrollbar_layer_impl_base.cc", @@ -251,8 +247,12 @@ component("cc") { "output/overlay_candidate_validator.h", "output/overlay_processor.cc", "output/overlay_processor.h", + "output/overlay_strategy_all_or_nothing.cc", + "output/overlay_strategy_all_or_nothing.h", "output/overlay_strategy_common.cc", "output/overlay_strategy_common.h", + "output/overlay_strategy_sandwich.cc", + "output/overlay_strategy_sandwich.h", "output/overlay_strategy_single_on_top.cc", "output/overlay_strategy_single_on_top.h", "output/overlay_strategy_underlay.cc", @@ -269,8 +269,6 @@ component("cc") { "output/renderer_settings.h", "output/shader.cc", "output/shader.h", - "output/software_frame_data.cc", - "output/software_frame_data.h", "output/software_output_device.cc", "output/software_output_device.h", "output/software_renderer.cc", @@ -288,10 +286,14 @@ component("cc") { "playback/clip_path_display_item.h", "playback/compositing_display_item.cc", "playback/compositing_display_item.h", + "playback/discardable_image_map.cc", + "playback/discardable_image_map.h", "playback/display_item.cc", "playback/display_item.h", "playback/display_item_list.cc", "playback/display_item_list.h", + "playback/display_item_list_bounds_calculator.cc", + "playback/display_item_list_bounds_calculator.h", "playback/display_item_list_settings.cc", "playback/display_item_list_settings.h", "playback/display_list_raster_source.cc", @@ -306,21 +308,12 @@ component("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/position_image.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", "quads/content_draw_quad_base.h", "quads/debug_border_draw_quad.cc", @@ -363,8 +356,6 @@ component("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", @@ -392,6 +383,7 @@ component("cc") { "resources/resource_pool.h", "resources/resource_provider.cc", "resources/resource_provider.h", + "resources/resource_util.h", "resources/returned_resource.h", "resources/scoped_resource.cc", "resources/scoped_resource.h", @@ -434,6 +426,8 @@ component("cc") { "scheduler/video_frame_controller.h", "tiles/eviction_tile_priority_queue.cc", "tiles/eviction_tile_priority_queue.h", + "tiles/image_decode_controller.cc", + "tiles/image_decode_controller.h", "tiles/picture_layer_tiling.cc", "tiles/picture_layer_tiling.h", "tiles/picture_layer_tiling_set.cc", @@ -462,6 +456,8 @@ component("cc") { "tiles/tiling_set_raster_queue_required.h", "trees/blocking_task_runner.cc", "trees/blocking_task_runner.h", + "trees/channel_impl.h", + "trees/channel_main.h", "trees/damage_tracker.cc", "trees/damage_tracker.h", "trees/draw_property_utils.cc", @@ -491,6 +487,8 @@ component("cc") { "trees/property_tree_builder.h", "trees/proxy.cc", "trees/proxy.h", + "trees/proxy_impl.h", + "trees/proxy_main.h", "trees/scoped_abort_remaining_swap_promises.h", "trees/single_thread_proxy.cc", "trees/single_thread_proxy.h", @@ -498,6 +496,8 @@ component("cc") { "trees/swap_promise_monitor.h", "trees/thread_proxy.cc", "trees/thread_proxy.h", + "trees/threaded_channel.cc", + "trees/threaded_channel.h", "trees/tree_synchronizer.cc", "trees/tree_synchronizer.h", ] @@ -509,6 +509,8 @@ component("cc") { ] } + configs += [ "//build/config:precompiled_headers" ] + public_deps = [ "//cc/base", "//skia", @@ -523,12 +525,13 @@ component("cc") { "//ui/events:events_base", "//ui/gfx", "//ui/gfx/geometry", + "//ui/gl", ] defines = [ "CC_IMPLEMENTATION=1" ] if (!is_debug && (is_win || is_android)) { - configs -= [ "//build/config/compiler:optimize" ] + configs -= [ "//build/config/compiler:default_optimization" ] configs += [ "//build/config/compiler:optimize_max" ] } } @@ -550,6 +553,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_raster_source.cc", + "test/fake_display_list_raster_source.h", + "test/fake_display_list_recording_source.cc", "test/fake_display_list_recording_source.h", "test/fake_external_begin_frame_source.cc", "test/fake_external_begin_frame_source.h", @@ -574,10 +580,6 @@ 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", "test/fake_proxy.h", "test/fake_renderer_client.cc", @@ -627,8 +629,6 @@ source_set("test_support") { "test/pixel_test_software_output_device.h", "test/pixel_test_utils.cc", "test/pixel_test_utils.h", - "test/render_pass_test_common.cc", - "test/render_pass_test_common.h", "test/render_pass_test_utils.cc", "test/render_pass_test_utils.h", "test/scheduler_test_common.cc", @@ -662,6 +662,7 @@ source_set("test_support") { "test/test_web_graphics_context_3d.h", ] + configs += [ "//build/config:precompiled_headers" ] include_dirs = [ ".", "test", @@ -688,6 +689,7 @@ source_set("test_support") { "//ui/gfx/geometry", "//ui/gfx:test_support", "//ui/gl", + "//ui/gl:test_support", ] if (!is_android) { # TODO(GYP) Enable on Android when osmesa links. @@ -695,6 +697,15 @@ source_set("test_support") { } } +# TODO(GYP): Delete this after we've converted everything to GN. +# The _run targets exist only for compatibility w/ GYP. +group("cc_unittests_run") { + testonly = true + deps = [ + ":cc_unittests", + ] +} + test("cc_unittests") { sources = [ "animation/animation_host_unittest.cc", @@ -708,18 +719,23 @@ test("cc_unittests") { "animation/scrollbar_animation_controller_linear_fade_unittest.cc", "animation/scrollbar_animation_controller_thinning_unittest.cc", "animation/transform_operations_unittest.cc", + "base/delayed_unique_notifier_unittest.cc", "base/float_quad_unittest.cc", "base/histograms_unittest.cc", "base/list_container_unittest.cc", "base/math_util_unittest.cc", + "base/random_access_list_container_unittest.cc", "base/region_unittest.cc", "base/rolling_time_delta_history_unittest.cc", + "base/rtree_unittest.cc", "base/scoped_ptr_vector_unittest.cc", - "base/sidecar_list_container_unittest.cc", "base/simple_enclosed_region_unittest.cc", "base/tiling_data_unittest.cc", + "base/unique_notifier_unittest.cc", "debug/frame_timing_tracker_unittest.cc", "debug/micro_benchmark_controller_unittest.cc", + "debug/rendering_stats_unittest.cc", + "input/scroll_state_unittest.cc", "input/top_controls_manager_unittest.cc", "layers/delegated_frame_provider_unittest.cc", "layers/delegated_frame_resource_collection_unittest.cc", @@ -754,6 +770,7 @@ test("cc_unittests") { "layers/video_frame_provider_client_impl_unittest.cc", "layers/video_layer_impl_unittest.cc", "output/begin_frame_args_unittest.cc", + "output/bsp_tree_unittest.cc", "output/delegating_renderer_unittest.cc", "output/filter_operations_unittest.cc", "output/gl_renderer_unittest.cc", @@ -765,14 +782,11 @@ test("cc_unittests") { "output/shader_unittest.cc", "output/software_renderer_unittest.cc", "output/texture_mailbox_deleter_unittest.cc", + "playback/discardable_image_map_unittest.cc", "playback/display_item_list_unittest.cc", "playback/display_list_raster_source_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/render_pass_unittest.cc", "raster/scoped_gpu_raster_unittest.cc", @@ -782,6 +796,7 @@ test("cc_unittests") { "resources/platform_color_unittest.cc", "resources/resource_pool_unittest.cc", "resources/resource_provider_unittest.cc", + "resources/resource_util_unittest.cc", "resources/scoped_resource_unittest.cc", "resources/video_resource_updater_unittest.cc", "scheduler/begin_frame_source_unittest.cc", @@ -790,6 +805,7 @@ test("cc_unittests") { "scheduler/scheduler_state_machine_unittest.cc", "scheduler/scheduler_unittest.cc", "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", @@ -824,9 +840,14 @@ test("cc_unittests") { "trees/tree_synchronizer_unittest.cc", # Surfaces test files. + "surfaces/display_scheduler_unittest.cc", + "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_hittest_unittest.cc", "surfaces/surface_unittest.cc", "surfaces/surfaces_pixeltest.cc", @@ -835,6 +856,11 @@ test("cc_unittests") { "test/run_all_unittests.cc", ] + configs += [ "//build/config:precompiled_headers" ] + data = [ + "test/data/", + ] + deps = [ ":cc", ":test_support", @@ -853,14 +879,16 @@ test("cc_unittests") { "//ui/gfx/geometry", "//ui/gfx:test_support", "//ui/gl", + "//ui/gl:test_support", ] + + data_deps = [ "//third_party/mesa:osmesa" ] } test("cc_perftests") { sources = [ "layers/layer_perftest.cc", "layers/picture_layer_impl_perftest.cc", - "playback/picture_pile_impl_perftest.cc", "quads/draw_quad_perftest.cc", "raster/task_graph_runner_perftest.cc", "raster/texture_compressor_perftest.cc", @@ -893,6 +921,7 @@ test("cc_perftests") { "//ui/gfx", "//ui/gfx/geometry", "//ui/gl", + "//ui/gl:test_support", ] if (is_android) { diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS index 6cc39e71a21..952f4b51d2d 100644 --- a/chromium/cc/OWNERS +++ b/chromium/cc/OWNERS @@ -6,8 +6,8 @@ # ask for informal reviews. enne@chromium.org -jamesr@chromium.org -nduca@chromium.org +danakj@chromium.org +vmpstr@chromium.org # layers / quads / passes enne@chromium.org @@ -17,8 +17,7 @@ danakj@chromium.org piman@chromium.org danakj@chromium.org -# resource management / mac-specific -# unofficial: epenner@chromium.org +# mac-specific ccameron@chromium.org # input, gestures, scrolling @@ -47,6 +46,10 @@ vollick@chromium.org vollick@chromium.org ajuma@chromium.org +# we miss you +# jamesr@chromium.org +# nduca@chromium.org + per-file *.isolate=maruel@chromium.org per-file *.isolate=tandrii@chromium.org per-file *.isolate=vadimsh@chromium.org diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc index e7f289fad9a..a9515be20aa 100644 --- a/chromium/cc/animation/animation_host.cc +++ b/chromium/cc/animation/animation_host.cc @@ -357,41 +357,79 @@ bool AnimationHost::ScrollOffsetAnimationWasInterrupted(int layer_id) const { : false; } -bool AnimationHost::IsAnimatingFilterProperty(int layer_id) const { +static LayerAnimationController::ObserverType ObserverTypeFromTreeType( + LayerTreeType tree_type) { + return tree_type == LayerTreeType::ACTIVE + ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; +} + +bool AnimationHost::IsAnimatingFilterProperty(int layer_id, + LayerTreeType tree_type) const { LayerAnimationController* controller = GetControllerForLayerId(layer_id); - return controller ? controller->IsAnimatingProperty(Animation::FILTER) - : false; + return controller + ? controller->IsCurrentlyAnimatingProperty( + Animation::FILTER, ObserverTypeFromTreeType(tree_type)) + : false; } -bool AnimationHost::IsAnimatingOpacityProperty(int layer_id) const { +bool AnimationHost::IsAnimatingOpacityProperty(int layer_id, + LayerTreeType tree_type) const { LayerAnimationController* controller = GetControllerForLayerId(layer_id); - return controller ? controller->IsAnimatingProperty(Animation::OPACITY) - : false; + return controller + ? controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, ObserverTypeFromTreeType(tree_type)) + : false; } -bool AnimationHost::IsAnimatingTransformProperty(int layer_id) const { +bool AnimationHost::IsAnimatingTransformProperty( + int layer_id, + LayerTreeType tree_type) const { LayerAnimationController* controller = GetControllerForLayerId(layer_id); - return controller ? controller->IsAnimatingProperty(Animation::TRANSFORM) - : false; + return controller + ? controller->IsCurrentlyAnimatingProperty( + Animation::TRANSFORM, ObserverTypeFromTreeType(tree_type)) + : false; } -bool AnimationHost::HasPotentiallyRunningOpacityAnimation(int layer_id) const { +bool AnimationHost::HasPotentiallyRunningFilterAnimation( + int layer_id, + LayerTreeType tree_type) const { LayerAnimationController* controller = GetControllerForLayerId(layer_id); - if (!controller) - return false; + return controller + ? controller->IsPotentiallyAnimatingProperty( + Animation::FILTER, ObserverTypeFromTreeType(tree_type)) + : false; +} - Animation* animation = controller->GetAnimation(Animation::OPACITY); - return animation && !animation->is_finished(); +bool AnimationHost::HasPotentiallyRunningOpacityAnimation( + int layer_id, + LayerTreeType tree_type) const { + LayerAnimationController* controller = GetControllerForLayerId(layer_id); + return controller + ? controller->IsPotentiallyAnimatingProperty( + Animation::OPACITY, ObserverTypeFromTreeType(tree_type)) + : false; } bool AnimationHost::HasPotentiallyRunningTransformAnimation( - int layer_id) const { + int layer_id, + LayerTreeType tree_type) const { + LayerAnimationController* controller = GetControllerForLayerId(layer_id); + return controller + ? controller->IsPotentiallyAnimatingProperty( + Animation::TRANSFORM, ObserverTypeFromTreeType(tree_type)) + : false; +} + +bool AnimationHost::HasAnyAnimationTargetingProperty( + int layer_id, + Animation::TargetProperty property) const { LayerAnimationController* controller = GetControllerForLayerId(layer_id); if (!controller) return false; - Animation* animation = controller->GetAnimation(Animation::TRANSFORM); - return animation && !animation->is_finished(); + return !!controller->GetAnimation(property); } bool AnimationHost::FilterIsAnimatingOnImplOnly(int layer_id) const { @@ -456,9 +494,14 @@ bool AnimationHost::TransformAnimationBoundsForBox(int layer_id, : true; } -bool AnimationHost::HasOnlyTranslationTransforms(int layer_id) const { +bool AnimationHost::HasOnlyTranslationTransforms( + int layer_id, + LayerTreeType tree_type) const { LayerAnimationController* controller = GetControllerForLayerId(layer_id); - return controller ? controller->HasOnlyTranslationTransforms() : true; + return controller + ? controller->HasOnlyTranslationTransforms( + ObserverTypeFromTreeType(tree_type)) + : true; } bool AnimationHost::AnimationsPreserveAxisAlignment(int layer_id) const { @@ -466,17 +509,26 @@ bool AnimationHost::AnimationsPreserveAxisAlignment(int layer_id) const { return controller ? controller->AnimationsPreserveAxisAlignment() : true; } -bool AnimationHost::MaximumTargetScale(int layer_id, float* max_scale) const { +bool AnimationHost::MaximumTargetScale(int layer_id, + LayerTreeType tree_type, + float* max_scale) const { *max_scale = 0.f; LayerAnimationController* controller = GetControllerForLayerId(layer_id); - return controller ? controller->MaximumTargetScale(max_scale) : true; + return controller + ? controller->MaximumTargetScale( + ObserverTypeFromTreeType(tree_type), max_scale) + : true; } bool AnimationHost::AnimationStartScale(int layer_id, + LayerTreeType tree_type, float* start_scale) const { *start_scale = 0.f; LayerAnimationController* controller = GetControllerForLayerId(layer_id); - return controller ? controller->AnimationStartScale(start_scale) : true; + return controller + ? controller->AnimationStartScale( + ObserverTypeFromTreeType(tree_type), start_scale) + : true; } bool AnimationHost::HasAnyAnimation(int layer_id) const { diff --git a/chromium/cc/animation/animation_host.h b/chromium/cc/animation/animation_host.h index 3f69a023379..05782c09786 100644 --- a/chromium/cc/animation/animation_host.h +++ b/chromium/cc/animation/animation_host.h @@ -93,12 +93,21 @@ class CC_EXPORT AnimationHost { bool ScrollOffsetAnimationWasInterrupted(int layer_id) const; - bool IsAnimatingFilterProperty(int layer_id) const; - bool IsAnimatingOpacityProperty(int layer_id) const; - bool IsAnimatingTransformProperty(int layer_id) const; - - bool HasPotentiallyRunningOpacityAnimation(int layer_id) const; - bool HasPotentiallyRunningTransformAnimation(int layer_id) const; + bool IsAnimatingFilterProperty(int layer_id, LayerTreeType tree_type) const; + bool IsAnimatingOpacityProperty(int layer_id, LayerTreeType tree_type) const; + bool IsAnimatingTransformProperty(int layer_id, + LayerTreeType tree_type) const; + + bool HasPotentiallyRunningFilterAnimation(int layer_id, + LayerTreeType tree_type) const; + bool HasPotentiallyRunningOpacityAnimation(int layer_id, + LayerTreeType tree_type) const; + bool HasPotentiallyRunningTransformAnimation(int layer_id, + LayerTreeType tree_type) const; + + bool HasAnyAnimationTargetingProperty( + int layer_id, + Animation::TargetProperty property) const; bool FilterIsAnimatingOnImplOnly(int layer_id) const; bool OpacityIsAnimatingOnImplOnly(int layer_id) const; @@ -115,11 +124,16 @@ class CC_EXPORT AnimationHost { const gfx::BoxF& box, gfx::BoxF* bounds) const; - bool HasOnlyTranslationTransforms(int layer_id) const; + bool HasOnlyTranslationTransforms(int layer_id, + LayerTreeType tree_type) const; bool AnimationsPreserveAxisAlignment(int layer_id) const; - bool MaximumTargetScale(int layer_id, float* max_scale) const; - bool AnimationStartScale(int layer_id, float* start_scale) const; + bool MaximumTargetScale(int layer_id, + LayerTreeType tree_type, + float* max_scale) const; + bool AnimationStartScale(int layer_id, + LayerTreeType tree_type, + float* start_scale) const; bool HasAnyAnimation(int layer_id) const; bool HasActiveAnimation(int layer_id) const; diff --git a/chromium/cc/animation/animation_timeline.cc b/chromium/cc/animation/animation_timeline.cc index 9d19f8fbe0b..c3f5e6918b7 100644 --- a/chromium/cc/animation/animation_timeline.cc +++ b/chromium/cc/animation/animation_timeline.cc @@ -35,8 +35,8 @@ void AnimationTimeline::SetAnimationHost(AnimationHost* animation_host) { } void AnimationTimeline::AttachPlayer(scoped_refptr<AnimationPlayer> player) { - DCHECK(animation_host_); player->SetAnimationHost(animation_host_); + player->SetAnimationTimeline(this); players_.push_back(player); } diff --git a/chromium/cc/animation/element_animations.cc b/chromium/cc/animation/element_animations.cc index 2974bff91a2..b358b5b5e6d 100644 --- a/chromium/cc/animation/element_animations.cc +++ b/chromium/cc/animation/element_animations.cc @@ -41,6 +41,11 @@ class ElementAnimations::ValueObserver : public LayerAnimationValueObserver { // PushProperties for AnimationTimelines for now. } + void OnTransformIsPotentiallyAnimatingChanged(bool is_animating) override { + element_animations_->SetTransformIsPotentiallyAnimatingChanged( + tree_type_, is_animating); + } + bool IsActive() const override { return tree_type_ == LayerTreeType::ACTIVE; } private: @@ -184,6 +189,18 @@ void ElementAnimations::SetScrollOffsetMutated( layer_id(), tree_type, scroll_offset); } +void ElementAnimations::SetTransformIsPotentiallyAnimatingChanged( + LayerTreeType tree_type, + bool is_animating) { + DCHECK(layer_id()); + DCHECK(animation_host()); + DCHECK(animation_host()->mutator_host_client()); + animation_host() + ->mutator_host_client() + ->LayerTransformIsPotentiallyAnimatingChanged(layer_id(), tree_type, + is_animating); +} + void ElementAnimations::CreateActiveValueObserver() { DCHECK(layer_animation_controller_); DCHECK(!active_value_observer_); diff --git a/chromium/cc/animation/element_animations.h b/chromium/cc/animation/element_animations.h index 6fb2a429d4a..0d4fb6ac383 100644 --- a/chromium/cc/animation/element_animations.h +++ b/chromium/cc/animation/element_animations.h @@ -83,6 +83,8 @@ class CC_EXPORT ElementAnimations : public AnimationDelegate, const gfx::Transform& transform); void SetScrollOffsetMutated(LayerTreeType tree_type, const gfx::ScrollOffset& scroll_offset); + void SetTransformIsPotentiallyAnimatingChanged(LayerTreeType tree_type, + bool is_animating); void CreateActiveValueObserver(); void DestroyActiveValueObserver(); diff --git a/chromium/cc/animation/layer_animation_controller.cc b/chromium/cc/animation/layer_animation_controller.cc index 54b1a717f78..d649ac73972 100644 --- a/chromium/cc/animation/layer_animation_controller.cc +++ b/chromium/cc/animation/layer_animation_controller.cc @@ -28,8 +28,9 @@ LayerAnimationController::LayerAnimationController(int id) value_provider_(nullptr), layer_animation_delegate_(nullptr), needs_to_start_animations_(false), - scroll_offset_animation_was_interrupted_(false) { -} + scroll_offset_animation_was_interrupted_(false), + potentially_animating_transform_for_active_observers_(false), + potentially_animating_transform_for_pending_observers_(false) {} LayerAnimationController::~LayerAnimationController() { if (registrar_) @@ -46,7 +47,8 @@ void LayerAnimationController::PauseAnimation(int animation_id, for (size_t i = 0; i < animations_.size(); ++i) { if (animations_[i]->id() == animation_id) { animations_[i]->SetRunState(Animation::PAUSED, - time_offset + animations_[i]->start_time()); + time_offset + animations_[i]->start_time() + + animations_[i]->time_offset()); } } } @@ -61,17 +63,56 @@ struct HasAnimationId { int id_; }; +void LayerAnimationController::UpdatePotentiallyAnimatingTransform() { + bool was_potentially_animating_transform_for_active_observers = + potentially_animating_transform_for_active_observers_; + bool was_potentially_animating_transform_for_pending_observers = + potentially_animating_transform_for_pending_observers_; + + potentially_animating_transform_for_active_observers_ = false; + potentially_animating_transform_for_pending_observers_ = false; + + for (Animation* animation : animations_) { + if (!animation->is_finished() && + animation->target_property() == Animation::TRANSFORM) { + potentially_animating_transform_for_active_observers_ |= + animation->affects_active_observers(); + potentially_animating_transform_for_pending_observers_ |= + animation->affects_pending_observers(); + } + } + + bool changed_for_active_observers = + was_potentially_animating_transform_for_active_observers != + potentially_animating_transform_for_active_observers_; + bool changed_for_pending_observers = + was_potentially_animating_transform_for_pending_observers != + potentially_animating_transform_for_pending_observers_; + + if (!changed_for_active_observers && !changed_for_pending_observers) + return; + + NotifyObserversTransformIsPotentiallyAnimatingChanged( + changed_for_active_observers, changed_for_pending_observers); +} + void LayerAnimationController::RemoveAnimation(int animation_id) { + bool removed_transform_animation = false; 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; + } else if ((*it)->target_property() == Animation::TRANSFORM && + !(*it)->is_finished()) { + removed_transform_animation = true; } } + animations_.erase(animations_to_remove, animations_.end()); UpdateActivation(NORMAL_ACTIVATION); + if (removed_transform_animation) + UpdatePotentiallyAnimatingTransform(); } struct HasAnimationIdAndProperty { @@ -90,23 +131,37 @@ struct HasAnimationIdAndProperty { void LayerAnimationController::RemoveAnimation( int animation_id, Animation::TargetProperty target_property) { + bool removed_transform_animation = false; auto animations_to_remove = animations_.remove_if( HasAnimationIdAndProperty(animation_id, target_property)); - if (target_property == Animation::SCROLL_OFFSET && - animations_to_remove != animations_.end()) + if (animations_to_remove == animations_.end()) + return; + + if (target_property == Animation::SCROLL_OFFSET) scroll_offset_animation_was_interrupted_ = true; + else if (target_property == Animation::TRANSFORM && + !(*animations_to_remove)->is_finished()) + removed_transform_animation = true; animations_.erase(animations_to_remove, animations_.end()); UpdateActivation(NORMAL_ACTIVATION); + if (removed_transform_animation) + UpdatePotentiallyAnimatingTransform(); } void LayerAnimationController::AbortAnimations( Animation::TargetProperty target_property) { + bool aborted_transform_animation = false; for (size_t i = 0; i < animations_.size(); ++i) { if (animations_[i]->target_property() == target_property && - !animations_[i]->is_finished()) + !animations_[i]->is_finished()) { animations_[i]->SetRunState(Animation::ABORTED, last_tick_time_); + if (target_property == Animation::TRANSFORM) + aborted_transform_animation = true; + } } + if (aborted_transform_animation) + UpdatePotentiallyAnimatingTransform(); } // Ensures that the list of active animations on the main thread and the impl @@ -241,7 +296,12 @@ struct AffectsNoObservers { }; void LayerAnimationController::ActivateAnimations() { + bool changed_transform_animation = false; for (size_t i = 0; i < animations_.size(); ++i) { + if (animations_[i]->affects_active_observers() != + animations_[i]->affects_pending_observers() && + animations_[i]->target_property() == Animation::TRANSFORM) + changed_transform_animation = true; animations_[i]->set_affects_active_observers( animations_[i]->affects_pending_observers()); } @@ -252,12 +312,18 @@ void LayerAnimationController::ActivateAnimations() { animations_.end()); scroll_offset_animation_was_interrupted_ = false; UpdateActivation(NORMAL_ACTIVATION); + if (changed_transform_animation) + UpdatePotentiallyAnimatingTransform(); } void LayerAnimationController::AddAnimation(scoped_ptr<Animation> animation) { + bool added_transform_animation = + animation->target_property() == Animation::TRANSFORM; animations_.push_back(animation.Pass()); needs_to_start_animations_ = true; UpdateActivation(NORMAL_ACTIVATION); + if (added_transform_animation) + UpdatePotentiallyAnimatingTransform(); } Animation* LayerAnimationController::GetAnimation( @@ -285,13 +351,35 @@ bool LayerAnimationController::HasActiveAnimation() const { return false; } -bool LayerAnimationController::IsAnimatingProperty( - Animation::TargetProperty target_property) const { +bool LayerAnimationController::IsPotentiallyAnimatingProperty( + Animation::TargetProperty target_property, + ObserverType observer_type) const { + for (size_t i = 0; i < animations_.size(); ++i) { + if (!animations_[i]->is_finished() && + animations_[i]->target_property() == target_property) { + if ((observer_type == ObserverType::ACTIVE && + animations_[i]->affects_active_observers()) || + (observer_type == ObserverType::PENDING && + animations_[i]->affects_pending_observers())) + return true; + } + } + return false; +} + +bool LayerAnimationController::IsCurrentlyAnimatingProperty( + Animation::TargetProperty target_property, + ObserverType observer_type) const { for (size_t i = 0; i < animations_.size(); ++i) { if (!animations_[i]->is_finished() && animations_[i]->InEffect(last_tick_time_) && - animations_[i]->target_property() == target_property) - return true; + animations_[i]->target_property() == target_property) { + if ((observer_type == ObserverType::ACTIVE && + animations_[i]->affects_active_observers()) || + (observer_type == ObserverType::PENDING && + animations_[i]->affects_pending_observers())) + return true; + } } return false; } @@ -365,12 +453,17 @@ void LayerAnimationController::NotifyAnimationFinished( void LayerAnimationController::NotifyAnimationAborted( const AnimationEvent& event) { + bool aborted_transform_animation = false; 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); + if (event.target_property == Animation::TRANSFORM) + aborted_transform_animation = true; } } + if (aborted_transform_animation) + UpdatePotentiallyAnimatingTransform(); } void LayerAnimationController::NotifyAnimationPropertyUpdate( @@ -428,7 +521,10 @@ bool LayerAnimationController::HasFilterAnimationThatInflatesBounds() const { } bool LayerAnimationController::HasTransformAnimationThatInflatesBounds() const { - return IsAnimatingProperty(Animation::TRANSFORM); + return IsCurrentlyAnimatingProperty(Animation::TRANSFORM, + ObserverType::ACTIVE) || + IsCurrentlyAnimatingProperty(Animation::TRANSFORM, + ObserverType::PENDING); } bool LayerAnimationController::FilterAnimationBoundsForBox( @@ -483,12 +579,19 @@ bool LayerAnimationController::HasAnimationThatAffectsScale() const { return false; } -bool LayerAnimationController::HasOnlyTranslationTransforms() const { +bool LayerAnimationController::HasOnlyTranslationTransforms( + ObserverType observer_type) const { for (size_t i = 0; i < animations_.size(); ++i) { if (animations_[i]->is_finished() || animations_[i]->target_property() != Animation::TRANSFORM) continue; + if ((observer_type == ObserverType::ACTIVE && + !animations_[i]->affects_active_observers()) || + (observer_type == ObserverType::PENDING && + !animations_[i]->affects_pending_observers())) + continue; + const TransformAnimationCurve* transform_animation_curve = animations_[i]->curve()->ToTransformAnimationCurve(); if (!transform_animation_curve->IsTranslation()) @@ -513,13 +616,20 @@ bool LayerAnimationController::AnimationsPreserveAxisAlignment() const { return true; } -bool LayerAnimationController::AnimationStartScale(float* start_scale) const { +bool LayerAnimationController::AnimationStartScale(ObserverType observer_type, + 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; + if ((observer_type == ObserverType::ACTIVE && + !animations_[i]->affects_active_observers()) || + (observer_type == ObserverType::PENDING && + !animations_[i]->affects_pending_observers())) + continue; + bool forward_direction = true; switch (animations_[i]->direction()) { case Animation::DIRECTION_NORMAL: @@ -543,13 +653,20 @@ bool LayerAnimationController::AnimationStartScale(float* start_scale) const { return true; } -bool LayerAnimationController::MaximumTargetScale(float* max_scale) const { +bool LayerAnimationController::MaximumTargetScale(ObserverType observer_type, + 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) continue; + if ((observer_type == ObserverType::ACTIVE && + !animations_[i]->affects_active_observers()) || + (observer_type == ObserverType::PENDING && + !animations_[i]->affects_pending_observers())) + continue; + bool forward_direction = true; switch (animations_[i]->direction()) { case Animation::DIRECTION_NORMAL: @@ -627,20 +744,27 @@ static bool AffectsActiveOnlyAndIsWaitingForDeletion(Animation* animation) { void LayerAnimationController::RemoveAnimationsCompletedOnMainThread( LayerAnimationController* controller_impl) const { + bool removed_transform_animation = false; // 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 WAITING_FOR_DELETION, they can be removed // immediately. ScopedPtrVector<Animation>& animations = controller_impl->animations_; for (size_t i = 0; i < animations.size(); ++i) { - if (IsCompleted(animations[i], this)) + if (IsCompleted(animations[i], this)) { animations[i]->set_affects_pending_observers(false); + if (animations[i]->target_property() == Animation::TRANSFORM) + removed_transform_animation = true; + } } animations.erase(cc::remove_if(&animations, animations.begin(), animations.end(), AffectsActiveOnlyAndIsWaitingForDeletion), animations.end()); + + if (removed_transform_animation) + controller_impl->UpdatePotentiallyAnimatingTransform(); } void LayerAnimationController::PushPropertiesToImplThread( @@ -775,12 +899,18 @@ void LayerAnimationController::PromoteStartedAnimations( void LayerAnimationController::MarkFinishedAnimations( base::TimeTicks monotonic_time) { + bool finished_transform_animation = false; 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::WAITING_FOR_DELETION) + if (!animations_[i]->is_finished() && + animations_[i]->IsFinishedAt(monotonic_time)) { animations_[i]->SetRunState(Animation::FINISHED, monotonic_time); + if (animations_[i]->target_property() == Animation::TRANSFORM) { + finished_transform_animation = true; + } + } } + if (finished_transform_animation) + UpdatePotentiallyAnimatingTransform(); } void LayerAnimationController::MarkAnimationsForDeletion( @@ -1053,6 +1183,25 @@ void LayerAnimationController::NotifyObserversAnimationWaitingForDeletion() { OnAnimationWaitingForDeletion()); } +void LayerAnimationController:: + NotifyObserversTransformIsPotentiallyAnimatingChanged( + bool notify_active_observers, + bool notify_pending_observers) { + if (value_observers_.might_have_observers()) { + base::ObserverListBase<LayerAnimationValueObserver>::Iterator it( + &value_observers_); + LayerAnimationValueObserver* obs; + while ((obs = it.GetNext()) != nullptr) { + if (notify_active_observers && obs->IsActive()) + obs->OnTransformIsPotentiallyAnimatingChanged( + potentially_animating_transform_for_active_observers_); + else if (notify_pending_observers && !obs->IsActive()) + obs->OnTransformIsPotentiallyAnimatingChanged( + potentially_animating_transform_for_pending_observers_); + } + } +} + bool LayerAnimationController::HasValueObserver() { if (value_observers_.might_have_observers()) { base::ObserverListBase<LayerAnimationValueObserver>::Iterator it( diff --git a/chromium/cc/animation/layer_animation_controller.h b/chromium/cc/animation/layer_animation_controller.h index 4b37ad44930..307e89920ae 100644 --- a/chromium/cc/animation/layer_animation_controller.h +++ b/chromium/cc/animation/layer_animation_controller.h @@ -36,6 +36,8 @@ class LayerAnimationValueProvider; class CC_EXPORT LayerAnimationController : public base::RefCounted<LayerAnimationController> { public: + enum class ObserverType { ACTIVE, PENDING }; + static scoped_refptr<LayerAnimationController> Create(int id); int id() const { return id_; } @@ -79,10 +81,16 @@ class CC_EXPORT LayerAnimationController // Returns true if there are any animations at all to process. bool has_any_animation() const { return !animations_.empty(); } - // Returns true if there is an animation currently animating the given - // property, or if there is an animation scheduled to animate this property in - // the future. - bool IsAnimatingProperty(Animation::TargetProperty target_property) const; + // Returns true if there is an animation that is either currently animating + // the given property or scheduled to animate this property in the future, and + // that affects the given observer type. + bool IsPotentiallyAnimatingProperty(Animation::TargetProperty target_property, + ObserverType observer_type) const; + + // Returns true if there is an animation that is currently animating the given + // property and that affects the given observer type. + bool IsCurrentlyAnimatingProperty(Animation::TargetProperty target_property, + ObserverType observer_type) const; void SetAnimationRegistrar(AnimationRegistrar* registrar); AnimationRegistrar* animation_registrar() { return registrar_; } @@ -130,19 +138,21 @@ class CC_EXPORT LayerAnimationController bool HasAnimationThatAffectsScale() const; - bool HasOnlyTranslationTransforms() const; + bool HasOnlyTranslationTransforms(ObserverType observer_type) 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; + bool AnimationStartScale(ObserverType observer_type, + 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; + bool MaximumTargetScale(ObserverType event_observers_, + float* max_scale) const; // When a scroll animation is removed on the main thread, its compositor // thread counterpart continues producing scroll deltas until activation. @@ -203,6 +213,12 @@ class CC_EXPORT LayerAnimationController void NotifyObserversAnimationWaitingForDeletion(); + void NotifyObserversTransformIsPotentiallyAnimatingChanged( + bool notify_active_observers, + bool notify_pending_observers); + + void UpdatePotentiallyAnimatingTransform(); + bool HasValueObserver(); bool HasActiveValueObserver(); @@ -228,6 +244,9 @@ class CC_EXPORT LayerAnimationController bool scroll_offset_animation_was_interrupted_; + bool potentially_animating_transform_for_active_observers_; + bool potentially_animating_transform_for_pending_observers_; + 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 e267eea1288..8089ebfe294 100644 --- a/chromium/cc/animation/layer_animation_controller_unittest.cc +++ b/chromium/cc/animation/layer_animation_controller_unittest.cc @@ -254,8 +254,14 @@ TEST(LayerAnimationControllerTest, SyncPause) { EXPECT_FALSE(controller_impl->GetAnimation(Animation::OPACITY)); - int animation_id = - AddOpacityTransitionToController(controller.get(), 1, 0, 1, false); + // Two steps, three ranges: [0-1) -> 0.2, [1-2) -> 0.3, [2-3] -> 0.4. + const double duration = 3.0; + const int animation_id = + AddOpacityStepsToController(controller.get(), duration, 0.2f, 0.4f, 2); + + // Set start offset to be at the beginning of the second range. + controller->GetAnimationById(animation_id) + ->set_time_offset(TimeDelta::FromSecondsD(1.01)); controller->PushAnimationUpdatesTo(controller_impl.get()); controller_impl->ActivateAnimations(); @@ -264,29 +270,52 @@ TEST(LayerAnimationControllerTest, SyncPause) { EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY, controller_impl->GetAnimationById(animation_id)->run_state()); + TimeTicks time = kInitialTickTime; + // Start the animations on each controller. AnimationEventsVector events; - controller_impl->Animate(kInitialTickTime); + controller_impl->Animate(time); controller_impl->UpdateState(true, &events); - controller->Animate(kInitialTickTime); + EXPECT_EQ(1u, events.size()); + + controller->Animate(time); controller->UpdateState(true, nullptr); + controller->NotifyAnimationStarted(events[0]); + 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(0.3f, dummy.opacity()); + EXPECT_EQ(0.3f, dummy_impl.opacity()); + + EXPECT_EQ(kInitialTickTime, + controller->GetAnimationById(animation_id)->start_time()); + EXPECT_EQ(kInitialTickTime, + controller_impl->GetAnimationById(animation_id)->start_time()); + + // Pause the animation at the middle of the second range so the offset + // delays animation until the middle of the third range. + controller->PauseAnimation(animation_id, TimeDelta::FromSecondsD(1.5)); 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(); + + // Advance time so it stays within the first range. + time += TimeDelta::FromMilliseconds(10); + controller->Animate(time); + controller_impl->Animate(time); + EXPECT_EQ(Animation::PAUSED, controller_impl->GetAnimationById(animation_id)->run_state()); + + // Opacity value doesn't depend on time if paused at specified time offset. + EXPECT_EQ(0.4f, dummy.opacity()); + EXPECT_EQ(0.4f, dummy_impl.opacity()); } TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) { @@ -1990,14 +2019,20 @@ TEST(LayerAnimationControllerTest, HasOnlyTranslationTransforms) { scoped_refptr<LayerAnimationController> controller_impl( LayerAnimationController::Create(0)); - EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms()); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::PENDING)); controller_impl->AddAnimation(CreateAnimation( scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), 1, Animation::OPACITY)); // Opacity animations aren't non-translation transforms. - EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms()); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::PENDING)); scoped_ptr<KeyframedTransformAnimationCurve> curve1( KeyframedTransformAnimationCurve::Create()); @@ -2014,7 +2049,10 @@ TEST(LayerAnimationControllerTest, HasOnlyTranslationTransforms) { controller_impl->AddAnimation(animation.Pass()); // The only transform animation we've added is a translation. - EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms()); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::PENDING)); scoped_ptr<KeyframedTransformAnimationCurve> curve2( KeyframedTransformAnimationCurve::Create()); @@ -2027,17 +2065,36 @@ TEST(LayerAnimationControllerTest, HasOnlyTranslationTransforms) { base::TimeDelta::FromSecondsD(1.0), operations2, nullptr)); animation = Animation::Create(curve2.Pass(), 3, 3, Animation::TRANSFORM); + animation->set_affects_active_observers(false); controller_impl->AddAnimation(animation.Pass()); // A scale animation is not a translation. - EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms()); + EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::PENDING)); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::ACTIVE)); + + controller_impl->ActivateAnimations(); + EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::ACTIVE)); + + controller_impl->GetAnimationById(3)->set_affects_pending_observers(false); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::ACTIVE)); controller_impl->GetAnimationById(3) ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0)); // Only unfinished animations should be considered by // HasOnlyTranslationTransforms. - EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms()); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::PENDING)); + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::ACTIVE)); } TEST(LayerAnimationControllerTest, AnimationStartScale) { @@ -2055,10 +2112,23 @@ TEST(LayerAnimationControllerTest, AnimationStartScale) { base::TimeDelta::FromSecondsD(1.0), operations2, nullptr)); scoped_ptr<Animation> animation( Animation::Create(curve1.Pass(), 1, 1, Animation::TRANSFORM)); + animation->set_affects_active_observers(false); controller_impl->AddAnimation(animation.Pass()); float start_scale = 0.f; - EXPECT_TRUE(controller_impl->AnimationStartScale(&start_scale)); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::PENDING, &start_scale)); + EXPECT_EQ(4.f, start_scale); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::ACTIVE, &start_scale)); + EXPECT_EQ(0.f, start_scale); + + controller_impl->ActivateAnimations(); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::PENDING, &start_scale)); + EXPECT_EQ(4.f, start_scale); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::ACTIVE, &start_scale)); EXPECT_EQ(4.f, start_scale); scoped_ptr<KeyframedTransformAnimationCurve> curve2( @@ -2076,6 +2146,7 @@ TEST(LayerAnimationControllerTest, AnimationStartScale) { // Reverse Direction animation->set_direction(Animation::DIRECTION_REVERSE); + animation->set_affects_active_observers(false); controller_impl->AddAnimation(animation.Pass()); scoped_ptr<KeyframedTransformAnimationCurve> curve3( @@ -2090,9 +2161,22 @@ TEST(LayerAnimationControllerTest, AnimationStartScale) { base::TimeDelta::FromSecondsD(1.0), operations5, nullptr)); animation = Animation::Create(curve3.Pass(), 3, 3, Animation::TRANSFORM); + animation->set_affects_active_observers(false); controller_impl->AddAnimation(animation.Pass()); - EXPECT_TRUE(controller_impl->AnimationStartScale(&start_scale)); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::PENDING, &start_scale)); + EXPECT_EQ(6.f, start_scale); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::ACTIVE, &start_scale)); + EXPECT_EQ(0.f, start_scale); + + controller_impl->ActivateAnimations(); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::PENDING, &start_scale)); + EXPECT_EQ(6.f, start_scale); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::ACTIVE, &start_scale)); EXPECT_EQ(6.f, start_scale); controller_impl->GetAnimationById(2) @@ -2100,7 +2184,11 @@ TEST(LayerAnimationControllerTest, AnimationStartScale) { // Only unfinished animations should be considered by // AnimationStartScale. - EXPECT_TRUE(controller_impl->AnimationStartScale(&start_scale)); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::PENDING, &start_scale)); + EXPECT_EQ(5.f, start_scale); + EXPECT_TRUE(controller_impl->AnimationStartScale( + LayerAnimationController::ObserverType::ACTIVE, &start_scale)); EXPECT_EQ(5.f, start_scale); } @@ -2109,7 +2197,11 @@ TEST(LayerAnimationControllerTest, MaximumTargetScale) { LayerAnimationController::Create(0)); float max_scale = 0.f; - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(0.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(0.f, max_scale); scoped_ptr<KeyframedTransformAnimationCurve> curve1( @@ -2124,9 +2216,22 @@ TEST(LayerAnimationControllerTest, MaximumTargetScale) { scoped_ptr<Animation> animation( Animation::Create(curve1.Pass(), 1, 1, Animation::TRANSFORM)); + animation->set_affects_active_observers(false); controller_impl->AddAnimation(animation.Pass()); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(4.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); + EXPECT_EQ(0.f, max_scale); + + controller_impl->ActivateAnimations(); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(4.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(4.f, max_scale); scoped_ptr<KeyframedTransformAnimationCurve> curve2( @@ -2140,9 +2245,22 @@ TEST(LayerAnimationControllerTest, MaximumTargetScale) { base::TimeDelta::FromSecondsD(1.0), operations2, nullptr)); animation = Animation::Create(curve2.Pass(), 2, 2, Animation::TRANSFORM); + animation->set_affects_active_observers(false); controller_impl->AddAnimation(animation.Pass()); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(6.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); + EXPECT_EQ(4.f, max_scale); + + controller_impl->ActivateAnimations(); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(6.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(6.f, max_scale); scoped_ptr<KeyframedTransformAnimationCurve> curve3( @@ -2156,9 +2274,20 @@ TEST(LayerAnimationControllerTest, MaximumTargetScale) { base::TimeDelta::FromSecondsD(1.0), operations3, nullptr)); animation = Animation::Create(curve3.Pass(), 3, 3, Animation::TRANSFORM); + animation->set_affects_active_observers(false); controller_impl->AddAnimation(animation.Pass()); - EXPECT_FALSE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_FALSE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); + EXPECT_EQ(6.f, max_scale); + + controller_impl->ActivateAnimations(); + EXPECT_FALSE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_FALSE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); controller_impl->GetAnimationById(3) ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0)); @@ -2167,7 +2296,11 @@ TEST(LayerAnimationControllerTest, MaximumTargetScale) { // Only unfinished animations should be considered by // MaximumTargetScale. - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(4.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(4.f, max_scale); } @@ -2197,44 +2330,76 @@ TEST(LayerAnimationControllerTest, MaximumTargetScaleWithDirection) { // NORMAL direction with positive playback rate. animation->set_direction(Animation::DIRECTION_NORMAL); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(6.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(6.f, max_scale); // ALTERNATE direction with positive playback rate. animation->set_direction(Animation::DIRECTION_ALTERNATE); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(6.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(6.f, max_scale); // REVERSE direction with positive playback rate. animation->set_direction(Animation::DIRECTION_REVERSE); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(3.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(3.f, max_scale); // ALTERNATE reverse direction. animation->set_direction(Animation::DIRECTION_REVERSE); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(3.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(3.f, max_scale); animation->set_playback_rate(-1.0); // NORMAL direction with negative playback rate. animation->set_direction(Animation::DIRECTION_NORMAL); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(3.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(3.f, max_scale); // ALTERNATE direction with negative playback rate. animation->set_direction(Animation::DIRECTION_ALTERNATE); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(3.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(3.f, max_scale); // REVERSE direction with negative playback rate. animation->set_direction(Animation::DIRECTION_REVERSE); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(6.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(6.f, max_scale); // ALTERNATE reverse direction with negative playback rate. animation->set_direction(Animation::DIRECTION_REVERSE); - EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale)); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::PENDING, &max_scale)); + EXPECT_EQ(6.f, max_scale); + EXPECT_TRUE(controller_impl->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, &max_scale)); EXPECT_EQ(6.f, max_scale); } @@ -2355,6 +2520,124 @@ TEST(LayerAnimationControllerTest, ActivationBetweenAnimateAndUpdateState) { EXPECT_EQ(0.75f, dummy_impl.opacity()); } +TEST(LayerAnimationControllerTest, + ObserverNotifiedWhenTransformIsPotentiallyAnimatingChanges) { + AnimationEventsVector events; + FakeLayerAnimationValueObserver active_dummy_impl; + FakeInactiveLayerAnimationValueObserver pending_dummy_impl; + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + controller_impl->AddValueObserver(&active_dummy_impl); + controller_impl->AddValueObserver(&pending_dummy_impl); + FakeLayerAnimationValueObserver dummy; + scoped_refptr<LayerAnimationController> controller( + LayerAnimationController::Create(0)); + controller->AddValueObserver(&dummy); + + EXPECT_FALSE(dummy.transform_is_animating()); + EXPECT_FALSE(pending_dummy_impl.transform_is_animating()); + EXPECT_FALSE(active_dummy_impl.transform_is_animating()); + + // Case 1: An animation that's allowed to run until its finish point. + AddAnimatedTransformToController(controller.get(), 1.0, 1, 1); + EXPECT_TRUE(dummy.transform_is_animating()); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_TRUE(pending_dummy_impl.transform_is_animating()); + EXPECT_FALSE(active_dummy_impl.transform_is_animating()); + + controller_impl->ActivateAnimations(); + EXPECT_TRUE(pending_dummy_impl.transform_is_animating()); + EXPECT_TRUE(active_dummy_impl.transform_is_animating()); + + controller_impl->Animate(kInitialTickTime); + controller_impl->UpdateState(true, &events); + + controller->NotifyAnimationStarted(events[0]); + events.clear(); + + // Finish the animation. + controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); + controller->UpdateState(true, nullptr); + EXPECT_FALSE(dummy.transform_is_animating()); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + + // controller_impl hasn't yet ticked at/past the end of the animation. + EXPECT_TRUE(pending_dummy_impl.transform_is_animating()); + EXPECT_TRUE(active_dummy_impl.transform_is_animating()); + + controller_impl->Animate(kInitialTickTime + + TimeDelta::FromMilliseconds(1000)); + controller_impl->UpdateState(true, &events); + EXPECT_FALSE(pending_dummy_impl.transform_is_animating()); + EXPECT_FALSE(active_dummy_impl.transform_is_animating()); + + controller->NotifyAnimationFinished(events[0]); + events.clear(); + + // Case 2: An animation that's removed before it finishes. + int animation_id = + AddAnimatedTransformToController(controller.get(), 10.0, 2, 2); + EXPECT_TRUE(dummy.transform_is_animating()); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_TRUE(pending_dummy_impl.transform_is_animating()); + EXPECT_FALSE(active_dummy_impl.transform_is_animating()); + + controller_impl->ActivateAnimations(); + EXPECT_TRUE(pending_dummy_impl.transform_is_animating()); + EXPECT_TRUE(active_dummy_impl.transform_is_animating()); + + controller_impl->Animate(kInitialTickTime + + TimeDelta::FromMilliseconds(2000)); + controller_impl->UpdateState(true, &events); + + controller->NotifyAnimationStarted(events[0]); + events.clear(); + + controller->RemoveAnimation(animation_id); + EXPECT_FALSE(dummy.transform_is_animating()); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_FALSE(pending_dummy_impl.transform_is_animating()); + EXPECT_TRUE(active_dummy_impl.transform_is_animating()); + + controller_impl->ActivateAnimations(); + EXPECT_FALSE(pending_dummy_impl.transform_is_animating()); + EXPECT_FALSE(active_dummy_impl.transform_is_animating()); + + // Case 3: An animation that's aborted before it finishes. + animation_id = AddAnimatedTransformToController(controller.get(), 10.0, 3, 3); + EXPECT_TRUE(dummy.transform_is_animating()); + + controller->PushAnimationUpdatesTo(controller_impl.get()); + EXPECT_TRUE(pending_dummy_impl.transform_is_animating()); + EXPECT_FALSE(active_dummy_impl.transform_is_animating()); + + controller_impl->ActivateAnimations(); + EXPECT_TRUE(pending_dummy_impl.transform_is_animating()); + EXPECT_TRUE(active_dummy_impl.transform_is_animating()); + + controller_impl->Animate(kInitialTickTime + + TimeDelta::FromMilliseconds(3000)); + controller_impl->UpdateState(true, &events); + + controller->NotifyAnimationStarted(events[0]); + events.clear(); + + controller_impl->AbortAnimations(Animation::TRANSFORM); + EXPECT_FALSE(pending_dummy_impl.transform_is_animating()); + EXPECT_FALSE(active_dummy_impl.transform_is_animating()); + + controller_impl->Animate(kInitialTickTime + + TimeDelta::FromMilliseconds(4000)); + controller_impl->UpdateState(true, &events); + + controller->NotifyAnimationAborted(events[0]); + EXPECT_FALSE(dummy.transform_is_animating()); +} + TEST(LayerAnimationControllerTest, ClippedOpacityValues) { FakeLayerAnimationValueObserver dummy; scoped_refptr<LayerAnimationController> controller( @@ -2524,23 +2807,75 @@ TEST(LayerAnimationControllerTest, StartAnimationsAffectingDifferentObservers) { EXPECT_EQ(1.f, dummy_impl.opacity()); } -TEST(LayerAnimationControllerTest, TestIsAnimatingProperty) { +TEST(LayerAnimationControllerTest, TestIsCurrentlyAnimatingProperty) { FakeLayerAnimationValueObserver dummy; scoped_refptr<LayerAnimationController> controller( LayerAnimationController::Create(0)); controller->AddValueObserver(&dummy); + // Create an animation that initially affects only pending observers. scoped_ptr<Animation> animation(CreateAnimation( scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), 1, Animation::OPACITY)); + animation->set_affects_active_observers(false); + controller->AddAnimation(animation.Pass()); controller->Animate(kInitialTickTime); - EXPECT_TRUE(controller->IsAnimatingProperty(Animation::OPACITY)); + EXPECT_TRUE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); controller->UpdateState(true, nullptr); EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_TRUE(controller->IsAnimatingProperty(Animation::OPACITY)); - EXPECT_FALSE(controller->IsAnimatingProperty(Animation::FILTER)); + + EXPECT_TRUE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::ACTIVE)); + + controller->ActivateAnimations(); + + EXPECT_TRUE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_TRUE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::ACTIVE)); + + controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(10)); + controller->UpdateState(true, nullptr); + + EXPECT_TRUE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_TRUE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_EQ(0.f, dummy.opacity()); + + // Tick past the end of the animation. + controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1100)); + controller->UpdateState(true, nullptr); + + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::ACTIVE)); + + EXPECT_EQ(1.f, dummy.opacity()); } TEST(LayerAnimationControllerTest, TestIsAnimatingPropertyTimeOffsetFillMode) { @@ -2549,23 +2884,79 @@ TEST(LayerAnimationControllerTest, TestIsAnimatingPropertyTimeOffsetFillMode) { LayerAnimationController::Create(0)); controller->AddValueObserver(&dummy); + // Create an animation that initially affects only pending observers, and has + // a start delay of 2 seconds. 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::FILL_MODE_NONE); animation->set_time_offset(TimeDelta::FromMilliseconds(-2000)); + animation->set_affects_active_observers(false); + controller->AddAnimation(animation.Pass()); controller->Animate(kInitialTickTime); - controller->UpdateState(true, nullptr); - EXPECT_FALSE(controller->IsAnimatingProperty(Animation::OPACITY)); + + // Since the animation has a start delay, the observers it affects have a + // potentially running transform animation but aren't currently animating + // transform. + EXPECT_TRUE(controller->IsPotentiallyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsPotentiallyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_TRUE(controller->HasActiveAnimation()); + EXPECT_FALSE(controller->IsPotentiallyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsPotentiallyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::ACTIVE)); + + controller->ActivateAnimations(); + + EXPECT_TRUE(controller->IsPotentiallyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_TRUE(controller->IsPotentiallyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); EXPECT_TRUE(controller->HasActiveAnimation()); - EXPECT_FALSE(controller->IsAnimatingProperty(Animation::OPACITY)); - EXPECT_FALSE(controller->IsAnimatingProperty(Animation::FILTER)); + EXPECT_FALSE(controller->IsPotentiallyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsPotentiallyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::ACTIVE)); + controller->UpdateState(true, nullptr); + + // Tick past the start delay. controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); controller->UpdateState(true, nullptr); - EXPECT_TRUE(controller->IsAnimatingProperty(Animation::OPACITY)); + EXPECT_TRUE(controller->IsPotentiallyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_TRUE(controller->IsPotentiallyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_TRUE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_TRUE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + + // After the animaton finishes, the observers it affects have neither a + // potentially running transform animation nor a currently running transform + // animation. + controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(4000)); + controller->UpdateState(true, nullptr); + EXPECT_FALSE(controller->IsPotentiallyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsPotentiallyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::PENDING)); + EXPECT_FALSE(controller->IsCurrentlyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE)); } } // namespace diff --git a/chromium/cc/animation/layer_animation_value_observer.h b/chromium/cc/animation/layer_animation_value_observer.h index fb9901d7514..092b53b0b9d 100644 --- a/chromium/cc/animation/layer_animation_value_observer.h +++ b/chromium/cc/animation/layer_animation_value_observer.h @@ -26,6 +26,7 @@ class CC_EXPORT LayerAnimationValueObserver { virtual void OnScrollOffsetAnimated( const gfx::ScrollOffset& scroll_offset) = 0; virtual void OnAnimationWaitingForDeletion() = 0; + virtual void OnTransformIsPotentiallyAnimatingChanged(bool is_animating) = 0; virtual bool IsActive() const = 0; }; diff --git a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc index d1049bda1cb..72fdd584960 100644 --- a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc +++ b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc @@ -62,7 +62,8 @@ void ScrollbarAnimationControllerLinearFade::ApplyOpacityToScrollbars( ScrollbarLayerImplBase* scrollbar = *it; if (scrollbar->is_overlay_scrollbar()) - scrollbar->SetOpacity(scrollbar->CanScrollOrientation() ? opacity : 0); + scrollbar->OnOpacityAnimated(scrollbar->CanScrollOrientation() ? opacity + : 0); } } diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning.cc b/chromium/cc/animation/scrollbar_animation_controller_thinning.cc index af6987e0e0b..6ced8098224 100644 --- a/chromium/cc/animation/scrollbar_animation_controller_thinning.cc +++ b/chromium/cc/animation/scrollbar_animation_controller_thinning.cc @@ -148,7 +148,7 @@ void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale( ? AdjustScale(opacity, scrollbar->opacity(), opacity_change_) : 0; - scrollbar->SetOpacity(effectiveOpacity); + scrollbar->OnOpacityAnimated(effectiveOpacity); scrollbar->SetThumbThicknessScaleFactor(AdjustScale( thumb_thickness_scale, scrollbar->thumb_thickness_scale_factor(), thickness_change_)); diff --git a/chromium/cc/animation/transform_operation.cc b/chromium/cc/animation/transform_operation.cc index e487921cdb4..465429df4b6 100644 --- a/chromium/cc/animation/transform_operation.cc +++ b/chromium/cc/animation/transform_operation.cc @@ -41,7 +41,7 @@ static bool ShareSameAxis(const TransformOperation* from, if (IsOperationIdentity(from) && IsOperationIdentity(to)) return false; - if (!from && !IsOperationIdentity(to)) { + if (IsOperationIdentity(from) && !IsOperationIdentity(to)) { *axis_x = to->rotate.axis.x; *axis_y = to->rotate.axis.y; *axis_z = to->rotate.axis.z; @@ -49,7 +49,7 @@ static bool ShareSameAxis(const TransformOperation* from, return true; } - if (!IsOperationIdentity(from) && !to) { + if (!IsOperationIdentity(from) && IsOperationIdentity(to)) { *axis_x = from->rotate.axis.x; *axis_y = from->rotate.axis.y; *axis_z = from->rotate.axis.z; @@ -157,8 +157,8 @@ bool TransformOperation::BlendTransformOperations( SkMScalar from_y = IsOperationIdentity(from) ? 0 : from->skew.y; SkMScalar to_x = IsOperationIdentity(to) ? 0 : to->skew.x; SkMScalar to_y = IsOperationIdentity(to) ? 0 : to->skew.y; - result->SkewX(BlendSkMScalars(from_x, to_x, progress)); - result->SkewY(BlendSkMScalars(from_y, to_y, progress)); + result->Skew(BlendSkMScalars(from_x, to_x, progress), + BlendSkMScalars(from_y, to_y, progress)); break; } case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: { diff --git a/chromium/cc/animation/transform_operations.cc b/chromium/cc/animation/transform_operations.cc index 6631a2a980b..29a3d90626b 100644 --- a/chromium/cc/animation/transform_operations.cc +++ b/chromium/cc/animation/transform_operations.cc @@ -224,8 +224,7 @@ void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) { void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) { TransformOperation to_add; - to_add.matrix.SkewX(x); - to_add.matrix.SkewY(y); + to_add.matrix.Skew(x, y); to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEW; to_add.skew.x = x; to_add.skew.y = y; @@ -277,9 +276,10 @@ bool TransformOperations::BlendInternal(const TransformOperations& from, for (size_t i = 0; i < num_operations; ++i) { gfx::Transform blended; if (!TransformOperation::BlendTransformOperations( - from.operations_.size() <= i ? 0 : &from.operations_[i], - operations_.size() <= i ? 0 : &operations_[i], progress, - &blended)) + from_identity ? 0 : &from.operations_[i], + to_identity ? 0 : &operations_[i], + progress, + &blended)) return false; result->PreconcatTransform(blended); } diff --git a/chromium/cc/animation/transform_operations_unittest.cc b/chromium/cc/animation/transform_operations_unittest.cc index a5cf7ec9619..572ab47ec7a 100644 --- a/chromium/cc/animation/transform_operations_unittest.cc +++ b/chromium/cc/animation/transform_operations_unittest.cc @@ -209,8 +209,7 @@ TEST(TransformOperationTest, ApplySkew) { TransformOperations operations; operations.AppendSkew(x, y); gfx::Transform expected; - expected.SkewX(x); - expected.SkewY(y); + expected.Skew(x, y); EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply()); } @@ -441,7 +440,7 @@ TEST(TransformOperationTest, LargeRotationsWithDifferentAxes) { expected, operations_to.Blend(operations_from, progress)); } -TEST(TransformOperationTest, RotationWithSlerpFromZeroDeg) { +TEST(TransformOperationTest, RotationFromZeroDegDifferentAxes) { TransformOperations operations_from; operations_from.AppendRotate(0, 0, 1, 0); @@ -449,20 +448,13 @@ TEST(TransformOperationTest, RotationWithSlerpFromZeroDeg) { operations_to.AppendRotate(0, 1, 0, 450); SkMScalar progress = 0.5f; - gfx::Transform matrix_from; - matrix_from.RotateAbout(gfx::Vector3dF(0, 0, 1), 0); - - gfx::Transform matrix_to; - matrix_to.RotateAbout(gfx::Vector3dF(0, 1, 0), 90); - - gfx::Transform expected = matrix_to; - expected.Blend(matrix_from, progress); - + gfx::Transform expected; + expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, operations_to.Blend(operations_from, progress)); } -TEST(TransformOperationTest, RotationWithoutSlerpFromZeroDeg) { +TEST(TransformOperationTest, RotationFromZeroDegSameAxes) { TransformOperations operations_from; operations_from.AppendRotate(0, 0, 1, 0); @@ -472,7 +464,34 @@ TEST(TransformOperationTest, RotationWithoutSlerpFromZeroDeg) { SkMScalar progress = 0.5f; gfx::Transform expected; expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225); + EXPECT_TRANSFORMATION_MATRIX_EQ( + expected, operations_to.Blend(operations_from, progress)); +} + +TEST(TransformOperationTest, RotationToZeroDegDifferentAxes) { + TransformOperations operations_from; + operations_from.AppendRotate(0, 1, 0, 450); + + TransformOperations operations_to; + operations_to.AppendRotate(0, 0, 1, 0); + + SkMScalar progress = 0.5f; + gfx::Transform expected; + expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225); + EXPECT_TRANSFORMATION_MATRIX_EQ( + expected, operations_to.Blend(operations_from, progress)); +} +TEST(TransformOperationTest, RotationToZeroDegSameAxes) { + TransformOperations operations_from; + operations_from.AppendRotate(0, 0, 1, 450); + + TransformOperations operations_to; + operations_to.AppendRotate(0, 0, 1, 0); + + SkMScalar progress = 0.5f; + gfx::Transform expected; + expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225); EXPECT_TRANSFORMATION_MATRIX_EQ( expected, operations_to.Blend(operations_from, progress)); } @@ -588,8 +607,7 @@ TEST(TransformOperationTest, BlendSkewFromEmpty) { SkMScalar progress = 0.5f; gfx::Transform expected; - expected.SkewX(1); - expected.SkewY(1); + expected.Skew(1, 1); EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Blend(empty_operation, progress)); @@ -597,8 +615,7 @@ TEST(TransformOperationTest, BlendSkewFromEmpty) { progress = -0.5f; expected.MakeIdentity(); - expected.SkewX(-1); - expected.SkewY(-1); + expected.Skew(-1, -1); EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Blend(empty_operation, progress)); @@ -606,8 +623,7 @@ TEST(TransformOperationTest, BlendSkewFromEmpty) { progress = 1.5f; expected.MakeIdentity(); - expected.SkewX(3); - expected.SkewY(3); + expected.Skew(3, 3); EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Blend(empty_operation, progress)); @@ -694,8 +710,7 @@ TEST(TransformOperationTest, BlendSkewToEmpty) { SkMScalar progress = 0.5f; gfx::Transform expected; - expected.SkewX(1); - expected.SkewY(1); + expected.Skew(1, 1); EXPECT_TRANSFORMATION_MATRIX_EQ(expected, empty_operation.Blend(operations, progress)); diff --git a/chromium/cc/base/BUILD.gn b/chromium/cc/base/BUILD.gn index 98a5d4ad1e6..c6dc603c836 100644 --- a/chromium/cc/base/BUILD.gn +++ b/chromium/cc/base/BUILD.gn @@ -13,19 +13,22 @@ source_set("base") { "histograms.h", "invalidation_region.cc", "invalidation_region.h", - "list_container.cc", "list_container.h", + "list_container_helper.cc", + "list_container_helper.h", "math_util.cc", "math_util.h", + "random_access_list_container.h", "region.cc", "region.h", "resource_id.h", "rolling_time_delta_history.cc", "rolling_time_delta_history.h", + "rtree.cc", + "rtree.h", "scoped_ptr_algorithm.h", "scoped_ptr_deque.h", "scoped_ptr_vector.h", - "sidecar_list_container.h", "simple_enclosed_region.cc", "simple_enclosed_region.h", "switches.cc", @@ -49,7 +52,7 @@ source_set("base") { defines = [ "CC_IMPLEMENTATION=1" ] if (!is_debug && (is_win || is_android)) { - configs -= [ "//build/config/compiler:optimize" ] + configs -= [ "//build/config/compiler:default_optimization" ] configs += [ "//build/config/compiler:optimize_max" ] } } diff --git a/chromium/cc/base/float_quad_unittest.cc b/chromium/cc/base/float_quad_unittest.cc index 6d9ce02f862..64c448c0d5a 100644 --- a/chromium/cc/base/float_quad_unittest.cc +++ b/chromium/cc/base/float_quad_unittest.cc @@ -18,8 +18,8 @@ TEST(FloatQuadTest, IsRectilinearTest) { rectilinear_trans[1].Rotate(90.f); rectilinear_trans[2].Rotate(180.f); rectilinear_trans[3].Rotate(270.f); - rectilinear_trans[4].SkewX(0.00000000001f); - rectilinear_trans[5].SkewY(0.00000000001f); + rectilinear_trans[4].Skew(0.00000000001f, 0.0f); + rectilinear_trans[5].Skew(0.0f, 0.00000000001f); rectilinear_trans[6].Scale(0.00001f, 0.00001f); rectilinear_trans[6].Rotate(180.f); rectilinear_trans[7].Scale(100000.f, 100000.f); @@ -46,8 +46,8 @@ TEST(FloatQuadTest, IsRectilinearTest) { non_rectilinear_trans[5].Rotate(180.00001f); non_rectilinear_trans[6].Rotate(269.9999f); non_rectilinear_trans[7].Rotate(270.0001f); - non_rectilinear_trans[8].SkewX(0.00001f); - non_rectilinear_trans[9].SkewY(0.00001f); + non_rectilinear_trans[8].Skew(0.00001f, 0.0f); + non_rectilinear_trans[9].Skew(0.0f, 0.00001f); for (int i = 0; i < kNumNonRectilinear; ++i) { bool clipped = false; diff --git a/chromium/cc/base/histograms.cc b/chromium/cc/base/histograms.cc index 9fe1515bc2a..ba6f4f66794 100644 --- a/chromium/cc/base/histograms.cc +++ b/chromium/cc/base/histograms.cc @@ -6,12 +6,51 @@ #include <algorithm> #include <cmath> +#include <cstring> #include <limits> +#include "base/lazy_instance.h" +#include "base/logging.h" #include "base/numerics/safe_conversions.h" +#include "base/synchronization/lock.h" namespace cc { +// Global data tracking the client name that was set. +// Both of these variables are protected by the lock. +static base::LazyInstance<base::Lock>::Leaky g_client_name_lock = + LAZY_INSTANCE_INITIALIZER; +static const char* g_client_name = nullptr; +static bool g_multiple_client_names_set = false; + +void SetClientNameForMetrics(const char* client_name) { + base::AutoLock auto_lock(g_client_name_lock.Get()); + + // Only warn once. + if (g_multiple_client_names_set) + return; + + // If a different name is set, return nullptr from now on and log a warning. + const char* old_client_name = g_client_name; + if (old_client_name && strcmp(old_client_name, client_name)) { + g_client_name = nullptr; + g_multiple_client_names_set = true; + LOG(WARNING) << "Started multiple compositor clients (" << old_client_name + << ", " << client_name + << ") in one process. Some metrics will be disabled."; + return; + } + + // If the client name is being set for the first time, store it. + if (!old_client_name) + g_client_name = client_name; +} + +const char* GetClientNameForMetrics() { + base::AutoLock auto_lock(g_client_name_lock.Get()); + return g_client_name; +} + // Minimum elapsed time of 1us to limit weighting of fast calls. static const int64 kMinimumTimeMicroseconds = 1; diff --git a/chromium/cc/base/histograms.h b/chromium/cc/base/histograms.h index 0c8a2bc8532..8c8b4672a09 100644 --- a/chromium/cc/base/histograms.h +++ b/chromium/cc/base/histograms.h @@ -9,44 +9,69 @@ #include "base/metrics/histogram_base.h" #include "base/metrics/histogram_macros.h" #include "base/numerics/safe_math.h" +#include "base/strings/stringprintf.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" #include "cc/base/cc_export.h" namespace cc { +// Supplies a client name to be inserted into histogram names. +// These are known so far: Renderer, Browser +// +// We currently assume that there is only one distinct client per process. +// Not thread-safe. If called multiple times, warns and skips metrics. +CC_EXPORT void SetClientNameForMetrics(const char* client_name); + +// Returns the client name, for use by applicable cc metrics code. +// May return null, in which case no clients, or at least two clients, set the +// client name, and these metrics should be omitted. +// +// This method guarantees that it will never return two distinct non-null +// values over the lifetime of the process. +const char* GetClientNameForMetrics(); + // Emits UMA histogram trackers for time spent as well as area (in pixels) // processed per unit time. Time is measured in microseconds, and work in -// pixels per millisecond. +// pixels per millisecond. Histogram name should include a %s to grab the client +// name. // // Usage: // // Outside of a method, perhaps in a namespace. -// DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER(ScopedReticulateSplinesTimer, -// "ReticulateSplinesUs", -// "ReticulateSplinesPixelsPerMs"); +// DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER( +// ScopedReticulateSplinesTimer, +// "Compositing.%s.ReticulateSplinesUs", +// "Compositing.%s.ReticulateSplinesPixelsPerMs"); // // // Inside a method. // ScopedReticulateSplinesTimer timer; // timer.AddArea(some_rect.size().GetArea()); -#define DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER(class_name, time_histogram, \ - area_histogram) \ - class class_name : public ::cc::ScopedUMAHistogramAreaTimerBase { \ - public: \ - ~class_name(); \ - }; \ - class_name::~class_name() { \ - Sample time_sample; \ - Sample area_sample; \ - if (GetHistogramValues(&time_sample, &area_sample)) { \ - UMA_HISTOGRAM_COUNTS(time_histogram, time_sample); \ - UMA_HISTOGRAM_COUNTS(area_histogram, area_sample); \ - } \ +// +#define DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER(class_name, time_histogram, \ + area_histogram) \ + class class_name : public ::cc::ScopedUMAHistogramAreaTimerBase { \ + public: \ + ~class_name(); \ + }; \ + class_name::~class_name() { \ + Sample time_sample; \ + Sample area_sample; \ + const char* client_name = ::cc::GetClientNameForMetrics(); \ + if (client_name && GetHistogramValues(&time_sample, &area_sample)) { \ + /* GetClientNameForMetrics only returns one non-null value over */ \ + /* the lifetime of the process, so these histogram names are */ \ + /* runtime constant. */ \ + UMA_HISTOGRAM_COUNTS(base::StringPrintf(time_histogram, client_name), \ + time_sample); \ + UMA_HISTOGRAM_COUNTS(base::StringPrintf(area_histogram, client_name), \ + area_sample); \ + } \ } class CC_EXPORT ScopedUMAHistogramAreaTimerBase { public: - void AddArea(int area) { area_ += area; } - void SetArea(int area) { area_ = area; } + void AddArea(const base::CheckedNumeric<int>& area) { area_ += area; } + void SetArea(const base::CheckedNumeric<int>& area) { area_ = area; } protected: using Sample = base::HistogramBase::Sample; diff --git a/chromium/cc/base/list_container.h b/chromium/cc/base/list_container.h index ae7afa92e5b..d5907407c0a 100644 --- a/chromium/cc/base/list_container.h +++ b/chromium/cc/base/list_container.h @@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" +#include "cc/base/list_container_helper.h" namespace cc { @@ -20,188 +21,27 @@ namespace cc { // contain SharedQuadState or DrawQuad. Since the size of each DrawQuad varies, // to hold DrawQuads, the allocations size of each element in this class is // LargestDrawQuadSize while BaseElementType is DrawQuad. - -// Base class for non-templated logic. All methods are protected, and only -// exposed by ListContainer<BaseElementType>. -// For usage, see comments in ListContainer. -class CC_EXPORT ListContainerBase { - protected: - explicit ListContainerBase(size_t max_size_for_derived_class); - ListContainerBase(size_t max_size_for_derived_class, - size_t num_of_elements_to_reserve_for); - ~ListContainerBase(); - - // This class deals only with char* and void*. It does allocation and passing - // out raw pointers, as well as memory deallocation when being destroyed. - class ListContainerCharAllocator; - - // This class points to a certain position inside memory of - // ListContainerCharAllocator. It is a base class for ListContainer iterators. - struct CC_EXPORT PositionInListContainerCharAllocator { - ListContainerCharAllocator* ptr_to_container; - size_t vector_index; - char* item_iterator; - - PositionInListContainerCharAllocator( - const PositionInListContainerCharAllocator& other); - - PositionInListContainerCharAllocator(ListContainerCharAllocator* container, - size_t vector_ind, - char* item_iter); - - bool operator==(const PositionInListContainerCharAllocator& other) const; - bool operator!=(const PositionInListContainerCharAllocator& other) const; - - PositionInListContainerCharAllocator Increment(); - PositionInListContainerCharAllocator ReverseIncrement(); - }; - - // Iterator classes that can be used to access data. - ///////////////////////////////////////////////////////////////// - class CC_EXPORT Iterator : public PositionInListContainerCharAllocator { - // This class is only defined to forward iterate through - // ListContainerCharAllocator. - public: - Iterator(ListContainerCharAllocator* container, - size_t vector_ind, - char* item_iter, - size_t index); - ~Iterator(); - - size_t index() const; - - protected: - // This is used to track how many increment has happened since begin(). It - // is used to avoid double increment at places an index reference is - // needed. For iterator this means begin() corresponds to index 0 and end() - // corresponds to index |size|. - size_t index_; - }; - - class CC_EXPORT ConstIterator : public PositionInListContainerCharAllocator { - // This class is only defined to forward iterate through - // ListContainerCharAllocator. - public: - ConstIterator(ListContainerCharAllocator* container, - size_t vector_ind, - char* item_iter, - size_t index); - ConstIterator(const Iterator& other); // NOLINT - ~ConstIterator(); - - size_t index() const; - - protected: - // This is used to track how many increment has happened since begin(). It - // is used to avoid double increment at places an index reference is - // needed. For iterator this means begin() corresponds to index 0 and end() - // corresponds to index |size|. - size_t index_; - }; - - class CC_EXPORT ReverseIterator - : public PositionInListContainerCharAllocator { - // This class is only defined to reverse iterate through - // ListContainerCharAllocator. - public: - ReverseIterator(ListContainerCharAllocator* container, - size_t vector_ind, - char* item_iter, - size_t index); - ~ReverseIterator(); - - size_t index() const; - - protected: - // This is used to track how many increment has happened since rbegin(). It - // is used to avoid double increment at places an index reference is - // needed. For reverse iterator this means rbegin() corresponds to index 0 - // and rend() corresponds to index |size|. - size_t index_; - }; - - class CC_EXPORT ConstReverseIterator - : public PositionInListContainerCharAllocator { - // This class is only defined to reverse iterate through - // ListContainerCharAllocator. - public: - ConstReverseIterator(ListContainerCharAllocator* container, - size_t vector_ind, - char* item_iter, - size_t index); - ConstReverseIterator(const ReverseIterator& other); // NOLINT - ~ConstReverseIterator(); - - size_t index() const; - - protected: - // This is used to track how many increment has happened since rbegin(). It - // is used to avoid double increment at places an index reference is - // needed. For reverse iterator this means rbegin() corresponds to index 0 - // and rend() corresponds to index |size|. - size_t index_; - }; - - // Unlike the ListContainer methods, these do not invoke element destructors. - void RemoveLast(); - void EraseAndInvalidateAllPointers(Iterator position); - - ConstReverseIterator crbegin() const; - ConstReverseIterator crend() const; - ReverseIterator rbegin(); - ReverseIterator rend(); - ConstIterator cbegin() const; - ConstIterator cend() const; - Iterator begin(); - Iterator end(); - - Iterator IteratorAt(size_t index); - ConstIterator IteratorAt(size_t index) const; - - size_t size() const; - bool empty() const; - - size_t MaxSizeForDerivedClass() const; - - size_t GetCapacityInBytes() const; - - // Unlike the ListContainer method, this one does not invoke element - // destructors. - void clear(); - - size_t AvailableSizeWithoutAnotherAllocationForTesting() const; - - // Hands out memory location for an element at the end of data structure. - void* Allocate(size_t size_of_actual_element_in_bytes); - - scoped_ptr<ListContainerCharAllocator> data_; - - private: - DISALLOW_COPY_AND_ASSIGN(ListContainerBase); -}; - template <class BaseElementType> -class ListContainer : public ListContainerBase { +class ListContainer { public: // BaseElementType is the type of raw pointers this class hands out; however, // its derived classes might require different memory sizes. // max_size_for_derived_class the largest memory size required for all the // derived classes to use for allocation. explicit ListContainer(size_t max_size_for_derived_class) - : ListContainerBase(max_size_for_derived_class) {} + : helper_(max_size_for_derived_class) {} // This constructor omits input variable for max_size_for_derived_class. This // is used when there is no derived classes from BaseElementType we need to // worry about, and allocation size is just sizeof(BaseElementType). - ListContainer() : ListContainerBase(sizeof(BaseElementType)) {} + ListContainer() : helper_(sizeof(BaseElementType)) {} // This constructor reserves the requested memory up front so only single // allocation is needed. When num_of_elements_to_reserve_for is zero, use the // default size. ListContainer(size_t max_size_for_derived_class, size_t num_of_elements_to_reserve_for) - : ListContainerBase(max_size_for_derived_class, - num_of_elements_to_reserve_for) {} + : helper_(max_size_for_derived_class, num_of_elements_to_reserve_for) {} ~ListContainer() { for (Iterator i = begin(); i != end(); ++i) { @@ -219,40 +59,36 @@ class ListContainer : public ListContainerBase { void RemoveLast() { DCHECK(!empty()); back()->~BaseElementType(); - ListContainerBase::RemoveLast(); + helper_.RemoveLast(); } // When called, all raw pointers that have been handed out are no longer // valid. Use with caution. + // Returns a valid Iterator pointing to the element after the erased element. // This function does not deallocate memory. - void EraseAndInvalidateAllPointers(Iterator position) { + Iterator EraseAndInvalidateAllPointers(Iterator position) { BaseElementType* item = *position; item->~BaseElementType(); - ListContainerBase::EraseAndInvalidateAllPointers(position); + helper_.EraseAndInvalidateAllPointers(&position); + return empty() ? end() : position; } ConstReverseIterator crbegin() const { - return ConstReverseIterator(ListContainerBase::crbegin()); + return ConstReverseIterator(helper_.crbegin()); } ConstReverseIterator crend() const { - return ConstReverseIterator(ListContainerBase::crend()); + return ConstReverseIterator(helper_.crend()); } ConstReverseIterator rbegin() const { return crbegin(); } ConstReverseIterator rend() const { return crend(); } - ReverseIterator rbegin() { - return ReverseIterator(ListContainerBase::rbegin()); - } - ReverseIterator rend() { return ReverseIterator(ListContainerBase::rend()); } - ConstIterator cbegin() const { - return ConstIterator(ListContainerBase::cbegin()); - } - ConstIterator cend() const { - return ConstIterator(ListContainerBase::cend()); - } + ReverseIterator rbegin() { return ReverseIterator(helper_.rbegin()); } + ReverseIterator rend() { return ReverseIterator(helper_.rend()); } + ConstIterator cbegin() const { return ConstIterator(helper_.cbegin()); } + ConstIterator cend() const { return ConstIterator(helper_.cend()); } ConstIterator begin() const { return cbegin(); } ConstIterator end() const { return cend(); } - Iterator begin() { return Iterator(ListContainerBase::begin()); } - Iterator end() { return Iterator(ListContainerBase::end()); } + Iterator begin() { return Iterator(helper_.begin()); } + Iterator end() { return Iterator(helper_.end()); } // TODO(weiliangc): front(), back() and ElementAt() function should return // reference, consistent with container-of-object. @@ -262,24 +98,25 @@ class ListContainer : public ListContainerBase { const BaseElementType* back() const { return *rbegin(); } BaseElementType* ElementAt(size_t index) { - return *Iterator(IteratorAt(index)); + return *Iterator(helper_.IteratorAt(index)); } const BaseElementType* ElementAt(size_t index) const { - return *ConstIterator(IteratorAt(index)); + return *ConstIterator(helper_.IteratorAt(index)); } // Take in derived element type and construct it at location generated by // Allocate(). template <typename DerivedElementType> DerivedElementType* AllocateAndConstruct() { - return new (Allocate(sizeof(DerivedElementType))) DerivedElementType; + return new (helper_.Allocate(sizeof(DerivedElementType))) + DerivedElementType; } // Take in derived element type and copy construct it at location generated by // Allocate(). template <typename DerivedElementType> DerivedElementType* AllocateAndCopyFrom(const DerivedElementType* source) { - return new (Allocate(sizeof(DerivedElementType))) + return new (helper_.Allocate(sizeof(DerivedElementType))) DerivedElementType(*source); } @@ -287,12 +124,26 @@ class ListContainer : public ListContainerBase { template <typename DerivedElementType> DerivedElementType* ReplaceExistingElement(Iterator at) { at->~BaseElementType(); - return new (*at) DerivedElementType(); + return new (at.item_iterator) DerivedElementType(); + } + + // Insert |count| new elements of |DerivedElementType| before |at|. This will + // invalidate all outstanding pointers and iterators. Return a valid iterator + // for the beginning of the newly inserted segment. + template <typename DerivedElementType> + Iterator InsertBeforeAndInvalidateAllPointers(Iterator at, size_t count) { + helper_.InsertBeforeAndInvalidateAllPointers(&at, count); + Iterator result = at; + for (size_t i = 0; i < count; ++i) { + new (at.item_iterator) DerivedElementType(); + ++at; + } + return result; } template <typename DerivedElementType> void swap(ListContainer<DerivedElementType>& other) { - data_.swap(other.data_); + helper_.data_.swap(other.helper_.data_); } // Appends a new item without copying. The original item will not be @@ -302,39 +153,43 @@ class ListContainer : public ListContainerBase { // the moved element is returned. template <typename DerivedElementType> DerivedElementType* AppendByMoving(DerivedElementType* item) { - size_t max_size_for_derived_class = MaxSizeForDerivedClass(); - void* new_item = Allocate(max_size_for_derived_class); + size_t max_size_for_derived_class = helper_.MaxSizeForDerivedClass(); + void* new_item = helper_.Allocate(max_size_for_derived_class); memcpy(new_item, static_cast<void*>(item), max_size_for_derived_class); // Construct a new element in-place so it can be destructed safely. new (item) DerivedElementType; return static_cast<DerivedElementType*>(new_item); } - using ListContainerBase::size; - using ListContainerBase::empty; - using ListContainerBase::GetCapacityInBytes; + size_t size() const { return helper_.size(); } + bool empty() const { return helper_.empty(); } + size_t GetCapacityInBytes() const { return helper_.GetCapacityInBytes(); } void clear() { for (Iterator i = begin(); i != end(); ++i) { i->~BaseElementType(); } - ListContainerBase::clear(); + helper_.clear(); } - using ListContainerBase::AvailableSizeWithoutAnotherAllocationForTesting; + size_t AvailableSizeWithoutAnotherAllocationForTesting() const { + return helper_.AvailableSizeWithoutAnotherAllocationForTesting(); + } // Iterator classes that can be used to access data. ///////////////////////////////////////////////////////////////// - class Iterator : public ListContainerBase::Iterator { + class Iterator : public ListContainerHelper::Iterator { // This class is only defined to forward iterate through - // ListContainerCharAllocator. + // CharAllocator. public: - Iterator(ListContainerCharAllocator* container, + Iterator(ListContainerHelper::CharAllocator* container, size_t vector_ind, char* item_iter, size_t index) - : ListContainerBase::Iterator(container, vector_ind, item_iter, index) { - } + : ListContainerHelper::Iterator(container, + vector_ind, + item_iter, + index) {} BaseElementType* operator->() const { return reinterpret_cast<BaseElementType*>(item_iterator); } @@ -353,28 +208,28 @@ class ListContainer : public ListContainerBase { } private: - explicit Iterator(const ListContainerBase::Iterator& base_iterator) - : ListContainerBase::Iterator(base_iterator) {} + explicit Iterator(const ListContainerHelper::Iterator& base_iterator) + : ListContainerHelper::Iterator(base_iterator) {} friend Iterator ListContainer<BaseElementType>::begin(); friend Iterator ListContainer<BaseElementType>::end(); friend BaseElementType* ListContainer<BaseElementType>::ElementAt( size_t index); }; - class ConstIterator : public ListContainerBase::ConstIterator { + class ConstIterator : public ListContainerHelper::ConstIterator { // This class is only defined to forward iterate through - // ListContainerCharAllocator. + // CharAllocator. public: - ConstIterator(ListContainerCharAllocator* container, + ConstIterator(ListContainerHelper::CharAllocator* container, size_t vector_ind, char* item_iter, size_t index) - : ListContainerBase::ConstIterator(container, - vector_ind, - item_iter, - index) {} + : ListContainerHelper::ConstIterator(container, + vector_ind, + item_iter, + index) {} ConstIterator(const Iterator& other) // NOLINT - : ListContainerBase::ConstIterator(other) {} + : ListContainerHelper::ConstIterator(other) {} const BaseElementType* operator->() const { return reinterpret_cast<const BaseElementType*>(item_iterator); } @@ -394,26 +249,26 @@ class ListContainer : public ListContainerBase { private: explicit ConstIterator( - const ListContainerBase::ConstIterator& base_iterator) - : ListContainerBase::ConstIterator(base_iterator) {} + const ListContainerHelper::ConstIterator& base_iterator) + : ListContainerHelper::ConstIterator(base_iterator) {} friend ConstIterator ListContainer<BaseElementType>::cbegin() const; friend ConstIterator ListContainer<BaseElementType>::cend() const; friend const BaseElementType* ListContainer<BaseElementType>::ElementAt( size_t index) const; }; - class ReverseIterator : public ListContainerBase::ReverseIterator { + class ReverseIterator : public ListContainerHelper::ReverseIterator { // This class is only defined to reverse iterate through - // ListContainerCharAllocator. + // CharAllocator. public: - ReverseIterator(ListContainerCharAllocator* container, + ReverseIterator(ListContainerHelper::CharAllocator* container, size_t vector_ind, char* item_iter, size_t index) - : ListContainerBase::ReverseIterator(container, - vector_ind, - item_iter, - index) {} + : ListContainerHelper::ReverseIterator(container, + vector_ind, + item_iter, + index) {} BaseElementType* operator->() const { return reinterpret_cast<BaseElementType*>(item_iterator); } @@ -432,26 +287,27 @@ class ListContainer : public ListContainerBase { } private: - explicit ReverseIterator(ListContainerBase::ReverseIterator base_iterator) - : ListContainerBase::ReverseIterator(base_iterator) {} + explicit ReverseIterator(ListContainerHelper::ReverseIterator base_iterator) + : ListContainerHelper::ReverseIterator(base_iterator) {} friend ReverseIterator ListContainer<BaseElementType>::rbegin(); friend ReverseIterator ListContainer<BaseElementType>::rend(); }; - class ConstReverseIterator : public ListContainerBase::ConstReverseIterator { + class ConstReverseIterator + : public ListContainerHelper::ConstReverseIterator { // This class is only defined to reverse iterate through - // ListContainerCharAllocator. + // CharAllocator. public: - ConstReverseIterator(ListContainerCharAllocator* container, + ConstReverseIterator(ListContainerHelper::CharAllocator* container, size_t vector_ind, char* item_iter, size_t index) - : ListContainerBase::ConstReverseIterator(container, - vector_ind, - item_iter, - index) {} + : ListContainerHelper::ConstReverseIterator(container, + vector_ind, + item_iter, + index) {} ConstReverseIterator(const ReverseIterator& other) // NOLINT - : ListContainerBase::ConstReverseIterator(other) {} + : ListContainerHelper::ConstReverseIterator(other) {} const BaseElementType* operator->() const { return reinterpret_cast<const BaseElementType*>(item_iterator); } @@ -471,11 +327,16 @@ class ListContainer : public ListContainerBase { private: explicit ConstReverseIterator( - ListContainerBase::ConstReverseIterator base_iterator) - : ListContainerBase::ConstReverseIterator(base_iterator) {} + ListContainerHelper::ConstReverseIterator base_iterator) + : ListContainerHelper::ConstReverseIterator(base_iterator) {} friend ConstReverseIterator ListContainer<BaseElementType>::crbegin() const; friend ConstReverseIterator ListContainer<BaseElementType>::crend() const; }; + + private: + ListContainerHelper helper_; + + DISALLOW_COPY_AND_ASSIGN(ListContainer); }; } // namespace cc diff --git a/chromium/cc/base/list_container.cc b/chromium/cc/base/list_container_helper.cc index d5cb4f03260..65be43adb38 100644 --- a/chromium/cc/base/list_container.cc +++ b/chromium/cc/base/list_container_helper.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/base/list_container.h" +#include "cc/base/list_container_helper.h" #include <algorithm> #include <vector> @@ -15,13 +15,13 @@ const size_t kDefaultNumElementTypesToReserve = 32; namespace cc { -// ListContainerCharAllocator +// CharAllocator //////////////////////////////////////////////////// // This class deals only with char* and void*. It does allocation and passing // out raw pointers, as well as memory deallocation when being destroyed. -class ListContainerBase::ListContainerCharAllocator { +class ListContainerHelper::CharAllocator { public: - // ListContainerCharAllocator::InnerList + // CharAllocator::InnerList ///////////////////////////////////////////// // This class holds the raw memory chunk, as well as information about its // size and availability. @@ -41,7 +41,7 @@ class ListContainerBase::ListContainerCharAllocator { void Erase(char* position) { // Confident that destructor is called by caller of this function. Since - // ListContainerCharAllocator does not handle construction after + // CharAllocator does not handle construction after // allocation, it doesn't handle desctrution before deallocation. DCHECK_LE(position, LastElement()); DCHECK_GE(position, Begin()); @@ -53,6 +53,28 @@ class ListContainerBase::ListContainerCharAllocator { --capacity; } + void InsertBefore(char** position, size_t count) { + DCHECK_LE(*position, LastElement() + step); + DCHECK_GE(*position, Begin()); + + // Adjust the size and capacity + size_t old_size = size; + size += count; + capacity = size; + + // Allocate the new data and update the iterator's pointer. + scoped_ptr<char[]> new_data(new char[size * step]); + size_t position_offset = *position - Begin(); + *position = new_data.get() + position_offset; + + // Copy the data before the inserted segment + memcpy(new_data.get(), data.get(), position_offset); + // Copy the data after the inserted segment. + memcpy(new_data.get() + position_offset + count * step, + data.get() + position_offset, old_size * step - position_offset); + new_data.swap(data); + } + bool IsEmpty() const { return !size; } bool IsFull() { return capacity == size; } size_t NumElementsAvailable() const { return capacity - size; } @@ -77,7 +99,7 @@ class ListContainerBase::ListContainerCharAllocator { DISALLOW_COPY_AND_ASSIGN(InnerList); }; - explicit ListContainerCharAllocator(size_t element_size) + explicit CharAllocator(size_t element_size) : element_size_(element_size), size_(0), last_list_index_(0), @@ -86,7 +108,7 @@ class ListContainerBase::ListContainerCharAllocator { last_list_ = storage_[last_list_index_]; } - ListContainerCharAllocator(size_t element_size, size_t element_count) + CharAllocator(size_t element_size, size_t element_count) : element_size_(element_size), size_(0), last_list_index_(0), @@ -96,7 +118,7 @@ class ListContainerBase::ListContainerCharAllocator { last_list_ = storage_[last_list_index_]; } - ~ListContainerCharAllocator() {} + ~CharAllocator() {} void* Allocate() { if (last_list_->IsFull()) { @@ -149,13 +171,41 @@ class ListContainerBase::ListContainerCharAllocator { --size_; } - void Erase(PositionInListContainerCharAllocator position) { - DCHECK_EQ(this, position.ptr_to_container); - storage_[position.vector_index]->Erase(position.item_iterator); + void Erase(PositionInCharAllocator* position) { + DCHECK_EQ(this, position->ptr_to_container); + + // Update |position| to point to the element after the erased element. + InnerList* list = storage_[position->vector_index]; + char* item_iterator = position->item_iterator; + if (item_iterator == list->LastElement()) + position->Increment(); + + list->Erase(item_iterator); // TODO(weiliangc): Free the InnerList if it is empty. --size_; } + void InsertBefore(ListContainerHelper::Iterator* position, size_t count) { + if (!count) + return; + + // If |position| is End(), then append |count| elements at the end. This + // will happen to not invalidate any iterators or memory. + if (!position->item_iterator) { + // Set |position| to be the first inserted element. + Allocate(); + position->vector_index = storage_.size() - 1; + position->item_iterator = storage_[position->vector_index]->LastElement(); + // Allocate the rest. + for (size_t i = 1; i < count; ++i) + Allocate(); + } else { + storage_[position->vector_index]->InsertBefore(&position->item_iterator, + count); + size_ += count; + } + } + InnerList* InnerListById(size_t id) const { DCHECK_LT(id, storage_.size()); return storage_[id]; @@ -208,46 +258,40 @@ class ListContainerBase::ListContainerCharAllocator { // This is equivalent to |storage_[last_list_index_]|. InnerList* last_list_; - DISALLOW_COPY_AND_ASSIGN(ListContainerCharAllocator); + DISALLOW_COPY_AND_ASSIGN(CharAllocator); }; -// PositionInListContainerCharAllocator +// PositionInCharAllocator ////////////////////////////////////////////////////// -ListContainerBase::PositionInListContainerCharAllocator:: - PositionInListContainerCharAllocator( - const ListContainerBase::PositionInListContainerCharAllocator& other) +ListContainerHelper::PositionInCharAllocator::PositionInCharAllocator( + const ListContainerHelper::PositionInCharAllocator& other) : ptr_to_container(other.ptr_to_container), vector_index(other.vector_index), - item_iterator(other.item_iterator) { -} + item_iterator(other.item_iterator) {} -ListContainerBase::PositionInListContainerCharAllocator:: - PositionInListContainerCharAllocator( - ListContainerBase::ListContainerCharAllocator* container, - size_t vector_ind, - char* item_iter) +ListContainerHelper::PositionInCharAllocator::PositionInCharAllocator( + ListContainerHelper::CharAllocator* container, + size_t vector_ind, + char* item_iter) : ptr_to_container(container), vector_index(vector_ind), - item_iterator(item_iter) { -} + item_iterator(item_iter) {} -bool ListContainerBase::PositionInListContainerCharAllocator::operator==( - const ListContainerBase::PositionInListContainerCharAllocator& other) - const { +bool ListContainerHelper::PositionInCharAllocator::operator==( + const ListContainerHelper::PositionInCharAllocator& other) const { DCHECK_EQ(ptr_to_container, other.ptr_to_container); return vector_index == other.vector_index && item_iterator == other.item_iterator; } -bool ListContainerBase::PositionInListContainerCharAllocator::operator!=( - const ListContainerBase::PositionInListContainerCharAllocator& other) - const { +bool ListContainerHelper::PositionInCharAllocator::operator!=( + const ListContainerHelper::PositionInCharAllocator& other) const { return !(*this == other); } -ListContainerBase::PositionInListContainerCharAllocator -ListContainerBase::PositionInListContainerCharAllocator::Increment() { - ListContainerCharAllocator::InnerList* list = +ListContainerHelper::PositionInCharAllocator +ListContainerHelper::PositionInCharAllocator::Increment() { + CharAllocator::InnerList* list = ptr_to_container->InnerListById(vector_index); if (item_iterator == list->LastElement()) { ++vector_index; @@ -266,9 +310,9 @@ ListContainerBase::PositionInListContainerCharAllocator::Increment() { return *this; } -ListContainerBase::PositionInListContainerCharAllocator -ListContainerBase::PositionInListContainerCharAllocator::ReverseIncrement() { - ListContainerCharAllocator::InnerList* list = +ListContainerHelper::PositionInCharAllocator +ListContainerHelper::PositionInCharAllocator::ReverseIncrement() { + CharAllocator::InnerList* list = ptr_to_container->InnerListById(vector_index); if (item_iterator == list->Begin()) { --vector_index; @@ -292,31 +336,34 @@ ListContainerBase::PositionInListContainerCharAllocator::ReverseIncrement() { return *this; } -// ListContainerBase +// ListContainerHelper //////////////////////////////////////////// -ListContainerBase::ListContainerBase(size_t max_size_for_derived_class) - : data_(new ListContainerCharAllocator(max_size_for_derived_class)) { -} +ListContainerHelper::ListContainerHelper(size_t max_size_for_derived_class) + : data_(new CharAllocator(max_size_for_derived_class)) {} -ListContainerBase::ListContainerBase(size_t max_size_for_derived_class, - size_t num_of_elements_to_reserve_for) - : data_(new ListContainerCharAllocator(max_size_for_derived_class, - num_of_elements_to_reserve_for)) { -} +ListContainerHelper::ListContainerHelper(size_t max_size_for_derived_class, + size_t num_of_elements_to_reserve_for) + : data_(new CharAllocator(max_size_for_derived_class, + num_of_elements_to_reserve_for)) {} -ListContainerBase::~ListContainerBase() { -} +ListContainerHelper::~ListContainerHelper() {} -void ListContainerBase::RemoveLast() { +void ListContainerHelper::RemoveLast() { data_->RemoveLast(); } -void ListContainerBase::EraseAndInvalidateAllPointers( - ListContainerBase::Iterator position) { +void ListContainerHelper::EraseAndInvalidateAllPointers( + ListContainerHelper::Iterator* position) { data_->Erase(position); } -ListContainerBase::ConstReverseIterator ListContainerBase::crbegin() const { +void ListContainerHelper::InsertBeforeAndInvalidateAllPointers( + ListContainerHelper::Iterator* position, + size_t count) { + data_->InsertBefore(position, count); +} + +ListContainerHelper::ConstReverseIterator ListContainerHelper::crbegin() const { if (data_->IsEmpty()) return crend(); @@ -325,12 +372,12 @@ ListContainerBase::ConstReverseIterator ListContainerBase::crbegin() const { data_->InnerListById(id)->LastElement(), 0); } -ListContainerBase::ConstReverseIterator ListContainerBase::crend() const { +ListContainerHelper::ConstReverseIterator ListContainerHelper::crend() const { return ConstReverseIterator(data_.get(), static_cast<size_t>(-1), NULL, size()); } -ListContainerBase::ReverseIterator ListContainerBase::rbegin() { +ListContainerHelper::ReverseIterator ListContainerHelper::rbegin() { if (data_->IsEmpty()) return rend(); @@ -339,11 +386,11 @@ ListContainerBase::ReverseIterator ListContainerBase::rbegin() { data_->InnerListById(id)->LastElement(), 0); } -ListContainerBase::ReverseIterator ListContainerBase::rend() { +ListContainerHelper::ReverseIterator ListContainerHelper::rend() { return ReverseIterator(data_.get(), static_cast<size_t>(-1), NULL, size()); } -ListContainerBase::ConstIterator ListContainerBase::cbegin() const { +ListContainerHelper::ConstIterator ListContainerHelper::cbegin() const { if (data_->IsEmpty()) return cend(); @@ -351,7 +398,7 @@ ListContainerBase::ConstIterator ListContainerBase::cbegin() const { return ConstIterator(data_.get(), id, data_->InnerListById(id)->Begin(), 0); } -ListContainerBase::ConstIterator ListContainerBase::cend() const { +ListContainerHelper::ConstIterator ListContainerHelper::cend() const { if (data_->IsEmpty()) return ConstIterator(data_.get(), 0, NULL, size()); @@ -359,7 +406,7 @@ ListContainerBase::ConstIterator ListContainerBase::cend() const { return ConstIterator(data_.get(), id, NULL, size()); } -ListContainerBase::Iterator ListContainerBase::begin() { +ListContainerHelper::Iterator ListContainerHelper::begin() { if (data_->IsEmpty()) return end(); @@ -367,7 +414,7 @@ ListContainerBase::Iterator ListContainerBase::begin() { return Iterator(data_.get(), id, data_->InnerListById(id)->Begin(), 0); } -ListContainerBase::Iterator ListContainerBase::end() { +ListContainerHelper::Iterator ListContainerHelper::end() { if (data_->IsEmpty()) return Iterator(data_.get(), 0, NULL, size()); @@ -375,7 +422,7 @@ ListContainerBase::Iterator ListContainerBase::end() { return Iterator(data_.get(), id, NULL, size()); } -ListContainerBase::ConstIterator ListContainerBase::IteratorAt( +ListContainerHelper::ConstIterator ListContainerHelper::IteratorAt( size_t index) const { DCHECK_LT(index, size()); size_t original_index = index; @@ -391,7 +438,7 @@ ListContainerBase::ConstIterator ListContainerBase::IteratorAt( original_index); } -ListContainerBase::Iterator ListContainerBase::IteratorAt(size_t index) { +ListContainerHelper::Iterator ListContainerHelper::IteratorAt(size_t index) { DCHECK_LT(index, size()); size_t original_index = index; size_t list_index; @@ -406,114 +453,102 @@ ListContainerBase::Iterator ListContainerBase::IteratorAt(size_t index) { original_index); } -void* ListContainerBase::Allocate(size_t size_of_actual_element_in_bytes) { +void* ListContainerHelper::Allocate(size_t size_of_actual_element_in_bytes) { DCHECK_LE(size_of_actual_element_in_bytes, data_->element_size()); return data_->Allocate(); } -size_t ListContainerBase::size() const { +size_t ListContainerHelper::size() const { return data_->size(); } -bool ListContainerBase::empty() const { +bool ListContainerHelper::empty() const { return data_->IsEmpty(); } -size_t ListContainerBase::MaxSizeForDerivedClass() const { +size_t ListContainerHelper::MaxSizeForDerivedClass() const { return data_->element_size(); } -size_t ListContainerBase::GetCapacityInBytes() const { +size_t ListContainerHelper::GetCapacityInBytes() const { return data_->Capacity() * data_->element_size(); } -void ListContainerBase::clear() { +void ListContainerHelper::clear() { data_->Clear(); } -size_t ListContainerBase::AvailableSizeWithoutAnotherAllocationForTesting() +size_t ListContainerHelper::AvailableSizeWithoutAnotherAllocationForTesting() const { return data_->NumAvailableElementsInLastList(); } -// ListContainerBase::Iterator +// ListContainerHelper::Iterator ///////////////////////////////////////////////// -ListContainerBase::Iterator::Iterator(ListContainerCharAllocator* container, - size_t vector_ind, - char* item_iter, - size_t index) - : PositionInListContainerCharAllocator(container, vector_ind, item_iter), - index_(index) { -} +ListContainerHelper::Iterator::Iterator(CharAllocator* container, + size_t vector_ind, + char* item_iter, + size_t index) + : PositionInCharAllocator(container, vector_ind, item_iter), + index_(index) {} -ListContainerBase::Iterator::~Iterator() { -} +ListContainerHelper::Iterator::~Iterator() {} -size_t ListContainerBase::Iterator::index() const { +size_t ListContainerHelper::Iterator::index() const { return index_; } -// ListContainerBase::ConstIterator +// ListContainerHelper::ConstIterator ///////////////////////////////////////////////// -ListContainerBase::ConstIterator::ConstIterator( - const ListContainerBase::Iterator& other) - : PositionInListContainerCharAllocator(other), index_(other.index()) { -} +ListContainerHelper::ConstIterator::ConstIterator( + const ListContainerHelper::Iterator& other) + : PositionInCharAllocator(other), index_(other.index()) {} -ListContainerBase::ConstIterator::ConstIterator( - ListContainerCharAllocator* container, - size_t vector_ind, - char* item_iter, - size_t index) - : PositionInListContainerCharAllocator(container, vector_ind, item_iter), - index_(index) { -} +ListContainerHelper::ConstIterator::ConstIterator(CharAllocator* container, + size_t vector_ind, + char* item_iter, + size_t index) + : PositionInCharAllocator(container, vector_ind, item_iter), + index_(index) {} -ListContainerBase::ConstIterator::~ConstIterator() { -} +ListContainerHelper::ConstIterator::~ConstIterator() {} -size_t ListContainerBase::ConstIterator::index() const { +size_t ListContainerHelper::ConstIterator::index() const { return index_; } -// ListContainerBase::ReverseIterator +// ListContainerHelper::ReverseIterator ///////////////////////////////////////////////// -ListContainerBase::ReverseIterator::ReverseIterator( - ListContainerCharAllocator* container, - size_t vector_ind, - char* item_iter, - size_t index) - : PositionInListContainerCharAllocator(container, vector_ind, item_iter), - index_(index) { -} +ListContainerHelper::ReverseIterator::ReverseIterator(CharAllocator* container, + size_t vector_ind, + char* item_iter, + size_t index) + : PositionInCharAllocator(container, vector_ind, item_iter), + index_(index) {} -ListContainerBase::ReverseIterator::~ReverseIterator() { -} +ListContainerHelper::ReverseIterator::~ReverseIterator() {} -size_t ListContainerBase::ReverseIterator::index() const { +size_t ListContainerHelper::ReverseIterator::index() const { return index_; } -// ListContainerBase::ConstReverseIterator +// ListContainerHelper::ConstReverseIterator ///////////////////////////////////////////////// -ListContainerBase::ConstReverseIterator::ConstReverseIterator( - const ListContainerBase::ReverseIterator& other) - : PositionInListContainerCharAllocator(other), index_(other.index()) { -} +ListContainerHelper::ConstReverseIterator::ConstReverseIterator( + const ListContainerHelper::ReverseIterator& other) + : PositionInCharAllocator(other), index_(other.index()) {} -ListContainerBase::ConstReverseIterator::ConstReverseIterator( - ListContainerCharAllocator* container, +ListContainerHelper::ConstReverseIterator::ConstReverseIterator( + CharAllocator* container, size_t vector_ind, char* item_iter, size_t index) - : PositionInListContainerCharAllocator(container, vector_ind, item_iter), - index_(index) { -} + : PositionInCharAllocator(container, vector_ind, item_iter), + index_(index) {} -ListContainerBase::ConstReverseIterator::~ConstReverseIterator() { -} +ListContainerHelper::ConstReverseIterator::~ConstReverseIterator() {} -size_t ListContainerBase::ConstReverseIterator::index() const { +size_t ListContainerHelper::ConstReverseIterator::index() const { return index_; } diff --git a/chromium/cc/base/list_container_helper.h b/chromium/cc/base/list_container_helper.h new file mode 100644 index 00000000000..31b2310d49d --- /dev/null +++ b/chromium/cc/base/list_container_helper.h @@ -0,0 +1,178 @@ +// 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_BASE_LIST_CONTAINER_HELPER_H_ +#define CC_BASE_LIST_CONTAINER_HELPER_H_ + +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" + +namespace cc { + +// Helper class for ListContainer non-templated logic. All methods are private, +// and only exposed to friend classes. +// For usage, see comments in ListContainer (list_container.h). +class CC_EXPORT ListContainerHelper final { + private: + template <typename T> + friend class ListContainer; + + template <typename T> + friend class RandomAccessListContainer; + + explicit ListContainerHelper(size_t max_size_for_derived_class); + ListContainerHelper(size_t max_size_for_derived_class, + size_t num_of_elements_to_reserve_for); + ~ListContainerHelper(); + + // This class deals only with char* and void*. It does allocation and passing + // out raw pointers, as well as memory deallocation when being destroyed. + class CharAllocator; + + // This class points to a certain position inside memory of + // CharAllocator. It is a base class for ListContainer iterators. + struct CC_EXPORT PositionInCharAllocator { + CharAllocator* ptr_to_container; + size_t vector_index; + char* item_iterator; + + PositionInCharAllocator(const PositionInCharAllocator& other); + + PositionInCharAllocator(CharAllocator* container, + size_t vector_ind, + char* item_iter); + + bool operator==(const PositionInCharAllocator& other) const; + bool operator!=(const PositionInCharAllocator& other) const; + + PositionInCharAllocator Increment(); + PositionInCharAllocator ReverseIncrement(); + }; + + // Iterator classes that can be used to access data. + ///////////////////////////////////////////////////////////////// + class CC_EXPORT Iterator : public PositionInCharAllocator { + // This class is only defined to forward iterate through + // CharAllocator. + public: + Iterator(CharAllocator* container, + size_t vector_ind, + char* item_iter, + size_t index); + ~Iterator(); + + size_t index() const; + + protected: + // This is used to track how many increment has happened since begin(). It + // is used to avoid double increment at places an index reference is + // needed. For iterator this means begin() corresponds to index 0 and end() + // corresponds to index |size|. + size_t index_; + }; + + class CC_EXPORT ConstIterator : public PositionInCharAllocator { + // This class is only defined to forward iterate through + // CharAllocator. + public: + ConstIterator(CharAllocator* container, + size_t vector_ind, + char* item_iter, + size_t index); + ConstIterator(const Iterator& other); // NOLINT + ~ConstIterator(); + + size_t index() const; + + protected: + // This is used to track how many increment has happened since begin(). It + // is used to avoid double increment at places an index reference is + // needed. For iterator this means begin() corresponds to index 0 and end() + // corresponds to index |size|. + size_t index_; + }; + + class CC_EXPORT ReverseIterator : public PositionInCharAllocator { + // This class is only defined to reverse iterate through + // CharAllocator. + public: + ReverseIterator(CharAllocator* container, + size_t vector_ind, + char* item_iter, + size_t index); + ~ReverseIterator(); + + size_t index() const; + + protected: + // This is used to track how many increment has happened since rbegin(). It + // is used to avoid double increment at places an index reference is + // needed. For reverse iterator this means rbegin() corresponds to index 0 + // and rend() corresponds to index |size|. + size_t index_; + }; + + class CC_EXPORT ConstReverseIterator : public PositionInCharAllocator { + // This class is only defined to reverse iterate through + // CharAllocator. + public: + ConstReverseIterator(CharAllocator* container, + size_t vector_ind, + char* item_iter, + size_t index); + ConstReverseIterator(const ReverseIterator& other); // NOLINT + ~ConstReverseIterator(); + + size_t index() const; + + protected: + // This is used to track how many increment has happened since rbegin(). It + // is used to avoid double increment at places an index reference is + // needed. For reverse iterator this means rbegin() corresponds to index 0 + // and rend() corresponds to index |size|. + size_t index_; + }; + + // Unlike the ListContainer methods, these do not invoke element destructors. + void RemoveLast(); + void EraseAndInvalidateAllPointers(Iterator* position); + void InsertBeforeAndInvalidateAllPointers(Iterator* position, + size_t number_of_elements); + + ConstReverseIterator crbegin() const; + ConstReverseIterator crend() const; + ReverseIterator rbegin(); + ReverseIterator rend(); + ConstIterator cbegin() const; + ConstIterator cend() const; + Iterator begin(); + Iterator end(); + + Iterator IteratorAt(size_t index); + ConstIterator IteratorAt(size_t index) const; + + size_t size() const; + bool empty() const; + + size_t MaxSizeForDerivedClass() const; + + size_t GetCapacityInBytes() const; + + // Unlike the ListContainer method, this one does not invoke element + // destructors. + void clear(); + + size_t AvailableSizeWithoutAnotherAllocationForTesting() const; + + // Hands out memory location for an element at the end of data structure. + void* Allocate(size_t size_of_actual_element_in_bytes); + + scoped_ptr<CharAllocator> data_; + + DISALLOW_COPY_AND_ASSIGN(ListContainerHelper); +}; + +} // namespace cc + +#endif // CC_BASE_LIST_CONTAINER_HELPER_H_ diff --git a/chromium/cc/base/list_container_unittest.cc b/chromium/cc/base/list_container_unittest.cc index d1fb3fb9490..be0b2b75b4e 100644 --- a/chromium/cc/base/list_container_unittest.cc +++ b/chromium/cc/base/list_container_unittest.cc @@ -657,30 +657,154 @@ TEST(ListContainerTest, DeletionAllInAllocationReversed) { } } -TEST(ListContainerTest, SimpleIterationAndManipulation) { +TEST(ListContainerTest, DeletionWhileIterating) { + ListContainer<SimpleDerivedElement> list(kCurrentLargestDerivedElementSize); + for (int i = 0; i < 4; ++i) + list.AllocateAndConstruct<SimpleDerivedElement>()->set_value(i); + + // Delete odd elements. + for (auto it = list.begin(); it != list.end();) { + if ((*it)->get_value() % 2) + it = list.EraseAndInvalidateAllPointers(it); + else + ++it; + } + + EXPECT_EQ(2u, list.size()); + EXPECT_EQ(0, list.front()->get_value()); + EXPECT_EQ(2, list.back()->get_value()); + + // Erase all elements. + for (auto it = list.begin(); it != list.end();) + it = list.EraseAndInvalidateAllPointers(it); + + EXPECT_TRUE(list.empty()); +} + +TEST(ListContainerTest, InsertBeforeBegin) { ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize); std::vector<SimpleDerivedElement*> sde_list; - size_t size = 10; + const int size = 4; + for (int i = 0; i < size; ++i) { + sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>()); + sde_list.back()->set_value(i); + } + EXPECT_EQ(static_cast<size_t>(size), list.size()); + + const int count = 2; + ListContainer<DerivedElement>::Iterator iter = + list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>( + list.begin(), count); + for (int i = 0; i < count; ++i) { + static_cast<SimpleDerivedElement*>(*iter)->set_value(100 + i); + ++iter; + } + + const int expected_result[] = {100, 101, 0, 1, 2, 3}; + int iter_index = 0; + for (iter = list.begin(); iter != list.end(); ++iter) { + EXPECT_EQ(expected_result[iter_index], + static_cast<SimpleDerivedElement*>(*iter)->get_value()); + ++iter_index; + } + EXPECT_EQ(size + count, iter_index); +} + +TEST(ListContainerTest, InsertBeforeEnd) { + ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize); + std::vector<SimpleDerivedElement*> sde_list; + const int size = 4; + for (int i = 0; i < size; ++i) { + sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>()); + sde_list.back()->set_value(i); + } + EXPECT_EQ(static_cast<size_t>(size), list.size()); + + const int count = 3; + ListContainer<DerivedElement>::Iterator iter = + list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>( + list.end(), count); + for (int i = 0; i < count; ++i) { + static_cast<SimpleDerivedElement*>(*iter)->set_value(100 + i); + ++iter; + } + + const int expected_result[] = {0, 1, 2, 3, 100, 101, 102}; + int iter_index = 0; + for (iter = list.begin(); iter != list.end(); ++iter) { + EXPECT_EQ(expected_result[iter_index], + static_cast<SimpleDerivedElement*>(*iter)->get_value()); + ++iter_index; + } + EXPECT_EQ(size + count, iter_index); +} + +TEST(ListContainerTest, InsertBeforeEmpty) { + ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize); + + const int count = 3; + ListContainer<DerivedElement>::Iterator iter = + list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>( + list.end(), count); + for (int i = 0; i < count; ++i) { + static_cast<SimpleDerivedElement*>(*iter)->set_value(100 + i); + ++iter; + } + + const int expected_result[] = {100, 101, 102}; + int iter_index = 0; + for (iter = list.begin(); iter != list.end(); ++iter) { + EXPECT_EQ(expected_result[iter_index], + static_cast<SimpleDerivedElement*>(*iter)->get_value()); + ++iter_index; + } + EXPECT_EQ(count, iter_index); +} + +TEST(ListContainerTest, InsertBeforeMany) { + ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize); + std::vector<SimpleDerivedElement*> sde_list; + // Create a partial list of 1,...,99. + int initial_list[] = { + 0, 1, 4, 5, 6, 7, 8, 9, 11, 12, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 32, 34, 36, 37, 51, 52, 54, 56, + 60, 64, 65, 70, 75, 76, 80, 81, 83, 86, 87, 90, 93, 95, 97, 98, + }; + const size_t size = sizeof(initial_list) / sizeof(initial_list[0]); for (size_t i = 0; i < size; ++i) { - SimpleDerivedElement* simple_dq = - list.AllocateAndConstruct<SimpleDerivedElement>(); - sde_list.push_back(simple_dq); + sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>()); + sde_list.back()->set_value(initial_list[i]); } - EXPECT_EQ(size, list.size()); + EXPECT_EQ(static_cast<size_t>(size), list.size()); + // Insert the missing elements. ListContainer<DerivedElement>::Iterator iter = list.begin(); - for (int i = 0; i < 10; ++i) { - static_cast<SimpleDerivedElement*>(*iter)->set_value(i); - ++iter; + while (iter != list.end()) { + ListContainer<DerivedElement>::Iterator iter_next = iter; + ++iter_next; + + int value = static_cast<SimpleDerivedElement*>(*iter)->get_value(); + int value_next = + iter_next != list.end() + ? static_cast<SimpleDerivedElement*>(*iter_next)->get_value() + : 100; + int count = value_next - value - 1; + + iter = list.InsertBeforeAndInvalidateAllPointers<SimpleDerivedElement>( + iter_next, count); + for (int i = value + 1; i < value_next; ++i) { + static_cast<SimpleDerivedElement*>(*iter)->set_value(i); + ++iter; + } } - int i = 0; - for (std::vector<SimpleDerivedElement*>::const_iterator sde_iter = - sde_list.begin(); - sde_iter < sde_list.end(); ++sde_iter) { - EXPECT_EQ(i, (*sde_iter)->get_value()); - ++i; + int iter_index = 0; + for (iter = list.begin(); iter != list.end(); ++iter) { + EXPECT_EQ(iter_index, + static_cast<SimpleDerivedElement*>(*iter)->get_value()); + ++iter_index; } + EXPECT_EQ(100, iter_index); } TEST(ListContainerTest, SimpleManipulationWithIndexSimpleDerivedElement) { diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc index 969e52a6ed7..6e5ac0bd45d 100644 --- a/chromium/cc/base/math_util.cc +++ b/chromium/cc/base/math_util.cc @@ -26,18 +26,19 @@ const float MathUtil::kPiFloat = 3.14159265358979323846f; static HomogeneousCoordinate ProjectHomogeneousPoint( const gfx::Transform& transform, const gfx::PointF& p) { + SkMScalar z = + -(transform.matrix().get(2, 0) * p.x() + + transform.matrix().get(2, 1) * p.y() + transform.matrix().get(2, 3)) / + transform.matrix().get(2, 2); + // In this case, the layer we are trying to project onto is perpendicular to // ray (point p and z-axis direction) that we are trying to project. This // happens when the layer is rotated so that it is infinitesimally thin, or // when it is co-planar with the camera origin -- i.e. when the layer is // invisible anyway. - if (!transform.matrix().get(2, 2)) + if (!std::isfinite(z)) return HomogeneousCoordinate(0.0, 0.0, 0.0, 1.0); - SkMScalar z = -(transform.matrix().get(2, 0) * p.x() + - transform.matrix().get(2, 1) * p.y() + - transform.matrix().get(2, 3)) / - transform.matrix().get(2, 2); HomogeneousCoordinate result(p.x(), p.y(), z, 1.0); transform.matrix().mapMScalars(result.vec, result.vec); return result; @@ -126,7 +127,14 @@ gfx::Rect MathUtil::MapEnclosingClippedRect(const gfx::Transform& transform, static_cast<int>(transform.matrix().getFloat(1, 3))); return src_rect + offset; } - return gfx::ToEnclosingRect(MapClippedRect(transform, gfx::RectF(src_rect))); + gfx::RectF mapped_rect = MapClippedRect(transform, gfx::RectF(src_rect)); + + // gfx::ToEnclosingRect crashes if called on a RectF with any NaN coordinate. + if (std::isnan(mapped_rect.x()) || std::isnan(mapped_rect.y()) || + std::isnan(mapped_rect.right()) || std::isnan(mapped_rect.bottom())) + return gfx::Rect(); + + return gfx::ToEnclosingRect(mapped_rect); } gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform, @@ -166,8 +174,15 @@ gfx::Rect MathUtil::ProjectEnclosingClippedRect(const gfx::Transform& transform, static_cast<int>(transform.matrix().getFloat(1, 3))); return src_rect + offset; } - return gfx::ToEnclosingRect( - ProjectClippedRect(transform, gfx::RectF(src_rect))); + gfx::RectF projected_rect = + ProjectClippedRect(transform, gfx::RectF(src_rect)); + + // gfx::ToEnclosingRect crashes if called on a RectF with any NaN coordinate. + if (std::isnan(projected_rect.x()) || std::isnan(projected_rect.y()) || + std::isnan(projected_rect.right()) || std::isnan(projected_rect.bottom())) + return gfx::Rect(); + + return gfx::ToEnclosingRect(projected_rect); } gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform, @@ -201,7 +216,7 @@ gfx::Rect MathUtil::MapEnclosedRectWith2dAxisAlignedTransform( if (transform.IsIdentityOrTranslation()) { gfx::Vector2dF offset(transform.matrix().getFloat(0, 3), transform.matrix().getFloat(1, 3)); - return gfx::ToEnclosedRect(rect + offset); + return gfx::ToEnclosedRect(gfx::RectF(rect) + offset); } SkMScalar quad[2 * 2]; // input: 2 x 2D points diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h index 4c40e8ef9a4..a83ab4fdce3 100644 --- a/chromium/cc/base/math_util.h +++ b/chromium/cc/base/math_util.h @@ -30,6 +30,7 @@ namespace gfx { class QuadF; class Rect; class RectF; +class SizeF; class Transform; class Vector2dF; class Vector2d; @@ -96,27 +97,62 @@ class CC_EXPORT MathUtil { return (d > 0.0) ? std::floor(d + 0.5) : std::ceil(d - 0.5); } - // RoundUp rounds up a given |n| to be a multiple of |mul|. + // Returns true if rounded up value does not overflow, false otherwise. + template <typename T> + static bool VerifyRoundup(T n, T mul) { + return mul && (n <= (std::numeric_limits<T>::max() - + (std::numeric_limits<T>::max() % mul))); + } + + // Rounds up a given |n| to be a multiple of |mul|, but may overflow. // Examples: // - RoundUp(123, 50) returns 150. // - RoundUp(-123, 50) returns -100. template <typename T> - static T RoundUp(T n, T mul) { + static T UncheckedRoundUp(T n, T mul) { 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; + DCHECK(VerifyRoundup(n, mul)); + return RoundUpInternal(n, mul); + } + + // Similar to UncheckedRoundUp(), but dies with a CRASH() if rounding up a + // given |n| overflows T. + template <typename T> + static T CheckedRoundUp(T n, T mul) { + static_assert(std::numeric_limits<T>::is_integer, + "T must be an integer type"); + CHECK(VerifyRoundup(n, mul)); + return RoundUpInternal(n, mul); } - // RoundDown rounds down a given |n| to be a multiple of |mul|. + // Returns true if rounded down value does not underflow, false otherwise. + template <typename T> + static bool VerifyRoundDown(T n, T mul) { + return mul && (n >= (std::numeric_limits<T>::min() - + (std::numeric_limits<T>::min() % mul))); + } + + // Rounds down a given |n| to be a multiple of |mul|, but may underflow. // Examples: // - RoundDown(123, 50) returns 100. // - RoundDown(-123, 50) returns -150. template <typename T> - static T RoundDown(T n, T mul) { + static T UncheckedRoundDown(T n, T mul) { 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; + DCHECK(VerifyRoundDown(n, mul)); + return RoundDownInternal(n, mul); + } + + // Similar to UncheckedRoundDown(), but dies with a CRASH() if rounding down a + // given |n| underflows T. + template <typename T> + static T CheckedRoundDown(T n, T mul) { + static_assert(std::numeric_limits<T>::is_integer, + "T must be an integer type"); + CHECK(VerifyRoundDown(n, mul)); + return RoundDownInternal(n, mul); } template <typename T> static T ClampToRange(T value, T min, T max) { @@ -270,6 +306,18 @@ class CC_EXPORT MathUtil { // Returns vector that y axis (0,1,0) transforms to under given transform. static gfx::Vector3dF GetYAxis(const gfx::Transform& transform); + + private: + template <typename T> + static T RoundUpInternal(T n, T mul) { + return (n > 0) ? ((n + mul - 1) / mul) * mul : (n / mul) * mul; + } + + template <typename T> + static T RoundDownInternal(T n, T mul) { + return (n > 0) ? (n / mul) * mul : (n == 0) ? 0 + : ((n - mul + 1) / mul) * mul; + } }; } // namespace cc diff --git a/chromium/cc/base/math_util_unittest.cc b/chromium/cc/base/math_util_unittest.cc index 1d43e0f2129..9d44fba8ac0 100644 --- a/chromium/cc/base/math_util_unittest.cc +++ b/chromium/cc/base/math_util_unittest.cc @@ -32,6 +32,32 @@ TEST(MathUtilTest, ProjectionOfPerpendicularPlane) { EXPECT_TRUE(projected_rect.IsEmpty()); } +TEST(MathUtilTest, ProjectionOfAlmostPerpendicularPlane) { + // In this case, the m33() element of the transform becomes almost zero, which + // could cause a divide-by-zero when projecting points/quads. + + gfx::Transform transform; + // The transform is from an actual test page: + // [ +1.0000 +0.0000 -1.0000 +3144132.0000 + // +0.0000 +1.0000 +0.0000 +0.0000 + // +16331238407143424.0000 +0.0000 -0.0000 +51346917453137000267776.0000 + // +0.0000 +0.0000 +0.0000 +1.0000 ] + transform.MakeIdentity(); + transform.matrix().set(0, 2, static_cast<SkMScalar>(-1)); + transform.matrix().set(0, 3, static_cast<SkMScalar>(3144132.0)); + transform.matrix().set(2, 0, static_cast<SkMScalar>(16331238407143424.0)); + transform.matrix().set(2, 2, static_cast<SkMScalar>(-1e-33)); + transform.matrix().set(2, 3, + static_cast<SkMScalar>(51346917453137000267776.0)); + + gfx::RectF rect = gfx::RectF(0, 0, 1, 1); + gfx::RectF projected_rect = MathUtil::ProjectClippedRect(transform, rect); + + EXPECT_EQ(0, projected_rect.x()); + EXPECT_EQ(0, projected_rect.y()); + EXPECT_TRUE(projected_rect.IsEmpty()) << projected_rect.ToString(); +} + TEST(MathUtilTest, EnclosingClippedRectUsesCorrectInitialBounds) { HomogeneousCoordinate h1(-100, -100, 0, 1); HomogeneousCoordinate h2(-10, -10, 0, 1); @@ -193,6 +219,104 @@ TEST(MathUtilTest, MapEnclosedRectWith2dAxisAlignedTransform) { EXPECT_EQ(gfx::Rect(2, 4, 6, 8), output); } +TEST(MathUtilTest, MapEnclosingRectWithLargeTransforms) { + gfx::Rect input(1, 2, 100, 200); + gfx::Rect output; + + gfx::Transform large_x_scale; + large_x_scale.Scale(SkDoubleToMScalar(1e37), 1.0); + + gfx::Transform infinite_x_scale; + infinite_x_scale = large_x_scale * large_x_scale; + + gfx::Transform large_y_scale; + large_y_scale.Scale(1.0, SkDoubleToMScalar(1e37)); + + gfx::Transform infinite_y_scale; + infinite_y_scale = large_y_scale * large_y_scale; + + gfx::Transform rotation; + rotation.RotateAboutYAxis(170.0); + + int max_int = std::numeric_limits<int>::max(); + + output = MathUtil::MapEnclosingClippedRect(large_x_scale, input); + EXPECT_EQ(gfx::Rect(max_int, 2, 0, 200), output); + + output = MathUtil::MapEnclosingClippedRect(large_x_scale * rotation, input); + EXPECT_EQ(gfx::Rect(), output); + + output = MathUtil::MapEnclosingClippedRect(infinite_x_scale, input); + EXPECT_EQ(gfx::Rect(max_int, 2, 0, 200), output); + + output = + MathUtil::MapEnclosingClippedRect(infinite_x_scale * rotation, input); + EXPECT_EQ(gfx::Rect(), output); + + output = MathUtil::MapEnclosingClippedRect(large_y_scale, input); + EXPECT_EQ(gfx::Rect(1, max_int, 100, 0), output); + + output = MathUtil::MapEnclosingClippedRect(large_y_scale * rotation, input); + EXPECT_EQ(gfx::Rect(-100, max_int, 100, 0), output); + + output = MathUtil::MapEnclosingClippedRect(infinite_y_scale, input); + EXPECT_EQ(gfx::Rect(1, max_int, 100, 0), output); + + output = + MathUtil::MapEnclosingClippedRect(infinite_y_scale * rotation, input); + EXPECT_EQ(gfx::Rect(), output); +} + +TEST(MathUtilTest, ProjectEnclosingRectWithLargeTransforms) { + gfx::Rect input(1, 2, 100, 200); + gfx::Rect output; + + gfx::Transform large_x_scale; + large_x_scale.Scale(SkDoubleToMScalar(1e37), 1.0); + + gfx::Transform infinite_x_scale; + infinite_x_scale = large_x_scale * large_x_scale; + + gfx::Transform large_y_scale; + large_y_scale.Scale(1.0, SkDoubleToMScalar(1e37)); + + gfx::Transform infinite_y_scale; + infinite_y_scale = large_y_scale * large_y_scale; + + gfx::Transform rotation; + rotation.RotateAboutYAxis(170.0); + + int max_int = std::numeric_limits<int>::max(); + + output = MathUtil::ProjectEnclosingClippedRect(large_x_scale, input); + EXPECT_EQ(gfx::Rect(max_int, 2, 0, 200), output); + + output = + MathUtil::ProjectEnclosingClippedRect(large_x_scale * rotation, input); + EXPECT_EQ(gfx::Rect(), output); + + output = MathUtil::ProjectEnclosingClippedRect(infinite_x_scale, input); + EXPECT_EQ(gfx::Rect(max_int, 2, 0, 200), output); + + output = + MathUtil::ProjectEnclosingClippedRect(infinite_x_scale * rotation, input); + EXPECT_EQ(gfx::Rect(), output); + + output = MathUtil::ProjectEnclosingClippedRect(large_y_scale, input); + EXPECT_EQ(gfx::Rect(1, max_int, 100, 0), output); + + output = + MathUtil::ProjectEnclosingClippedRect(large_y_scale * rotation, input); + EXPECT_EQ(gfx::Rect(-103, max_int, 102, 0), output); + + output = MathUtil::ProjectEnclosingClippedRect(infinite_y_scale, input); + EXPECT_EQ(gfx::Rect(1, max_int, 100, 0), output); + + output = + MathUtil::ProjectEnclosingClippedRect(infinite_y_scale * rotation, input); + EXPECT_EQ(gfx::Rect(), output); +} + TEST(MathUtilTest, RoundUp) { for (int multiplier = 1; multiplier <= 10; ++multiplier) { // Try attempts in descending order, so that we can @@ -201,7 +325,7 @@ TEST(MathUtilTest, RoundUp) { for (int attempt = 5 * multiplier; attempt >= -5 * multiplier; --attempt) { if ((attempt % multiplier) == 0) correct = attempt; - EXPECT_EQ(correct, MathUtil::RoundUp(attempt, multiplier)) + EXPECT_EQ(correct, MathUtil::UncheckedRoundUp(attempt, multiplier)) << "attempt=" << attempt << " multiplier=" << multiplier; } } @@ -213,14 +337,20 @@ TEST(MathUtilTest, RoundUp) { for (unsigned attempt = 5 * multiplier; attempt > 0; --attempt) { if ((attempt % multiplier) == 0) correct = attempt; - EXPECT_EQ(correct, MathUtil::RoundUp(attempt, multiplier)) + EXPECT_EQ(correct, MathUtil::UncheckedRoundUp(attempt, multiplier)) << "attempt=" << attempt << " multiplier=" << multiplier; } - EXPECT_EQ(0u, MathUtil::RoundUp(0u, multiplier)) + EXPECT_EQ(0u, MathUtil::UncheckedRoundUp(0u, multiplier)) << "attempt=0 multiplier=" << multiplier; } } +TEST(MathUtilTest, RoundUpOverflow) { + // Rounding up 123 by 50 is 150, which overflows int8_t, but fits in uint8_t. + EXPECT_FALSE(MathUtil::VerifyRoundup<int8_t>(123, 50)); + EXPECT_TRUE(MathUtil::VerifyRoundup<uint8_t>(123, 50)); +} + TEST(MathUtilTest, RoundDown) { for (int multiplier = 1; multiplier <= 10; ++multiplier) { // Try attempts in ascending order, so that we can @@ -229,7 +359,7 @@ TEST(MathUtilTest, RoundDown) { for (int attempt = -5 * multiplier; attempt <= 5 * multiplier; ++attempt) { if ((attempt % multiplier) == 0) correct = attempt; - EXPECT_EQ(correct, MathUtil::RoundDown(attempt, multiplier)) + EXPECT_EQ(correct, MathUtil::UncheckedRoundDown(attempt, multiplier)) << "attempt=" << attempt << " multiplier=" << multiplier; } } @@ -241,11 +371,18 @@ TEST(MathUtilTest, RoundDown) { for (unsigned attempt = 0; attempt <= 5 * multiplier; ++attempt) { if ((attempt % multiplier) == 0) correct = attempt; - EXPECT_EQ(correct, MathUtil::RoundDown(attempt, multiplier)) + EXPECT_EQ(correct, MathUtil::UncheckedRoundDown(attempt, multiplier)) << "attempt=" << attempt << " multiplier=" << multiplier; } } } +TEST(MathUtilTest, RoundDownUnderflow) { + // Rounding down -123 by 50 is -150, which underflows int8_t, but fits in + // int16_t. + EXPECT_FALSE(MathUtil::VerifyRoundDown<int8_t>(-123, 50)); + EXPECT_TRUE(MathUtil::VerifyRoundDown<int16_t>(-123, 50)); +} + } // namespace } // namespace cc diff --git a/chromium/cc/base/random_access_list_container.h b/chromium/cc/base/random_access_list_container.h new file mode 100644 index 00000000000..b2baf3064d2 --- /dev/null +++ b/chromium/cc/base/random_access_list_container.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_BASE_RANDOM_ACCESS_LIST_CONTAINER_H_ +#define CC_BASE_RANDOM_ACCESS_LIST_CONTAINER_H_ + +#include <vector> + +#include "base/logging.h" +#include "cc/base/list_container_helper.h" + +namespace cc { + +// RandomAccessListContainer is a container similar to ListContainer (see +// list_container.h), but it allows random access into its elements via +// operator[]. In order to have efficient support for random access, some +// functionality is not available for RandomAccessListContainers, such as +// insert/deletes in the middle of the list. +template <class BaseElementType> +class RandomAccessListContainer { + public: + // BaseElementType is the type of raw pointers this class hands out; however, + // its derived classes might require different memory sizes. + // max_size_for_derived_class the largest memory size required for all the + // derived classes to use for allocation. + explicit RandomAccessListContainer(size_t max_size_for_derived_class) + : helper_(max_size_for_derived_class) {} + + // This constructor reserves the requested memory up front so only a single + // allocation is needed. When num_of_elements_to_reserve_for is zero, use the + // default size. + RandomAccessListContainer(size_t max_size_for_derived_class, + size_t num_of_elements_to_reserve_for) + : helper_(max_size_for_derived_class, num_of_elements_to_reserve_for) { + items_.reserve(num_of_elements_to_reserve_for); + } + + ~RandomAccessListContainer() { + for (BaseElementType* item : items_) + item->~BaseElementType(); + } + + void clear() { + for (BaseElementType* item : items_) + item->~BaseElementType(); + helper_.clear(); + items_.clear(); + } + + bool empty() const { return helper_.empty(); } + size_t size() const { return helper_.size(); } + size_t GetCapacityInBytes() const { return helper_.GetCapacityInBytes(); } + + template <typename DerivedElementType> + DerivedElementType* AllocateAndConstruct() { + auto* value = + new (helper_.Allocate(sizeof(DerivedElementType))) DerivedElementType; + items_.push_back(value); + return value; + } + + void RemoveLast() { + items_.back()->~BaseElementType(); + items_.pop_back(); + helper_.RemoveLast(); + } + + const BaseElementType* operator[](size_t index) const { + DCHECK_GE(index, 0u); + DCHECK_LT(index, items_.size()); + return items_[index]; + } + + BaseElementType* operator[](size_t index) { + DCHECK_GE(index, 0u); + DCHECK_LT(index, items_.size()); + return items_[index]; + } + + // Note that although BaseElementType objects can change, the pointer itself + // (in the vector) cannot. So this class only supports a const iterator. + using ConstIterator = typename std::vector<BaseElementType*>::const_iterator; + ConstIterator begin() const { return items_.begin(); } + ConstIterator end() const { return items_.end(); } + + private: + ListContainerHelper helper_; + std::vector<BaseElementType*> items_; +}; + +} // namespace cc + +#endif // CC_BASE_RANDOM_ACCESS_LIST_CONTAINER_H_ diff --git a/chromium/cc/base/random_access_list_container_unittest.cc b/chromium/cc/base/random_access_list_container_unittest.cc new file mode 100644 index 00000000000..78004b4a8f4 --- /dev/null +++ b/chromium/cc/base/random_access_list_container_unittest.cc @@ -0,0 +1,107 @@ +// 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/base/random_access_list_container.h" + +#include <algorithm> +#include <vector> + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +class Base { + public: + virtual ~Base() {} + int get_value() const { return value_; } + + protected: + explicit Base(int value) : value_(value) {} + + int value_; +}; + +const int kMagicNumberOne = 1; +const int kMagicNumberTwo = 2; +const int kMagicNumberThree = 3; + +class Derived1 : public Base { + public: + Derived1() : Base(kMagicNumberOne) {} +}; + +class Derived2 : public Base { + public: + Derived2() : Base(kMagicNumberTwo) {} +}; + +class Derived3 : public Base { + public: + Derived3() : Base(kMagicNumberThree) {} +}; + +size_t LargestDerivedElementSize() { + static_assert(sizeof(Derived1) >= sizeof(Derived2), + "Derived2 is larger than Derived1"); + static_assert(sizeof(Derived1) >= sizeof(Derived3), + "Derived3 is larger than Derived1"); + return sizeof(Derived1); +} + +TEST(RandomAccessListContainerTest, RandomAccess) { + RandomAccessListContainer<Base> list(LargestDerivedElementSize(), 1); + + list.AllocateAndConstruct<Derived1>(); + list.AllocateAndConstruct<Derived2>(); + list.AllocateAndConstruct<Derived3>(); + list.AllocateAndConstruct<Derived1>(); + list.AllocateAndConstruct<Derived2>(); + list.AllocateAndConstruct<Derived3>(); + + EXPECT_EQ(kMagicNumberOne, list[0]->get_value()); + EXPECT_EQ(kMagicNumberTwo, list[1]->get_value()); + EXPECT_EQ(kMagicNumberThree, list[2]->get_value()); + EXPECT_EQ(kMagicNumberOne, list[3]->get_value()); + EXPECT_EQ(kMagicNumberTwo, list[4]->get_value()); + EXPECT_EQ(kMagicNumberThree, list[5]->get_value()); + + list.RemoveLast(); + list.RemoveLast(); + list.RemoveLast(); + + EXPECT_EQ(kMagicNumberOne, list[0]->get_value()); + EXPECT_EQ(kMagicNumberTwo, list[1]->get_value()); + EXPECT_EQ(kMagicNumberThree, list[2]->get_value()); + + list.AllocateAndConstruct<Derived3>(); + list.AllocateAndConstruct<Derived2>(); + list.AllocateAndConstruct<Derived1>(); + + EXPECT_EQ(kMagicNumberOne, list[0]->get_value()); + EXPECT_EQ(kMagicNumberTwo, list[1]->get_value()); + EXPECT_EQ(kMagicNumberThree, list[2]->get_value()); + EXPECT_EQ(kMagicNumberThree, list[3]->get_value()); + EXPECT_EQ(kMagicNumberTwo, list[4]->get_value()); + EXPECT_EQ(kMagicNumberOne, list[5]->get_value()); +} + +TEST(RandomAccessListContainerTest, Clear) { + RandomAccessListContainer<Base> list(LargestDerivedElementSize(), 1); + + list.AllocateAndConstruct<Derived1>(); + list.AllocateAndConstruct<Derived2>(); + + EXPECT_EQ(kMagicNumberOne, list[0]->get_value()); + EXPECT_EQ(kMagicNumberTwo, list[1]->get_value()); + + list.clear(); + list.AllocateAndConstruct<Derived3>(); + + EXPECT_EQ(kMagicNumberThree, list[0]->get_value()); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/base/rtree.cc b/chromium/cc/base/rtree.cc new file mode 100644 index 00000000000..ca64e87dfe1 --- /dev/null +++ b/chromium/cc/base/rtree.cc @@ -0,0 +1,111 @@ +// Copyright (c) 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/base/rtree.h" + +#include <cmath> + +#include "base/logging.h" + +namespace cc { + +RTree::RTree() : num_data_elements_(0u) {} + +RTree::~RTree() {} + +RTree::Node* RTree::AllocateNodeAtLevel(int level) { + nodes_.push_back(Node()); + Node& node = nodes_.back(); + node.num_children = 0; + node.level = level; + return &node; +} + +RTree::Branch RTree::BuildRecursive(std::vector<Branch>* branches, int level) { + // Only one branch. It will be the root. + if (branches->size() == 1) + return (*branches)[0]; + + // TODO(vmpstr): Investigate if branches should be sorted in y. + // The comment from Skia reads: + // We might sort our branches here, but we expect Blink gives us a reasonable + // x,y order. Skipping a call to sort (in Y) here resulted in a 17% win for + // recording with negligible difference in playback speed. + int num_branches = static_cast<int>(branches->size() / MAX_CHILDREN); + int remainder = static_cast<int>(branches->size() % MAX_CHILDREN); + + if (remainder > 0) { + ++num_branches; + // If the remainder isn't enough to fill a node, we'll add fewer nodes to + // other branches. + if (remainder >= MIN_CHILDREN) + remainder = 0; + else + remainder = MIN_CHILDREN - remainder; + } + + int num_strips = static_cast<int>(std::ceil(std::sqrt(num_branches))); + int num_tiles = static_cast<int>( + std::ceil(num_branches / static_cast<float>(num_strips))); + size_t current_branch = 0; + + size_t new_branch_index = 0; + for (int i = 0; i < num_strips; ++i) { + // Might be worth sorting by X here too. + for (int j = 0; j < num_tiles && current_branch < branches->size(); ++j) { + int increment_by = MAX_CHILDREN; + if (remainder != 0) { + // if need be, omit some nodes to make up for remainder + if (remainder <= MAX_CHILDREN - MIN_CHILDREN) { + increment_by -= remainder; + remainder = 0; + } else { + increment_by = MIN_CHILDREN; + remainder -= MAX_CHILDREN - MIN_CHILDREN; + } + } + Node* node = AllocateNodeAtLevel(level); + node->num_children = 1; + node->children[0] = (*branches)[current_branch]; + + Branch branch; + branch.bounds = (*branches)[current_branch].bounds; + branch.subtree = node; + ++current_branch; + for (int k = 1; k < increment_by && current_branch < branches->size(); + ++k) { + branch.bounds.Union((*branches)[current_branch].bounds); + node->children[k] = (*branches)[current_branch]; + ++node->num_children; + ++current_branch; + } + DCHECK_LT(new_branch_index, current_branch); + (*branches)[new_branch_index] = branch; + ++new_branch_index; + } + } + branches->resize(new_branch_index); + return BuildRecursive(branches, level + 1); +} + +void RTree::Search(const gfx::RectF& query, + std::vector<size_t>* results) const { + if (num_data_elements_ > 0 && query.Intersects(root_.bounds)) + SearchRecursive(root_.subtree, query, results); +} + +void RTree::SearchRecursive(Node* node, + const gfx::RectF& query, + std::vector<size_t>* results) const { + for (uint16_t i = 0; i < node->num_children; ++i) { + if (query.Intersects(node->children[i].bounds)) { + if (node->level == 0) + results->push_back(node->children[i].index); + else + SearchRecursive(node->children[i].subtree, query, results); + } + } +} + +} // namespace cc diff --git a/chromium/cc/base/rtree.h b/chromium/cc/base/rtree.h new file mode 100644 index 00000000000..f765c3534ff --- /dev/null +++ b/chromium/cc/base/rtree.h @@ -0,0 +1,118 @@ +// Copyright (c) 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_BASE_RTREE_H_ +#define CC_BASE_RTREE_H_ + +#include <deque> +#include <vector> + +#include "cc/base/cc_export.h" +#include "ui/gfx/geometry/rect_f.h" + +namespace cc { + +// The following description and most of the implementation is borrowed from +// Skia's SkRTree implementation. +// +// An R-Tree implementation. In short, it is a balanced n-ary tree containing a +// hierarchy of bounding rectangles. +// +// It only supports bulk-loading, i.e. creation from a batch of bounding +// rectangles. This performs a bottom-up bulk load using the STR +// (sort-tile-recursive) algorithm. +// +// Things to do: Experiment with other bulk-load algorithms (in particular the +// Hilbert pack variant, which groups rects by position on the Hilbert curve, is +// probably worth a look). There also exist top-down bulk load variants +// (VAMSplit, TopDownGreedy, etc). +// +// For more details see: +// +// Beckmann, N.; Kriegel, H. P.; Schneider, R.; Seeger, B. (1990). +// "The R*-tree: an efficient and robust access method for points and +// rectangles" +class CC_EXPORT RTree { + public: + RTree(); + ~RTree(); + + template <typename Container, typename Functor> + void Build(const Container& items, const Functor& bounds_getter) { + DCHECK_EQ(0u, num_data_elements_); + + std::vector<Branch> branches; + branches.reserve(items.size()); + + for (size_t i = 0; i < items.size(); i++) { + const gfx::RectF& bounds = bounds_getter(items[i]); + if (bounds.IsEmpty()) + continue; + + branches.push_back(Branch()); + Branch& branch = branches.back(); + branch.bounds = bounds; + branch.index = i; + } + + num_data_elements_ = branches.size(); + if (num_data_elements_ == 1u) { + Node* node = AllocateNodeAtLevel(0); + node->num_children = 1; + node->children[0] = branches[0]; + root_.subtree = node; + root_.bounds = branches[0].bounds; + } else if (num_data_elements_ > 1u) { + root_ = BuildRecursive(&branches, 0); + } + } + + template <typename Container> + void Build(const Container& items) { + Build(items, [](const gfx::RectF& bounds) { return bounds; }); + } + + void Search(const gfx::RectF& query, std::vector<size_t>* results) const; + + private: + // These values were empirically determined to produce reasonable performance + // in most cases. + enum { MIN_CHILDREN = 6, MAX_CHILDREN = 11 }; + + struct Node; + struct Branch { + // When the node level is 0, then the node is a leaf and the branch has a + // valid index pointing to an element in the vector that was used to build + // this rtree. When the level is not 0, it's an internal node and it has a + // valid subtree pointer. + union { + Node* subtree; + size_t index; + }; + gfx::RectF bounds; + }; + + struct Node { + uint16_t num_children; + uint16_t level; + Branch children[MAX_CHILDREN]; + }; + + void SearchRecursive(Node* root, + const gfx::RectF& query, + std::vector<size_t>* results) const; + + // Consumes the input array. + Branch BuildRecursive(std::vector<Branch>* branches, int level); + Node* AllocateNodeAtLevel(int level); + + // This is the count of data elements (rather than total nodes in the tree) + size_t num_data_elements_; + Branch root_; + std::deque<Node> nodes_; +}; + +} // namespace cc + +#endif // CC_BASE_RTREE_H_ diff --git a/chromium/cc/base/rtree_unittest.cc b/chromium/cc/base/rtree_unittest.cc new file mode 100644 index 00000000000..b703a173b8e --- /dev/null +++ b/chromium/cc/base/rtree_unittest.cc @@ -0,0 +1,68 @@ +// 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/base/rtree.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { + +TEST(RTreeTest, NoOverlap) { + std::vector<gfx::RectF> rects; + for (int y = 0; y < 50; ++y) { + for (int x = 0; x < 50; ++x) { + rects.push_back(gfx::RectF(x, y, 1.f, 1.f)); + } + } + + RTree rtree; + rtree.Build(rects); + + std::vector<size_t> results; + rtree.Search(gfx::RectF(0.f, 0.f, 50.f, 50.f), &results); + ASSERT_EQ(2500u, results.size()); + for (size_t i = 0; i < 2500; ++i) { + ASSERT_EQ(results[i], i); + } + + results.clear(); + rtree.Search(gfx::RectF(0.f, 0.f, 50.f, 49.f), &results); + ASSERT_EQ(2450u, results.size()); + for (size_t i = 0; i < 2450; ++i) { + ASSERT_EQ(results[i], i); + } + + results.clear(); + rtree.Search(gfx::RectF(5.2f, 6.3f, 0.1f, 0.2f), &results); + ASSERT_EQ(1u, results.size()); + EXPECT_EQ(6u * 50 + 5u, results[0]); +} + +TEST(RTreeTest, Overlap) { + std::vector<gfx::RectF> rects; + for (int h = 1; h <= 50; ++h) { + for (int w = 1; w <= 50; ++w) { + rects.push_back(gfx::RectF(0, 0, w, h)); + } + } + + RTree rtree; + rtree.Build(rects); + + std::vector<size_t> results; + rtree.Search(gfx::RectF(0.f, 0.f, 1.f, 1.f), &results); + ASSERT_EQ(2500u, results.size()); + for (size_t i = 0; i < 2500; ++i) { + ASSERT_EQ(results[i], i); + } + + results.clear(); + rtree.Search(gfx::RectF(0.f, 49.f, 1.f, 1.f), &results); + ASSERT_EQ(50u, results.size()); + for (size_t i = 0; i < 50; ++i) { + EXPECT_EQ(results[i], 2450u + i); + } +} + +} // namespace cc diff --git a/chromium/cc/base/sidecar_list_container.h b/chromium/cc/base/sidecar_list_container.h deleted file mode 100644 index 5135ab1d7d2..00000000000 --- a/chromium/cc/base/sidecar_list_container.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_BASE_SIDECAR_LIST_CONTAINER_H_ -#define CC_BASE_SIDECAR_LIST_CONTAINER_H_ - -#include "base/logging.h" -#include "cc/base/list_container.h" - -namespace cc { - -// This is a container, based on ListContainer, which allocates space in a -// contiguous block for objects subclassing BaseElementType, as well as an -// additional "sidecar" of opaque type. -// -// It takes a pointer to a function for tearing down sidecar objects, which must -// free any resources held by it as its memory will be deallocated by the -// container afterwards. When an element is constructed, callers are expected to -// immediately construct the sidecar as well (such that the sidecar destroyer -// will run safely and successfully). -// -// TODO(jbroman): It would be nice to be clear about the memory alignment -// constraints here, but that probably requires closer inspection of -// ListContainer first. -template <class BaseElementType> -class SidecarListContainer { - public: - using SidecarDestroyer = void (*)(void* sidecar); - using Iterator = typename ListContainer<BaseElementType>::Iterator; - using ConstIterator = typename ListContainer<BaseElementType>::ConstIterator; - using ReverseIterator = - typename ListContainer<BaseElementType>::ReverseIterator; - using ConstReverseIterator = - typename ListContainer<BaseElementType>::ConstReverseIterator; - - explicit SidecarListContainer(size_t max_size_for_derived_class, - size_t max_size_for_sidecar, - size_t num_of_elements_to_reserve_for, - SidecarDestroyer destroyer) - : list_(max_size_for_derived_class + max_size_for_sidecar, - num_of_elements_to_reserve_for), - destroyer_(destroyer), - sidecar_offset_(max_size_for_derived_class) {} - ~SidecarListContainer() { DestroyAllSidecars(); } - - // Forward most of the reading logic to ListContainer. - bool empty() const { return list_.empty(); } - size_t size() const { return list_.size(); } - size_t GetCapacityInBytes() const { return list_.GetCapacityInBytes(); } - ConstIterator begin() const { return list_.begin(); } - ConstIterator end() const { return list_.end(); } - - template <typename DerivedElementType> - DerivedElementType* AllocateAndConstruct() { - return list_.template AllocateAndConstruct<DerivedElementType>(); - } - template <typename DerivedElementType> - DerivedElementType* AllocateAndCopyFrom(const DerivedElementType* source) { - return list_.template AllocateAndCopyFrom<DerivedElementType>(source); - } - - void clear() { - DestroyAllSidecars(); - list_.clear(); - } - - void RemoveLast() { - destroyer_(GetSidecar(*list_.rbegin())); - list_.RemoveLast(); - } - - // This permits a client to exchange a pointer to an element to a pointer to - // its corresponding sidecar. - void* GetSidecar(BaseElementType* element) { - DCHECK_GT(sidecar_offset_, 0u); - return reinterpret_cast<char*>(element) + sidecar_offset_; - } - const void* GetSidecar(const BaseElementType* element) { - DCHECK_GT(sidecar_offset_, 0u); - return reinterpret_cast<const char*>(element) + sidecar_offset_; - } - - private: - void DestroyAllSidecars() { - for (auto* element : list_) - destroyer_(GetSidecar(element)); - } - - ListContainer<BaseElementType> list_; - SidecarDestroyer destroyer_; - size_t sidecar_offset_; -}; - -} // namespace cc - -#endif // CC_BASE_SIDECAR_LIST_CONTAINER_H_ diff --git a/chromium/cc/base/sidecar_list_container_unittest.cc b/chromium/cc/base/sidecar_list_container_unittest.cc deleted file mode 100644 index 0012014df8f..00000000000 --- a/chromium/cc/base/sidecar_list_container_unittest.cc +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/base/sidecar_list_container.h" - -#include <algorithm> - -#include "base/logging.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace cc { -namespace { - -const size_t kNumInitiallyReservedElements = 2; -const size_t kNumElementsForTest = 100; - -class DestructionNotifier { - public: - DestructionNotifier() : flag_(nullptr) {} - explicit DestructionNotifier(bool* flag) { set_flag(flag); } - ~DestructionNotifier() { - if (flag_) - *flag_ = true; - } - void set_flag(bool* flag) { - if (flag) - DCHECK(!*flag); - flag_ = flag; - } - - private: - bool* flag_; -}; - -class TestElement { - public: - TestElement() {} - virtual ~TestElement() {} - void set_destruction_flag(bool* flag) { notifier_.set_flag(flag); } - - private: - DestructionNotifier notifier_; -}; - -class DerivedTestElement : public TestElement { - public: - int additional_field = 0; -}; - -class TestSidecar { - public: - TestSidecar() {} - explicit TestSidecar(bool* destruction_flag) : notifier_(destruction_flag) {} - - static void Destroy(void* sidecar) { - static_cast<TestSidecar*>(sidecar)->~TestSidecar(); - } - - protected: - virtual ~TestSidecar() {} - - private: - DestructionNotifier notifier_; -}; - -class DerivedTestSidecar : public TestSidecar { - public: - DerivedTestSidecar() {} - explicit DerivedTestSidecar(bool* destruction_flag) - : TestSidecar(destruction_flag) {} - int additional_field = 0; - - private: - ~DerivedTestSidecar() override {} -}; - -class TestContainer : public SidecarListContainer<TestElement> { - public: - TestContainer() - : SidecarListContainer( - std::max(sizeof(TestElement), sizeof(DerivedTestElement)), - std::max(sizeof(TestSidecar), sizeof(DerivedTestSidecar)), - kNumInitiallyReservedElements, - &TestSidecar::Destroy) {} -}; - -TEST(SidecarListContainerTest, Destructor) { - bool element_destroyed = false; - bool sidecar_destroyed = false; - - { - TestContainer container; - - TestElement* element = container.AllocateAndConstruct<TestElement>(); - TestSidecar* sidecar = - new (container.GetSidecar(element)) TestSidecar(&sidecar_destroyed); - element->set_destruction_flag(&element_destroyed); - - // They shouldn't be destroyed yet. And they shouldn't overlap in memory. - ASSERT_FALSE(element_destroyed); - ASSERT_FALSE(sidecar_destroyed); - ASSERT_GE(reinterpret_cast<char*>(sidecar), - reinterpret_cast<char*>(element) + sizeof(TestElement)); - } - - // They should, however, be destroyed when going out of scope. - ASSERT_TRUE(element_destroyed); - ASSERT_TRUE(sidecar_destroyed); -} - -TEST(SidecarListContainerTest, Clear) { - bool element_destroyed = false; - bool sidecar_destroyed = false; - - TestContainer container; - - TestElement* element = container.AllocateAndConstruct<TestElement>(); - new (container.GetSidecar(element)) TestSidecar(&sidecar_destroyed); - element->set_destruction_flag(&element_destroyed); - - // They shouldn't be destroyed yet. - ASSERT_FALSE(element_destroyed); - ASSERT_FALSE(sidecar_destroyed); - - // They should, however, be destroyed after clearing. - container.clear(); - EXPECT_TRUE(element_destroyed); - EXPECT_TRUE(sidecar_destroyed); -} - -TEST(SidecarListContainerTest, DerivedTypes) { - bool element_destroyed = false; - bool sidecar_destroyed = false; - - { - TestContainer container; - - DerivedTestElement* element = - container.AllocateAndConstruct<DerivedTestElement>(); - DerivedTestSidecar* sidecar = new (container.GetSidecar(element)) - DerivedTestSidecar(&sidecar_destroyed); - element->set_destruction_flag(&element_destroyed); - element->additional_field = 12; - sidecar->additional_field = 13; - - // They shouldn't be destroyed yet. - ASSERT_FALSE(element_destroyed); - ASSERT_FALSE(sidecar_destroyed); - } - - // They should, however, be destroyed when going out of scope. - EXPECT_TRUE(element_destroyed); - EXPECT_TRUE(sidecar_destroyed); -} - -TEST(SidecarListContainerTest, AddingAndRemovingElements) { - TestContainer container; - EXPECT_TRUE(container.empty()); - EXPECT_EQ(0u, container.size()); - EXPECT_EQ(container.end(), container.begin()); - - for (size_t i = 1; i <= kNumElementsForTest; i++) { - TestElement* element = container.AllocateAndConstruct<TestElement>(); - new (container.GetSidecar(element)) TestSidecar(); - - ASSERT_FALSE(container.empty()); - ASSERT_EQ(i, container.size()); - ASSERT_NE(container.end(), container.begin()); - } - - size_t num_elements = 0; - for (const auto* element : container) { - (void)element; - num_elements++; - } - EXPECT_EQ(kNumElementsForTest, num_elements); - - container.clear(); - EXPECT_TRUE(container.empty()); - EXPECT_EQ(0u, container.size()); - EXPECT_EQ(container.end(), container.begin()); -} - -TEST(SidecarListContainerTest, RemoveLast) { - // We need only ensure that the sidecar is also destroyed on RemoveLast. - // The rest is logic already present in ListContainer. - bool sidecar_destroyed = false; - TestContainer container; - TestElement* element = container.AllocateAndConstruct<TestElement>(); - new (container.GetSidecar(element)) TestSidecar(&sidecar_destroyed); - ASSERT_FALSE(sidecar_destroyed); - container.RemoveLast(); - ASSERT_TRUE(sidecar_destroyed); -} - -} // namespace -} // namespace cc diff --git a/chromium/cc/base/switches.cc b/chromium/cc/base/switches.cc index 0a27205d9d3..0db15030d5b 100644 --- a/chromium/cc/base/switches.cc +++ b/chromium/cc/base/switches.cc @@ -35,18 +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"; - -// Causes the compositor to render to textures which are then sent to the parent -// through the texture mailbox mechanism. -// Requires --enable-compositor-frame-message. -const char kCompositeToMailbox[] = "composite-to-mailbox"; - // Check that property changes during paint do not occur. const char kStrictLayerPropertyChangeChecking[] = "strict-layer-property-change-checking"; diff --git a/chromium/cc/base/switches.h b/chromium/cc/base/switches.h index cd5e3678824..3bce14e892e 100644 --- a/chromium/cc/base/switches.h +++ b/chromium/cc/base/switches.h @@ -24,9 +24,6 @@ CC_EXPORT extern const char kJankInsteadOfCheckerboard[]; 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 kStrictLayerPropertyChangeChecking[]; CC_EXPORT extern const char kEnablePropertyTreeVerification[]; diff --git a/chromium/cc/blink/BUILD.gn b/chromium/cc/blink/BUILD.gn index c39498fe73a..4ee8862a9ae 100644 --- a/chromium/cc/blink/BUILD.gn +++ b/chromium/cc/blink/BUILD.gn @@ -43,8 +43,6 @@ component("blink") { "web_layer_impl.h", "web_layer_impl_fixed_bounds.cc", "web_layer_impl_fixed_bounds.h", - "web_nine_patch_layer_impl.cc", - "web_nine_patch_layer_impl.h", "web_scroll_offset_animation_curve_impl.cc", "web_scroll_offset_animation_curve_impl.h", "web_scrollbar_layer_impl.cc", diff --git a/chromium/cc/blink/cc_blink.gyp b/chromium/cc/blink/cc_blink.gyp index c55213c5444..dc01cae456a 100644 --- a/chromium/cc/blink/cc_blink.gyp +++ b/chromium/cc/blink/cc_blink.gyp @@ -59,8 +59,6 @@ 'web_layer_impl.h', 'web_layer_impl_fixed_bounds.cc', 'web_layer_impl_fixed_bounds.h', - 'web_nine_patch_layer_impl.cc', - 'web_nine_patch_layer_impl.h', 'web_scroll_offset_animation_curve_impl.cc', 'web_scroll_offset_animation_curve_impl.h', 'web_scrollbar_layer_impl.cc', diff --git a/chromium/cc/blink/web_animation_impl.h b/chromium/cc/blink/web_animation_impl.h index 585df6a827a..c1bdb0efdfa 100644 --- a/chromium/cc/blink/web_animation_impl.h +++ b/chromium/cc/blink/web_animation_impl.h @@ -26,26 +26,26 @@ class WebCompositorAnimationImpl : public blink::WebCompositorAnimation { TargetProperty target, int animation_id, int group_id); - virtual ~WebCompositorAnimationImpl(); + ~WebCompositorAnimationImpl() override; // blink::WebCompositorAnimation implementation - virtual int id(); - virtual int group(); - virtual TargetProperty targetProperty() const; - virtual double iterations() const; - virtual void setIterations(double iterations); - virtual double iterationStart() const; - virtual void setIterationStart(double iteration_start); - virtual double startTime() const; - virtual void setStartTime(double monotonic_time); - virtual double timeOffset() const; - virtual void setTimeOffset(double monotonic_time); - virtual Direction direction() const; - virtual void setDirection(Direction); - virtual double playbackRate() const; - virtual void setPlaybackRate(double playback_rate); - virtual FillMode fillMode() const; - virtual void setFillMode(blink::WebCompositorAnimation::FillMode fill_mode); + int id() override; + int group() override; + TargetProperty targetProperty() const override; + double iterations() const override; + void setIterations(double iterations) override; + double iterationStart() const override; + void setIterationStart(double iteration_start) override; + double startTime() const override; + void setStartTime(double monotonic_time) override; + double timeOffset() const override; + void setTimeOffset(double monotonic_time) override; + Direction direction() const override; + void setDirection(Direction) override; + double playbackRate() const override; + void setPlaybackRate(double playback_rate) override; + FillMode fillMode() const override; + void setFillMode(blink::WebCompositorAnimation::FillMode fill_mode) override; scoped_ptr<cc::Animation> PassAnimation(); private: diff --git a/chromium/cc/blink/web_compositor_animation_player_impl.h b/chromium/cc/blink/web_compositor_animation_player_impl.h index 9b5ea4475e7..1d4879b45a4 100644 --- a/chromium/cc/blink/web_compositor_animation_player_impl.h +++ b/chromium/cc/blink/web_compositor_animation_player_impl.h @@ -22,19 +22,19 @@ class WebCompositorAnimationPlayerImpl : public blink::WebCompositorAnimationPlayer { public: CC_BLINK_EXPORT WebCompositorAnimationPlayerImpl(); - virtual ~WebCompositorAnimationPlayerImpl(); + ~WebCompositorAnimationPlayerImpl() override; CC_BLINK_EXPORT cc::AnimationPlayer* animation_player() const; // blink::WebCompositorAnimationPlayer implementation - virtual void setAnimationDelegate( - blink::WebCompositorAnimationDelegate* delegate); - virtual void attachLayer(blink::WebLayer* web_layer); - virtual void detachLayer(); - virtual bool isLayerAttached() const; - virtual void addAnimation(blink::WebCompositorAnimation* animation); - virtual void removeAnimation(int animation_id); - virtual void pauseAnimation(int animation_id, double time_offset); + void setAnimationDelegate( + blink::WebCompositorAnimationDelegate* delegate) override; + void attachLayer(blink::WebLayer* web_layer) override; + void detachLayer() override; + bool isLayerAttached() const override; + void addAnimation(blink::WebCompositorAnimation* animation) override; + void removeAnimation(int animation_id) override; + void pauseAnimation(int animation_id, double time_offset) override; private: scoped_refptr<cc::AnimationPlayer> animation_player_; diff --git a/chromium/cc/blink/web_compositor_animation_timeline_impl.h b/chromium/cc/blink/web_compositor_animation_timeline_impl.h index 65d05d83157..624d29fcec7 100644 --- a/chromium/cc/blink/web_compositor_animation_timeline_impl.h +++ b/chromium/cc/blink/web_compositor_animation_timeline_impl.h @@ -24,15 +24,15 @@ class WebCompositorAnimationTimelineImpl : public blink::WebCompositorAnimationTimeline { public: CC_BLINK_EXPORT explicit WebCompositorAnimationTimelineImpl(); - virtual ~WebCompositorAnimationTimelineImpl(); + ~WebCompositorAnimationTimelineImpl() override; CC_BLINK_EXPORT cc::AnimationTimeline* animation_timeline() const; // blink::WebCompositorAnimationTimeline implementation - virtual void playerAttached( - const blink::WebCompositorAnimationPlayerClient& client); - virtual void playerDestroyed( - const blink::WebCompositorAnimationPlayerClient& client); + void playerAttached( + const blink::WebCompositorAnimationPlayerClient& client) override; + void playerDestroyed( + const blink::WebCompositorAnimationPlayerClient& client) override; private: scoped_refptr<cc::AnimationTimeline> animation_timeline_; diff --git a/chromium/cc/blink/web_compositor_support_impl.cc b/chromium/cc/blink/web_compositor_support_impl.cc index 13a868d7ebf..74c5491d7db 100644 --- a/chromium/cc/blink/web_compositor_support_impl.cc +++ b/chromium/cc/blink/web_compositor_support_impl.cc @@ -17,7 +17,6 @@ #include "cc/blink/web_float_animation_curve_impl.h" #include "cc/blink/web_image_layer_impl.h" #include "cc/blink/web_layer_impl.h" -#include "cc/blink/web_nine_patch_layer_impl.h" #include "cc/blink/web_scroll_offset_animation_curve_impl.h" #include "cc/blink/web_scrollbar_layer_impl.h" #include "cc/blink/web_transform_animation_curve_impl.h" @@ -38,7 +37,6 @@ using blink::WebFilterAnimationCurve; using blink::WebFilterOperations; using blink::WebFloatAnimationCurve; using blink::WebImageLayer; -using blink::WebNinePatchLayer; using blink::WebLayer; using blink::WebScrollbar; using blink::WebScrollbarLayer; @@ -74,10 +72,6 @@ blink::WebImageLayer* WebCompositorSupportImpl::createImageLayer() { return new WebImageLayerImpl(); } -blink::WebNinePatchLayer* WebCompositorSupportImpl::createNinePatchLayer() { - return new WebNinePatchLayerImpl(); -} - WebScrollbarLayer* WebCompositorSupportImpl::createScrollbarLayer( WebScrollbar* scrollbar, WebScrollbarThemePainter painter, @@ -133,10 +127,6 @@ WebFilterOperations* WebCompositorSupportImpl::createFilterOperations() { return new WebFilterOperationsImpl(); } -WebDisplayItemList* WebCompositorSupportImpl::createDisplayItemList() { - return new WebDisplayItemListImpl(); -} - WebCompositorAnimationPlayer* WebCompositorSupportImpl::createAnimationPlayer() { return new WebCompositorAnimationPlayerImpl(); diff --git a/chromium/cc/blink/web_compositor_support_impl.h b/chromium/cc/blink/web_compositor_support_impl.h index 989966989e6..0547a1492aa 100644 --- a/chromium/cc/blink/web_compositor_support_impl.h +++ b/chromium/cc/blink/web_compositor_support_impl.h @@ -23,43 +23,40 @@ class CC_BLINK_EXPORT WebCompositorSupportImpl : public NON_EXPORTED_BASE(blink::WebCompositorSupport) { public: WebCompositorSupportImpl(); - virtual ~WebCompositorSupportImpl(); + ~WebCompositorSupportImpl() override; - virtual blink::WebLayer* createLayer(); - virtual blink::WebContentLayer* createContentLayer( - blink::WebContentLayerClient* client); - virtual blink::WebExternalTextureLayer* createExternalTextureLayer( - blink::WebExternalTextureLayerClient* client); - virtual blink::WebImageLayer* createImageLayer(); - virtual blink::WebNinePatchLayer* createNinePatchLayer(); - virtual blink::WebScrollbarLayer* createScrollbarLayer( + blink::WebLayer* createLayer() override; + blink::WebContentLayer* createContentLayer( + blink::WebContentLayerClient* client) override; + blink::WebExternalTextureLayer* createExternalTextureLayer( + blink::WebExternalTextureLayerClient* client) override; + blink::WebImageLayer* createImageLayer() override; + blink::WebScrollbarLayer* createScrollbarLayer( blink::WebScrollbar* scrollbar, blink::WebScrollbarThemePainter painter, - blink::WebScrollbarThemeGeometry*); - virtual blink::WebScrollbarLayer* createSolidColorScrollbarLayer( + blink::WebScrollbarThemeGeometry*) override; + blink::WebScrollbarLayer* createSolidColorScrollbarLayer( blink::WebScrollbar::Orientation orientation, int thumb_thickness, int track_start, - bool is_left_side_vertical_scrollbar); - virtual blink::WebCompositorAnimation* createAnimation( + bool is_left_side_vertical_scrollbar) override; + blink::WebCompositorAnimation* createAnimation( const blink::WebCompositorAnimationCurve& curve, blink::WebCompositorAnimation::TargetProperty target, int group_id, - int animation_id); - virtual blink::WebFilterAnimationCurve* createFilterAnimationCurve(); - virtual blink::WebFloatAnimationCurve* createFloatAnimationCurve(); - virtual blink::WebScrollOffsetAnimationCurve* - createScrollOffsetAnimationCurve( - blink::WebFloatPoint target_value, - blink::WebCompositorAnimationCurve::TimingFunctionType - timing_function); - virtual blink::WebTransformAnimationCurve* createTransformAnimationCurve(); - virtual blink::WebTransformOperations* createTransformOperations(); - virtual blink::WebFilterOperations* createFilterOperations(); - virtual blink::WebDisplayItemList* createDisplayItemList(); + int animation_id) override; + blink::WebFilterAnimationCurve* createFilterAnimationCurve() override; + blink::WebFloatAnimationCurve* createFloatAnimationCurve() override; + blink::WebScrollOffsetAnimationCurve* createScrollOffsetAnimationCurve( + blink::WebFloatPoint target_value, + blink::WebCompositorAnimationCurve::TimingFunctionType timing_function) + override; + blink::WebTransformAnimationCurve* createTransformAnimationCurve() override; + blink::WebTransformOperations* createTransformOperations() override; + blink::WebFilterOperations* createFilterOperations() override; - virtual blink::WebCompositorAnimationPlayer* createAnimationPlayer(); - virtual blink::WebCompositorAnimationTimeline* createAnimationTimeline(); + blink::WebCompositorAnimationPlayer* createAnimationPlayer() override; + blink::WebCompositorAnimationTimeline* createAnimationTimeline() override; private: DISALLOW_COPY_AND_ASSIGN(WebCompositorSupportImpl); diff --git a/chromium/cc/blink/web_content_layer_impl.cc b/chromium/cc/blink/web_content_layer_impl.cc index c9ca473cf8e..4ccd7639086 100644 --- a/chromium/cc/blink/web_content_layer_impl.cc +++ b/chromium/cc/blink/web_content_layer_impl.cc @@ -54,10 +54,6 @@ void WebContentLayerImpl::setDoubleSided(bool double_sided) { layer_->layer()->SetDoubleSided(double_sided); } -void WebContentLayerImpl::setDrawCheckerboardForMissingTiles(bool enable) { - layer_->layer()->SetDrawCheckerboardForMissingTiles(enable); -} - void WebContentLayerImpl::PaintContents( SkCanvas* canvas, const gfx::Rect& clip, @@ -89,4 +85,8 @@ bool WebContentLayerImpl::FillsBoundsCompletely() const { return false; } +size_t WebContentLayerImpl::GetApproximateUnsharedMemoryUsage() const { + return client_->approximateUnsharedMemoryUsage(); +} + } // namespace cc_blink diff --git a/chromium/cc/blink/web_content_layer_impl.h b/chromium/cc/blink/web_content_layer_impl.h index 3e7b55c59a4..fb0fcb77732 100644 --- a/chromium/cc/blink/web_content_layer_impl.h +++ b/chromium/cc/blink/web_content_layer_impl.h @@ -28,12 +28,11 @@ class WebContentLayerImpl : public blink::WebContentLayer, CC_BLINK_EXPORT explicit WebContentLayerImpl(blink::WebContentLayerClient*); // WebContentLayer implementation. - virtual blink::WebLayer* layer(); - virtual void setDoubleSided(bool double_sided); - virtual void setDrawCheckerboardForMissingTiles(bool checkerboard); + blink::WebLayer* layer() override; + void setDoubleSided(bool double_sided) override; protected: - virtual ~WebContentLayerImpl(); + ~WebContentLayerImpl() override; // ContentLayerClient implementation. void PaintContents(SkCanvas* canvas, @@ -43,6 +42,7 @@ class WebContentLayerImpl : public blink::WebContentLayer, const gfx::Rect& clip, PaintingControlSetting painting_control) override; bool FillsBoundsCompletely() const override; + size_t GetApproximateUnsharedMemoryUsage() const override; scoped_ptr<WebLayerImpl> layer_; blink::WebContentLayerClient* client_; diff --git a/chromium/cc/blink/web_display_item_list_impl.cc b/chromium/cc/blink/web_display_item_list_impl.cc index ffcd5e35df7..79d0972299e 100644 --- a/chromium/cc/blink/web_display_item_list_impl.cc +++ b/chromium/cc/blink/web_display_item_list_impl.cc @@ -31,7 +31,8 @@ namespace { scoped_refptr<cc::DisplayItemList> CreateUncachedDisplayItemListForBlink() { cc::DisplayItemListSettings settings; settings.use_cached_picture = false; - return cc::DisplayItemList::CreateWithoutCachedPicture(settings); + gfx::Rect layer_rect; + return cc::DisplayItemList::Create(layer_rect, settings); } } // namespace diff --git a/chromium/cc/blink/web_display_item_list_impl.h b/chromium/cc/blink/web_display_item_list_impl.h index d45d7d36d48..438bee0ded3 100644 --- a/chromium/cc/blink/web_display_item_list_impl.h +++ b/chromium/cc/blink/web_display_item_list_impl.h @@ -38,33 +38,33 @@ class WebDisplayItemListImpl : public blink::WebDisplayItemList { CC_BLINK_EXPORT WebDisplayItemListImpl(); CC_BLINK_EXPORT explicit WebDisplayItemListImpl( cc::DisplayItemList* display_list); - virtual ~WebDisplayItemListImpl(); + ~WebDisplayItemListImpl() override; // blink::WebDisplayItemList implementation. - virtual void appendDrawingItem(const SkPicture*); - virtual void appendClipItem( + void appendDrawingItem(const SkPicture*) override; + 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(); + const blink::WebVector<SkRRect>& rounded_clip_rects) override; + void appendEndClipItem() override; + void appendClipPathItem(const SkPath& clip_path, + SkRegion::Op clip_op, + bool antialias) override; + void appendEndClipPathItem() override; + void appendFloatClipItem(const blink::WebFloatRect& clip_rect) override; + void appendEndFloatClipItem() override; + void appendTransformItem(const SkMatrix44& matrix) override; + void appendEndTransformItem() override; + void appendCompositingItem(float opacity, + SkXfermode::Mode, + SkRect* bounds, + SkColorFilter*) override; + void appendEndCompositingItem() override; + void appendFilterItem(const blink::WebFilterOperations& filters, + const blink::WebFloatRect& bounds) override; + void appendEndFilterItem() override; + void appendScrollItem(const blink::WebSize& scrollOffset, + ScrollContainerId) override; + void appendEndScrollItem() override; private: scoped_refptr<cc::DisplayItemList> display_item_list_; diff --git a/chromium/cc/blink/web_external_bitmap_impl.cc b/chromium/cc/blink/web_external_bitmap_impl.cc index e2c67e42996..2301896027b 100644 --- a/chromium/cc/blink/web_external_bitmap_impl.cc +++ b/chromium/cc/blink/web_external_bitmap_impl.cc @@ -37,6 +37,13 @@ blink::WebSize WebExternalBitmapImpl::size() { } uint8* WebExternalBitmapImpl::pixels() { + if (!shared_bitmap_) { + // crbug.com/520417: not sure why a non-null WebExternalBitmap is + // being passed to prepareMailbox when the shared_bitmap_ is null. + // Best hypothesis is that the bitmap is zero-sized. + DCHECK(size_.isEmpty()); + return nullptr; + } return shared_bitmap_->pixels(); } diff --git a/chromium/cc/blink/web_external_texture_layer_impl.cc b/chromium/cc/blink/web_external_texture_layer_impl.cc index e9700c6c6d9..acc7df44e63 100644 --- a/chromium/cc/blink/web_external_texture_layer_impl.cc +++ b/chromium/cc/blink/web_external_texture_layer_impl.cc @@ -57,10 +57,6 @@ void WebExternalTextureLayerImpl::setBlendBackgroundColor(bool blend) { static_cast<TextureLayer*>(layer_->layer())->SetBlendBackgroundColor(blend); } -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); diff --git a/chromium/cc/blink/web_external_texture_layer_impl.h b/chromium/cc/blink/web_external_texture_layer_impl.h index a12a00b8e37..5425ae53413 100644 --- a/chromium/cc/blink/web_external_texture_layer_impl.h +++ b/chromium/cc/blink/web_external_texture_layer_impl.h @@ -35,16 +35,15 @@ class WebExternalTextureLayerImpl public: CC_BLINK_EXPORT explicit WebExternalTextureLayerImpl( blink::WebExternalTextureLayerClient*); - virtual ~WebExternalTextureLayerImpl(); + ~WebExternalTextureLayerImpl() override; // blink::WebExternalTextureLayer implementation. - virtual blink::WebLayer* layer(); - virtual void clearTexture(); - virtual void setOpaque(bool opaque); - virtual void setPremultipliedAlpha(bool premultiplied); - virtual void setBlendBackgroundColor(bool blend); - virtual void setRateLimitContext(bool rate_limit); - virtual void setNearestNeighbor(bool nearest_neighbor); + blink::WebLayer* layer() override; + void clearTexture() override; + void setOpaque(bool opaque) override; + void setPremultipliedAlpha(bool premultiplied) override; + void setBlendBackgroundColor(bool blend) override; + void setNearestNeighbor(bool nearest_neighbor) override; // TextureLayerClient implementation. bool PrepareTextureMailbox( diff --git a/chromium/cc/blink/web_filter_animation_curve_impl.h b/chromium/cc/blink/web_filter_animation_curve_impl.h index 93dae4ed052..e922ccbde22 100644 --- a/chromium/cc/blink/web_filter_animation_curve_impl.h +++ b/chromium/cc/blink/web_filter_animation_curve_impl.h @@ -23,30 +23,30 @@ namespace cc_blink { class WebFilterAnimationCurveImpl : public blink::WebFilterAnimationCurve { public: CC_BLINK_EXPORT WebFilterAnimationCurveImpl(); - virtual ~WebFilterAnimationCurveImpl(); + ~WebFilterAnimationCurveImpl() override; // blink::WebCompositorAnimationCurve implementation. - virtual AnimationCurveType type() const; + AnimationCurveType type() const override; // blink::WebFilterAnimationCurve implementation. - virtual void add(const blink::WebFilterKeyframe& keyframe, - TimingFunctionType type); - virtual void add(const blink::WebFilterKeyframe& keyframe, - 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); + void add(const blink::WebFilterKeyframe& keyframe, + TimingFunctionType type) override; + void add(const blink::WebFilterKeyframe& keyframe, + double x1, + double y1, + double x2, + double y2) override; + void add(const blink::WebFilterKeyframe& keyframe, + int steps, + float steps_start_offset) override; + void setLinearTimingFunction() override; + void setCubicBezierTimingFunction(TimingFunctionType) override; + void setCubicBezierTimingFunction(double x1, + double y1, + double x2, + double y2) override; + void setStepsTimingFunction(int number_of_steps, + float steps_start_offset) override; scoped_ptr<cc::AnimationCurve> CloneToAnimationCurve() const; diff --git a/chromium/cc/blink/web_filter_operations_impl.h b/chromium/cc/blink/web_filter_operations_impl.h index 36c3b4565cf..d1746cea9af 100644 --- a/chromium/cc/blink/web_filter_operations_impl.h +++ b/chromium/cc/blink/web_filter_operations_impl.h @@ -14,30 +14,30 @@ namespace cc_blink { class WebFilterOperationsImpl : public blink::WebFilterOperations { public: CC_BLINK_EXPORT WebFilterOperationsImpl(); - virtual ~WebFilterOperationsImpl(); + ~WebFilterOperationsImpl() override; const cc::FilterOperations& AsFilterOperations() const; // Implementation of blink::WebFilterOperations methods - virtual void appendGrayscaleFilter(float amount); - virtual void appendSepiaFilter(float amount); - virtual void appendSaturateFilter(float amount); - virtual void appendHueRotateFilter(float amount); - virtual void appendInvertFilter(float amount); - virtual void appendBrightnessFilter(float amount); - virtual void appendContrastFilter(float amount); - virtual void appendOpacityFilter(float amount); - virtual void appendBlurFilter(float amount); - virtual void appendDropShadowFilter(blink::WebPoint offset, - float std_deviation, - blink::WebColor color); - virtual void appendColorMatrixFilter(SkScalar matrix[20]); - virtual void appendZoomFilter(float amount, int inset); - virtual void appendSaturatingBrightnessFilter(float amount); - virtual void appendReferenceFilter(SkImageFilter* image_filter); - - virtual void clear(); - virtual bool isEmpty() const; + void appendGrayscaleFilter(float amount) override; + void appendSepiaFilter(float amount) override; + void appendSaturateFilter(float amount) override; + void appendHueRotateFilter(float amount) override; + void appendInvertFilter(float amount) override; + void appendBrightnessFilter(float amount) override; + void appendContrastFilter(float amount) override; + void appendOpacityFilter(float amount) override; + void appendBlurFilter(float amount) override; + void appendDropShadowFilter(blink::WebPoint offset, + float std_deviation, + blink::WebColor color) override; + void appendColorMatrixFilter(SkScalar matrix[20]) override; + void appendZoomFilter(float amount, int inset) override; + void appendSaturatingBrightnessFilter(float amount) override; + void appendReferenceFilter(SkImageFilter* image_filter) override; + + void clear() override; + bool isEmpty() const override; private: cc::FilterOperations filter_operations_; diff --git a/chromium/cc/blink/web_float_animation_curve_impl.h b/chromium/cc/blink/web_float_animation_curve_impl.h index b5a97aa5db6..42bab59f82b 100644 --- a/chromium/cc/blink/web_float_animation_curve_impl.h +++ b/chromium/cc/blink/web_float_animation_curve_impl.h @@ -23,33 +23,33 @@ namespace cc_blink { class WebFloatAnimationCurveImpl : public blink::WebFloatAnimationCurve { public: CC_BLINK_EXPORT WebFloatAnimationCurveImpl(); - virtual ~WebFloatAnimationCurveImpl(); + ~WebFloatAnimationCurveImpl() override; // WebCompositorAnimationCurve implementation. - virtual AnimationCurveType type() const; + AnimationCurveType type() const override; // WebFloatAnimationCurve implementation. - virtual void add(const blink::WebFloatKeyframe& keyframe); - virtual void add(const blink::WebFloatKeyframe& keyframe, - TimingFunctionType type); - virtual void add(const blink::WebFloatKeyframe& keyframe, - 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); + void add(const blink::WebFloatKeyframe& keyframe) override; + void add(const blink::WebFloatKeyframe& keyframe, + TimingFunctionType type) override; + void add(const blink::WebFloatKeyframe& keyframe, + double x1, + double y1, + double x2, + double y2) override; + void add(const blink::WebFloatKeyframe& keyframe, + int steps, + float steps_start_offset) override; + void setLinearTimingFunction() override; + void setCubicBezierTimingFunction(TimingFunctionType) override; + void setCubicBezierTimingFunction(double x1, + double y1, + double x2, + double y2) override; + void setStepsTimingFunction(int number_of_steps, + float steps_start_offset) override; - virtual float getValue(double time) const; + float getValue(double time) const override; scoped_ptr<cc::AnimationCurve> CloneToAnimationCurve() const; diff --git a/chromium/cc/blink/web_image_layer_impl.cc b/chromium/cc/blink/web_image_layer_impl.cc index 55e28ef8152..efa4242b59e 100644 --- a/chromium/cc/blink/web_image_layer_impl.cc +++ b/chromium/cc/blink/web_image_layer_impl.cc @@ -7,6 +7,7 @@ #include "cc/blink/web_layer_impl.h" #include "cc/blink/web_layer_impl_fixed_bounds.h" #include "cc/layers/picture_image_layer.h" +#include "third_party/skia/include/core/SkImage.h" namespace cc_blink { @@ -22,10 +23,12 @@ blink::WebLayer* WebImageLayerImpl::layer() { return layer_.get(); } -void WebImageLayerImpl::setImageBitmap(const SkBitmap& bitmap) { - static_cast<cc::PictureImageLayer*>(layer_->layer())->SetBitmap(bitmap); +void WebImageLayerImpl::setImage(const SkImage* image) { + skia::RefPtr<const SkImage> imageRef = skia::SharePtr(image); + static_cast<cc::PictureImageLayer*>(layer_->layer()) + ->SetImage(imageRef.Pass()); static_cast<WebLayerImplFixedBounds*>(layer_.get()) - ->SetFixedBounds(gfx::Size(bitmap.width(), bitmap.height())); + ->SetFixedBounds(gfx::Size(image->width(), image->height())); } void WebImageLayerImpl::setNearestNeighbor(bool nearest_neighbor) { diff --git a/chromium/cc/blink/web_image_layer_impl.h b/chromium/cc/blink/web_image_layer_impl.h index 48c31ea80c7..74a8e76b5b1 100644 --- a/chromium/cc/blink/web_image_layer_impl.h +++ b/chromium/cc/blink/web_image_layer_impl.h @@ -8,7 +8,6 @@ #include "base/memory/scoped_ptr.h" #include "cc/blink/cc_blink_export.h" #include "third_party/WebKit/public/platform/WebImageLayer.h" -#include "third_party/skia/include/core/SkBitmap.h" namespace cc_blink { @@ -17,12 +16,12 @@ class WebLayerImpl; class WebImageLayerImpl : public blink::WebImageLayer { public: CC_BLINK_EXPORT WebImageLayerImpl(); - virtual ~WebImageLayerImpl(); + ~WebImageLayerImpl() override; // blink::WebImageLayer implementation. - virtual blink::WebLayer* layer(); - virtual void setImageBitmap(const SkBitmap& bitmap); - virtual void setNearestNeighbor(bool nearest_neighbor); + blink::WebLayer* layer() override; + void setImage(const SkImage* image) override; + void setNearestNeighbor(bool nearest_neighbor) override; private: scoped_ptr<WebLayerImpl> layer_; diff --git a/chromium/cc/blink/web_layer_impl.cc b/chromium/cc/blink/web_layer_impl.cc index 3ba9431171d..48f27008e98 100644 --- a/chromium/cc/blink/web_layer_impl.cc +++ b/chromium/cc/blink/web_layer_impl.cc @@ -51,18 +51,19 @@ base::LazyInstance<cc::LayerSettings> g_layer_settings = } // namespace -WebLayerImpl::WebLayerImpl() : layer_(Layer::Create(LayerSettings())) { +WebLayerImpl::WebLayerImpl() + : layer_(Layer::Create(LayerSettings())), contents_opaque_is_fixed_(false) { web_layer_client_ = nullptr; layer_->SetLayerClient(this); } -WebLayerImpl::WebLayerImpl(scoped_refptr<Layer> layer) : layer_(layer) { +WebLayerImpl::WebLayerImpl(scoped_refptr<Layer> layer) + : layer_(layer), contents_opaque_is_fixed_(false) { web_layer_client_ = nullptr; layer_->SetLayerClient(this); } WebLayerImpl::~WebLayerImpl() { - layer_->ClearRenderSurface(); if (animation_delegate_adapter_.get()) layer_->set_layer_animation_delegate(nullptr); web_layer_client_ = nullptr; @@ -162,6 +163,8 @@ bool WebLayerImpl::isRootForIsolatedGroup() { } void WebLayerImpl::setOpaque(bool opaque) { + if (contents_opaque_is_fixed_) + return; layer_->SetContentsOpaque(opaque); } @@ -537,4 +540,8 @@ Layer* WebLayerImpl::layer() const { return layer_.get(); } +void WebLayerImpl::SetContentsOpaqueIsFixed(bool fixed) { + contents_opaque_is_fixed_ = fixed; +} + } // namespace cc_blink diff --git a/chromium/cc/blink/web_layer_impl.h b/chromium/cc/blink/web_layer_impl.h index eb049b8e711..44ef02e2210 100644 --- a/chromium/cc/blink/web_layer_impl.h +++ b/chromium/cc/blink/web_layer_impl.h @@ -50,7 +50,7 @@ class WebLayerImpl : public blink::WebLayer, public cc::LayerClient { public: CC_BLINK_EXPORT WebLayerImpl(); CC_BLINK_EXPORT explicit WebLayerImpl(scoped_refptr<cc::Layer>); - virtual ~WebLayerImpl(); + ~WebLayerImpl() override; CC_BLINK_EXPORT static void SetLayerSettings( const cc::LayerSettings& settings); @@ -58,100 +58,108 @@ class WebLayerImpl : public blink::WebLayer, public cc::LayerClient { CC_BLINK_EXPORT cc::Layer* layer() const; + // If set to true, content opaqueness cannot be changed using setOpaque. + // However, it can still be modified using SetContentsOpaque on the + // cc::Layer. + CC_BLINK_EXPORT void SetContentsOpaqueIsFixed(bool fixed); + // WebLayer implementation. - virtual int id() const; - virtual void invalidateRect(const blink::WebRect&); - virtual void invalidate(); - virtual void addChild(blink::WebLayer* child); - virtual void insertChild(blink::WebLayer* child, size_t index); - virtual void replaceChild(blink::WebLayer* reference, - blink::WebLayer* new_layer); - virtual void removeFromParent(); - virtual void removeAllChildren(); - virtual void setBounds(const blink::WebSize& bounds); - virtual blink::WebSize bounds() const; - virtual void setMasksToBounds(bool masks_to_bounds); - virtual bool masksToBounds() const; - virtual void setMaskLayer(blink::WebLayer* mask); - virtual void setReplicaLayer(blink::WebLayer* replica); - virtual void setOpacity(float opacity); - virtual float opacity() const; - virtual void setBlendMode(blink::WebBlendMode blend_mode); - virtual blink::WebBlendMode blendMode() const; - virtual void setIsRootForIsolatedGroup(bool root); - virtual bool isRootForIsolatedGroup(); - virtual void setOpaque(bool opaque); - virtual bool opaque() const; - virtual void setPosition(const blink::WebFloatPoint& position); - virtual blink::WebFloatPoint position() const; - virtual void setTransform(const SkMatrix44& transform); - virtual void setTransformOrigin(const blink::WebFloatPoint3D& point); - virtual blink::WebFloatPoint3D transformOrigin() const; - virtual SkMatrix44 transform() const; - virtual void setDrawsContent(bool draws_content); - virtual bool drawsContent() const; - virtual void setShouldFlattenTransform(bool flatten); - virtual void setRenderingContext(int context); - virtual void setUseParentBackfaceVisibility(bool visible); - virtual void setBackgroundColor(blink::WebColor color); - virtual blink::WebColor backgroundColor() const; - virtual void setFilters(const blink::WebFilterOperations& filters); - virtual void setBackgroundFilters(const blink::WebFilterOperations& filters); - virtual void setAnimationDelegate( - blink::WebCompositorAnimationDelegate* delegate); - virtual bool addAnimation(blink::WebCompositorAnimation* animation); - virtual void removeAnimation(int animation_id); - virtual void removeAnimation(int animation_id, - blink::WebCompositorAnimation::TargetProperty); - virtual void pauseAnimation(int animation_id, double time_offset); - virtual bool hasActiveAnimation(); - 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); - virtual bool userScrollableHorizontal() const; - virtual bool userScrollableVertical() const; - virtual void setHaveWheelEventHandlers(bool have_wheel_event_handlers); - virtual bool haveWheelEventHandlers() const; - virtual void setHaveScrollEventHandlers(bool have_scroll_event_handlers); - virtual bool haveScrollEventHandlers() const; - virtual void setShouldScrollOnMainThread(bool scroll_on_main); - virtual bool shouldScrollOnMainThread() const; - virtual void setNonFastScrollableRegion( - const blink::WebVector<blink::WebRect>& region); - virtual blink::WebVector<blink::WebRect> nonFastScrollableRegion() const; - 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( - const blink::WebLayerPositionConstraint& constraint); - virtual blink::WebLayerPositionConstraint positionConstraint() const; - virtual void setScrollClient(blink::WebLayerScrollClient* client); - virtual bool isOrphan() const; - virtual void setWebLayerClient(blink::WebLayerClient* client); + int id() const override; + void invalidateRect(const blink::WebRect&) override; + void invalidate() override; + void addChild(blink::WebLayer* child) override; + void insertChild(blink::WebLayer* child, size_t index) override; + void replaceChild(blink::WebLayer* reference, + blink::WebLayer* new_layer) override; + void removeFromParent() override; + void removeAllChildren() override; + void setBounds(const blink::WebSize& bounds) override; + blink::WebSize bounds() const override; + void setMasksToBounds(bool masks_to_bounds) override; + bool masksToBounds() const override; + void setMaskLayer(blink::WebLayer* mask) override; + void setReplicaLayer(blink::WebLayer* replica) override; + void setOpacity(float opacity) override; + float opacity() const override; + void setBlendMode(blink::WebBlendMode blend_mode) override; + blink::WebBlendMode blendMode() const override; + void setIsRootForIsolatedGroup(bool root) override; + bool isRootForIsolatedGroup() override; + void setOpaque(bool opaque) override; + bool opaque() const override; + void setPosition(const blink::WebFloatPoint& position) override; + blink::WebFloatPoint position() const override; + void setTransform(const SkMatrix44& transform) override; + void setTransformOrigin(const blink::WebFloatPoint3D& point) override; + blink::WebFloatPoint3D transformOrigin() const override; + SkMatrix44 transform() const override; + void setDrawsContent(bool draws_content) override; + bool drawsContent() const override; + void setShouldFlattenTransform(bool flatten) override; + void setRenderingContext(int context) override; + void setUseParentBackfaceVisibility(bool visible) override; + void setBackgroundColor(blink::WebColor color) override; + blink::WebColor backgroundColor() const override; + void setFilters(const blink::WebFilterOperations& filters) override; + void setBackgroundFilters(const blink::WebFilterOperations& filters) override; + void setAnimationDelegate( + blink::WebCompositorAnimationDelegate* delegate) override; + bool addAnimation(blink::WebCompositorAnimation* animation) override; + void removeAnimation(int animation_id) override; + void removeAnimation(int animation_id, + blink::WebCompositorAnimation::TargetProperty) override; + void pauseAnimation(int animation_id, double time_offset) override; + bool hasActiveAnimation() override; + void setForceRenderSurface(bool force) override; + void setScrollPositionDouble(blink::WebDoublePoint position) override; + blink::WebDoublePoint scrollPositionDouble() const override; + void setScrollCompensationAdjustment(blink::WebDoublePoint position) override; + void setScrollClipLayer(blink::WebLayer* clip_layer) override; + bool scrollable() const override; + void setUserScrollable(bool horizontal, bool vertical) override; + bool userScrollableHorizontal() const override; + bool userScrollableVertical() const override; + void setHaveWheelEventHandlers(bool have_wheel_event_handlers) override; + bool haveWheelEventHandlers() const override; + void setHaveScrollEventHandlers(bool have_scroll_event_handlers) override; + bool haveScrollEventHandlers() const override; + void setShouldScrollOnMainThread(bool scroll_on_main) override; + bool shouldScrollOnMainThread() const override; + void setNonFastScrollableRegion( + const blink::WebVector<blink::WebRect>& region) override; + blink::WebVector<blink::WebRect> nonFastScrollableRegion() const override; + void setTouchEventHandlerRegion( + const blink::WebVector<blink::WebRect>& region) override; + blink::WebVector<blink::WebRect> touchEventHandlerRegion() const override; + void setScrollBlocksOn(blink::WebScrollBlocksOn) override; + blink::WebScrollBlocksOn scrollBlocksOn() const override; + void setFrameTimingRequests( + const blink::WebVector<std::pair<int64_t, blink::WebRect>>& requests) + override; + blink::WebVector<std::pair<int64_t, blink::WebRect>> frameTimingRequests() + const override; + void setIsContainerForFixedPositionLayers(bool is_container) override; + bool isContainerForFixedPositionLayers() const override; + void setPositionConstraint( + const blink::WebLayerPositionConstraint& constraint) override; + blink::WebLayerPositionConstraint positionConstraint() const override; + void setScrollClient(blink::WebLayerScrollClient* client) override; + bool isOrphan() const override; + void setWebLayerClient(blink::WebLayerClient* client) override; // LayerClient implementation. scoped_refptr<base::trace_event::ConvertableToTraceFormat> TakeDebugInfo() override; - virtual void setScrollParent(blink::WebLayer* parent); - virtual void setClipParent(blink::WebLayer* parent); + void setScrollParent(blink::WebLayer* parent) override; + void setClipParent(blink::WebLayer* parent) override; protected: scoped_refptr<cc::Layer> layer_; blink::WebLayerClient* web_layer_client_; + bool contents_opaque_is_fixed_; + private: scoped_ptr<WebToCCAnimationDelegateAdapter> animation_delegate_adapter_; diff --git a/chromium/cc/blink/web_layer_impl_fixed_bounds.h b/chromium/cc/blink/web_layer_impl_fixed_bounds.h index edfd4bbb558..328924542bb 100644 --- a/chromium/cc/blink/web_layer_impl_fixed_bounds.h +++ b/chromium/cc/blink/web_layer_impl_fixed_bounds.h @@ -21,7 +21,7 @@ class WebLayerImplFixedBounds : public WebLayerImpl { CC_BLINK_EXPORT WebLayerImplFixedBounds(); CC_BLINK_EXPORT explicit WebLayerImplFixedBounds( scoped_refptr<cc::Layer> layer); - virtual ~WebLayerImplFixedBounds(); + ~WebLayerImplFixedBounds() override; // WebLayerImpl overrides. void invalidateRect(const blink::WebRect& rect) override; 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 26f445ae072..65433feb445 100644 --- a/chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc +++ b/chromium/cc/blink/web_layer_impl_fixed_bounds_unittest.cc @@ -68,10 +68,10 @@ TEST(WebLayerImplFixedBoundsTest, BoundsScaleSimple) { } void ExpectEqualLayerRectsInTarget(cc::Layer* layer1, cc::Layer* layer2) { - gfx::RectF layer1_rect_in_target(layer1->bounds()); + gfx::RectF layer1_rect_in_target(gfx::SizeF(layer1->bounds())); layer1->draw_transform().TransformRect(&layer1_rect_in_target); - gfx::RectF layer2_rect_in_target(layer2->bounds()); + gfx::RectF layer2_rect_in_target(gfx::SizeF(layer2->bounds())); layer2->draw_transform().TransformRect(&layer2_rect_in_target); EXPECT_FLOAT_RECT_EQ(layer1_rect_in_target, layer2_rect_in_target); @@ -112,9 +112,8 @@ void CompareFixedBoundsLayerAndNormalLayer(const WebFloatPoint& anchor_point, host->SetRootLayer(root_layer->layer()); { - cc::RenderSurfaceLayerList render_surface_layer_list; - cc::LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root_layer->layer(), kDeviceViewportSize, &render_surface_layer_list); + cc::LayerTreeHostCommon::CalcDrawPropsMainInputs inputs( + root_layer->layer(), kDeviceViewportSize); inputs.device_scale_factor = kDeviceScaleFactor; inputs.page_scale_factor = kPageScaleFactor; inputs.page_scale_layer = root_layer->layer(), @@ -129,9 +128,8 @@ void CompareFixedBoundsLayerAndNormalLayer(const WebFloatPoint& anchor_point, gfx::Size(fixed_bounds.width() / 2, fixed_bounds.height() * 2)); { - cc::RenderSurfaceLayerList render_surface_layer_list; - cc::LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root_layer->layer(), kDeviceViewportSize, &render_surface_layer_list); + cc::LayerTreeHostCommon::CalcDrawPropsMainInputs inputs( + root_layer->layer(), kDeviceViewportSize); inputs.device_scale_factor = kDeviceScaleFactor; inputs.page_scale_factor = kPageScaleFactor; inputs.page_scale_layer = root_layer->layer(), diff --git a/chromium/cc/blink/web_nine_patch_layer_impl.cc b/chromium/cc/blink/web_nine_patch_layer_impl.cc deleted file mode 100644 index 8dd9980f331..00000000000 --- a/chromium/cc/blink/web_nine_patch_layer_impl.cc +++ /dev/null @@ -1,46 +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/blink/web_nine_patch_layer_impl.h" - -#include "base/command_line.h" -#include "cc/base/switches.h" -#include "cc/blink/web_layer_impl.h" -#include "cc/blink/web_layer_impl_fixed_bounds.h" -#include "cc/layers/nine_patch_layer.h" -#include "cc/layers/picture_image_layer.h" - -namespace cc_blink { - -WebNinePatchLayerImpl::WebNinePatchLayerImpl() { - layer_.reset(new WebLayerImpl( - cc::NinePatchLayer::Create(WebLayerImpl::LayerSettings()))); -} - -WebNinePatchLayerImpl::~WebNinePatchLayerImpl() { -} - -blink::WebLayer* WebNinePatchLayerImpl::layer() { - return layer_.get(); -} - -void WebNinePatchLayerImpl::setBitmap(const SkBitmap& bitmap) { - cc::NinePatchLayer* nine_patch = - static_cast<cc::NinePatchLayer*>(layer_->layer()); - nine_patch->SetBitmap(bitmap); -} - -void WebNinePatchLayerImpl::setAperture(const blink::WebRect& aperture) { - cc::NinePatchLayer* nine_patch = - static_cast<cc::NinePatchLayer*>(layer_->layer()); - nine_patch->SetAperture(gfx::Rect(aperture)); -} - -void WebNinePatchLayerImpl::setBorder(const blink::WebRect& border) { - cc::NinePatchLayer* nine_patch = - static_cast<cc::NinePatchLayer*>(layer_->layer()); - nine_patch->SetBorder(gfx::Rect(border)); -} - -} // namespace cc_blink diff --git a/chromium/cc/blink/web_nine_patch_layer_impl.h b/chromium/cc/blink/web_nine_patch_layer_impl.h deleted file mode 100644 index cbb39660cd5..00000000000 --- a/chromium/cc/blink/web_nine_patch_layer_impl.h +++ /dev/null @@ -1,37 +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_BLINK_WEB_NINE_PATCH_LAYER_IMPL_H_ -#define CC_BLINK_WEB_NINE_PATCH_LAYER_IMPL_H_ - -#include "base/memory/scoped_ptr.h" -#include "cc/blink/cc_blink_export.h" -#include "third_party/WebKit/public/platform/WebNinePatchLayer.h" -#include "third_party/skia/include/core/SkBitmap.h" - -namespace cc_blink { - -class WebLayerImpl; - -class WebNinePatchLayerImpl : public blink::WebNinePatchLayer { - public: - CC_BLINK_EXPORT WebNinePatchLayerImpl(); - virtual ~WebNinePatchLayerImpl(); - - // blink::WebNinePatchLayer implementation. - virtual blink::WebLayer* layer(); - - virtual void setBitmap(const SkBitmap& bitmap); - virtual void setAperture(const blink::WebRect& aperture); - virtual void setBorder(const blink::WebRect& border); - - private: - scoped_ptr<WebLayerImpl> layer_; - - DISALLOW_COPY_AND_ASSIGN(WebNinePatchLayerImpl); -}; - -} // namespace cc_blink - -#endif // CC_BLINK_WEB_NINE_PATCH_LAYER_IMPL_H_ 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 5f914b9ca54..11a1635b2d2 100644 --- a/chromium/cc/blink/web_scroll_offset_animation_curve_impl.h +++ b/chromium/cc/blink/web_scroll_offset_animation_curve_impl.h @@ -22,15 +22,16 @@ class WebScrollOffsetAnimationCurveImpl CC_BLINK_EXPORT WebScrollOffsetAnimationCurveImpl( blink::WebFloatPoint target_value, TimingFunctionType timing_function); - virtual ~WebScrollOffsetAnimationCurveImpl(); + ~WebScrollOffsetAnimationCurveImpl() override; // blink::WebCompositorAnimationCurve implementation. - virtual AnimationCurveType type() const; + AnimationCurveType type() const override; // blink::WebScrollOffsetAnimationCurve implementation. - virtual void setInitialValue(blink::WebFloatPoint initial_value); - virtual blink::WebFloatPoint getValue(double time) const; - virtual double duration() const; + void setInitialValue(blink::WebFloatPoint initial_value) override; + blink::WebFloatPoint getValue(double time) const override; + double duration() const override; + virtual blink::WebFloatPoint targetValue() const; virtual void updateTarget(double time, blink::WebFloatPoint new_target); diff --git a/chromium/cc/blink/web_scrollbar_layer_impl.h b/chromium/cc/blink/web_scrollbar_layer_impl.h index 14ed66ebb96..d4963d99db3 100644 --- a/chromium/cc/blink/web_scrollbar_layer_impl.h +++ b/chromium/cc/blink/web_scrollbar_layer_impl.h @@ -30,12 +30,12 @@ class WebScrollbarLayerImpl : public blink::WebScrollbarLayer { int thumb_thickness, int track_start, bool is_left_side_vertical_scrollbar); - virtual ~WebScrollbarLayerImpl(); + ~WebScrollbarLayerImpl() override; // blink::WebScrollbarLayer implementation. - virtual blink::WebLayer* layer(); - virtual void setScrollLayer(blink::WebLayer* layer); - virtual void setClipLayer(blink::WebLayer* layer); + blink::WebLayer* layer() override; + void setScrollLayer(blink::WebLayer* layer) override; + void setClipLayer(blink::WebLayer* layer) override; private: scoped_ptr<WebLayerImpl> layer_; diff --git a/chromium/cc/blink/web_transform_animation_curve_impl.h b/chromium/cc/blink/web_transform_animation_curve_impl.h index 81ed6073fa7..9143d3cc019 100644 --- a/chromium/cc/blink/web_transform_animation_curve_impl.h +++ b/chromium/cc/blink/web_transform_animation_curve_impl.h @@ -24,31 +24,31 @@ class WebTransformAnimationCurveImpl : public blink::WebTransformAnimationCurve { public: CC_BLINK_EXPORT WebTransformAnimationCurveImpl(); - virtual ~WebTransformAnimationCurveImpl(); + ~WebTransformAnimationCurveImpl() override; // blink::WebCompositorAnimationCurve implementation. - virtual AnimationCurveType type() const; + AnimationCurveType type() const override; // blink::WebTransformAnimationCurve implementation. - virtual void add(const blink::WebTransformKeyframe& keyframe); - virtual void add(const blink::WebTransformKeyframe& keyframe, - TimingFunctionType type); - virtual void add(const blink::WebTransformKeyframe& keyframe, - 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); + void add(const blink::WebTransformKeyframe& keyframe) override; + void add(const blink::WebTransformKeyframe& keyframe, + TimingFunctionType type) override; + void add(const blink::WebTransformKeyframe& keyframe, + double x1, + double y1, + double x2, + double y2) override; + void add(const blink::WebTransformKeyframe& keyframe, + int steps, + float stepsStartOffset) override; + void setLinearTimingFunction() override; + void setCubicBezierTimingFunction(TimingFunctionType) override; + void setCubicBezierTimingFunction(double x1, + double y1, + double x2, + double y2) override; + void setStepsTimingFunction(int number_of_steps, + float steps_start_offset) override; scoped_ptr<cc::AnimationCurve> CloneToAnimationCurve() const; diff --git a/chromium/cc/blink/web_transform_operations_impl.h b/chromium/cc/blink/web_transform_operations_impl.h index 0c91e06289a..f8fe22b6d88 100644 --- a/chromium/cc/blink/web_transform_operations_impl.h +++ b/chromium/cc/blink/web_transform_operations_impl.h @@ -15,20 +15,20 @@ namespace cc_blink { class WebTransformOperationsImpl : public blink::WebTransformOperations { public: CC_BLINK_EXPORT WebTransformOperationsImpl(); - virtual ~WebTransformOperationsImpl(); + ~WebTransformOperationsImpl() override; const cc::TransformOperations& AsTransformOperations() const; // Implementation of blink::WebTransformOperations methods - virtual bool canBlendWith(const blink::WebTransformOperations& other) const; - virtual void appendTranslate(double x, double y, double z); - virtual void appendRotate(double x, double y, double z, double degrees); - virtual void appendScale(double x, double y, double z); - virtual void appendSkew(double x, double y); - virtual void appendPerspective(double depth); - virtual void appendMatrix(const SkMatrix44&); - virtual void appendIdentity(); - virtual bool isIdentity() const; + bool canBlendWith(const blink::WebTransformOperations& other) const override; + void appendTranslate(double x, double y, double z) override; + void appendRotate(double x, double y, double z, double degrees) override; + void appendScale(double x, double y, double z) override; + void appendSkew(double x, double y) override; + void appendPerspective(double depth) override; + void appendMatrix(const SkMatrix44&) override; + void appendIdentity() override; + bool isIdentity() const override; private: cc::TransformOperations transform_operations_; diff --git a/chromium/cc/cc.gyp b/chromium/cc/cc.gyp index d4a2ea02fe7..642ec7559e3 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', + '<(DEPTH)/ui/gl/gl.gyp:gl', ], 'variables': { 'optimize': 'max', @@ -79,19 +80,22 @@ 'base/histograms.h', 'base/invalidation_region.cc', 'base/invalidation_region.h', - 'base/list_container.cc', 'base/list_container.h', + 'base/list_container_helper.cc', + 'base/list_container_helper.h', 'base/math_util.cc', 'base/math_util.h', + 'base/random_access_list_container.h', 'base/region.cc', 'base/region.h', 'base/resource_id.h', 'base/rolling_time_delta_history.cc', 'base/rolling_time_delta_history.h', + 'base/rtree.cc', + 'base/rtree.h', 'base/scoped_ptr_algorithm.h', 'base/scoped_ptr_deque.h', 'base/scoped_ptr_vector.h', - 'base/sidecar_list_container.h', 'base/simple_enclosed_region.cc', 'base/simple_enclosed_region.h', 'base/switches.cc', @@ -131,12 +135,8 @@ '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', 'debug/rasterize_and_record_benchmark.h', 'debug/rasterize_and_record_benchmark_impl.cc', @@ -148,8 +148,6 @@ 'debug/ring_buffer.h', 'debug/traced_display_item_list.cc', 'debug/traced_display_item_list.h', - 'debug/traced_picture.cc', - 'debug/traced_picture.h', 'debug/traced_value.cc', 'debug/traced_value.h', 'debug/unittest_only_benchmark.cc', @@ -164,6 +162,8 @@ 'input/page_scale_animation.h', 'input/scroll_elasticity_helper.cc', 'input/scroll_elasticity_helper.h', + 'input/scroll_state.cc', + 'input/scroll_state.h', 'input/selection_bound_type.h', 'input/selection.h', 'input/top_controls_manager.cc', @@ -179,6 +179,7 @@ 'layers/delegated_renderer_layer.h', 'layers/delegated_renderer_layer_impl.cc', 'layers/delegated_renderer_layer_impl.h', + 'layers/draw_properties.cc', 'layers/draw_properties.h', 'layers/heads_up_display_layer.cc', 'layers/heads_up_display_layer.h', @@ -194,7 +195,6 @@ 'layers/layer_impl.cc', 'layers/layer_impl.h', 'layers/layer_iterator.h', - 'layers/layer_lists.cc', 'layers/layer_lists.h', 'layers/layer_position_constraint.cc', 'layers/layer_position_constraint.h', @@ -218,8 +218,8 @@ 'layers/picture_layer_impl.cc', 'layers/picture_layer_impl.h', 'layers/render_pass_sink.h', - 'layers/render_surface.cc', - 'layers/render_surface.h', + 'layers/render_surface_draw_properties.cc', + 'layers/render_surface_draw_properties.h', 'layers/render_surface_impl.cc', 'layers/render_surface_impl.h', 'layers/scrollbar_layer_impl_base.cc', @@ -307,8 +307,12 @@ 'output/overlay_candidate_validator.h', 'output/overlay_processor.cc', 'output/overlay_processor.h', + 'output/overlay_strategy_all_or_nothing.cc', + 'output/overlay_strategy_all_or_nothing.h', 'output/overlay_strategy_common.cc', 'output/overlay_strategy_common.h', + 'output/overlay_strategy_sandwich.cc', + 'output/overlay_strategy_sandwich.h', 'output/overlay_strategy_single_on_top.cc', 'output/overlay_strategy_single_on_top.h', 'output/overlay_strategy_underlay.cc', @@ -325,8 +329,6 @@ 'output/renderer_settings.h', 'output/shader.cc', 'output/shader.h', - 'output/software_frame_data.cc', - 'output/software_frame_data.h', 'output/software_output_device.cc', 'output/software_output_device.h', 'output/software_renderer.cc', @@ -344,10 +346,14 @@ 'playback/clip_path_display_item.h', 'playback/compositing_display_item.cc', 'playback/compositing_display_item.h', + 'playback/discardable_image_map.cc', + 'playback/discardable_image_map.h', 'playback/display_item.cc', 'playback/display_item.h', 'playback/display_item_list.cc', 'playback/display_item_list.h', + 'playback/display_item_list_bounds_calculator.cc', + 'playback/display_item_list_bounds_calculator.h', 'playback/display_item_list_settings.cc', 'playback/display_item_list_settings.h', 'playback/display_list_raster_source.cc', @@ -362,22 +368,13 @@ '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/position_image.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', 'quads/content_draw_quad_base.h', 'quads/debug_border_draw_quad.cc', @@ -420,8 +417,6 @@ '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', @@ -449,6 +444,7 @@ 'resources/resource_pool.h', 'resources/resource_provider.cc', 'resources/resource_provider.h', + 'resources/resource_util.h', 'resources/returned_resource.h', 'resources/scoped_resource.cc', 'resources/scoped_resource.h', @@ -491,6 +487,8 @@ 'scheduler/video_frame_controller.h', 'tiles/eviction_tile_priority_queue.cc', 'tiles/eviction_tile_priority_queue.h', + 'tiles/image_decode_controller.cc', + 'tiles/image_decode_controller.h', 'tiles/picture_layer_tiling.cc', 'tiles/picture_layer_tiling.h', 'tiles/picture_layer_tiling_set.cc', @@ -519,6 +517,8 @@ 'tiles/tiling_set_raster_queue_required.h', 'trees/blocking_task_runner.cc', 'trees/blocking_task_runner.h', + 'trees/channel_impl.h', + 'trees/channel_main.h', 'trees/damage_tracker.cc', 'trees/damage_tracker.h', 'trees/draw_property_utils.cc', @@ -548,11 +548,15 @@ 'trees/property_tree_builder.h', 'trees/proxy.cc', 'trees/proxy.h', + 'trees/proxy_impl.h', + 'trees/proxy_main.h', '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/threaded_channel.cc', + 'trees/threaded_channel.h', 'trees/thread_proxy.cc', 'trees/thread_proxy.h', 'trees/tree_synchronizer.cc', @@ -605,6 +609,8 @@ 'surfaces/surface_factory.cc', 'surfaces/surface_factory.h', 'surfaces/surface_factory_client.h', + 'surfaces/surface_hittest.cc', + 'surfaces/surface_hittest.h', 'surfaces/surface_id.h', 'surfaces/surface_id_allocator.cc', 'surfaces/surface_id_allocator.h', diff --git a/chromium/cc/cc_tests.gyp b/chromium/cc/cc_tests.gyp index 5f5f4e418aa..419f68cd7ad 100644 --- a/chromium/cc/cc_tests.gyp +++ b/chromium/cc/cc_tests.gyp @@ -22,16 +22,18 @@ 'base/histograms_unittest.cc', 'base/list_container_unittest.cc', 'base/math_util_unittest.cc', + 'base/random_access_list_container_unittest.cc', 'base/region_unittest.cc', 'base/rolling_time_delta_history_unittest.cc', + 'base/rtree_unittest.cc', 'base/scoped_ptr_vector_unittest.cc', - 'base/sidecar_list_container_unittest.cc', 'base/simple_enclosed_region_unittest.cc', 'base/tiling_data_unittest.cc', 'base/unique_notifier_unittest.cc', 'debug/frame_timing_tracker_unittest.cc', 'debug/micro_benchmark_controller_unittest.cc', 'debug/rendering_stats_unittest.cc', + 'input/scroll_state_unittest.cc', 'input/top_controls_manager_unittest.cc', 'layers/delegated_frame_provider_unittest.cc', 'layers/delegated_frame_resource_collection_unittest.cc', @@ -78,14 +80,10 @@ 'output/shader_unittest.cc', 'output/software_renderer_unittest.cc', 'output/texture_mailbox_deleter_unittest.cc', + 'playback/discardable_image_map_unittest.cc', 'playback/display_item_list_unittest.cc', 'playback/display_list_raster_source_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/render_pass_unittest.cc', @@ -96,6 +94,7 @@ 'resources/platform_color_unittest.cc', 'resources/resource_pool_unittest.cc', 'resources/resource_provider_unittest.cc', + 'resources/resource_util_unittest.cc', 'resources/scoped_resource_unittest.cc', 'resources/video_resource_updater_unittest.cc', 'scheduler/begin_frame_source_unittest.cc', @@ -146,6 +145,7 @@ 'surfaces/surface_aggregator_unittest.cc', 'surfaces/surface_display_output_surface_unittest.cc', 'surfaces/surface_factory_unittest.cc', + 'surfaces/surface_hittest_unittest.cc', 'surfaces/surface_unittest.cc', 'surfaces/surfaces_pixeltest.cc', ], @@ -164,6 +164,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_raster_source.cc', + 'test/fake_display_list_raster_source.h', + 'test/fake_display_list_recording_source.cc', 'test/fake_display_list_recording_source.h', 'test/fake_external_begin_frame_source.cc', 'test/fake_external_begin_frame_source.h', @@ -188,10 +191,6 @@ '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', 'test/fake_proxy.h', 'test/fake_renderer_client.cc', @@ -241,8 +240,6 @@ 'test/pixel_test_software_output_device.h', 'test/pixel_test_utils.cc', 'test/pixel_test_utils.h', - 'test/render_pass_test_common.cc', - 'test/render_pass_test_common.h', 'test/render_pass_test_utils.cc', 'test/render_pass_test_utils.h', 'test/scheduler_test_common.cc', @@ -353,7 +350,6 @@ # Note: sources list duplicated in GN build. 'layers/layer_perftest.cc', 'layers/picture_layer_impl_perftest.cc', - 'playback/picture_pile_impl_perftest.cc', 'quads/draw_quad_perftest.cc', 'raster/task_graph_runner_perftest.cc', 'raster/texture_compressor_perftest.cc', @@ -415,6 +411,7 @@ '../ui/gfx/gfx.gyp:gfx_geometry', '../ui/gfx/gfx.gyp:gfx_test_support', '../ui/gl/gl.gyp:gl', + '../ui/gl/gl.gyp:gl_test_support', ], 'sources': [ '<@(cc_tests_support_files)', @@ -467,7 +464,7 @@ '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', + ['use_x11==1', { 'dependencies': [ '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck', diff --git a/chromium/cc/cc_unittests.isolate b/chromium/cc/cc_unittests.isolate index 6a16fcd5e9c..09bfcf9e34a 100644 --- a/chromium/cc/cc_unittests.isolate +++ b/chromium/cc/cc_unittests.isolate @@ -39,7 +39,6 @@ 'files': [ 'test/data/', '../testing/test_env.py', - '<(PRODUCT_DIR)/cc_unittests<(EXECUTABLE_SUFFIX)', ], }, }], @@ -81,6 +80,6 @@ ], 'includes': [ '../base/base.isolate', - '../third_party/angle/angle.isolate', + '../ui/gl/gl.isolate', ], } diff --git a/chromium/cc/debug/devtools_instrumentation.h b/chromium/cc/debug/devtools_instrumentation.h index 8f03f8c76fc..3a285799840 100644 --- a/chromium/cc/debug/devtools_instrumentation.h +++ b/chromium/cc/debug/devtools_instrumentation.h @@ -52,9 +52,10 @@ class ScopedLayerTask { class ScopedImageDecodeTask { public: - explicit ScopedImageDecodeTask(void* pixelRef) { + explicit ScopedImageDecodeTask(const void* imagePtr) { TRACE_EVENT_BEGIN1(internal::kCategory, internal::kImageDecodeTask, - internal::kPixelRefId, reinterpret_cast<uint64>(pixelRef)); + internal::kPixelRefId, + reinterpret_cast<uint64>(imagePtr)); } ~ScopedImageDecodeTask() { TRACE_EVENT_END0(internal::kCategory, internal::kImageDecodeTask); diff --git a/chromium/cc/debug/layer_tree_debug_state.cc b/chromium/cc/debug/layer_tree_debug_state.cc index e840220ca6f..a084bf38d20 100644 --- a/chromium/cc/debug/layer_tree_debug_state.cc +++ b/chromium/cc/debug/layer_tree_debug_state.cc @@ -12,7 +12,6 @@ namespace cc { LayerTreeDebugState::LayerTreeDebugState() : show_fps_counter(false), show_debug_borders(false), - continuous_painting(false), show_paint_rects(false), show_property_changed_rects(false), show_surface_damage_rects(false), @@ -35,12 +34,11 @@ void LayerTreeDebugState::SetRecordRenderingStats(bool enabled) { } bool LayerTreeDebugState::RecordRenderingStats() const { - return record_rendering_stats_ || continuous_painting; + return record_rendering_stats_; } bool LayerTreeDebugState::ShowHudInfo() const { - return show_fps_counter || continuous_painting || - ShowHudRects(); + return show_fps_counter || ShowHudRects(); } bool LayerTreeDebugState::ShowHudRects() const { @@ -52,7 +50,7 @@ bool LayerTreeDebugState::ShowHudRects() const { } bool LayerTreeDebugState::ShowMemoryStats() const { - return show_fps_counter || continuous_painting; + return show_fps_counter; } bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a, @@ -60,7 +58,6 @@ bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a, return ( a.show_fps_counter == b.show_fps_counter && a.show_debug_borders == b.show_debug_borders && - a.continuous_painting == b.continuous_painting && a.show_paint_rects == b.show_paint_rects && a.show_property_changed_rects == b.show_property_changed_rects && a.show_surface_damage_rects == b.show_surface_damage_rects && @@ -84,7 +81,6 @@ LayerTreeDebugState LayerTreeDebugState::Unite(const LayerTreeDebugState& a, r.show_fps_counter |= b.show_fps_counter; r.show_debug_borders |= b.show_debug_borders; - r.continuous_painting |= b.continuous_painting; r.show_paint_rects |= b.show_paint_rects; r.show_property_changed_rects |= b.show_property_changed_rects; diff --git a/chromium/cc/debug/layer_tree_debug_state.h b/chromium/cc/debug/layer_tree_debug_state.h index 4b71cd9bbbe..13db0ce4be9 100644 --- a/chromium/cc/debug/layer_tree_debug_state.h +++ b/chromium/cc/debug/layer_tree_debug_state.h @@ -17,7 +17,6 @@ class CC_EXPORT LayerTreeDebugState { bool show_fps_counter; bool show_debug_borders; - bool continuous_painting; bool show_paint_rects; bool show_property_changed_rects; diff --git a/chromium/cc/debug/micro_benchmark_controller.cc b/chromium/cc/debug/micro_benchmark_controller.cc index a38e5ad01a3..a0dc306612f 100644 --- a/chromium/cc/debug/micro_benchmark_controller.cc +++ b/chromium/cc/debug/micro_benchmark_controller.cc @@ -11,7 +11,6 @@ #include "base/thread_task_runner_handle.h" #include "base/values.h" #include "cc/debug/invalidation_benchmark.h" -#include "cc/debug/picture_record_benchmark.h" #include "cc/debug/rasterize_and_record_benchmark.h" #include "cc/debug/unittest_only_benchmark.h" #include "cc/trees/layer_tree_host.h" @@ -29,8 +28,6 @@ scoped_ptr<MicroBenchmark> CreateBenchmark( const MicroBenchmark::DoneCallback& callback) { if (name == "invalidation_benchmark") { return make_scoped_ptr(new InvalidationBenchmark(value.Pass(), callback)); - } else if (name == "picture_record_benchmark") { - return make_scoped_ptr(new PictureRecordBenchmark(value.Pass(), callback)); } else if (name == "rasterize_and_record_benchmark") { return make_scoped_ptr( new RasterizeAndRecordBenchmark(value.Pass(), callback)); diff --git a/chromium/cc/debug/paint_time_counter.cc b/chromium/cc/debug/paint_time_counter.cc deleted file mode 100644 index 41ef1a334a6..00000000000 --- a/chromium/cc/debug/paint_time_counter.cc +++ /dev/null @@ -1,43 +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/debug/paint_time_counter.h" - -namespace cc { - -// static -scoped_ptr<PaintTimeCounter> PaintTimeCounter::Create() { - return make_scoped_ptr(new PaintTimeCounter()); -} - -PaintTimeCounter::PaintTimeCounter() { -} - -void PaintTimeCounter::SavePaintTime(const base::TimeDelta& paint_time) { - ring_buffer_.SaveToBuffer(paint_time); -} - -void PaintTimeCounter::GetMinAndMaxPaintTime(base::TimeDelta* min, - base::TimeDelta* max) const { - *min = base::TimeDelta::FromDays(1); - *max = base::TimeDelta(); - - for (RingBufferType::Iterator it = ring_buffer_.Begin(); it; ++it) { - const base::TimeDelta paint_time = **it; - - if (paint_time < *min) - *min = paint_time; - if (paint_time > *max) - *max = paint_time; - } - - if (*min > *max) - *min = *max; -} - -void PaintTimeCounter::ClearHistory() { - ring_buffer_.Clear(); -} - -} // namespace cc diff --git a/chromium/cc/debug/paint_time_counter.h b/chromium/cc/debug/paint_time_counter.h deleted file mode 100644 index c93980bc836..00000000000 --- a/chromium/cc/debug/paint_time_counter.h +++ /dev/null @@ -1,45 +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_DEBUG_PAINT_TIME_COUNTER_H_ -#define CC_DEBUG_PAINT_TIME_COUNTER_H_ - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/time/time.h" -#include "cc/debug/ring_buffer.h" - -namespace cc { - -// Maintains a history of paint times for each frame -class PaintTimeCounter { - public: - static scoped_ptr<PaintTimeCounter> Create(); - - size_t HistorySize() const { return ring_buffer_.BufferSize(); } - - // n = 0 returns the oldest and - // n = PaintTimeHistorySize() - 1 the most recent paint time. - base::TimeDelta GetPaintTimeOfRecentFrame(const size_t& n) const; - - void SavePaintTime(const base::TimeDelta& total_paint_time); - void GetMinAndMaxPaintTime(base::TimeDelta* min, base::TimeDelta* max) const; - - void ClearHistory(); - - typedef RingBuffer<base::TimeDelta, 200> RingBufferType; - RingBufferType::Iterator Begin() const { return ring_buffer_.Begin(); } - RingBufferType::Iterator End() const { return ring_buffer_.End(); } - - private: - PaintTimeCounter(); - - RingBufferType ring_buffer_; - - DISALLOW_COPY_AND_ASSIGN(PaintTimeCounter); -}; - -} // namespace cc - -#endif // CC_DEBUG_PAINT_TIME_COUNTER_H_ diff --git a/chromium/cc/debug/picture_record_benchmark.cc b/chromium/cc/debug/picture_record_benchmark.cc deleted file mode 100644 index 0f093ce1ecc..00000000000 --- a/chromium/cc/debug/picture_record_benchmark.cc +++ /dev/null @@ -1,119 +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/picture_record_benchmark.h" - -#include <algorithm> - -#include "base/basictypes.h" -#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" - -namespace cc { - -namespace { - -const int kPositionIncrement = 100; -const int kTileGridSize = 512; - -} // namespace - -PictureRecordBenchmark::PictureRecordBenchmark( - scoped_ptr<base::Value> value, - const MicroBenchmark::DoneCallback& callback) - : MicroBenchmark(callback) { - if (!value) - return; - - base::ListValue* list = nullptr; - value->GetAsList(&list); - if (!list) - return; - - for (base::ListValue::iterator it = list->begin(); it != list->end(); ++it) { - base::DictionaryValue* dictionary = nullptr; - (*it)->GetAsDictionary(&dictionary); - if (!dictionary || - !dictionary->HasKey("width") || - !dictionary->HasKey("height")) - continue; - - int width, height; - dictionary->GetInteger("width", &width); - dictionary->GetInteger("height", &height); - - dimensions_.push_back(std::make_pair(width, height)); - } -} - -PictureRecordBenchmark::~PictureRecordBenchmark() {} - -void PictureRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) { - LayerTreeHostCommon::CallFunctionForSubtree( - host->root_layer(), - [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(); - it != times_.end(); - ++it) { - std::pair<int, int> dimensions = it->first; - base::TimeDelta total_time = it->second.first; - unsigned total_count = it->second.second; - - double average_time = 0.0; - if (total_count > 0) - average_time = total_time.InMillisecondsF() / total_count; - - scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); - result->SetInteger("width", dimensions.first); - result->SetInteger("height", dimensions.second); - result->SetInteger("samples_count", total_count); - result->SetDouble("time_ms", average_time); - - results->Append(result.release()); - } - - NotifyDone(results.Pass()); -} - -void PictureRecordBenchmark::RunOnLayer(PictureLayer* layer) { - ContentLayerClient* painter = layer->client(); - gfx::Size bounds = layer->bounds(); - - gfx::Size tile_grid_size(kTileGridSize, kTileGridSize); - - for (size_t i = 0; i < dimensions_.size(); ++i) { - std::pair<int, int> dimensions = dimensions_[i]; - int width = dimensions.first; - int height = dimensions.second; - - int y_limit = std::max(1, bounds.height() - height); - int x_limit = std::max(1, bounds.width() - width); - for (int y = 0; y < y_limit; y += kPositionIncrement) { - for (int x = 0; x < x_limit; x += kPositionIncrement) { - gfx::Rect rect = gfx::Rect(x, y, width, height); - - base::TimeTicks start = base::TimeTicks::Now(); - - scoped_refptr<Picture> picture = - Picture::Create(rect, painter, tile_grid_size, false, - RecordingSource::RECORD_NORMALLY); - - base::TimeTicks end = base::TimeTicks::Now(); - base::TimeDelta duration = end - start; - TotalTime& total_time = times_[dimensions]; - total_time.first += duration; - total_time.second++; - } - } - } -} - -} // namespace cc diff --git a/chromium/cc/debug/picture_record_benchmark.h b/chromium/cc/debug/picture_record_benchmark.h deleted file mode 100644 index 3710d83b21b..00000000000 --- a/chromium/cc/debug/picture_record_benchmark.h +++ /dev/null @@ -1,37 +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_DEBUG_PICTURE_RECORD_BENCHMARK_H_ -#define CC_DEBUG_PICTURE_RECORD_BENCHMARK_H_ - -#include <map> -#include <utility> -#include <vector> - -#include "base/time/time.h" -#include "cc/debug/micro_benchmark_controller.h" - -namespace cc { - -class LayerTreeHost; -class Layer; -class CC_EXPORT PictureRecordBenchmark : public MicroBenchmark { - public: - explicit PictureRecordBenchmark(scoped_ptr<base::Value> value, - const MicroBenchmark::DoneCallback& callback); - ~PictureRecordBenchmark() override; - - // Implements MicroBenchmark interface. - void DidUpdateLayers(LayerTreeHost* host) override; - void RunOnLayer(PictureLayer* layer) override; - - private: - typedef std::pair<base::TimeDelta, unsigned> TotalTime; - std::map<std::pair<int, int>, TotalTime> times_; - std::vector<std::pair<int, int>> dimensions_; -}; - -} // namespace cc - -#endif // CC_DEBUG_PICTURE_RECORD_BENCHMARK_H_ diff --git a/chromium/cc/debug/rasterize_and_record_benchmark.cc b/chromium/cc/debug/rasterize_and_record_benchmark.cc index b474e431fd2..9b958d3bd2e 100644 --- a/chromium/cc/debug/rasterize_and_record_benchmark.cc +++ b/chromium/cc/debug/rasterize_and_record_benchmark.cc @@ -17,9 +17,9 @@ #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 "skia/ext/analysis_canvas.h" #include "third_party/skia/include/utils/SkPictureUtils.h" #include "ui/gfx/geometry/rect.h" @@ -113,66 +113,7 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) { 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::RunOnPictureLayer( - PictureLayer* layer, - const gfx::Rect& visible_layer_rect) { - ContentLayerClient* painter = layer->client(); - - DCHECK(host_ && !host_->settings().use_display_lists); - - gfx::Size tile_grid_size = host_->settings().default_tile_size; - - for (int mode_index = 0; mode_index < RecordingSource::RECORDING_MODE_COUNT; - mode_index++) { - RecordingSource::RecordingMode mode = - static_cast<RecordingSource::RecordingMode>(mode_index); - - // Not supported for SkPicture recording. - if (mode == RecordingSource::RECORD_WITH_CONSTRUCTION_DISABLED) - continue; - - base::TimeDelta min_time = base::TimeDelta::Max(); - size_t memory_used = 0; - - 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; - } + RunOnDisplayListLayer(layer, visible_layer_rect); } void RasterizeAndRecordBenchmark::RunOnDisplayListLayer( @@ -180,8 +121,6 @@ void RasterizeAndRecordBenchmark::RunOnDisplayListLayer( 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 = @@ -220,6 +159,11 @@ void RasterizeAndRecordBenchmark::RunOnDisplayListLayer( do { display_list = painter->PaintContentsToDisplayList(visible_layer_rect, painting_control); + if (display_list->ShouldBeAnalyzedForSolidColor()) { + gfx::Size layer_size = layer->paint_properties().bounds; + skia::AnalysisCanvas canvas(layer_size.width(), layer_size.height()); + display_list->Raster(&canvas, nullptr, gfx::Rect(), 1.f); + } if (memory_used) { // Verify we are recording the same thing each time. @@ -237,7 +181,8 @@ void RasterizeAndRecordBenchmark::RunOnDisplayListLayer( } if (mode_index == RecordingSource::RECORD_NORMALLY) { - record_results_.bytes_used += memory_used; + record_results_.bytes_used += + memory_used + painter->GetApproximateUnsharedMemoryUsage(); record_results_.pixels_recorded += visible_layer_rect.width() * visible_layer_rect.height(); } diff --git a/chromium/cc/debug/rasterize_and_record_benchmark.h b/chromium/cc/debug/rasterize_and_record_benchmark.h index 207254f24c6..97cecb15a53 100644 --- a/chromium/cc/debug/rasterize_and_record_benchmark.h +++ b/chromium/cc/debug/rasterize_and_record_benchmark.h @@ -13,7 +13,8 @@ #include "base/single_thread_task_runner.h" #include "base/time/time.h" #include "cc/debug/micro_benchmark_controller.h" -#include "cc/playback/picture.h" +#include "cc/playback/recording_source.h" +#include "ui/gfx/geometry/rect.h" namespace base { class DictionaryValue; @@ -40,8 +41,6 @@ class RasterizeAndRecordBenchmark : public MicroBenchmark { private: 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); diff --git a/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc b/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc index 1dc110b4fac..d798dc6705e 100644 --- a/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc +++ b/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc @@ -73,9 +73,8 @@ class FixedInvalidationPictureLayerTilingClient const Region invalidation) : base_client_(base_client), invalidation_(invalidation) {} - ScopedTilePtr CreateTile(float contents_scale, - const gfx::Rect& content_rect) override { - return base_client_->CreateTile(contents_scale, content_rect); + ScopedTilePtr CreateTile(const Tile::CreateInfo& info) override { + return base_client_->CreateTile(info); } gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override { @@ -171,12 +170,13 @@ void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) { // really matter. const LayerTreeSettings& settings = layer->layer_tree_impl()->settings(); scoped_ptr<PictureLayerTilingSet> tiling_set = PictureLayerTilingSet::Create( - layer->GetTree(), &client, settings.max_tiles_for_interest_area, + layer->GetTree(), &client, settings.tiling_interest_area_padding, settings.skewport_target_time_in_seconds, settings.skewport_extrapolation_limit_in_content_pixels); PictureLayerTiling* tiling = tiling_set->AddTiling(1.f, layer->GetRasterSource()); + tiling->set_resolution(HIGH_RESOLUTION); tiling->CreateAllTilesForTesting(); RasterSource* raster_source = tiling->raster_source(); for (PictureLayerTiling::CoverageIterator it(tiling, 1.f, diff --git a/chromium/cc/debug/traced_picture.cc b/chromium/cc/debug/traced_picture.cc deleted file mode 100644 index 3241871d8ee..00000000000 --- a/chromium/cc/debug/traced_picture.cc +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 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/traced_picture.h" - -#include "base/json/json_writer.h" -#include "base/strings/stringprintf.h" -#include "base/values.h" - -namespace cc { - -TracedPicture::TracedPicture(scoped_refptr<const Picture> picture) - : picture_(picture), is_alias_(false) {} - -TracedPicture::~TracedPicture() { -} - -scoped_refptr<base::trace_event::ConvertableToTraceFormat> -TracedPicture::AsTraceablePicture(const Picture* picture) { - return scoped_refptr<base::trace_event::ConvertableToTraceFormat>( - new TracedPicture(picture)); -} - -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::trace_event::ConvertableToTraceFormat>(ptr); -} - -void TracedPicture::AppendAsTraceFormat(std::string* out) const { - if (is_alias_) - AppendPictureAlias(out); - else - AppendPicture(out); -} - -void TracedPicture::AppendPictureAlias(std::string* out) const { - scoped_ptr<base::DictionaryValue> alias(new base::DictionaryValue()); - alias->SetString("id_ref", base::StringPrintf("%p", picture_.get())); - - base::DictionaryValue res; - res.Set("alias", alias.release()); - std::string tmp; - base::JSONWriter::Write(res, &tmp); - out->append(tmp); -} - -void TracedPicture::AppendPicture(std::string* out) const { - std::string tmp; - base::JSONWriter::Write(*picture_->AsValue(), &tmp); - out->append(tmp); -} - -} // namespace cc diff --git a/chromium/cc/debug/traced_picture.h b/chromium/cc/debug/traced_picture.h deleted file mode 100644 index 0cb044e7212..00000000000 --- a/chromium/cc/debug/traced_picture.h +++ /dev/null @@ -1,42 +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_DEBUG_TRACED_PICTURE_H_ -#define CC_DEBUG_TRACED_PICTURE_H_ - -#include <string> - -#include "base/memory/scoped_ptr.h" -#include "base/trace_event/trace_event.h" -#include "cc/playback/picture.h" - -namespace cc { - -class TracedPicture : public base::trace_event::ConvertableToTraceFormat { - public: - explicit TracedPicture(scoped_refptr<const Picture>); - - static scoped_refptr<base::trace_event::ConvertableToTraceFormat> - AsTraceablePicture(const Picture* picture); - - static scoped_refptr<base::trace_event::ConvertableToTraceFormat> - AsTraceablePictureAlias(const Picture* original); - - void AppendAsTraceFormat(std::string* out) const override; - - private: - ~TracedPicture() override; - - void AppendPicture(std::string* out) const; - void AppendPictureAlias(std::string* out) const; - - scoped_refptr<const Picture> picture_; - bool is_alias_; - - DISALLOW_COPY_AND_ASSIGN(TracedPicture); -}; - -} // namespace cc - -#endif // CC_DEBUG_TRACED_PICTURE_H_ diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h index 3401eceb553..4696fb5ceca 100644 --- a/chromium/cc/input/input_handler.h +++ b/chromium/cc/input/input_handler.h @@ -15,11 +15,15 @@ namespace gfx { class Point; class PointF; +class ScrollOffset; +class SizeF; class Vector2d; class Vector2dF; } -namespace ui { struct LatencyInfo; } +namespace ui { +class LatencyInfo; +} namespace cc { @@ -49,6 +53,13 @@ class CC_EXPORT InputHandlerClient { virtual void Animate(base::TimeTicks time) = 0; virtual void MainThreadHasStoppedFlinging() = 0; virtual void ReconcileElasticOverscrollAndRootScroll() = 0; + virtual void UpdateRootLayerStateForSynchronousInputHandler( + const gfx::ScrollOffset& total_scroll_offset, + const gfx::ScrollOffset& max_scroll_offset, + const gfx::SizeF& scrollable_size, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) = 0; protected: InputHandlerClient() {} @@ -123,15 +134,14 @@ class CC_EXPORT InputHandler { // returned SCROLL_STARTED. virtual void ScrollEnd() = 0; - virtual void SetRootLayerScrollOffsetDelegate( - LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate) = 0; + // Requests a callback to UpdateRootLayerStateForSynchronousInputHandler() + // giving the current root scroll and page scale information. + virtual void RequestUpdateForSynchronousInputHandler() = 0; - // Called when the value returned by - // LayerScrollOffsetDelegate.GetTotalScrollOffset has changed for reasons - // other than a SetTotalScrollOffset call. - // NOTE: This should only called after a valid delegate was set via a call to - // SetRootLayerScrollOffsetDelegate. - virtual void OnRootLayerDelegatedScrollOffsetChanged() = 0; + // Called when the root scroll offset has been changed in the synchronous + // input handler by the application (outside of input event handling). + virtual void SetSynchronousInputHandlerRootScrollOffset( + const gfx::ScrollOffset& root_offset) = 0; virtual void PinchGestureBegin() = 0; virtual void PinchGestureUpdate(float magnify_delta, @@ -141,9 +151,13 @@ class CC_EXPORT InputHandler { // Request another callback to InputHandlerClient::Animate(). virtual void SetNeedsAnimateInput() = 0; + // If there is a scroll active, this reports whether the scroll is on the + // root layer, or on some other sublayer. + virtual bool IsCurrentlyScrollingRoot() const = 0; + // Whether the layer under |viewport_point| is the currently scrolling layer. virtual bool IsCurrentlyScrollingLayerAt(const gfx::Point& viewport_point, - ScrollInputType type) = 0; + ScrollInputType type) const = 0; virtual bool HaveWheelEventHandlersAt(const gfx::Point& viewport_point) = 0; diff --git a/chromium/cc/input/layer_scroll_offset_delegate.h b/chromium/cc/input/layer_scroll_offset_delegate.h deleted file mode 100644 index 0afc4db89e3..00000000000 --- a/chromium/cc/input/layer_scroll_offset_delegate.h +++ /dev/null @@ -1,68 +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_INPUT_LAYER_SCROLL_OFFSET_DELEGATE_H_ -#define CC_INPUT_LAYER_SCROLL_OFFSET_DELEGATE_H_ - -#include "base/basictypes.h" -#include "base/callback_forward.h" -#include "base/time/time.h" -#include "ui/gfx/geometry/scroll_offset.h" -#include "ui/gfx/geometry/size_f.h" - -namespace cc { - -// The LayerScrollOffsetDelegate allows for the embedder to take ownership of -// the scroll offset of the root layer. -// -// The LayerScrollOffsetDelegate is only used on the impl thread. -class LayerScrollOffsetDelegate { - public: - // This is called by the compositor to query the current scroll offset of the - // layer. - // There is no requirement that the return values of this method are - // stable in time (two subsequent calls may yield different results). - // The return value is not required to be related to the values passed in to - // the SetTotalScrollOffset method in any way however it is required to be no - // more than the value passed to the most recent SetMaxScrollOffset call. - virtual gfx::ScrollOffset GetTotalScrollOffset() = 0; - - // This is called by the compositor to notify the delegate of any change to - // the following parameters: - // |total_scroll_offset| current scroll offset of the root layer, - // |max_scroll_offset| total scroll offset upper bound for the root layer, - // |scrollable_size| root layer scrollable size, - // |page_scale_factor| current page scale, - // |min_page_scale_factor| page scale lower limit, - // |max_page_scale_factor| page scale upper limit. - virtual void UpdateRootLayerState( - const gfx::ScrollOffset& total_scroll_offset, - const gfx::ScrollOffset& max_scroll_offset, - const gfx::SizeF& scrollable_size, - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) = 0; - - // This is called by the compositor to check whether a delegate-managed fling - // is active or not. - // TODO(hush): Remove after WebView's smooth scrolling path is unified with - // Chrome's. - virtual bool IsExternalScrollActive() const = 0; - - // This is called by the compositor when a fling hitting the root layer - // requires a scheduled animation update. - typedef base::Callback<void(base::TimeTicks)> AnimationCallback; - virtual void SetNeedsAnimate(const AnimationCallback& animation) = 0; - - protected: - LayerScrollOffsetDelegate() {} - virtual ~LayerScrollOffsetDelegate() {} - - private: - DISALLOW_COPY_AND_ASSIGN(LayerScrollOffsetDelegate); -}; - -} // namespace cc - -#endif // CC_INPUT_LAYER_SCROLL_OFFSET_DELEGATE_H_ diff --git a/chromium/cc/input/page_scale_animation.cc b/chromium/cc/input/page_scale_animation.cc index 111502b95cd..1e2954419d3 100644 --- a/chromium/cc/input/page_scale_animation.cc +++ b/chromium/cc/input/page_scale_animation.cc @@ -147,7 +147,7 @@ void PageScaleAnimation::InferTargetAnchorFromScrollOffsets() { void PageScaleAnimation::ClampTargetScrollOffset() { gfx::Vector2dF max_scroll_offset = gfx::RectF(root_layer_size_).bottom_right() - - gfx::RectF(TargetViewportSize()).bottom_right(); + gfx::RectF(gfx::SizeF(TargetViewportSize())).bottom_right(); target_scroll_offset_.SetToMax(gfx::Vector2dF()); target_scroll_offset_.SetToMin(max_scroll_offset); } diff --git a/chromium/cc/input/page_scale_animation.h b/chromium/cc/input/page_scale_animation.h index 0e430c212fe..d73116c5d7d 100644 --- a/chromium/cc/input/page_scale_animation.h +++ b/chromium/cc/input/page_scale_animation.h @@ -9,7 +9,7 @@ #include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "cc/base/cc_export.h" -#include "ui/gfx/geometry/size.h" +#include "ui/gfx/geometry/size_f.h" #include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/geometry/vector2d_f.h" diff --git a/chromium/cc/input/scroll_state.cc b/chromium/cc/input/scroll_state.cc new file mode 100644 index 00000000000..52a0cca6943 --- /dev/null +++ b/chromium/cc/input/scroll_state.cc @@ -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. + +#include "cc/input/scroll_state.h" + +#include "cc/layers/layer_impl.h" + +namespace cc { + +ScrollState::ScrollState(double delta_x, + double delta_y, + int start_position_x, + int start_position_y, + bool should_propagate, + bool delta_consumed_for_scroll_sequence, + bool is_direct_manipulation) + : delta_x_(delta_x), + delta_y_(delta_y), + start_position_x_(start_position_x), + start_position_y_(start_position_y), + should_propagate_(should_propagate), + delta_consumed_for_scroll_sequence_(delta_consumed_for_scroll_sequence), + is_direct_manipulation_(is_direct_manipulation), + caused_scroll_x_(false), + caused_scroll_y_(false) {} + +ScrollState::~ScrollState() {} + +void ScrollState::ConsumeDelta(double x, double y) { + delta_x_ -= x; + delta_y_ -= y; + + if (x || y) + delta_consumed_for_scroll_sequence_ = true; +} + +void ScrollState::DistributeToScrollChainDescendant() { + if (!scroll_chain_.empty()) { + LayerImpl* next = scroll_chain_.front(); + scroll_chain_.pop_front(); + next->DistributeScroll(this); + } +} + +} // namespace cc diff --git a/chromium/cc/input/scroll_state.h b/chromium/cc/input/scroll_state.h new file mode 100644 index 00000000000..2cd437d0ea7 --- /dev/null +++ b/chromium/cc/input/scroll_state.h @@ -0,0 +1,108 @@ +// 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_INPUT_SCROLL_STATE_H_ +#define CC_INPUT_SCROLL_STATE_H_ + +#include <list> + +#include "cc/base/cc_export.h" + +namespace cc { + +class LayerImpl; + +// ScrollState is based on the proposal for scroll customization in blink, found +// here: https://goo.gl/1ipTpP. +class CC_EXPORT ScrollState { + public: + ScrollState(double delta_x, + double delta_y, + int start_position_x, + int start_position_y, + bool should_propagate, + bool delta_consumed_for_scroll_sequence, + bool is_direct_manipulation); + ~ScrollState(); + + // Reduce deltas by x, y. + void ConsumeDelta(double x, double y); + // Pops the first layer off of |scroll_chain_| and calls + // |DistributeScroll| on it. + void DistributeToScrollChainDescendant(); + // Positive when scrolling left. + double delta_x() const { return delta_x_; } + // Positive when scrolling up. + double delta_y() const { return delta_y_; } + // The location the scroll started at. For touch, the starting + // position of the finger. For mouse, the location of the cursor. + int start_position_x() const { return start_position_x_; } + int start_position_y() const { return start_position_y_; } + + // True if this scroll is allowed to bubble upwards. + bool should_propagate() const { return should_propagate_; } + // True if the user interacts directly with the screen, e.g., via touch. + bool is_direct_manipulation() const { return is_direct_manipulation_; } + + void set_scroll_chain(const std::list<LayerImpl*>& scroll_chain) { + scroll_chain_ = scroll_chain; + } + + void set_current_native_scrolling_layer(LayerImpl* layer) { + current_native_scrolling_layer_ = layer; + } + + LayerImpl* current_native_scrolling_layer() const { + return current_native_scrolling_layer_; + } + + bool delta_consumed_for_scroll_sequence() const { + return delta_consumed_for_scroll_sequence_; + } + + bool FullyConsumed() const { return !delta_x_ && !delta_y_; } + + void set_caused_scroll(bool x, bool y) { + caused_scroll_x_ |= x; + caused_scroll_y_ |= y; + } + + bool caused_scroll_x() const { return caused_scroll_x_; } + bool caused_scroll_y() const { return caused_scroll_y_; } + + private: + ScrollState(); + double delta_x_; + double delta_y_; + double start_position_x_; + double start_position_y_; + + bool should_propagate_; + + // The last layer to respond to a scroll, or null if none exists. + LayerImpl* current_native_scrolling_layer_; + // Whether the scroll sequence has had any delta consumed, in the + // current frame, or any child frames. + bool delta_consumed_for_scroll_sequence_; + // True if the user interacts directly with the display, e.g., via + // touch. + bool is_direct_manipulation_; + // TODO(tdresser): ScrollState shouldn't need to keep track of whether or not + // this ScrollState object has caused a scroll. Ideally, any native scroller + // consuming delta has caused a scroll. Currently, there are some cases where + // we consume delta without scrolling, such as in + // |Viewport::AdjustOverscroll|. Once these cases are fixed, we should get rid + // of |caused_scroll_*_|. See crbug.com/510045 for details. + bool caused_scroll_x_; + bool caused_scroll_y_; + + // TODO(tdresser): Change LayerImpl* to an abstract scrollable type. See + // crbug.com/476553 for detail on the effort to unify impl and main thread + // scrolling, which will require an abstract scrollable type. + std::list<LayerImpl*> scroll_chain_; +}; + +} // namespace cc + +#endif // CC_INPUT_SCROLL_STATE_H_ diff --git a/chromium/cc/input/scroll_state_unittest.cc b/chromium/cc/input/scroll_state_unittest.cc new file mode 100644 index 00000000000..5e091df685f --- /dev/null +++ b/chromium/cc/input/scroll_state_unittest.cc @@ -0,0 +1,79 @@ +// 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/input/scroll_state.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/test/test_task_graph_runner.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { + +class ScrollStateTest : public testing::Test {}; + +TEST_F(ScrollStateTest, ConsumeDeltaNative) { + const float delta_x = 12.3f; + const float delta_y = 3.9f; + + const float delta_x_to_consume = 1.2f; + const float delta_y_to_consume = 2.3f; + + ScrollState scrollState(delta_x, delta_y, 0, 0, false /* should_propagate */, + false /* delta_consumed_for_scroll_sequence */, + false /* is_direct_manipulation */); + EXPECT_FLOAT_EQ(delta_x, scrollState.delta_x()); + EXPECT_FLOAT_EQ(delta_y, scrollState.delta_y()); + EXPECT_FALSE(scrollState.delta_consumed_for_scroll_sequence()); + EXPECT_FALSE(scrollState.FullyConsumed()); + + scrollState.ConsumeDelta(0, 0); + EXPECT_FLOAT_EQ(delta_x, scrollState.delta_x()); + EXPECT_FLOAT_EQ(delta_y, scrollState.delta_y()); + EXPECT_FALSE(scrollState.delta_consumed_for_scroll_sequence()); + EXPECT_FALSE(scrollState.FullyConsumed()); + + scrollState.ConsumeDelta(delta_x_to_consume, 0); + EXPECT_FLOAT_EQ(delta_x - delta_x_to_consume, scrollState.delta_x()); + EXPECT_FLOAT_EQ(delta_y, scrollState.delta_y()); + EXPECT_TRUE(scrollState.delta_consumed_for_scroll_sequence()); + EXPECT_FALSE(scrollState.FullyConsumed()); + + scrollState.ConsumeDelta(0, delta_y_to_consume); + EXPECT_FLOAT_EQ(delta_x - delta_x_to_consume, scrollState.delta_x()); + EXPECT_FLOAT_EQ(delta_y - delta_y_to_consume, scrollState.delta_y()); + EXPECT_TRUE(scrollState.delta_consumed_for_scroll_sequence()); + EXPECT_FALSE(scrollState.FullyConsumed()); + + scrollState.ConsumeDelta(scrollState.delta_x(), scrollState.delta_y()); + EXPECT_TRUE(scrollState.delta_consumed_for_scroll_sequence()); + EXPECT_TRUE(scrollState.FullyConsumed()); +} + +TEST_F(ScrollStateTest, CurrentNativeScrollingScrollable) { + ScrollState scrollState(0, 0, 0, 0, false, false, false); + + FakeImplProxy proxy; + TestSharedBitmapManager shared_bitmap_manager; + TestTaskGraphRunner task_graph_runner; + FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, + &task_graph_runner); + + scoped_ptr<LayerImpl> layer_impl = + LayerImpl::Create(host_impl.active_tree(), 1); + scrollState.set_current_native_scrolling_layer(layer_impl.get()); + EXPECT_EQ(layer_impl, scrollState.current_native_scrolling_layer()); +} + +TEST_F(ScrollStateTest, FullyConsumed) { + ScrollState scrollState(1, 3, 0, 0, 0, false, false); + EXPECT_FALSE(scrollState.FullyConsumed()); + + scrollState.ConsumeDelta(1, 3); + EXPECT_TRUE(scrollState.FullyConsumed()); +} +} // namespace cc diff --git a/chromium/cc/layers/content_layer_client.h b/chromium/cc/layers/content_layer_client.h index 3a56263248d..deb9d619e32 100644 --- a/chromium/cc/layers/content_layer_client.h +++ b/chromium/cc/layers/content_layer_client.h @@ -37,6 +37,12 @@ class CC_EXPORT ContentLayerClient { // because it will cover any uncleared data with content. virtual bool FillsBoundsCompletely() const = 0; + // Returns an estimate of the current memory usage within this object, + // excluding memory shared with painting artifacts (i.e., + // DisplayItemList). Should be invoked after PaintContentsToDisplayList, + // so that the result includes data cached internally during painting. + virtual size_t GetApproximateUnsharedMemoryUsage() const = 0; + protected: virtual ~ContentLayerClient() {} }; diff --git a/chromium/cc/layers/delegated_frame_provider.cc b/chromium/cc/layers/delegated_frame_provider.cc index bae5e438c0a..5e016ebc6ac 100644 --- a/chromium/cc/layers/delegated_frame_provider.cc +++ b/chromium/cc/layers/delegated_frame_provider.cc @@ -33,7 +33,7 @@ void DelegatedFrameProvider::AddObserver(DelegatedRendererLayer* layer) { DCHECK(observers_[i].layer != layer); #endif - observers_.push_back(Observer(layer, gfx::RectF(frame_size_))); + observers_.push_back(Observer(layer, gfx::Rect(frame_size_))); DCHECK(frame_) << "Must have a frame when given to a DelegatedRendererLayer."; } @@ -80,15 +80,14 @@ void DelegatedFrameProvider::SetFrameData( DelegatedFrameData* DelegatedFrameProvider::GetFrameDataAndRefResources( DelegatedRendererLayer* observer, - gfx::RectF* damage) { - + gfx::Rect* damage) { bool found_observer = false; for (size_t i = 0; i < observers_.size(); ++i) { if (observers_[i].layer != observer) continue; *damage = observers_[i].damage; // The observer is now responsible for the damage. - observers_[i].damage = gfx::RectF(); + observers_[i].damage = gfx::Rect(); found_observer = true; } DCHECK(found_observer); diff --git a/chromium/cc/layers/delegated_frame_provider.h b/chromium/cc/layers/delegated_frame_provider.h index 3bcf91957c8..f3f93732a6e 100644 --- a/chromium/cc/layers/delegated_frame_provider.h +++ b/chromium/cc/layers/delegated_frame_provider.h @@ -12,7 +12,7 @@ #include "cc/base/cc_export.h" #include "cc/resources/return_callback.h" #include "cc/resources/returned_resource.h" -#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" namespace cc { @@ -41,7 +41,7 @@ class CC_EXPORT DelegatedFrameProvider // lose track of damage. DelegatedFrameData* GetFrameDataAndRefResources( DelegatedRendererLayer* observer, - gfx::RectF* damage); + gfx::Rect* damage); ReturnCallback GetReturnResourcesCallbackForImplThread(); void UnrefResourcesOnMainThread(const ReturnedResourceArray& unused); @@ -58,9 +58,9 @@ class CC_EXPORT DelegatedFrameProvider struct Observer { DelegatedRendererLayer* layer; - gfx::RectF damage; + gfx::Rect damage; - Observer(DelegatedRendererLayer* layer, const gfx::RectF& damage) + Observer(DelegatedRendererLayer* layer, const gfx::Rect& damage) : layer(layer), damage(damage) {} }; std::vector<Observer> observers_; diff --git a/chromium/cc/layers/delegated_frame_provider_unittest.cc b/chromium/cc/layers/delegated_frame_provider_unittest.cc index 3aef0d18c7d..4248899641a 100644 --- a/chromium/cc/layers/delegated_frame_provider_unittest.cc +++ b/chromium/cc/layers/delegated_frame_provider_unittest.cc @@ -159,20 +159,20 @@ TEST_F(DelegatedFrameProviderTest, RefResources) { scoped_refptr<DelegatedRendererLayer> observer2 = DelegatedRendererLayer::Create(layer_settings_, frame_provider_); - gfx::RectF damage; + gfx::Rect damage; // Both observers get a full frame of damage on the first request. frame_provider_->GetFrameDataAndRefResources(observer1.get(), &damage); - EXPECT_EQ(gfx::RectF(5.f, 5.f).ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(5, 5), damage); frame_provider_->GetFrameDataAndRefResources(observer2.get(), &damage); - EXPECT_EQ(gfx::RectF(5.f, 5.f).ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(5, 5), damage); // And both get no damage on the 2nd request. This adds a second ref to the // resources. frame_provider_->GetFrameDataAndRefResources(observer1.get(), &damage); - EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(), damage); frame_provider_->GetFrameDataAndRefResources(observer2.get(), &damage); - EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(), damage); EXPECT_FALSE(ReturnAndResetResourcesAvailable()); @@ -217,7 +217,7 @@ TEST_F(DelegatedFrameProviderTest, RefResourcesInFrameProvider) { scoped_refptr<DelegatedRendererLayer> observer2 = DelegatedRendererLayer::Create(layer_settings_, frame_provider_); - gfx::RectF damage; + gfx::Rect damage; // Take a ref on each observer. frame_provider_->GetFrameDataAndRefResources(observer1.get(), &damage); @@ -259,7 +259,7 @@ TEST_F(DelegatedFrameProviderTest, RefResourcesInFrameProviderUntilDestroy) { scoped_refptr<DelegatedRendererLayer> observer2 = DelegatedRendererLayer::Create(layer_settings_, frame_provider_); - gfx::RectF damage; + gfx::Rect damage; // Take a ref on each observer. frame_provider_->GetFrameDataAndRefResources(observer1.get(), &damage); @@ -303,19 +303,19 @@ TEST_F(DelegatedFrameProviderTest, Damage) { scoped_refptr<DelegatedRendererLayer> observer2 = DelegatedRendererLayer::Create(layer_settings_, frame_provider_); - gfx::RectF damage; + gfx::Rect damage; // Both observers get a full frame of damage on the first request. frame_provider_->GetFrameDataAndRefResources(observer1.get(), &damage); - EXPECT_EQ(gfx::RectF(5.f, 5.f).ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(5, 5), damage); frame_provider_->GetFrameDataAndRefResources(observer2.get(), &damage); - EXPECT_EQ(gfx::RectF(5.f, 5.f).ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(5, 5), damage); // And both get no damage on the 2nd request. frame_provider_->GetFrameDataAndRefResources(observer1.get(), &damage); - EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(), damage); frame_provider_->GetFrameDataAndRefResources(observer2.get(), &damage); - EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(), damage); frame = CreateFrameData(gfx::Rect(5, 5), gfx::Rect(2, 2)); AddTextureQuad(frame.get(), 555); @@ -324,15 +324,15 @@ TEST_F(DelegatedFrameProviderTest, Damage) { // Both observers get the damage for the new frame. frame_provider_->GetFrameDataAndRefResources(observer1.get(), &damage); - EXPECT_EQ(gfx::RectF(2.f, 2.f).ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(2, 2), damage); frame_provider_->GetFrameDataAndRefResources(observer2.get(), &damage); - EXPECT_EQ(gfx::RectF(2.f, 2.f).ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(2, 2), damage); // And both get no damage on the 2nd request. frame_provider_->GetFrameDataAndRefResources(observer1.get(), &damage); - EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(), damage); frame_provider_->GetFrameDataAndRefResources(observer2.get(), &damage); - EXPECT_EQ(gfx::RectF().ToString(), damage.ToString()); + EXPECT_EQ(gfx::Rect(), damage); } TEST_F(DelegatedFrameProviderTest, LostNothing) { diff --git a/chromium/cc/layers/delegated_renderer_layer.cc b/chromium/cc/layers/delegated_renderer_layer.cc index b48d1eae91e..4c0e3cca9da 100644 --- a/chromium/cc/layers/delegated_renderer_layer.cc +++ b/chromium/cc/layers/delegated_renderer_layer.cc @@ -72,7 +72,7 @@ void DelegatedRendererLayer::PushPropertiesTo(LayerImpl* impl) { if (frame_data_) delegated_impl->SetFrameData(frame_data_, frame_damage_); frame_data_ = nullptr; - frame_damage_ = gfx::RectF(); + frame_damage_ = gfx::Rect(); } void DelegatedRendererLayer::ProviderHasNewFrame() { diff --git a/chromium/cc/layers/delegated_renderer_layer.h b/chromium/cc/layers/delegated_renderer_layer.h index 124b389a0f7..8845258895c 100644 --- a/chromium/cc/layers/delegated_renderer_layer.h +++ b/chromium/cc/layers/delegated_renderer_layer.h @@ -44,7 +44,7 @@ class CC_EXPORT DelegatedRendererLayer : public Layer { bool should_collect_new_frame_; DelegatedFrameData* frame_data_; - gfx::RectF frame_damage_; + gfx::Rect frame_damage_; base::WeakPtrFactory<DelegatedRendererLayer> weak_ptrs_; diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.cc b/chromium/cc/layers/delegated_renderer_layer_impl.cc index 9235af5a826..9b3a513206c 100644 --- a/chromium/cc/layers/delegated_renderer_layer_impl.cc +++ b/chromium/cc/layers/delegated_renderer_layer_impl.cc @@ -87,7 +87,7 @@ void DelegatedRendererLayerImpl::CreateChildIdIfNeeded( void DelegatedRendererLayerImpl::SetFrameData( const DelegatedFrameData* frame_data, - const gfx::RectF& damage_in_frame) { + const gfx::Rect& damage_in_frame) { DCHECK(child_id_) << "CreateChildIdIfNeeded must be called first."; DCHECK(frame_data); DCHECK(!frame_data->render_pass_list.empty()); @@ -153,11 +153,10 @@ void DelegatedRendererLayerImpl::SetFrameData( // the frame, so intersect the damage to the layer's bounds. RenderPass* new_root_pass = render_pass_list.back(); gfx::Size frame_size = new_root_pass->output_rect.size(); - gfx::RectF damage_in_layer = damage_in_frame; - damage_in_layer.Scale(inverse_device_scale_factor_); + gfx::Rect damage_in_layer = + gfx::ScaleToEnclosingRect(damage_in_frame, inverse_device_scale_factor_); SetUpdateRect(gfx::IntersectRects( - gfx::UnionRects(update_rect(), gfx::ToEnclosingRect(damage_in_layer)), - gfx::Rect(bounds()))); + gfx::UnionRects(update_rect(), damage_in_layer), gfx::Rect(bounds()))); SetRenderPasses(&render_pass_list); have_render_passes_to_push_ = true; diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.h b/chromium/cc/layers/delegated_renderer_layer_impl.h index 2543894c5d4..e59c3ac8760 100644 --- a/chromium/cc/layers/delegated_renderer_layer_impl.h +++ b/chromium/cc/layers/delegated_renderer_layer_impl.h @@ -45,7 +45,7 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl { void CreateChildIdIfNeeded(const ReturnCallback& return_callback); void SetFrameData(const DelegatedFrameData* frame_data, - const gfx::RectF& damage_in_frame); + const gfx::Rect& damage_in_frame); float inverse_device_scale_factor() const { return inverse_device_scale_factor_; diff --git a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc index a2e8d704725..5deef6c11bc 100644 --- a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc +++ b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc @@ -15,7 +15,6 @@ #include "cc/test/fake_output_surface.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" @@ -33,13 +32,14 @@ class DelegatedRendererLayerImplTest : public testing::Test { public: DelegatedRendererLayerImplTest() : proxy_(), - always_impl_thread_and_main_thread_blocked_(&proxy_) { + always_impl_thread_and_main_thread_blocked_(&proxy_), + output_surface_(FakeOutputSurface::Create3d()) { LayerTreeSettings settings; settings.minimum_occlusion_tracking_size = gfx::Size(); host_impl_.reset(new FakeLayerTreeHostImpl( settings, &proxy_, &shared_bitmap_manager_, &task_graph_runner_)); - host_impl_->InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl_->InitializeRenderer(output_surface_.get()); host_impl_->SetViewportSize(gfx::Size(10, 10)); } @@ -49,6 +49,7 @@ class DelegatedRendererLayerImplTest : public testing::Test { always_impl_thread_and_main_thread_blocked_; TestSharedBitmapManager shared_bitmap_manager_; TestTaskGraphRunner task_graph_runner_; + scoped_ptr<OutputSurface> output_surface_; scoped_ptr<LayerTreeHostImpl> host_impl_; }; @@ -88,21 +89,18 @@ class DelegatedRendererLayerImplTestSimple 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)); + RenderPass* 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)); + RenderPass* 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)); + RenderPass* 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); @@ -152,16 +150,16 @@ TEST_F(DelegatedRendererLayerImplTest, delegated_renderer_layer->SetTransform(transform); RenderPassList delegated_render_passes; - TestRenderPass* pass1 = + RenderPass* 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 = + RenderPass* 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 = + RenderPass* 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); @@ -231,16 +229,16 @@ TEST_F(DelegatedRendererLayerImplTest, delegated_renderer_layer->SetTransform(transform); RenderPassList delegated_render_passes; - TestRenderPass* pass1 = + RenderPass* 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 = + RenderPass* 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 = + RenderPass* 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); @@ -615,7 +613,7 @@ class DelegatedRendererLayerImplTestTransform delegated_device_scale_factor_(2.f) {} void SetUpTest() { - host_impl_->SetDeviceScaleFactor(2.f); + host_impl_->active_tree()->SetDeviceScaleFactor(2.f); scoped_ptr<LayerImpl> root_layer = LayerImpl::Create( host_impl_->active_tree(), 1); @@ -645,10 +643,9 @@ class DelegatedRendererLayerImplTestTransform bool child_pass_clipped = false; { - TestRenderPass* pass = AddRenderPass(&delegated_render_passes, - RenderPassId(10, 7), - child_pass_rect, - gfx::Transform()); + RenderPass* pass = + AddRenderPass(&delegated_render_passes, RenderPassId(10, 7), + child_pass_rect, gfx::Transform()); SharedQuadState* shared_quad_state = pass->CreateAndAppendSharedQuadState(); shared_quad_state->SetAll(child_pass_transform, child_pass_bounds, @@ -680,10 +677,9 @@ class DelegatedRendererLayerImplTestTransform gfx::Rect root_pass_clip_rect(10, 10, 35, 35); bool root_pass_clipped = root_delegated_render_pass_is_clipped_; - TestRenderPass* pass = AddRenderPass(&delegated_render_passes, - RenderPassId(9, 6), - root_pass_rect, - gfx::Transform()); + RenderPass* pass = + AddRenderPass(&delegated_render_passes, RenderPassId(9, 6), + root_pass_rect, gfx::Transform()); SharedQuadState* shared_quad_state = pass->CreateAndAppendSharedQuadState(); shared_quad_state->SetAll(root_pass_transform, root_pass_bounds, root_pass_rect, root_pass_clip_rect, @@ -1067,10 +1063,9 @@ class DelegatedRendererLayerImplTestClip bool child_pass_clipped = false; { - TestRenderPass* pass = AddRenderPass(&delegated_render_passes, - RenderPassId(10, 7), - child_pass_rect, - gfx::Transform()); + RenderPass* pass = + AddRenderPass(&delegated_render_passes, RenderPassId(10, 7), + child_pass_rect, gfx::Transform()); SharedQuadState* shared_quad_state = pass->CreateAndAppendSharedQuadState(); shared_quad_state->SetAll(child_pass_transform, child_pass_bounds, @@ -1100,10 +1095,9 @@ class DelegatedRendererLayerImplTestClip gfx::Rect root_pass_clip_rect(5, 5, 40, 40); bool root_pass_clipped = root_delegated_render_pass_is_clipped_; - TestRenderPass* pass = AddRenderPass(&delegated_render_passes, - RenderPassId(9, 6), - root_pass_rect, - gfx::Transform()); + RenderPass* pass = + AddRenderPass(&delegated_render_passes, RenderPassId(9, 6), + root_pass_rect, gfx::Transform()); SharedQuadState* shared_quad_state = pass->CreateAndAppendSharedQuadState(); shared_quad_state->SetAll(root_pass_transform, root_pass_bounds, root_pass_rect, root_pass_clip_rect, @@ -1250,6 +1244,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, SetUpTest(); LayerTreeHostImpl::FrameData frame; + host_impl_->active_tree()->BuildPropertyTreesForTesting(); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); ASSERT_EQ(2u, frame.render_passes.size()); @@ -1280,6 +1275,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, SetUpTest(); LayerTreeHostImpl::FrameData frame; + host_impl_->active_tree()->BuildPropertyTreesForTesting(); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); ASSERT_EQ(2u, frame.render_passes.size()); @@ -1370,6 +1366,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, delegated_renderer_layer_->SetHasRenderSurface(true); LayerTreeHostImpl::FrameData frame; + host_impl_->active_tree()->BuildPropertyTreesForTesting(); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); ASSERT_EQ(3u, frame.render_passes.size()); @@ -1398,6 +1395,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, QuadsClipped_LayerClipped_Surface) { delegated_renderer_layer_->SetHasRenderSurface(true); LayerTreeHostImpl::FrameData frame; + host_impl_->active_tree()->BuildPropertyTreesForTesting(); EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); ASSERT_EQ(3u, frame.render_passes.size()); @@ -1443,17 +1441,14 @@ TEST_F(DelegatedRendererLayerImplTest, Occlusion) { // 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); + RenderPass* 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()); + RenderPass* pass1 = AddRenderPass(&delegated_render_passes, pass1_id, + gfx::Rect(layer_size), gfx::Transform()); AddRenderPassQuad(pass1, pass2, 0, @@ -1610,15 +1605,14 @@ TEST_F(DelegatedRendererLayerImplTest, DeviceScaleFactorOcclusion) { // translation of (211,300). RenderPassId pass2_id = delegated_renderer_layer_impl->FirstContributingRenderPassId(); - TestRenderPass* pass2 = + RenderPass* 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()); + RenderPass* 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( diff --git a/chromium/cc/layers/draw_properties.cc b/chromium/cc/layers/draw_properties.cc new file mode 100644 index 00000000000..7fd380a4b7b --- /dev/null +++ b/chromium/cc/layers/draw_properties.cc @@ -0,0 +1,23 @@ +// 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/draw_properties.h" + +namespace cc { + +DrawProperties::DrawProperties() + : opacity(0.f), + screen_space_transform_is_animating(false), + can_use_lcd_text(false), + is_clipped(false), + render_target(nullptr), + num_unclipped_descendants(0), + has_child_with_a_scroll_parent(false), + last_drawn_render_surface_layer_list_id(0), + maximum_animation_contents_scale(0.f), + starting_animation_contents_scale(0.f) {} + +DrawProperties::~DrawProperties() {} + +} // namespace cc diff --git a/chromium/cc/layers/draw_properties.h b/chromium/cc/layers/draw_properties.h index 5a07af04e32..bcab91036be 100644 --- a/chromium/cc/layers/draw_properties.h +++ b/chromium/cc/layers/draw_properties.h @@ -12,32 +12,13 @@ #include "ui/gfx/transform.h" namespace cc { +class LayerImpl; // Container for properties that layers need to compute before they can be // drawn. -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), - screen_space_transform_is_animating(false), - can_use_lcd_text(false), - is_clipped(false), - render_target(nullptr), - num_unclipped_descendants(0), - layer_or_descendant_has_copy_request(false), - layer_or_descendant_has_input_handler(false), - has_child_with_a_scroll_parent(false), - index_of_first_descendants_addition(0), - num_descendants_added(0), - index_of_first_render_surface_layer_list_addition(0), - num_render_surfaces_added(0), - last_drawn_render_surface_layer_list_id(0), - maximum_animation_contents_scale(0.f), - starting_animation_contents_scale(0.f) {} + DrawProperties(); + ~DrawProperties(); // Transforms objects from content space to target surface space, where // this layer would be drawn. @@ -49,22 +30,15 @@ struct CC_EXPORT DrawProperties { // 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, + // DrawProperties::opacity may be different than LayerImpl::opacity, // particularly in the case when a RenderSurface re-parents the layer's // opacity, or when opacity is compounded by the hierarchy. float opacity; - // 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 // to draw. - bool opacity_is_animating; - bool screen_space_opacity_is_animating; - bool target_space_transform_is_animating; bool screen_space_transform_is_animating; // True if the layer can use LCD text. @@ -76,7 +50,7 @@ struct CC_EXPORT DrawProperties { // The layer whose coordinate space this layer draws into. This can be // either the same layer (draw_properties_.render_target == this) or an // ancestor of this layer. - LayerType* render_target; + LayerImpl* render_target; // This rect is a bounding box around what part of the layer is visible, in // the layer's coordinate space. @@ -94,27 +68,12 @@ struct CC_EXPORT DrawProperties { // does not include our clip children because they are clipped by us. size_t num_unclipped_descendants; - // If true, the layer or some layer in its sub-tree has a CopyOutputRequest - // present on it. - bool layer_or_descendant_has_copy_request; - - // If true, the layer or one of its descendants has a wheel or touch handler. - bool layer_or_descendant_has_input_handler; - // 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 // children have scroll parents, we will not need to recur out of order. bool has_child_with_a_scroll_parent; - // 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. - size_t index_of_first_descendants_addition; - size_t num_descendants_added; - size_t index_of_first_render_surface_layer_list_addition; - size_t num_render_surfaces_added; - // Each time we generate a new render surface layer list, an ID is used to // identify it. |last_drawn_render_surface_layer_list_id| is set to the ID // that marked the render surface layer list generation which last updated diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc index dffa6d18d65..1f765091381 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.cc +++ b/chromium/cc/layers/heads_up_display_layer_impl.cc @@ -13,7 +13,6 @@ #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" #include "cc/output/begin_frame_args.h" #include "cc/output/renderer.h" #include "cc/quads/texture_draw_quad.h" @@ -22,6 +21,7 @@ #include "cc/trees/layer_tree_impl.h" #include "skia/ext/platform_canvas.h" #include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkTypeface.h" #include "third_party/skia/include/effects/SkColorMatrixFilter.h" #include "ui/gfx/geometry/point.h" @@ -132,7 +132,7 @@ bool HeadsUpDisplayLayerImpl::WillDraw(DrawMode draw_mode, internal_contents_scale_ = GetIdealContentsScale(); internal_content_bounds_ = - gfx::ToCeiledSize(gfx::ScaleSize(bounds(), internal_contents_scale_)); + gfx::ScaleToCeiledSize(bounds(), internal_contents_scale_); ReleaseUnmatchedSizeResources(resource_provider); AcquireResource(resource_provider); @@ -244,20 +244,6 @@ void HeadsUpDisplayLayerImpl::UpdateHudContents() { fps_counter->GetMinAndMaxFPS(&fps_graph_.min, &fps_graph_.max); } - if (debug_state.continuous_painting) { - PaintTimeCounter* paint_time_counter = - layer_tree_impl()->paint_time_counter(); - base::TimeDelta latest, min, max; - - if (paint_time_counter->End()) - latest = **paint_time_counter->End(); - paint_time_counter->GetMinAndMaxPaintTime(&min, &max); - - paint_time_graph_.value = latest.InMillisecondsF(); - paint_time_graph_.min = min.InMillisecondsF(); - paint_time_graph_.max = max.InMillisecondsF(); - } - if (debug_state.ShowMemoryStats()) { MemoryHistory* memory_history = layer_tree_impl()->memory_history(); if (memory_history->End()) @@ -281,21 +267,13 @@ void HeadsUpDisplayLayerImpl::DrawHudContents(SkCanvas* canvas) { } } - SkRect area = SkRect::MakeEmpty(); - if (debug_state.continuous_painting) { - area = DrawPaintTimeDisplay( - canvas, layer_tree_impl()->paint_time_counter(), 0, 0); - } else if (debug_state.show_fps_counter) { - // Don't show the FPS display when continuous painting is enabled, because - // it would show misleading numbers. - area = - DrawFPSDisplay(canvas, layer_tree_impl()->frame_rate_counter(), 0, 0); - } + if (!debug_state.show_fps_counter) + return; - if (debug_state.show_fps_counter || debug_state.continuous_painting) { - area = DrawGpuRasterizationStatus(canvas, 0, area.bottom(), - SkMaxScalar(area.width(), 150)); - } + SkRect area = + DrawFPSDisplay(canvas, layer_tree_impl()->frame_rate_counter(), 0, 0); + area = DrawGpuRasterizationStatus(canvas, 0, area.bottom(), + SkMaxScalar(area.width(), 150)); if (debug_state.ShowMemoryStats()) DrawMemoryDisplay(canvas, 0, area.bottom(), SkMaxScalar(area.width(), 150)); @@ -620,92 +598,6 @@ SkRect HeadsUpDisplayLayerImpl::DrawGpuRasterizationStatus(SkCanvas* canvas, return area; } -SkRect HeadsUpDisplayLayerImpl::DrawPaintTimeDisplay( - SkCanvas* canvas, - const PaintTimeCounter* paint_time_counter, - int right, - int top) const { - const int kPadding = 4; - const int kFontHeight = 14; - - const int kGraphWidth = - base::saturated_cast<int>(paint_time_counter->HistorySize()); - const int kGraphHeight = 40; - - 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); - - DrawGraphBackground(canvas, &paint, area); - - 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); - - const std::string value_text = - base::StringPrintf("%.1f", paint_time_graph_.value); - const std::string min_max_text = base::StringPrintf( - "%.1f-%.1f", paint_time_graph_.min, paint_time_graph_.max); - - paint.setColor(DebugColors::PaintTimeDisplayTextAndGraphColor()); - DrawText(canvas, &paint, title, SkPaint::kLeft_Align, kFontHeight, - text_bounds.left(), text_bounds.bottom()); - DrawText(canvas, - &paint, - value_text, - SkPaint::kLeft_Align, - kFontHeight, - text_bounds2.left(), - text_bounds2.bottom()); - DrawText(canvas, - &paint, - min_max_text, - SkPaint::kRight_Align, - kFontHeight, - text_bounds2.right(), - text_bounds2.bottom()); - - paint.setColor(DebugColors::PaintTimeDisplayTextAndGraphColor()); - for (PaintTimeCounter::RingBufferType::Iterator it = - paint_time_counter->End(); - it; - --it) { - double pt = it->InMillisecondsF(); - - if (pt == 0.0) - continue; - - double p = pt / paint_time_graph_.current_upper_bound; - if (p > 1.0) - p = 1.0; - - canvas->drawRect( - SkRect::MakeXYWH(graph_bounds.left() + it.index(), - graph_bounds.bottom() - p * graph_bounds.height(), - 1, - p * graph_bounds.height()), - paint); - } - - DrawGraphLines(canvas, &paint, graph_bounds, paint_time_graph_); - - return area; -} - void HeadsUpDisplayLayerImpl::DrawDebugRect( SkCanvas* canvas, SkPaint* paint, diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h index 299d91eb19d..0663b825417 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.h +++ b/chromium/cc/layers/heads_up_display_layer_impl.h @@ -111,10 +111,6 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl { int right, int top, int width) const; - SkRect DrawPaintTimeDisplay(SkCanvas* canvas, - const PaintTimeCounter* paint_time_counter, - int top, - int right) const; void DrawDebugRect(SkCanvas* canvas, SkPaint* paint, const DebugRect& rect, 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 ad2215595aa..ef377838571 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc +++ b/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc @@ -34,10 +34,11 @@ TEST(HeadsUpDisplayLayerImplTest, ResourcelessSoftwareDrawAfterResourceLoss) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, &task_graph_runner); host_impl.CreatePendingTree(); - host_impl.InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl.InitializeRenderer(output_surface.get()); scoped_ptr<HeadsUpDisplayLayerImpl> layer = HeadsUpDisplayLayerImpl::Create(host_impl.pending_tree(), 1); layer->SetBounds(gfx::Size(100, 100)); diff --git a/chromium/cc/layers/io_surface_layer_impl.cc b/chromium/cc/layers/io_surface_layer_impl.cc index 234d3f3a767..902a73d65b0 100644 --- a/chromium/cc/layers/io_surface_layer_impl.cc +++ b/chromium/cc/layers/io_surface_layer_impl.cc @@ -85,7 +85,8 @@ void IOSurfaceLayerImpl::AppendQuads( visible_quad_rect, io_surface_size_, io_surface_resource_id_, - IOSurfaceDrawQuad::FLIPPED); + IOSurfaceDrawQuad::FLIPPED, + false); ValidateQuadResources(quad); } diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc index b9867d6217c..4b9162ff5ce 100644 --- a/chromium/cc/layers/layer.cc +++ b/chromium/cc/layers/layer.cc @@ -24,6 +24,7 @@ #include "cc/layers/scrollbar_layer_interface.h" #include "cc/output/copy_output_request.h" #include "cc/output/copy_output_result.h" +#include "cc/trees/draw_property_utils.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_impl.h" #include "third_party/skia/include/core/SkImageFilter.h" @@ -51,12 +52,10 @@ Layer::Layer(const LayerSettings& settings) scroll_clip_layer_id_(INVALID_ID), num_descendants_that_draw_content_(0), transform_tree_index_(-1), - opacity_tree_index_(-1), + effect_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), - num_children_with_scroll_parent_(0), should_flatten_transform_from_property_tree_(false), should_scroll_on_main_thread_(false), have_wheel_event_handlers_(false), @@ -73,7 +72,6 @@ Layer::Layer(const LayerSettings& settings) double_sided_(true), should_flatten_transform_(true), use_parent_backface_visibility_(false), - draw_checkerboard_for_missing_tiles_(false), force_render_surface_(false), transform_is_invertible_(true), has_render_surface_(false), @@ -81,6 +79,7 @@ Layer::Layer(const LayerSettings& settings) background_color_(0), opacity_(1.f), blend_mode_(SkXfermode::kSrcOver_Mode), + draw_blend_mode_(SkXfermode::kSrcOver_Mode), scroll_parent_(nullptr), layer_or_descendant_is_drawn_tracker_(0), sorted_for_recursion_tracker_(0), @@ -88,6 +87,7 @@ Layer::Layer(const LayerSettings& settings) clip_parent_(nullptr), replica_layer_(nullptr), client_(nullptr), + num_unclipped_descendants_(0), frame_timing_requests_dirty_(false) { if (!settings.use_compositor_animation_timelines) { layer_animation_controller_ = LayerAnimationController::Create(layer_id_); @@ -259,7 +259,15 @@ void Layer::SetParent(Layer* layer) { layer->AddDependentNeedsPushProperties(); } + if (parent_) { + parent_->UpdateNumCopyRequestsForSubtree( + -num_layer_or_descendants_with_copy_request_); + } parent_ = layer; + if (parent_) { + parent_->UpdateNumCopyRequestsForSubtree( + num_layer_or_descendants_with_copy_request_); + } SetLayerTreeHost(parent_ ? parent_->layer_tree_host() : nullptr); if (!layer_tree_host_) @@ -356,7 +364,7 @@ void Layer::SetBounds(const gfx::Size& size) { 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); + clip_node->data.clip.set_size(gfx::SizeF(size)); layer_tree_host_->property_trees()->clip_tree.set_needs_update(true); } } @@ -413,18 +421,17 @@ void Layer::RequestCopyOfOutput( return; copy_requests_.push_back(request.Pass()); if (had_no_copy_requests) { - bool copy_request_added = true; - UpdateNumCopyRequestsForSubtree(copy_request_added); + UpdateNumCopyRequestsForSubtree(1); } SetNeedsCommit(); } -void Layer::UpdateNumCopyRequestsForSubtree(bool add) { - int change = add ? 1 : -1; +void Layer::UpdateNumCopyRequestsForSubtree(int delta) { + if (!delta) + return; 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); + layer->num_layer_or_descendants_with_copy_request_ += delta; + layer->SetNeedsPushProperties(); DCHECK_GE(layer->num_layer_or_descendants_with_copy_request_, 0); } } @@ -510,11 +517,20 @@ void Layer::SetFilters(const FilterOperations& filters) { bool Layer::FilterIsAnimating() const { DCHECK(layer_tree_host_); return layer_animation_controller_ - ? layer_animation_controller_->IsAnimatingProperty( - Animation::FILTER) + ? layer_animation_controller_->IsCurrentlyAnimatingProperty( + Animation::FILTER, + LayerAnimationController::ObserverType::ACTIVE) : layer_tree_host_->IsAnimatingFilterProperty(this); } +bool Layer::HasPotentiallyRunningFilterAnimation() const { + if (layer_animation_controller_) { + return layer_animation_controller_->IsPotentiallyAnimatingProperty( + Animation::FILTER, LayerAnimationController::ObserverType::ACTIVE); + } + return layer_tree_host_->HasPotentiallyRunningFilterAnimation(this); +} + void Layer::SetBackgroundFilters(const FilterOperations& filters) { DCHECK(IsPropertyChangeAllowed()); if (background_filters_ == filters) @@ -534,22 +550,18 @@ void Layer::SetOpacity(float opacity) { bool Layer::OpacityIsAnimating() const { DCHECK(layer_tree_host_); return layer_animation_controller_ - ? layer_animation_controller_->IsAnimatingProperty( - Animation::OPACITY) + ? layer_animation_controller_->IsCurrentlyAnimatingProperty( + Animation::OPACITY, + LayerAnimationController::ObserverType::ACTIVE) : layer_tree_host_->IsAnimatingOpacityProperty(this); } bool Layer::HasPotentiallyRunningOpacityAnimation() const { if (layer_animation_controller_) { - if (Animation* animation = - layer_animation_controller()->GetAnimation(Animation::OPACITY)) { - return !animation->is_finished(); - } - return false; - } else { - DCHECK(layer_tree_host_); - return layer_tree_host_->HasPotentiallyRunningOpacityAnimation(this); + return layer_animation_controller_->IsPotentiallyAnimatingProperty( + Animation::OPACITY, LayerAnimationController::ObserverType::ACTIVE); } + return layer_tree_host_->HasPotentiallyRunningOpacityAnimation(this); } bool Layer::OpacityCanAnimateOnImplThread() const { @@ -742,22 +754,50 @@ bool Layer::AnimationsPreserveAxisAlignment() const { bool Layer::TransformIsAnimating() const { DCHECK(layer_tree_host_); return layer_animation_controller_ - ? layer_animation_controller_->IsAnimatingProperty( - Animation::TRANSFORM) + ? layer_animation_controller_->IsCurrentlyAnimatingProperty( + Animation::TRANSFORM, + LayerAnimationController::ObserverType::ACTIVE) : layer_tree_host_->IsAnimatingTransformProperty(this); } bool Layer::HasPotentiallyRunningTransformAnimation() const { if (layer_animation_controller_) { - if (Animation* animation = - layer_animation_controller()->GetAnimation(Animation::TRANSFORM)) { - return !animation->is_finished(); - } - return false; - } else { - DCHECK(layer_tree_host_); - return layer_tree_host_->HasPotentiallyRunningTransformAnimation(this); + return layer_animation_controller_->IsPotentiallyAnimatingProperty( + Animation::TRANSFORM, LayerAnimationController::ObserverType::ACTIVE); + } + return layer_tree_host_->HasPotentiallyRunningTransformAnimation(this); +} + +bool Layer::HasOnlyTranslationTransforms() const { + if (layer_animation_controller_) { + return layer_animation_controller_->HasOnlyTranslationTransforms( + LayerAnimationController::ObserverType::ACTIVE); } + return layer_tree_host_->HasOnlyTranslationTransforms(this); +} + +bool Layer::MaximumTargetScale(float* max_scale) const { + if (layer_animation_controller_) { + return layer_animation_controller_->MaximumTargetScale( + LayerAnimationController::ObserverType::ACTIVE, max_scale); + } + return layer_tree_host_->MaximumTargetScale(this, max_scale); +} + +bool Layer::AnimationStartScale(float* start_scale) const { + if (layer_animation_controller_) { + return layer_animation_controller_->AnimationStartScale( + LayerAnimationController::ObserverType::ACTIVE, start_scale); + } + return layer_tree_host_->AnimationStartScale(this, start_scale); +} + +bool Layer::HasAnyAnimationTargetingProperty( + Animation::TargetProperty property) const { + if (layer_animation_controller_) + return !!layer_animation_controller_->GetAnimation(property); + + return layer_tree_host_->HasAnyAnimationTargetingProperty(this, property); } bool Layer::ScrollOffsetAnimationWasInterrupted() const { @@ -788,10 +828,6 @@ void Layer::AddScrollChild(Layer* child) { if (!scroll_children_) scroll_children_.reset(new std::set<Layer*>); scroll_children_->insert(child); - if (layer_tree_host_ && !layer_tree_host_->needs_meta_info_recomputation()) { - num_children_with_scroll_parent_++; - draw_properties().has_child_with_a_scroll_parent = true; - } SetNeedsCommit(); } @@ -799,12 +835,6 @@ void Layer::RemoveScrollChild(Layer* child) { scroll_children_->erase(child); if (scroll_children_->empty()) scroll_children_ = nullptr; - if (layer_tree_host_ && !layer_tree_host_->needs_meta_info_recomputation()) { - num_children_with_scroll_parent_--; - DCHECK_GE(num_children_with_scroll_parent_, 0); - draw_properties().has_child_with_a_scroll_parent = - (num_children_with_scroll_parent_ != 0); - } SetNeedsCommit(); } @@ -939,24 +969,11 @@ 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) @@ -977,9 +994,6 @@ 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(); @@ -993,14 +1007,6 @@ void Layer::SetScrollBlocksOn(ScrollBlocksOn scroll_blocks_on) { SetNeedsCommit(); } -void Layer::SetDrawCheckerboardForMissingTiles(bool checkerboard) { - DCHECK(IsPropertyChangeAllowed()); - if (draw_checkerboard_for_missing_tiles_ == checkerboard) - return; - draw_checkerboard_for_missing_tiles_ = checkerboard; - SetNeedsCommit(); -} - void Layer::SetForceRenderSurface(bool force) { DCHECK(IsPropertyChangeAllowed()); if (force_render_surface_ == force) @@ -1059,28 +1065,28 @@ int Layer::clip_tree_index() const { return clip_tree_index_; } -void Layer::SetOpacityTreeIndex(int index) { +void Layer::SetEffectTreeIndex(int index) { DCHECK(IsPropertyChangeAllowed()); - if (opacity_tree_index_ == index) + if (effect_tree_index_ == index) return; - opacity_tree_index_ = index; + effect_tree_index_ = index; SetNeedsPushProperties(); } -int Layer::opacity_tree_index() const { +int Layer::effect_tree_index() const { if (!layer_tree_host_ || layer_tree_host_->property_trees()->sequence_number != property_tree_sequence_number_) { return -1; } - return opacity_tree_index_; + return effect_tree_index_; } void Layer::InvalidatePropertyTreesIndices() { int invalid_property_tree_index = -1; SetTransformTreeIndex(invalid_property_tree_index); SetClipTreeIndex(invalid_property_tree_index); - SetOpacityTreeIndex(invalid_property_tree_index); + SetEffectTreeIndex(invalid_property_tree_index); } void Layer::SetShouldFlattenTransform(bool should_flatten) { @@ -1182,12 +1188,10 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { layer->SetDebugInfo(TakeDebugInfo()); layer->SetTransformTreeIndex(transform_tree_index()); - layer->SetOpacityTreeIndex(opacity_tree_index()); + layer->SetEffectTreeIndex(effect_tree_index()); layer->SetClipTreeIndex(clip_tree_index()); layer->set_offset_to_transform_parent(offset_to_transform_parent_); layer->SetDoubleSided(double_sided_); - layer->SetDrawCheckerboardForMissingTiles( - draw_checkerboard_for_missing_tiles_); layer->SetDrawsContent(DrawsContent()); layer->SetHideLayerAndSubtree(hide_layer_and_subtree_); layer->SetHasRenderSurface(has_render_surface_); @@ -1215,6 +1219,9 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { layer->SetShouldFlattenTransform(should_flatten_transform_); layer->set_should_flatten_transform_from_property_tree( should_flatten_transform_from_property_tree_); + layer->set_num_layer_or_descendant_with_copy_request( + num_layer_or_descendants_with_copy_request_); + layer->set_draw_blend_mode(draw_blend_mode_); layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_); if (!layer->TransformIsAnimatingOnImplOnly() && !TransformIsAnimating()) layer->SetTransformAndInvertibility(transform_, transform_is_invertible_); @@ -1302,7 +1309,8 @@ void Layer::PushPropertiesTo(LayerImpl* layer) { if (!copy_requests_.empty() && layer_tree_host_) layer_tree_host_->property_trees()->needs_rebuild = true; if (had_copy_requests) - UpdateNumCopyRequestsForSubtree(false); + UpdateNumCopyRequestsForSubtree(-1); + copy_requests_.clear(); layer->PassCopyRequests(&main_thread_copy_requests); @@ -1393,10 +1401,6 @@ bool Layer::Update() { return false; } -bool Layer::NeedMoreUpdates() { - return false; -} - bool Layer::IsSuitableForGpuRasterization() const { return true; } @@ -1416,20 +1420,7 @@ void Layer::SetHasRenderSurface(bool 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(!render_surface_); - render_surface_ = make_scoped_ptr(new RenderSurface(this)); -} - -void Layer::ClearRenderSurface() { - render_surface_ = nullptr; -} - -void Layer::ClearRenderSurfaceLayerList() { - if (render_surface_) - render_surface_->ClearLayerLists(); + layer_tree_host_->property_trees()->needs_rebuild = true; } gfx::ScrollOffset Layer::ScrollOffsetForAnimation() const { @@ -1447,12 +1438,11 @@ 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 (EffectNode* node = layer_tree_host_->property_trees()->effect_tree.Node( + effect_tree_index())) { if (node->owner_id == id()) { node->data.opacity = opacity; - layer_tree_host_->property_trees()->opacity_tree.set_needs_update(true); + layer_tree_host_->property_trees()->effect_tree.set_needs_update(true); } } } @@ -1489,6 +1479,40 @@ void Layer::OnAnimationWaitingForDeletion() { SetNeedsPushProperties(); } +void Layer::OnTransformIsPotentiallyAnimatingChanged(bool is_animating) { + if (!layer_tree_host_) + return; + TransformTree& transform_tree = + layer_tree_host_->property_trees()->transform_tree; + TransformNode* node = transform_tree.Node(transform_tree_index()); + if (!node) + return; + + if (node->owner_id == id()) { + node->data.is_animated = is_animating; + if (is_animating) { + float maximum_target_scale = 0.f; + node->data.local_maximum_animation_target_scale = + MaximumTargetScale(&maximum_target_scale) ? maximum_target_scale + : 0.f; + + float animation_start_scale = 0.f; + node->data.local_starting_animation_scale = + AnimationStartScale(&animation_start_scale) ? animation_start_scale + : 0.f; + + node->data.has_only_translation_animations = + HasOnlyTranslationTransforms(); + + } else { + node->data.local_maximum_animation_target_scale = 0.f; + node->data.local_starting_animation_scale = 0.f; + node->data.has_only_translation_animations = true; + } + transform_tree.set_needs_update(true); + } +} + bool Layer::IsActive() const { return true; } @@ -1665,4 +1689,16 @@ bool Layer::sorted_for_recursion() { layer_tree_host()->meta_information_sequence_number(); } +gfx::Transform Layer::draw_transform() const { + DCHECK_NE(transform_tree_index_, -1); + return DrawTransformFromPropertyTrees( + this, layer_tree_host_->property_trees()->transform_tree); +} + +gfx::Transform Layer::screen_space_transform() const { + DCHECK_NE(transform_tree_index_, -1); + return ScreenSpaceTransformFromPropertyTrees( + this, layer_tree_host_->property_trees()->transform_tree); +} + } // namespace cc diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h index 3ff2810c9d6..800deff5ce2 100644 --- a/chromium/cc/layers/layer.h +++ b/chromium/cc/layers/layer.h @@ -20,11 +20,9 @@ #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" @@ -75,9 +73,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, public LayerAnimationValueObserver, public LayerAnimationValueProvider { public: - typedef RenderSurfaceLayerList RenderSurfaceListType; typedef LayerList LayerListType; - typedef RenderSurface RenderSurfaceType; enum LayerIdLabels { INVALID_ID = -1, @@ -141,6 +137,14 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, void SetBlendMode(SkXfermode::Mode blend_mode); SkXfermode::Mode blend_mode() const { return blend_mode_; } + void set_draw_blend_mode(SkXfermode::Mode blend_mode) { + if (draw_blend_mode_ == blend_mode) + return; + draw_blend_mode_ = blend_mode; + SetNeedsPushProperties(); + } + SkXfermode::Mode draw_blend_mode() const { return draw_blend_mode_; } + bool uses_default_blend_mode() const { return blend_mode_ == SkXfermode::kSrcOver_Mode; } @@ -157,6 +161,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, void SetFilters(const FilterOperations& filters); const FilterOperations& filters() const { return filters_; } bool FilterIsAnimating() const; + bool HasPotentiallyRunningFilterAnimation() const; // Background filters are filters applied to what is behind this layer, when // they are viewed through non-opaque regions in this layer. They are used @@ -190,12 +195,19 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, const gfx::Transform& transform() const { return transform_; } bool TransformIsAnimating() const; bool HasPotentiallyRunningTransformAnimation() const; + bool HasOnlyTranslationTransforms() const; bool AnimationsPreserveAxisAlignment() const; bool transform_is_invertible() const { return transform_is_invertible_; } + bool MaximumTargetScale(float* max_scale) const; + bool AnimationStartScale(float* start_scale) const; + void SetTransformOrigin(const gfx::Point3F&); gfx::Point3F transform_origin() const { return transform_origin_; } + bool HasAnyAnimationTargetingProperty( + Animation::TargetProperty property) const; + bool ScrollOffsetAnimationWasInterrupted() const; void SetScrollParent(Layer* parent); @@ -226,55 +238,17 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, return clip_children_.get(); } - DrawProperties<Layer>& draw_properties() { return draw_properties_; } - const DrawProperties<Layer>& draw_properties() const { - return draw_properties_; - } + // TODO(enne): Fix style here (and everywhere) once LayerImpl does the same. + gfx::Transform draw_transform() const; + gfx::Transform screen_space_transform() const; - // The following are shortcut accessors to get various information from - // draw_properties_ - const gfx::Transform& draw_transform() const { - return draw_properties_.target_space_transform; - } - const gfx::Transform& screen_space_transform() const { - return draw_properties_.screen_space_transform; - } - float draw_opacity() const { return draw_properties_.opacity; } - bool draw_opacity_is_animating() const { - return draw_properties_.opacity_is_animating; - } - bool draw_transform_is_animating() const { - return draw_properties_.target_space_transform_is_animating; - } - bool screen_space_transform_is_animating() const { - return draw_properties_.screen_space_transform_is_animating; - } - bool screen_space_opacity_is_animating() const { - return draw_properties_.screen_space_opacity_is_animating; - } - 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 { - return draw_properties_.drawable_content_rect; - } - gfx::Rect visible_layer_rect() const { - return draw_properties_.visible_layer_rect; - } - Layer* render_target() { - DCHECK(!draw_properties_.render_target || - draw_properties_.render_target->render_surface()); - return draw_properties_.render_target; - } - const Layer* render_target() const { - DCHECK(!draw_properties_.render_target || - draw_properties_.render_target->render_surface()); - return draw_properties_.render_target; + void set_num_unclipped_descendants(size_t descendants) { + num_unclipped_descendants_ = descendants; } size_t num_unclipped_descendants() const { - return draw_properties_.num_unclipped_descendants; + return 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); @@ -322,11 +296,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, did_scroll_callback_ = callback; } - void SetDrawCheckerboardForMissingTiles(bool checkerboard); - bool draw_checkerboard_for_missing_tiles() const { - return draw_checkerboard_for_missing_tiles_; - } - void SetForceRenderSurface(bool force_render_surface); bool force_render_surface() const { return force_render_surface_; } @@ -379,10 +348,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, virtual void SavePaintProperties(); // Returns true iff anything was updated that needs to be committed. virtual bool Update(); - virtual bool NeedMoreUpdates(); virtual void SetIsMask(bool is_mask) {} - virtual void ReduceMemoryUsage() {} - virtual void OnOutputSurfaceCreated() {} virtual bool IsSuitableForGpuRasterization() const; virtual scoped_refptr<base::trace_event::ConvertableToTraceFormat> @@ -392,11 +358,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, virtual void PushPropertiesTo(LayerImpl* layer); - void CreateRenderSurface(); - void ClearRenderSurface(); - - void ClearRenderSurfaceLayerList(); - LayerTreeHost* layer_tree_host() { return layer_tree_host_; } const LayerTreeHost* layer_tree_host() const { return layer_tree_host_; } @@ -463,8 +424,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, void SetClipTreeIndex(int index); int clip_tree_index() const; - void SetOpacityTreeIndex(int index); - int opacity_tree_index() const; + void SetEffectTreeIndex(int index); + int effect_tree_index() const; void set_offset_to_transform_parent(gfx::Vector2dF offset) { if (offset_to_transform_parent_ == offset) @@ -476,20 +437,24 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, 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. - + // TODO(enne): Once LayerImpl only uses property trees, remove these + // functions. const gfx::Rect& visible_rect_from_property_trees() const { - return visible_rect_from_property_trees_; + return visible_layer_rect(); } 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; + set_visible_layer_rect(rect); } - + const gfx::Rect& clip_rect_in_target_space_from_property_trees() const { + return clip_rect(); + } + void set_clip_rect_in_target_space_from_property_trees( + const gfx::Rect& rect) { + set_clip_rect(rect); + } + // TODO(enne): This needs a different name. It is a calculated value + // from the property tree builder and not a synonym for "should + // flatten transform". void set_should_flatten_transform_from_property_tree(bool should_flatten) { if (should_flatten_transform_from_property_tree_ == should_flatten) return; @@ -500,13 +465,14 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, 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. + const gfx::Rect& visible_layer_rect() const { return visible_layer_rect_; } + void set_visible_layer_rect(const gfx::Rect& rect) { + visible_layer_rect_ = rect; + } + + const gfx::Rect& clip_rect() const { return clip_rect_; } + void set_clip_rect(const gfx::Rect& rect) { clip_rect_ = rect; } + bool has_render_surface() const { return has_render_surface_; } @@ -520,29 +486,14 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, } void DidBeginTracing(); - void set_num_layer_or_descandant_with_copy_request( + // TODO(weiliangc): this should move to the effect tree. + void set_num_layer_or_descendant_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_; - } - - void set_num_children_with_scroll_parent( - int num_children_with_scroll_parent) { - num_children_with_scroll_parent_ = num_children_with_scroll_parent; - } - - int num_children_with_scroll_parent() { - return num_children_with_scroll_parent_; + int num_layer_or_descendants_with_copy_request() { + return num_layer_or_descendants_with_copy_request_; } void set_visited(bool visited); @@ -652,6 +603,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, void OnTransformAnimated(const gfx::Transform& transform) override; void OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset) override; void OnAnimationWaitingForDeletion() override; + void OnTransformIsPotentiallyAnimatingChanged(bool is_animating) override; bool IsActive() const override; // If this layer has a scroll parent, it removes |this| from its list of @@ -666,8 +618,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, // indices becomes invalid. void InvalidatePropertyTreesIndices(); - void UpdateNumCopyRequestsForSubtree(bool add); - void UpdateNumInputHandlersForSubtree(bool add); + void UpdateNumCopyRequestsForSubtree(int delta); LayerList children_; Layer* parent_; @@ -690,12 +641,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, int scroll_clip_layer_id_; int num_descendants_that_draw_content_; int transform_tree_index_; - int opacity_tree_index_; + int effect_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_; - int num_children_with_scroll_parent_; gfx::Vector2dF offset_to_transform_parent_; bool should_flatten_transform_from_property_tree_ : 1; bool should_scroll_on_main_thread_ : 1; @@ -713,7 +662,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, bool double_sided_ : 1; bool should_flatten_transform_ : 1; bool use_parent_backface_visibility_ : 1; - bool draw_checkerboard_for_missing_tiles_ : 1; bool force_render_surface_ : 1; bool transform_is_invertible_ : 1; bool has_render_surface_ : 1; @@ -724,6 +672,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, SkColor background_color_; float opacity_; SkXfermode::Mode blend_mode_; + // draw_blend_mode may be different than blend_mode_, + // when a RenderSurface re-parents the layer's blend_mode. + SkXfermode::Mode draw_blend_mode_; FilterOperations filters_; FilterOperations background_filters_; LayerPositionConstraint position_constraint_; @@ -753,14 +704,12 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>, base::Closure did_scroll_callback_; - 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_; + // These all act like draw properties, so don't need push properties. + gfx::Rect visible_layer_rect_; + gfx::Rect clip_rect_; + size_t num_unclipped_descendants_; std::vector<FrameTimingRequest> frame_timing_requests_; bool frame_timing_requests_dirty_; diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc index 588c8ac4d90..afacef86551 100644 --- a/chromium/cc/layers/layer_impl.cc +++ b/chromium/cc/layers/layer_impl.cc @@ -17,6 +17,7 @@ #include "cc/debug/layer_tree_debug_state.h" #include "cc/debug/micro_benchmark_impl.h" #include "cc/debug/traced_value.h" +#include "cc/input/scroll_state.h" #include "cc/layers/layer_utils.h" #include "cc/layers/painted_scrollbar_layer_impl.h" #include "cc/output/copy_output_request.h" @@ -65,7 +66,6 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, contents_opaque_(false), is_root_for_isolated_group_(false), use_parent_backface_visibility_(false), - draw_checkerboard_for_missing_tiles_(false), draws_content_(false), hide_layer_and_subtree_(false), transform_is_invertible_(true), @@ -74,18 +74,21 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, background_color_(0), opacity_(1.0), blend_mode_(SkXfermode::kSrcOver_Mode), + draw_blend_mode_(SkXfermode::kSrcOver_Mode), num_descendants_that_draw_content_(0), transform_tree_index_(-1), - opacity_tree_index_(-1), + effect_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), + num_layer_or_descendants_with_copy_request_(0), frame_timing_requests_dirty_(false), visited_(false), layer_or_descendant_is_drawn_(false), + layer_or_descendant_has_input_handler_(false), sorted_for_recursion_(false) { DCHECK_GT(layer_id_, 0); DCHECK(layer_tree_impl_); @@ -196,6 +199,30 @@ void LayerImpl::SetScrollChildren(std::set<LayerImpl*>* children) { SetNeedsPushProperties(); } +void LayerImpl::DistributeScroll(ScrollState* scroll_state) { + DCHECK(scroll_state); + if (scroll_state->FullyConsumed()) + return; + + scroll_state->DistributeToScrollChainDescendant(); + + // If the scroll doesn't propagate, and we're currently scrolling + // a layer other than this one, prevent the scroll from + // propagating to this layer. + if (!scroll_state->should_propagate() && + scroll_state->delta_consumed_for_scroll_sequence() && + scroll_state->current_native_scrolling_layer() != this) { + return; + } + + ApplyScroll(scroll_state); +} + +void LayerImpl::ApplyScroll(ScrollState* scroll_state) { + DCHECK(scroll_state); + layer_tree_impl()->ApplyScroll(this, scroll_state); +} + void LayerImpl::SetNumDescendantsThatDrawContent(int num_descendants) { if (num_descendants_that_draw_content_ == num_descendants) return; @@ -228,8 +255,8 @@ void LayerImpl::SetClipTreeIndex(int index) { SetNeedsPushProperties(); } -void LayerImpl::SetOpacityTreeIndex(int index) { - opacity_tree_index_ = index; +void LayerImpl::SetEffectTreeIndex(int index) { + effect_tree_index_ = index; SetNeedsPushProperties(); } @@ -291,7 +318,7 @@ void LayerImpl::PopulateSharedQuadState(SharedQuadState* state) const { state->SetAll(draw_properties_.target_space_transform, bounds(), draw_properties_.visible_layer_rect, draw_properties_.clip_rect, draw_properties_.is_clipped, draw_properties_.opacity, - draw_properties_.blend_mode, sorting_context_id_); + draw_blend_mode_, sorting_context_id_); } void LayerImpl::PopulateScaledSharedQuadState(SharedQuadState* state, @@ -299,14 +326,14 @@ void LayerImpl::PopulateScaledSharedQuadState(SharedQuadState* state, gfx::Transform scaled_draw_transform = draw_properties_.target_space_transform; scaled_draw_transform.Scale(SK_MScalar1 / scale, SK_MScalar1 / scale); - gfx::Size scaled_bounds = gfx::ToCeiledSize(gfx::ScaleSize(bounds(), scale)); + gfx::Size scaled_bounds = gfx::ScaleToCeiledSize(bounds(), scale); gfx::Rect scaled_visible_layer_rect = gfx::ScaleToEnclosingRect(visible_layer_rect(), scale); scaled_visible_layer_rect.Intersect(gfx::Rect(scaled_bounds)); state->SetAll(scaled_draw_transform, scaled_bounds, scaled_visible_layer_rect, draw_properties().clip_rect, draw_properties().is_clipped, - draw_properties().opacity, draw_properties().blend_mode, + draw_properties().opacity, draw_blend_mode_, sorting_context_id_); } @@ -521,8 +548,6 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetBackgroundColor(background_color_); layer->SetBounds(bounds_); layer->SetDoubleSided(double_sided_); - layer->SetDrawCheckerboardForMissingTiles( - draw_checkerboard_for_missing_tiles_); layer->SetDrawsContent(DrawsContent()); layer->SetHideLayerAndSubtree(hide_layer_and_subtree_); layer->SetHasRenderSurface(!!render_surface()); @@ -546,6 +571,7 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetShouldFlattenTransform(should_flatten_transform_); layer->set_should_flatten_transform_from_property_tree( should_flatten_transform_from_property_tree_); + layer->set_draw_blend_mode(draw_blend_mode_); layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_); layer->SetTransformAndInvertibility(transform_, transform_is_invertible_); @@ -563,7 +589,7 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetTransformTreeIndex(transform_tree_index_); layer->SetClipTreeIndex(clip_tree_index_); - layer->SetOpacityTreeIndex(opacity_tree_index_); + layer->SetEffectTreeIndex(effect_tree_index_); layer->set_offset_to_transform_parent(offset_to_transform_parent_); LayerImpl* scroll_parent = nullptr; @@ -618,6 +644,9 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) { layer->SetStackingOrderChanged(stacking_order_changed_); layer->SetDebugInfo(debug_info_); + layer->set_num_layer_or_descendant_with_copy_request( + num_layer_or_descendants_with_copy_request_); + set_num_layer_or_descendant_with_copy_request(0); if (frame_timing_requests_dirty_) { layer->SetFrameTimingRequests(frame_timing_requests_); @@ -752,8 +781,8 @@ const char* LayerImpl::LayerTypeAsString() const { void LayerImpl::ResetAllChangeTrackingForSubtree() { layer_property_changed_ = false; - update_rect_ = gfx::Rect(); - damage_rect_ = gfx::RectF(); + update_rect_.SetRect(0, 0, 0, 0); + damage_rect_.SetRect(0, 0, 0, 0); if (render_surface_) render_surface_->ResetPropertyChangedFlag(); @@ -778,6 +807,14 @@ void LayerImpl::UpdatePropertyTreeTransform() { TransformTree& transform_tree = layer_tree_impl()->property_trees()->transform_tree; TransformNode* node = transform_tree.Node(transform_tree_index_); + // A LayerImpl's own current state is insufficient for determining whether + // it owns a TransformNode, since this depends on the state of the + // corresponding Layer at the time of the last commit. For example, a + // transform animation might have been in progress at the time the last + // commit started, but might have finished since then on the compositor + // thread. + if (node->owner_id != id()) + return; if (node->data.local != transform_) { node->data.local = transform_; node->data.needs_local_transform_update = true; @@ -792,13 +829,61 @@ void LayerImpl::UpdatePropertyTreeTransform() { } } +void LayerImpl::UpdatePropertyTreeTransformIsAnimated(bool is_animated) { + if (transform_tree_index_ != -1) { + TransformTree& transform_tree = + layer_tree_impl()->property_trees()->transform_tree; + TransformNode* node = transform_tree.Node(transform_tree_index_); + // A LayerImpl's own current state is insufficient for determining whether + // it owns a TransformNode, since this depends on the state of the + // corresponding Layer at the time of the last commit. For example, if + // |is_animated| is false, this might mean a transform animation just ticked + // past its finish point (so the LayerImpl still owns a TransformNode) or it + // might mean that a transform animation was removed during commit or + // activation (and, in that case, the LayerImpl will no longer own a + // TransformNode, unless it has non-animation-related reasons for owning a + // node). + if (node->owner_id != id()) + return; + if (node->data.is_animated != is_animated) { + node->data.is_animated = is_animated; + if (is_animated) { + float maximum_target_scale = 0.f; + node->data.local_maximum_animation_target_scale = + MaximumTargetScale(&maximum_target_scale) ? maximum_target_scale + : 0.f; + + float animation_start_scale = 0.f; + node->data.local_starting_animation_scale = + AnimationStartScale(&animation_start_scale) ? animation_start_scale + : 0.f; + + node->data.has_only_translation_animations = + HasOnlyTranslationTransforms(); + } else { + node->data.local_maximum_animation_target_scale = 0.f; + node->data.local_starting_animation_scale = 0.f; + node->data.has_only_translation_animations = true; + } + + transform_tree.set_needs_update(true); + } + } +} + void LayerImpl::UpdatePropertyTreeOpacity() { - if (opacity_tree_index_ != -1) { - OpacityTree& opacity_tree = - layer_tree_impl()->property_trees()->opacity_tree; - OpacityNode* node = opacity_tree.Node(opacity_tree_index_); + if (effect_tree_index_ != -1) { + EffectTree& effect_tree = layer_tree_impl()->property_trees()->effect_tree; + EffectNode* node = effect_tree.Node(effect_tree_index_); + // A LayerImpl's own current state is insufficient for determining whether + // it owns an OpacityNode, since this depends on the state of the + // corresponding Layer at the time of the last commit. For example, an + // opacity animation might have been in progress at the time the last commit + // started, but might have finished since then on the compositor thread. + if (node->owner_id != id()) + return; node->data.opacity = opacity_; - opacity_tree.set_needs_update(true); + effect_tree.set_needs_update(true); } } @@ -806,11 +891,14 @@ void LayerImpl::UpdatePropertyTreeForScrollingAndAnimationIfNeeded() { if (scrollable()) UpdatePropertyTreeScrollOffset(); - if (OpacityIsAnimating()) + if (HasAnyAnimationTargetingProperty(Animation::OPACITY)) UpdatePropertyTreeOpacity(); - if (TransformIsAnimating()) + if (HasAnyAnimationTargetingProperty(Animation::TRANSFORM)) { UpdatePropertyTreeTransform(); + UpdatePropertyTreeTransformIsAnimated( + HasPotentiallyRunningTransformAnimation()); + } } gfx::ScrollOffset LayerImpl::ScrollOffsetForAnimation() const { @@ -845,6 +933,10 @@ void LayerImpl::OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset) { void LayerImpl::OnAnimationWaitingForDeletion() {} +void LayerImpl::OnTransformIsPotentiallyAnimatingChanged(bool is_animating) { + UpdatePropertyTreeTransformIsAnimated(is_animating); +} + bool LayerImpl::IsActive() const { return layer_tree_impl_->IsActiveTree(); } @@ -895,8 +987,8 @@ void LayerImpl::SetBoundsDelta(const gfx::Vector2dF& bounds_delta) { layer_tree_impl()->property_trees()->clip_tree.Node(clip_tree_index()); if (clip_node) { DCHECK(id() == clip_node->owner_id); - clip_node->data.clip = - gfx::RectF(gfx::PointF() + offset_to_transform_parent(), bounds()); + clip_node->data.clip = gfx::RectF( + gfx::PointF() + offset_to_transform_parent(), gfx::SizeF(bounds())); layer_tree_impl()->property_trees()->clip_tree.set_needs_update(true); } @@ -1013,12 +1105,25 @@ void LayerImpl::SetFilters(const FilterOperations& filters) { } bool LayerImpl::FilterIsAnimating() const { + LayerAnimationController::ObserverType observer_type = + IsActive() ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; return layer_animation_controller_ - ? layer_animation_controller_->IsAnimatingProperty( - Animation::FILTER) + ? layer_animation_controller_->IsCurrentlyAnimatingProperty( + Animation::FILTER, observer_type) : layer_tree_impl_->IsAnimatingFilterProperty(this); } +bool LayerImpl::HasPotentiallyRunningFilterAnimation() const { + LayerAnimationController::ObserverType observer_type = + IsActive() ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; + return layer_animation_controller_ + ? layer_animation_controller_->IsPotentiallyAnimatingProperty( + Animation::FILTER, observer_type) + : layer_tree_impl_->HasPotentiallyRunningFilterAnimation(this); +} + bool LayerImpl::FilterIsAnimatingOnImplOnly() const { if (!layer_animation_controller_) return layer_tree_impl_->FilterIsAnimatingOnImplOnly(this); @@ -1062,22 +1167,23 @@ void LayerImpl::SetOpacity(float opacity) { } bool LayerImpl::OpacityIsAnimating() const { + LayerAnimationController::ObserverType observer_type = + IsActive() ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; return layer_animation_controller_ - ? layer_animation_controller_->IsAnimatingProperty( - Animation::OPACITY) + ? layer_animation_controller_->IsCurrentlyAnimatingProperty( + Animation::OPACITY, observer_type) : layer_tree_impl_->IsAnimatingOpacityProperty(this); } bool LayerImpl::HasPotentiallyRunningOpacityAnimation() const { - if (layer_animation_controller_) { - if (Animation* animation = - layer_animation_controller()->GetAnimation(Animation::OPACITY)) { - return !animation->is_finished(); - } - return false; - } else { - return layer_tree_impl_->HasPotentiallyRunningOpacityAnimation(this); - } + LayerAnimationController::ObserverType observer_type = + IsActive() ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; + return layer_animation_controller_ + ? layer_animation_controller_->IsPotentiallyAnimatingProperty( + Animation::OPACITY, observer_type) + : layer_tree_impl_->HasPotentiallyRunningOpacityAnimation(this); } bool LayerImpl::OpacityIsAnimatingOnImplOnly() const { @@ -1162,22 +1268,23 @@ void LayerImpl::SetTransformAndInvertibility(const gfx::Transform& transform, } bool LayerImpl::TransformIsAnimating() const { + LayerAnimationController::ObserverType observer_type = + IsActive() ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; return layer_animation_controller_ - ? layer_animation_controller_->IsAnimatingProperty( - Animation::TRANSFORM) + ? layer_animation_controller_->IsCurrentlyAnimatingProperty( + Animation::TRANSFORM, observer_type) : layer_tree_impl_->IsAnimatingTransformProperty(this); } bool LayerImpl::HasPotentiallyRunningTransformAnimation() const { - if (layer_animation_controller_) { - if (Animation* animation = - layer_animation_controller()->GetAnimation(Animation::TRANSFORM)) { - return !animation->is_finished(); - } - return false; - } else { - return layer_tree_impl_->HasPotentiallyRunningTransformAnimation(this); - } + LayerAnimationController::ObserverType observer_type = + IsActive() ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; + return layer_animation_controller_ + ? layer_animation_controller_->IsPotentiallyAnimatingProperty( + Animation::TRANSFORM, observer_type) + : layer_tree_impl_->HasPotentiallyRunningTransformAnimation(this); } bool LayerImpl::TransformIsAnimatingOnImplOnly() const { @@ -1193,21 +1300,41 @@ bool LayerImpl::HasOnlyTranslationTransforms() const { if (!layer_animation_controller_) return layer_tree_impl_->HasOnlyTranslationTransforms(this); - return layer_animation_controller_->HasOnlyTranslationTransforms(); + LayerAnimationController::ObserverType observer_type = + IsActive() ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; + return layer_animation_controller_->HasOnlyTranslationTransforms( + observer_type); } bool LayerImpl::MaximumTargetScale(float* max_scale) const { if (!layer_animation_controller_) return layer_tree_impl_->MaximumTargetScale(this, max_scale); - return layer_animation_controller_->MaximumTargetScale(max_scale); + LayerAnimationController::ObserverType observer_type = + IsActive() ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; + return layer_animation_controller_->MaximumTargetScale(observer_type, + max_scale); } bool LayerImpl::AnimationStartScale(float* start_scale) const { if (!layer_animation_controller_) return layer_tree_impl_->AnimationStartScale(this, start_scale); - return layer_animation_controller_->AnimationStartScale(start_scale); + LayerAnimationController::ObserverType observer_type = + IsActive() ? LayerAnimationController::ObserverType::ACTIVE + : LayerAnimationController::ObserverType::PENDING; + return layer_animation_controller_->AnimationStartScale(observer_type, + start_scale); +} + +bool LayerImpl::HasAnyAnimationTargetingProperty( + Animation::TargetProperty property) const { + if (!layer_animation_controller_) + return layer_tree_impl_->HasAnyAnimationTargetingProperty(this, property); + + return !!layer_animation_controller_->GetAnimation(property); } bool LayerImpl::HasFilterAnimationThatInflatesBounds() const { @@ -1253,25 +1380,14 @@ void LayerImpl::SetUpdateRect(const gfx::Rect& update_rect) { SetNeedsPushProperties(); } -void LayerImpl::AddDamageRect(const gfx::RectF& damage_rect) { - damage_rect_ = gfx::UnionRects(damage_rect_, damage_rect); -} - -bool LayerImpl::IsExternalScrollActive() const { - return layer_tree_impl_->IsExternalScrollActive(); +void LayerImpl::AddDamageRect(const gfx::Rect& damage_rect) { + damage_rect_.Union(damage_rect); } void LayerImpl::SetCurrentScrollOffset(const gfx::ScrollOffset& scroll_offset) { DCHECK(IsActive()); if (scroll_offset_->SetCurrent(scroll_offset)) - DidUpdateScrollOffset(false); -} - -void LayerImpl::SetCurrentScrollOffsetFromDelegate( - const gfx::ScrollOffset& scroll_offset) { - DCHECK(IsActive()); - if (scroll_offset_->SetCurrent(scroll_offset)) - DidUpdateScrollOffset(true); + DidUpdateScrollOffset(); } void LayerImpl::PushScrollOffsetFromMainThread( @@ -1289,12 +1405,13 @@ 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); + gfx::ScrollOffset current_delta = IsActive() + ? scroll_offset_->Delta() + : scroll_offset_->PendingDelta().get(); + gfx::ScrollOffset floored_delta(floor(current_delta.x()), + floor(current_delta.y())); + gfx::ScrollOffset diff_delta = floored_delta - current_delta; + gfx::ScrollOffset tmp_offset = current_offset + diff_delta; scroll_offset_->SetCurrent(tmp_offset); gfx::ScrollOffset delta = scroll_offset_->PullDeltaForMainThread(); scroll_offset_->SetCurrent(current_offset); @@ -1340,7 +1457,7 @@ void LayerImpl::PushScrollOffset(const gfx::ScrollOffset* scroll_offset) { } if (changed) - DidUpdateScrollOffset(false); + DidUpdateScrollOffset(); } void LayerImpl::UpdatePropertyTreeScrollOffset() { @@ -1359,11 +1476,9 @@ void LayerImpl::UpdatePropertyTreeScrollOffset() { } } -void LayerImpl::DidUpdateScrollOffset(bool is_from_root_delegate) { +void LayerImpl::DidUpdateScrollOffset() { DCHECK(scroll_offset_); - if (!is_from_root_delegate) - layer_tree_impl()->DidUpdateScrollOffset(id()); NoteLayerPropertyChangedForSubtree(); ScrollbarParametersDidChange(false); @@ -1373,7 +1488,7 @@ void LayerImpl::DidUpdateScrollOffset(bool is_from_root_delegate) { if (layer_tree_impl()->IsActiveTree()) { LayerImpl* pending_twin = layer_tree_impl()->FindPendingTreeLayerById(id()); if (pending_twin) - pending_twin->DidUpdateScrollOffset(is_from_root_delegate); + pending_twin->DidUpdateScrollOffset(); } } @@ -1402,7 +1517,7 @@ gfx::ScrollOffset LayerImpl::MaxScrollOffset() const { if (!scroll_clip_layer_ || bounds().IsEmpty()) return gfx::ScrollOffset(); - LayerImpl const* page_scale_layer = layer_tree_impl()->page_scale_layer(); + LayerImpl const* page_scale_layer = layer_tree_impl()->PageScaleLayer(); DCHECK(this != page_scale_layer); DCHECK(this != layer_tree_impl()->InnerViewportScrollLayer() || IsContainerForFixedPositionLayers()); @@ -1416,8 +1531,9 @@ gfx::ScrollOffset LayerImpl::MaxScrollOffset() const { } gfx::SizeF scaled_scroll_bounds = - gfx::ToFlooredSize(gfx::ScaleSize(BoundsForScrolling(), scale_factor)); - scaled_scroll_bounds = gfx::ToFlooredSize(scaled_scroll_bounds); + gfx::ScaleSize(BoundsForScrolling(), scale_factor); + scaled_scroll_bounds.SetSize(std::floor(scaled_scroll_bounds.width()), + std::floor(scaled_scroll_bounds.height())); gfx::ScrollOffset max_offset( scaled_scroll_bounds.width() - scroll_clip_layer_->bounds().width(), @@ -1448,7 +1564,7 @@ void LayerImpl::SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer, LayerImpl* scrollbar_clip_layer, bool on_resize) const { DCHECK(scrollbar_layer); - LayerImpl* page_scale_layer = layer_tree_impl()->page_scale_layer(); + LayerImpl* page_scale_layer = layer_tree_impl()->PageScaleLayer(); DCHECK(this != page_scale_layer); DCHECK(scrollbar_clip_layer); @@ -1640,8 +1756,9 @@ void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const { MathUtil::AddToTracedValue("transform_origin", transform_origin_, state); bool clipped; - gfx::QuadF layer_quad = MathUtil::MapQuad( - screen_space_transform(), gfx::QuadF(gfx::Rect(bounds())), &clipped); + gfx::QuadF layer_quad = + MathUtil::MapQuad(screen_space_transform(), + gfx::QuadF(gfx::RectF(gfx::Rect(bounds()))), &clipped); MathUtil::AddToTracedValue("layer_quad", layer_quad, state); if (!touch_event_handler_region_.IsEmpty()) { state->BeginArray("touch_event_handler_region"); @@ -1789,7 +1906,7 @@ 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_bounds = gfx::ToCeiledSize(gfx::ScaleSize(bounds(), scale)); + gfx::Size scaled_bounds = gfx::ScaleToCeiledSize(bounds(), scale); return MathUtil::MapEnclosingClippedRect(scaled_draw_transform, gfx::Rect(scaled_bounds)); } diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h index 57a0be1204a..4e94980939e 100644 --- a/chromium/cc/layers/layer_impl.h +++ b/chromium/cc/layers/layer_impl.h @@ -57,7 +57,7 @@ class LayerTreeHostImpl; class LayerTreeImpl; class MicroBenchmarkImpl; class Occlusion; -class OpacityTree; +class EffectTree; class PrioritizedTile; class RenderPass; class RenderPassId; @@ -67,6 +67,7 @@ class ScrollbarLayerImplBase; class SimpleEnclosedRegion; class Tile; class TransformTree; +class ScrollState; struct AppendQuadsData; @@ -112,6 +113,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, void OnTransformAnimated(const gfx::Transform& transform) override; void OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset) override; void OnAnimationWaitingForDeletion() override; + void OnTransformIsPotentiallyAnimatingChanged(bool is_animating) override; bool IsActive() const override; // AnimationDelegate implementation. @@ -149,6 +151,9 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, return scroll_children_.get(); } + void DistributeScroll(ScrollState* scroll_state); + void ApplyScroll(ScrollState* scroll_state); + void set_property_tree_sequence_number(int sequence_number) {} void SetTransformTreeIndex(int index); @@ -157,8 +162,8 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, 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 SetEffectTreeIndex(int index); + int effect_tree_index() const { return effect_tree_index_; } void set_offset_to_transform_parent(const gfx::Vector2dF& offset) { offset_to_transform_parent_ = offset; @@ -175,6 +180,14 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, visible_rect_from_property_trees_ = rect; } + const gfx::Rect& clip_rect_in_target_space_from_property_trees() const { + return clip_rect_in_target_space_from_property_trees_; + } + void set_clip_rect_in_target_space_from_property_trees( + const gfx::Rect& rect) { + clip_rect_in_target_space_from_property_trees_ = rect; + } + void set_should_flatten_transform_from_property_tree(bool should_flatten) { should_flatten_transform_from_property_tree_ = should_flatten; SetNeedsPushProperties(); @@ -183,7 +196,10 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, return should_flatten_transform_from_property_tree_; } + bool is_clipped() const { return draw_properties_.is_clipped; } + void UpdatePropertyTreeTransform(); + void UpdatePropertyTreeTransformIsAnimated(bool is_animated); void UpdatePropertyTreeOpacity(); void UpdatePropertyTreeScrollOffset(); @@ -284,6 +300,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, void SetFilters(const FilterOperations& filters); const FilterOperations& filters() const { return filters_; } bool FilterIsAnimating() const; + bool HasPotentiallyRunningFilterAnimation() const; bool FilterIsAnimatingOnImplOnly() const; void SetBackgroundFilters(const FilterOperations& filters); @@ -305,6 +322,13 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, void SetBlendMode(SkXfermode::Mode); SkXfermode::Mode blend_mode() const { return blend_mode_; } + void set_draw_blend_mode(SkXfermode::Mode blend_mode) { + if (draw_blend_mode_ == blend_mode) + return; + draw_blend_mode_ = blend_mode; + SetNeedsPushProperties(); + } + SkXfermode::Mode draw_blend_mode() const { return draw_blend_mode_; } bool uses_default_blend_mode() const { return blend_mode_ == SkXfermode::kSrcOver_Mode; } @@ -361,12 +385,8 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, RenderSurfaceImpl* render_surface() const { return render_surface_.get(); } - DrawProperties<LayerImpl>& draw_properties() { - return draw_properties_; - } - const DrawProperties<LayerImpl>& draw_properties() const { - return draw_properties_; - } + DrawProperties& draw_properties() { return draw_properties_; } + const DrawProperties& draw_properties() const { return draw_properties_; } // The following are shortcut accessors to get various information from // draw_properties_ @@ -377,23 +397,10 @@ 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; - } - bool draw_transform_is_animating() const { - return draw_properties_.target_space_transform_is_animating; - } bool screen_space_transform_is_animating() const { return draw_properties_.screen_space_transform_is_animating; } - 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 { return draw_properties_.drawable_content_rect; @@ -428,11 +435,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, void SetBoundsDelta(const gfx::Vector2dF& bounds_delta); gfx::Vector2dF bounds_delta() const { return bounds_delta_; } - bool IsExternalScrollActive() const; - 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 @@ -518,12 +521,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, 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; - } - bool draw_checkerboard_for_missing_tiles() const { - return draw_checkerboard_for_missing_tiles_; - } InputHandler::ScrollStatus TryScroll( const gfx::PointF& screen_space_point, @@ -546,6 +543,11 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, bool MaximumTargetScale(float* max_scale) const; bool AnimationStartScale(float* start_scale) const; + // This includes all animations, even those that are finished but haven't yet + // been deleted. + bool HasAnyAnimationTargetingProperty( + Animation::TargetProperty property) const; + bool HasFilterAnimationThatInflatesBounds() const; bool HasTransformAnimationThatInflatesBounds() const; bool HasAnimationThatInflatesBounds() const; @@ -557,11 +559,10 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, // Note this rect is in layer space (not content space). void SetUpdateRect(const gfx::Rect& update_rect); - gfx::Rect update_rect() const { return update_rect_; } - - void AddDamageRect(const gfx::RectF& damage_rect); + const gfx::Rect& update_rect() const { return update_rect_; } - const gfx::RectF& damage_rect() const { return damage_rect_; } + void AddDamageRect(const gfx::Rect& damage_rect); + const gfx::Rect& damage_rect() const { return damage_rect_; } virtual base::DictionaryValue* LayerTreeAsJson() const; @@ -666,12 +667,30 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, bool layer_or_descendant_is_drawn() { return layer_or_descendant_is_drawn_; } + void set_layer_or_descendant_has_input_handler( + bool layer_or_descendant_has_input_handler) { + layer_or_descendant_has_input_handler_ = + layer_or_descendant_has_input_handler; + } + + bool layer_or_descendant_has_input_handler() { + return layer_or_descendant_has_input_handler_; + } + void set_sorted_for_recursion(bool sorted_for_recursion) { sorted_for_recursion_ = sorted_for_recursion; } - bool sorted_for_recursion() { return sorted_for_recursion_; } + void set_num_layer_or_descendant_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; + } + int num_layer_or_descendants_with_copy_request() { + return num_layer_or_descendants_with_copy_request_; + } + void UpdatePropertyTreeForScrollingAndAnimationIfNeeded(); float GetIdealContentsScale() const; @@ -708,10 +727,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, 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 DidUpdateScrollOffset(); void NoteLayerPropertyChangedForDescendantsInternal(); virtual const char* LayerTypeAsString() const; @@ -751,7 +767,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, 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; @@ -774,7 +789,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, bool contents_opaque_ : 1; bool is_root_for_isolated_group_ : 1; bool use_parent_backface_visibility_ : 1; - bool draw_checkerboard_for_missing_tiles_ : 1; bool draws_content_ : 1; bool hide_layer_and_subtree_ : 1; @@ -792,6 +806,9 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, float opacity_; SkXfermode::Mode blend_mode_; + // draw_blend_mode may be different than blend_mode_, + // when a RenderSurface re-parents the layer's blend_mode. + SkXfermode::Mode draw_blend_mode_; gfx::PointF position_; gfx::Transform transform_; @@ -802,8 +819,9 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, int num_descendants_that_draw_content_; gfx::Rect visible_rect_from_property_trees_; + gfx::Rect clip_rect_in_target_space_from_property_trees_; int transform_tree_index_; - int opacity_tree_index_; + int effect_tree_index_; int clip_tree_index_; // The global depth value of the center of the layer. This value is used @@ -835,11 +853,12 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, private: // Rect indicating what was repainted/updated during update. // Note that plugin layers bypass this and leave it empty. - // Uses layer (not content) space. + // This is in the layer's space. gfx::Rect update_rect_; - // This rect is in layer space. - gfx::RectF damage_rect_; + // Denotes an area that is damaged and needs redraw. This is in the layer's + // space. + gfx::Rect damage_rect_; // Manages animations for this layer. scoped_refptr<LayerAnimationController> layer_animation_controller_; @@ -853,15 +872,18 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver, // Group of properties that need to be computed based on the layer tree // hierarchy before layers can be drawn. - DrawProperties<LayerImpl> draw_properties_; + DrawProperties draw_properties_; scoped_refptr<base::trace_event::ConvertableToTraceFormat> debug_info_; scoped_ptr<RenderSurfaceImpl> render_surface_; std::vector<FrameTimingRequest> frame_timing_requests_; + int num_layer_or_descendants_with_copy_request_; bool frame_timing_requests_dirty_; bool visited_; bool layer_or_descendant_is_drawn_; + // If true, the layer or one of its descendants has a wheel or touch handler. + bool layer_or_descendant_has_input_handler_; bool sorted_for_recursion_; DISALLOW_COPY_AND_ASSIGN(LayerImpl); diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc index 964b9994085..7404e4e2663 100644 --- a/chromium/cc/layers/layer_impl_unittest.cc +++ b/chromium/cc/layers/layer_impl_unittest.cc @@ -89,9 +89,10 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, &task_graph_runner); - EXPECT_TRUE(host_impl.InitializeRenderer(FakeOutputSurface::Create3d())); + EXPECT_TRUE(host_impl.InitializeRenderer(output_surface.get())); scoped_ptr<LayerImpl> root_clip = LayerImpl::Create(host_impl.active_tree(), 1); scoped_ptr<LayerImpl> root_ptr = @@ -247,9 +248,10 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, &task_graph_runner); - EXPECT_TRUE(host_impl.InitializeRenderer(FakeOutputSurface::Create3d())); + EXPECT_TRUE(host_impl.InitializeRenderer(output_surface.get())); host_impl.active_tree()->SetRootLayer( LayerImpl::Create(host_impl.active_tree(), 1)); LayerImpl* root = host_impl.active_tree()->root_layer(); @@ -310,6 +312,7 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) { // Unrelated functions, always set to new values, always set needs update. VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES( layer->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 4))); + host_impl.active_tree()->BuildPropertyTreesForTesting(); VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetMasksToBounds(true)); VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetContentsOpaque(true)); VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES( @@ -360,9 +363,10 @@ TEST(LayerImplTest, SafeOpaqueBackgroundColor) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, &task_graph_runner); - EXPECT_TRUE(host_impl.InitializeRenderer(FakeOutputSurface::Create3d())); + EXPECT_TRUE(host_impl.InitializeRenderer(output_surface.get())); scoped_ptr<LayerImpl> layer = LayerImpl::Create(host_impl.active_tree(), 1); for (int contents_opaque = 0; contents_opaque < 2; ++contents_opaque) { diff --git a/chromium/cc/layers/layer_lists.cc b/chromium/cc/layers/layer_lists.cc deleted file mode 100644 index 7a4df7295a3..00000000000 --- a/chromium/cc/layers/layer_lists.cc +++ /dev/null @@ -1,67 +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/layer_lists.h" - -#include "cc/layers/layer.h" - -namespace cc { - -RenderSurfaceLayerList::RenderSurfaceLayerList() {} - -RenderSurfaceLayerList::~RenderSurfaceLayerList() { - for (size_t i = 0; i < size(); ++i) - at(size() - 1 - i)->ClearRenderSurface(); -} - -Layer* RenderSurfaceLayerList::at(size_t i) const { - return list_.at(i).get(); -} - -void RenderSurfaceLayerList::pop_back() { - list_.pop_back(); -} - -void RenderSurfaceLayerList::push_back(const scoped_refptr<Layer>& layer) { - list_.push_back(layer); -} - -Layer* RenderSurfaceLayerList::back() { - return list_.back().get(); -} - -size_t RenderSurfaceLayerList::size() const { - return list_.size(); -} - -scoped_refptr<Layer>& RenderSurfaceLayerList::operator[](size_t i) { - return list_[i]; -} -const scoped_refptr<Layer>& RenderSurfaceLayerList::operator[](size_t i) const { - return list_[i]; -} - -LayerList::iterator RenderSurfaceLayerList::begin() { - return list_.begin(); -} - -LayerList::iterator RenderSurfaceLayerList::end() { - return list_.end(); -} - -LayerList::const_iterator RenderSurfaceLayerList::begin() const { - return list_.begin(); -} - -LayerList::const_iterator RenderSurfaceLayerList::end() const { - return list_.end(); -} - -void RenderSurfaceLayerList::clear() { - for (size_t i = 0; i < list_.size(); ++i) - DCHECK(!list_[i]->render_surface()); - list_.clear(); -} - -} // namespace cc diff --git a/chromium/cc/layers/layer_lists.h b/chromium/cc/layers/layer_lists.h index 9a4084b340f..870785dad93 100644 --- a/chromium/cc/layers/layer_lists.h +++ b/chromium/cc/layers/layer_lists.h @@ -16,37 +16,9 @@ class Layer; class LayerImpl; typedef std::vector<scoped_refptr<Layer>> LayerList; - typedef ScopedPtrVector<LayerImpl> OwnedLayerImplList; typedef std::vector<LayerImpl*> LayerImplList; -class CC_EXPORT RenderSurfaceLayerList { - public: - RenderSurfaceLayerList(); - ~RenderSurfaceLayerList(); - - Layer* at(size_t i) const; - void pop_back(); - void push_back(const scoped_refptr<Layer>& layer); - Layer* back(); - size_t size() const; - bool empty() const { return size() == 0u; } - scoped_refptr<Layer>& operator[](size_t i); - const scoped_refptr<Layer>& operator[](size_t i) const; - LayerList::iterator begin(); - LayerList::iterator end(); - LayerList::const_iterator begin() const; - LayerList::const_iterator end() const; - void clear(); - LayerList& AsLayerList() { return list_; } - const LayerList& AsLayerList() const { return list_; } - - private: - LayerList list_; - - DISALLOW_COPY_AND_ASSIGN(RenderSurfaceLayerList); -}; - } // namespace cc #endif // CC_LAYERS_LAYER_LISTS_H_ diff --git a/chromium/cc/layers/layer_position_constraint_unittest.cc b/chromium/cc/layers/layer_position_constraint_unittest.cc index fdb7f5b6ea4..377d3f417ff 100644 --- a/chromium/cc/layers/layer_position_constraint_unittest.cc +++ b/chromium/cc/layers/layer_position_constraint_unittest.cc @@ -136,9 +136,8 @@ class LayerPositionConstraintTest : public testing::Test { } void CommitAndUpdateImplPointers() { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root_.get(), root_->bounds(), &render_surface_layer_list); + LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(root_.get(), + root_->bounds()); inputs.inner_viewport_scroll_layer = layer_tree_host_->inner_viewport_scroll_layer(); inputs.outer_viewport_scroll_layer = diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc index ba8e92d75b9..10b1d147eaf 100644 --- a/chromium/cc/layers/layer_unittest.cc +++ b/chromium/cc/layers/layer_unittest.cc @@ -630,10 +630,6 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) { EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDoubleSided(false)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTouchEventHandlerRegion( gfx::Rect(10, 10))); - EXPECT_SET_NEEDS_COMMIT( - 1, - test_layer->SetDrawCheckerboardForMissingTiles( - !test_layer->draw_checkerboard_for_missing_tiles())); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetForceRenderSurface(true)); EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHideLayerAndSubtree(true)); diff --git a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc index 3535c985106..3405bc545cf 100644 --- a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc +++ b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc @@ -46,9 +46,10 @@ void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size, FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, &task_graph_runner); - host_impl.InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl.InitializeRenderer(output_surface.get()); scoped_ptr<NinePatchLayerImpl> layer = NinePatchLayerImpl::Create(host_impl.active_tree(), 1); @@ -84,7 +85,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_EQ(expected_remaining, gfx::ToEnclosedRect(remaining.bounds())); + EXPECT_EQ(expected_remaining, remaining.bounds()); } else { EXPECT_TRUE(remaining.bounds().IsEmpty()); } diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc index f537ffc7e07..67f83c650cf 100644 --- a/chromium/cc/layers/painted_scrollbar_layer.cc +++ b/chromium/cc/layers/painted_scrollbar_layer.cc @@ -94,7 +94,7 @@ float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) { // 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 = gfx::ToCeiledSize(gfx::ScaleSize(bounds(), scale)); + gfx::Size scaled_bounds = gfx::ScaleToCeiledSize(bounds(), scale); if (scaled_bounds.width() > MaxTextureSize() || scaled_bounds.height() > MaxTextureSize()) { if (scaled_bounds.width() > scaled_bounds.height()) @@ -218,9 +218,9 @@ void PaintedScrollbarLayer::UpdateInternalContentScale() { bool changed = false; changed |= UpdateProperty(ClampScaleToMaxTextureSize(scale), &internal_contents_scale_); - changed |= UpdateProperty( - gfx::ToCeiledSize(gfx::ScaleSize(bounds(), internal_contents_scale_)), - &internal_content_bounds_); + changed |= + UpdateProperty(gfx::ScaleToCeiledSize(bounds(), internal_contents_scale_), + &internal_content_bounds_); if (changed) { // If the content scale or bounds change, repaint. SetNeedsDisplay(); @@ -243,7 +243,7 @@ bool PaintedScrollbarLayer::Update() { bool updated = false; - if (track_rect_.IsEmpty() || scaled_track_rect.IsEmpty()) { + if (scaled_track_rect.IsEmpty()) { if (track_resource_) { track_resource_ = nullptr; thumb_resource_ = nullptr; diff --git a/chromium/cc/layers/picture_image_layer.cc b/chromium/cc/layers/picture_image_layer.cc index 6d903bd40bc..ee129330b3e 100644 --- a/chromium/cc/layers/picture_image_layer.cc +++ b/chromium/cc/layers/picture_image_layer.cc @@ -5,8 +5,10 @@ #include "cc/layers/picture_image_layer.h" #include "cc/layers/picture_image_layer_impl.h" +#include "cc/playback/display_item_list_settings.h" #include "cc/playback/drawing_display_item.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkPictureRecorder.h" #include "ui/gfx/skia_util.h" @@ -31,18 +33,18 @@ scoped_ptr<LayerImpl> PictureImageLayer::CreateLayerImpl( } bool PictureImageLayer::HasDrawableContent() const { - return !bitmap_.isNull() && PictureLayer::HasDrawableContent(); + return image_ && PictureLayer::HasDrawableContent(); } -void PictureImageLayer::SetBitmap(const SkBitmap& bitmap) { - // SetBitmap() currently gets called whenever there is any +void PictureImageLayer::SetImage(skia::RefPtr<const SkImage> image) { + // SetImage() currently gets called whenever there is any // style change that affects the layer even if that change doesn't // affect the actual contents of the image (e.g. a CSS animation). // With this check in place we avoid unecessary texture uploads. - if (bitmap.pixelRef() && bitmap.pixelRef() == bitmap_.pixelRef()) + if (image_.get() == image.get()) return; - bitmap_ = bitmap; + image_ = image.Pass(); UpdateDrawsContent(HasDrawableContent()); SetNeedsDisplay(); } @@ -51,19 +53,20 @@ void PictureImageLayer::PaintContents( SkCanvas* canvas, const gfx::Rect& clip, ContentLayerClient::PaintingControlSetting painting_control) { - if (!bitmap_.width() || !bitmap_.height()) - return; + DCHECK(image_); + DCHECK_GT(image_->width(), 0); + DCHECK_GT(image_->height(), 0); SkScalar content_to_layer_scale_x = - SkFloatToScalar(static_cast<float>(bounds().width()) / bitmap_.width()); + SkFloatToScalar(static_cast<float>(bounds().width()) / image_->width()); SkScalar content_to_layer_scale_y = - SkFloatToScalar(static_cast<float>(bounds().height()) / bitmap_.height()); + SkFloatToScalar(static_cast<float>(bounds().height()) / image_->height()); canvas->scale(content_to_layer_scale_x, content_to_layer_scale_y); // Because Android WebView resourceless software draw mode rasters directly // to the root canvas, this draw must use the kSrcOver_Mode so that // transparent images blend correctly. - canvas->drawBitmap(bitmap_, 0, 0); + canvas->drawImage(image_.get(), 0, 0); } scoped_refptr<DisplayItemList> PictureImageLayer::PaintContentsToDisplayList( @@ -71,9 +74,10 @@ scoped_refptr<DisplayItemList> PictureImageLayer::PaintContentsToDisplayList( ContentLayerClient::PaintingControlSetting painting_control) { // Picture image layers can be used with GatherPixelRefs, so cached SkPictures // are currently required. - const bool use_cached_picture = true; + DisplayItemListSettings settings; + settings.use_cached_picture = true; scoped_refptr<DisplayItemList> display_list = - DisplayItemList::Create(clip, use_cached_picture); + DisplayItemList::Create(clip, settings); SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(clip)); @@ -92,4 +96,8 @@ bool PictureImageLayer::FillsBoundsCompletely() const { return false; } +size_t PictureImageLayer::GetApproximateUnsharedMemoryUsage() const { + return 0; +} + } // namespace cc diff --git a/chromium/cc/layers/picture_image_layer.h b/chromium/cc/layers/picture_image_layer.h index df597f3bf02..df3068683c3 100644 --- a/chromium/cc/layers/picture_image_layer.h +++ b/chromium/cc/layers/picture_image_layer.h @@ -8,16 +8,18 @@ #include "cc/base/cc_export.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/picture_layer.h" -#include "third_party/skia/include/core/SkBitmap.h" +#include "skia/ext/refptr.h" #include "ui/gfx/geometry/size.h" +class SkImage; + namespace cc { class CC_EXPORT PictureImageLayer : public PictureLayer, ContentLayerClient { public: static scoped_refptr<PictureImageLayer> Create(const LayerSettings& settings); - void SetBitmap(const SkBitmap& image); + void SetImage(skia::RefPtr<const SkImage> image); // Layer implementation. scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; @@ -31,6 +33,7 @@ class CC_EXPORT PictureImageLayer : public PictureLayer, ContentLayerClient { const gfx::Rect& clip, ContentLayerClient::PaintingControlSetting painting_control) override; bool FillsBoundsCompletely() const override; + size_t GetApproximateUnsharedMemoryUsage() const override; protected: bool HasDrawableContent() const override; @@ -39,7 +42,7 @@ class CC_EXPORT PictureImageLayer : public PictureLayer, ContentLayerClient { explicit PictureImageLayer(const LayerSettings& settings); ~PictureImageLayer() override; - SkBitmap bitmap_; + skia::RefPtr<const SkImage> image_; DISALLOW_COPY_AND_ASSIGN(PictureImageLayer); }; diff --git a/chromium/cc/layers/picture_image_layer_impl_unittest.cc b/chromium/cc/layers/picture_image_layer_impl_unittest.cc index 2a9dda710db..8d36095e0f3 100644 --- a/chromium/cc/layers/picture_image_layer_impl_unittest.cc +++ b/chromium/cc/layers/picture_image_layer_impl_unittest.cc @@ -7,10 +7,10 @@ #include "base/thread_task_runner_handle.h" #include "cc/layers/append_quads_data.h" #include "cc/quads/draw_quad.h" +#include "cc/test/fake_display_list_raster_source.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/test_shared_bitmap_manager.h" #include "cc/test/test_task_graph_runner.h" #include "cc/tiles/tile_priority.h" @@ -43,12 +43,13 @@ class PictureImageLayerImplTest : public testing::Test { public: PictureImageLayerImplTest() : proxy_(base::ThreadTaskRunnerHandle::Get()), + output_surface_(FakeOutputSurface::Create3d()), host_impl_(PictureLayerImplImageTestSettings(), &proxy_, &shared_bitmap_manager_, &task_graph_runner_) { host_impl_.CreatePendingTree(); - host_impl_.InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl_.InitializeRenderer(output_surface_.get()); } scoped_ptr<TestablePictureImageLayerImpl> CreateLayer(int id, @@ -64,7 +65,7 @@ class PictureImageLayerImplTest : public testing::Test { } TestablePictureImageLayerImpl* layer = new TestablePictureImageLayerImpl(tree, id); - layer->raster_source_ = FakePicturePileImpl::CreateInfiniteFilledPile(); + layer->raster_source_ = FakeDisplayListRasterSource::CreateInfiniteFilled(); layer->SetBounds(layer->raster_source_->GetSize()); return make_scoped_ptr(layer); } @@ -93,6 +94,7 @@ class PictureImageLayerImplTest : public testing::Test { FakeImplProxy proxy_; TestSharedBitmapManager shared_bitmap_manager_; TestTaskGraphRunner task_graph_runner_; + scoped_ptr<OutputSurface> output_surface_; FakeLayerTreeHostImpl host_impl_; }; diff --git a/chromium/cc/layers/picture_image_layer_unittest.cc b/chromium/cc/layers/picture_image_layer_unittest.cc index fafdbf12541..f9379c6e3f9 100644 --- a/chromium/cc/layers/picture_image_layer_unittest.cc +++ b/chromium/cc/layers/picture_image_layer_unittest.cc @@ -8,9 +8,10 @@ #include "cc/test/skia_common.h" #include "cc/trees/layer_tree_settings.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/SkImage.h" +#include "third_party/skia/include/core/SkSurface.h" namespace cc { namespace { @@ -20,19 +21,21 @@ TEST(PictureImageLayerTest, PaintContentsToDisplayList) { PictureImageLayer::Create(LayerSettings()); 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); + skia::RefPtr<SkSurface> image_surface = skia::AdoptRef( + SkSurface::NewRasterDirect(info, image_pixels, info.minRowBytes())); + SkCanvas* image_canvas = image_surface->getCanvas(); + 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); + 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); + skia::RefPtr<const SkImage> image = + skia::AdoptRef(image_surface->newImageSnapshot()); + layer->SetImage(image.Pass()); layer->SetBounds(gfx::Size(layer_rect.width(), layer_rect.height())); scoped_refptr<DisplayItemList> display_list = diff --git a/chromium/cc/layers/picture_layer.cc b/chromium/cc/layers/picture_layer.cc index 53d5d97d456..6c215a3eba8 100644 --- a/chromium/cc/layers/picture_layer.cc +++ b/chromium/cc/layers/picture_layer.cc @@ -8,7 +8,6 @@ #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" @@ -89,19 +88,15 @@ void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) { 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)); - } else { - recording_source_.reset(new PicturePile(settings.minimum_contents_scale, - settings.default_tile_grid_size)); - } - } + if (!recording_source_) + recording_source_.reset(new DisplayListRecordingSource); recording_source_->SetSlowdownRasterScaleFactor( host->debug_state().slow_down_raster_scale_factor); - recording_source_->SetGatherPixelRefs(settings.gather_pixel_refs); + // If we need to enable image decode tasks, then we have to generate the + // discardable images metadata. + const LayerTreeSettings& settings = layer_tree_host()->settings(); + recording_source_->SetGenerateDiscardableImagesMetadata( + settings.image_decode_tasks_enabled); } void PictureLayer::SetNeedsDisplayRect(const gfx::Rect& layer_rect) { @@ -181,33 +176,16 @@ skia::RefPtr<SkPicture> PictureLayer::GetPicture() const { return skia::RefPtr<SkPicture>(); 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)); - 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(); - } + scoped_ptr<RecordingSource> recording_source(new DisplayListRecordingSource); + Region recording_invalidation; + recording_source->UpdateAndExpandInvalidation( + client_, &recording_invalidation, layer_size, gfx::Rect(layer_size), + update_source_frame_number_, RecordingSource::RECORD_NORMALLY); - int width = layer_size.width(); - int height = layer_size.height(); + scoped_refptr<RasterSource> raster_source = + recording_source->CreateRasterSource(false); - SkPictureRecorder recorder; - SkCanvas* canvas = recorder.beginRecording(width, height, nullptr, 0); - client_->PaintContents(canvas, gfx::Rect(width, height), - ContentLayerClient::PAINTING_BEHAVIOR_NORMAL); - skia::RefPtr<SkPicture> picture = - skia::AdoptRef(recorder.endRecordingAsPicture()); - return picture; + return raster_source->GetFlattenedPicture(); } bool PictureLayer::IsSuitableForGpuRasterization() const { diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc index 90fdeb1efb4..a550968e69f 100644 --- a/chromium/cc/layers/picture_layer_impl.cc +++ b/chromium/cc/layers/picture_layer_impl.cc @@ -18,7 +18,6 @@ #include "cc/layers/append_quads_data.h" #include "cc/layers/solid_color_layer_impl.h" #include "cc/output/begin_frame_args.h" -#include "cc/quads/checkerboard_draw_quad.h" #include "cc/quads/debug_border_draw_quad.h" #include "cc/quads/picture_draw_quad.h" #include "cc/quads/solid_color_draw_quad.h" @@ -183,14 +182,22 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass, gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect(); gfx::Rect visible_geometry_rect = scaled_occlusion.GetUnoccludedContentRect(geometry_rect); - // TODO(enne): HasRecordings is a workaround for crash in crbug.com/526402. - // Need proper fix for when recording does not cover visible rect. - if (visible_geometry_rect.IsEmpty() || !raster_source_->HasRecordings()) + + // The raster source may not be valid over the entire visible rect, + // and rastering outside of that may cause incorrect pixels. + gfx::Rect scaled_recorded_viewport = gfx::ScaleToEnclosingRect( + raster_source_->RecordedViewport(), max_contents_scale); + geometry_rect.Intersect(scaled_recorded_viewport); + opaque_rect.Intersect(scaled_recorded_viewport); + visible_geometry_rect.Intersect(scaled_recorded_viewport); + + if (visible_geometry_rect.IsEmpty()) return; + DCHECK(raster_source_->HasRecordings()); gfx::Rect quad_content_rect = shared_quad_state->visible_quad_layer_rect; gfx::Size texture_size = quad_content_rect.size(); - gfx::RectF texture_rect = gfx::RectF(texture_size); + gfx::RectF texture_rect = gfx::RectF(gfx::SizeF(texture_size)); PictureDrawQuad* quad = render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); @@ -324,8 +331,11 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass, if (!has_draw_quad) { // Checkerboard. - // TODO(danakj): Make this a different color when debugging. SkColor color = SafeOpaqueBackgroundColor(); + if (ShowDebugBorders()) { + // Fill the whole tile with the missing tile color. + color = DebugColors::OOMTileBorderColor(); + } SolidColorDrawQuad* quad = render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); quad->SetNew(shared_quad_state, geometry_rect, visible_geometry_rect, @@ -336,8 +346,6 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass, append_quads_data->num_missing_tiles++; ++missing_tile_count; } - 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; @@ -405,6 +413,9 @@ bool PictureLayerImpl::UpdateTiles(bool resourceless_software_draw) { AddTilingsForRasterScale(); } + if (layer_tree_impl()->IsActiveTree()) + AddLowResolutionTilingIfNeeded(); + DCHECK(raster_page_scale_); DCHECK(raster_device_scale_); DCHECK(raster_source_scale_); @@ -414,7 +425,7 @@ bool PictureLayerImpl::UpdateTiles(bool resourceless_software_draw) { was_screen_space_transform_animating_ = draw_properties().screen_space_transform_is_animating; - if (draw_transform_is_animating()) + if (screen_space_transform_is_animating()) raster_source_->SetShouldAttemptToUseDistanceFieldText(); double current_frame_time_in_seconds = @@ -466,9 +477,8 @@ void PictureLayerImpl::UpdateViewportRectForTilePriorityInContentSpace() { gfx::Transform view_to_layer(gfx::Transform::kSkipInitialization); if (screen_space_transform().GetInverse(&view_to_layer)) { // Transform from view space to content space. - visible_rect_in_content_space = - gfx::ToEnclosingRect(MathUtil::ProjectClippedRect( - view_to_layer, viewport_rect_for_tile_priority)); + visible_rect_in_content_space = MathUtil::ProjectEnclosingClippedRect( + view_to_layer, viewport_rect_for_tile_priority); // We have to allow for a viewport that is outside of the layer bounds in // order to compute tile priorities correctly for offscreen content that @@ -579,8 +589,8 @@ bool PictureLayerImpl::RasterSourceUsesLCDText() const { void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) { if (layer_tree_impl()->IsActiveTree()) { - gfx::RectF layer_damage_rect = - gfx::ScaleRect(tile->content_rect(), 1.f / tile->contents_scale()); + gfx::Rect layer_damage_rect = gfx::ScaleToEnclosingRect( + tile->content_rect(), 1.f / tile->contents_scale()); AddDamageRect(layer_damage_rect); } if (tile->draw_info().NeedsRaster()) { @@ -624,8 +634,7 @@ Region PictureLayerImpl::GetInvalidationRegion() { return IntersectRegions(invalidation_, update_rect()); } -ScopedTilePtr PictureLayerImpl::CreateTile(float contents_scale, - const gfx::Rect& content_rect) { +ScopedTilePtr PictureLayerImpl::CreateTile(const Tile::CreateInfo& info) { int flags = 0; // We don't handle solid color masks, so we shouldn't bother analyzing those. @@ -633,9 +642,11 @@ ScopedTilePtr PictureLayerImpl::CreateTile(float contents_scale, if (!is_mask_) flags = Tile::USE_PICTURE_ANALYSIS; + if (contents_opaque()) + flags |= Tile::IS_OPAQUE; + return layer_tree_impl()->tile_manager()->CreateTile( - content_rect.size(), content_rect, contents_scale, id(), - layer_tree_impl()->source_frame_number(), flags); + info, id(), layer_tree_impl()->source_frame_number(), flags); } const Region* PictureLayerImpl::GetPendingInvalidation() { @@ -695,7 +706,8 @@ gfx::Size PictureLayerImpl::CalculateTileSize( divisor = 2; if (content_bounds.width() <= viewport_width / 4) divisor = 1; - default_tile_height = MathUtil::RoundUp(viewport_height, divisor) / divisor; + default_tile_height = + MathUtil::UncheckedRoundUp(viewport_height, divisor) / divisor; // Grow default sizes to account for overlapping border texels. default_tile_width += 2 * PictureLayerTiling::kBorderTexels; @@ -731,12 +743,12 @@ gfx::Size PictureLayerImpl::CalculateTileSize( // Clamp the tile width/height to the content width/height to save space. if (content_bounds.width() < default_tile_width) { tile_width = std::min(tile_width, content_bounds.width()); - tile_width = MathUtil::RoundUp(tile_width, kTileRoundUp); + tile_width = MathUtil::UncheckedRoundUp(tile_width, kTileRoundUp); tile_width = std::min(tile_width, default_tile_width); } if (content_bounds.height() < default_tile_height) { tile_height = std::min(tile_height, content_bounds.height()); - tile_height = MathUtil::RoundUp(tile_height, kTileRoundUp); + tile_height = MathUtil::UncheckedRoundUp(tile_height, kTileRoundUp); tile_height = std::min(tile_height, default_tile_height); } @@ -809,31 +821,18 @@ void PictureLayerImpl::AddTilingsForRasterScale() { 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) + if (!high_res) { + // We always need a high res tiling, so create one if it doesn't exist. high_res = AddTiling(raster_contents_scale_); - high_res->set_resolution(HIGH_RESOLUTION); - - // If the low res scale is the same as the high res scale, that tiling - // will be treated as high res. - if (layer_tree_impl()->create_low_res_tiling() && - raster_contents_scale_ != low_res_raster_contents_scale_) { - PictureLayerTiling* 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 is_pinching = layer_tree_impl()->PinchGestureActive(); - bool is_animating = draw_properties().screen_space_transform_is_animating; - if (!low_res && !is_pinching && !is_animating) - low_res = AddTiling(low_res_raster_contents_scale_); - - if (low_res) { - DCHECK_NE(low_res, high_res); - low_res->set_resolution(LOW_RESOLUTION); - } + } else if (high_res->may_contain_low_resolution_tiles()) { + // If the tiling we find here was LOW_RESOLUTION previously, it may not be + // fully rastered, so destroy the old tiles. + high_res->Reset(); + // Reset the flag now that we'll make it high res, it will have fully + // rastered content. + high_res->reset_may_contain_low_resolution_tiles(); } + 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 @@ -890,6 +889,34 @@ bool PictureLayerImpl::ShouldAdjustRasterScale() const { return false; } +void PictureLayerImpl::AddLowResolutionTilingIfNeeded() { + DCHECK(layer_tree_impl()->IsActiveTree()); + + if (!layer_tree_impl()->create_low_res_tiling()) + return; + + // We should have a high resolution tiling at raster_contents_scale, so if the + // low res one is the same then we shouldn't try to override this tiling by + // marking it as a low res. + if (raster_contents_scale_ == low_res_raster_contents_scale_) + return; + + PictureLayerTiling* low_res = + tilings_->FindTilingWithScale(low_res_raster_contents_scale_); + DCHECK_IMPLIES(low_res, low_res->resolution() != HIGH_RESOLUTION); + + // 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 is_pinching = layer_tree_impl()->PinchGestureActive(); + bool is_animating = draw_properties().screen_space_transform_is_animating; + if (!is_pinching && !is_animating) { + if (!low_res) + low_res = AddTiling(low_res_raster_contents_scale_); + low_res->set_resolution(LOW_RESOLUTION); + } +} + void PictureLayerImpl::RecalculateRasterScales() { float old_raster_contents_scale = raster_contents_scale_; float old_raster_page_scale = raster_page_scale_; @@ -953,8 +980,8 @@ void PictureLayerImpl::RecalculateRasterScales() { 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(raster_source_->GetSize(), maximum_scale)); + gfx::Size bounds_at_maximum_scale = + gfx::ScaleToCeiledSize(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(); @@ -964,8 +991,8 @@ void PictureLayerImpl::RecalculateRasterScales() { 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)); + gfx::Size bounds_at_starting_scale = + gfx::ScaleToCeiledSize(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(); @@ -994,8 +1021,8 @@ void PictureLayerImpl::RecalculateRasterScales() { // 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(raster_source_->GetSize(), raster_contents_scale_)); + gfx::Size raster_bounds = + gfx::ScaleToCeiledSize(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(); @@ -1035,9 +1062,9 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer( } PictureLayerTilingSet* twin_set = twin ? twin->tilings_.get() : nullptr; - tilings_->CleanUpTilings( - min_acceptable_high_res_scale, max_acceptable_high_res_scale, - used_tilings, layer_tree_impl()->create_low_res_tiling(), twin_set); + tilings_->CleanUpTilings(min_acceptable_high_res_scale, + max_acceptable_high_res_scale, used_tilings, + twin_set); DCHECK_GT(tilings_->num_tilings(), 0u); SanityCheckTilingState(); } @@ -1130,7 +1157,7 @@ scoped_ptr<PictureLayerTilingSet> PictureLayerImpl::CreatePictureLayerTilingSet() { const LayerTreeSettings& settings = layer_tree_impl()->settings(); return PictureLayerTilingSet::Create( - GetTree(), this, settings.max_tiles_for_interest_area, + GetTree(), this, settings.tiling_interest_area_padding, layer_tree_impl()->use_gpu_rasterization() ? settings.gpu_rasterization_skewport_target_time_in_seconds : settings.skewport_target_time_in_seconds, diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h index a23dbba61d7..409afaeb9ca 100644 --- a/chromium/cc/layers/picture_layer_impl.h +++ b/chromium/cc/layers/picture_layer_impl.h @@ -12,7 +12,6 @@ #include "cc/base/cc_export.h" #include "cc/base/scoped_ptr_vector.h" #include "cc/layers/layer_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" @@ -55,8 +54,7 @@ class CC_EXPORT PictureLayerImpl Region GetInvalidationRegion() override; // PictureLayerTilingClient overrides. - ScopedTilePtr CreateTile(float contents_scale, - const gfx::Rect& content_rect) override; + ScopedTilePtr CreateTile(const Tile::CreateInfo& info) override; gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override; const Region* GetPendingInvalidation() override; const PictureLayerTiling* GetPendingOrActiveTwinTiling( @@ -108,6 +106,7 @@ class CC_EXPORT PictureLayerImpl PictureLayerTiling* AddTiling(float contents_scale); void RemoveAllTilings(); void AddTilingsForRasterScale(); + void AddLowResolutionTilingIfNeeded(); virtual bool ShouldAdjustRasterScale() const; virtual void RecalculateRasterScales(); void CleanUpTilingsOnActiveLayer( diff --git a/chromium/cc/layers/picture_layer_impl_perftest.cc b/chromium/cc/layers/picture_layer_impl_perftest.cc index dcbf2fba85f..6c45b095142 100644 --- a/chromium/cc/layers/picture_layer_impl_perftest.cc +++ b/chromium/cc/layers/picture_layer_impl_perftest.cc @@ -6,11 +6,11 @@ #include "base/thread_task_runner_handle.h" #include "cc/debug/lap_timer.h" +#include "cc/test/fake_display_list_raster_source.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_layer_impl.h" -#include "cc/test/fake_picture_pile_impl.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" @@ -30,6 +30,7 @@ void AddTiling(float scale, std::vector<Tile*>* all_tiles) { PictureLayerTiling* tiling = layer->AddTiling(scale); + tiling->set_resolution(HIGH_RESOLUTION); tiling->CreateAllTilesForTesting(); std::vector<Tile*> tiling_tiles = tiling->AllTilesForTesting(); std::copy( @@ -40,6 +41,7 @@ class PictureLayerImplPerfTest : public testing::Test { public: PictureLayerImplPerfTest() : proxy_(base::ThreadTaskRunnerHandle::Get()), + output_surface_(FakeOutputSurface::Create3d()), host_impl_(LayerTreeSettings(), &proxy_, &shared_bitmap_manager_, @@ -49,24 +51,25 @@ class PictureLayerImplPerfTest : public testing::Test { kTimeCheckInterval) {} void SetUp() override { - host_impl_.InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl_.InitializeRenderer(output_surface_.get()); } - void SetupActiveTree(const gfx::Size& layer_bounds, - const gfx::Size& tile_size) { - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - LayerTreeImpl* active_tree = host_impl_.active_tree(); - active_tree->DetachLayerTree(); - - scoped_ptr<FakePictureLayerImpl> active_layer = - FakePictureLayerImpl::CreateWithRasterSource(active_tree, 7, pile); - active_layer->SetDrawsContent(true); - active_layer->SetHasRenderSurface(true); - active_tree->SetRootLayer(active_layer.Pass()); - - active_layer_ = static_cast<FakePictureLayerImpl*>( - host_impl_.active_tree()->LayerById(7)); + void SetupPendingTree(const gfx::Size& layer_bounds) { + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + host_impl_.CreatePendingTree(); + LayerTreeImpl* pending_tree = host_impl_.pending_tree(); + pending_tree->DetachLayerTree(); + + scoped_ptr<FakePictureLayerImpl> pending_layer = + FakePictureLayerImpl::CreateWithRasterSource(pending_tree, 7, + raster_source); + 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)); } void RunRasterQueueConstructAndIterateTest(const std::string& test_name, @@ -74,13 +77,13 @@ class PictureLayerImplPerfTest : public testing::Test { const gfx::Size& viewport_size) { host_impl_.SetViewportSize(viewport_size); bool update_lcd_text = false; - host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text); + host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text); timer_.Reset(); do { int count = num_tiles; scoped_ptr<TilingSetRasterQueueAll> queue(new TilingSetRasterQueueAll( - active_layer_->picture_layer_tiling_set(), false)); + pending_layer_->picture_layer_tiling_set(), false)); while (count--) { ASSERT_TRUE(!queue->IsEmpty()) << "count: " << count; ASSERT_TRUE(queue->Top().tile()) << "count: " << count; @@ -96,15 +99,15 @@ class PictureLayerImplPerfTest : public testing::Test { void RunRasterQueueConstructTest(const std::string& test_name, const gfx::Rect& viewport) { host_impl_.SetViewportSize(viewport.size()); - active_layer_->PushScrollOffsetFromMainThreadAndClobberActiveValue( + pending_layer_->PushScrollOffsetFromMainThread( gfx::ScrollOffset(viewport.x(), viewport.y())); bool update_lcd_text = false; - host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text); + host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text); timer_.Reset(); do { scoped_ptr<TilingSetRasterQueueAll> queue(new TilingSetRasterQueueAll( - active_layer_->picture_layer_tiling_set(), false)); + pending_layer_->picture_layer_tiling_set(), false)); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -117,15 +120,14 @@ class PictureLayerImplPerfTest : public testing::Test { int num_tiles, const gfx::Size& viewport_size) { host_impl_.SetViewportSize(viewport_size); - active_layer_->MarkAllTilingsUsed(); bool update_lcd_text = false; - host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text); + host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text); timer_.Reset(); do { int count = num_tiles; scoped_ptr<TilingSetEvictionQueue> queue(new TilingSetEvictionQueue( - active_layer_->picture_layer_tiling_set())); + pending_layer_->picture_layer_tiling_set())); while (count--) { ASSERT_TRUE(!queue->IsEmpty()) << "count: " << count; ASSERT_TRUE(queue->Top().tile()) << "count: " << count; @@ -142,16 +144,15 @@ class PictureLayerImplPerfTest : public testing::Test { void RunEvictionQueueConstructTest(const std::string& test_name, const gfx::Rect& viewport) { host_impl_.SetViewportSize(viewport.size()); - active_layer_->PushScrollOffsetFromMainThreadAndClobberActiveValue( + pending_layer_->PushScrollOffsetFromMainThread( gfx::ScrollOffset(viewport.x(), viewport.y())); - active_layer_->MarkAllTilingsUsed(); bool update_lcd_text = false; - host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text); + host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text); timer_.Reset(); do { scoped_ptr<TilingSetEvictionQueue> queue(new TilingSetEvictionQueue( - active_layer_->picture_layer_tiling_set())); + pending_layer_->picture_layer_tiling_set())); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -163,8 +164,9 @@ class PictureLayerImplPerfTest : public testing::Test { TestSharedBitmapManager shared_bitmap_manager_; TestTaskGraphRunner task_graph_runner_; FakeImplProxy proxy_; + scoped_ptr<OutputSurface> output_surface_; FakeLayerTreeHostImpl host_impl_; - FakePictureLayerImpl* active_layer_; + FakePictureLayerImpl* pending_layer_; LapTimer timer_; private: @@ -172,15 +174,15 @@ class PictureLayerImplPerfTest : public testing::Test { }; TEST_F(PictureLayerImplPerfTest, TilingSetRasterQueueConstructAndIterate) { - SetupActiveTree(gfx::Size(10000, 10000), gfx::Size(256, 256)); + SetupPendingTree(gfx::Size(10000, 10000)); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; - active_layer_->AddTiling(low_res_factor); - active_layer_->AddTiling(0.3f); - active_layer_->AddTiling(0.7f); - active_layer_->AddTiling(1.0f); - active_layer_->AddTiling(2.0f); + 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); RunRasterQueueConstructAndIterateTest("32_100x100", 32, gfx::Size(100, 100)); RunRasterQueueConstructAndIterateTest("32_500x500", 32, gfx::Size(500, 500)); @@ -189,15 +191,15 @@ TEST_F(PictureLayerImplPerfTest, TilingSetRasterQueueConstructAndIterate) { } TEST_F(PictureLayerImplPerfTest, TilingSetRasterQueueConstruct) { - SetupActiveTree(gfx::Size(10000, 10000), gfx::Size(256, 256)); + SetupPendingTree(gfx::Size(10000, 10000)); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; - active_layer_->AddTiling(low_res_factor); - active_layer_->AddTiling(0.3f); - active_layer_->AddTiling(0.7f); - active_layer_->AddTiling(1.0f); - active_layer_->AddTiling(2.0f); + 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); RunRasterQueueConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100)); RunRasterQueueConstructTest("5000_0_100x100", gfx::Rect(5000, 0, 100, 100)); @@ -205,16 +207,16 @@ TEST_F(PictureLayerImplPerfTest, TilingSetRasterQueueConstruct) { } TEST_F(PictureLayerImplPerfTest, TilingSetEvictionQueueConstructAndIterate) { - SetupActiveTree(gfx::Size(10000, 10000), gfx::Size(256, 256)); + SetupPendingTree(gfx::Size(10000, 10000)); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; std::vector<Tile*> all_tiles; - AddTiling(low_res_factor, active_layer_, &all_tiles); - AddTiling(0.3f, active_layer_, &all_tiles); - AddTiling(0.7f, active_layer_, &all_tiles); - AddTiling(1.0f, active_layer_, &all_tiles); - AddTiling(2.0f, active_layer_, &all_tiles); + AddTiling(low_res_factor, pending_layer_, &all_tiles); + AddTiling(0.3f, pending_layer_, &all_tiles); + AddTiling(0.7f, pending_layer_, &all_tiles); + AddTiling(1.0f, pending_layer_, &all_tiles); + AddTiling(2.0f, pending_layer_, &all_tiles); ASSERT_TRUE(host_impl_.tile_manager() != nullptr); host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles); @@ -230,16 +232,16 @@ TEST_F(PictureLayerImplPerfTest, TilingSetEvictionQueueConstructAndIterate) { } TEST_F(PictureLayerImplPerfTest, TilingSetEvictionQueueConstruct) { - SetupActiveTree(gfx::Size(10000, 10000), gfx::Size(256, 256)); + SetupPendingTree(gfx::Size(10000, 10000)); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; std::vector<Tile*> all_tiles; - AddTiling(low_res_factor, active_layer_, &all_tiles); - AddTiling(0.3f, active_layer_, &all_tiles); - AddTiling(0.7f, active_layer_, &all_tiles); - AddTiling(1.0f, active_layer_, &all_tiles); - AddTiling(2.0f, active_layer_, &all_tiles); + AddTiling(low_res_factor, pending_layer_, &all_tiles); + AddTiling(0.3f, pending_layer_, &all_tiles); + AddTiling(0.7f, pending_layer_, &all_tiles); + AddTiling(1.0f, pending_layer_, &all_tiles); + AddTiling(2.0f, pending_layer_, &all_tiles); ASSERT_TRUE(host_impl_.tile_manager() != nullptr); host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles); diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc index 6e89caa802a..78f56fd90f5 100644 --- a/chromium/cc/layers/picture_layer_impl_unittest.cc +++ b/chromium/cc/layers/picture_layer_impl_unittest.cc @@ -18,11 +18,12 @@ #include "cc/quads/tile_draw_quad.h" #include "cc/test/begin_frame_args_test.h" #include "cc/test/fake_content_layer_client.h" +#include "cc/test/fake_display_list_raster_source.h" +#include "cc/test/fake_display_list_recording_source.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_layer_impl.h" -#include "cc/test/fake_picture_pile_impl.h" #include "cc/test/geometry_test_utils.h" #include "cc/test/gpu_rasterization_enabled_settings.h" #include "cc/test/layer_test_common.h" @@ -51,6 +52,18 @@ namespace { EXPECT_NE(x, active_layer_->expression); \ } while (false) +#define EXPECT_BOTH_TRUE(expression) \ + do { \ + EXPECT_TRUE(pending_layer_->expression); \ + EXPECT_TRUE(active_layer_->expression); \ + } while (false) + +#define EXPECT_BOTH_FALSE(expression) \ + do { \ + EXPECT_FALSE(pending_layer_->expression); \ + EXPECT_FALSE(active_layer_->expression); \ + } while (false) + class MockCanvas : public SkCanvas { public: explicit MockCanvas(int w, int h) : SkCanvas(w, h) {} @@ -81,6 +94,7 @@ class PictureLayerImplTest : public testing::Test { public: PictureLayerImplTest() : proxy_(base::ThreadTaskRunnerHandle::Get()), + output_surface_(FakeOutputSurface::Create3d()), host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_, @@ -95,6 +109,7 @@ class PictureLayerImplTest : public testing::Test { explicit PictureLayerImplTest(const LayerTreeSettings& settings) : proxy_(base::ThreadTaskRunnerHandle::Get()), + output_surface_(FakeOutputSurface::Create3d()), host_impl_(settings, &proxy_, &shared_bitmap_manager_, @@ -109,30 +124,27 @@ class PictureLayerImplTest : public testing::Test { void SetUp() override { InitializeRenderer(); } virtual void InitializeRenderer() { - host_impl_.InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl_.InitializeRenderer(output_surface_.get()); } void SetupDefaultTrees(const gfx::Size& layer_bounds) { - gfx::Size tile_size(100, 100); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - 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); + SetupTrees(pending_raster_source, active_raster_source); } 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); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupTreesWithInvalidation(pending_pile, active_pile, invalidation); + SetupTreesWithInvalidation(pending_raster_source, active_raster_source, + invalidation); } void ActivateTree() { @@ -151,40 +163,41 @@ class PictureLayerImplTest : public testing::Test { void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds, const gfx::Size& tile_size, const Region& invalidation) { - gfx::Size pile_tile_size(100, 100); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - 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); + SetupTreesWithFixedTileSize(pending_raster_source, active_raster_source, + tile_size, invalidation); } - void SetupTrees( - scoped_refptr<PicturePileImpl> pending_pile, - scoped_refptr<PicturePileImpl> active_pile) { - SetupPendingTree(active_pile); + void SetupTrees(scoped_refptr<RasterSource> pending_raster_source, + scoped_refptr<RasterSource> active_raster_source) { + SetupPendingTree(active_raster_source); ActivateTree(); - SetupPendingTreeInternal(pending_pile, gfx::Size(), Region()); + SetupPendingTreeInternal(pending_raster_source, 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()); + void SetupTreesWithInvalidation( + scoped_refptr<RasterSource> pending_raster_source, + scoped_refptr<RasterSource> active_raster_source, + const Region& pending_invalidation) { + SetupPendingTreeInternal(active_raster_source, gfx::Size(), Region()); ActivateTree(); - SetupPendingTreeInternal(pending_pile, gfx::Size(), pending_invalidation); + SetupPendingTreeInternal(pending_raster_source, 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()); + void SetupTreesWithFixedTileSize( + scoped_refptr<RasterSource> pending_raster_source, + scoped_refptr<RasterSource> active_raster_source, + const gfx::Size& tile_size, + const Region& pending_invalidation) { + SetupPendingTreeInternal(active_raster_source, tile_size, Region()); ActivateTree(); - SetupPendingTreeInternal(pending_pile, tile_size, pending_invalidation); + SetupPendingTreeInternal(pending_raster_source, tile_size, + pending_invalidation); } void SetupPendingTree(scoped_refptr<RasterSource> raster_source) { @@ -211,6 +224,8 @@ class PictureLayerImplTest : public testing::Test { host_impl_.pending_tree()->PushPageScaleFromMainThread(1.f, 0.00001f, 100000.f); LayerTreeImpl* pending_tree = host_impl_.pending_tree(); + pending_tree->SetDeviceScaleFactor( + host_impl_.active_tree()->device_scale_factor()); // Steal from the recycled tree if possible. scoped_ptr<LayerImpl> pending_root = pending_tree->DetachLayerTree(); @@ -229,7 +244,7 @@ class PictureLayerImplTest : public testing::Test { pending_layer->set_fixed_tile_size(tile_size); } pending_root->SetHasRenderSurface(true); - // The bounds() just mirror the pile size. + // The bounds() just mirror the raster source size. pending_layer->SetBounds(raster_source->GetSize()); pending_layer->SetRasterSourceOnPending(raster_source, invalidation); @@ -252,8 +267,8 @@ class PictureLayerImplTest : public testing::Test { float maximum_animation_contents_scale, float starting_animation_contents_scale, bool animating_transform_to_screen) { - host_impl_.SetDeviceScaleFactor(device_scale_factor); - host_impl_.SetPageScaleOnActiveTree(page_scale_factor); + layer->layer_tree_impl()->SetDeviceScaleFactor(device_scale_factor); + host_impl_.active_tree()->SetPageScaleOnActiveTree(page_scale_factor); gfx::Transform scale_transform; scale_transform.Scale(ideal_contents_scale, ideal_contents_scale); @@ -268,9 +283,9 @@ class PictureLayerImplTest : public testing::Test { bool resourceless_software_draw = false; layer->UpdateTiles(resourceless_software_draw); } - static void VerifyAllPrioritizedTilesExistAndHavePile( + static void VerifyAllPrioritizedTilesExistAndHaveRasterSource( const PictureLayerTiling* tiling, - PicturePileImpl* pile) { + RasterSource* raster_source) { auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting(); for (PictureLayerTiling::CoverageIterator iter( @@ -280,7 +295,7 @@ class PictureLayerImplTest : public testing::Test { iter; ++iter) { EXPECT_TRUE(*iter); - EXPECT_EQ(pile, prioritized_tiles[*iter].raster_source()); + EXPECT_EQ(raster_source, prioritized_tiles[*iter].raster_source()); } } @@ -341,12 +356,23 @@ class PictureLayerImplTest : public testing::Test { EXPECT_GT(tiles.size(), 0u); } + void SetInitialDeviceScaleFactor(float device_scale_factor) { + // Device scale factor is a per-tree property. However, tests can't directly + // set the pending tree's device scale factor before the pending tree is + // created, and setting it after SetupPendingTreeInternal is too late, since + // draw properties will already have been updated on the tree. To handle + // this, we initially set only the active tree's device scale factor, and we + // copy this over to the pending tree inside SetupPendingTreeInternal. + host_impl_.active_tree()->SetDeviceScaleFactor(device_scale_factor); + } + protected: void TestQuadsForSolidColor(bool test_for_solid); FakeImplProxy proxy_; TestSharedBitmapManager shared_bitmap_manager_; TestTaskGraphRunner task_graph_runner_; + scoped_ptr<OutputSurface> output_surface_; FakeLayerTreeHostImpl host_impl_; int root_id_; int id_; @@ -371,41 +397,49 @@ TEST_F(PictureLayerImplTest, TileGridAlignment) { 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<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_size); - scoped_ptr<FakePicturePile> active_recording = - FakePicturePile::CreateFilledPile(layer_size, layer_size); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFromPile(active_recording.get(), nullptr); + // Create an active recording source, but make sure it's not solid. + scoped_ptr<FakeDisplayListRecordingSource> active_recording_source = + FakeDisplayListRecordingSource::CreateFilledRecordingSource(layer_size); + active_recording_source->add_draw_rect(gfx::Rect(layer_size)); + active_recording_source->add_draw_rect( + gfx::Rect(0, 0, layer_size.width() - 1, layer_size.height() - 1)); + active_recording_source->Rerecord(); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource( + active_recording_source.get(), false); - SetupTrees(pending_pile, active_pile); + SetupTrees(pending_raster_source, active_raster_source); - // Add 1x1 rects at the centers of each tile, then re-record pile contents + // Add 1x1 rects at the centers of each tile, then re-record recording source + // 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; + active_recording_source->reset_draws(); 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); + active_recording_source->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); + active_recording_source->Rerecord(); - scoped_refptr<FakePicturePileImpl> updated_active_pile = - FakePicturePileImpl::CreateFromPile(active_recording.get(), nullptr); + scoped_refptr<FakeDisplayListRasterSource> updated_active_raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource( + active_recording_source.get(), false); 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( + updated_active_raster_source->PlaybackToSharedCanvas( &mock_canvas, (*tile_iter)->content_rect(), 1.0f); // This test verifies that when drawing the contents of a specific tile @@ -419,15 +453,8 @@ TEST_F(PictureLayerImplTest, TileGridAlignment) { } TEST_F(PictureLayerImplTest, CloneNoInvalidation) { - 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()); + SetupDefaultTrees(layer_bounds); EXPECT_EQ(pending_layer_->tilings()->num_tilings(), active_layer_->tilings()->num_tilings()); @@ -440,15 +467,8 @@ TEST_F(PictureLayerImplTest, CloneNoInvalidation) { TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - 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()); + SetupDefaultTrees(layer_bounds); SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f, false); @@ -512,8 +532,8 @@ TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) { // bounds, then tile priorities will end up being incorrect in cases of fully // offscreen layer. viewport_rect_for_tile_priority_in_view_space = - gfx::ToEnclosingRect(MathUtil::ProjectClippedRect( - screen_to_view, viewport_rect_for_tile_priority)); + MathUtil::ProjectEnclosingClippedRect(screen_to_view, + viewport_rect_for_tile_priority); EXPECT_EQ(viewport_rect_for_tile_priority_in_view_space, active_layer_->viewport_rect_for_tile_priority_in_content_space()); @@ -529,16 +549,8 @@ TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) { TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - - 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()); + SetupDefaultTrees(layer_bounds); SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f, false); @@ -606,15 +618,8 @@ TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) { TEST_F(PictureLayerImplTest, ViewportRectForTilePriorityIsCached) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - 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()); + SetupDefaultTrees(layer_bounds); SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f, false); @@ -655,31 +660,32 @@ TEST_F(PictureLayerImplTest, ViewportRectForTilePriorityIsCached) { } TEST_F(PictureLayerImplTest, ClonePartialInvalidation) { - gfx::Size tile_size(100, 100); gfx::Size layer_bounds(400, 400); gfx::Rect layer_invalidation(150, 200, 30, 180); - scoped_refptr<FakePicturePileImpl> pending_pile = - 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); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> lost_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupPendingTreeWithFixedTileSize(lost_pile, gfx::Size(50, 50), Region()); + SetupPendingTreeWithFixedTileSize(lost_raster_source, gfx::Size(50, 50), + Region()); ActivateTree(); // Add a unique tiling on the active tree. PictureLayerTiling* tiling = active_layer_->AddTiling(3.f); + tiling->set_resolution(HIGH_RESOLUTION); tiling->CreateAllTilesForTesting(); // 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); + SetupTreesWithFixedTileSize(pending_raster_source, active_raster_source, + gfx::Size(50, 50), layer_invalidation); - EXPECT_EQ(2u, pending_layer_->num_tilings()); + EXPECT_EQ(1u, pending_layer_->num_tilings()); EXPECT_EQ(3u, active_layer_->num_tilings()); const PictureLayerTilingSet* tilings = pending_layer_->tilings(); @@ -701,7 +707,8 @@ TEST_F(PictureLayerImplTest, ClonePartialInvalidation) { // 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_EQ(pending_raster_source.get(), + prioritized_tiles[*iter].raster_source()); EXPECT_TRUE(iter.geometry_rect().Intersects(content_invalidation)); } else { // We don't create tiles in non-invalidated regions. @@ -726,22 +733,22 @@ TEST_F(PictureLayerImplTest, ClonePartialInvalidation) { ++iter) { EXPECT_TRUE(*iter); EXPECT_FALSE(iter.geometry_rect().IsEmpty()); - // Pile will be updated upon activation. - EXPECT_EQ(active_pile.get(), prioritized_tiles[*iter].raster_source()); + // Raster source will be updated upon activation. + EXPECT_EQ(active_raster_source.get(), + prioritized_tiles[*iter].raster_source()); } } } 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); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupTreesWithInvalidation(pending_pile, active_pile, + SetupTreesWithInvalidation(pending_raster_source, active_raster_source, gfx::Rect(layer_bounds)); EXPECT_EQ(pending_layer_->tilings()->num_tilings(), @@ -749,21 +756,15 @@ TEST_F(PictureLayerImplTest, CloneFullInvalidation) { const PictureLayerTilingSet* tilings = pending_layer_->tilings(); EXPECT_GT(tilings->num_tilings(), 0u); - for (size_t i = 0; i < tilings->num_tilings(); ++i) - VerifyAllPrioritizedTilesExistAndHavePile(tilings->tiling_at(i), - pending_pile.get()); + for (size_t i = 0; i < tilings->num_tilings(); ++i) { + VerifyAllPrioritizedTilesExistAndHaveRasterSource( + tilings->tiling_at(i), pending_raster_source.get()); + } } TEST_F(PictureLayerImplTest, UpdateTilesCreatesTilings) { - 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); + SetupDefaultTrees(layer_bounds); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; EXPECT_LT(low_res_factor, 1.f); @@ -830,16 +831,9 @@ TEST_F(PictureLayerImplTest, UpdateTilesCreatesTilings) { active_layer_->tilings()->tiling_at(3)->contents_scale()); } -TEST_F(PictureLayerImplTest, PendingLayerOnlyHasHighAndLowResTiling) { - gfx::Size tile_size(400, 400); +TEST_F(PictureLayerImplTest, PendingLayerOnlyHasHighResTiling) { 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); + SetupDefaultTrees(layer_bounds); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; EXPECT_LT(low_res_factor, 1.f); @@ -856,11 +850,9 @@ TEST_F(PictureLayerImplTest, PendingLayerOnlyHasHighAndLowResTiling) { 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.f, pending_layer_->tilings()->tiling_at(0)->contents_scale()); - EXPECT_FLOAT_EQ(6.f * low_res_factor, - pending_layer_->tilings()->tiling_at(1)->contents_scale()); // If we change the page scale factor, then we should get new tilings. SetupDrawPropertiesAndUpdateTiles(pending_layer_, @@ -870,11 +862,9 @@ TEST_F(PictureLayerImplTest, PendingLayerOnlyHasHighAndLowResTiling) { 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()); - EXPECT_FLOAT_EQ(6.6f * low_res_factor, - pending_layer_->tilings()->tiling_at(1)->contents_scale()); // If we change the device scale factor, then we should get new tilings. SetupDrawPropertiesAndUpdateTiles(pending_layer_, @@ -884,11 +874,9 @@ TEST_F(PictureLayerImplTest, PendingLayerOnlyHasHighAndLowResTiling) { 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(7.26f, pending_layer_->tilings()->tiling_at(0)->contents_scale()); - EXPECT_FLOAT_EQ(7.26f * low_res_factor, - 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. @@ -899,30 +887,27 @@ TEST_F(PictureLayerImplTest, PendingLayerOnlyHasHighAndLowResTiling) { 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(7.26f, pending_layer_->tilings()->tiling_at(0)->contents_scale()); - EXPECT_FLOAT_EQ(7.26f * low_res_factor, - pending_layer_->tilings()->tiling_at(1)->contents_scale()); } TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) { // This test makes sure that if a layer can have tilings, then a commit makes // it not able to have tilings (empty size), and then a future commit that // makes it valid again should be able to create tilings. - gfx::Size tile_size(400, 400); gfx::Size layer_bounds(1300, 1900); - scoped_refptr<FakePicturePileImpl> empty_pile = - FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds); - scoped_refptr<FakePicturePileImpl> valid_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> empty_raster_source = + FakeDisplayListRasterSource::CreateEmpty(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> valid_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupPendingTree(valid_pile); - ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings()); + SetupPendingTree(valid_raster_source); + ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings()); ActivateTree(); - SetupPendingTree(empty_pile); + SetupPendingTree(empty_raster_source); EXPECT_FALSE(pending_layer_->CanHaveTilings()); ASSERT_EQ(2u, active_layer_->tilings()->num_tilings()); ASSERT_EQ(0u, pending_layer_->tilings()->num_tilings()); @@ -931,22 +916,43 @@ TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) { EXPECT_FALSE(active_layer_->CanHaveTilings()); ASSERT_EQ(0u, active_layer_->tilings()->num_tilings()); - SetupPendingTree(valid_pile); - ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings()); + SetupPendingTree(valid_raster_source); + ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings()); ASSERT_EQ(0u, active_layer_->tilings()->num_tilings()); } +TEST_F(PictureLayerImplTest, LowResTilingStaysOnActiveTree) { + gfx::Size layer_bounds(1300, 1900); + + scoped_refptr<FakeDisplayListRasterSource> valid_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> other_valid_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + + SetupPendingTree(valid_raster_source); + ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings()); + + ActivateTree(); + SetupPendingTree(other_valid_raster_source); + ASSERT_EQ(2u, active_layer_->tilings()->num_tilings()); + ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings()); + auto* low_res_tiling = + active_layer_->tilings()->FindTilingWithResolution(LOW_RESOLUTION); + EXPECT_TRUE(low_res_tiling); + + ActivateTree(); + ASSERT_EQ(2u, active_layer_->tilings()->num_tilings()); + auto* other_low_res_tiling = + active_layer_->tilings()->FindTilingWithResolution(LOW_RESOLUTION); + EXPECT_TRUE(other_low_res_tiling); + EXPECT_EQ(low_res_tiling, other_low_res_tiling); +} + TEST_F(PictureLayerImplTest, ZoomOutCrash) { - gfx::Size tile_size(400, 400); gfx::Size layer_bounds(1300, 1900); // Set up the high and low res tilings before pinch zoom. - 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); + SetupDefaultTrees(layer_bounds); ResetTilingsAndRasterScales(); EXPECT_EQ(0u, active_layer_->tilings()->num_tilings()); SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, 1.0f, 0.f, false); @@ -958,25 +964,22 @@ TEST_F(PictureLayerImplTest, ZoomOutCrash) { } 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 = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - // Set up the high and low res tilings before pinch zoom. - SetupTrees(pending_pile, active_pile); + SetupDefaultTrees(layer_bounds); 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); + EXPECT_EQ(active_layer_->num_tilings(), 2u); + EXPECT_EQ(pending_layer_->num_tilings(), 1u); + EXPECT_EQ(active_layer_->tilings()->tiling_at(0)->contents_scale(), 2.f); + EXPECT_EQ(active_layer_->tilings()->tiling_at(1)->contents_scale(), + 2.f * low_res_factor); + // One of the tilings has to be a low resolution one. + EXPECT_EQ(LOW_RESOLUTION, + active_layer_->tilings()->tiling_at(1)->resolution()); // Ensure UpdateTiles won't remove any tilings. active_layer_->MarkAllTilingsUsed(); @@ -994,6 +997,9 @@ TEST_F(PictureLayerImplTest, PinchGestureTilings) { active_layer_->tilings()->tiling_at(1)->contents_scale()); EXPECT_FLOAT_EQ(2.0f * low_res_factor, active_layer_->tilings()->tiling_at(2)->contents_scale()); + // Since we're pinching, we shouldn't create a low resolution tiling. + EXPECT_FALSE( + active_layer_->tilings()->FindTilingWithResolution(LOW_RESOLUTION)); // Ensure UpdateTiles won't remove any tilings. active_layer_->MarkAllTilingsUsed(); @@ -1003,6 +1009,8 @@ TEST_F(PictureLayerImplTest, PinchGestureTilings) { 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()); + EXPECT_FALSE( + active_layer_->tilings()->FindTilingWithResolution(LOW_RESOLUTION)); // Zoom in a lot now. Since we increase by increments of // kMaxScaleRatioDuringPinch, this will create a new tiling at 4.0. @@ -1010,18 +1018,36 @@ TEST_F(PictureLayerImplTest, PinchGestureTilings) { EXPECT_EQ(4u, active_layer_->tilings()->num_tilings()); EXPECT_FLOAT_EQ(4.0f, active_layer_->tilings()->tiling_at(0)->contents_scale()); + // Although one of the tilings matches the low resolution scale, it still + // shouldn't be marked as low resolution since we're pinching. + auto* low_res_tiling = + active_layer_->tilings()->FindTilingWithScale(4.f * low_res_factor); + EXPECT_TRUE(low_res_tiling); + EXPECT_NE(LOW_RESOLUTION, low_res_tiling->resolution()); + + // Stop a pinch gesture. + host_impl_.PinchGestureEnd(); + + // Ensure UpdateTiles won't remove any tilings. + active_layer_->MarkAllTilingsUsed(); + + // After pinch ends, set the scale to what the raster scale was updated to + // (checked above). + SetContentsScaleOnBothLayers(4.0f, 1.0f, 4.0f, 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()); + // Now that we stopped pinching, the low resolution tiling that existed should + // now be marked as low resolution. + low_res_tiling = + active_layer_->tilings()->FindTilingWithScale(4.f * low_res_factor); + EXPECT_TRUE(low_res_tiling); + EXPECT_EQ(LOW_RESOLUTION, low_res_tiling->resolution()); } TEST_F(PictureLayerImplTest, SnappedTilingDuringZoom) { - gfx::Size tile_size(300, 300); gfx::Size layer_bounds(2600, 3800); - - 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); + SetupDefaultTrees(layer_bounds); ResetTilingsAndRasterScales(); EXPECT_EQ(0u, active_layer_->tilings()->num_tilings()); @@ -1073,14 +1099,8 @@ TEST_F(PictureLayerImplTest, SnappedTilingDuringZoom) { } TEST_F(PictureLayerImplTest, CleanUpTilings) { - 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; float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; @@ -1089,7 +1109,7 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) { float scale = 1.f; float page_scale = 1.f; - SetupTrees(pending_pile, active_pile); + SetupDefaultTrees(layer_bounds); EXPECT_EQ(2u, active_layer_->tilings()->num_tilings()); EXPECT_EQ(1.f, active_layer_->HighResTiling()->contents_scale()); @@ -1219,8 +1239,9 @@ TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) { maximum_animation_scale, 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); + EXPECT_EQ(active_layer_->LowResTiling()->contents_scale(), low_res_factor); + EXPECT_EQ(active_layer_->num_tilings(), 2u); + EXPECT_EQ(pending_layer_->num_tilings(), 1u); // Ensure UpdateTiles won't remove any tilings. active_layer_->MarkAllTilingsUsed(); @@ -1247,21 +1268,21 @@ TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) { maximum_animation_scale, 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_EQ(active_layer_->LowResTiling()->contents_scale(), + 2.f * low_res_factor); EXPECT_EQ(4u, active_layer_->num_tilings()); - EXPECT_EQ(2u, pending_layer_->num_tilings()); + EXPECT_EQ(1u, pending_layer_->num_tilings()); } TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) { gfx::Size layer_bounds(host_impl_.settings().default_tile_size); - 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); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupTrees(pending_pile, active_pile); + SetupTrees(pending_raster_source, active_raster_source); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; float device_scale = 1.f; @@ -1297,14 +1318,16 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) { maximum_animation_scale, 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); + EXPECT_EQ(active_layer_->LowResTiling()->contents_scale(), + contents_scale * low_res_factor); + EXPECT_FALSE(pending_layer_->LowResTiling()); + EXPECT_EQ(active_layer_->num_tilings(), 2u); + EXPECT_EQ(pending_layer_->num_tilings(), 1u); // Mask layers dont create low res since they always fit on one tile. scoped_ptr<FakePictureLayerImpl> mask = FakePictureLayerImpl::CreateMaskWithRasterSource( - host_impl_.pending_tree(), 3, pending_pile); + host_impl_.pending_tree(), 3, pending_raster_source); mask->SetBounds(layer_bounds); mask->SetDrawsContent(true); @@ -1318,21 +1341,21 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) { TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); - scoped_refptr<FakePicturePileImpl> valid_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTree(valid_pile); + scoped_refptr<FakeDisplayListRasterSource> valid_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(valid_raster_source); scoped_ptr<FakePictureLayerImpl> mask_ptr = FakePictureLayerImpl::CreateMaskWithRasterSource( - host_impl_.pending_tree(), 3, valid_pile); + host_impl_.pending_tree(), 3, valid_raster_source); mask_ptr->SetBounds(layer_bounds); mask_ptr->SetDrawsContent(true); pending_layer_->SetMaskLayer(mask_ptr.Pass()); pending_layer_->SetHasRenderSurface(true); + host_impl_.pending_tree()->BuildPropertyTreesForTesting(); host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); bool update_lcd_text = false; host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text); @@ -1375,12 +1398,12 @@ TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) { // 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, huge_bounds); + scoped_refptr<FakeDisplayListRasterSource> huge_raster_source = + FakeDisplayListRasterSource::CreateFilled(huge_bounds); - SetupPendingTree(huge_pile); + SetupPendingTree(huge_raster_source); pending_mask->SetBounds(huge_bounds); - pending_mask->SetRasterSourceOnPending(huge_pile, Region()); + pending_mask->SetRasterSourceOnPending(huge_raster_source, Region()); host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text); @@ -1416,7 +1439,7 @@ TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) { EXPECT_EQ(expected_size, mask_texture_size); // Do another activate, the same holds. - SetupPendingTree(huge_pile); + SetupPendingTree(huge_raster_source); ActivateTree(); EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size()); active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size); @@ -1427,12 +1450,12 @@ TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) { // 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); + scoped_refptr<FakeDisplayListRasterSource> extra_huge_raster_source = + FakeDisplayListRasterSource::CreateFilled(extra_huge_bounds); - SetupPendingTree(extra_huge_pile); + SetupPendingTree(extra_huge_raster_source); pending_mask->SetBounds(extra_huge_bounds); - pending_mask->SetRasterSourceOnPending(extra_huge_pile, Region()); + pending_mask->SetRasterSourceOnPending(extra_huge_raster_source, Region()); EXPECT_FALSE(pending_mask->CanHaveTilings()); @@ -1445,23 +1468,23 @@ TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) { TEST_F(PictureLayerImplTest, ScaledMaskLayer) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); - host_impl_.SetDeviceScaleFactor(1.3f); + SetInitialDeviceScaleFactor(1.3f); - scoped_refptr<FakePicturePileImpl> valid_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTree(valid_pile); + scoped_refptr<FakeDisplayListRasterSource> valid_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(valid_raster_source); scoped_ptr<FakePictureLayerImpl> mask_ptr = FakePictureLayerImpl::CreateMaskWithRasterSource( - host_impl_.pending_tree(), 3, valid_pile); + host_impl_.pending_tree(), 3, valid_raster_source); mask_ptr->SetBounds(layer_bounds); mask_ptr->SetDrawsContent(true); pending_layer_->SetMaskLayer(mask_ptr.Pass()); pending_layer_->SetHasRenderSurface(true); + host_impl_.pending_tree()->BuildPropertyTreesForTesting(); host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); bool update_lcd_text = false; host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text); @@ -1489,21 +1512,14 @@ TEST_F(PictureLayerImplTest, ScaledMaskLayer) { 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_mask->bounds(), 1.3f)); + gfx::ScaleToCeiledSize(active_mask->bounds(), 1.3f); EXPECT_EQ(mask_texture_size, expected_mask_texture_size); } TEST_F(PictureLayerImplTest, ReleaseResources) { - 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); - EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings()); + SetupDefaultTrees(layer_bounds); + EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings()); // All tilings should be removed when losing output surface. active_layer_->ReleaseResources(); @@ -1523,18 +1539,16 @@ TEST_F(PictureLayerImplTest, ReleaseResources) { 1.f, // maximum animation scale 0.f, // starting animation_scale false); - EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings()); + EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings()); } 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<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupPendingTree(pending_pile); + SetupPendingTree(pending_raster_source); EXPECT_GE(pending_layer_->tilings()->num_tilings(), 1u); pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting(); @@ -1554,12 +1568,14 @@ TEST_F(PictureLayerImplTest, ClampTilesToMaxTileSize) { TestWebGraphicsContext3D::Create(); context->set_max_texture_size(140); host_impl_.DidLoseOutputSurface(); - host_impl_.InitializeRenderer( - FakeOutputSurface::Create3d(context.Pass()).Pass()); + scoped_ptr<OutputSurface> new_output_surface = + FakeOutputSurface::Create3d(context.Pass()); + host_impl_.InitializeRenderer(new_output_surface.get()); + output_surface_ = new_output_surface.Pass(); SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, 0.f, false); - ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings()); + ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings()); pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting(); @@ -1570,16 +1586,8 @@ TEST_F(PictureLayerImplTest, ClampTilesToMaxTileSize) { } TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) { - // The default max tile size is larger than 400x400. - gfx::Size tile_size(400, 400); gfx::Size layer_bounds(500, 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); + SetupDefaultTrees(layer_bounds); EXPECT_GE(active_layer_->tilings()->num_tilings(), 1u); active_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting(); @@ -1599,8 +1607,10 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) { TestWebGraphicsContext3D::Create(); context->set_max_texture_size(140); host_impl_.DidLoseOutputSurface(); - host_impl_.InitializeRenderer( - FakeOutputSurface::Create3d(context.Pass()).Pass()); + scoped_ptr<OutputSurface> new_output_surface = + FakeOutputSurface::Create3d(context.Pass()); + host_impl_.InitializeRenderer(new_output_surface.get()); + output_surface_ = new_output_surface.Pass(); SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f, false); @@ -1622,17 +1632,13 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) { TEST_F(PictureLayerImplTest, DisallowTileDrawQuads) { scoped_ptr<RenderPass> render_pass = RenderPass::Create(); - 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); + gfx::Rect layer_rect(layer_bounds); gfx::Rect layer_invalidation(150, 200, 30, 180); - SetupTreesWithInvalidation(pending_pile, active_pile, layer_invalidation); + SetupDefaultTreesWithInvalidation(layer_bounds, layer_invalidation); + active_layer_->SetContentsOpaque(true); active_layer_->draw_properties().visible_layer_rect = gfx::Rect(layer_bounds); AppendQuadsData data; @@ -1640,28 +1646,85 @@ TEST_F(PictureLayerImplTest, DisallowTileDrawQuads) { active_layer_->AppendQuads(render_pass.get(), &data); active_layer_->DidDraw(nullptr); + ASSERT_EQ(1u, render_pass->quad_list.size()); + EXPECT_EQ(DrawQuad::PICTURE_CONTENT, + render_pass->quad_list.front()->material); + EXPECT_EQ(render_pass->quad_list.front()->rect, layer_rect); + EXPECT_EQ(render_pass->quad_list.front()->opaque_rect, layer_rect); + EXPECT_EQ(render_pass->quad_list.front()->visible_rect, layer_rect); +} + +TEST_F(PictureLayerImplTest, ResourcelessPartialRecording) { + scoped_ptr<RenderPass> render_pass = RenderPass::Create(); + + gfx::Size tile_size(400, 400); + gfx::Size layer_bounds(700, 650); + gfx::Rect layer_rect(layer_bounds); + SetInitialDeviceScaleFactor(2.f); + + gfx::Rect recorded_viewport(20, 30, 40, 50); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreatePartiallyFilled(layer_bounds, + recorded_viewport); + + SetupPendingTree(active_raster_source); + ActivateTree(); + + active_layer_->SetContentsOpaque(true); + gfx::Rect visible_rect(30, 35, 10, 5); + active_layer_->draw_properties().visible_layer_rect = visible_rect; + + AppendQuadsData data; + active_layer_->WillDraw(DRAW_MODE_RESOURCELESS_SOFTWARE, nullptr); + active_layer_->AppendQuads(render_pass.get(), &data); + active_layer_->DidDraw(nullptr); + + gfx::Rect scaled_visible = gfx::ScaleToEnclosingRect(visible_rect, 2.f); + gfx::Rect scaled_recorded = gfx::ScaleToEnclosingRect(recorded_viewport, 2.f); + gfx::Rect quad_visible = gfx::IntersectRects(scaled_visible, scaled_recorded); + ASSERT_EQ(1U, render_pass->quad_list.size()); EXPECT_EQ(DrawQuad::PICTURE_CONTENT, render_pass->quad_list.front()->material); + const DrawQuad* quad = render_pass->quad_list.front(); + EXPECT_EQ(quad_visible, quad->rect); + EXPECT_EQ(quad_visible, quad->opaque_rect); + EXPECT_EQ(quad_visible, quad->visible_rect); +} + +TEST_F(PictureLayerImplTest, ResourcelessEmptyRecording) { + scoped_ptr<RenderPass> render_pass = RenderPass::Create(); + + gfx::Size layer_bounds(700, 650); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreatePartiallyFilled(layer_bounds, + gfx::Rect()); + SetupPendingTree(active_raster_source); + ActivateTree(); + + active_layer_->SetContentsOpaque(true); + active_layer_->draw_properties().visible_layer_rect = gfx::Rect(layer_bounds); + + AppendQuadsData data; + active_layer_->WillDraw(DRAW_MODE_RESOURCELESS_SOFTWARE, nullptr); + active_layer_->AppendQuads(render_pass.get(), &data); + active_layer_->DidDraw(nullptr); + + EXPECT_EQ(0U, render_pass->quad_list.size()); } TEST_F(PictureLayerImplTest, SolidColorLayerHasVisibleFullCoverage) { scoped_ptr<RenderPass> render_pass = RenderPass::Create(); - gfx::Size tile_size(1000, 1000); 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<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilledSolidColor(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilledSolidColor(layer_bounds); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFromPile(empty_recording.get(), nullptr); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFromPile(empty_recording.get(), nullptr); - - SetupTrees(pending_pile, active_pile); + SetupTrees(pending_raster_source, active_raster_source); active_layer_->draw_properties().visible_layer_rect = visible_rect; @@ -1680,29 +1743,26 @@ TEST_F(PictureLayerImplTest, SolidColorLayerHasVisibleFullCoverage) { EXPECT_TRUE(remaining.IsEmpty()); } -TEST_F(PictureLayerImplTest, TileScalesWithSolidColorPile) { +TEST_F(PictureLayerImplTest, TileScalesWithSolidColorRasterSource) { gfx::Size layer_bounds(200, 200); - gfx::Size tile_size(host_impl_.settings().default_tile_size); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings( - tile_size, layer_bounds, false); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings( - tile_size, layer_bounds, true); - - SetupTrees(pending_pile, active_pile); - // Solid color pile should not allow tilings at any scale. + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilledSolidColor(layer_bounds); + + SetupTrees(pending_raster_source, active_raster_source); + // Solid color raster source should not allow tilings at any scale. EXPECT_FALSE(active_layer_->CanHaveTilings()); EXPECT_EQ(0.f, active_layer_->ideal_contents_scale()); - // Activate non-solid-color pending pile makes active layer can have tilings. + // Activate non-solid-color pending raster source makes active layer can have + // tilings. ActivateTree(); EXPECT_TRUE(active_layer_->CanHaveTilings()); EXPECT_GT(active_layer_->ideal_contents_scale(), 0.f); } TEST_F(NoLowResPictureLayerImplTest, MarkRequiredOffscreenTiles) { - gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); gfx::Transform transform; @@ -1716,9 +1776,10 @@ TEST_F(NoLowResPictureLayerImplTest, MarkRequiredOffscreenTiles) { transform, resourceless_software_draw); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTreeWithFixedTileSize(pending_raster_source, gfx::Size(100, 100), + Region()); EXPECT_EQ(1u, pending_layer_->num_tilings()); EXPECT_EQ(viewport, pending_layer_->visible_rect_for_tile_priority()); @@ -1757,11 +1818,7 @@ TEST_F(NoLowResPictureLayerImplTest, gfx::Rect external_viewport_for_tile_priority(400, 200); gfx::Rect visible_layer_rect(200, 400); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region()); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region()); ASSERT_EQ(1u, pending_layer_->num_tilings()); ASSERT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale()); @@ -1840,10 +1897,10 @@ TEST_F(PictureLayerImplTest, HighResTileIsComplete) { gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); ActivateTree(); // All high res tiles have resources. @@ -1870,9 +1927,9 @@ TEST_F(PictureLayerImplTest, HighResTileIsIncomplete) { gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); ActivateTree(); scoped_ptr<RenderPass> render_pass = RenderPass::Create(); @@ -1893,9 +1950,9 @@ TEST_F(PictureLayerImplTest, HighResTileIsIncompleteLowResComplete) { gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); ActivateTree(); std::vector<Tile*> low_tiles = @@ -1920,9 +1977,9 @@ TEST_F(PictureLayerImplTest, LowResTileIsIncomplete) { gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); ActivateTree(); // All high res tiles have resources except one. @@ -1958,13 +2015,9 @@ TEST_F(PictureLayerImplTest, gfx::Size viewport_size(400, 400); host_impl_.SetViewportSize(viewport_size); - host_impl_.SetDeviceScaleFactor(2.f); + SetInitialDeviceScaleFactor(2.f); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region()); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region()); // One ideal tile exists, this will get used when drawing. std::vector<Tile*> ideal_tiles; @@ -2026,10 +2079,9 @@ TEST_F(PictureLayerImplTest, HighResRequiredWhenActiveAllReady) { // All active tiles ready, so pending can only activate with all high res // tiles. pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting(); - pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting(); + EXPECT_FALSE(pending_layer_->LowResTiling()); AssertAllTilesRequired(pending_layer_->HighResTiling()); - AssertNoTilesRequired(pending_layer_->LowResTiling()); } TEST_F(PictureLayerImplTest, HighResRequiredWhenMissingHighResFlagOn) { @@ -2049,12 +2101,11 @@ TEST_F(PictureLayerImplTest, HighResRequiredWhenMissingHighResFlagOn) { host_impl_.SetRequiresHighResToDraw(); pending_layer_->HighResTiling()->UpdateAllRequiredStateForTesting(); - pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting(); + EXPECT_FALSE(pending_layer_->LowResTiling()); active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting(); active_layer_->LowResTiling()->UpdateAllRequiredStateForTesting(); EXPECT_TRUE(pending_layer_->HighResTiling()->AllTilesForTesting().empty()); - EXPECT_TRUE(pending_layer_->LowResTiling()->AllTilesForTesting().empty()); AssertAllTilesRequired(active_layer_->HighResTiling()); AssertNoTilesRequired(active_layer_->LowResTiling()); } @@ -2071,7 +2122,7 @@ TEST_F(PictureLayerImplTest, AllHighResRequiredEvenIfNotChanged) { // 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()); + EXPECT_FALSE(pending_layer_->LowResTiling()); active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting(); active_layer_->LowResTiling()->UpdateAllRequiredStateForTesting(); @@ -2091,11 +2142,10 @@ TEST_F(PictureLayerImplTest, DisallowRequiredForActivation) { EXPECT_FALSE(some_active_tile->draw_info().IsReadyToDraw()); EXPECT_TRUE(pending_layer_->HighResTiling()->AllTilesForTesting().empty()); - EXPECT_TRUE(pending_layer_->LowResTiling()->AllTilesForTesting().empty()); + EXPECT_FALSE(pending_layer_->LowResTiling()); 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. active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting(); @@ -2109,18 +2159,18 @@ 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, is_solid_color); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + // This raster source 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. + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreatePartiallyFilled(layer_bounds, + gfx::Rect()); - SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region()); + SetupTreesWithFixedTileSize(pending_raster_source, active_raster_source, + tile_size, Region()); // Active layer has tilings, but no tiles due to missing recordings. EXPECT_TRUE(active_layer_->CanHaveTilings()); @@ -2130,21 +2180,21 @@ 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()->UpdateAllRequiredStateForTesting(); - pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting(); + EXPECT_FALSE(pending_layer_->LowResTiling()); AssertNoTilesRequired(pending_layer_->HighResTiling()); - AssertNoTilesRequired(pending_layer_->LowResTiling()); } 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); - SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region()); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateEmpty(layer_bounds); + SetupTreesWithFixedTileSize(pending_raster_source, active_raster_source, + tile_size, Region()); // Active layer can't have tiles. EXPECT_FALSE(active_layer_->CanHaveTilings()); @@ -2154,10 +2204,9 @@ TEST_F(PictureLayerImplTest, HighResRequiredIfActiveCantHaveTiles) { // 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()->UpdateAllRequiredStateForTesting(); - pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting(); + EXPECT_FALSE(pending_layer_->LowResTiling()); AssertAllTilesRequired(pending_layer_->HighResTiling()); - AssertNoTilesRequired(pending_layer_->LowResTiling()); } TEST_F(PictureLayerImplTest, HighResRequiredWhenActiveHasDifferentBounds) { @@ -2165,41 +2214,37 @@ TEST_F(PictureLayerImplTest, HighResRequiredWhenActiveHasDifferentBounds) { gfx::Size active_layer_bounds(200, 200); gfx::Size tile_size(100, 100); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, pending_layer_bounds); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, active_layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(pending_layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(active_layer_bounds); - SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region()); + SetupTreesWithFixedTileSize(pending_raster_source, active_raster_source, + 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()->UpdateAllRequiredStateForTesting(); - pending_layer_->LowResTiling()->UpdateAllRequiredStateForTesting(); + EXPECT_FALSE(pending_layer_->LowResTiling()); active_layer_->HighResTiling()->UpdateAllRequiredStateForTesting(); active_layer_->LowResTiling()->UpdateAllRequiredStateForTesting(); AssertAllTilesRequired(pending_layer_->HighResTiling()); 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) { - 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<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); host_impl_.CreatePendingTree(); LayerTreeImpl* pending_tree = host_impl_.pending_tree(); scoped_ptr<FakePictureLayerImpl> pending_layer = FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, - pending_pile); + pending_raster_source); pending_layer->SetDrawsContent(true); pending_tree->SetRootLayer(pending_layer.Pass()); @@ -2224,12 +2269,11 @@ TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) { TEST_F(PictureLayerImplTest, ShareTilesOnNextFrame) { gfx::Size layer_bounds(1500, 1500); - gfx::Size tile_size(100, 100); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupPendingTree(pending_pile); + SetupPendingTree(pending_raster_source); PictureLayerTiling* tiling = pending_layer_->HighResTiling(); gfx::Rect first_invalidate = tiling->TilingDataForTesting().TileBounds(0, 0); @@ -2242,18 +2286,16 @@ TEST_F(PictureLayerImplTest, ShareTilesOnNextFrame) { ActivateTree(); // Make a pending tree with an invalidated raster tile 0,0. - SetupPendingTreeWithInvalidation(pending_pile, first_invalidate); + SetupPendingTreeWithInvalidation(pending_raster_source, first_invalidate); // Activate and make a pending tree with an invalidated raster tile 1,1. ActivateTree(); - SetupPendingTreeWithInvalidation(pending_pile, second_invalidate); + SetupPendingTreeWithInvalidation(pending_raster_source, second_invalidate); PictureLayerTiling* pending_tiling = pending_layer_->tilings()->tiling_at(0); PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(0); - // pending_tiling->CreateAllTilesForTesting(); - // 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)); @@ -2306,20 +2348,20 @@ TEST_F(PictureLayerImplTest, PendingHasNoTilesWithNoInvalidation) { } TEST_F(PictureLayerImplTest, ShareInvalidActiveTreeTiles) { - gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1500, 1500); - 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)); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupTreesWithInvalidation(pending_raster_source, active_raster_source, + 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); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source2 = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(pending_raster_source2); EXPECT_GE(active_layer_->num_tilings(), 1u); EXPECT_GE(pending_layer_->num_tilings(), 1u); @@ -2371,15 +2413,14 @@ TEST_F(PictureLayerImplTest, RecreateInvalidPendingTreeTiles) { TEST_F(PictureLayerImplTest, SyncTilingAfterGpuRasterizationToggles) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - 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); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupTrees(pending_pile, active_pile); + SetupTrees(pending_raster_source, active_raster_source); EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.f)); EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(1.f)); @@ -2403,7 +2444,7 @@ TEST_F(PictureLayerImplTest, SyncTilingAfterGpuRasterizationToggles) { ActivateTree(); EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(1.f)); - SetupPendingTree(pending_pile); + SetupPendingTree(pending_raster_source); EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.f)); // Toggling the gpu rasterization clears all tilings on both trees. @@ -2422,14 +2463,12 @@ TEST_F(PictureLayerImplTest, SyncTilingAfterGpuRasterizationToggles) { } TEST_F(PictureLayerImplTest, HighResCreatedWhenBoundsShrink) { - gfx::Size tile_size(100, 100); - // Put 0.5 as high res. - host_impl_.SetDeviceScaleFactor(0.5f); + SetInitialDeviceScaleFactor(0.5f); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(10, 10)); - SetupPendingTree(pending_pile); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(gfx::Size(10, 10)); + SetupPendingTree(pending_raster_source); // Sanity checks. EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings()); @@ -2438,9 +2477,9 @@ TEST_F(PictureLayerImplTest, HighResCreatedWhenBoundsShrink) { 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); + pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(gfx::Size(1, 1)); + SetupPendingTree(pending_raster_source); // Another sanity check. EXPECT_EQ(1.f, pending_layer_->MinimumContentsScale()); @@ -2463,8 +2502,11 @@ TEST_F(PictureLayerImplTest, LowResTilingWithoutGpuRasterization) { SetupDefaultTrees(layer_bounds); EXPECT_FALSE(host_impl_.use_gpu_rasterization()); - // Should have a low-res and a high-res tiling. - EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings()); + // Should have only a high-res tiling. + EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings()); + ActivateTree(); + // Should add a high and a low res for active tree. + EXPECT_EQ(2u, active_layer_->tilings()->num_tilings()); } TEST_F(PictureLayerImplTest, NoLowResTilingWithGpuRasterization) { @@ -2479,6 +2521,9 @@ TEST_F(PictureLayerImplTest, NoLowResTilingWithGpuRasterization) { EXPECT_TRUE(host_impl_.use_gpu_rasterization()); // Should only have the high-res tiling. EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings()); + ActivateTree(); + // Should only have the high-res tiling. + EXPECT_EQ(1u, active_layer_->tilings()->num_tilings()); } TEST_F(PictureLayerImplTest, RequiredTilesWithGpuRasterization) { @@ -2665,6 +2710,7 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) { maximum_animation_scale, starting_animation_scale, animating_transform); EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f); + EXPECT_BOTH_TRUE(GetRasterSource()->ShouldAttemptToUseDistanceFieldText()); // Further changes to scale during the animation should not cause a new // high-res tiling to get created. @@ -2799,6 +2845,7 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForGpuRasterization) { maximum_animation_scale, starting_animation_scale, animating_transform); EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f); + EXPECT_BOTH_FALSE(GetRasterSource()->ShouldAttemptToUseDistanceFieldText()); // Since we're GPU-rasterizing, starting an animation should cause tiling // resolution to get set to the current contents scale. @@ -2810,6 +2857,7 @@ TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForGpuRasterization) { maximum_animation_scale, starting_animation_scale, animating_transform); EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f); + EXPECT_BOTH_TRUE(GetRasterSource()->ShouldAttemptToUseDistanceFieldText()); // Further changes to scale during the animation should cause a new high-res // tiling to get created. @@ -2844,14 +2892,13 @@ TEST_F(PictureLayerImplTest, TilingSetRasterQueue) { 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(recording_tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupPendingTree(pending_pile); - EXPECT_EQ(2u, pending_layer_->num_tilings()); + SetupPendingTree(pending_raster_source); + EXPECT_EQ(1u, pending_layer_->num_tilings()); std::set<Tile*> unique_tiles; bool reached_prepaint = false; @@ -2968,26 +3015,9 @@ TEST_F(PictureLayerImplTest, TilingSetRasterQueue) { draw_info.SetSolidColorForTesting(SK_ColorRED); } - non_ideal_tile_count = 0; - low_res_tile_count = 0; - high_res_tile_count = 0; 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(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(0, non_ideal_tile_count); - EXPECT_EQ(1, low_res_tile_count); - EXPECT_EQ(0, high_res_tile_count); + EXPECT_TRUE(queue->IsEmpty()); } TEST_F(PictureLayerImplTest, TilingSetRasterQueueActiveTree) { @@ -2995,13 +3025,12 @@ TEST_F(PictureLayerImplTest, TilingSetRasterQueueActiveTree) { host_impl_.SetViewportSize(gfx::Size(500, 500)); - gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupPendingTree(pending_pile); + SetupPendingTree(pending_raster_source); ActivateTree(); EXPECT_EQ(2u, active_layer_->num_tilings()); @@ -3024,15 +3053,11 @@ TEST_F(PictureLayerImplTest, TilingSetRasterQueueActiveTree) { } TEST_F(PictureLayerImplTest, TilingSetRasterQueueRequiredNoHighRes) { - scoped_ptr<FakePicturePile> empty_recording = - FakePicturePile::CreateEmptyPile(gfx::Size(256, 256), - gfx::Size(1024, 1024)); - empty_recording->SetIsSolidColor(true); - - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFromPile(empty_recording.get(), nullptr); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilledSolidColor( + gfx::Size(1024, 1024)); - SetupPendingTree(pending_pile); + SetupPendingTree(pending_raster_source); EXPECT_FALSE( pending_layer_->picture_layer_tiling_set()->FindTilingWithResolution( HIGH_RESOLUTION)); @@ -3045,19 +3070,18 @@ TEST_F(PictureLayerImplTest, TilingSetRasterQueueRequiredNoHighRes) { } 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)); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(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()); + // TODO(vmpstr): Add a test with tilings other than high res on the active + // tree (crbug.com/519607). + SetupPendingTree(pending_raster_source); + EXPECT_EQ(1u, pending_layer_->num_tilings()); std::vector<Tile*> all_tiles; for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) { @@ -3087,8 +3111,8 @@ TEST_F(PictureLayerImplTest, TilingSetEvictionQueue) { } // Sanity checks. - EXPECT_EQ(17u, all_tiles.size()); - EXPECT_EQ(17u, all_tiles_set.size()); + EXPECT_EQ(16u, all_tiles.size()); + EXPECT_EQ(16u, all_tiles_set.size()); EXPECT_GT(number_of_marked_tiles, 1u); EXPECT_GT(number_of_unmarked_tiles, 1u); @@ -3196,9 +3220,9 @@ TEST_F(PictureLayerImplTest, Occlusion) { LayerTestCommon::LayerImplTest impl; host_impl_.SetViewportSize(viewport_size); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(layer_bounds, layer_bounds); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); ActivateTree(); std::vector<Tile*> tiles = @@ -3287,7 +3311,7 @@ TEST_F(PictureLayerImplTest, LowResReadyToDrawNotEnoughToActivate) { EXPECT_FALSE(host_impl_.tile_manager()->IsReadyToActivate()); // Initialize all low-res tiles. - pending_layer_->SetAllTilesReadyInTiling(pending_layer_->LowResTiling()); + EXPECT_FALSE(pending_layer_->LowResTiling()); pending_layer_->SetAllTilesReadyInTiling(active_layer_->LowResTiling()); // Low-res tiles should not be enough. @@ -3319,28 +3343,6 @@ TEST_F(PictureLayerImplTest, HighResReadyToDrawEnoughToActivate) { EXPECT_TRUE(host_impl_.tile_manager()->IsReadyToActivate()); } -TEST_F(PictureLayerImplTest, - ActiveHighResReadyAndPendingLowResReadyNotEnoughToActivate) { - gfx::Size tile_size(100, 100); - gfx::Size layer_bounds(1000, 1000); - - // 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 pending high-res tiles are not ready, so we cannot activate. - EXPECT_FALSE(host_impl_.tile_manager()->IsReadyToActivate()); - - // When the pending high-res tiles are ready, we can activate. - pending_layer_->SetAllTilesReadyInTiling(pending_layer_->HighResTiling()); - EXPECT_TRUE(host_impl_.tile_manager()->IsReadyToActivate()); -} - TEST_F(PictureLayerImplTest, ActiveHighResReadyNotEnoughToActivate) { gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); @@ -3355,21 +3357,14 @@ TEST_F(PictureLayerImplTest, ActiveHighResReadyNotEnoughToActivate) { // The pending high-res tiles are not ready, so we cannot activate. EXPECT_FALSE(host_impl_.tile_manager()->IsReadyToActivate()); - // When the pending 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(host_impl_.tile_manager()->IsReadyToActivate()); } TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) { - 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); + SetupDefaultTrees(layer_bounds); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; EXPECT_LT(low_res_factor, 1.f); @@ -3426,15 +3421,8 @@ TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) { } 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); + SetupDefaultTrees(layer_bounds); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; EXPECT_LT(low_res_factor, 1.f); @@ -3518,18 +3506,18 @@ 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, is_solid_color); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + // This raster source 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. + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreatePartiallyFilled(layer_bounds, + gfx::Rect()); - SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region()); + SetupTreesWithFixedTileSize(pending_raster_source, active_raster_source, + tile_size, Region()); // Active layer has tilings, but no tiles due to missing recordings. EXPECT_TRUE(active_layer_->CanHaveTilings()); @@ -3550,16 +3538,8 @@ TEST_F(NoLowResPictureLayerImplTest, NothingRequiredIfActiveMissingTiles) { TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - - 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()); + SetupDefaultTrees(layer_bounds); SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, 0.f, false); @@ -3626,17 +3606,9 @@ TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) { } TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) { - 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); + SetupDefaultTrees(layer_bounds); float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; EXPECT_LT(low_res_factor, 1.f); @@ -3743,15 +3715,8 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) { } TEST_F(NoLowResPictureLayerImplTest, ReleaseResources) { - 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); + SetupDefaultTrees(layer_bounds); EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings()); EXPECT_EQ(1u, active_layer_->tilings()->num_tilings()); @@ -3779,17 +3744,9 @@ TEST_F(NoLowResPictureLayerImplTest, ReleaseResources) { TEST_F(PictureLayerImplTest, SharedQuadStateContainsMaxTilingScale) { scoped_ptr<RenderPass> render_pass = RenderPass::Create(); - 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 = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - - SetupTrees(pending_pile, active_pile); + SetupDefaultTrees(layer_bounds); ResetTilingsAndRasterScales(); SetupDrawPropertiesAndUpdateTiles(active_layer_, 2.5f, 1.f, 1.f, 1.f, 0.f, @@ -3826,10 +3783,12 @@ TEST_F(PictureLayerImplTest, SharedQuadStateContainsMaxTilingScale) { class PictureLayerImplTestWithDelegatingRenderer : public PictureLayerImplTest { public: - PictureLayerImplTestWithDelegatingRenderer() : PictureLayerImplTest() {} + PictureLayerImplTestWithDelegatingRenderer() : PictureLayerImplTest() { + output_surface_ = FakeOutputSurface::CreateDelegating3d(); + } void InitializeRenderer() override { - host_impl_.InitializeRenderer(FakeOutputSurface::CreateDelegating3d()); + host_impl_.InitializeRenderer(output_surface_.get()); } }; @@ -3837,13 +3796,12 @@ TEST_F(PictureLayerImplTestWithDelegatingRenderer, DelegatingRendererWithTileOOM) { // This test is added for crbug.com/402321, where quad should be produced when // raster on demand is not allowed and tile is OOM. - gfx::Size tile_size = host_impl_.settings().default_tile_size; gfx::Size layer_bounds(1000, 1000); // Create tiles. - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTree(pending_pile); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(pending_raster_source); pending_layer_->SetBounds(layer_bounds); ActivateTree(); bool update_lcd_text = false; @@ -3858,6 +3816,7 @@ TEST_F(PictureLayerImplTestWithDelegatingRenderer, // state. We also need to update tree priority separately. GlobalStateThatImpactsTilePriority state; size_t max_tiles = 1; + gfx::Size tile_size(host_impl_.settings().default_tile_size); size_t memory_limit = max_tiles * 4 * tile_size.width() * tile_size.height(); size_t resource_limit = max_tiles; ManagedMemoryPolicy policy(memory_limit, @@ -3947,9 +3906,9 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, host_impl_.SetViewportSize(viewport_size); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); // No occlusion. int unoccluded_tile_count = 0; @@ -4036,9 +3995,9 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, host_impl_.SetViewportSize(viewport_size); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); // No occlusion. int occluded_tile_count = 0; @@ -4151,12 +4110,12 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForDifferentScales) { gfx::Size viewport_size(500, 500); gfx::Point occluding_layer_position(310, 0); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); host_impl_.SetViewportSize(viewport_size); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); ASSERT_TRUE(pending_layer_->CanHaveTilings()); pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1)); @@ -4168,11 +4127,11 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForDifferentScales) { 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); + pending_layer_->AddTiling(low_res_factor)->set_resolution(LOW_RESOLUTION); + pending_layer_->AddTiling(0.3f)->set_resolution(HIGH_RESOLUTION); + pending_layer_->AddTiling(0.7f)->set_resolution(HIGH_RESOLUTION); + pending_layer_->AddTiling(1.0f)->set_resolution(HIGH_RESOLUTION); + pending_layer_->AddTiling(2.0f)->set_resolution(HIGH_RESOLUTION); host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); // UpdateDrawProperties with the occluding layer. @@ -4219,19 +4178,18 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForDifferentScales) { } TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) { - gfx::Size tile_size(102, 102); gfx::Size layer_bounds(1000, 1000); gfx::Size viewport_size(1000, 1000); gfx::Point occluding_layer_position(310, 0); gfx::Rect invalidation_rect(230, 230, 102, 102); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); host_impl_.SetViewportSize(viewport_size); - SetupPendingTree(active_pile); + SetupPendingTree(active_raster_source); // Partially occlude the active layer. pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 2)); @@ -4265,7 +4223,7 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) { } // Partially invalidate the pending layer. - SetupPendingTreeWithInvalidation(pending_pile, invalidation_rect); + SetupPendingTreeWithInvalidation(pending_raster_source, invalidation_rect); for (size_t i = 0; i < active_layer_->num_tilings(); ++i) { PictureLayerTiling* tiling = active_layer_->tilings()->tiling_at(i); @@ -4278,10 +4236,16 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) { if (!*iter) continue; const Tile* tile = *iter; + EXPECT_TRUE(tile); // All tiles are unoccluded, because the pending tree has no occlusion. EXPECT_FALSE(prioritized_tiles[tile].is_occluded()); + if (tiling->resolution() == LOW_RESOLUTION) { + EXPECT_FALSE(active_layer_->GetPendingOrActiveTwinTiling(tiling)); + continue; + } + Tile* twin_tile = active_layer_->GetPendingOrActiveTwinTiling(tiling) ->TileAt(iter.i(), iter.j()); gfx::Rect scaled_content_rect = ScaleToEnclosingRect( @@ -4289,12 +4253,10 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) { if (scaled_content_rect.Intersects(invalidation_rect)) { // Tiles inside the invalidation rect exist on both trees. - EXPECT_TRUE(tile); EXPECT_TRUE(twin_tile); EXPECT_NE(tile, twin_tile); } else { // Tiles outside the invalidation rect only exist on the active tree. - EXPECT_TRUE(tile); EXPECT_FALSE(twin_tile); } } @@ -4313,14 +4275,14 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, gfx::Rect invalidation_rect(230, 230, 152, 152); host_impl_.SetViewportSize(viewport_size); - host_impl_.SetDeviceScaleFactor(2.f); + SetInitialDeviceScaleFactor(2.f); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupPendingTreeWithFixedTileSize(active_pile, tile_size, Region()); + SetupPendingTreeWithFixedTileSize(active_raster_source, tile_size, Region()); // Partially occlude the active layer. pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 2)); @@ -4334,7 +4296,8 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, // Partially invalidate the pending layer. Tiles inside the invalidation rect // are created. - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, invalidation_rect); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, + invalidation_rect); // Partially occlude the pending layer in a different way. pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 3)); @@ -4344,7 +4307,7 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, pending_occluding_layer->SetContentsOpaque(true); pending_occluding_layer->SetPosition(pending_occluding_layer_position); - EXPECT_EQ(2u, pending_layer_->num_tilings()); + EXPECT_EQ(1u, pending_layer_->num_tilings()); EXPECT_EQ(2u, active_layer_->num_tilings()); host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); @@ -4355,8 +4318,8 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, // 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_pending[] = {4u, 0u}; - size_t expected_occluded_tile_count_on_active[] = {12u, 1u}; - size_t total_expected_occluded_tile_count_on_trees[] = {13u, 4u}; + size_t expected_occluded_tile_count_on_active[] = {12u, 3u}; + size_t total_expected_occluded_tile_count_on_trees[] = {15u, 4u}; // Verify number of occluded tiles on the pending layer for each tiling. for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) { @@ -4450,18 +4413,17 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, } TEST_F(PictureLayerImplTest, PendingOrActiveTwinLayer) { - gfx::Size tile_size(102, 102); gfx::Size layer_bounds(1000, 1000); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTree(pile); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(raster_source); EXPECT_FALSE(pending_layer_->GetPendingOrActiveTwinLayer()); ActivateTree(); EXPECT_FALSE(active_layer_->GetPendingOrActiveTwinLayer()); - SetupPendingTree(pile); + SetupPendingTree(raster_source); EXPECT_TRUE(pending_layer_->GetPendingOrActiveTwinLayer()); EXPECT_TRUE(active_layer_->GetPendingOrActiveTwinLayer()); EXPECT_EQ(pending_layer_, active_layer_->GetPendingOrActiveTwinLayer()); @@ -4598,15 +4560,8 @@ TEST_F(PictureLayerImplTest, NonSolidToSolidNoTilings) { TEST_F(PictureLayerImplTest, ChangeInViewportAllowsTilingUpdates) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - gfx::Size tile_size(100, 100); gfx::Size layer_bounds(400, 4000); - - 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); + SetupDefaultTrees(layer_bounds); Region invalidation; gfx::Rect viewport = gfx::Rect(0, 0, 100, 100); @@ -4664,19 +4619,14 @@ 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_refptr<FakeDisplayListRasterSource> filled_raster_source = + FakeDisplayListRasterSource::CreateFilled(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); + scoped_refptr<FakeDisplayListRasterSource> partial_raster_source = + FakeDisplayListRasterSource::CreatePartiallyFilled( + layer_bounds, gfx::Rect(100, 100, 300, 300)); - SetupPendingTreeWithFixedTileSize(filled_pile, tile_size, Region()); + SetupPendingTreeWithFixedTileSize(filled_raster_source, tile_size, Region()); ActivateTree(); PictureLayerTiling* pending_tiling = old_pending_layer_->HighResTiling(); @@ -4686,10 +4636,10 @@ TEST_F(PictureLayerImplTest, CloneMissingRecordings) { 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, + // Now put a partially-recorded raster source on the pending tree (and + // invalidate everything, since the main thread recording will invalidate + // dropped recordings). This will cause us to be missing some tiles. + SetupPendingTreeWithFixedTileSize(partial_raster_source, tile_size, Region(gfx::Rect(layer_bounds))); EXPECT_EQ(3u * 3u, pending_tiling->AllTilesForTesting().size()); EXPECT_FALSE(pending_tiling->TileAt(0, 0)); @@ -4708,7 +4658,7 @@ TEST_F(PictureLayerImplTest, CloneMissingRecordings) { // Now put a full recording on the pending tree again. We'll get all our tiles // back. - SetupPendingTreeWithFixedTileSize(filled_pile, tile_size, + SetupPendingTreeWithFixedTileSize(filled_raster_source, tile_size, Region(gfx::Rect(layer_bounds))); EXPECT_EQ(5u * 5u, pending_tiling->AllTilesForTesting().size()); Tile* tile00 = pending_tiling->TileAt(0, 0); @@ -4734,14 +4684,14 @@ TEST_F(PictureLayerImplTest, ScrollPastLiveTilesRectAndBack) { gfx::Size viewport_size(100, 100); host_impl_.SetViewportSize(viewport_size); - host_impl_.SetDeviceScaleFactor(1.f); + SetInitialDeviceScaleFactor(1.f); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupPendingTreeWithFixedTileSize(active_pile, tile_size, Region()); + SetupPendingTreeWithFixedTileSize(active_raster_source, tile_size, Region()); ActivateTree(); EXPECT_TRUE(active_layer_->HighResTiling()->has_tiles()); @@ -4750,11 +4700,12 @@ TEST_F(PictureLayerImplTest, ScrollPastLiveTilesRectAndBack) { gfx::Transform(), // transform gfx::Rect(), // clip gfx::Rect(), // viewport - gfx::Rect(0, 1000, 100, 100), // viewport_rect_for_tile_priority + gfx::Rect(0, 5000, 100, 100), // viewport_rect_for_tile_priority gfx::Transform(), // transform_for_tile_priority false); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, gfx::Rect()); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, + gfx::Rect()); EXPECT_FALSE(pending_layer_->HighResTiling()->has_tiles()); EXPECT_TRUE(pending_layer_->HighResTiling()->live_tiles_rect().IsEmpty()); @@ -4770,7 +4721,8 @@ TEST_F(PictureLayerImplTest, ScrollPastLiveTilesRectAndBack) { gfx::Transform(), // transform_for_tile_priority false); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, gfx::Rect()); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, + gfx::Rect()); EXPECT_FALSE(pending_layer_->HighResTiling()->has_tiles()); EXPECT_FALSE(pending_layer_->HighResTiling()->live_tiles_rect().IsEmpty()); @@ -4782,19 +4734,13 @@ TEST_F(PictureLayerImplTest, ScrollPastLiveTilesRectAndBack) { TEST_F(PictureLayerImplTest, ScrollPropagatesToPending) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - 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); + SetInitialDeviceScaleFactor(1.f); - SetupTrees(pending_pile, active_pile); + SetupDefaultTrees(layer_bounds); active_layer_->SetCurrentScrollOffset(gfx::ScrollOffset(0.0, 50.0)); host_impl_.active_tree()->UpdateDrawProperties(false); @@ -4819,11 +4765,11 @@ TEST_F(PictureLayerImplTest, UpdateLCDInvalidatesPendingTree) { gfx::Size viewport_size(100, 100); host_impl_.SetViewportSize(viewport_size); - host_impl_.SetDeviceScaleFactor(1.f); + SetInitialDeviceScaleFactor(1.f); - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region()); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilledLCD(layer_bounds); + SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region()); EXPECT_TRUE(pending_layer_->RasterSourceUsesLCDText()); EXPECT_TRUE(pending_layer_->HighResTiling()->has_tiles()); @@ -4840,7 +4786,7 @@ TEST_F(PictureLayerImplTest, UpdateLCDInvalidatesPendingTree) { pending_layer_->UpdateCanUseLCDTextAfterCommit(); EXPECT_FALSE(pending_layer_->RasterSourceUsesLCDText()); - EXPECT_NE(pending_pile.get(), pending_layer_->raster_source()); + EXPECT_NE(pending_raster_source.get(), pending_layer_->raster_source()); EXPECT_TRUE(pending_layer_->HighResTiling()->has_tiles()); tiles = pending_layer_->HighResTiling()->AllTilesForTesting(); prioritized_tiles = pending_layer_->HighResTiling() @@ -4856,9 +4802,9 @@ TEST_F(PictureLayerImplTest, TilingAllTilesDone) { gfx::Size layer_bounds(1000, 1000); // Create tiles. - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - SetupPendingTree(pending_pile); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(pending_raster_source); pending_layer_->SetBounds(layer_bounds); ActivateTree(); host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting( @@ -4966,19 +4912,11 @@ TEST_F(TileSizeTest, TileSizes) { EXPECT_EQ(result.height(), 500 + 2); } -TEST_F(NoLowResPictureLayerImplTest, HighResLowResCollision) { - gfx::Size tile_size(400, 400); +TEST_F(NoLowResPictureLayerImplTest, LowResWasHighResCollision) { 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 = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - - // Set up the high and low res tilings before pinch zoom. - SetupTrees(pending_pile, active_pile); + SetupDefaultTrees(layer_bounds); ResetTilingsAndRasterScales(); float page_scale = 2.f; @@ -4996,5 +4934,67 @@ TEST_F(NoLowResPictureLayerImplTest, HighResLowResCollision) { EXPECT_EQ(zoomed, pending_layer_->tilings()->tiling_at(0)->contents_scale()); } +TEST_F(PictureLayerImplTest, HighResWasLowResCollision) { + gfx::Size layer_bounds(1300, 1900); + + float low_res_factor = host_impl_.settings().low_res_contents_scale_factor; + + SetupDefaultTrees(layer_bounds); + ResetTilingsAndRasterScales(); + + float page_scale = 4.f; + float low_res = page_scale * low_res_factor; + float extra_low_res = low_res * low_res_factor; + SetupDrawPropertiesAndUpdateTiles(active_layer_, page_scale, 1.0f, page_scale, + 1.0f, 0.f, false); + EXPECT_EQ(2u, active_layer_->tilings()->num_tilings()); + EXPECT_EQ(page_scale, + active_layer_->tilings()->tiling_at(0)->contents_scale()); + EXPECT_EQ(low_res, active_layer_->tilings()->tiling_at(1)->contents_scale()); + + // Grab a current low res tile. + PictureLayerTiling* old_low_res_tiling = + active_layer_->tilings()->tiling_at(1); + Tile* old_low_res_tile = active_layer_->tilings()->tiling_at(1)->TileAt(0, 0); + + // The tiling knows it has low res content. + EXPECT_TRUE(active_layer_->tilings() + ->tiling_at(1) + ->may_contain_low_resolution_tiles()); + + host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); + + // Zoom in to exactly the low res factor so that the previous low res + // would be equal to the current high res. + SetupDrawPropertiesAndUpdateTiles(active_layer_, low_res, 1.0f, low_res, 1.0f, + 0.f, false); + // 3 tilings. The old high res, the new high res (old low res) and the new low + // res. + EXPECT_EQ(3u, active_layer_->num_tilings()); + + PictureLayerTilingSet* tilings = active_layer_->tilings(); + EXPECT_EQ(page_scale, tilings->tiling_at(0)->contents_scale()); + EXPECT_EQ(low_res, tilings->tiling_at(1)->contents_scale()); + EXPECT_EQ(extra_low_res, tilings->tiling_at(2)->contents_scale()); + + EXPECT_EQ(NON_IDEAL_RESOLUTION, tilings->tiling_at(0)->resolution()); + EXPECT_EQ(HIGH_RESOLUTION, tilings->tiling_at(1)->resolution()); + EXPECT_EQ(LOW_RESOLUTION, tilings->tiling_at(2)->resolution()); + + // The old low res tile was destroyed and replaced. + EXPECT_EQ(old_low_res_tiling, tilings->tiling_at(1)); + EXPECT_NE(old_low_res_tile, tilings->tiling_at(1)->TileAt(0, 0)); + EXPECT_TRUE(tilings->tiling_at(1)->TileAt(0, 0)); + + // New high res tiling. + EXPECT_FALSE(tilings->tiling_at(0)->may_contain_low_resolution_tiles()); + // New low res tiling. + EXPECT_TRUE(tilings->tiling_at(2)->may_contain_low_resolution_tiles()); + + // This tiling will be high res now, it won't contain low res content since it + // was all destroyed. + EXPECT_FALSE(tilings->tiling_at(1)->may_contain_low_resolution_tiles()); +} + } // namespace } // namespace cc diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc index b607f2eff99..cb73d15a5e9 100644 --- a/chromium/cc/layers/picture_layer_unittest.cc +++ b/chromium/cc/layers/picture_layer_unittest.cc @@ -7,6 +7,8 @@ #include "base/thread_task_runner_handle.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/picture_layer_impl.h" +#include "cc/playback/display_item_list_settings.h" +#include "cc/test/fake_display_list_recording_source.h" #include "cc/test/fake_layer_tree_host.h" #include "cc/test/fake_picture_layer.h" #include "cc/test/fake_picture_layer_impl.h" @@ -27,10 +29,10 @@ class MockContentLayerClient : public ContentLayerClient { scoped_refptr<DisplayItemList> PaintContentsToDisplayList( const gfx::Rect& clip, PaintingControlSetting picture_control) override { - NOTIMPLEMENTED(); - return nullptr; + return DisplayItemList::Create(clip, DisplayItemListSettings()); } bool FillsBoundsCompletely() const override { return false; }; + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } }; TEST(PictureLayerTest, NoTilesIfEmptyBounds) { @@ -77,46 +79,40 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) { } TEST(PictureLayerTest, SuitableForGpuRasterization) { + scoped_ptr<FakeDisplayListRecordingSource> recording_source_owned( + new FakeDisplayListRecordingSource); + FakeDisplayListRecordingSource* recording_source = + recording_source_owned.get(); + MockContentLayerClient client; - scoped_refptr<PictureLayer> layer = - PictureLayer::Create(LayerSettings(), &client); + scoped_refptr<FakePictureLayer> layer = + FakePictureLayer::CreateWithRecordingSource( + LayerSettings(), &client, recording_source_owned.Pass()); + FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D); TestTaskGraphRunner task_graph_runner; scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client, &task_graph_runner); host->SetRootLayer(layer); - RecordingSource* recording_source = layer->GetRecordingSourceForTesting(); + + // Update layers to initialize the recording source. + gfx::Size layer_bounds(200, 200); + gfx::Rect layer_rect(layer_bounds); + Region invalidation(layer_rect); + recording_source->UpdateAndExpandInvalidation( + &client, &invalidation, layer_bounds, layer_rect, 1, + RecordingSource::RECORD_NORMALLY); // Layer is suitable for gpu rasterization by default. EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization()); EXPECT_TRUE(layer->IsSuitableForGpuRasterization()); // Veto gpu rasterization. - recording_source->SetUnsuitableForGpuRasterizationForTesting(); + recording_source->SetUnsuitableForGpuRasterization(); EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization()); EXPECT_FALSE(layer->IsSuitableForGpuRasterization()); } -TEST(PictureLayerTest, UseTileGridSize) { - LayerTreeSettings settings; - settings.default_tile_grid_size = gfx::Size(123, 123); - - MockContentLayerClient client; - scoped_refptr<PictureLayer> layer = - PictureLayer::Create(LayerSettings(), &client); - FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D); - TestTaskGraphRunner task_graph_runner; - scoped_ptr<FakeLayerTreeHost> host = - FakeLayerTreeHost::Create(&host_client, &task_graph_runner, settings); - host->SetRootLayer(layer); - - // Tile-grid is set according to its setting. - 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 @@ -125,7 +121,6 @@ TEST(PictureLayerTest, NonMonotonicSourceFrameNumber) { LayerTreeSettings settings; settings.single_thread_proxy_scheduler = false; settings.use_zero_copy = true; - settings.use_one_copy = false; FakeLayerTreeHostClient host_client1(FakeLayerTreeHostClient::DIRECT_3D); FakeLayerTreeHostClient host_client2(FakeLayerTreeHostClient::DIRECT_3D); diff --git a/chromium/cc/layers/render_surface.cc b/chromium/cc/layers/render_surface.cc deleted file mode 100644 index 35dde100836..00000000000 --- a/chromium/cc/layers/render_surface.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2010 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/render_surface.h" - -#include "cc/base/math_util.h" -#include "cc/layers/layer.h" -#include "ui/gfx/transform.h" - -namespace cc { - -RenderSurface::RenderSurface(Layer* owning_layer) - : owning_layer_(owning_layer), - draw_opacity_(1), - draw_opacity_is_animating_(false), - target_surface_transforms_are_animating_(false), - screen_space_transforms_are_animating_(false), - is_clipped_(false), - contributes_to_drawn_surface_(false), - nearest_occlusion_immune_ancestor_(nullptr) { -} - -RenderSurface::~RenderSurface() { - for (size_t i = 0; i < layer_list_.size(); ++i) { - DCHECK(!layer_list_.at(i)->render_surface()) << - "RenderSurfaces should be cleared from the contributing layers " << - "before destroying this surface to avoid leaking a circular " << - "reference on the contributing layer. Probably the " << - "RenderSurfaceLayerList should just be destroyed before destroying " << - "any RenderSurfaces on layers."; - } -} - -gfx::RectF RenderSurface::DrawableContentRect() const { - gfx::RectF drawable_content_rect = - MathUtil::MapClippedRect(draw_transform_, content_rect_); - if (owning_layer_->has_replica()) - drawable_content_rect.Union( - MathUtil::MapClippedRect(replica_draw_transform_, content_rect_)); - return drawable_content_rect; -} - -void RenderSurface::ClearLayerLists() { - layer_list_.clear(); -} - -} // namespace cc diff --git a/chromium/cc/layers/render_surface.h b/chromium/cc/layers/render_surface.h deleted file mode 100644 index 29401e29951..00000000000 --- a/chromium/cc/layers/render_surface.h +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2010 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_RENDER_SURFACE_H_ -#define CC_LAYERS_RENDER_SURFACE_H_ - -#include <vector> - -#include "base/basictypes.h" -#include "base/memory/ref_counted.h" -#include "cc/base/cc_export.h" -#include "cc/layers/layer_lists.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/rect_f.h" -#include "ui/gfx/transform.h" - -namespace cc { - -class Layer; - -class CC_EXPORT RenderSurface { - public: - explicit RenderSurface(Layer* owning_layer); - ~RenderSurface(); - - // Returns the rect that encloses the RenderSurfaceImpl including any - // reflection. - gfx::RectF DrawableContentRect() const; - - void SetContentRect(const gfx::Rect& content_rect) { - content_rect_ = content_rect; - } - gfx::Rect content_rect() const { return content_rect_; } - - void SetDrawOpacity(float opacity) { draw_opacity_ = opacity; } - float draw_opacity() const { return draw_opacity_; } - - void SetDrawOpacityIsAnimating(bool draw_opacity_is_animating) { - draw_opacity_is_animating_ = draw_opacity_is_animating; - } - bool draw_opacity_is_animating() const { return draw_opacity_is_animating_; } - - void SetDrawTransform(const gfx::Transform& draw_transform) { - draw_transform_ = draw_transform; - } - const gfx::Transform& draw_transform() const { return draw_transform_; } - - void SetScreenSpaceTransform(const gfx::Transform& screen_space_transform) { - screen_space_transform_ = screen_space_transform; - } - const gfx::Transform& screen_space_transform() const { - return screen_space_transform_; - } - - void SetReplicaDrawTransform(const gfx::Transform& replica_draw_transform) { - replica_draw_transform_ = replica_draw_transform; - } - const gfx::Transform& replica_draw_transform() const { - return replica_draw_transform_; - } - - void SetReplicaScreenSpaceTransform( - const gfx::Transform& replica_screen_space_transform) { - replica_screen_space_transform_ = replica_screen_space_transform; - } - const gfx::Transform& replica_screen_space_transform() const { - return replica_screen_space_transform_; - } - - void SetTargetSurfaceTransformsAreAnimating(bool animating) { - target_surface_transforms_are_animating_ = animating; - } - bool target_surface_transforms_are_animating() const { - return target_surface_transforms_are_animating_; - } - void SetScreenSpaceTransformsAreAnimating(bool animating) { - screen_space_transforms_are_animating_ = animating; - } - bool screen_space_transforms_are_animating() const { - return screen_space_transforms_are_animating_; - } - - bool is_clipped() const { return is_clipped_; } - void SetIsClipped(bool is_clipped) { is_clipped_ = is_clipped; } - - gfx::Rect clip_rect() const { return clip_rect_; } - void SetClipRect(const gfx::Rect& clip_rect) { clip_rect_ = clip_rect; } - - // When false, the RenderSurface does not contribute to another target - // RenderSurface that is being drawn for the current frame. It could still be - // drawn to as a target, but its output will not be a part of any other - // surface. - bool contributes_to_drawn_surface() const { - return contributes_to_drawn_surface_; - } - void set_contributes_to_drawn_surface(bool contributes_to_drawn_surface) { - contributes_to_drawn_surface_ = contributes_to_drawn_surface; - } - - LayerList& layer_list() { return layer_list_; } - // A no-op since DelegatedRendererLayers on the main thread don't have any - // RenderPasses so they can't contribute to a surface. - void AddContributingDelegatedRenderPassLayer(Layer* layer) {} - - void SetNearestOcclusionImmuneAncestor(RenderSurface* surface) { - nearest_occlusion_immune_ancestor_ = surface; - } - const RenderSurface* nearest_occlusion_immune_ancestor() const { - return nearest_occlusion_immune_ancestor_; - } - - void ClearLayerLists(); - - private: - Layer* owning_layer_; - - // Uses this surface's space. - gfx::Rect content_rect_; - - float draw_opacity_; - bool draw_opacity_is_animating_; - gfx::Transform draw_transform_; - gfx::Transform screen_space_transform_; - gfx::Transform replica_draw_transform_; - gfx::Transform replica_screen_space_transform_; - bool target_surface_transforms_are_animating_; - bool screen_space_transforms_are_animating_; - - bool is_clipped_; - bool contributes_to_drawn_surface_; - - // Uses the space of the surface's target surface. - gfx::Rect clip_rect_; - - LayerList layer_list_; - - // The nearest ancestor target surface that will contain the contents of this - // surface, and that ignores outside occlusion. This can point to itself. - RenderSurface* nearest_occlusion_immune_ancestor_; - - DISALLOW_COPY_AND_ASSIGN(RenderSurface); -}; - -} // namespace cc -#endif // CC_LAYERS_RENDER_SURFACE_H_ diff --git a/chromium/cc/layers/render_surface_draw_properties.cc b/chromium/cc/layers/render_surface_draw_properties.cc new file mode 100644 index 00000000000..22131fd0424 --- /dev/null +++ b/chromium/cc/layers/render_surface_draw_properties.cc @@ -0,0 +1,14 @@ +// 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/render_surface_draw_properties.h" + +namespace cc { + +RenderSurfaceDrawProperties::RenderSurfaceDrawProperties() + : draw_opacity(0.f), is_clipped(false) {} + +RenderSurfaceDrawProperties::~RenderSurfaceDrawProperties() {} + +} // namespace cc diff --git a/chromium/cc/layers/render_surface_draw_properties.h b/chromium/cc/layers/render_surface_draw_properties.h new file mode 100644 index 00000000000..f648909a81d --- /dev/null +++ b/chromium/cc/layers/render_surface_draw_properties.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_LAYERS_RENDER_SURFACE_DRAW_PROPERTIES_H_ +#define CC_LAYERS_RENDER_SURFACE_DRAW_PROPERTIES_H_ + +#include "cc/base/cc_export.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/transform.h" + +namespace cc { + +// Container for properties that render surfaces need to compute before they can +// be drawn. +struct CC_EXPORT RenderSurfaceDrawProperties { + RenderSurfaceDrawProperties(); + ~RenderSurfaceDrawProperties(); + + float draw_opacity; + + // Transforms from the surface's own space to the space of its target surface. + gfx::Transform draw_transform; + + // Transforms from the surface's own space to the viewport. + gfx::Transform screen_space_transform; + + // If the surface has a replica, these transform from the replica's space to + // the space of the target surface and the viewport. + gfx::Transform replica_draw_transform; + gfx::Transform replica_screen_space_transform; + + // This is in the surface's own space. + gfx::Rect content_rect; + + // This is in the space of the surface's target surface. + gfx::Rect clip_rect; + + // True if the surface needs to be clipped by clip_rect. + bool is_clipped; +}; + +} // namespace cc + +#endif // CC_LAYERS_RENDER_SURFACE_DRAW_PROPERTIES_H_ diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc index ebb3016c64d..560c75c5b51 100644 --- a/chromium/cc/layers/render_surface_impl.cc +++ b/chromium/cc/layers/render_surface_impl.cc @@ -28,9 +28,6 @@ namespace cc { RenderSurfaceImpl::RenderSurfaceImpl(LayerImpl* owning_layer) : owning_layer_(owning_layer), surface_property_changed_(false), - draw_opacity_is_animating_(false), - target_surface_transforms_are_animating_(false), - screen_space_transforms_are_animating_(false), is_clipped_(false), contributes_to_drawn_surface_(false), draw_opacity_(1), @@ -44,10 +41,10 @@ RenderSurfaceImpl::~RenderSurfaceImpl() {} gfx::RectF RenderSurfaceImpl::DrawableContentRect() const { gfx::RectF drawable_content_rect = - MathUtil::MapClippedRect(draw_transform_, content_rect_); + MathUtil::MapClippedRect(draw_transform_, gfx::RectF(content_rect_)); if (owning_layer_->has_replica()) { - drawable_content_rect.Union( - MathUtil::MapClippedRect(replica_draw_transform_, content_rect_)); + drawable_content_rect.Union(MathUtil::MapClippedRect( + replica_draw_transform_, gfx::RectF(content_rect_))); } return drawable_content_rect; @@ -74,6 +71,31 @@ int RenderSurfaceImpl::OwningLayerId() const { return owning_layer_ ? owning_layer_->id() : 0; } +bool RenderSurfaceImpl::HasReplica() const { + return owning_layer_->has_replica(); +} + +const LayerImpl* RenderSurfaceImpl::ReplicaLayer() const { + return owning_layer_->replica_layer(); +} + +int RenderSurfaceImpl::TransformTreeIndex() const { + return owning_layer_->transform_tree_index(); +} + +int RenderSurfaceImpl::ClipTreeIndex() const { + return owning_layer_->clip_tree_index(); +} + +int RenderSurfaceImpl::EffectTreeIndex() const { + return owning_layer_->effect_tree_index(); +} + +int RenderSurfaceImpl::TargetEffectTreeIndex() const { + if (!owning_layer_->parent() || !owning_layer_->parent()->render_target()) + return -1; + return owning_layer_->parent()->render_target()->effect_tree_index(); +} void RenderSurfaceImpl::SetClipRect(const gfx::Rect& clip_rect) { if (clip_rect_ == clip_rect) @@ -91,6 +113,20 @@ void RenderSurfaceImpl::SetContentRect(const gfx::Rect& content_rect) { content_rect_ = content_rect; } +void RenderSurfaceImpl::SetContentRectFromPropertyTrees( + const gfx::Rect& content_rect) { + if (content_rect_from_property_trees_ == content_rect) + return; + + surface_property_changed_ = true; + content_rect_from_property_trees_ = content_rect; +} + +void RenderSurfaceImpl::SetAccumulatedContentRect( + const gfx::Rect& content_rect) { + accumulated_content_rect_ = content_rect; +} + bool RenderSurfaceImpl::SurfacePropertyChanged() const { // Surface property changes are tracked as follows: // @@ -186,9 +222,9 @@ void RenderSurfaceImpl::AppendQuads(RenderPass* render_pass, gfx::Vector2dF owning_layer_draw_scale = MathUtil::ComputeTransform2dScaleComponents( owning_layer_->draw_transform(), 1.f); - gfx::SizeF unclipped_mask_target_size = - gfx::ScaleSize(owning_layer_->bounds(), owning_layer_draw_scale.x(), - owning_layer_draw_scale.y()); + gfx::SizeF unclipped_mask_target_size = gfx::ScaleSize( + gfx::SizeF(owning_layer_->bounds()), owning_layer_draw_scale.x(), + owning_layer_draw_scale.y()); mask_uv_scale = gfx::Vector2dF( content_rect_.width() / unclipped_mask_target_size.width(), content_rect_.height() / unclipped_mask_target_size.height()); diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h index 80a4f720b7b..283f0eb47b6 100644 --- a/chromium/cc/layers/render_surface_impl.h +++ b/chromium/cc/layers/render_surface_impl.h @@ -54,11 +54,6 @@ class CC_EXPORT RenderSurfaceImpl { return nearest_occlusion_immune_ancestor_; } - void SetDrawOpacityIsAnimating(bool draw_opacity_is_animating) { - draw_opacity_is_animating_ = draw_opacity_is_animating; - } - bool draw_opacity_is_animating() const { return draw_opacity_is_animating_; } - SkColor GetDebugBorderColor() const; SkColor GetReplicaDebugBorderColor() const; @@ -92,19 +87,6 @@ class CC_EXPORT RenderSurfaceImpl { return replica_screen_space_transform_; } - void SetTargetSurfaceTransformsAreAnimating(bool animating) { - target_surface_transforms_are_animating_ = animating; - } - bool target_surface_transforms_are_animating() const { - return target_surface_transforms_are_animating_; - } - void SetScreenSpaceTransformsAreAnimating(bool animating) { - screen_space_transforms_are_animating_ = animating; - } - bool screen_space_transforms_are_animating() const { - return screen_space_transforms_are_animating_; - } - void SetIsClipped(bool is_clipped) { is_clipped_ = is_clipped; } bool is_clipped() const { return is_clipped_; } @@ -125,6 +107,16 @@ class CC_EXPORT RenderSurfaceImpl { void SetContentRect(const gfx::Rect& content_rect); gfx::Rect content_rect() const { return content_rect_; } + void SetContentRectFromPropertyTrees(const gfx::Rect& content_rect); + gfx::Rect content_rect_from_property_trees() const { + return content_rect_from_property_trees_; + } + + void SetAccumulatedContentRect(const gfx::Rect& content_rect); + gfx::Rect accumulated_content_rect() const { + return accumulated_content_rect_; + } + const Occlusion& occlusion_in_content_space() const { return occlusion_in_content_space_; } @@ -137,6 +129,8 @@ class CC_EXPORT RenderSurfaceImpl { void ClearLayerLists(); int OwningLayerId() const; + bool HasReplica() const; + const LayerImpl* ReplicaLayer() const; void ResetPropertyChangedFlag() { surface_property_changed_ = false; } bool SurfacePropertyChanged() const; @@ -156,15 +150,20 @@ class CC_EXPORT RenderSurfaceImpl { AppendQuadsData* append_quads_data, RenderPassId render_pass_id); + int TransformTreeIndex() const; + int ClipTreeIndex() const; + int EffectTreeIndex() const; + int TargetEffectTreeIndex() const; + private: LayerImpl* owning_layer_; // Uses this surface's space. gfx::Rect content_rect_; + gfx::Rect content_rect_from_property_trees_; + // Is used to calculate the content rect from property trees. + gfx::Rect accumulated_content_rect_; bool surface_property_changed_ : 1; - bool draw_opacity_is_animating_ : 1; - bool target_surface_transforms_are_animating_ : 1; - bool screen_space_transforms_are_animating_ : 1; bool is_clipped_ : 1; bool contributes_to_drawn_surface_ : 1; diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.cc b/chromium/cc/layers/scrollbar_layer_impl_base.cc index 1d07a8349e4..6696e498bd0 100644 --- a/chromium/cc/layers/scrollbar_layer_impl_base.cc +++ b/chromium/cc/layers/scrollbar_layer_impl_base.cc @@ -42,6 +42,11 @@ void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) { PushScrollClipPropertiesTo(layer); } +void ScrollbarLayerImplBase::DidBecomeActive() { + LayerImpl::DidBecomeActive(); + UpdatePropertyTreeOpacity(); +} + void ScrollbarLayerImplBase::PushScrollClipPropertiesTo(LayerImpl* layer) { DCHECK(layer->ToScrollbarLayer()); layer->ToScrollbarLayer()->SetScrollLayerAndClipLayerByIds(ScrollLayerId(), diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.h b/chromium/cc/layers/scrollbar_layer_impl_base.h index da7fa52d1f1..339dcc9f890 100644 --- a/chromium/cc/layers/scrollbar_layer_impl_base.h +++ b/chromium/cc/layers/scrollbar_layer_impl_base.h @@ -47,6 +47,7 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl { bool CanScrollOrientation() const; void PushPropertiesTo(LayerImpl* layer) override; + void DidBecomeActive() override; ScrollbarLayerImplBase* ToScrollbarLayer() override; void PushScrollClipPropertiesTo(LayerImpl* layer); diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc index 0042204505e..f631fcea0f7 100644 --- a/chromium/cc/layers/scrollbar_layer_unittest.cc +++ b/chromium/cc/layers/scrollbar_layer_unittest.cc @@ -121,7 +121,6 @@ class ScrollbarLayerTest : public testing::Test { ScrollbarLayerTest() : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) { layer_tree_settings_.single_thread_proxy_scheduler = false; layer_tree_settings_.use_zero_copy = true; - layer_tree_settings_.use_one_copy = false; LayerTreeHost::InitParams params; params.client = &fake_client_; @@ -488,8 +487,8 @@ TEST_F(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) { layer_tree_host_->CommitAndCreateLayerImplTree(); LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0]; - ScrollbarLayerImplBase* scrollbar_layer_impl = - static_cast<PaintedScrollbarLayerImpl*>(scroll_layer_impl->children()[1]); + auto* scrollbar_layer_impl = + static_cast<ScrollbarLayerImplBase*>(scroll_layer_impl->children()[1]); // Choose layer bounds to give max_scroll_offset = (8, 8). layer_impl_tree_root->SetBounds(gfx::Size(2, 2)); @@ -600,9 +599,9 @@ TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) { layers[0]->SetBounds(gfx::Size(100, 3)); layers[1]->SetBounds(gfx::Size(3, 100)); - EXPECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f), + EXPECT_EQ(gfx::Rect(20, 0, 20, 3), horizontal_scrollbar_layer_->ComputeThumbQuadRect()); - EXPECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f), + EXPECT_EQ(gfx::Rect(0, 20, 3, 20), vertical_scrollbar_layer_->ComputeThumbQuadRect()); horizontal_scrollbar_layer_->SetVerticalAdjust(10.f); @@ -713,10 +712,7 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest { layer_tree_root->SetScrollOffset(gfx::ScrollOffset(10, 20)); layer_tree_root->SetBounds(gfx::Size(100, 200)); content_layer->SetBounds(gfx::Size(100, 200)); - scrollbar_layer->draw_properties().visible_layer_rect = - gfx::Rect(0, 0, 100, 200); - scrollbar_layer->CreateRenderSurface(); - scrollbar_layer->draw_properties().render_target = scrollbar_layer.get(); + scrollbar_layer->set_visible_layer_rect(gfx::Rect(0, 0, 100, 200)); testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get()); @@ -731,8 +727,6 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest { EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted()); testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - - scrollbar_layer->ClearRenderSurface(); } }; @@ -775,12 +769,7 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) { scrollbar_layer->SetPosition(scrollbar_location); layer_tree_root->SetBounds(gfx::Size(100, 200)); content_layer->SetBounds(gfx::Size(100, 200)); - - scrollbar_layer->draw_properties().visible_layer_rect = - gfx::Rect(0, 0, 100, 200); - - scrollbar_layer->CreateRenderSurface(); - scrollbar_layer->draw_properties().render_target = scrollbar_layer.get(); + scrollbar_layer->set_visible_layer_rect(gfx::Rect(0, 0, 100, 200)); testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get()); @@ -802,6 +791,7 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) { resource_count = 0; expected_created = 2; expected_deleted = 2; + scrollbar_layer->SetBounds(gfx::Size(0, 0)); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0)); EXPECT_TRUE(scrollbar_layer->Update()); EXPECT_EQ(0, scrollbar_layer->track_resource_id()); @@ -824,6 +814,7 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) { resource_count = 2; expected_created = 4; expected_deleted = 2; + scrollbar_layer->SetBounds(gfx::Size(100, 15)); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); EXPECT_TRUE(scrollbar_layer->Update()); EXPECT_NE(0, scrollbar_layer->track_resource_id()); @@ -846,6 +837,7 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) { resource_count = 0; expected_created = 5; expected_deleted = 5; + scrollbar_layer->SetBounds(gfx::Size(0, 0)); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0)); EXPECT_TRUE(scrollbar_layer->Update()); EXPECT_EQ(0, scrollbar_layer->track_resource_id()); @@ -857,15 +849,27 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) { resource_count = 2; expected_created = 7; expected_deleted = 5; + scrollbar_layer->SetBounds(gfx::Size(100, 15)); scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); scrollbar_layer->fake_scrollbar()->set_has_thumb(true); EXPECT_TRUE(scrollbar_layer->Update()); EXPECT_NE(0, scrollbar_layer->track_resource_id()); EXPECT_NE(0, scrollbar_layer->thumb_resource_id()); - resource_count = 1; - expected_created = 8; + resource_count = 2; + expected_created = 9; expected_deleted = 7; + scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0)); + EXPECT_TRUE(scrollbar_layer->Update()); + EXPECT_NE(0, scrollbar_layer->track_resource_id()); + EXPECT_NE(0, scrollbar_layer->thumb_resource_id()); + EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount()); + EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated()); + EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted()); + + resource_count = 1; + expected_created = 10; + expected_deleted = 9; scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); scrollbar_layer->fake_scrollbar()->set_has_thumb(false); scrollbar_layer->SetBounds(gfx::Size(90, 15)); @@ -886,7 +890,6 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) { EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted()); testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - scrollbar_layer->ClearRenderSurface(); } class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest { @@ -909,10 +912,8 @@ class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest { scrollbar_layer->SetPosition(scrollbar_location); layer_tree_root->SetBounds(gfx::Size(100, 200)); content_layer->SetBounds(gfx::Size(100, 200)); - scrollbar_layer->draw_properties().visible_layer_rect = - gfx::Rect(scrollbar_location, scrollbar_layer->bounds()); - scrollbar_layer->CreateRenderSurface(); - scrollbar_layer->draw_properties().render_target = scrollbar_layer.get(); + scrollbar_layer->set_visible_layer_rect( + gfx::Rect(scrollbar_location, scrollbar_layer->bounds())); testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get()); @@ -940,8 +941,6 @@ class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest { scrollbar_layer->internal_content_bounds().height()); testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - - scrollbar_layer->ClearRenderSurface(); } }; @@ -971,7 +970,7 @@ class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest { scrollbar_layer->SetPosition(scrollbar_rect.origin()); scrollbar_layer->fake_scrollbar()->set_location(scrollbar_rect.origin()); scrollbar_layer->fake_scrollbar()->set_track_rect(scrollbar_rect); - scrollbar_layer->draw_properties().visible_layer_rect = scrollbar_rect; + scrollbar_layer->set_visible_layer_rect(scrollbar_rect); layer_tree_host_->SetDeviceScaleFactor(test_scale); diff --git a/chromium/cc/layers/solid_color_layer_impl_unittest.cc b/chromium/cc/layers/solid_color_layer_impl_unittest.cc index 59ef6ba70fa..a27f22971d0 100644 --- a/chromium/cc/layers/solid_color_layer_impl_unittest.cc +++ b/chromium/cc/layers/solid_color_layer_impl_unittest.cc @@ -113,7 +113,7 @@ TEST(SolidColorLayerImplTest, VerifyCorrectBlendModeInQuad) { scoped_ptr<SolidColorLayerImpl> layer = SolidColorLayerImpl::Create(host_impl.active_tree(), 1); layer->SetBounds(layer_size); - layer->draw_properties().blend_mode = blend_mode; + layer->set_draw_blend_mode(blend_mode); AppendQuadsData data; layer->AppendQuads(render_pass.get(), &data); @@ -143,9 +143,8 @@ TEST(SolidColorLayerImplTest, VerifyOpaqueRect) { FakeLayerTreeHost::Create(&client, &task_graph_runner); host->SetRootLayer(root); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), gfx::Size(500, 500), &render_surface_layer_list); + LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(root.get(), + gfx::Size(500, 500)); LayerTreeHostCommon::CalculateDrawProperties(&inputs); EXPECT_FALSE(layer->contents_opaque()); diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc index 0b78de7f8c7..beb9cb6886d 100644 --- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc +++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc @@ -116,4 +116,8 @@ void SolidColorScrollbarLayerImpl::AppendQuads( shared_quad_state, thumb_quad_rect, visible_quad_rect, color_, false); } +const char* SolidColorScrollbarLayerImpl::LayerTypeAsString() const { + return "cc::SolidColorScrollbarLayerImpl"; +} + } // namespace cc diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.h b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h index df6179d3ef6..1cb03c76269 100644 --- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.h +++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h @@ -46,6 +46,8 @@ class CC_EXPORT SolidColorScrollbarLayerImpl : public ScrollbarLayerImplBase { bool IsThumbResizable() const override; private: + const char* LayerTypeAsString() const override; + int thumb_thickness_; int track_start_; SkColor color_; diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc index 0cd4f248645..546af40c522 100644 --- a/chromium/cc/layers/surface_layer_impl.cc +++ b/chromium/cc/layers/surface_layer_impl.cc @@ -6,6 +6,7 @@ #include "base/trace_event/trace_event_argument.h" #include "cc/debug/debug_colors.h" +#include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/surface_draw_quad.h" #include "cc/trees/occlusion.h" @@ -57,13 +58,12 @@ void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) { void SurfaceLayerImpl::AppendQuads(RenderPass* render_pass, AppendQuadsData* append_quads_data) { + AppendRainbowDebugBorder(render_pass); + SharedQuadState* shared_quad_state = render_pass->CreateAndAppendSharedQuadState(); PopulateScaledSharedQuadState(shared_quad_state, surface_scale_); - AppendDebugBorderQuad(render_pass, surface_size_, shared_quad_state, - append_quads_data); - if (surface_id_.is_null()) return; @@ -85,6 +85,93 @@ void SurfaceLayerImpl::GetDebugBorderProperties(SkColor* color, *width = DebugColors::SurfaceLayerBorderWidth(layer_tree_impl()); } +void SurfaceLayerImpl::AppendRainbowDebugBorder(RenderPass* render_pass) { + if (!ShowDebugBorders()) + return; + + SharedQuadState* shared_quad_state = + render_pass->CreateAndAppendSharedQuadState(); + PopulateSharedQuadState(shared_quad_state); + + SkColor color; + float border_width; + GetDebugBorderProperties(&color, &border_width); + + SkColor colors[] = { + 0x80ff0000, // Red. + 0x80ffa500, // Orange. + 0x80ffff00, // Yellow. + 0x80008000, // Green. + 0x800000ff, // Blue. + 0x80ee82ee, // Violet. + }; + const int kNumColors = arraysize(colors); + + const int kStripeWidth = 300; + const int kStripeHeight = 300; + + for (int i = 0;; ++i) { + // For horizontal lines. + int x = kStripeWidth * i; + int width = std::min(kStripeWidth, bounds().width() - x - 1); + + // For vertical lines. + int y = kStripeHeight * i; + int height = std::min(kStripeHeight, bounds().height() - y - 1); + + gfx::Rect top(x, 0, width, border_width); + gfx::Rect bottom(x, bounds().height() - border_width, width, border_width); + gfx::Rect left(0, y, border_width, height); + gfx::Rect right(bounds().width() - border_width, y, border_width, height); + + if (top.IsEmpty() && left.IsEmpty()) + 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], + force_anti_aliasing_off); + + SolidColorDrawQuad* bottom_quad = + render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + bottom_quad->SetNew(shared_quad_state, bottom, bottom, + colors[kNumColors - 1 - (i % kNumColors)], + 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, 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, + colors[kNumColors - 1 - (i % kNumColors)], + force_anti_aliasing_off); + + SolidColorDrawQuad* right_quad = + render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + right_quad->SetNew(shared_quad_state, right, right, + colors[i % kNumColors], force_anti_aliasing_off); + } + } +} + 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 b190b3af940..2bf6a9a008a 100644 --- a/chromium/cc/layers/surface_layer_impl.h +++ b/chromium/cc/layers/surface_layer_impl.h @@ -34,6 +34,7 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl { private: void GetDebugBorderProperties(SkColor* color, float* width) const override; + void AppendRainbowDebugBorder(RenderPass* render_pass); void AsValueInto(base::trace_event::TracedValue* dict) const override; const char* LayerTypeAsString() const override; diff --git a/chromium/cc/layers/surface_layer_unittest.cc b/chromium/cc/layers/surface_layer_unittest.cc index eac14a0c245..e35b88683d8 100644 --- a/chromium/cc/layers/surface_layer_unittest.cc +++ b/chromium/cc/layers/surface_layer_unittest.cc @@ -143,23 +143,43 @@ class SurfaceLayerSwapPromise : public LayerTreeTest { gfx::Size bounds(100, 100); layer_tree_host()->SetViewportSize(bounds); + + blank_layer_ = SolidColorLayer::Create(layer_settings()); + blank_layer_->SetIsDrawable(true); + blank_layer_->SetBounds(gfx::Size(10, 10)); + PostSetNeedsCommitToMainThread(); } + virtual void ChangeTree() = 0; + void DidCommitAndDrawFrame() override { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&SurfaceLayerSwapPromise::ChangeTree, base::Unretained(this))); } - void ChangeTree() { + protected: + int commit_count_; + bool sequence_was_satisfied_; + scoped_refptr<SurfaceLayer> layer_; + scoped_refptr<Layer> blank_layer_; + SurfaceSequence satisfied_sequence_; + + SurfaceId required_id_; + std::set<SurfaceSequence> required_set_; +}; + +// Check that SurfaceSequence is sent through swap promise. +class SurfaceLayerSwapPromiseWithDraw : public SurfaceLayerSwapPromise { + public: + SurfaceLayerSwapPromiseWithDraw() : SurfaceLayerSwapPromise() {} + + void ChangeTree() override { ++commit_count_; switch (commit_count_) { case 1: // Remove SurfaceLayer from tree to cause SwapPromise to be created. - blank_layer_ = SolidColorLayer::Create(layer_settings()); - blank_layer_->SetIsDrawable(true); - blank_layer_->SetBounds(gfx::Size(10, 10)); layer_tree_host()->SetRootLayer(blank_layer_); break; case 2: @@ -193,21 +213,49 @@ class SurfaceLayerSwapPromise : public LayerTreeTest { // callback. EXPECT_TRUE(satisfied_sequence_.is_null()); } - - private: - int commit_count_; - bool sequence_was_satisfied_; - scoped_refptr<SurfaceLayer> layer_; - scoped_refptr<Layer> blank_layer_; - SurfaceSequence satisfied_sequence_; - - SurfaceId required_id_; - std::set<SurfaceSequence> required_set_; }; // TODO(jbauman): Reenable on single thread once http://crbug.com/421923 is // fixed. -MULTI_THREAD_TEST_F(SurfaceLayerSwapPromise); +MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithDraw); + +// Check that SurfaceSequence is sent through swap promise and resolved when +// swap fails. +class SurfaceLayerSwapPromiseWithoutDraw : public SurfaceLayerSwapPromise { + public: + SurfaceLayerSwapPromiseWithoutDraw() : SurfaceLayerSwapPromise() {} + + DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, + LayerTreeHostImpl::FrameData* frame, + DrawResult draw_result) override { + return DRAW_ABORTED_MISSING_HIGH_RES_CONTENT; + } + + void ChangeTree() override { + ++commit_count_; + switch (commit_count_) { + case 1: + // Remove SurfaceLayer from tree to cause SwapPromise to be created. + layer_tree_host()->SetRootLayer(blank_layer_); + break; + case 2: + layer_tree_host()->SetNeedsCommit(); + break; + default: + EndTest(); + break; + } + } + + void AfterTest() override { + EXPECT_TRUE(required_id_ == SurfaceId(1)); + EXPECT_EQ(1u, required_set_.size()); + // Sequence should have been satisfied with the callback. + EXPECT_TRUE(satisfied_sequence_ == SurfaceSequence(1u, 1u)); + } +}; + +MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithoutDraw); } // namespace } // namespace cc diff --git a/chromium/cc/layers/texture_layer.cc b/chromium/cc/layers/texture_layer.cc index 20741fddad8..c9fb61b86a0 100644 --- a/chromium/cc/layers/texture_layer.cc +++ b/chromium/cc/layers/texture_layer.cc @@ -34,7 +34,6 @@ TextureLayer::TextureLayer(const LayerSettings& settings, uv_bottom_right_(1.f, 1.f), premultiplied_alpha_(true), blend_background_color_(false), - rate_limit_context_(false), needs_set_mailbox_(false) { vertex_opacity_[0] = 1.0f; vertex_opacity_[1] = 1.0f; @@ -46,8 +45,6 @@ TextureLayer::~TextureLayer() { } void TextureLayer::ClearClient() { - if (rate_limit_context_ && client_ && layer_tree_host()) - layer_tree_host()->StopRateLimiter(); client_ = nullptr; ClearTexture(); UpdateDrawsContent(HasDrawableContent()); @@ -118,13 +115,6 @@ void TextureLayer::SetBlendBackgroundColor(bool blend) { SetNeedsCommit(); } -void TextureLayer::SetRateLimitContext(bool rate_limit) { - if (!rate_limit && rate_limit_context_ && client_ && layer_tree_host()) - layer_tree_host()->StopRateLimiter(); - - rate_limit_context_ = rate_limit; -} - void TextureLayer::SetTextureMailboxInternal( const TextureMailbox& mailbox, scoped_ptr<SingleReleaseCallback> release_callback, @@ -185,9 +175,6 @@ void TextureLayer::SetTextureMailboxWithoutReleaseCallback( void TextureLayer::SetNeedsDisplayRect(const gfx::Rect& dirty_rect) { Layer::SetNeedsDisplayRect(dirty_rect); - - if (rate_limit_context_ && client_ && layer_tree_host() && DrawsContent()) - layer_tree_host()->StartRateLimiter(); } void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) { @@ -196,10 +183,6 @@ void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) { return; } - if (layer_tree_host()) { - if (rate_limit_context_ && client_) - layer_tree_host()->StopRateLimiter(); - } // If we're removed from the tree, the TextureLayerImpl will be destroyed, and // we will need to set the mailbox again on a new TextureLayerImpl the next // time we push. diff --git a/chromium/cc/layers/texture_layer.h b/chromium/cc/layers/texture_layer.h index 53f2d8d4065..0c0b2ec237d 100644 --- a/chromium/cc/layers/texture_layer.h +++ b/chromium/cc/layers/texture_layer.h @@ -124,11 +124,6 @@ class CC_EXPORT TextureLayer : public Layer { // at draw time. Defaults to false. void SetBlendBackgroundColor(bool blend); - // Sets whether this context should rate limit on damage to prevent too many - // frames from being queued up before the compositor gets a chance to run. - // Requires a non-nil client. Defaults to false. - void SetRateLimitContext(bool rate_limit); - // Code path for plugins which supply their own mailbox. void SetTextureMailbox(const TextureMailbox& mailbox, scoped_ptr<SingleReleaseCallback> release_callback); @@ -167,7 +162,6 @@ class CC_EXPORT TextureLayer : public Layer { float vertex_opacity_[4]; bool premultiplied_alpha_; bool blend_background_color_; - bool rate_limit_context_; scoped_ptr<TextureMailboxHolder::MainThreadReference> holder_ref_; bool needs_set_mailbox_; diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc index 97bb7a15b20..8c138c35bd4 100644 --- a/chromium/cc/layers/texture_layer_unittest.cc +++ b/chromium/cc/layers/texture_layer_unittest.cc @@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/location.h" #include "base/single_thread_task_runner.h" +#include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/thread_task_runner_handle.h" #include "base/threading/thread.h" @@ -188,6 +189,7 @@ class TextureLayerTest : public testing::Test { TextureLayerTest() : fake_client_( FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)), + output_surface_(FakeOutputSurface::Create3d()), host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_), test_data_(&shared_bitmap_manager_) {} @@ -213,6 +215,7 @@ class TextureLayerTest : public testing::Test { FakeLayerTreeHostClient fake_client_; TestSharedBitmapManager shared_bitmap_manager_; TestTaskGraphRunner task_graph_runner_; + scoped_ptr<OutputSurface> output_surface_; FakeLayerTreeHostImpl host_impl_; CommonMailboxObjects test_data_; LayerSettings layer_settings_; @@ -235,55 +238,6 @@ TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) { EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendBackgroundColor(true)); } -TEST_F(TextureLayerTest, RateLimiter) { - FakeTextureLayerClient client; - scoped_refptr<TextureLayer> test_layer = - TextureLayer::CreateForMailbox(layer_settings_, &client); - test_layer->SetIsDrawable(true); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber()); - layer_tree_host_->SetRootLayer(test_layer); - - // Don't rate limit until we invalidate. - EXPECT_CALL(*layer_tree_host_, StartRateLimiter()).Times(0); - test_layer->SetRateLimitContext(true); - Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - - // Do rate limit after we invalidate. - EXPECT_CALL(*layer_tree_host_, StartRateLimiter()); - test_layer->SetNeedsDisplay(); - Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - - // Stop rate limiter when we don't want it any more. - EXPECT_CALL(*layer_tree_host_, StopRateLimiter()); - test_layer->SetRateLimitContext(false); - Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - - // Or we clear the client. - test_layer->SetRateLimitContext(true); - EXPECT_CALL(*layer_tree_host_, StopRateLimiter()); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber()); - test_layer->ClearClient(); - Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - - // Reset to a layer with a client, that started the rate limiter. - test_layer = TextureLayer::CreateForMailbox(layer_settings_, &client); - test_layer->SetIsDrawable(true); - test_layer->SetRateLimitContext(true); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber()); - layer_tree_host_->SetRootLayer(test_layer); - EXPECT_CALL(*layer_tree_host_, StartRateLimiter()).Times(0); - Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - EXPECT_CALL(*layer_tree_host_, StartRateLimiter()); - test_layer->SetNeedsDisplay(); - Mock::VerifyAndClearExpectations(layer_tree_host_.get()); - - // Stop rate limiter when we're removed from the tree. - EXPECT_CALL(*layer_tree_host_, StopRateLimiter()); - EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); - layer_tree_host_->SetRootLayer(nullptr); - Mock::VerifyAndClearExpectations(layer_tree_host_.get()); -} - class TestMailboxHolder : public TextureLayer::TextureMailboxHolder { public: using TextureLayer::TextureMailboxHolder::Create; @@ -823,10 +777,19 @@ class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest { } void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override { + base::AutoLock lock(activate_count_lock_); ++activate_count_; } void DidCommit() override { + // The first frame doesn't cause anything to be returned so it does not + // need to wait for activation. + if (layer_tree_host()->source_frame_number() > 1) { + base::AutoLock lock(activate_count_lock_); + // The activate happened before commit is done on the main side. + EXPECT_EQ(activate_count_, layer_tree_host()->source_frame_number()); + } + switch (layer_tree_host()->source_frame_number()) { case 1: // The first mailbox has been activated. Set a new mailbox, and @@ -846,31 +809,14 @@ class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest { } void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { - switch (host_impl->active_tree()->source_frame_number()) { - case 0: { - // The activate for the 1st mailbox should have happened before now. - EXPECT_EQ(1, activate_count_); - break; - } - case 1: { - // The activate for the 2nd mailbox should have happened before now. - EXPECT_EQ(2, activate_count_); - break; - } - case 2: { - // The activate to remove the layer should have happened before now. - EXPECT_EQ(3, activate_count_); - break; - } - case 3: { - NOTREACHED(); - break; - } - } + // The activate didn't happen before commit is done on the impl side (but it + // should happen before the main thread is done). + EXPECT_EQ(activate_count_, host_impl->sync_tree()->source_frame_number()); } void AfterTest() override {} + base::Lock activate_count_lock_; int activate_count_; scoped_refptr<Layer> root_; scoped_refptr<TextureLayer> layer_; @@ -889,7 +835,7 @@ class TextureLayerImplWithMailboxTest : public TextureLayerTest { TextureLayerTest::SetUp(); layer_tree_host_ = MockLayerTreeHost::Create(&fake_client_, &task_graph_runner_); - EXPECT_TRUE(host_impl_.InitializeRenderer(FakeOutputSurface::Create3d())); + EXPECT_TRUE(host_impl_.InitializeRenderer(output_surface_.get())); } bool WillDraw(TextureLayerImpl* layer, DrawMode mode) { diff --git a/chromium/cc/layers/ui_resource_layer_impl_unittest.cc b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc index e31d68ae6e5..826c53f8181 100644 --- a/chromium/cc/layers/ui_resource_layer_impl_unittest.cc +++ b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc @@ -60,9 +60,10 @@ TEST(UIResourceLayerImplTest, VerifyDrawQuads) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, &task_graph_runner); - host_impl.InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl.InitializeRenderer(output_surface.get()); // Make sure we're appending quads when there are valid values. gfx::Size bitmap_size(100, 100); @@ -106,9 +107,10 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnSkBitmap) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, &task_graph_runner); - host_impl.InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl.InitializeRenderer(output_surface.get()); gfx::Size bitmap_size(100, 100); gfx::Size layer_size(100, 100);; @@ -136,9 +138,10 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnLayer) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, &task_graph_runner); - host_impl.InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl.InitializeRenderer(output_surface.get()); gfx::Size bitmap_size(100, 100); gfx::Size layer_size(100, 100); diff --git a/chromium/cc/layers/video_frame_provider_client_impl_unittest.cc b/chromium/cc/layers/video_frame_provider_client_impl_unittest.cc index 05385e46e56..4cbd493e0d5 100644 --- a/chromium/cc/layers/video_frame_provider_client_impl_unittest.cc +++ b/chromium/cc/layers/video_frame_provider_client_impl_unittest.cc @@ -31,7 +31,7 @@ class VideoFrameProviderClientImplTest : public testing::Test, VideoFrameProviderClientImplTest() : client_impl_(VideoFrameProviderClientImpl::Create(&provider_, this)), video_layer_impl_(nullptr), - test_frame_(media::VideoFrame::CreateFrame(media::VideoFrame::YV12, + test_frame_(media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12, gfx::Size(10, 10), gfx::Rect(10, 10), gfx::Size(10, 10), diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc index 2233583ed09..3313aa5cfb1 100644 --- a/chromium/cc/layers/video_layer_impl.cc +++ b/chromium/cc/layers/video_layer_impl.cc @@ -225,10 +225,9 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass, int videoframe_color_space; if (frame_->metadata()->GetInteger(media::VideoFrameMetadata::COLOR_SPACE, &videoframe_color_space)) { - if (videoframe_color_space == media::VideoFrame::COLOR_SPACE_JPEG) { + if (videoframe_color_space == media::COLOR_SPACE_JPEG) { color_space = YUVVideoDrawQuad::JPEG; - } else if (videoframe_color_space == - media::VideoFrame::COLOR_SPACE_HD_REC709) { + } else if (videoframe_color_space == media::COLOR_SPACE_HD_REC709) { color_space = YUVVideoDrawQuad::REC_709; } } @@ -237,7 +236,7 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass, gfx::Size uv_tex_size; if (frame_->HasTextures()) { - DCHECK_EQ(media::VideoFrame::I420, frame_->format()); + DCHECK_EQ(media::PIXEL_FORMAT_I420, frame_->format()); DCHECK_EQ(3u, frame_resources_.size()); // Alpha is not supported yet. DCHECK(visible_rect.origin().IsOrigin()); DCHECK(visible_rect.size() == coded_size); @@ -328,7 +327,8 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass, io_surface_quad->SetNew(shared_quad_state, quad_rect, opaque_rect, visible_quad_rect, visible_rect.size(), frame_resources_[0].id, - IOSurfaceDrawQuad::UNFLIPPED); + IOSurfaceDrawQuad::UNFLIPPED, + frame_resources_[0].allow_overlay); ValidateQuadResources(io_surface_quad); break; } diff --git a/chromium/cc/layers/video_layer_impl_unittest.cc b/chromium/cc/layers/video_layer_impl_unittest.cc index da2de85d9ef..28ba58acc2d 100644 --- a/chromium/cc/layers/video_layer_impl_unittest.cc +++ b/chromium/cc/layers/video_layer_impl_unittest.cc @@ -35,12 +35,9 @@ TEST(VideoLayerImplTest, Occlusion) { LayerTestCommon::LayerImplTest impl; DebugSetImplThreadAndMainThreadBlocked(impl.proxy()); - 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()); + scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( + media::PIXEL_FORMAT_YV12, gfx::Size(10, 10), gfx::Rect(10, 10), + gfx::Size(10, 10), base::TimeDelta()); FakeVideoFrameProvider provider; provider.set_frame(video_frame); @@ -118,7 +115,7 @@ TEST(VideoLayerImplTest, OccludesOtherLayers) { 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), + media::PIXEL_FORMAT_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(); @@ -152,12 +149,9 @@ TEST(VideoLayerImplTest, Rotated0) { LayerTestCommon::LayerImplTest impl; DebugSetImplThreadAndMainThreadBlocked(impl.proxy()); - 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()); + scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( + media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10), + gfx::Size(20, 10), base::TimeDelta()); FakeVideoFrameProvider provider; provider.set_frame(video_frame); @@ -191,12 +185,9 @@ TEST(VideoLayerImplTest, Rotated90) { LayerTestCommon::LayerImplTest impl; DebugSetImplThreadAndMainThreadBlocked(impl.proxy()); - 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()); + scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( + media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10), + gfx::Size(20, 10), base::TimeDelta()); FakeVideoFrameProvider provider; provider.set_frame(video_frame); @@ -230,12 +221,9 @@ TEST(VideoLayerImplTest, Rotated180) { LayerTestCommon::LayerImplTest impl; DebugSetImplThreadAndMainThreadBlocked(impl.proxy()); - 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()); + scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( + media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10), + gfx::Size(20, 10), base::TimeDelta()); FakeVideoFrameProvider provider; provider.set_frame(video_frame); @@ -269,12 +257,9 @@ TEST(VideoLayerImplTest, Rotated270) { LayerTestCommon::LayerImplTest impl; DebugSetImplThreadAndMainThreadBlocked(impl.proxy()); - 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()); + scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( + media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10), + gfx::Size(20, 10), base::TimeDelta()); FakeVideoFrameProvider provider; provider.set_frame(video_frame); @@ -315,7 +300,7 @@ TEST(VideoLayerImplTest, SoftwareVideoFrameGeneratesYUVQuad) { 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), + media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10), gfx::Size(20, 10), base::TimeDelta()); FakeVideoFrameProvider provider; diff --git a/chromium/cc/layers/viewport.cc b/chromium/cc/layers/viewport.cc index 059e0a491a9..80e711fd027 100644 --- a/chromium/cc/layers/viewport.cc +++ b/chromium/cc/layers/viewport.cc @@ -34,43 +34,41 @@ void Viewport::Pan(const gfx::Vector2dF& delta) { Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta, const gfx::Point& viewport_point, - bool is_wheel_scroll, + bool is_direct_manipulation, bool affect_top_controls) { gfx::Vector2dF content_delta = delta; - ScrollResult result; - if (affect_top_controls && ShouldTopControlsConsumeScroll(delta)) { - result.top_controls_applied_delta = ScrollTopControls(delta); - content_delta -= result.top_controls_applied_delta; - } + if (affect_top_controls && ShouldTopControlsConsumeScroll(delta)) + content_delta -= ScrollTopControls(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); - } + pending_content_delta -= host_impl_->ScrollLayer(InnerScrollLayer(), + pending_content_delta, + viewport_point, + is_direct_manipulation); + + ScrollResult result; // 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(), + if (gfx::ToRoundedVector2d(pending_content_delta).IsZero()) { + result.consumed_delta = delta; + } else { + pending_content_delta -= host_impl_->ScrollLayer(OuterScrollLayer(), pending_content_delta, viewport_point, - is_wheel_scroll); - result.unused_scroll_delta = AdjustOverscroll(pending_content_delta); + is_direct_manipulation); + result.consumed_delta = delta - AdjustOverscroll(pending_content_delta); } - - result.applied_delta = content_delta - pending_content_delta; + result.content_scrolled_delta = content_delta - pending_content_delta; return result; } void Viewport::SnapPinchAnchorIfWithinMargin(const gfx::Point& anchor) { - gfx::SizeF viewport_size = - host_impl_->active_tree()->InnerViewportContainerLayer()->bounds(); + gfx::SizeF viewport_size = gfx::SizeF( + host_impl_->active_tree()->InnerViewportContainerLayer()->bounds()); if (anchor.x() < kPinchZoomSnapMarginDips) pinch_anchor_adjustment_.set_x(-anchor.x()); @@ -89,8 +87,7 @@ void Viewport::PinchUpdate(float magnify_delta, const gfx::Point& anchor) { // length of the screen edge, offset all updates by the amount so that we // effectively snap the pinch zoom to the edge of the screen. This makes it // easy to zoom in on position: fixed elements. - if (host_impl_->settings().invert_viewport_scroll_order) - SnapPinchAnchorIfWithinMargin(anchor); + SnapPinchAnchorIfWithinMargin(anchor); pinch_zoom_active_ = true; } @@ -117,14 +114,7 @@ void Viewport::PinchUpdate(float magnify_delta, const gfx::Point& anchor) { // be accounted for from the intended move. move -= InnerScrollLayer()->ClampScrollToMaxScrollOffset(); - if (host_impl_->settings().invert_viewport_scroll_order) { - Pan(move); - } else { - gfx::Point viewport_point; - bool is_wheel_event = false; - bool affect_top_controls = false; - ScrollBy(move, viewport_point, is_wheel_event, affect_top_controls); - } + Pan(move); } void Viewport::PinchEnd() { @@ -152,6 +142,8 @@ bool Viewport::ShouldTopControlsConsumeScroll( } gfx::Vector2dF Viewport::AdjustOverscroll(const gfx::Vector2dF& delta) const { + // TODO(tdresser): Use a more rational epsilon. See crbug.com/510550 for + // details. const float kEpsilon = 0.1f; gfx::Vector2dF adjusted = delta; @@ -160,16 +152,6 @@ gfx::Vector2dF Viewport::AdjustOverscroll(const gfx::Vector2dF& delta) const { 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; } diff --git a/chromium/cc/layers/viewport.h b/chromium/cc/layers/viewport.h index 01885d7774f..5d96cd3b283 100644 --- a/chromium/cc/layers/viewport.h +++ b/chromium/cc/layers/viewport.h @@ -25,10 +25,11 @@ class CC_EXPORT Viewport { // determined. static const int kPinchZoomSnapMarginDips = 100; + // TODO(tdresser): eventually |consumed_delta| should equal + // |content_scrolled_delta|. See crbug.com/510045 for details. struct ScrollResult { - gfx::Vector2dF applied_delta; - gfx::Vector2dF unused_scroll_delta; - gfx::Vector2dF top_controls_applied_delta; + gfx::Vector2dF consumed_delta; + gfx::Vector2dF content_scrolled_delta; }; static scoped_ptr<Viewport> Create(LayerTreeHostImpl* host_impl); diff --git a/chromium/cc/output/compositor_frame.cc b/chromium/cc/output/compositor_frame.cc index e6d713d50e5..e612b28cfad 100644 --- a/chromium/cc/output/compositor_frame.cc +++ b/chromium/cc/output/compositor_frame.cc @@ -13,7 +13,6 @@ CompositorFrame::~CompositorFrame() {} void CompositorFrame::AssignTo(CompositorFrame* target) { target->delegated_frame_data = delegated_frame_data.Pass(); target->gl_frame_data = gl_frame_data.Pass(); - target->software_frame_data = software_frame_data.Pass(); target->metadata = metadata; } diff --git a/chromium/cc/output/compositor_frame.h b/chromium/cc/output/compositor_frame.h index e5c8a334161..3ab1e8c2c9a 100644 --- a/chromium/cc/output/compositor_frame.h +++ b/chromium/cc/output/compositor_frame.h @@ -10,10 +10,12 @@ #include "cc/output/compositor_frame_metadata.h" #include "cc/output/delegated_frame_data.h" #include "cc/output/gl_frame_data.h" -#include "cc/output/software_frame_data.h" namespace cc { +// A CompositorFrame struct contains the complete output of a compositor meant +// for display. +// TODO(fsamuel): Write more here. class CC_EXPORT CompositorFrame { public: CompositorFrame(); @@ -22,7 +24,6 @@ class CC_EXPORT CompositorFrame { CompositorFrameMetadata metadata; scoped_ptr<DelegatedFrameData> delegated_frame_data; scoped_ptr<GLFrameData> gl_frame_data; - scoped_ptr<SoftwareFrameData> software_frame_data; void AssignTo(CompositorFrame* target); diff --git a/chromium/cc/output/compositor_frame_ack.cc b/chromium/cc/output/compositor_frame_ack.cc index feb0bac3674..a411b42f5de 100644 --- a/chromium/cc/output/compositor_frame_ack.cc +++ b/chromium/cc/output/compositor_frame_ack.cc @@ -6,8 +6,7 @@ namespace cc { -CompositorFrameAck::CompositorFrameAck() - : last_software_frame_id(0) {} +CompositorFrameAck::CompositorFrameAck() {} CompositorFrameAck::~CompositorFrameAck() {} diff --git a/chromium/cc/output/compositor_frame_ack.h b/chromium/cc/output/compositor_frame_ack.h index 943a206e391..aa48fa157b3 100644 --- a/chromium/cc/output/compositor_frame_ack.h +++ b/chromium/cc/output/compositor_frame_ack.h @@ -19,7 +19,6 @@ class CC_EXPORT CompositorFrameAck { ReturnedResourceArray resources; scoped_ptr<GLFrameData> gl_frame_data; - unsigned last_software_frame_id; private: DISALLOW_COPY_AND_ASSIGN(CompositorFrameAck); diff --git a/chromium/cc/output/compositor_frame_metadata.cc b/chromium/cc/output/compositor_frame_metadata.cc index dad78a0c822..b3a9b2d40a0 100644 --- a/chromium/cc/output/compositor_frame_metadata.cc +++ b/chromium/cc/output/compositor_frame_metadata.cc @@ -12,8 +12,8 @@ CompositorFrameMetadata::CompositorFrameMetadata() min_page_scale_factor(0.f), max_page_scale_factor(0.f), root_overflow_x_hidden(false), - root_overflow_y_hidden(false) { -} + root_overflow_y_hidden(false), + root_background_color(SK_ColorWHITE) {} CompositorFrameMetadata::~CompositorFrameMetadata() { } diff --git a/chromium/cc/output/compositor_frame_metadata.h b/chromium/cc/output/compositor_frame_metadata.h index 999a6b4406a..72035e32afd 100644 --- a/chromium/cc/output/compositor_frame_metadata.h +++ b/chromium/cc/output/compositor_frame_metadata.h @@ -9,6 +9,7 @@ #include "cc/base/cc_export.h" #include "cc/output/viewport_selection_bound.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/events/latency_info.h" #include "ui/gfx/geometry/size_f.h" #include "ui/gfx/geometry/vector2d_f.h" @@ -42,6 +43,11 @@ class CC_EXPORT CompositorFrameMetadata { gfx::Vector2dF location_bar_offset; gfx::Vector2dF location_bar_content_translation; + // This color is usually obtained from the background color of the <body> + // element. It can be used for filling in gutter areas around the frame when + // it's too small to fill the box the parent reserved for it. + SkColor root_background_color; + // Provides selection region updates relative to the current viewport. If the // selection is empty or otherwise unused, the bound types will indicate such. ViewportSelection selection; diff --git a/chromium/cc/output/context_provider.h b/chromium/cc/output/context_provider.h index aa4367d97ff..47eff203548 100644 --- a/chromium/cc/output/context_provider.h +++ b/chromium/cc/output/context_provider.h @@ -7,6 +7,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" #include "cc/base/cc_export.h" #include "gpu/command_buffer/common/capabilities.h" @@ -26,10 +27,33 @@ struct ManagedMemoryPolicy; class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> { public: + class ScopedContextLock { + public: + explicit ScopedContextLock(ContextProvider* context_provider) + : context_provider_(context_provider), + context_lock_(*context_provider_->GetLock()) { + // Allow current thread to use |context_provider_|. + context_provider_->DetachFromThread(); + } + ~ScopedContextLock() { + // Allow usage by thread for which |context_provider_| is bound to. + context_provider_->DetachFromThread(); + } + + gpu::gles2::GLES2Interface* ContextGL() { + return context_provider_->ContextGL(); + } + + private: + ContextProvider* const context_provider_; + base::AutoLock context_lock_; + }; // Bind the 3d context to the current thread. This should be called before // accessing the contexts. Calling it more than once should have no effect. // Once this function has been called, the class should only be accessed - // from the same thread. + // from the same thread unless the function has some explicitly specified + // rules for access on a different thread. See SetupLockOnMainThread(), which + // can be used to provide access from multiple threads. virtual bool BindToCurrentThread() = 0; virtual void DetachFromThread() {} @@ -48,11 +72,13 @@ class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> { // 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. + // Sets up a lock so this context can be used from multiple threads. After + // calling this, all functions without explicit thread usage constraints can + // be used on any thread while the lock returned by GetLock() is acquired. virtual void SetupLock() = 0; // Returns the lock that should be held if using this context from multiple - // threads. + // threads. This can be called on any thread. virtual base::Lock* GetLock() = 0; // Returns the capabilities of the currently bound 3d context. diff --git a/chromium/cc/output/delegating_renderer_unittest.cc b/chromium/cc/output/delegating_renderer_unittest.cc index 3238d2d9028..b32e9a369fc 100644 --- a/chromium/cc/output/delegating_renderer_unittest.cc +++ b/chromium/cc/output/delegating_renderer_unittest.cc @@ -6,7 +6,6 @@ #include "cc/test/fake_output_surface.h" #include "cc/test/layer_tree_test.h" -#include "cc/test/render_pass_test_common.h" #include "cc/test/render_pass_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -90,19 +89,17 @@ class DelegatingRendererTestResources : public DelegatingRendererTest { frame->render_passes.clear(); frame->render_passes_by_id.clear(); - TestRenderPass* child_pass = AddRenderPass(&frame->render_passes, - RenderPassId(2, 1), - gfx::Rect(3, 3, 10, 10), - gfx::Transform()); - child_pass->AppendOneOfEveryQuadType(host_impl->resource_provider(), - RenderPassId(0, 0)); - - TestRenderPass* pass = AddRenderPass(&frame->render_passes, - RenderPassId(1, 1), - gfx::Rect(3, 3, 10, 10), - gfx::Transform()); - pass->AppendOneOfEveryQuadType( - host_impl->resource_provider(), child_pass->id); + RenderPass* child_pass = + AddRenderPass(&frame->render_passes, RenderPassId(2, 1), + gfx::Rect(3, 3, 10, 10), gfx::Transform()); + uint32_t mailbox_sync_point; + AddOneOfEveryQuadType(child_pass, host_impl->resource_provider(), + RenderPassId(0, 0), &mailbox_sync_point); + + RenderPass* pass = AddRenderPass(&frame->render_passes, RenderPassId(1, 1), + gfx::Rect(3, 3, 10, 10), gfx::Transform()); + AddOneOfEveryQuadType(pass, host_impl->resource_provider(), child_pass->id, + &mailbox_sync_point); return draw_result; } diff --git a/chromium/cc/output/direct_renderer.cc b/chromium/cc/output/direct_renderer.cc index 7ceaa00379f..f98151833e0 100644 --- a/chromium/cc/output/direct_renderer.cc +++ b/chromium/cc/output/direct_renderer.cc @@ -17,6 +17,7 @@ #include "cc/output/bsp_walk_action.h" #include "cc/output/copy_output_request.h" #include "cc/quads/draw_quad.h" +#include "ui/gfx/geometry/quad_f.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/transform.h" @@ -221,6 +222,20 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order, BeginDrawingFrame(&frame); + if (output_surface_->IsDisplayedAsOverlayPlane()) { + // Create the overlay candidate for the output surface, and mark it as + // always + // handled. + OverlayCandidate output_surface_plane; + output_surface_plane.display_rect = + gfx::RectF(root_render_pass->output_rect); + output_surface_plane.quad_rect_in_target_space = + root_render_pass->output_rect; + output_surface_plane.use_output_surface_for_resource = true; + output_surface_plane.overlay_handled = true; + frame.overlay_list.push_back(output_surface_plane); + } + // 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()) { @@ -445,7 +460,7 @@ void DirectRenderer::DrawRenderPass(DrawingFrame* frame, for (auto it = quad_list.BackToFrontBegin(); it != quad_list.BackToFrontEnd(); ++it) { const DrawQuad& quad = **it; - gfx::QuadF send_quad(quad.visible_rect); + gfx::QuadF send_quad(gfx::RectF(quad.visible_rect)); if (render_pass_is_clipped && ShouldSkipQuad(quad, render_pass_scissor_in_draw_space)) { @@ -462,7 +477,7 @@ void DirectRenderer::DrawRenderPass(DrawingFrame* frame, // 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, + *it, gfx::RectF(quad.visible_rect), quad.shared_quad_state->quad_to_target_transform, next_polygon_id++)); if (new_polygon->points().size() > 2u) { poly_list.push_back(new_polygon.Pass()); diff --git a/chromium/cc/output/filter_operations.cc b/chromium/cc/output/filter_operations.cc index 92423de9b59..659acae64b0 100644 --- a/chromium/cc/output/filter_operations.cc +++ b/chromium/cc/output/filter_operations.cc @@ -61,22 +61,31 @@ void FilterOperations::GetOutsets(int* top, *top = *right = *bottom = *left = 0; for (size_t i = 0; i < operations_.size(); ++i) { const FilterOperation& op = operations_[i]; - // TODO(ajuma): Add support for reference filters once SkImageFilter - // reports its outsets. - DCHECK(op.type() != FilterOperation::REFERENCE); - if (op.type() == FilterOperation::BLUR || - op.type() == FilterOperation::DROP_SHADOW) { - int spread = SpreadForStdDeviation(op.amount()); - if (op.type() == FilterOperation::BLUR) { - *top += spread; - *right += spread; - *bottom += spread; - *left += spread; - } else { - *top += spread - op.drop_shadow_offset().y(); - *right += spread + op.drop_shadow_offset().x(); - *bottom += spread + op.drop_shadow_offset().y(); - *left += spread - op.drop_shadow_offset().x(); + // TODO(hendrikw): We should refactor some of this. See crbug.com/523534. + if (op.type() == FilterOperation::REFERENCE) { + SkIRect src = SkIRect::MakeWH(0, 0); + SkIRect dst; + bool result = op.image_filter()->filterBounds(src, SkMatrix::I(), &dst); + DCHECK(result); + *top += std::max(0, -dst.top()); + *right += std::max(0, dst.right()); + *bottom += std::max(0, dst.bottom()); + *left += std::max(0, -dst.left()); + } else { + if (op.type() == FilterOperation::BLUR || + op.type() == FilterOperation::DROP_SHADOW) { + int spread = SpreadForStdDeviation(op.amount()); + if (op.type() == FilterOperation::BLUR) { + *top += spread; + *right += spread; + *bottom += spread; + *left += spread; + } else { + *top += spread - op.drop_shadow_offset().y(); + *right += spread + op.drop_shadow_offset().x(); + *bottom += spread + op.drop_shadow_offset().y(); + *left += spread - op.drop_shadow_offset().x(); + } } } } @@ -85,13 +94,14 @@ void FilterOperations::GetOutsets(int* top, bool FilterOperations::HasFilterThatMovesPixels() const { for (size_t i = 0; i < operations_.size(); ++i) { const FilterOperation& op = operations_[i]; - // TODO(ajuma): Once SkImageFilter reports its outsets, use those here to - // determine whether a reference filter really moves pixels. switch (op.type()) { case FilterOperation::BLUR: case FilterOperation::DROP_SHADOW: case FilterOperation::ZOOM: + return true; case FilterOperation::REFERENCE: + // TODO(hendrikw): SkImageFilter needs a function that tells us if the + // filter can move pixels. See crbug.com/523538. return true; case FilterOperation::OPACITY: case FilterOperation::COLOR_MATRIX: diff --git a/chromium/cc/output/filter_operations_unittest.cc b/chromium/cc/output/filter_operations_unittest.cc index d6ae6ab500a..7717bde1213 100644 --- a/chromium/cc/output/filter_operations_unittest.cc +++ b/chromium/cc/output/filter_operations_unittest.cc @@ -6,6 +6,7 @@ #include "skia/ext/refptr.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/effects/SkBlurImageFilter.h" +#include "third_party/skia/include/effects/SkDropShadowImageFilter.h" #include "ui/gfx/geometry/point.h" namespace cc { @@ -23,6 +24,26 @@ TEST(FilterOperationsTest, GetOutsetsBlur) { EXPECT_EQ(57, left); } +TEST(FilterOperationsTest, GetOutsetsDropShadowReferenceFilter) { + // TODO(hendrikw): We need to make outsets for reference filters be in line + // with non-reference filters. See crbug.com/523534 + skia::RefPtr<SkImageFilter> filter = + skia::AdoptRef(SkDropShadowImageFilter::Create( + SkIntToScalar(3), SkIntToScalar(8), SkIntToScalar(4), + SkIntToScalar(9), SK_ColorBLACK, + SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode)); + FilterOperations ops; + ops.Append(FilterOperation::CreateReferenceFilter(filter)); + + int top, right, bottom, left; + top = right = bottom = left = 0; + ops.GetOutsets(&top, &right, &bottom, &left); + EXPECT_EQ(35, top); + EXPECT_EQ(9, right); + EXPECT_EQ(19, bottom); + EXPECT_EQ(15, left); +} + TEST(FilterOperationsTest, GetOutsetsDropShadow) { FilterOperations ops; ops.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(3, 8), 20, 0)); diff --git a/chromium/cc/output/gl_renderer.cc b/chromium/cc/output/gl_renderer.cc index 3ffc676a66d..536ab50082d 100644 --- a/chromium/cc/output/gl_renderer.cc +++ b/chromium/cc/output/gl_renderer.cc @@ -381,6 +381,7 @@ GLRenderer::~GLRenderer() { pending_async_read_pixels_.pop_back(); } + previous_swap_overlay_resources_.clear(); in_use_overlay_resources_.clear(); CleanupSharedObjects(); @@ -501,11 +502,6 @@ void GLRenderer::BeginDrawingFrame(DrawingFrame* frame) { ReinitializeGLState(); } -void GLRenderer::DoNoOp() { - gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); - gl_->Flush(); -} - void GLRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad, const gfx::QuadF* clip_region) { @@ -518,10 +514,6 @@ void GLRenderer::DoDrawQuad(DrawingFrame* frame, case DrawQuad::INVALID: NOTREACHED(); break; - case DrawQuad::CHECKERBOARD: - DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad), - clip_region); - break; case DrawQuad::DEBUG_BORDER: DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad)); break; @@ -564,48 +556,6 @@ void GLRenderer::DoDrawQuad(DrawingFrame* frame, } } -void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame, - 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(); - DCHECK(program && (program->initialized() || IsContextLost())); - SetUseProgram(program->program()); - - SkColor color = quad->color; - 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 kCheckerboardWidth = 16; - float frequency = 1.0f / kCheckerboardWidth; - - gfx::Rect tile_rect = quad->rect; - 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->shared_quad_state->opacity, - program->fragment_shader().alpha_location()); - DrawQuadGeometry(frame, quad->shared_quad_state->quad_to_target_transform, - quad->rect, 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. @@ -624,7 +574,7 @@ void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame, gfx::Transform render_matrix; QuadRectTransform(&render_matrix, quad->shared_quad_state->quad_to_target_transform, - layer_rect); + gfx::RectF(layer_rect)); GLRenderer::ToGLMatrix(&gl_matrix[0], frame->projection_matrix * render_matrix); gl_->UniformMatrix4fv(program->vertex_shader().matrix_location(), 1, false, @@ -805,21 +755,13 @@ void GLRenderer::RestoreBlendFuncToDefault(SkXfermode::Mode blend_mode) { } } -bool GLRenderer::ShouldApplyBackgroundFilters(DrawingFrame* frame, - const RenderPassDrawQuad* quad) { +bool GLRenderer::ShouldApplyBackgroundFilters(const RenderPassDrawQuad* quad) { if (quad->background_filters.IsEmpty()) return false; - // TODO(danakj): We only allow background filters on an opaque render surface - // because other surfaces may contain translucent pixels, and the contents - // behind those translucent pixels wouldn't have the filter applied. - if (frame->current_render_pass->has_transparent_background) - return false; + // TODO(hendrikw): Look into allowing background filters to see pixels from + // other render targets. See crbug.com/314867. - // TODO(ajuma): Add support for reference filters once - // FilterOperations::GetOutsets supports reference filters. - if (quad->background_filters.HasReferenceFilter()) - return false; return true; } @@ -874,7 +816,7 @@ gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad( gfx::Rect backdrop_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect( contents_device_transform, scaled_region.BoundingBox())); - if (ShouldApplyBackgroundFilters(frame, quad)) { + if (ShouldApplyBackgroundFilters(quad)) { int top, right, bottom, left; quad->background_filters.GetOutsets(&top, &right, &bottom, &left); backdrop_rect.Inset(-left, -top, -right, -bottom); @@ -910,9 +852,9 @@ skia::RefPtr<SkImage> GLRenderer::ApplyBackgroundFilters( DrawingFrame* frame, const RenderPassDrawQuad* quad, ScopedResource* background_texture) { - DCHECK(ShouldApplyBackgroundFilters(frame, quad)); + DCHECK(ShouldApplyBackgroundFilters(quad)); skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( - quad->background_filters, background_texture->size()); + quad->background_filters, gfx::SizeF(background_texture->size())); skia::RefPtr<SkImage> background_with_filters = ApplyImageFilter( ScopedUseGrContext::Create(this, frame), resource_provider_, quad->rect, @@ -931,7 +873,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, gfx::Transform quad_rect_matrix; QuadRectTransform(&quad_rect_matrix, quad->shared_quad_state->quad_to_target_transform, - quad->rect); + gfx::RectF(quad->rect)); gfx::Transform contents_device_transform = frame->window_matrix * frame->projection_matrix * quad_rect_matrix; contents_device_transform.FlattenTo2d(); @@ -960,7 +902,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode; bool use_shaders_for_blending = !CanApplyBlendModeUsingBlendFunc(blend_mode) || - ShouldApplyBackgroundFilters(frame, quad) || + ShouldApplyBackgroundFilters(quad) || settings_->force_blending_with_shaders; scoped_ptr<ScopedResource> background_texture; @@ -985,7 +927,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, // LayerTreeHost::CalculateMemoryForRenderSurfaces. background_texture = GetBackdropTexture(background_rect); - if (ShouldApplyBackgroundFilters(frame, quad) && background_texture) { + if (ShouldApplyBackgroundFilters(quad) && background_texture) { // Apply the background filters to R, so that it is applied in the // pixels' coordinate space. background_image = @@ -1005,7 +947,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, if (!quad->mask_resource_id()) background_texture.reset(); } else if (CanApplyBlendModeUsingBlendFunc(blend_mode) && - ShouldApplyBackgroundFilters(frame, quad)) { + ShouldApplyBackgroundFilters(quad)) { // Something went wrong with applying background filters to the backdrop. use_shaders_for_blending = false; background_texture.reset(); @@ -1028,7 +970,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, bool use_color_matrix = false; if (!quad->filters.IsEmpty()) { skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( - quad->filters, contents_texture->size()); + quad->filters, gfx::SizeF(contents_texture->size())); if (filter) { skia::RefPtr<SkColorFilter> cf; @@ -1260,7 +1202,7 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, SetShaderOpacity(quad->shared_quad_state->opacity, locations.alpha); SetShaderQuadF(surface_quad, locations.quad); DrawQuadGeometry(frame, quad->shared_quad_state->quad_to_target_transform, - quad->rect, locations.matrix); + gfx::RectF(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. @@ -1349,7 +1291,7 @@ static gfx::QuadF GetDeviceQuadWithAntialiasingOnExteriorEdges( const gfx::QuadF& tile_quad, const gfx::QuadF* clip_region, const DrawQuad* quad) { - gfx::RectF tile_rect = quad->visible_rect; + auto tile_rect = gfx::RectF(quad->visible_rect); gfx::PointF bottom_right = tile_quad.p3(); gfx::PointF bottom_left = tile_quad.p4(); @@ -1412,7 +1354,7 @@ float GetTotalQuadError(const gfx::QuadF* clipped_quad, // 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()); + auto 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) { @@ -1519,8 +1461,9 @@ void GLRenderer::SetupQuadForClippingAndAntialiasing( if (use_aa_on_all_four_edges) { device_quad = device_layer_edges.ToQuadF(); } else { - gfx::QuadF tile_quad(local_clip_region ? *local_clip_region - : gfx::QuadF(quad->visible_rect)); + gfx::QuadF tile_quad(local_clip_region + ? *local_clip_region + : gfx::QuadF(gfx::RectF(quad->visible_rect))); device_quad = GetDeviceQuadWithAntialiasingOnExteriorEdges( device_layer_edges, device_transform, tile_quad, local_clip_region, quad); @@ -1557,7 +1500,7 @@ void GLRenderer::SetupRenderPassQuadForClippingAndAntialiasing( // Apply anti-aliasing only to the edges that are not being clipped if (local_clip_region) { - gfx::QuadF tile_quad(quad->visible_rect); + gfx::QuadF tile_quad(gfx::RectF(quad->visible_rect)); GetScaledRegion(quad->rect, local_clip_region, &tile_quad); device_quad = GetDeviceQuadWithAntialiasingOnExteriorEdges( device_layer_edges, device_transform, tile_quad, local_clip_region, @@ -1590,7 +1533,7 @@ void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame, if (!device_transform.IsInvertible()) return; - gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); + auto local_quad = gfx::QuadF(gfx::RectF(tile_rect)); gfx::QuadF device_layer_quad; bool use_aa = false; @@ -1602,7 +1545,9 @@ void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame, bool force_aa = false; device_layer_quad = MathUtil::MapQuad( device_transform, - gfx::QuadF(quad->shared_quad_state->visible_quad_layer_rect), &clipped); + gfx::QuadF( + gfx::RectF(quad->shared_quad_state->visible_quad_layer_rect)), + &clipped); use_aa = ShouldAntialiasQuad(device_layer_quad, clipped, force_aa); } @@ -1653,7 +1598,7 @@ void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame, // quad_rect. gfx::RectF centered_rect( gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()), - tile_rect.size()); + gfx::SizeF(tile_rect.size())); DrawQuadGeometry(frame, quad->shared_quad_state->quad_to_target_transform, centered_rect, uniforms.matrix_location); } else { @@ -1720,7 +1665,9 @@ void GLRenderer::DrawContentQuad(const DrawingFrame* frame, bool force_aa = false; device_layer_quad = MathUtil::MapQuad( device_transform, - gfx::QuadF(quad->shared_quad_state->visible_quad_layer_rect), &clipped); + gfx::QuadF( + gfx::RectF(quad->shared_quad_state->visible_quad_layer_rect)), + &clipped); use_aa = ShouldAntialiasQuad(device_layer_quad, clipped, force_aa); } @@ -1746,7 +1693,7 @@ void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame, gfx::Rect tile_rect = quad->visible_rect; gfx::RectF tex_coord_rect = MathUtil::ScaleRectProportional( - quad->tex_coord_rect, quad->rect, tile_rect); + quad->tex_coord_rect, gfx::RectF(quad->rect), gfx::RectF(tile_rect)); float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width(); float tex_to_geom_scale_y = quad->rect.height() / quad->tex_coord_rect.height(); @@ -1782,7 +1729,7 @@ void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame, TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( gl_, &highp_threshold_cache_, highp_threshold_min_, quad->texture_size); - gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); + auto local_quad = gfx::QuadF(gfx::RectF(tile_rect)); float edge[24]; SetupQuadForClippingAndAntialiasing(device_transform, quad, &aa_quad, clip_region, &local_quad, edge); @@ -1850,7 +1797,7 @@ void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame, // it. This is why this centered rect is used and not the original quad_rect. gfx::RectF centered_rect( gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()), - tile_rect.size()); + gfx::SizeF(tile_rect.size())); DrawQuadGeometry(frame, quad->shared_quad_state->quad_to_target_transform, centered_rect, uniforms.matrix_location); } @@ -1860,7 +1807,8 @@ void GLRenderer::DrawContentQuadNoAA(const DrawingFrame* frame, ResourceId resource_id, const gfx::QuadF* clip_region) { gfx::RectF tex_coord_rect = MathUtil::ScaleRectProportional( - quad->tex_coord_rect, quad->rect, quad->visible_rect); + quad->tex_coord_rect, gfx::RectF(quad->rect), + gfx::RectF(quad->visible_rect)); float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width(); float tex_to_geom_scale_y = quad->rect.height() / quad->tex_coord_rect.height(); @@ -1930,37 +1878,32 @@ 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::QuadF tile_rect(quad->visible_rect); + gfx::QuadF tile_quad(gfx::RectF(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; + tile_quad = *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, + (tile_quad.p4().x() - top_left.x()) / width, + (tile_quad.p4().y() - top_left.y()) / height, + (tile_quad.p1().x() - top_left.x()) / width, + (tile_quad.p1().y() - top_left.y()) / height, + (tile_quad.p2().x() - top_left.x()) / width, + (tile_quad.p2().y() - top_left.y()) / height, + (tile_quad.p3().x() - top_left.x()) / width, + (tile_quad.p3().y() - top_left.y()) / height, }; PrepareGeometry(CLIPPED_BINDING); clipped_geometry_->InitializeCustomQuadWithUVs( - gfx::QuadF(quad->visible_rect), gl_uv); + gfx::QuadF(gfx::RectF(quad->visible_rect)), gl_uv); } else { PrepareGeometry(SHARED_BINDING); } float gl_quad[8] = { - 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(), + tile_quad.p4().x(), tile_quad.p4().y(), tile_quad.p1().x(), + tile_quad.p1().y(), tile_quad.p2().x(), tile_quad.p2().y(), + tile_quad.p3().x(), tile_quad.p3().y(), }; gl_->Uniform2fv(uniforms.quad_location, 4, gl_quad); @@ -2167,7 +2110,7 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame, // 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; + auto tile_rect = gfx::RectF(quad->rect); gl_->UniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb); gl_->Uniform3fv(yuv_adj_location, 1, yuv_adjust); @@ -2219,7 +2162,8 @@ void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame, program->fragment_shader().alpha_location()); if (!clip_region) { DrawQuadGeometry(frame, quad->shared_quad_state->quad_to_target_transform, - quad->rect, program->vertex_shader().matrix_location()); + gfx::RectF(quad->rect), + program->vertex_shader().matrix_location()); } else { gfx::QuadF region_quad(*clip_region); region_quad.Scale(1.0f / quad->rect.width(), 1.0f / quad->rect.height()); @@ -2227,8 +2171,9 @@ void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame, float uvs[8] = {0}; GetScaledUVs(quad->visible_rect, clip_region, uvs); DrawQuadGeometryClippedByQuadF( - frame, quad->shared_quad_state->quad_to_target_transform, quad->rect, - region_quad, program->vertex_shader().matrix_location(), uvs); + frame, quad->shared_quad_state->quad_to_target_transform, + gfx::RectF(quad->rect), region_quad, + program->vertex_shader().matrix_location(), uvs); } } @@ -2408,7 +2353,7 @@ void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame, gfx::Transform quad_rect_matrix; QuadRectTransform(&quad_rect_matrix, quad->shared_quad_state->quad_to_target_transform, - quad->rect); + gfx::RectF(quad->rect)); quad_rect_matrix = frame->projection_matrix * quad_rect_matrix; Float16 m; @@ -2474,13 +2419,13 @@ void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame, if (!clip_region) { DrawQuadGeometry(frame, quad->shared_quad_state->quad_to_target_transform, - quad->rect, binding.matrix_location); + gfx::RectF(quad->rect), binding.matrix_location); } else { float uvs[8] = {0}; GetScaledUVs(quad->visible_rect, clip_region, uvs); DrawQuadGeometryClippedByQuadF( - frame, quad->shared_quad_state->quad_to_target_transform, quad->rect, - *clip_region, binding.matrix_location, uvs); + frame, quad->shared_quad_state->quad_to_target_transform, + gfx::RectF(quad->rect), *clip_region, binding.matrix_location, uvs); } gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); @@ -2494,7 +2439,7 @@ void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) { } current_framebuffer_lock_ = nullptr; - swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame->root_damage_rect)); + swap_buffer_rect_.Union(frame->root_damage_rect); gl_->Disable(GL_BLEND); blend_shadow_ = false; @@ -2673,8 +2618,14 @@ void GLRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) { output_surface_->SwapBuffers(&compositor_frame); // Release previously used overlay resources and hold onto the pending ones - // until the next swap buffers. - in_use_overlay_resources_.clear(); + // until the next swap buffers. On some platforms, hold onto resources for + // an extra frame. + if (settings_->delay_releasing_overlay_resources) { + previous_swap_overlay_resources_.clear(); + previous_swap_overlay_resources_.swap(in_use_overlay_resources_); + } else { + in_use_overlay_resources_.clear(); + } in_use_overlay_resources_.swap(pending_overlay_resources_); swap_buffer_rect_ = gfx::Rect(); @@ -3027,17 +2978,6 @@ void GLRenderer::PrepareGeometry(BoundGeometry binding) { bound_geometry_ = binding; } -const GLRenderer::TileCheckerboardProgram* -GLRenderer::GetTileCheckerboardProgram() { - if (!tile_checkerboard_program_.initialized()) { - TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize"); - tile_checkerboard_program_.Initialize(output_surface_->context_provider(), - TEX_COORD_PRECISION_NA, - SAMPLER_TYPE_NA); - } - return &tile_checkerboard_program_; -} - const GLRenderer::DebugBorderProgram* GLRenderer::GetDebugBorderProgram() { if (!debug_border_program_.initialized()) { TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize"); @@ -3499,8 +3439,6 @@ void GLRenderer::CleanupSharedObjects() { video_stream_texture_program_[i].Cleanup(gl_); } - tile_checkerboard_program_.Cleanup(gl_); - debug_border_program_.Cleanup(gl_); solid_color_program_.Cleanup(gl_); solid_color_program_aa_.Cleanup(gl_); @@ -3577,20 +3515,20 @@ void GLRenderer::ScheduleOverlays(DrawingFrame* frame) { ResourceProvider::ResourceIdArray resources; OverlayCandidateList& overlays = frame->overlay_list; for (const OverlayCandidate& overlay : overlays) { - // Skip primary plane. - if (overlay.plane_z_order == 0) - continue; - - pending_overlay_resources_.push_back( - make_scoped_ptr(new ResourceProvider::ScopedReadLockGL( - resource_provider_, overlay.resource_id))); + unsigned texture_id = 0; + if (overlay.use_output_surface_for_resource) { + texture_id = output_surface_->GetOverlayTextureId(); + DCHECK(texture_id); + } else { + pending_overlay_resources_.push_back( + make_scoped_ptr(new ResourceProvider::ScopedReadLockGL( + resource_provider_, overlay.resource_id))); + texture_id = pending_overlay_resources_.back()->texture_id(); + } context_support_->ScheduleOverlayPlane( - overlay.plane_z_order, - overlay.transform, - pending_overlay_resources_.back()->texture_id(), - ToNearestRect(overlay.display_rect), - overlay.uv_rect); + overlay.plane_z_order, overlay.transform, texture_id, + ToNearestRect(overlay.display_rect), overlay.uv_rect); } } diff --git a/chromium/cc/output/gl_renderer.h b/chromium/cc/output/gl_renderer.h index d80e1561502..a090324b820 100644 --- a/chromium/cc/output/gl_renderer.h +++ b/chromium/cc/output/gl_renderer.h @@ -13,7 +13,6 @@ #include "cc/output/gl_renderer_draw_cache.h" #include "cc/output/program_binding.h" #include "cc/output/renderer.h" -#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/render_pass_draw_quad.h" @@ -63,7 +62,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer { // Waits for rendering to finish. void Finish() override; - void DoNoOp() override; void SwapBuffers(const CompositorFrameMetadata& metadata) override; virtual bool IsContextLost(); @@ -154,9 +152,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer { void ClearFramebuffer(DrawingFrame* frame); void SetViewport(); - void DrawCheckerboardQuad(const DrawingFrame* frame, - const CheckerboardDrawQuad* quad, - const gfx::QuadF* clip_region); void DrawDebugBorderQuad(const DrawingFrame* frame, const DebugBorderDrawQuad* quad); static bool IsDefaultBlendMode(SkXfermode::Mode blend_mode) { @@ -174,8 +169,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer { bool use_aa); scoped_ptr<ScopedResource> GetBackdropTexture(const gfx::Rect& bounding_rect); - static bool ShouldApplyBackgroundFilters(DrawingFrame* frame, - const RenderPassDrawQuad* quad); + static bool ShouldApplyBackgroundFilters(const RenderPassDrawQuad* quad); skia::RefPtr<SkImage> ApplyBackgroundFilters( DrawingFrame* frame, const RenderPassDrawQuad* quad, @@ -268,6 +262,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer { OverlayResourceLockList; OverlayResourceLockList pending_overlay_resources_; OverlayResourceLockList in_use_overlay_resources_; + OverlayResourceLockList previous_swap_overlay_resources_; RendererCapabilitiesImpl capabilities_; @@ -294,8 +289,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer { TileProgramSwizzle; typedef ProgramBinding<VertexShaderTile, FragmentShaderRGBATexSwizzleOpaque> TileProgramSwizzleOpaque; - typedef ProgramBinding<VertexShaderPosTex, FragmentShaderCheckerboard> - TileCheckerboardProgram; // Texture shaders. typedef ProgramBinding<VertexShaderPosTexTransform, @@ -362,8 +355,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer { const TileProgramSwizzleAA* GetTileProgramSwizzleAA( TexCoordPrecision precision, SamplerType sampler); - const TileCheckerboardProgram* GetTileCheckerboardProgram(); - const RenderPassProgram* GetRenderPassProgram(TexCoordPrecision precision, BlendMode blend_mode); const RenderPassProgramAA* GetRenderPassProgramAA(TexCoordPrecision precision, @@ -434,8 +425,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer { TileProgramSwizzleAA tile_program_swizzle_aa_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1]; - TileCheckerboardProgram tile_checkerboard_program_; - TextureProgram texture_program_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1]; NonPremultipliedTextureProgram diff --git a/chromium/cc/output/gl_renderer_unittest.cc b/chromium/cc/output/gl_renderer_unittest.cc index 4b133c930a5..dd025f2383a 100644 --- a/chromium/cc/output/gl_renderer_unittest.cc +++ b/chromium/cc/output/gl_renderer_unittest.cc @@ -14,6 +14,7 @@ #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/overlay_strategy_underlay.h" #include "cc/output/texture_mailbox_deleter.h" #include "cc/quads/texture_draw_quad.h" #include "cc/resources/resource_provider.h" @@ -24,7 +25,6 @@ #include "cc/test/fake_renderer_client.h" #include "cc/test/fake_resource_provider.h" #include "cc/test/pixel_test.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_web_graphics_context_3d.h" @@ -117,7 +117,6 @@ class GLRendererShaderPixelTest : public GLRendererPixelTest { } void TestBasicShaders() { - EXPECT_PROGRAM_VALID(renderer()->GetTileCheckerboardProgram()); EXPECT_PROGRAM_VALID(renderer()->GetDebugBorderProgram()); EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgram()); EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgramAA()); @@ -546,10 +545,9 @@ TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) { output_surface_->set_has_external_stencil_test(true); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - RenderPassId(1, 0), - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, RenderPassId(1, 0), + viewport_rect, gfx::Transform()); root_pass->has_transparent_background = false; renderer_->DrawFrame(&render_passes_in_draw_order_, @@ -743,10 +741,9 @@ TEST_F(GLRendererTest, OpaqueBackground) { resource_provider.get()); gfx::Rect viewport_rect(1, 1); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - RenderPassId(1, 0), - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, RenderPassId(1, 0), + viewport_rect, gfx::Transform()); root_pass->has_transparent_background = false; // On DEBUG builds, render passes with opaque background clear to blue to @@ -789,10 +786,9 @@ TEST_F(GLRendererTest, TransparentBackground) { resource_provider.get()); gfx::Rect viewport_rect(1, 1); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - RenderPassId(1, 0), - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, RenderPassId(1, 0), + viewport_rect, gfx::Transform()); root_pass->has_transparent_background = true; EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1); @@ -974,11 +970,12 @@ TEST_F(GLRendererTest, ActiveTextureState) { // During initialization we are allowed to set any texture parameters. EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber()); - TestRenderPass* root_pass = + RenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, RenderPassId(1, 1), gfx::Rect(100, 100), gfx::Transform()); - root_pass->AppendOneOfEveryQuadType(resource_provider.get(), - RenderPassId(0, 0)); + uint32_t mailbox_sync_point; + AddOneOfEveryQuadType(root_pass, resource_provider.get(), RenderPassId(0, 0), + &mailbox_sync_point); renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); @@ -990,9 +987,7 @@ TEST_F(GLRendererTest, ActiveTextureState) { // The sync points for all quads are waited on first. This sync point is // for a texture quad drawn later in the frame. - EXPECT_CALL(*context, - waitSyncPoint(TestRenderPass::kSyncPointForMailboxTextureQuad)) - .Times(1); + EXPECT_CALL(*context, waitSyncPoint(mailbox_sync_point)).Times(1); // yuv_quad is drawn with the default linear filter. EXPECT_CALL(*context, drawElements(_, _, _, _)); @@ -1015,7 +1010,7 @@ TEST_F(GLRendererTest, ActiveTextureState) { // The remaining quads also use GL_LINEAR because nearest neighbor // filtering is currently only used with tile quads. - EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(7); + EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(6); } gfx::Rect viewport_rect(100, 100); @@ -1061,16 +1056,15 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) { gfx::Rect viewport_rect(10, 10); RenderPassId child_pass_id(2, 0); - TestRenderPass* child_pass = + RenderPass* 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, - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, root_pass_id, viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); @@ -1153,26 +1147,22 @@ TEST_F(GLRendererTest, ScissorTestWhenClearing) { gfx::Rect grand_child_rect(25, 25); RenderPassId grand_child_pass_id(3, 0); - TestRenderPass* grand_child_pass = - AddRenderPass(&render_passes_in_draw_order_, - grand_child_pass_id, - grand_child_rect, - gfx::Transform()); + RenderPass* grand_child_pass = + AddRenderPass(&render_passes_in_draw_order_, grand_child_pass_id, + grand_child_rect, gfx::Transform()); AddClippedQuad(grand_child_pass, grand_child_rect, SK_ColorYELLOW); gfx::Rect child_rect(50, 50); RenderPassId child_pass_id(2, 0); - TestRenderPass* child_pass = AddRenderPass(&render_passes_in_draw_order_, - child_pass_id, - child_rect, - gfx::Transform()); + RenderPass* child_pass = + AddRenderPass(&render_passes_in_draw_order_, child_pass_id, child_rect, + gfx::Transform()); AddQuad(child_pass, child_rect, SK_ColorBLUE); RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - root_pass_id, - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, root_pass_id, viewport_rect, + gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); AddRenderPassQuad(root_pass, child_pass); @@ -1248,10 +1238,9 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) { { // Partial frame, should not discard. RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - root_pass_id, - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, root_pass_id, + viewport_rect, gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = gfx::Rect(2, 2, 3, 3); @@ -1267,10 +1256,9 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) { { // Full frame, should discard. RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - root_pass_id, - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, root_pass_id, + viewport_rect, gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = root_pass->output_rect; @@ -1287,10 +1275,9 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) { // Full frame, external scissor is set, should not discard. output_surface->set_has_external_stencil_test(true); RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - root_pass_id, - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, root_pass_id, + viewport_rect, gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = root_pass->output_rect; root_pass->has_transparent_background = false; @@ -1309,10 +1296,9 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) { // Full frame, clipped, should not discard. clip_rect = gfx::Rect(10, 10, 10, 10); RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - root_pass_id, - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, root_pass_id, + viewport_rect, gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = root_pass->output_rect; @@ -1329,10 +1315,9 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) { // Full frame, doesn't cover the surface, should not discard. viewport_rect = gfx::Rect(10, 10, 10, 10); RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - root_pass_id, - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, root_pass_id, + viewport_rect, gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = root_pass->output_rect; @@ -1350,10 +1335,9 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) { clip_rect = gfx::Rect(100, 100); viewport_rect = gfx::Rect(50, 50); RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, - root_pass_id, - viewport_rect, - gfx::Transform()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, root_pass_id, + viewport_rect, gfx::Transform()); AddQuad(root_pass, viewport_rect, SK_ColorGREEN); root_pass->damage_rect = root_pass->output_rect; @@ -1411,10 +1395,9 @@ TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) { 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()); + RenderPass* root_pass = + AddRenderPass(&render_passes_in_draw_order_, root_pass_id, viewport_rect, + gfx::Transform()); AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN); renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); @@ -1452,7 +1435,7 @@ TEST_F(GLRendererTest, DrawFramePreservesFramebuffer) { gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20); RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass = + RenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, root_pass_id, viewport_rect, gfx::Transform()); AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN); @@ -1477,10 +1460,10 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) { gfx::Rect child_rect(50, 50); RenderPassId child_pass_id(2, 0); - TestRenderPass* child_pass; + RenderPass* child_pass; RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass; + RenderPass* root_pass; ResourceId mask = resource_provider_->CreateResource( gfx::Size(20, 12), GL_CLAMP_TO_EDGE, @@ -1744,11 +1727,11 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) { TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) { gfx::Rect child_rect(50, 50); RenderPassId child_pass_id(2, 0); - TestRenderPass* child_pass; + RenderPass* child_pass; gfx::Rect viewport_rect(1, 1); RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass; + RenderPass* root_pass; gfx::Transform transform_preventing_aa; transform_preventing_aa.ApplyPerspectiveDepth(40.0); @@ -1758,7 +1741,8 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) { // Verify that the test transform and test rect actually do cause the clipped // flag to trigger. Otherwise we are not testing the intended scenario. bool clipped = false; - MathUtil::MapQuad(transform_preventing_aa, gfx::QuadF(child_rect), &clipped); + MathUtil::MapQuad(transform_preventing_aa, gfx::QuadF(gfx::RectF(child_rect)), + &clipped); ASSERT_TRUE(clipped); child_pass = AddRenderPass(&render_passes_in_draw_order_, @@ -1793,7 +1777,7 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) { TEST_F(GLRendererShaderTest, DrawSolidColorShader) { gfx::Rect viewport_rect(1, 1); RenderPassId root_pass_id(1, 0); - TestRenderPass* root_pass; + RenderPass* root_pass; gfx::Transform pixel_aligned_transform_causing_aa; pixel_aligned_transform_causing_aa.Translate(25.5f, 25.5f); @@ -1871,10 +1855,9 @@ class MockOutputSurfaceTest : public GLRendererTest { void DrawFrame(float device_scale_factor, const gfx::Rect& device_viewport_rect) { RenderPassId render_pass_id(1, 0); - TestRenderPass* render_pass = AddRenderPass(&render_passes_in_draw_order_, - render_pass_id, - device_viewport_rect, - gfx::Transform()); + RenderPass* render_pass = + AddRenderPass(&render_passes_in_draw_order_, render_pass_id, + device_viewport_rect, gfx::Transform()); AddQuad(render_pass, device_viewport_rect, SK_ColorGREEN); EXPECT_CALL(output_surface_, EnsureBackbuffer()).WillRepeatedly(Return()); @@ -2024,9 +2007,10 @@ class TestOverlayProcessor : public OverlayProcessor { public: Strategy() {} ~Strategy() override {} - MOCK_METHOD2(Attempt, + MOCK_METHOD3(Attempt, bool(RenderPassList* render_passes_in_draw_order, - OverlayCandidateList* candidates)); + OverlayCandidateList* candidates, + float device_scale_factor)); }; explicit TestOverlayProcessor(OutputSurface* surface) @@ -2073,7 +2057,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) { renderer.SetOverlayProcessor(processor); gfx::Rect viewport_rect(1, 1); - TestRenderPass* root_pass = + RenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_, RenderPassId(1, 0), viewport_rect, gfx::Transform()); root_pass->has_transparent_background = false; @@ -2106,7 +2090,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) { // 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); + 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_); @@ -2123,7 +2107,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) { gfx::PointF(1, 1), SK_ColorTRANSPARENT, vertex_opacity, flipped, nearest_neighbor); - EXPECT_CALL(*processor->strategy_, Attempt(_, _)).Times(1); + EXPECT_CALL(*processor->strategy_, Attempt(_, _, _)).Times(1); renderer.DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_rect, viewport_rect, false); } @@ -2132,8 +2116,15 @@ class SingleOverlayOnTopProcessor : public OverlayProcessor { public: class SingleOverlayValidator : public OverlayCandidateValidator { public: + void GetStrategies(OverlayProcessor::StrategyList* strategies) override { + strategies->push_back(scoped_ptr<OverlayProcessor::Strategy>( + new OverlayStrategyCommon(this, new OverlayStrategySingleOnTop))); + strategies->push_back(scoped_ptr<OverlayProcessor::Strategy>( + new OverlayStrategyCommon(this, new OverlayStrategyUnderlay))); + } + void CheckOverlaySupport(OverlayCandidateList* surfaces) override { - ASSERT_EQ(2U, surfaces->size()); + ASSERT_EQ(1U, surfaces->size()); OverlayCandidate& candidate = surfaces->back(); candidate.overlay_handled = true; } @@ -2143,8 +2134,8 @@ class SingleOverlayOnTopProcessor : public OverlayProcessor { : OverlayProcessor(surface) {} void Initialize() override { - strategies_.push_back( - scoped_ptr<Strategy>(new OverlayStrategySingleOnTop(&validator_))); + strategies_.push_back(scoped_ptr<Strategy>(new OverlayStrategyCommon( + &validator_, new OverlayStrategySingleOnTop))); } SingleOverlayValidator validator_; @@ -2199,12 +2190,12 @@ TEST_F(GLRendererTest, OverlaySyncPointsAreProcessed) { renderer.SetOverlayProcessor(processor); gfx::Rect viewport_rect(1, 1); - TestRenderPass* root_pass = + RenderPass* 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; + unsigned sync_point = 29; TextureMailbox mailbox = TextureMailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point); scoped_ptr<SingleReleaseCallbackImpl> release_callback = @@ -2231,9 +2222,7 @@ TEST_F(GLRendererTest, OverlaySyncPointsAreProcessed) { // 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(*context, waitSyncPoint(sync_point)).Times(1); EXPECT_CALL(overlay_scheduler, Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, viewport_rect, BoundingRect(uv_top_left, uv_bottom_right))).Times(1); diff --git a/chromium/cc/output/latency_info_swap_promise.cc b/chromium/cc/output/latency_info_swap_promise.cc index 5e08470fb07..3b267454076 100644 --- a/chromium/cc/output/latency_info_swap_promise.cc +++ b/chromium/cc/output/latency_info_swap_promise.cc @@ -34,7 +34,7 @@ LatencyInfoSwapPromise::~LatencyInfoSwapPromise() { } void LatencyInfoSwapPromise::DidSwap(CompositorFrameMetadata* metadata) { - DCHECK(!latency_.terminated); + DCHECK(!latency_.terminated()); metadata->latency_info.push_back(latency_); } @@ -47,14 +47,16 @@ void LatencyInfoSwapPromise::DidNotSwap(DidNotSwapReason reason) { } int64 LatencyInfoSwapPromise::TraceId() const { - return latency_.trace_id; + return latency_.trace_id(); } // Trace the original LatencyInfo of a LatencyInfoSwapPromise void LatencyInfoSwapPromise::OnCommit() { - TRACE_EVENT_FLOW_STEP0("input,benchmark", "LatencyInfo.Flow", + TRACE_EVENT_WITH_FLOW1("input,benchmark", + "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(TraceId()), - "HanldeInputEventMainCommit"); + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "step", "HandleInputEventMainCommit"); } } // namespace cc diff --git a/chromium/cc/output/output_surface.cc b/chromium/cc/output/output_surface.cc index a597a87d845..38b13463c1b 100644 --- a/chromium/cc/output/output_surface.cc +++ b/chromium/cc/output/output_surface.cc @@ -14,13 +14,107 @@ #include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" +#include "third_party/skia/include/core/SkTraceMemoryDump.h" #include "third_party/skia/include/gpu/GrContext.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" +#include "ui/gl/trace_util.h" +class SkDiscardableMemory; namespace cc { +namespace { + +// Constants used by SkiaGpuTraceMemoryDump to identify different memory types. +const char* kGLTextureBackingType = "gl_texture"; +const char* kGLBufferBackingType = "gl_buffer"; +const char* kGLRenderbufferBackingType = "gl_renderbuffer"; + +// Derives from SkTraceMemoryDump and implements graphics specific memory +// backing functionality. +class SkiaGpuTraceMemoryDump : public SkTraceMemoryDump { + public: + // This should never outlive the provided ProcessMemoryDump, as it should + // always be scoped to a single OnMemoryDump funciton call. + explicit SkiaGpuTraceMemoryDump(base::trace_event::ProcessMemoryDump* pmd, + uint64_t share_group_tracing_guid) + : pmd_(pmd), share_group_tracing_guid_(share_group_tracing_guid) {} + + // Overridden from SkTraceMemoryDump: + void dumpNumericValue(const char* dump_name, + const char* value_name, + const char* units, + uint64_t value) override { + auto dump = GetOrCreateAllocatorDump(dump_name); + dump->AddScalar(value_name, units, value); + } + + void setMemoryBacking(const char* dump_name, + const char* backing_type, + const char* backing_object_id) override { + const uint64 tracing_process_id = + base::trace_event::MemoryDumpManager::GetInstance() + ->GetTracingProcessId(); + + // For uniformity, skia provides this value as a string. Convert back to a + // uint32_t. + uint32_t gl_id = + std::strtoul(backing_object_id, nullptr /* str_end */, 10 /* base */); + + // Populated in if statements below. + base::trace_event::MemoryAllocatorDumpGuid guid; + + if (strcmp(backing_type, kGLTextureBackingType) == 0) { + guid = gfx::GetGLTextureClientGUIDForTracing(share_group_tracing_guid_, + gl_id); + } else if (strcmp(backing_type, kGLBufferBackingType) == 0) { + guid = gfx::GetGLBufferGUIDForTracing(tracing_process_id, gl_id); + } else if (strcmp(backing_type, kGLRenderbufferBackingType) == 0) { + guid = gfx::GetGLRenderbufferGUIDForTracing(tracing_process_id, gl_id); + } + + if (!guid.empty()) { + pmd_->CreateSharedGlobalAllocatorDump(guid); + + auto* dump = GetOrCreateAllocatorDump(dump_name); + + const int kImportance = 2; + pmd_->AddOwnershipEdge(dump->guid(), guid, kImportance); + } + } + + void setDiscardableMemoryBacking( + const char* dump_name, + const SkDiscardableMemory& discardable_memory_object) override { + // We don't use this class for dumping discardable memory. + NOTREACHED(); + } + + LevelOfDetail getRequestedDetails() const override { + // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested + // (crbug.com/499731). + return kObjectsBreakdowns_LevelOfDetail; + } + + private: + // Helper to create allocator dumps. + base::trace_event::MemoryAllocatorDump* GetOrCreateAllocatorDump( + const char* dump_name) { + auto dump = pmd_->GetAllocatorDump(dump_name); + if (!dump) + dump = pmd_->CreateAllocatorDump(dump_name); + return dump; + } + + base::trace_event::ProcessMemoryDump* pmd_; + uint64_t share_group_tracing_guid_; + + DISALLOW_COPY_AND_ASSIGN(SkiaGpuTraceMemoryDump); +}; + +} // namespace + OutputSurface::OutputSurface( const scoped_refptr<ContextProvider>& context_provider, const scoped_refptr<ContextProvider>& worker_context_provider, @@ -32,6 +126,7 @@ OutputSurface::OutputSurface( device_scale_factor_(-1), external_stencil_test_enabled_(false), weak_ptr_factory_(this) { + client_thread_checker_.DetachFromThread(); } OutputSurface::OutputSurface( @@ -101,16 +196,8 @@ void OutputSurface::SetExternalDrawConstraints( } OutputSurface::~OutputSurface() { - 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()); - } + if (client_) + DetachFromClientInternal(); } bool OutputSurface::HasExternalStencilTest() const { @@ -118,7 +205,9 @@ bool OutputSurface::HasExternalStencilTest() const { } bool OutputSurface::BindToClient(OutputSurfaceClient* client) { + DCHECK(client_thread_checker_.CalledOnValidThread()); DCHECK(client); + DCHECK(!client_); client_ = client; bool success = true; @@ -132,24 +221,27 @@ bool OutputSurface::BindToClient(OutputSurfaceClient* client) { } } - 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) client_ = NULL; + // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview). + // Don't register a dump provider in these cases. + // TODO(ericrk): Get this working in Android Webview. crbug.com/517156 + if (client_ && base::ThreadTaskRunnerHandle::IsSet()) { + // Now that we are on the context thread, register a dump provider with this + // thread's task runner. This will overwrite any previous dump provider + // registered. + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( + this, base::ThreadTaskRunnerHandle::Get()); + } + return success; } +void OutputSurface::DetachFromClient() { + DetachFromClientInternal(); +} + void OutputSurface::EnsureBackbuffer() { if (software_device_) software_device_->EnsureBackbuffer(); @@ -176,10 +268,6 @@ void OutputSurface::Reshape(const gfx::Size& size, float scale_factor) { software_device_->Resize(size, scale_factor); } -gfx::Size OutputSurface::SurfaceSize() const { - return surface_size_; -} - void OutputSurface::BindFramebuffer() { DCHECK(context_provider_.get()); context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0); @@ -211,17 +299,21 @@ OverlayCandidateValidator* OutputSurface::GetOverlayCandidateValidator() const { return nullptr; } +bool OutputSurface::IsDisplayedAsOverlayPlane() const { + return false; +} + +unsigned OutputSurface::GetOverlayTextureId() const { + return 0; +} + void OutputSurface::SetWorkerContextShouldAggressivelyFreeResources( bool aggressively_free_resources) { TRACE_EVENT1("cc", "OutputSurface::SetWorkerContextShouldAggressivelyFreeResources", "aggressively_free_resources", aggressively_free_resources); if (auto* context_provider = worker_context_provider()) { - // The context lock must be held while accessing the worker context. - base::AutoLock context_lock(*context_provider->GetLock()); - - // Allow context to bind to current thread. - context_provider->DetachFromThread(); + ContextProvider::ScopedContextLock scoped_context(context_provider); if (aggressively_free_resources) { context_provider->DeleteCachedResources(); @@ -231,9 +323,6 @@ void OutputSurface::SetWorkerContextShouldAggressivelyFreeResources( context_support->SetAggressivelyFreeResources( aggressively_free_resources); } - - // Allow context to bind to other threads. - context_provider->DetachFromThread(); } } @@ -241,4 +330,47 @@ bool OutputSurface::SurfaceIsSuspendForRecycle() const { return false; } +bool OutputSurface::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + if (auto* context_provider = this->context_provider()) { + // No need to lock, main context provider is not shared. + if (auto* gr_context = context_provider->GrContext()) { + SkiaGpuTraceMemoryDump trace_memory_dump( + pmd, context_provider->ContextSupport()->ShareGroupTracingGUID()); + gr_context->dumpMemoryStatistics(&trace_memory_dump); + } + } + if (auto* context_provider = worker_context_provider()) { + ContextProvider::ScopedContextLock scoped_context(context_provider); + + if (auto* gr_context = context_provider->GrContext()) { + SkiaGpuTraceMemoryDump trace_memory_dump( + pmd, context_provider->ContextSupport()->ShareGroupTracingGUID()); + gr_context->dumpMemoryStatistics(&trace_memory_dump); + } + } + + return true; +} + +void OutputSurface::DetachFromClientInternal() { + DCHECK(client_thread_checker_.CalledOnValidThread()); + DCHECK(client_); + + // Unregister any dump provider. Safe to call (no-op) if we have not yet + // registered. + base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( + this); + + if (context_provider_.get()) { + context_provider_->SetLostContextCallback( + ContextProvider::LostContextCallback()); + context_provider_->SetMemoryPolicyChangedCallback( + ContextProvider::MemoryPolicyChangedCallback()); + } + context_provider_ = nullptr; + client_ = nullptr; + weak_ptr_factory_.InvalidateWeakPtrs(); +} + } // namespace cc diff --git a/chromium/cc/output/output_surface.h b/chromium/cc/output/output_surface.h index 423dc6317c3..bb6a59e7ecd 100644 --- a/chromium/cc/output/output_surface.h +++ b/chromium/cc/output/output_surface.h @@ -11,6 +11,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/threading/thread_checker.h" #include "cc/base/cc_export.h" #include "cc/output/context_provider.h" #include "cc/output/overlay_candidate_validator.h" @@ -18,7 +19,9 @@ namespace base { class SingleThreadTaskRunner; } -namespace ui { struct LatencyInfo; } +namespace ui { +class LatencyInfo; +} namespace gfx { class Rect; @@ -40,7 +43,7 @@ class OutputSurfaceClient; // From here on, it will only be used on the compositor thread. // 3. If the 3D context is lost, then the compositor will delete the output // surface (on the compositor thread) and go back to step 1. -class CC_EXPORT OutputSurface { +class CC_EXPORT OutputSurface : public base::trace_event::MemoryDumpProvider { public: enum { DEFAULT_MAX_FRAMES_PENDING = 2 @@ -59,7 +62,7 @@ class CC_EXPORT OutputSurface { OutputSurface(const scoped_refptr<ContextProvider>& context_provider, scoped_ptr<SoftwareOutputDevice> software_device); - virtual ~OutputSurface(); + ~OutputSurface() override; struct Capabilities { Capabilities() @@ -110,15 +113,20 @@ class CC_EXPORT OutputSurface { // Called by the compositor on the compositor thread. This is a place where // thread-specific data for the output surface can be initialized, since from - // this point on the output surface will only be used on the compositor - // thread. + // this point to when DetachFromClient() is called the output surface will + // only be used on the compositor thread. virtual bool BindToClient(OutputSurfaceClient* client); + // Called by the compositor on the compositor thread. This is a place where + // thread-specific data for the output surface can be uninitialized. + virtual void DetachFromClient(); + virtual void EnsureBackbuffer(); virtual void DiscardBackbuffer(); virtual void Reshape(const gfx::Size& size, float scale_factor); - virtual gfx::Size SurfaceSize() const; + gfx::Size SurfaceSize() const { return surface_size_; } + float device_scale_factor() const { return device_scale_factor_; } // If supported, this causes a ReclaimResources for all resources that are // currently in use. @@ -143,6 +151,12 @@ class CC_EXPORT OutputSurface { // Get the class capable of informing cc of hardware overlay capability. virtual OverlayCandidateValidator* GetOverlayCandidateValidator() const; + // Returns true if a main image overlay plane should be scheduled. + virtual bool IsDisplayedAsOverlayPlane() const; + + // Get the texture for the main image's overlay. + virtual unsigned GetOverlayTextureId() const; + void DidLoseOutputSurface(); void SetMemoryPolicy(const ManagedMemoryPolicy& policy); @@ -159,6 +173,10 @@ class CC_EXPORT OutputSurface { // If this returns true, then the surface will not attempt to draw. virtual bool SurfaceIsSuspendForRecycle() const; + // base::trace_event::MemoryDumpProvider implementation. + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) override; + protected: OutputSurfaceClient* client_; @@ -170,6 +188,7 @@ class CC_EXPORT OutputSurface { scoped_ptr<SoftwareOutputDevice> software_device_; gfx::Size surface_size_; float device_scale_factor_; + base::ThreadChecker client_thread_checker_; void CommitVSyncParameters(base::TimeTicks timebase, base::TimeDelta interval); @@ -184,6 +203,7 @@ class CC_EXPORT OutputSurface { const gfx::Rect& viewport_rect_for_tile_priority, const gfx::Transform& transform_for_tile_priority, bool resourceless_software_draw); + void DetachFromClientInternal(); private: bool external_stencil_test_enabled_; diff --git a/chromium/cc/output/overlay_candidate.cc b/chromium/cc/output/overlay_candidate.cc index 7a825707d1d..5ecdc32ed36 100644 --- a/chromium/cc/output/overlay_candidate.cc +++ b/chromium/cc/output/overlay_candidate.cc @@ -8,6 +8,10 @@ #include <limits> #include "base/logging.h" #include "cc/base/math_util.h" +#include "cc/quads/io_surface_draw_quad.h" +#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/rect_conversions.h" #include "ui/gfx/geometry/vector3d_f.h" @@ -32,22 +36,8 @@ Axis VectorToAxis(const gfx::Vector3dF& vec) { return NONE; } -} // namespace - -OverlayCandidate::OverlayCandidate() - : transform(gfx::OVERLAY_TRANSFORM_NONE), - format(RGBA_8888), - uv_rect(0.f, 0.f, 1.f, 1.f), - resource_id(0), - plane_z_order(0), - overlay_handled(false) {} - -OverlayCandidate::~OverlayCandidate() {} - -// static -gfx::OverlayTransform OverlayCandidate::GetOverlayTransform( - const gfx::Transform& quad_transform, - bool y_flipped) { +gfx::OverlayTransform GetOverlayTransform(const gfx::Transform& quad_transform, + bool y_flipped) { if (!quad_transform.Preserves2dAxisAlignment()) { return gfx::OVERLAY_TRANSFORM_INVALID; } @@ -77,10 +67,10 @@ gfx::OverlayTransform OverlayCandidate::GetOverlayTransform( return gfx::OVERLAY_TRANSFORM_INVALID; } -// static -gfx::OverlayTransform OverlayCandidate::ModifyTransform( - gfx::OverlayTransform in, - gfx::OverlayTransform delta) { +// Apply transform |delta| to |in| and return the resulting transform, +// or OVERLAY_TRANSFORM_INVALID. +gfx::OverlayTransform ComposeTransforms(gfx::OverlayTransform delta, + gfx::OverlayTransform in) { // 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). @@ -173,15 +163,130 @@ gfx::OverlayTransform OverlayCandidate::ModifyTransform( } } +} // namespace + +OverlayCandidate::OverlayCandidate() + : transform(gfx::OVERLAY_TRANSFORM_NONE), + format(RGBA_8888), + uv_rect(0.f, 0.f, 1.f, 1.f), + is_clipped(false), + use_output_surface_for_resource(false), + resource_id(0), + plane_z_order(0), + overlay_handled(false) {} + +OverlayCandidate::~OverlayCandidate() {} + +// static +bool OverlayCandidate::FromDrawQuad(const DrawQuad* quad, + OverlayCandidate* candidate) { + if (quad->needs_blending || quad->shared_quad_state->opacity != 1.f || + quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode) + return false; + + auto& transform = quad->shared_quad_state->quad_to_target_transform; + candidate->display_rect = gfx::RectF(quad->rect); + transform.TransformRect(&candidate->display_rect); + candidate->quad_rect_in_target_space = + MathUtil::MapEnclosingClippedRect(transform, quad->rect); + + candidate->format = RGBA_8888; + candidate->clip_rect = quad->shared_quad_state->clip_rect; + candidate->is_clipped = quad->shared_quad_state->is_clipped; + + switch (quad->material) { + case DrawQuad::TEXTURE_CONTENT: + return FromTextureQuad(TextureDrawQuad::MaterialCast(quad), candidate); + case DrawQuad::STREAM_VIDEO_CONTENT: + return FromStreamVideoQuad(StreamVideoDrawQuad::MaterialCast(quad), + candidate); + case DrawQuad::IO_SURFACE_CONTENT: + return FromIOSurfaceQuad(IOSurfaceDrawQuad::MaterialCast(quad), + candidate); + default: + break; + } + + return false; +} + +// static +bool OverlayCandidate::FromTextureQuad(const TextureDrawQuad* quad, + OverlayCandidate* candidate) { + if (!quad->allow_overlay()) + return false; + gfx::OverlayTransform overlay_transform = GetOverlayTransform( + quad->shared_quad_state->quad_to_target_transform, quad->y_flipped); + if (quad->background_color != SK_ColorTRANSPARENT || + quad->premultiplied_alpha || + overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID) + return false; + candidate->resource_id = quad->resource_id(); + candidate->resource_size_in_pixels = quad->resource_size_in_pixels(); + candidate->transform = overlay_transform; + candidate->uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right); + return true; +} + +// static +bool OverlayCandidate::FromStreamVideoQuad(const StreamVideoDrawQuad* quad, + OverlayCandidate* candidate) { + if (!quad->allow_overlay()) + return false; + gfx::OverlayTransform overlay_transform = GetOverlayTransform( + quad->shared_quad_state->quad_to_target_transform, 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; + } + candidate->resource_id = quad->resource_id(); + candidate->resource_size_in_pixels = quad->resource_size_in_pixels(); + candidate->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) { + candidate->transform = ComposeTransforms( + gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL, candidate->transform); + 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. + candidate->uv_rect = gfx::RectF(uv0.x(), uv1.y(), delta.x(), -delta.y()); + } else { + candidate->transform = ComposeTransforms( + gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL, candidate->transform); + candidate->uv_rect = gfx::RectF(uv0.x(), uv0.y(), delta.x(), delta.y()); + } + return true; +} + // static -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 float_rect; +bool OverlayCandidate::FromIOSurfaceQuad(const IOSurfaceDrawQuad* quad, + OverlayCandidate* candidate) { + if (!quad->allow_overlay) + return false; + gfx::OverlayTransform overlay_transform = GetOverlayTransform( + quad->shared_quad_state->quad_to_target_transform, false); + if (overlay_transform != gfx::OVERLAY_TRANSFORM_NONE) + return false; + candidate->resource_id = quad->io_surface_resource_id(); + candidate->resource_size_in_pixels = quad->io_surface_size; + candidate->transform = overlay_transform; + candidate->uv_rect = gfx::RectF(1.f, 1.f); + return true; } } // namespace cc diff --git a/chromium/cc/output/overlay_candidate.h b/chromium/cc/output/overlay_candidate.h index b3e7fb359f1..f54a7ddf113 100644 --- a/chromium/cc/output/overlay_candidate.h +++ b/chromium/cc/output/overlay_candidate.h @@ -10,23 +10,27 @@ #include "cc/base/cc_export.h" #include "cc/resources/resource_format.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/geometry/size.h" #include "ui/gfx/overlay_transform.h" #include "ui/gfx/transform.h" +namespace gfx { +class Rect; +} + namespace cc { +class DrawQuad; +class IOSurfaceDrawQuad; +class StreamVideoDrawQuad; +class TextureDrawQuad; + class CC_EXPORT OverlayCandidate { public: - static gfx::OverlayTransform GetOverlayTransform( - const gfx::Transform& quad_transform, - 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); - + // Returns true and fills in |candidate| if |draw_quad| is of a known quad + // type and contains an overlayable resource. + static bool FromDrawQuad(const DrawQuad* quad, OverlayCandidate* candidate); OverlayCandidate(); ~OverlayCandidate(); @@ -41,6 +45,15 @@ class CC_EXPORT OverlayCandidate { gfx::RectF display_rect; // Crop within the buffer to be placed inside |display_rect|. gfx::RectF uv_rect; + // Quad geometry rect after applying the quad_transform(). + gfx::Rect quad_rect_in_target_space; + // Clip rect in the target content space after composition. + gfx::Rect clip_rect; + // If the quad is clipped after composition. + bool is_clipped; + // True if the texture for this overlay should be the same one used by the + // output surface's main overlay. + bool use_output_surface_for_resource; // Texture resource to present in an overlay. unsigned resource_id; // Stacking order of the overlay plane relative to the main surface, @@ -50,6 +63,14 @@ class CC_EXPORT OverlayCandidate { // To be modified by the implementer if this candidate can go into // an overlay. bool overlay_handled; + + private: + static bool FromTextureQuad(const TextureDrawQuad* quad, + OverlayCandidate* candidate); + static bool FromStreamVideoQuad(const StreamVideoDrawQuad* quad, + OverlayCandidate* candidate); + static bool FromIOSurfaceQuad(const IOSurfaceDrawQuad* quad, + OverlayCandidate* candidate); }; typedef std::vector<OverlayCandidate> OverlayCandidateList; diff --git a/chromium/cc/output/overlay_candidate_validator.h b/chromium/cc/output/overlay_candidate_validator.h index 60647316f8b..8586b4de170 100644 --- a/chromium/cc/output/overlay_candidate_validator.h +++ b/chromium/cc/output/overlay_candidate_validator.h @@ -9,6 +9,7 @@ #include "cc/base/cc_export.h" #include "cc/output/overlay_candidate.h" +#include "cc/output/overlay_processor.h" namespace cc { @@ -16,6 +17,9 @@ namespace cc { // configurations for a particular output device. class CC_EXPORT OverlayCandidateValidator { public: + // Populates a list of strategies that may work with this validator. + virtual void GetStrategies(OverlayProcessor::StrategyList* strategies) = 0; + // 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 diff --git a/chromium/cc/output/overlay_processor.cc b/chromium/cc/output/overlay_processor.cc index baae69dd10e..ab334ec9534 100644 --- a/chromium/cc/output/overlay_processor.cc +++ b/chromium/cc/output/overlay_processor.cc @@ -17,15 +17,10 @@ OverlayProcessor::OverlayProcessor(OutputSurface* surface) : surface_(surface) { void OverlayProcessor::Initialize() { DCHECK(surface_); - - OverlayCandidateValidator* candidates = + OverlayCandidateValidator* validator = surface_->GetOverlayCandidateValidator(); - if (candidates) { - strategies_.push_back( - scoped_ptr<Strategy>(new OverlayStrategySingleOnTop(candidates))); - strategies_.push_back( - scoped_ptr<Strategy>(new OverlayStrategyUnderlay(candidates))); - } + if (validator) + validator->GetStrategies(&strategies_); } OverlayProcessor::~OverlayProcessor() {} @@ -35,8 +30,10 @@ void OverlayProcessor::ProcessForOverlays( OverlayCandidateList* candidate_list) { for (StrategyList::iterator it = strategies_.begin(); it != strategies_.end(); ++it) { - if ((*it)->Attempt(render_passes_in_draw_order, candidate_list)) + if ((*it)->Attempt(render_passes_in_draw_order, candidate_list, + surface_->device_scale_factor())) { return; + } } } diff --git a/chromium/cc/output/overlay_processor.h b/chromium/cc/output/overlay_processor.h index e37816c9565..feba0481b29 100644 --- a/chromium/cc/output/overlay_processor.h +++ b/chromium/cc/output/overlay_processor.h @@ -25,7 +25,8 @@ class CC_EXPORT OverlayProcessor { // and adds any additional passes necessary to represent overlays to // |render_passes_in_draw_order|. virtual bool Attempt(RenderPassList* render_passes_in_draw_order, - OverlayCandidateList* candidates) = 0; + OverlayCandidateList* candidates, + float device_scale_factor) = 0; }; typedef ScopedPtrVector<Strategy> StrategyList; diff --git a/chromium/cc/output/overlay_strategy_all_or_nothing.cc b/chromium/cc/output/overlay_strategy_all_or_nothing.cc new file mode 100644 index 00000000000..bead0a707b6 --- /dev/null +++ b/chromium/cc/output/overlay_strategy_all_or_nothing.cc @@ -0,0 +1,44 @@ +// 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_all_or_nothing.h" + +#include "cc/output/overlay_candidate_validator.h" +#include "cc/quads/draw_quad.h" + +namespace cc { + +OverlayStrategyAllOrNothing::OverlayStrategyAllOrNothing( + OverlayCandidateValidator* capability_checker) + : capability_checker_(capability_checker) {} + +OverlayStrategyAllOrNothing::~OverlayStrategyAllOrNothing() {} + +bool OverlayStrategyAllOrNothing::Attempt(RenderPassList* render_passes, + OverlayCandidateList* candidates, + float device_scale_factor) { + QuadList& quad_list = render_passes->back()->quad_list; + OverlayCandidateList new_candidates; + int next_z_order = -1; + + for (const DrawQuad* quad : quad_list) { + OverlayCandidate candidate; + if (!OverlayCandidate::FromDrawQuad(quad, &candidate)) + return false; + candidate.plane_z_order = next_z_order--; + new_candidates.push_back(candidate); + } + + capability_checker_->CheckOverlaySupport(&new_candidates); + for (const OverlayCandidate& candidate : new_candidates) { + if (!candidate.overlay_handled) + return false; + } + + quad_list.clear(); + candidates->swap(new_candidates); + return true; +} + +} // namespace cc diff --git a/chromium/cc/output/overlay_strategy_all_or_nothing.h b/chromium/cc/output/overlay_strategy_all_or_nothing.h new file mode 100644 index 00000000000..7986d0e2682 --- /dev/null +++ b/chromium/cc/output/overlay_strategy_all_or_nothing.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_OUTPUT_OVERLAY_STRATEGY_ALL_OR_NOTHING_H_ +#define CC_OUTPUT_OVERLAY_STRATEGY_ALL_OR_NOTHING_H_ + +#include "cc/output/overlay_processor.h" + +namespace cc { + +class OverlayCandidateValidator; + +// This strategy attempts to promote all quads into overlays. +// If any quad can't be promoted, it returns false and no quads are promoted. +class CC_EXPORT OverlayStrategyAllOrNothing + : public OverlayProcessor::Strategy { + public: + explicit OverlayStrategyAllOrNothing( + OverlayCandidateValidator* capability_checker); + ~OverlayStrategyAllOrNothing() override; + + bool Attempt(RenderPassList* render_passes, + OverlayCandidateList* candidate_list, + float device_scale_factor) override; + + private: + OverlayCandidateValidator* capability_checker_; // Weak. + + DISALLOW_COPY_AND_ASSIGN(OverlayStrategyAllOrNothing); +}; + +} // namespace cc + +#endif // CC_OUTPUT_OVERLAY_STRATEGY_ALL_OR_NOTHING_H_ diff --git a/chromium/cc/output/overlay_strategy_common.cc b/chromium/cc/output/overlay_strategy_common.cc index 33b45942398..d142ba54155 100644 --- a/chromium/cc/output/overlay_strategy_common.cc +++ b/chromium/cc/output/overlay_strategy_common.cc @@ -4,57 +4,54 @@ #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 "cc/resources/resource_provider.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) - : capability_checker_(capability_checker) { -} + OverlayCandidateValidator* capability_checker, + OverlayStrategyCommonDelegate* delegate) + : capability_checker_(capability_checker), delegate_(delegate) {} OverlayStrategyCommon::~OverlayStrategyCommon() { } bool OverlayStrategyCommon::Attempt(RenderPassList* render_passes_in_draw_order, - OverlayCandidateList* candidate_list) { + OverlayCandidateList* candidate_list, + float device_scale_factor) { if (!capability_checker_) return false; RenderPass* root_render_pass = render_passes_in_draw_order->back(); DCHECK(root_render_pass); + bool created_overlay = false; QuadList& quad_list = root_render_pass->quad_list; - for (auto it = quad_list.begin(); it != quad_list.end(); ++it) { + for (auto it = quad_list.begin(); it != quad_list.end();) { OverlayCandidate candidate; - const DrawQuad* draw_quad = *it; - if (IsOverlayQuad(draw_quad) && - GetCandidateQuadInfo(*draw_quad, &candidate) && - TryOverlay(capability_checker_, render_passes_in_draw_order, - candidate_list, candidate, it)) - return true; + if (!OverlayCandidate::FromDrawQuad(*it, &candidate)) { + ++it; + continue; + } + + OverlayResult result = delegate_->TryOverlay( + capability_checker_, render_passes_in_draw_order, candidate_list, + candidate, &it, device_scale_factor); + switch (result) { + case DID_NOT_CREATE_OVERLAY: + ++it; + break; + case CREATED_OVERLAY_STOP_LOOKING: + return true; + case CREATED_OVERLAY_KEEP_LOOKING: + created_overlay = true; + break; + } } - return false; -} -bool OverlayStrategyCommon::IsOverlayQuad(const DrawQuad* draw_quad) { - switch (draw_quad->material) { - case DrawQuad::TEXTURE_CONTENT: - return TextureDrawQuad::MaterialCast(draw_quad)->allow_overlay(); - case DrawQuad::STREAM_VIDEO_CONTENT: - return StreamVideoDrawQuad::MaterialCast(draw_quad)->allow_overlay(); - default: - return false; - } + return created_overlay; } +// static bool OverlayStrategyCommon::IsInvisibleQuad(const DrawQuad* draw_quad) { if (draw_quad->material == DrawQuad::SOLID_COLOR) { const SolidColorDrawQuad* solid_quad = @@ -68,87 +65,4 @@ bool OverlayStrategyCommon::IsInvisibleQuad(const DrawQuad* draw_quad) { return false; } -bool OverlayStrategyCommon::GetTextureQuadInfo(const TextureDrawQuad& quad, - OverlayCandidate* quad_info) { - gfx::OverlayTransform overlay_transform = - OverlayCandidate::GetOverlayTransform( - quad.shared_quad_state->quad_to_target_transform, 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->resource_size_in_pixels = quad.resource_size_in_pixels(); - 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.shared_quad_state->quad_to_target_transform, 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->resource_size_in_pixels = quad.resource_size_in_pixels(); - 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.shared_quad_state->quad_to_target_transform, 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 index 2b81b90ee40..59fc1f4e279 100644 --- a/chromium/cc/output/overlay_strategy_common.h +++ b/chromium/cc/output/overlay_strategy_common.h @@ -10,44 +10,52 @@ #include "cc/output/overlay_processor.h" namespace cc { +class IOSurfaceDrawQuad; +class OverlayCandidate; class OverlayCandidateValidator; class StreamVideoDrawQuad; class TextureDrawQuad; -class OverlayCandidate; + +enum OverlayResult { + DID_NOT_CREATE_OVERLAY, + CREATED_OVERLAY_STOP_LOOKING, + CREATED_OVERLAY_KEEP_LOOKING, +}; + +class CC_EXPORT OverlayStrategyCommonDelegate { + public: + virtual ~OverlayStrategyCommonDelegate() {} + + // Check if |candidate| can be promoted into an overlay. If so, add it to + // |candidate_list| and update the quads in |render_passes_in_draw_order| + // as necessary. When returning CREATED_OVERLAY_KEEP_LOOKING, |iter| is + // updated to point to the next quad to evaluate. + virtual OverlayResult TryOverlay( + OverlayCandidateValidator* capability_checker, + RenderPassList* render_passes_in_draw_order, + OverlayCandidateList* candidate_list, + const OverlayCandidate& candidate, + QuadList::Iterator* iter, + float device_scale_factor) = 0; +}; class CC_EXPORT OverlayStrategyCommon : public OverlayProcessor::Strategy { public: - explicit OverlayStrategyCommon(OverlayCandidateValidator* capability_checker); + explicit OverlayStrategyCommon(OverlayCandidateValidator* capability_checker, + OverlayStrategyCommonDelegate* delegate); ~OverlayStrategyCommon() override; bool Attempt(RenderPassList* render_passes_in_draw_order, - OverlayCandidateList* candidate_list) override; - - protected: - bool GetCandidateQuadInfo(const DrawQuad& draw_quad, - OverlayCandidate* quad_info); + OverlayCandidateList* candidate_list, + float device_scale_factor) override; // 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); - - virtual bool TryOverlay(OverlayCandidateValidator* capability_checker, - RenderPassList* render_passes_in_draw_order, - OverlayCandidateList* candidate_list, - const OverlayCandidate& candidate, - QuadList::Iterator iter) = 0; + static bool IsInvisibleQuad(const DrawQuad* draw_quad); private: OverlayCandidateValidator* capability_checker_; + scoped_ptr<OverlayStrategyCommonDelegate> delegate_; DISALLOW_COPY_AND_ASSIGN(OverlayStrategyCommon); }; diff --git a/chromium/cc/output/overlay_strategy_sandwich.cc b/chromium/cc/output/overlay_strategy_sandwich.cc new file mode 100644 index 00000000000..63032a76e55 --- /dev/null +++ b/chromium/cc/output/overlay_strategy_sandwich.cc @@ -0,0 +1,163 @@ +// 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_sandwich.h" + +#include "cc/base/math_util.h" +#include "cc/base/region.h" +#include "cc/output/overlay_candidate_validator.h" +#include "cc/quads/draw_quad.h" +#include "cc/quads/solid_color_draw_quad.h" + +namespace cc { + +namespace { + +void ClipDisplayAndUVRects(gfx::Rect* display_rect, + gfx::RectF* uv_rect, + const gfx::Rect& clip_rect) { + gfx::Rect display_cropped_rect = + gfx::IntersectRects(*display_rect, clip_rect); + + gfx::RectF uv_cropped_rect = gfx::RectF(display_cropped_rect); + uv_cropped_rect -= gfx::Vector2dF(display_rect->x(), display_rect->y()); + uv_cropped_rect.Scale(uv_rect->width() / display_rect->width(), + uv_rect->height() / display_rect->height()); + uv_cropped_rect += gfx::Vector2dF(uv_rect->x(), uv_rect->y()); + + *display_rect = display_cropped_rect; + *uv_rect = uv_cropped_rect; +} + +} // namespace + +OverlayStrategySandwich::~OverlayStrategySandwich() {} + +OverlayResult OverlayStrategySandwich::TryOverlay( + OverlayCandidateValidator* capability_checker, + RenderPassList* render_passes_in_draw_order, + OverlayCandidateList* candidate_list, + const OverlayCandidate& candidate, + QuadList::Iterator* candidate_iter_in_quad_list, + float device_scale_factor) { + RenderPass* root_render_pass = render_passes_in_draw_order->back(); + QuadList& quad_list = root_render_pass->quad_list; + gfx::Rect pixel_bounds = root_render_pass->output_rect; + + const DrawQuad* candidate_quad = **candidate_iter_in_quad_list; + const gfx::Transform& candidate_transform = + candidate_quad->shared_quad_state->quad_to_target_transform; + gfx::Transform candidate_inverse_transform; + if (!candidate_transform.GetInverse(&candidate_inverse_transform)) + return DID_NOT_CREATE_OVERLAY; + + // Compute the candidate's rect in display space (pixels on the screen). + gfx::Rect candidate_pixel_rect = candidate.quad_rect_in_target_space; + gfx::RectF candidate_uv_rect = candidate.uv_rect; + if (candidate.is_clipped && + !candidate.clip_rect.Contains(candidate_pixel_rect)) { + ClipDisplayAndUVRects(&candidate_pixel_rect, &candidate_uv_rect, + candidate.clip_rect); + } + + // Don't allow overlapping overlays for now. + for (const OverlayCandidate& other_candidate : *candidate_list) { + if (other_candidate.display_rect.Intersects(candidate.display_rect) && + other_candidate.plane_z_order == 1) { + return DID_NOT_CREATE_OVERLAY; + } + } + + // Iterate through the quads in front of |candidate|, and compute the region + // of |candidate| that is covered. + Region pixel_covered_region; + for (auto overlap_iter = quad_list.cbegin(); + overlap_iter != *candidate_iter_in_quad_list; ++overlap_iter) { + if (OverlayStrategyCommon::IsInvisibleQuad(*overlap_iter)) + continue; + // Compute the quad's bounds in display space. + gfx::Rect pixel_covered_rect = MathUtil::MapEnclosingClippedRect( + overlap_iter->shared_quad_state->quad_to_target_transform, + overlap_iter->rect); + + // Include the intersection of that quad with the candidate's quad in the + // covered region. + pixel_covered_rect.Intersect(candidate_pixel_rect); + pixel_covered_region.Union(pixel_covered_rect); + } + + // Add the candidate's overlay. + DCHECK(candidate.resource_id); + OverlayCandidateList new_candidate_list = *candidate_list; + new_candidate_list.push_back(candidate); + OverlayCandidate& new_candidate = new_candidate_list.back(); + new_candidate.plane_z_order = 1; + new_candidate.display_rect = gfx::RectF(candidate_pixel_rect); + new_candidate.quad_rect_in_target_space = candidate_pixel_rect; + new_candidate.uv_rect = candidate_uv_rect; + + // Add an overlay of the primary surface for any part of the candidate's + // quad that was covered. + std::vector<gfx::Rect> pixel_covered_rects; + for (Region::Iterator it(pixel_covered_region); it.has_rect(); it.next()) + pixel_covered_rects.push_back(it.rect()); + for (const gfx::Rect& pixel_covered_rect : pixel_covered_rects) { + OverlayCandidate main_image_on_top; + main_image_on_top.display_rect = gfx::RectF(pixel_covered_rect); + main_image_on_top.uv_rect = gfx::RectF(pixel_covered_rect); + main_image_on_top.uv_rect.Scale(1.f / pixel_bounds.width(), + 1.f / pixel_bounds.height()); + main_image_on_top.plane_z_order = 2; + main_image_on_top.transform = gfx::OVERLAY_TRANSFORM_NONE; + main_image_on_top.use_output_surface_for_resource = true; + new_candidate_list.push_back(main_image_on_top); + } + + // Check for support. + capability_checker->CheckOverlaySupport(&new_candidate_list); + for (const OverlayCandidate& candidate : new_candidate_list) { + if (!candidate.overlay_handled) + return DID_NOT_CREATE_OVERLAY; + } + + // Remove the quad for the overlay quad. Replace it with a transparent quad + // if we're putting a new overlay on top. + if (pixel_covered_rects.empty()) { + *candidate_iter_in_quad_list = + quad_list.EraseAndInvalidateAllPointers(*candidate_iter_in_quad_list); + } else { + // Cache the information from the candidate quad that we'll need to + // construct the solid color quads. + const SharedQuadState* candidate_shared_quad_state = + candidate_quad->shared_quad_state; + const gfx::Rect candidate_rect = candidate_quad->rect; + + // Reserve space in the quad list for the transparent quads. + quad_list.ReplaceExistingElement<SolidColorDrawQuad>( + *candidate_iter_in_quad_list); + *candidate_iter_in_quad_list = + quad_list.InsertBeforeAndInvalidateAllPointers<SolidColorDrawQuad>( + *candidate_iter_in_quad_list, pixel_covered_rects.size() - 1); + + // Cover the region with transparent quads. + for (const gfx::Rect& pixel_covered_rect : pixel_covered_rects) { + gfx::Rect quad_space_covered_rect = MathUtil::MapEnclosingClippedRect( + candidate_inverse_transform, pixel_covered_rect); + quad_space_covered_rect.Intersect(candidate_rect); + + SolidColorDrawQuad* transparent_quad = + static_cast<SolidColorDrawQuad*>(**candidate_iter_in_quad_list); + transparent_quad->SetAll(candidate_shared_quad_state, + quad_space_covered_rect, quad_space_covered_rect, + quad_space_covered_rect, false, + SK_ColorTRANSPARENT, true); + ++(*candidate_iter_in_quad_list); + } + } + + candidate_list->swap(new_candidate_list); + return CREATED_OVERLAY_KEEP_LOOKING; +} + +} // namespace cc diff --git a/chromium/cc/output/overlay_strategy_sandwich.h b/chromium/cc/output/overlay_strategy_sandwich.h new file mode 100644 index 00000000000..a1bd9d1bb24 --- /dev/null +++ b/chromium/cc/output/overlay_strategy_sandwich.h @@ -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. + +#ifndef CC_OUTPUT_OVERLAY_STRATEGY_SANDWICH_H_ +#define CC_OUTPUT_OVERLAY_STRATEGY_SANDWICH_H_ + +#include "cc/output/overlay_strategy_common.h" + +namespace cc { + +// The sandwich strategy looks for a video quad without regard to quads above +// it. The video is "overlaid" on top of the scene, and then the non-empty +// parts of the scene are "overlaid" on top of the video. This is only valid +// for overlay contents that are fully opaque. +class CC_EXPORT OverlayStrategySandwich : public OverlayStrategyCommonDelegate { + public: + OverlayStrategySandwich() {} + ~OverlayStrategySandwich() override; + + OverlayResult TryOverlay(OverlayCandidateValidator* capability_checker, + RenderPassList* render_passes_in_draw_order, + OverlayCandidateList* candidate_list, + const OverlayCandidate& candidate, + QuadList::Iterator* candidate_iterator, + float device_scale_factor) override; + + private: + DISALLOW_COPY_AND_ASSIGN(OverlayStrategySandwich); +}; + +} // namespace cc + +#endif // CC_OUTPUT_OVERLAY_STRATEGY_SANDWICH_H_ diff --git a/chromium/cc/output/overlay_strategy_single_on_top.cc b/chromium/cc/output/overlay_strategy_single_on_top.cc index fd47e0f3b72..6b63045c015 100644 --- a/chromium/cc/output/overlay_strategy_single_on_top.cc +++ b/chromium/cc/output/overlay_strategy_single_on_top.cc @@ -6,59 +6,50 @@ #include <limits> +#include "cc/base/math_util.h" #include "cc/output/overlay_candidate_validator.h" #include "cc/quads/draw_quad.h" namespace cc { -OverlayStrategySingleOnTop::OverlayStrategySingleOnTop( - OverlayCandidateValidator* capability_checker) - : OverlayStrategyCommon(capability_checker) { -} +OverlayStrategySingleOnTop::~OverlayStrategySingleOnTop() {} -bool OverlayStrategySingleOnTop::TryOverlay( +OverlayResult OverlayStrategySingleOnTop::TryOverlay( OverlayCandidateValidator* capability_checker, - RenderPassList* render_passes_in_draw_order, OverlayCandidateList* candidate_list, const OverlayCandidate& candidate, - QuadList::Iterator candidate_iterator) { + QuadList::Iterator* candidate_iterator, + float device_scale_factor) { RenderPass* root_render_pass = render_passes_in_draw_order->back(); QuadList& quad_list = root_render_pass->quad_list; - const DrawQuad* draw_quad = *candidate_iterator; - gfx::RectF rect = draw_quad->rect; - draw_quad->shared_quad_state->quad_to_target_transform.TransformRect(&rect); - // Check that no prior quads overlap it. for (auto overlap_iter = quad_list.cbegin(); - overlap_iter != candidate_iterator; ++overlap_iter) { - gfx::RectF overlap_rect = overlap_iter->rect; - overlap_iter->shared_quad_state->quad_to_target_transform.TransformRect( - &overlap_rect); - if (rect.Intersects(overlap_rect) && !IsInvisibleQuad(*overlap_iter)) - return false; + overlap_iter != *candidate_iterator; ++overlap_iter) { + gfx::RectF overlap_rect = MathUtil::MapClippedRect( + overlap_iter->shared_quad_state->quad_to_target_transform, + gfx::RectF(overlap_iter->rect)); + if (candidate.display_rect.Intersects(overlap_rect) && + !OverlayStrategyCommon::IsInvisibleQuad(*overlap_iter)) + return DID_NOT_CREATE_OVERLAY; } - // 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. - candidates.push_back(candidate); - candidates.back().plane_z_order = 1; + OverlayCandidateList new_candidate_list = *candidate_list; + new_candidate_list.push_back(candidate); + new_candidate_list.back().plane_z_order = 1; // Check for support. - capability_checker->CheckOverlaySupport(&candidates); + capability_checker->CheckOverlaySupport(&new_candidate_list); // If the candidate can be handled by an overlay, create a pass for it. - if (candidates[1].overlay_handled) { - quad_list.EraseAndInvalidateAllPointers(candidate_iterator); - candidate_list->swap(candidates); - return true; + if (new_candidate_list.back().overlay_handled) { + quad_list.EraseAndInvalidateAllPointers(*candidate_iterator); + candidate_list->swap(new_candidate_list); + return CREATED_OVERLAY_STOP_LOOKING; } - return false; + + return DID_NOT_CREATE_OVERLAY; } } // namespace cc diff --git a/chromium/cc/output/overlay_strategy_single_on_top.h b/chromium/cc/output/overlay_strategy_single_on_top.h index 2b9cf4d04fd..17c763d8896 100644 --- a/chromium/cc/output/overlay_strategy_single_on_top.h +++ b/chromium/cc/output/overlay_strategy_single_on_top.h @@ -17,15 +17,18 @@ namespace cc { class StreamVideoDrawQuad; class TextureDrawQuad; -class CC_EXPORT OverlayStrategySingleOnTop : public OverlayStrategyCommon { +class CC_EXPORT OverlayStrategySingleOnTop + : public OverlayStrategyCommonDelegate { public: - explicit OverlayStrategySingleOnTop( - OverlayCandidateValidator* capability_checker); - bool TryOverlay(OverlayCandidateValidator* capability_checker, - RenderPassList* render_passes_in_draw_order, - OverlayCandidateList* candidate_list, - const OverlayCandidate& candidate, - QuadList::Iterator candidate_iterator) override; + OverlayStrategySingleOnTop() {} + ~OverlayStrategySingleOnTop() override; + + OverlayResult TryOverlay(OverlayCandidateValidator* capability_checker, + RenderPassList* render_passes_in_draw_order, + OverlayCandidateList* candidate_list, + const OverlayCandidate& candidate, + QuadList::Iterator* candidate_iterator, + float device_scale_factor) override; private: DISALLOW_COPY_AND_ASSIGN(OverlayStrategySingleOnTop); diff --git a/chromium/cc/output/overlay_strategy_underlay.cc b/chromium/cc/output/overlay_strategy_underlay.cc index dd2b90f4814..88213695762 100644 --- a/chromium/cc/output/overlay_strategy_underlay.cc +++ b/chromium/cc/output/overlay_strategy_underlay.cc @@ -10,49 +10,42 @@ namespace cc { -OverlayStrategyUnderlay::OverlayStrategyUnderlay( - OverlayCandidateValidator* capability_checker) - : OverlayStrategyCommon(capability_checker) { -} +OverlayStrategyUnderlay::~OverlayStrategyUnderlay() {} -bool OverlayStrategyUnderlay::TryOverlay( +OverlayResult OverlayStrategyUnderlay::TryOverlay( OverlayCandidateValidator* capability_checker, - RenderPassList* render_passes_in_draw_order, OverlayCandidateList* candidate_list, const OverlayCandidate& candidate, - QuadList::Iterator candidate_iterator) { + QuadList::Iterator* candidate_iterator, + float device_scale_factor) { RenderPass* root_render_pass = render_passes_in_draw_order->back(); QuadList& quad_list = root_render_pass->quad_list; - // 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. - candidates.push_back(candidate); - candidates.back().plane_z_order = -1; + OverlayCandidateList new_candidate_list = *candidate_list; + new_candidate_list.push_back(candidate); + new_candidate_list.back().plane_z_order = -1; // Check for support. - capability_checker->CheckOverlaySupport(&candidates); + capability_checker->CheckOverlaySupport(&new_candidate_list); // 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) { + if (new_candidate_list.back().overlay_handled) { const SharedQuadState* shared_quad_state = - candidate_iterator->shared_quad_state; - gfx::Rect rect = candidate_iterator->visible_rect; + (*candidate_iterator)->shared_quad_state; + gfx::Rect rect = (*candidate_iterator)->visible_rect; SolidColorDrawQuad* replacement = quad_list.ReplaceExistingElement<SolidColorDrawQuad>( - candidate_iterator); + *candidate_iterator); replacement->SetAll(shared_quad_state, rect, rect, rect, false, SK_ColorTRANSPARENT, true); - candidate_list->swap(candidates); - return true; + candidate_list->swap(new_candidate_list); + return CREATED_OVERLAY_STOP_LOOKING; } - return false; + + return DID_NOT_CREATE_OVERLAY; } } // namespace cc diff --git a/chromium/cc/output/overlay_strategy_underlay.h b/chromium/cc/output/overlay_strategy_underlay.h index fd55bef4319..20c210697f5 100644 --- a/chromium/cc/output/overlay_strategy_underlay.h +++ b/chromium/cc/output/overlay_strategy_underlay.h @@ -16,15 +16,17 @@ class TextureDrawQuad; // 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 { +class CC_EXPORT OverlayStrategyUnderlay : public OverlayStrategyCommonDelegate { public: - explicit OverlayStrategyUnderlay( - OverlayCandidateValidator* capability_checker); - bool TryOverlay(OverlayCandidateValidator* capability_checker, - RenderPassList* render_passes_in_draw_order, - OverlayCandidateList* candidate_list, - const OverlayCandidate& candidate, - QuadList::Iterator candidate_iterator) override; + OverlayStrategyUnderlay() {} + ~OverlayStrategyUnderlay() override; + + OverlayResult TryOverlay(OverlayCandidateValidator* capability_checker, + RenderPassList* render_passes_in_draw_order, + OverlayCandidateList* candidate_list, + const OverlayCandidate& candidate, + QuadList::Iterator* candidate_iterator, + float device_scale_factor) override; private: DISALLOW_COPY_AND_ASSIGN(OverlayStrategyUnderlay); diff --git a/chromium/cc/output/overlay_unittest.cc b/chromium/cc/output/overlay_unittest.cc index 6ac9b1c64c8..155707bc6a1 100644 --- a/chromium/cc/output/overlay_unittest.cc +++ b/chromium/cc/output/overlay_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 "cc/base/region.h" #include "cc/base/scoped_ptr_vector.h" #include "cc/output/compositor_frame_metadata.h" #include "cc/output/gl_renderer.h" @@ -9,10 +10,12 @@ #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_all_or_nothing.h" +#include "cc/output/overlay_strategy_sandwich.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/solid_color_draw_quad.h" #include "cc/quads/stream_video_draw_quad.h" #include "cc/quads/texture_draw_quad.h" #include "cc/resources/resource_provider.h" @@ -24,6 +27,7 @@ #include "cc/test/test_shared_bitmap_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/rect_conversions.h" using testing::_; using testing::Mock; @@ -31,9 +35,11 @@ using testing::Mock; namespace cc { namespace { +const gfx::Size kDisplaySize(256, 256); const gfx::Rect kOverlayRect(0, 0, 128, 128); const gfx::Rect kOverlayTopLeftRect(0, 0, 64, 64); const gfx::Rect kOverlayBottomRightRect(64, 64, 64, 64); +const gfx::Rect kOverlayClipRect(0, 0, 128, 128); const gfx::PointF kUVTopLeft(0.1f, 0.2f); const gfx::PointF kUVBottomRight(1.0f, 1.0f); const gfx::Transform kNormalTransform = @@ -54,42 +60,76 @@ void MailboxReleased(unsigned sync_point, class SingleOverlayValidator : public OverlayCandidateValidator { public: - void CheckOverlaySupport(OverlayCandidateList* surfaces) override; + void GetStrategies(OverlayProcessor::StrategyList* strategies) override { + strategies->push_back(make_scoped_ptr( + new OverlayStrategyCommon(this, new OverlayStrategySingleOnTop))); + strategies->push_back(make_scoped_ptr( + new OverlayStrategyCommon(this, new OverlayStrategyUnderlay))); + } + void CheckOverlaySupport(OverlayCandidateList* surfaces) override { + // We may have 1 or 2 surfaces depending on whether this ran through the + // full renderer and picked up the output surface, or not. + ASSERT_LE(1U, surfaces->size()); + ASSERT_GE(2U, surfaces->size()); + + OverlayCandidate& candidate = surfaces->back(); + EXPECT_TRUE(!candidate.use_output_surface_for_resource); + if (candidate.display_rect.width() == 64) { + EXPECT_EQ(gfx::RectF(kOverlayBottomRightRect), 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_FLOAT_RECT_EQ(BoundingRect(kUVTopLeft, kUVBottomRight), + candidate.uv_rect); + if (!candidate.clip_rect.IsEmpty()) { + EXPECT_EQ(true, candidate.is_clipped); + EXPECT_EQ(kOverlayClipRect, candidate.clip_rect); + } + candidate.overlay_handled = true; + } }; -void SingleOverlayValidator::CheckOverlaySupport( - OverlayCandidateList* surfaces) { - ASSERT_EQ(2U, surfaces->size()); - - OverlayCandidate& candidate = surfaces->back(); - if (candidate.display_rect.width() == 64) { - EXPECT_EQ(kOverlayBottomRightRect, 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); +class SingleOnTopOverlayValidator : public SingleOverlayValidator { + public: + void GetStrategies(OverlayProcessor::StrategyList* strategies) override { + strategies->push_back(make_scoped_ptr( + new OverlayStrategyCommon(this, new OverlayStrategySingleOnTop))); } - EXPECT_EQ(BoundingRect(kUVTopLeft, kUVBottomRight).ToString(), - candidate.uv_rect.ToString()); - candidate.overlay_handled = true; -} +}; -template <typename OverlayStrategyType> -class SingleOverlayProcessor : public OverlayProcessor { +class UnderlayOverlayValidator : public SingleOverlayValidator { public: - explicit SingleOverlayProcessor(OutputSurface* surface) - : OverlayProcessor(surface) { - EXPECT_EQ(surface, surface_); + void GetStrategies(OverlayProcessor::StrategyList* strategies) override { + strategies->push_back(make_scoped_ptr( + new OverlayStrategyCommon(this, new OverlayStrategyUnderlay))); } +}; - // Virtual to allow testing different strategies. - void Initialize() override { - OverlayCandidateValidator* candidates = - surface_->GetOverlayCandidateValidator(); - ASSERT_TRUE(candidates != NULL); - strategies_.push_back( - scoped_ptr<Strategy>(new OverlayStrategyType(candidates))); +class SandwichOverlayValidator : public OverlayCandidateValidator { + public: + void GetStrategies(OverlayProcessor::StrategyList* strategies) override { + strategies->push_back(make_scoped_ptr( + new OverlayStrategyCommon(this, new OverlayStrategySandwich))); + } + void CheckOverlaySupport(OverlayCandidateList* surfaces) override { + for (OverlayCandidate& candidate : *surfaces) + candidate.overlay_handled = true; + } +}; + +class AllOrNothingOverlayValidator : public OverlayCandidateValidator { + public: + void GetStrategies(OverlayProcessor::StrategyList* strategies) override { + strategies->push_back( + make_scoped_ptr(new OverlayStrategyAllOrNothing(this))); + } + void CheckOverlaySupport(OverlayCandidateList* surfaces) override { + for (OverlayCandidate& candidate : *surfaces) + candidate.overlay_handled = true; } }; @@ -110,21 +150,38 @@ size_t DefaultOverlayProcessor::GetStrategyCount() { class OverlayOutputSurface : public OutputSurface { public: explicit OverlayOutputSurface(scoped_refptr<ContextProvider> context_provider) - : OutputSurface(context_provider) {} + : OutputSurface(context_provider) { + surface_size_ = kDisplaySize; + device_scale_factor_ = 1; + is_displayed_as_overlay_plane_ = true; + } + + void SetScaleFactor(float scale_factor) { + device_scale_factor_ = scale_factor; + } // OutputSurface implementation void SwapBuffers(CompositorFrame* frame) override; - void InitWithSingleOverlayValidator() { - overlay_candidate_validator_.reset(new SingleOverlayValidator); + void SetOverlayCandidateValidator(OverlayCandidateValidator* validator) { + overlay_candidate_validator_.reset(validator); } OverlayCandidateValidator* GetOverlayCandidateValidator() const override { return overlay_candidate_validator_.get(); } + bool IsDisplayedAsOverlayPlane() const override { + return is_displayed_as_overlay_plane_; + } + unsigned GetOverlayTextureId() const override { return 10000; } + void set_is_displayed_as_overlay_plane(bool value) { + is_displayed_as_overlay_plane_ = value; + } + private: scoped_ptr<OverlayCandidateValidator> overlay_candidate_validator_; + bool is_displayed_as_overlay_plane_; }; void OverlayOutputSurface::SwapBuffers(CompositorFrame* frame) { @@ -238,20 +295,20 @@ StreamVideoDrawQuad* CreateFullscreenCandidateVideoQuad( 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(), 1.f); +void CreateOpaqueQuadAt(ResourceProvider* resource_provider, + const SharedQuadState* shared_quad_state, + RenderPass* render_pass, + const gfx::Rect& rect) { + SolidColorDrawQuad* color_quad = + render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + color_quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false); } -void CreateFullscreenCheckeredQuad(ResourceProvider* resource_provider, - const SharedQuadState* shared_quad_state, - RenderPass* render_pass) { - CreateCheckeredQuadAt( - resource_provider, shared_quad_state, render_pass, kOverlayRect); +void CreateFullscreenOpaqueQuad(ResourceProvider* resource_provider, + const SharedQuadState* shared_quad_state, + RenderPass* render_pass) { + CreateOpaqueQuadAt(resource_provider, shared_quad_state, render_pass, + kOverlayRect); } static void CompareRenderPassLists(const RenderPassList& expected_list, @@ -284,12 +341,43 @@ static void CompareRenderPassLists(const RenderPassList& expected_list, } } +template <typename OverlayCandidateValidatorType> +class OverlayTest : public testing::Test { + protected: + void SetUp() override { + provider_ = TestContextProvider::Create(); + output_surface_.reset(new OverlayOutputSurface(provider_)); + EXPECT_TRUE(output_surface_->BindToClient(&client_)); + output_surface_->SetOverlayCandidateValidator( + new OverlayCandidateValidatorType); + + shared_bitmap_manager_.reset(new TestSharedBitmapManager()); + resource_provider_ = FakeResourceProvider::Create( + output_surface_.get(), shared_bitmap_manager_.get()); + + overlay_processor_.reset(new OverlayProcessor(output_surface_.get())); + overlay_processor_->Initialize(); + } + + scoped_refptr<TestContextProvider> provider_; + scoped_ptr<OverlayOutputSurface> output_surface_; + FakeOutputSurfaceClient client_; + scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; + scoped_ptr<ResourceProvider> resource_provider_; + scoped_ptr<OverlayProcessor> overlay_processor_; +}; + +typedef OverlayTest<SingleOnTopOverlayValidator> SingleOverlayOnTopTest; +typedef OverlayTest<UnderlayOverlayValidator> UnderlayTest; +typedef OverlayTest<SandwichOverlayValidator> SandwichTest; +typedef OverlayTest<AllOrNothingOverlayValidator> AllOrNothingOverlayTest; + TEST(OverlayTest, NoOverlaysByDefault) { scoped_refptr<TestContextProvider> provider = TestContextProvider::Create(); OverlayOutputSurface output_surface(provider); EXPECT_EQ(NULL, output_surface.GetOverlayCandidateValidator()); - output_surface.InitWithSingleOverlayValidator(); + output_surface.SetOverlayCandidateValidator(new SingleOverlayValidator); EXPECT_TRUE(output_surface.GetOverlayCandidateValidator() != NULL); } @@ -298,8 +386,7 @@ TEST(OverlayTest, OverlaysProcessorHasStrategy) { OverlayOutputSurface output_surface(provider); FakeOutputSurfaceClient client; EXPECT_TRUE(output_surface.BindToClient(&client)); - output_surface.InitWithSingleOverlayValidator(); - EXPECT_TRUE(output_surface.GetOverlayCandidateValidator() != NULL); + output_surface.SetOverlayCandidateValidator(new SingleOverlayValidator); scoped_ptr<SharedBitmapManager> shared_bitmap_manager( new TestSharedBitmapManager()); @@ -312,35 +399,246 @@ TEST(OverlayTest, OverlaysProcessorHasStrategy) { EXPECT_GE(2U, overlay_processor->GetStrategyCount()); } -template <typename OverlayStrategyType> -class OverlayTest : public testing::Test { - protected: - 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_->GetOverlayCandidateValidator() != NULL); +TEST_F(SandwichTest, SuccessfulSingleOverlay) { + scoped_ptr<RenderPass> pass = CreateRenderPass(); + TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad( + resource_provider_.get(), pass->shared_quad_state_list.back(), + pass.get()); + unsigned original_resource_id = original_quad->resource_id(); - shared_bitmap_manager_.reset(new TestSharedBitmapManager()); - resource_provider_ = FakeResourceProvider::Create( - output_surface_.get(), shared_bitmap_manager_.get()); + // Add something behind it. + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); - overlay_processor_.reset( - new SingleOverlayProcessor<OverlayStrategyType>(output_surface_.get())); - overlay_processor_->Initialize(); + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + // Check for potential candidates. + OverlayCandidateList candidate_list; + overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); + + ASSERT_EQ(1U, pass_list.size()); + ASSERT_EQ(1U, candidate_list.size()); + + RenderPass* main_pass = pass_list.back(); + // Check that the quad is gone. + EXPECT_EQ(2U, main_pass->quad_list.size()); + const QuadList& quad_list = main_pass->quad_list; + for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin(); + it != quad_list.BackToFrontEnd(); ++it) { + EXPECT_NE(DrawQuad::TEXTURE_CONTENT, it->material); } - scoped_refptr<TestContextProvider> provider_; - scoped_ptr<OverlayOutputSurface> output_surface_; - FakeOutputSurfaceClient client_; - scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; - scoped_ptr<ResourceProvider> resource_provider_; - scoped_ptr<SingleOverlayProcessor<OverlayStrategyType>> overlay_processor_; -}; + // Check that the right resource id got extracted. + EXPECT_EQ(original_resource_id, candidate_list.back().resource_id); +} -typedef OverlayTest<OverlayStrategySingleOnTop> SingleOverlayOnTopTest; -typedef OverlayTest<OverlayStrategyUnderlay> UnderlayTest; +TEST_F(SandwichTest, CroppedSingleOverlay) { + scoped_ptr<RenderPass> pass = CreateRenderPass(); + pass->shared_quad_state_list.back()->is_clipped = true; + pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(0, 32, 64, 64); + + TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad( + resource_provider_.get(), pass->shared_quad_state_list.back(), + pass.get()); + original_quad->uv_top_left = gfx::PointF(0, 0); + original_quad->uv_bottom_right = gfx::PointF(1, 1); + unsigned candidate_id = original_quad->resource_id(); + + // Add something behind it. + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + // Check for potential candidates. + OverlayCandidateList candidate_list; + overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); + + // Ensure that the display and uv rects have cropping applied to them. + ASSERT_EQ(1U, pass_list.size()); + ASSERT_EQ(1U, candidate_list.size()); + EXPECT_EQ(candidate_id, candidate_list[0].resource_id); + EXPECT_EQ(gfx::RectF(0.f, 32.f, 64.f, 64.f), candidate_list[0].display_rect); + EXPECT_EQ(gfx::RectF(0.f, 0.25f, 0.5f, 0.5f), candidate_list[0].uv_rect); +} + +TEST_F(SandwichTest, SuccessfulTwoOverlays) { + scoped_ptr<RenderPass> pass = CreateRenderPass(); + + // Add two non-overlapping candidates. + CreateCandidateQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayTopLeftRect); + CreateCandidateQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayBottomRightRect); + + // Add something behind it. + CreateFullscreenOpaqueQuad(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); + + // Both candidates should become overlays. + EXPECT_EQ(1u, pass_list.size()); + EXPECT_EQ(2u, candidate_list.size()); + EXPECT_EQ(gfx::RectF(kOverlayTopLeftRect), candidate_list[0].display_rect); + EXPECT_EQ(gfx::RectF(kOverlayBottomRightRect), + candidate_list[1].display_rect); + + // The overlay quads should be gone. + const QuadList& quad_list = pass_list.back()->quad_list; + EXPECT_EQ(1u, quad_list.size()); + EXPECT_EQ(DrawQuad::SOLID_COLOR, quad_list.front()->material); +} + +TEST_F(SandwichTest, OverlappingOverlays) { + scoped_ptr<RenderPass> pass = CreateRenderPass(); + + // Add two overlapping candidates. + CreateCandidateQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayTopLeftRect); + CreateCandidateQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayRect); + + // Add something behind it. + CreateFullscreenOpaqueQuad(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); + + // Only one of the candidates should become an overlay. + EXPECT_EQ(1u, pass_list.size()); + EXPECT_EQ(1u, candidate_list.size()); + EXPECT_EQ(gfx::RectF(kOverlayTopLeftRect), candidate_list[0].display_rect); + + // One of the overlay quads should be gone. + const QuadList& quad_list = pass_list.back()->quad_list; + EXPECT_EQ(2u, quad_list.size()); + EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, quad_list.front()->material); + EXPECT_EQ(DrawQuad::SOLID_COLOR, quad_list.back()->material); +} + +TEST_F(SandwichTest, SuccessfulSandwichOverlay) { + scoped_ptr<RenderPass> pass = CreateRenderPass(); + + CreateOpaqueQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + gfx::Rect(16, 16, 32, 32)); + unsigned candidate_id = + CreateCandidateQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + gfx::Rect(32, 32, 32, 32)) + ->resource_id(); + CreateOpaqueQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + gfx::Rect(kDisplaySize)); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + // Check for potential candidates. + OverlayCandidateList candidate_list; + overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); + + ASSERT_EQ(1U, pass_list.size()); + ASSERT_EQ(2U, candidate_list.size()); + + RenderPass* main_pass = pass_list.back(); + // Check that the quad is gone. + EXPECT_EQ(3U, main_pass->quad_list.size()); + const QuadList& quad_list = main_pass->quad_list; + for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin(); + it != quad_list.BackToFrontEnd(); ++it) { + EXPECT_NE(DrawQuad::TEXTURE_CONTENT, it->material); + } + + EXPECT_EQ(candidate_id, candidate_list[0].resource_id); + EXPECT_EQ(gfx::RectF(32.f, 32.f, 32.f, 32.f), candidate_list[0].display_rect); + EXPECT_TRUE(candidate_list[1].use_output_surface_for_resource); + EXPECT_EQ(gfx::RectF(32.f, 32.f, 16.f, 16.f), candidate_list[1].display_rect); + EXPECT_EQ(gfx::RectF(32.f / 256.f, 32.f / 256.f, 16.f / 256.f, 16.f / 256.f), + candidate_list[1].uv_rect); +} + +TEST_F(SandwichTest, MultiQuadOverlay) { + scoped_ptr<RenderPass> pass = CreateRenderPass(); + + // Put two non-intersecting quads on top. + const gfx::Rect rect1(gfx::Rect(0, 0, 32, 32)); + const gfx::Rect rect2(gfx::Rect(32, 32, 32, 32)); + Region covered_region; + covered_region.Union(rect1); + covered_region.Union(rect2); + CreateOpaqueQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), rect1); + CreateOpaqueQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), rect2); + + // Then a candidate that we'll turn into an overlay. + unsigned candidate_id = + CreateCandidateQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + gfx::Rect(0, 0, 64, 64)) + ->resource_id(); + + // Then some opaque background. + CreateOpaqueQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + gfx::Rect(kDisplaySize)); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + // Run the overlay strategy on that input. + RenderPass* main_pass = pass_list.back(); + OverlayCandidateList candidate_list; + EXPECT_EQ(4U, main_pass->quad_list.size()); + overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); + ASSERT_EQ(1U, pass_list.size()); + ASSERT_EQ(3U, candidate_list.size()); + + // Check that the candidate quad is gone and that we now have two transparent + // quads for the same region that was covered on the overlay. + EXPECT_EQ(5U, main_pass->quad_list.size()); + const QuadList& quad_list = main_pass->quad_list; + Region transparent_quad_region; + for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin(); + it != quad_list.BackToFrontEnd(); ++it) { + EXPECT_NE(DrawQuad::TEXTURE_CONTENT, it->material); + if (it->material == DrawQuad::SOLID_COLOR) { + const SolidColorDrawQuad* solid_color_quad = + SolidColorDrawQuad::MaterialCast(*it); + if (solid_color_quad->color == SK_ColorTRANSPARENT) + transparent_quad_region.Union(solid_color_quad->rect); + } + } + DCHECK(covered_region == transparent_quad_region); + + // Check that overlays cover the same region that the quads covered. + EXPECT_EQ(candidate_id, candidate_list[0].resource_id); + EXPECT_EQ(gfx::RectF(64.f, 64.f), candidate_list[0].display_rect); + EXPECT_TRUE(candidate_list[1].use_output_surface_for_resource); + EXPECT_TRUE(candidate_list[2].use_output_surface_for_resource); + Region overlay_region; + overlay_region.Union(gfx::ToEnclosingRect(candidate_list[1].display_rect)); + overlay_region.Union(gfx::ToEnclosingRect(candidate_list[2].display_rect)); + DCHECK(covered_region == overlay_region); +} TEST_F(SingleOverlayOnTopTest, SuccessfullOverlay) { scoped_ptr<RenderPass> pass = CreateRenderPass(); @@ -351,12 +649,10 @@ TEST_F(SingleOverlayOnTopTest, SuccessfullOverlay) { unsigned original_resource_id = original_quad->resource_id(); // Add something behind it. - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -366,7 +662,7 @@ TEST_F(SingleOverlayOnTopTest, SuccessfullOverlay) { overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - ASSERT_EQ(2U, candidate_list.size()); + ASSERT_EQ(1U, candidate_list.size()); RenderPass* main_pass = pass_list.back(); // Check that the quad is gone. @@ -384,12 +680,10 @@ TEST_F(SingleOverlayOnTopTest, SuccessfullOverlay) { TEST_F(SingleOverlayOnTopTest, NoCandidates) { scoped_ptr<RenderPass> pass = CreateRenderPass(); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -406,12 +700,10 @@ TEST_F(SingleOverlayOnTopTest, NoCandidates) { TEST_F(SingleOverlayOnTopTest, OccludedCandidates) { scoped_ptr<RenderPass> pass = CreateRenderPass(); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); CreateFullscreenCandidateQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), @@ -441,12 +733,10 @@ TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) { pass.get()); // Add something behind it. - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); pass_list.push_back(pass.Pass()); @@ -456,7 +746,7 @@ TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) { // Check for potential candidates. OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); - EXPECT_EQ(2U, candidate_list.size()); + EXPECT_EQ(1U, candidate_list.size()); // This should be the same. ASSERT_EQ(2U, pass_list.size()); @@ -556,6 +846,22 @@ TEST_F(SingleOverlayOnTopTest, RejectNonAxisAlignedTransform) { EXPECT_EQ(0U, candidate_list.size()); } +TEST_F(SingleOverlayOnTopTest, AllowClipped) { + scoped_ptr<RenderPass> pass = CreateRenderPass(); + CreateFullscreenCandidateQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), + pass.get()); + pass->shared_quad_state_list.back()->is_clipped = true; + pass->shared_quad_state_list.back()->clip_rect = kOverlayClipRect; + + 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(1U, candidate_list.size()); +} + TEST_F(SingleOverlayOnTopTest, AllowVerticalFlip) { gfx::Rect rect = kOverlayRect; rect.set_width(rect.width() / 2); @@ -571,7 +877,7 @@ TEST_F(SingleOverlayOnTopTest, AllowVerticalFlip) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - ASSERT_EQ(2U, candidate_list.size()); + ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL, candidate_list.back().transform); } @@ -591,7 +897,7 @@ TEST_F(SingleOverlayOnTopTest, AllowHorizontalFlip) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - ASSERT_EQ(2U, candidate_list.size()); + ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL, candidate_list.back().transform); } @@ -610,7 +916,7 @@ TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - EXPECT_EQ(2U, candidate_list.size()); + EXPECT_EQ(1U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, Allow90DegreeRotation) { @@ -627,7 +933,7 @@ TEST_F(SingleOverlayOnTopTest, Allow90DegreeRotation) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - ASSERT_EQ(2U, candidate_list.size()); + ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_90, candidate_list.back().transform); } @@ -645,7 +951,7 @@ TEST_F(SingleOverlayOnTopTest, Allow180DegreeRotation) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - ASSERT_EQ(2U, candidate_list.size()); + ASSERT_EQ(1U, candidate_list.size()); EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_180, candidate_list.back().transform); } @@ -663,16 +969,15 @@ TEST_F(SingleOverlayOnTopTest, Allow270DegreeRotation) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - ASSERT_EQ(2U, candidate_list.size()); + ASSERT_EQ(1U, 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(), - pass->shared_quad_state_list.back(), - pass.get(), - kOverlayTopLeftRect); + CreateOpaqueQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayTopLeftRect); CreateCandidateQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), @@ -687,7 +992,7 @@ TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); EXPECT_EQ(1U, pass_list.size()); - EXPECT_EQ(2U, candidate_list.size()); + EXPECT_EQ(1U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) { @@ -710,7 +1015,7 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); EXPECT_EQ(1U, pass_list.size()); - EXPECT_EQ(2U, candidate_list.size()); + EXPECT_EQ(1U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) { @@ -731,7 +1036,7 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); EXPECT_EQ(1U, pass_list.size()); - EXPECT_EQ(2U, candidate_list.size()); + EXPECT_EQ(1U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, RejectOpaqueColorOnTop) { @@ -803,7 +1108,7 @@ TEST_F(SingleOverlayOnTopTest, AllowVideoXMirrorTransform) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - EXPECT_EQ(2U, candidate_list.size()); + EXPECT_EQ(1U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, AllowVideoBothMirrorTransform) { @@ -817,7 +1122,7 @@ TEST_F(SingleOverlayOnTopTest, AllowVideoBothMirrorTransform) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - EXPECT_EQ(2U, candidate_list.size()); + EXPECT_EQ(1U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, AllowVideoNormalTransform) { @@ -831,7 +1136,7 @@ TEST_F(SingleOverlayOnTopTest, AllowVideoNormalTransform) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - EXPECT_EQ(2U, candidate_list.size()); + EXPECT_EQ(1U, candidate_list.size()); } TEST_F(SingleOverlayOnTopTest, AllowVideoYMirrorTransform) { @@ -845,14 +1150,13 @@ TEST_F(SingleOverlayOnTopTest, AllowVideoYMirrorTransform) { OverlayCandidateList candidate_list; overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list); ASSERT_EQ(1U, pass_list.size()); - EXPECT_EQ(2U, candidate_list.size()); + EXPECT_EQ(1U, candidate_list.size()); } TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) { scoped_ptr<RenderPass> pass = CreateRenderPass(); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); CreateCandidateQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect); @@ -863,9 +1167,8 @@ TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) { 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); + ASSERT_EQ(1U, candidate_list.size()); + EXPECT_EQ(-1, candidate_list[0].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); @@ -877,9 +1180,8 @@ TEST_F(UnderlayTest, AllowOnTop) { 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()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -887,13 +1189,63 @@ TEST_F(UnderlayTest, AllowOnTop) { 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); + ASSERT_EQ(1U, candidate_list.size()); + EXPECT_EQ(-1, candidate_list[0].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); } +TEST_F(AllOrNothingOverlayTest, SuccessfulOverlappingOverlays) { + scoped_ptr<RenderPass> pass = CreateRenderPass(); + + // Add two overlapping candidates. + CreateCandidateQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayTopLeftRect); + CreateCandidateQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayRect); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + OverlayCandidateList candidates; + overlay_processor_->ProcessForOverlays(&pass_list, &candidates); + + // Both quads should become overlays. + EXPECT_EQ(2u, candidates.size()); + EXPECT_EQ(-1, candidates[0].plane_z_order); + EXPECT_EQ(-2, candidates[1].plane_z_order); + EXPECT_EQ(gfx::RectF(kOverlayTopLeftRect), candidates[0].display_rect); + EXPECT_EQ(gfx::RectF(kOverlayRect), candidates[1].display_rect); + + // All quads should be gone. + EXPECT_TRUE(pass_list.back()->quad_list.empty()); +} + +TEST_F(AllOrNothingOverlayTest, RejectQuadWithTransform) { + scoped_ptr<RenderPass> pass = CreateRenderPass(); + + CreateCandidateQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayTopLeftRect); + + // Add a rotated quad that can't be promoted into overlay. + SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState(); + shared_state->opacity = 1.f; + shared_state->quad_to_target_transform.Rotate(90); + CreateSolidColorQuadAt(shared_state, SK_ColorBLACK, pass.get(), + kOverlayBottomRightRect); + + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + OverlayCandidateList candidates; + overlay_processor_->ProcessForOverlays(&pass_list, &candidates); + + // No quads should become overlays. + EXPECT_EQ(0u, candidates.size()); + EXPECT_EQ(2u, pass_list.back()->quad_list.size()); +} + class OverlayInfoRendererGL : public GLRenderer { public: OverlayInfoRendererGL(RendererClient* client, @@ -966,7 +1318,7 @@ class GLRendererWithOverlaysTest : public testing::Test { void Init(bool use_validator) { if (use_validator) - output_surface_->InitWithSingleOverlayValidator(); + output_surface_->SetOverlayCandidateValidator(new SingleOverlayValidator); renderer_ = make_scoped_ptr(new OverlayInfoRendererGL(&renderer_client_, @@ -999,12 +1351,10 @@ TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) { pass->shared_quad_state_list.back(), pass.get()); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -1013,11 +1363,13 @@ TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) { // so only draw 2 quads. EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(2); EXPECT_CALL(scheduler_, - Schedule(1, - gfx::OVERLAY_TRANSFORM_NONE, - _, - kOverlayRect, - BoundingRect(kUVTopLeft, kUVBottomRight))).Times(1); + Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _, + gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1))) + .Times(1); + 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(); @@ -1034,12 +1386,10 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadInUnderlay) { scoped_ptr<RenderPass> pass = CreateRenderPass(); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); CreateFullscreenCandidateQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), @@ -1052,8 +1402,13 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadInUnderlay) { // Expect to be replaced with transparent hole quad and placed in underlay. EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(3); EXPECT_CALL(scheduler_, + Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _, + gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1))) + .Times(1); + EXPECT_CALL(scheduler_, Schedule(-1, gfx::OVERLAY_TRANSFORM_NONE, _, kOverlayRect, - BoundingRect(kUVTopLeft, kUVBottomRight))).Times(1); + BoundingRect(kUVTopLeft, kUVBottomRight))) + .Times(1); renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false); SwapBuffers(); @@ -1074,23 +1429,20 @@ TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) { pass->shared_quad_state_list.back(), pass.get()); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); - CreateFullscreenCheckeredQuad(resource_provider_.get(), - pass->shared_quad_state_list.back(), - pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); + CreateFullscreenOpaqueQuad(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); - // Should see no overlays. + // Should not see the primary surface's overlay. + output_surface_->set_is_displayed_as_overlay_plane(false); EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(3); EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false); - SwapBuffers(); - Mock::VerifyAndClearExpectations(renderer_.get()); Mock::VerifyAndClearExpectations(&scheduler_); } @@ -1110,6 +1462,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturned) { DirectRenderer::DrawingFrame frame1; frame1.render_passes_in_draw_order = &pass_list; frame1.overlay_list.resize(2); + frame1.overlay_list.front().use_output_surface_for_resource = true; OverlayCandidate& overlay1 = frame1.overlay_list.back(); overlay1.resource_id = resource1; overlay1.plane_z_order = 1; @@ -1117,19 +1470,21 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturned) { DirectRenderer::DrawingFrame frame2; frame2.render_passes_in_draw_order = &pass_list; frame2.overlay_list.resize(2); + frame2.overlay_list.front().use_output_surface_for_resource = true; OverlayCandidate& overlay2 = frame2.overlay_list.back(); overlay2.resource_id = resource2; overlay2.plane_z_order = 1; - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); renderer_->BeginDrawingFrame(&frame1); + printf("About to finish, %d %d\n", resource1, resource2); renderer_->FinishDrawingFrame(&frame1); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2)); SwapBuffers(); Mock::VerifyAndClearExpectations(&scheduler_); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); renderer_->BeginDrawingFrame(&frame2); renderer_->FinishDrawingFrame(&frame2); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); @@ -1138,7 +1493,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturned) { EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); Mock::VerifyAndClearExpectations(&scheduler_); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); renderer_->BeginDrawingFrame(&frame1); renderer_->FinishDrawingFrame(&frame1); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); @@ -1162,14 +1517,14 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturned) { // Use the same buffer twice. renderer_->set_expect_overlays(true); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); renderer_->BeginDrawingFrame(&frame1); renderer_->FinishDrawingFrame(&frame1); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); SwapBuffers(); Mock::VerifyAndClearExpectations(&scheduler_); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); renderer_->BeginDrawingFrame(&frame1); renderer_->FinishDrawingFrame(&frame1); EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); @@ -1187,5 +1542,125 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturned) { Mock::VerifyAndClearExpectations(&scheduler_); } +TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { + bool use_validator = true; + settings_.delay_releasing_overlay_resources = true; + Init(use_validator); + renderer_->set_expect_overlays(true); + + ResourceId resource1 = CreateResource(resource_provider_.get()); + ResourceId resource2 = CreateResource(resource_provider_.get()); + ResourceId resource3 = CreateResource(resource_provider_.get()); + + scoped_ptr<RenderPass> pass = CreateRenderPass(); + RenderPassList pass_list; + pass_list.push_back(pass.Pass()); + + DirectRenderer::DrawingFrame frame1; + frame1.render_passes_in_draw_order = &pass_list; + frame1.overlay_list.resize(2); + frame1.overlay_list.front().use_output_surface_for_resource = true; + OverlayCandidate& overlay1 = frame1.overlay_list.back(); + overlay1.resource_id = resource1; + overlay1.plane_z_order = 1; + + DirectRenderer::DrawingFrame frame2; + frame2.render_passes_in_draw_order = &pass_list; + frame2.overlay_list.resize(2); + frame2.overlay_list.front().use_output_surface_for_resource = true; + OverlayCandidate& overlay2 = frame2.overlay_list.back(); + overlay2.resource_id = resource2; + overlay2.plane_z_order = 1; + + DirectRenderer::DrawingFrame frame3; + frame3.render_passes_in_draw_order = &pass_list; + frame3.overlay_list.resize(2); + frame3.overlay_list.front().use_output_surface_for_resource = true; + OverlayCandidate& overlay3 = frame3.overlay_list.back(); + overlay3.resource_id = resource3; + overlay3.plane_z_order = 1; + + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + renderer_->BeginDrawingFrame(&frame1); + renderer_->FinishDrawingFrame(&frame1); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2)); + SwapBuffers(); + Mock::VerifyAndClearExpectations(&scheduler_); + + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + renderer_->BeginDrawingFrame(&frame2); + renderer_->FinishDrawingFrame(&frame2); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); + SwapBuffers(); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); + Mock::VerifyAndClearExpectations(&scheduler_); + + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + renderer_->BeginDrawingFrame(&frame3); + renderer_->FinishDrawingFrame(&frame3); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); + SwapBuffers(); + EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); + Mock::VerifyAndClearExpectations(&scheduler_); + + // No overlays, release the resource. + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); + DirectRenderer::DrawingFrame frame_no_overlays; + frame_no_overlays.render_passes_in_draw_order = &pass_list; + renderer_->set_expect_overlays(false); + renderer_->BeginDrawingFrame(&frame_no_overlays); + renderer_->FinishDrawingFrame(&frame_no_overlays); + EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); + SwapBuffers(); + EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); + EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource3)); + Mock::VerifyAndClearExpectations(&scheduler_); + + // Use the same buffer twice. + renderer_->set_expect_overlays(true); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + renderer_->BeginDrawingFrame(&frame1); + renderer_->FinishDrawingFrame(&frame1); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + SwapBuffers(); + Mock::VerifyAndClearExpectations(&scheduler_); + + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + renderer_->BeginDrawingFrame(&frame1); + renderer_->FinishDrawingFrame(&frame1); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + SwapBuffers(); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + Mock::VerifyAndClearExpectations(&scheduler_); + + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); + renderer_->set_expect_overlays(false); + renderer_->BeginDrawingFrame(&frame_no_overlays); + renderer_->FinishDrawingFrame(&frame_no_overlays); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + SwapBuffers(); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + Mock::VerifyAndClearExpectations(&scheduler_); + + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); + renderer_->set_expect_overlays(false); + renderer_->BeginDrawingFrame(&frame_no_overlays); + renderer_->FinishDrawingFrame(&frame_no_overlays); + EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1)); + SwapBuffers(); + EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1)); + Mock::VerifyAndClearExpectations(&scheduler_); +} + } // namespace } // namespace cc diff --git a/chromium/cc/output/renderer.h b/chromium/cc/output/renderer.h index 8143e2a0410..96406a23fb2 100644 --- a/chromium/cc/output/renderer.h +++ b/chromium/cc/output/renderer.h @@ -73,8 +73,6 @@ class CC_EXPORT Renderer { // Waits for rendering to finish. virtual void Finish() = 0; - virtual void DoNoOp() {} - // Puts backbuffer onscreen. virtual void SwapBuffers(const CompositorFrameMetadata& metadata) = 0; virtual void ReceiveSwapBuffersAck(const CompositorFrameAck& ack) {} diff --git a/chromium/cc/output/renderer_pixeltest.cc b/chromium/cc/output/renderer_pixeltest.cc index 8472ff50613..76fb2c3811d 100644 --- a/chromium/cc/output/renderer_pixeltest.cc +++ b/chromium/cc/output/renderer_pixeltest.cc @@ -8,13 +8,15 @@ #include "cc/quads/picture_draw_quad.h" #include "cc/quads/texture_draw_quad.h" #include "cc/resources/video_resource_updater.h" -#include "cc/test/fake_picture_pile_impl.h" +#include "cc/test/fake_display_list_raster_source.h" +#include "cc/test/fake_display_list_recording_source.h" #include "cc/test/pixel_test.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "media/base/video_frame.h" #include "third_party/skia/include/core/SkColorPriv.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/effects/SkColorFilterImageFilter.h" #include "third_party/skia/include/effects/SkColorMatrixFilter.h" #include "ui/gfx/geometry/rect_conversions.h" @@ -190,12 +192,12 @@ void CreateTestYUVVideoDrawQuad_FromVideoFrame( const gfx::Rect& rect, const gfx::Rect& visible_rect, ResourceProvider* resource_provider) { - const bool with_alpha = (video_frame->format() == media::VideoFrame::YV12A); + const bool with_alpha = (video_frame->format() == media::PIXEL_FORMAT_YV12A); YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601; int video_frame_color_space; if (video_frame->metadata()->GetInteger( media::VideoFrameMetadata::COLOR_SPACE, &video_frame_color_space) && - video_frame_color_space == media::VideoFrame::COLOR_SPACE_JPEG) { + video_frame_color_space == media::COLOR_SPACE_JPEG) { color_space = YUVVideoDrawQuad::JPEG; } @@ -269,7 +271,7 @@ void CreateTestYUVVideoDrawQuad_FromVideoFrame( void CreateTestYUVVideoDrawQuad_Striped( const SharedQuadState* shared_state, - media::VideoFrame::Format format, + media::VideoPixelFormat format, bool is_transparent, const gfx::RectF& tex_coord_rect, RenderPass* render_pass, @@ -316,8 +318,8 @@ void CreateTestYUVVideoDrawQuad_Striped( // by 2 because YUV is a block format. void CreateTestYUVVideoDrawQuad_TwoColor( const SharedQuadState* shared_state, - media::VideoFrame::Format format, - media::VideoFrame::ColorSpace color_space, + media::VideoPixelFormat format, + media::ColorSpace color_space, bool is_transparent, const gfx::RectF& tex_coord_rect, const gfx::Size& background_size, @@ -380,8 +382,8 @@ void CreateTestYUVVideoDrawQuad_TwoColor( void CreateTestYUVVideoDrawQuad_Solid( const SharedQuadState* shared_state, - media::VideoFrame::Format format, - media::VideoFrame::ColorSpace color_space, + media::VideoPixelFormat format, + media::ColorSpace color_space, bool is_transparent, const gfx::RectF& tex_coord_rect, uint8 y, @@ -749,11 +751,11 @@ TYPED_TEST(IntersectingQuadPixelTest, TexturedQuads) { 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); + gfx::Rect outer_rect(this->quad_rect_); + gfx::Rect 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); @@ -762,37 +764,40 @@ TYPED_TEST(IntersectingQuadSoftwareTest, PictureQuads) { SkPaint green_paint; green_paint.setColor(SK_ColorGREEN); - scoped_ptr<FakePicturePile> blue_recording = - FakePicturePile::CreateFilledPile(gfx::Size(1000, 1000), - this->quad_rect_.size()); + scoped_ptr<FakeDisplayListRecordingSource> blue_recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + 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); + scoped_refptr<FakeDisplayListRasterSource> blue_raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource( + blue_recording.get(), false); 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); + this->quad_rect_, gfx::RectF(this->quad_rect_), + this->quad_rect_.size(), false, RGBA_8888, this->quad_rect_, + 1.f, blue_raster_source); - scoped_ptr<FakePicturePile> green_recording = - FakePicturePile::CreateFilledPile(this->quad_rect_.size(), - this->quad_rect_.size()); + scoped_ptr<FakeDisplayListRecordingSource> green_recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + 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); + scoped_refptr<FakeDisplayListRasterSource> green_raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource( + green_recording.get(), false); 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_, gfx::RectF(this->quad_rect_), this->quad_rect_.size(), false, RGBA_8888, - this->quad_rect_, 1.f, green_pile); + this->quad_rect_, 1.f, green_raster_source); SCOPED_TRACE("IntersectingPictureQuadsPass"); this->template AppendBackgroundAndRunTest<PictureDrawQuad>( FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f)); @@ -843,17 +848,15 @@ TYPED_TEST(IntersectingQuadGLPixelTest, YUVVideoQuads) { (this->quad_rect_.height() / 2) & ~0xF); CreateTestYUVVideoDrawQuad_TwoColor( - this->front_quad_state_, media::VideoFrame::YV12, - media::VideoFrame::COLOR_SPACE_JPEG, 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->front_quad_state_, media::PIXEL_FORMAT_YV12, + media::COLOR_SPACE_JPEG, 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::YV12, - media::VideoFrame::COLOR_SPACE_JPEG, false, - gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(), + this->back_quad_state_, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_JPEG, + 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()); @@ -930,8 +933,8 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) { class VideoGLRendererPixelTest : public GLRendererPixelTest { protected: - void CreateEdgeBleedPass(media::VideoFrame::Format format, - media::VideoFrame::ColorSpace color_space, + void CreateEdgeBleedPass(media::VideoPixelFormat format, + media::ColorSpace color_space, RenderPassList* pass_list) { gfx::Rect rect(200, 200); @@ -985,7 +988,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) { SharedQuadState* shared_state = CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); - CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12, + CreateTestYUVVideoDrawQuad_Striped(shared_state, media::PIXEL_FORMAT_YV12, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get()); @@ -1010,7 +1013,7 @@ TEST_F(VideoGLRendererPixelTest, ClippedYUVRect) { SharedQuadState* shared_state = CreateTestSharedQuadState(gfx::Transform(), viewport, pass.get()); - CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12, + CreateTestYUVVideoDrawQuad_Striped(shared_state, media::PIXEL_FORMAT_YV12, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), video_resource_updater_.get(), draw_rect, viewport, @@ -1034,7 +1037,7 @@ TEST_F(VideoGLRendererPixelTest, OffsetYUVRect) { // Intentionally sets frame format to I420 for testing coverage. CreateTestYUVVideoDrawQuad_Striped( - shared_state, media::VideoFrame::I420, false, + shared_state, media::PIXEL_FORMAT_I420, false, gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f), pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get()); @@ -1058,9 +1061,8 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVRectBlack) { // In MPEG color range YUV values of (15,128,128) should produce black. CreateTestYUVVideoDrawQuad_Solid( - shared_state, media::VideoFrame::YV12, - media::VideoFrame::COLOR_SPACE_UNSPECIFIED, false, - gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(), + shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_UNSPECIFIED, + 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; @@ -1084,8 +1086,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) { // YUV of (149,43,21) should be green (0,255,0) in RGB. CreateTestYUVVideoDrawQuad_Solid( - shared_state, media::VideoFrame::YV12, - media::VideoFrame::COLOR_SPACE_JPEG, false, + shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_JPEG, 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()); @@ -1101,8 +1102,8 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) { // tex coord rect is only a partial subrectangle of the coded contents. TEST_F(VideoGLRendererPixelTest, YUVEdgeBleed) { RenderPassList pass_list; - CreateEdgeBleedPass(media::VideoFrame::YV12, - media::VideoFrame::COLOR_SPACE_JPEG, &pass_list); + CreateEdgeBleedPass(media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_JPEG, + &pass_list); EXPECT_TRUE(this->RunPixelTest(&pass_list, base::FilePath(FILE_PATH_LITERAL("green.png")), FuzzyPixelOffByOneComparator(true))); @@ -1110,8 +1111,8 @@ TEST_F(VideoGLRendererPixelTest, YUVEdgeBleed) { TEST_F(VideoGLRendererPixelTest, YUVAEdgeBleed) { RenderPassList pass_list; - CreateEdgeBleedPass(media::VideoFrame::YV12A, - media::VideoFrame::COLOR_SPACE_UNSPECIFIED, &pass_list); + CreateEdgeBleedPass(media::PIXEL_FORMAT_YV12A, media::COLOR_SPACE_UNSPECIFIED, + &pass_list); EXPECT_TRUE(this->RunPixelTest(&pass_list, base::FilePath(FILE_PATH_LITERAL("green.png")), FuzzyPixelOffByOneComparator(true))); @@ -1128,8 +1129,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) { // Dark grey in JPEG color range (in MPEG, this is black). CreateTestYUVVideoDrawQuad_Solid( - shared_state, media::VideoFrame::YV12, - media::VideoFrame::COLOR_SPACE_JPEG, false, + shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_JPEG, 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()); @@ -1151,7 +1151,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVARect) { SharedQuadState* shared_state = CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); - CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12A, + CreateTestYUVVideoDrawQuad_Striped(shared_state, media::PIXEL_FORMAT_YV12A, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get()); @@ -1178,7 +1178,7 @@ TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) { SharedQuadState* shared_state = CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); - CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12A, + CreateTestYUVVideoDrawQuad_Striped(shared_state, media::PIXEL_FORMAT_YV12A, true, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get()); @@ -2174,7 +2174,6 @@ TEST_F(GLRendererPixelTest, AntiAliasingPerspective) { } 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; @@ -2190,8 +2189,9 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadIdentityScale) { gfx::Rect blue_rect(gfx::Size(100, 100)); gfx::Rect blue_clip_rect(gfx::Point(50, 50), gfx::Size(50, 50)); - scoped_ptr<FakePicturePile> blue_recording = - FakePicturePile::CreateFilledPile(pile_tile_size, blue_rect.size()); + scoped_ptr<FakeDisplayListRecordingSource> blue_recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + blue_rect.size()); SkPaint red_paint; red_paint.setColor(SK_ColorRED); blue_recording->add_draw_rect_with_paint(blue_rect, red_paint); @@ -2200,17 +2200,18 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadIdentityScale) { 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); + scoped_refptr<FakeDisplayListRasterSource> blue_raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource( + blue_recording.get(), false); - gfx::Transform blue_quad_to_target_transform; gfx::Vector2d offset(viewport.bottom_right() - blue_rect.bottom_right()); + gfx::Transform blue_quad_to_target_transform; blue_quad_to_target_transform.Translate(offset.x(), offset.y()); - gfx::RectF blue_scissor_rect = blue_clip_rect; - blue_quad_to_target_transform.TransformRect(&blue_scissor_rect); - SharedQuadState* blue_shared_state = CreateTestSharedQuadStateClipped( - blue_quad_to_target_transform, blue_rect, - gfx::ToEnclosingRect(blue_scissor_rect), pass.get()); + gfx::Rect blue_target_clip_rect = MathUtil::MapEnclosingClippedRect( + blue_quad_to_target_transform, blue_clip_rect); + SharedQuadState* blue_shared_state = + CreateTestSharedQuadStateClipped(blue_quad_to_target_transform, blue_rect, + blue_target_clip_rect, pass.get()); PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); @@ -2218,17 +2219,19 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadIdentityScale) { viewport, // Intentionally bigger than clip. gfx::Rect(), viewport, gfx::RectF(viewport), viewport.size(), nearest_neighbor, texture_format, viewport, - 1.f, blue_pile.get()); + 1.f, blue_raster_source.Pass()); // One viewport-filling green quad. - scoped_ptr<FakePicturePile> green_recording = - FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size()); + scoped_ptr<FakeDisplayListRecordingSource> green_recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + viewport.size()); SkPaint green_paint; green_paint.setColor(SK_ColorGREEN); green_recording->add_draw_rect_with_paint(viewport, green_paint); green_recording->Rerecord(); - scoped_refptr<FakePicturePileImpl> green_pile = - FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr); + scoped_refptr<FakeDisplayListRasterSource> green_raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource( + green_recording.get(), false); gfx::Transform green_quad_to_target_transform; SharedQuadState* green_shared_state = CreateTestSharedQuadState( @@ -2239,7 +2242,7 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadIdentityScale) { green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport, gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(), nearest_neighbor, texture_format, viewport, 1.f, - green_pile.get()); + green_raster_source.Pass()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -2252,7 +2255,6 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadIdentityScale) { // Not WithSkiaGPUBackend since that path currently requires tiles for opacity. 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; @@ -2263,14 +2265,16 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadOpacity) { CreateTestRenderPass(id, viewport, transform_to_root); // One viewport-filling 0.5-opacity green quad. - scoped_ptr<FakePicturePile> green_recording = - FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size()); + scoped_ptr<FakeDisplayListRecordingSource> green_recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + viewport.size()); SkPaint green_paint; green_paint.setColor(SK_ColorGREEN); green_recording->add_draw_rect_with_paint(viewport, green_paint); green_recording->Rerecord(); - scoped_refptr<FakePicturePileImpl> green_pile = - FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr); + scoped_refptr<FakeDisplayListRasterSource> green_raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource( + green_recording.get(), false); gfx::Transform green_quad_to_target_transform; SharedQuadState* green_shared_state = CreateTestSharedQuadState( @@ -2281,17 +2285,19 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadOpacity) { pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport, gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor, - texture_format, viewport, 1.f, green_pile.get()); + texture_format, viewport, 1.f, green_raster_source.get()); // One viewport-filling white quad. - scoped_ptr<FakePicturePile> white_recording = - FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size()); + scoped_ptr<FakeDisplayListRecordingSource> white_recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + viewport.size()); SkPaint white_paint; white_paint.setColor(SK_ColorWHITE); white_recording->add_draw_rect_with_paint(viewport, white_paint); white_recording->Rerecord(); - scoped_refptr<FakePicturePileImpl> white_pile = - FakePicturePileImpl::CreateFromPile(white_recording.get(), nullptr); + scoped_refptr<FakeDisplayListRasterSource> white_raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource( + white_recording.get(), false); gfx::Transform white_quad_to_target_transform; SharedQuadState* white_shared_state = CreateTestSharedQuadState( @@ -2301,7 +2307,7 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadOpacity) { pass->CreateAndAppendDrawQuad<PictureDrawQuad>(); white_quad->SetNew(white_shared_state, viewport, gfx::Rect(), viewport, gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor, - texture_format, viewport, 1.f, white_pile.get()); + texture_format, viewport, 1.f, white_raster_source.Pass()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -2334,7 +2340,6 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadDisableImageFiltering) { if (!IsSoftwareRenderer<TypeParam>()) return; - gfx::Size pile_tile_size(1000, 1000); gfx::Rect viewport(this->device_viewport_size_); ResourceFormat texture_format = RGBA_8888; bool nearest_neighbor = false; @@ -2344,25 +2349,26 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadDisableImageFiltering) { 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()); + skia::RefPtr<SkSurface> surface = + skia::AdoptRef(SkSurface::NewRasterN32Premul(2, 2)); + ASSERT_NE(surface, nullptr); + SkCanvas* canvas = surface->getCanvas(); + canvas->drawPoint(0, 0, SK_ColorGREEN); + canvas->drawPoint(0, 1, SK_ColorBLUE); + canvas->drawPoint(1, 0, SK_ColorBLUE); + canvas->drawPoint(1, 1, SK_ColorGREEN); + skia::RefPtr<SkImage> image = skia::AdoptRef(surface->newImageSnapshot()); + + scoped_ptr<FakeDisplayListRecordingSource> recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + viewport.size()); SkPaint paint; paint.setFilterQuality(kLow_SkFilterQuality); - recording->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint); + recording->add_draw_image_with_paint(image.get(), gfx::Point(), paint); recording->Rerecord(); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFromPile(recording.get(), nullptr); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource(recording.get(), + false); gfx::Transform quad_to_target_transform; SharedQuadState* shared_state = @@ -2371,7 +2377,7 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadDisableImageFiltering) { 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()); + texture_format, viewport, 1.f, raster_source.Pass()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -2386,7 +2392,6 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadDisableImageFiltering) { // 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; @@ -2396,25 +2401,26 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNearestNeighbor) { 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()); + skia::RefPtr<SkSurface> surface = + skia::AdoptRef(SkSurface::NewRasterN32Premul(2, 2)); + ASSERT_NE(surface, nullptr); + SkCanvas* canvas = surface->getCanvas(); + canvas->drawPoint(0, 0, SK_ColorGREEN); + canvas->drawPoint(0, 1, SK_ColorBLUE); + canvas->drawPoint(1, 0, SK_ColorBLUE); + canvas->drawPoint(1, 1, SK_ColorGREEN); + skia::RefPtr<SkImage> image = skia::AdoptRef(surface->newImageSnapshot()); + + scoped_ptr<FakeDisplayListRecordingSource> recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + viewport.size()); SkPaint paint; paint.setFilterQuality(kLow_SkFilterQuality); - recording->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint); + recording->add_draw_image_with_paint(image.get(), gfx::Point(), paint); recording->Rerecord(); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFromPile(recording.get(), nullptr); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource(recording.get(), + false); gfx::Transform quad_to_target_transform; SharedQuadState* shared_state = @@ -2423,7 +2429,7 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNearestNeighbor) { 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()); + texture_format, viewport, 1.f, raster_source.Pass()); RenderPassList pass_list; pass_list.push_back(pass.Pass()); @@ -2473,7 +2479,7 @@ TYPED_TEST(RendererPixelTest, TileDrawQuadNearestNeighbor) { TileDrawQuad* quad = pass->CreateAndAppendDrawQuad<TileDrawQuad>(); quad->SetNew(shared_state, viewport, gfx::Rect(), viewport, resource, - gfx::Rect(tile_size), tile_size, swizzle_contents, + gfx::RectF(gfx::Rect(tile_size)), tile_size, swizzle_contents, nearest_neighbor); RenderPassList pass_list; @@ -2592,7 +2598,6 @@ TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadLinear) { } 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; @@ -2611,8 +2616,9 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) { 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_ptr<FakePicturePile> green_recording = - FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size()); + scoped_ptr<FakeDisplayListRecordingSource> green_recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + viewport.size()); SkPaint red_paint; red_paint.setColor(SK_ColorRED); @@ -2622,8 +2628,9 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) { 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); + scoped_refptr<FakeDisplayListRasterSource> green_raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource( + green_recording.get(), false); SharedQuadState* top_right_green_shared_quad_state = CreateTestSharedQuadState(green_quad_to_target_transform, viewport, @@ -2631,17 +2638,18 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) { PictureDrawQuad* green_quad1 = 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(), nearest_neighbor, texture_format, - green_rect1, 1.f, green_pile.get()); + green_quad1->SetNew( + top_right_green_shared_quad_state, green_rect1, gfx::Rect(), green_rect1, + gfx::RectF(gfx::SizeF(green_rect1.size())), green_rect1.size(), + nearest_neighbor, texture_format, green_rect1, 1.f, green_raster_source); 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()), + gfx::Rect(), green_rect2, + gfx::RectF(gfx::SizeF(green_rect2.size())), green_rect2.size(), nearest_neighbor, texture_format, - green_rect2, 1.f, green_pile.get()); + green_rect2, 1.f, green_raster_source.Pass()); // Add a green clipped checkerboard in the bottom right to help test // interleaving picture quad content and solid color content. @@ -2676,8 +2684,9 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) { blue_layer_rect1.Inset(inset, inset, inset, inset); blue_layer_rect2.Inset(inset, inset, inset, inset); - scoped_ptr<FakePicturePile> recording = - FakePicturePile::CreateFilledPile(pile_tile_size, layer_rect.size()); + scoped_ptr<FakeDisplayListRecordingSource> recording = + FakeDisplayListRecordingSource::CreateFilledRecordingSource( + layer_rect.size()); Region outside(layer_rect); outside.Subtract(gfx::ToEnclosingRect(union_layer_rect)); @@ -2687,11 +2696,12 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) { SkPaint blue_paint; blue_paint.setColor(SK_ColorBLUE); - recording->add_draw_rect_with_paint(blue_layer_rect1, blue_paint); - recording->add_draw_rect_with_paint(blue_layer_rect2, blue_paint); + recording->add_draw_rectf_with_paint(blue_layer_rect1, blue_paint); + recording->add_draw_rectf_with_paint(blue_layer_rect2, blue_paint); recording->Rerecord(); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFromPile(recording.get(), nullptr); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFromRecordingSource(recording.get(), + false); gfx::Rect content_rect( gfx::ScaleToEnclosingRect(layer_rect, contents_scale)); @@ -2710,7 +2720,7 @@ TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) { blue_quad->SetNew(blue_shared_state, quad_content_rect, gfx::Rect(), quad_content_rect, gfx::RectF(quad_content_rect), content_union_rect.size(), nearest_neighbor, texture_format, - content_union_rect, contents_scale, pile.get()); + content_union_rect, contents_scale, raster_source.Pass()); // Fill left half of viewport with green. gfx::Transform half_green_quad_to_target_transform; @@ -2942,109 +2952,6 @@ 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 index 0c0a10d1e01..35415f19866 100644 --- a/chromium/cc/output/renderer_settings.cc +++ b/chromium/cc/output/renderer_settings.cc @@ -17,12 +17,12 @@ RendererSettings::RendererSettings() partial_swap_enabled(false), finish_rendering_on_resize(false), should_clear_root_render_pass(true), - disable_gpu_vsync(false), + disable_display_vsync(false), + delay_releasing_overlay_resources(false), refresh_rate(60.0), highp_threshold_min(0), use_rgba_4444_textures(false), - texture_id_allocation_chunk_size(64) { -} + texture_id_allocation_chunk_size(64) {} RendererSettings::~RendererSettings() { } diff --git a/chromium/cc/output/renderer_settings.h b/chromium/cc/output/renderer_settings.h index 4757f8d5571..48aa13d0054 100644 --- a/chromium/cc/output/renderer_settings.h +++ b/chromium/cc/output/renderer_settings.h @@ -21,7 +21,8 @@ class CC_EXPORT RendererSettings { bool partial_swap_enabled; bool finish_rendering_on_resize; bool should_clear_root_render_pass; - bool disable_gpu_vsync; + bool disable_display_vsync; + bool delay_releasing_overlay_resources; double refresh_rate; int highp_threshold_min; bool use_rgba_4444_textures; diff --git a/chromium/cc/output/shader.cc b/chromium/cc/output/shader.cc index 15ad7e05fa7..a4ee1bbfc6b 100644 --- a/chromium/cc/output/shader.cc +++ b/chromium/cc/output/shader.cc @@ -772,7 +772,7 @@ FragmentTexBlendMode::FragmentTexBlendMode() } std::string FragmentTexBlendMode::SetBlendModeFunctions( - std::string shader_string) const { + const std::string& shader_string) const { if (shader_string.find("ApplyBlendMode") == std::string::npos) return shader_string; @@ -2253,64 +2253,4 @@ std::string FragmentShaderColorAA::GetShaderBody() { }); } -FragmentShaderCheckerboard::FragmentShaderCheckerboard() - : alpha_location_(-1), - tex_transform_location_(-1), - frequency_location_(-1) { -} - -void FragmentShaderCheckerboard::Init(GLES2Interface* context, - unsigned program, - int* base_uniform_index) { - static const char* uniforms[] = { - "alpha", "texTransform", "frequency", "color", - }; - int locations[arraysize(uniforms)]; - - GetProgramUniformLocations(context, - program, - arraysize(uniforms), - uniforms, - locations, - base_uniform_index); - alpha_location_ = locations[0]; - tex_transform_location_ = locations[1]; - frequency_location_ = locations[2]; - color_location_ = locations[3]; -} - -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. - 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 d692a123cd7..448ff07a8b2 100644 --- a/chromium/cc/output/shader.h +++ b/chromium/cc/output/shader.h @@ -371,7 +371,7 @@ class FragmentTexBlendMode { protected: FragmentTexBlendMode(); - std::string SetBlendModeFunctions(std::string shader_string) const; + std::string SetBlendModeFunctions(const std::string& shader_string) const; int backdrop_location_; int original_backdrop_location_; @@ -868,31 +868,6 @@ class FragmentShaderColorAA : public FragmentTexBlendMode { DISALLOW_COPY_AND_ASSIGN(FragmentShaderColorAA); }; -class FragmentShaderCheckerboard : public FragmentTexBlendMode { - public: - 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, - int* base_uniform_index); - int alpha_location() const { return alpha_location_; } - int tex_transform_location() const { return tex_transform_location_; } - int frequency_location() const { return frequency_location_; } - int color_location() const { return color_location_; } - - private: - int alpha_location_; - int tex_transform_location_; - int frequency_location_; - int color_location_; - - DISALLOW_COPY_AND_ASSIGN(FragmentShaderCheckerboard); -}; - } // namespace cc #endif // CC_OUTPUT_SHADER_H_ diff --git a/chromium/cc/output/software_frame_data.cc b/chromium/cc/output/software_frame_data.cc deleted file mode 100644 index 7fc380e7b64..00000000000 --- a/chromium/cc/output/software_frame_data.cc +++ /dev/null @@ -1,13 +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/output/software_frame_data.h" - -namespace cc { - -SoftwareFrameData::SoftwareFrameData() : id(0) {} - -SoftwareFrameData::~SoftwareFrameData() {} - -} // namespace cc diff --git a/chromium/cc/output/software_frame_data.h b/chromium/cc/output/software_frame_data.h deleted file mode 100644 index 9cb74efa6e9..00000000000 --- a/chromium/cc/output/software_frame_data.h +++ /dev/null @@ -1,28 +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_OUTPUT_SOFTWARE_FRAME_DATA_H_ -#define CC_OUTPUT_SOFTWARE_FRAME_DATA_H_ - -#include "cc/base/cc_export.h" -#include "cc/resources/shared_bitmap.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" - -namespace cc { - -class CC_EXPORT SoftwareFrameData { - public: - SoftwareFrameData(); - ~SoftwareFrameData(); - - unsigned id; - gfx::Size size; - gfx::Rect damage_rect; - SharedBitmapId bitmap_id; -}; - -} // namespace cc - -#endif // CC_OUTPUT_SOFTWARE_FRAME_DATA_H_ diff --git a/chromium/cc/output/software_output_device.cc b/chromium/cc/output/software_output_device.cc index 3692224679d..07129387ad0 100644 --- a/chromium/cc/output/software_output_device.cc +++ b/chromium/cc/output/software_output_device.cc @@ -5,7 +5,6 @@ #include "cc/output/software_output_device.h" #include "base/logging.h" -#include "cc/output/software_frame_data.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/vsync_provider.h" @@ -31,21 +30,11 @@ void SoftwareOutputDevice::Resize(const gfx::Size& viewport_pixel_size, } SkCanvas* SoftwareOutputDevice::BeginPaint(const gfx::Rect& damage_rect) { - DCHECK(surface_); damage_rect_ = damage_rect; - return surface_->getCanvas(); + return surface_ ? surface_->getCanvas() : nullptr; } -void SoftwareOutputDevice::EndPaint(SoftwareFrameData* frame_data) { - DCHECK(frame_data); - frame_data->id = 0; - frame_data->size = viewport_pixel_size_; - frame_data->damage_rect = damage_rect_; -} - -void SoftwareOutputDevice::ReclaimSoftwareFrame(unsigned id) { - NOTIMPLEMENTED(); -} +void SoftwareOutputDevice::EndPaint() {} gfx::VSyncProvider* SoftwareOutputDevice::GetVSyncProvider() { return vsync_provider_.get(); diff --git a/chromium/cc/output/software_output_device.h b/chromium/cc/output/software_output_device.h index 45ce83117c7..127c70a5fae 100644 --- a/chromium/cc/output/software_output_device.h +++ b/chromium/cc/output/software_output_device.h @@ -23,8 +23,6 @@ class VSyncProvider; namespace cc { -class SoftwareFrameData; - // This is a "tear-off" class providing software drawing support to // OutputSurface, such as to a platform-provided window framebuffer. class CC_EXPORT SoftwareOutputDevice { @@ -46,7 +44,7 @@ class CC_EXPORT SoftwareOutputDevice { // Called on FinishDrawingFrame. The compositor will no longer mutate the the // SkCanvas instance returned by |BeginPaint| and should discard any reference // that it holds to it. - virtual void EndPaint(SoftwareFrameData* frame_data); + virtual void EndPaint(); // Discard the backing buffer in the surface provided by this instance. virtual void DiscardBackbuffer() {} @@ -54,12 +52,6 @@ class CC_EXPORT SoftwareOutputDevice { // Ensures that there is a backing buffer available on this instance. virtual void EnsureBackbuffer() {} - // TODO(skaslev) Remove this after UberCompositor lands. - // Called in response to receiving a SwapBuffersAck. At this point, software - // frame identified by id can be reused or discarded as it is no longer being - // displayed. - virtual void ReclaimSoftwareFrame(unsigned id); - // VSyncProvider used to update the timer used to schedule draws with the // hardware vsync. Return NULL if a provider doesn't exist. virtual gfx::VSyncProvider* GetVSyncProvider(); diff --git a/chromium/cc/output/software_renderer.cc b/chromium/cc/output/software_renderer.cc index a8110efb4dc..ea980a854f6 100644 --- a/chromium/cc/output/software_renderer.cc +++ b/chromium/cc/output/software_renderer.cc @@ -13,7 +13,6 @@ #include "cc/output/output_surface.h" #include "cc/output/render_surface_filters.h" #include "cc/output/software_output_device.h" -#include "cc/quads/checkerboard_draw_quad.h" #include "cc/quads/debug_border_draw_quad.h" #include "cc/quads/picture_draw_quad.h" #include "cc/quads/render_pass_draw_quad.h" @@ -25,6 +24,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/SkPath.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" @@ -102,8 +102,7 @@ const RendererCapabilitiesImpl& SoftwareRenderer::Capabilities() const { void SoftwareRenderer::BeginDrawingFrame(DrawingFrame* frame) { TRACE_EVENT0("cc", "SoftwareRenderer::BeginDrawingFrame"); - root_canvas_ = output_device_->BeginPaint( - gfx::ToEnclosingRect(frame->root_damage_rect)); + root_canvas_ = output_device_->BeginPaint(frame->root_damage_rect); } void SoftwareRenderer::FinishDrawingFrame(DrawingFrame* frame) { @@ -113,22 +112,16 @@ void SoftwareRenderer::FinishDrawingFrame(DrawingFrame* frame) { current_canvas_ = NULL; root_canvas_ = NULL; - current_frame_data_.reset(new SoftwareFrameData); - output_device_->EndPaint(current_frame_data_.get()); + output_device_->EndPaint(); } void SoftwareRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) { TRACE_EVENT0("cc,benchmark", "SoftwareRenderer::SwapBuffers"); CompositorFrame compositor_frame; compositor_frame.metadata = metadata; - compositor_frame.software_frame_data = current_frame_data_.Pass(); output_surface_->SwapBuffers(&compositor_frame); } -void SoftwareRenderer::ReceiveSwapBuffersAck(const CompositorFrameAck& ack) { - output_device_->ReclaimSoftwareFrame(ack.last_software_frame_id); -} - bool SoftwareRenderer::FlippedFramebuffer(const DrawingFrame* frame) const { return false; } @@ -143,6 +136,8 @@ void SoftwareRenderer::EnsureScissorTestDisabled() { // rendering, but the underlying effect we want is to clear any existing // clipRect on the current SkCanvas. This is done by setting clipRect to // the viewport's dimensions. + if (!current_canvas_) + return; is_scissor_enabled_ = false; SkISize size = current_canvas_->getDeviceSize(); SetClipRect(gfx::Rect(size.width(), size.height())); @@ -182,6 +177,8 @@ void SoftwareRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) { } void SoftwareRenderer::SetClipRect(const gfx::Rect& rect) { + if (!current_canvas_) + return; // Skia applies the current matrix to clip rects so we reset it temporary. SkMatrix current_matrix = current_canvas_->getTotalMatrix(); current_canvas_->resetMatrix(); @@ -190,6 +187,8 @@ void SoftwareRenderer::SetClipRect(const gfx::Rect& rect) { } void SoftwareRenderer::ClearCanvas(SkColor color) { + if (!current_canvas_) + return; // SkCanvas::clear doesn't respect the current clipping region // so we SkCanvas::drawColor instead if scissoring is active. if (is_scissor_enabled_) @@ -244,6 +243,8 @@ bool SoftwareRenderer::IsSoftwareResource(ResourceId resource_id) const { void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad, const gfx::QuadF* draw_region) { + if (!current_canvas_) + return; if (draw_region) { current_canvas_->save(); } @@ -252,7 +253,7 @@ void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, gfx::Transform quad_rect_matrix; QuadRectTransform(&quad_rect_matrix, quad->shared_quad_state->quad_to_target_transform, - quad->rect); + gfx::RectF(quad->rect)); gfx::Transform contents_device_transform = frame->window_matrix * frame->projection_matrix * quad_rect_matrix; contents_device_transform.FlattenTo2d(); @@ -302,14 +303,6 @@ void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, } switch (quad->material) { - case DrawQuad::CHECKERBOARD: - // 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)); break; @@ -348,16 +341,6 @@ void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, } } -void SoftwareRenderer::DrawCheckerboardQuad(const DrawingFrame* frame, - const CheckerboardDrawQuad* quad) { - gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( - QuadVertexRect(), quad->rect, quad->visible_rect); - current_paint_.setColor(quad->color); - current_paint_.setAlpha(quad->shared_quad_state->opacity); - current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect), - current_paint_); -} - void SoftwareRenderer::DrawDebugBorderQuad(const DrawingFrame* frame, const DebugBorderDrawQuad* quad) { // We need to apply the matrix manually to have pixel-sized stroke width. @@ -412,7 +395,7 @@ void SoftwareRenderer::DrawPictureQuad(const DrawingFrame* frame, void SoftwareRenderer::DrawSolidColorQuad(const DrawingFrame* frame, const SolidColorDrawQuad* quad) { gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( - QuadVertexRect(), quad->rect, quad->visible_rect); + QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect)); current_paint_.setColor(quad->color); current_paint_.setAlpha(quad->shared_quad_state->opacity * SkColorGetA(quad->color)); @@ -437,11 +420,11 @@ void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame, quad->uv_bottom_right), bitmap->width(), bitmap->height()); - gfx::RectF visible_uv_rect = - MathUtil::ScaleRectProportional(uv_rect, quad->rect, quad->visible_rect); + gfx::RectF visible_uv_rect = MathUtil::ScaleRectProportional( + uv_rect, gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect)); SkRect sk_uv_rect = gfx::RectFToSkRect(visible_uv_rect); gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( - QuadVertexRect(), quad->rect, quad->visible_rect); + QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect)); SkRect quad_rect = gfx::RectFToSkRect(visible_quad_vertex_rect); if (quad->y_flipped) @@ -472,10 +455,8 @@ void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame, paint.setShader(shader.get()); current_canvas_->drawRect(quad_rect, paint); } else { - current_canvas_->drawBitmapRectToRect(*bitmap, - &sk_uv_rect, - quad_rect, - ¤t_paint_); + current_canvas_->drawBitmapRect(*bitmap, sk_uv_rect, quad_rect, + ¤t_paint_); } if (needs_layer) @@ -496,18 +477,17 @@ void SoftwareRenderer::DrawTileQuad(const DrawingFrame* frame, DCHECK_EQ(GL_CLAMP_TO_EDGE, lock.wrap_mode()); gfx::RectF visible_tex_coord_rect = MathUtil::ScaleRectProportional( - quad->tex_coord_rect, quad->rect, quad->visible_rect); + quad->tex_coord_rect, gfx::RectF(quad->rect), + gfx::RectF(quad->visible_rect)); gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional( - QuadVertexRect(), quad->rect, quad->visible_rect); + QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect)); SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect); current_paint_.setFilterQuality( quad->nearest_neighbor ? kNone_SkFilterQuality : kLow_SkFilterQuality); - current_canvas_->drawBitmapRectToRect( - *lock.sk_bitmap(), - &uv_rect, - gfx::RectFToSkRect(visible_quad_vertex_rect), - ¤t_paint_); + current_canvas_->drawBitmapRect(*lock.sk_bitmap(), uv_rect, + gfx::RectFToSkRect(visible_quad_vertex_rect), + ¤t_paint_); } void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, @@ -525,8 +505,9 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, SkShader::TileMode content_tile_mode = WrapModeToTileMode(lock.wrap_mode()); SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect()); - SkRect dest_visible_rect = gfx::RectFToSkRect(MathUtil::ScaleRectProportional( - QuadVertexRect(), quad->rect, quad->visible_rect)); + SkRect dest_visible_rect = gfx::RectFToSkRect( + MathUtil::ScaleRectProportional(QuadVertexRect(), gfx::RectF(quad->rect), + gfx::RectF(quad->visible_rect))); SkRect content_rect = SkRect::MakeWH(quad->rect.width(), quad->rect.height()); SkMatrix content_mat; @@ -538,23 +519,10 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, SkBitmap filter_bitmap; if (!quad->filters.IsEmpty()) { skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( - quad->filters, content_texture->size()); + quad->filters, gfx::SizeF(content_texture->size())); // TODO(ajuma): Apply the filter in the same pass as the content where // possible (e.g. when there's no origin offset). See crbug.com/308201. - if (filter) { - SkImageInfo info = SkImageInfo::MakeN32Premul( - content_texture->size().width(), content_texture->size().height()); - if (filter_bitmap.tryAllocPixels(info)) { - SkCanvas canvas(filter_bitmap); - SkPaint paint; - paint.setImageFilter(filter.get()); - canvas.clear(SK_ColorTRANSPARENT); - canvas.translate(SkIntToScalar(-quad->rect.origin().x()), - SkIntToScalar(-quad->rect.origin().y())); - canvas.scale(quad->filters_scale.x(), quad->filters_scale.y()); - canvas.drawSprite(*content, 0, 0, &paint); - } - } + filter_bitmap = ApplyImageFilter(filter.get(), quad, content); } skia::RefPtr<SkShader> shader; @@ -565,17 +533,20 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, shader = skia::AdoptRef(SkShader::CreateBitmapShader( filter_bitmap, content_tile_mode, content_tile_mode, &content_mat)); } - current_paint_.setShader(shader.get()); + scoped_ptr<ResourceProvider::ScopedReadLockSoftware> mask_lock; if (quad->mask_resource_id()) { - ResourceProvider::ScopedReadLockSoftware mask_lock( - resource_provider_, quad->mask_resource_id()); - if (!lock.valid()) + mask_lock = scoped_ptr<ResourceProvider::ScopedReadLockSoftware>( + new ResourceProvider::ScopedReadLockSoftware(resource_provider_, + quad->mask_resource_id())); + + if (!mask_lock->valid()) return; - SkShader::TileMode mask_tile_mode = WrapModeToTileMode( - mask_lock.wrap_mode()); - const SkBitmap* mask = mask_lock.sk_bitmap(); + SkShader::TileMode mask_tile_mode = + WrapModeToTileMode(mask_lock->wrap_mode()); + + const SkBitmap* mask = mask_lock->sk_bitmap(); // Scale normalized uv rect into absolute texel coordinates. SkRect mask_rect = @@ -600,11 +571,17 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame, skia::AdoptRef(builder.detachRasterizer()); current_paint_.setRasterizer(mask_rasterizer.get()); - current_canvas_->drawRect(dest_visible_rect, current_paint_); - } else { - // TODO(skaslev): Apply background filters + } + + // If we have a background filter shader, render its results first. + skia::RefPtr<SkShader> background_filter_shader = + GetBackgroundFilterShader(frame, quad, content_tile_mode); + if (background_filter_shader) { + current_paint_.setShader(background_filter_shader.get()); current_canvas_->drawRect(dest_visible_rect, current_paint_); } + current_paint_.setShader(shader.get()); + current_canvas_->drawRect(dest_visible_rect, current_paint_); } void SoftwareRenderer::DrawUnsupportedQuad(const DrawingFrame* frame, @@ -663,4 +640,107 @@ void SoftwareRenderer::DidChangeVisibility() { DiscardBackbuffer(); } +bool SoftwareRenderer::ShouldApplyBackgroundFilters( + const RenderPassDrawQuad* quad) const { + if (quad->background_filters.IsEmpty()) + return false; + + // TODO(hendrikw): Look into allowing background filters to see pixels from + // other render targets. See crbug.com/314867. + + return true; +} + +SkBitmap SoftwareRenderer::ApplyImageFilter(SkImageFilter* filter, + const RenderPassDrawQuad* quad, + const SkBitmap* to_filter) const { + if (!filter) + return SkBitmap(); + + SkBitmap filter_bitmap; + if (filter_bitmap.tryAllocPixels(SkImageInfo::MakeN32Premul( + to_filter->width(), to_filter->height()))) { + SkCanvas canvas(filter_bitmap); + SkPaint paint; + paint.setImageFilter(filter); + canvas.clear(SK_ColorTRANSPARENT); + canvas.translate(SkIntToScalar(-quad->rect.origin().x()), + SkIntToScalar(-quad->rect.origin().y())); + canvas.scale(quad->filters_scale.x(), quad->filters_scale.y()); + canvas.drawSprite(*to_filter, 0, 0, &paint); + } + return filter_bitmap; +} + +SkBitmap SoftwareRenderer::GetBackdropBitmap( + const gfx::Rect& bounding_rect) const { + SkBitmap bitmap; + bitmap.setInfo(SkImageInfo::MakeN32Premul(bounding_rect.width(), + bounding_rect.height())); + current_canvas_->readPixels(&bitmap, bounding_rect.x(), bounding_rect.y()); + return bitmap; +} + +gfx::Rect SoftwareRenderer::GetBackdropBoundingBoxForRenderPassQuad( + const DrawingFrame* frame, + const RenderPassDrawQuad* quad, + const gfx::Transform& contents_device_transform) const { + DCHECK(ShouldApplyBackgroundFilters(quad)); + gfx::Rect backdrop_rect = gfx::ToEnclosingRect( + MathUtil::MapClippedRect(contents_device_transform, QuadVertexRect())); + + int top, right, bottom, left; + quad->background_filters.GetOutsets(&top, &right, &bottom, &left); + backdrop_rect.Inset(-left, -top, -right, -bottom); + + backdrop_rect.Intersect(MoveFromDrawToWindowSpace( + frame, frame->current_render_pass->output_rect)); + + return backdrop_rect; +} + +skia::RefPtr<SkShader> SoftwareRenderer::GetBackgroundFilterShader( + const DrawingFrame* frame, + const RenderPassDrawQuad* quad, + SkShader::TileMode content_tile_mode) const { + if (!ShouldApplyBackgroundFilters(quad)) + return skia::RefPtr<SkShader>(); + + gfx::Transform quad_rect_matrix; + QuadRectTransform(&quad_rect_matrix, + quad->shared_quad_state->quad_to_target_transform, + gfx::RectF(quad->rect)); + gfx::Transform contents_device_transform = + frame->window_matrix * frame->projection_matrix * quad_rect_matrix; + contents_device_transform.FlattenTo2d(); + + gfx::Rect backdrop_rect = GetBackdropBoundingBoxForRenderPassQuad( + frame, quad, contents_device_transform); + + // Figure out the transformations to move it back to pixel space. + gfx::Transform contents_device_transform_inverse; + if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) + return skia::RefPtr<SkShader>(); + + SkMatrix filter_backdrop_transform = + contents_device_transform_inverse.matrix(); + filter_backdrop_transform.preTranslate(backdrop_rect.x(), backdrop_rect.y()); + + // Draw what's behind, and apply the filter to it. + SkBitmap backdrop_bitmap = GetBackdropBitmap(backdrop_rect); + + skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter( + quad->background_filters, + gfx::SizeF(backdrop_bitmap.width(), backdrop_bitmap.height())); + SkBitmap filter_backdrop_bitmap = + ApplyImageFilter(filter.get(), quad, &backdrop_bitmap); + + if (filter_backdrop_bitmap.empty()) + return skia::RefPtr<SkShader>(); + + return skia::AdoptRef(SkShader::CreateBitmapShader( + filter_backdrop_bitmap, content_tile_mode, content_tile_mode, + &filter_backdrop_transform)); +} + } // namespace cc diff --git a/chromium/cc/output/software_renderer.h b/chromium/cc/output/software_renderer.h index c3090429635..339bf6fb64a 100644 --- a/chromium/cc/output/software_renderer.h +++ b/chromium/cc/output/software_renderer.h @@ -37,7 +37,6 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer { const RendererCapabilitiesImpl& Capabilities() const override; void Finish() override; void SwapBuffers(const CompositorFrameMetadata& metadata) override; - void ReceiveSwapBuffersAck(const CompositorFrameAck& ack) override; void DiscardBackbuffer() override; void EnsureBackbuffer() override; @@ -92,6 +91,19 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer { const TileDrawQuad* quad); void DrawUnsupportedQuad(const DrawingFrame* frame, const DrawQuad* quad); + bool ShouldApplyBackgroundFilters(const RenderPassDrawQuad* quad) const; + SkBitmap ApplyImageFilter(SkImageFilter* filter, + const RenderPassDrawQuad* quad, + const SkBitmap* to_filter) const; + gfx::Rect GetBackdropBoundingBoxForRenderPassQuad( + const DrawingFrame* frame, + const RenderPassDrawQuad* quad, + const gfx::Transform& contents_device_transform) const; + SkBitmap GetBackdropBitmap(const gfx::Rect& bounding_rect) const; + skia::RefPtr<SkShader> GetBackgroundFilterShader( + const DrawingFrame* frame, + const RenderPassDrawQuad* quad, + SkShader::TileMode content_tile_mode) const; RendererCapabilitiesImpl capabilities_; bool is_scissor_enabled_; @@ -105,7 +117,6 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer { 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 a7ef1a20f7d..488cf344c63 100644 --- a/chromium/cc/output/software_renderer_unittest.cc +++ b/chromium/cc/output/software_renderer_unittest.cc @@ -18,7 +18,6 @@ #include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_resource_provider.h" #include "cc/test/geometry_test_utils.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 "testing/gmock/include/gmock/gmock.h" @@ -100,7 +99,7 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) { InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice)); RenderPassId root_render_pass_id = RenderPassId(1, 1); - scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); + scoped_ptr<RenderPass> root_render_pass = RenderPass::Create(); root_render_pass->SetNew( root_render_pass_id, outer_rect, outer_rect, gfx::Transform()); SharedQuadState* shared_quad_state = @@ -173,7 +172,7 @@ TEST_F(SoftwareRendererTest, TileQuad) { gfx::Rect root_rect = outer_rect; RenderPassId root_render_pass_id = RenderPassId(1, 1); - scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); + scoped_ptr<RenderPass> root_render_pass = RenderPass::Create(); root_render_pass->SetNew( root_render_pass_id, root_rect, root_rect, gfx::Transform()); SharedQuadState* shared_quad_state = @@ -188,26 +187,14 @@ TEST_F(SoftwareRendererTest, TileQuad) { 0); TileDrawQuad* inner_quad = root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>(); - inner_quad->SetNew(shared_quad_state, - inner_rect, - inner_rect, - inner_rect, - resource_cyan, - gfx::RectF(inner_size), - inner_size, - false, - false); + inner_quad->SetNew(shared_quad_state, inner_rect, inner_rect, inner_rect, + resource_cyan, gfx::RectF(gfx::SizeF(inner_size)), + inner_size, false, false); TileDrawQuad* outer_quad = root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>(); - outer_quad->SetNew(shared_quad_state, - outer_rect, - outer_rect, - outer_rect, - resource_yellow, - gfx::RectF(outer_size), - outer_size, - false, - false); + outer_quad->SetNew(shared_quad_state, outer_rect, outer_rect, outer_rect, + resource_yellow, gfx::RectF(gfx::SizeF(outer_size)), + outer_size, false, false); RenderPassList list; list.push_back(root_render_pass.Pass()); @@ -252,7 +239,7 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { gfx::Rect root_rect(tile_size); RenderPassId root_render_pass_id = RenderPassId(1, 1); - scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create(); + scoped_ptr<RenderPass> root_render_pass = RenderPass::Create(); root_render_pass->SetNew( root_render_pass_id, root_rect, root_rect, gfx::Transform()); SharedQuadState* shared_quad_state = @@ -267,15 +254,9 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { 0); TileDrawQuad* quad = root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>(); - quad->SetNew(shared_quad_state, - tile_rect, - tile_rect, - tile_rect, - resource_cyan, - gfx::RectF(tile_size), - tile_size, - false, - false); + quad->SetNew(shared_quad_state, tile_rect, tile_rect, tile_rect, + resource_cyan, gfx::RectF(gfx::SizeF(tile_size)), tile_size, + false, false); quad->visible_rect = visible_rect; RenderPassList list; @@ -319,7 +300,7 @@ TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) { // Draw a fullscreen green quad in a first frame. RenderPassId root_clear_pass_id(1, 0); - TestRenderPass* root_clear_pass = AddRenderPass( + RenderPass* root_clear_pass = AddRenderPass( &list, root_clear_pass_id, device_viewport_rect, gfx::Transform()); AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN); @@ -342,7 +323,7 @@ TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) { gfx::Rect smaller_rect(20, 20, 60, 60); RenderPassId root_smaller_pass_id(2, 0); - TestRenderPass* root_smaller_pass = AddRenderPass( + RenderPass* root_smaller_pass = AddRenderPass( &list, root_smaller_pass_id, device_viewport_rect, gfx::Transform()); AddQuad(root_smaller_pass, smaller_rect, SK_ColorMAGENTA); @@ -375,13 +356,13 @@ TEST_F(SoftwareRendererTest, RenderPassVisibleRect) { // Pass drawn as inner quad is magenta. gfx::Rect smaller_rect(20, 20, 60, 60); RenderPassId smaller_pass_id(2, 1); - TestRenderPass* smaller_pass = + RenderPass* smaller_pass = AddRenderPass(&list, smaller_pass_id, smaller_rect, gfx::Transform()); AddQuad(smaller_pass, smaller_rect, SK_ColorMAGENTA); // Root pass is green. RenderPassId root_clear_pass_id(1, 0); - TestRenderPass* root_clear_pass = AddRenderPass( + RenderPass* root_clear_pass = AddRenderPass( &list, root_clear_pass_id, device_viewport_rect, gfx::Transform()); AddRenderPassQuad(root_clear_pass, smaller_pass); AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN); diff --git a/chromium/cc/playback/clip_display_item.cc b/chromium/cc/playback/clip_display_item.cc index 5941502860b..e0901b88e07 100644 --- a/chromium/cc/playback/clip_display_item.cc +++ b/chromium/cc/playback/clip_display_item.cc @@ -48,6 +48,11 @@ void ClipDisplayItem::Raster(SkCanvas* canvas, } } +void ClipDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddStartingDisplayItem(); +} + void ClipDisplayItem::AsValueInto(base::trace_event::TracedValue* array) const { std::string value = base::StringPrintf("ClipDisplayItem rect: [%s]", clip_rect_.ToString().c_str()); @@ -88,6 +93,11 @@ void EndClipDisplayItem::Raster(SkCanvas* canvas, canvas->restore(); } +void EndClipDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddEndingDisplayItem(); +} + void EndClipDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString("EndClipDisplayItem"); diff --git a/chromium/cc/playback/clip_display_item.h b/chromium/cc/playback/clip_display_item.h index 83e0b6bf21a..2af0fa33e9d 100644 --- a/chromium/cc/playback/clip_display_item.h +++ b/chromium/cc/playback/clip_display_item.h @@ -29,6 +29,8 @@ class CC_EXPORT ClipDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; private: gfx::Rect clip_rect_; @@ -44,6 +46,8 @@ class CC_EXPORT EndClipDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; }; } // namespace cc diff --git a/chromium/cc/playback/clip_path_display_item.cc b/chromium/cc/playback/clip_path_display_item.cc index f7fd60626e5..9ac5bdea80a 100644 --- a/chromium/cc/playback/clip_path_display_item.cc +++ b/chromium/cc/playback/clip_path_display_item.cc @@ -36,6 +36,11 @@ void ClipPathDisplayItem::Raster(SkCanvas* canvas, canvas->clipPath(clip_path_, clip_op_, antialias_); } +void ClipPathDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddStartingDisplayItem(); +} + void ClipPathDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString(base::StringPrintf("ClipPathDisplayItem length: %d", @@ -57,6 +62,11 @@ void EndClipPathDisplayItem::Raster( canvas->restore(); } +void EndClipPathDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddEndingDisplayItem(); +} + void EndClipPathDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString("EndClipPathDisplayItem"); diff --git a/chromium/cc/playback/clip_path_display_item.h b/chromium/cc/playback/clip_path_display_item.h index 732087b9789..08581e29dd1 100644 --- a/chromium/cc/playback/clip_path_display_item.h +++ b/chromium/cc/playback/clip_path_display_item.h @@ -26,6 +26,8 @@ class CC_EXPORT ClipPathDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; private: SkPath clip_path_; @@ -46,6 +48,8 @@ class CC_EXPORT EndClipPathDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; }; } // namespace cc diff --git a/chromium/cc/playback/compositing_display_item.cc b/chromium/cc/playback/compositing_display_item.cc index 31365b5881c..c9b74fc4786 100644 --- a/chromium/cc/playback/compositing_display_item.cc +++ b/chromium/cc/playback/compositing_display_item.cc @@ -47,6 +47,12 @@ void CompositingDisplayItem::Raster( canvas->saveLayer(has_bounds_ ? &bounds_ : nullptr, &paint); } +void CompositingDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddStartingDisplayItem(); + calculator->Save(); +} + void CompositingDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString(base::StringPrintf( @@ -73,6 +79,12 @@ void EndCompositingDisplayItem::Raster( canvas->restore(); } +void EndCompositingDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->Restore(); + calculator->AddEndingDisplayItem(); +} + void EndCompositingDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString("EndCompositingDisplayItem"); diff --git a/chromium/cc/playback/compositing_display_item.h b/chromium/cc/playback/compositing_display_item.h index 91cd3e71f8e..9ee6b7a0eca 100644 --- a/chromium/cc/playback/compositing_display_item.h +++ b/chromium/cc/playback/compositing_display_item.h @@ -32,6 +32,8 @@ class CC_EXPORT CompositingDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; private: uint8_t alpha_; @@ -54,6 +56,8 @@ class CC_EXPORT EndCompositingDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; }; } // namespace cc diff --git a/chromium/cc/playback/discardable_image_map.cc b/chromium/cc/playback/discardable_image_map.cc new file mode 100644 index 00000000000..a78ef5fc812 --- /dev/null +++ b/chromium/cc/playback/discardable_image_map.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/playback/discardable_image_map.h" + +#include <algorithm> +#include <limits> + +#include "cc/base/math_util.h" +#include "cc/playback/display_item_list.h" +#include "third_party/skia/include/utils/SkNWayCanvas.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/skia_util.h" + +namespace cc { + +namespace { + +SkRect MapRect(const SkMatrix& matrix, const SkRect& src) { + SkRect dst; + matrix.mapRect(&dst, src); + return dst; +} + +// We're using an NWay canvas with no added canvases, so in effect +// non-overridden functions are no-ops. +class DiscardableImagesMetadataCanvas : public SkNWayCanvas { + public: + DiscardableImagesMetadataCanvas(int width, + int height, + std::vector<PositionImage>* image_set) + : SkNWayCanvas(width, height), + image_set_(image_set), + canvas_bounds_(SkRect::MakeIWH(width, height)) {} + + protected: + // we need to "undo" the behavior of SkNWayCanvas, which will try to forward + // it. + void onDrawPicture(const SkPicture* picture, + const SkMatrix* matrix, + const SkPaint* paint) override { + SkCanvas::onDrawPicture(picture, matrix, paint); + } + + void onDrawImage(const SkImage* image, + SkScalar x, + SkScalar y, + const SkPaint* paint) override { + const SkMatrix& ctm = this->getTotalMatrix(); + AddImage(image, MapRect(ctm, SkRect::MakeXYWH(x, y, image->width(), + image->height())), + ctm, paint); + } + + void onDrawImageRect(const SkImage* image, + const SkRect* src, + const SkRect& dst, + const SkPaint* paint, + SrcRectConstraint) override { + const SkMatrix& ctm = this->getTotalMatrix(); + SkRect src_storage; + if (!src) { + src_storage = SkRect::MakeIWH(image->width(), image->height()); + src = &src_storage; + } + SkMatrix matrix; + matrix.setRectToRect(*src, dst, SkMatrix::kFill_ScaleToFit); + matrix.postConcat(ctm); + AddImage(image, MapRect(ctm, dst), matrix, paint); + } + + void onDrawImageNine(const SkImage* image, + const SkIRect& center, + const SkRect& dst, + const SkPaint* paint) override { + AddImage(image, dst, this->getTotalMatrix(), paint); + } + + private: + void AddImage(const SkImage* image, + const SkRect& rect, + const SkMatrix& matrix, + const SkPaint* paint) { + if (rect.intersects(canvas_bounds_) && image->isLazyGenerated()) { + SkFilterQuality filter_quality = kNone_SkFilterQuality; + if (paint) { + filter_quality = paint->getFilterQuality(); + } + image_set_->push_back(PositionImage(image, rect, matrix, filter_quality)); + } + } + + std::vector<PositionImage>* image_set_; + const SkRect canvas_bounds_; +}; + +} // namespace + +DiscardableImageMap::DiscardableImageMap() {} + +DiscardableImageMap::~DiscardableImageMap() {} + +scoped_ptr<SkCanvas> DiscardableImageMap::BeginGeneratingMetadata( + const gfx::Size& bounds) { + DCHECK(all_images_.empty()); + return scoped_ptr<SkCanvas>(new DiscardableImagesMetadataCanvas( + bounds.width(), bounds.height(), &all_images_)); +} + +void DiscardableImageMap::EndGeneratingMetadata() { + images_rtree_.Build(all_images_, [](const PositionImage& image) { + return gfx::SkRectToRectF(image.image_rect); + }); +} + +void DiscardableImageMap::GetDiscardableImagesInRect( + const gfx::Rect& rect, + std::vector<PositionImage>* images) { + std::vector<size_t> indices; + images_rtree_.Search(gfx::RectF(rect), &indices); + for (size_t index : indices) + images->push_back(all_images_[index]); +} + +DiscardableImageMap::ScopedMetadataGenerator::ScopedMetadataGenerator( + DiscardableImageMap* image_map, + const gfx::Size& bounds) + : image_map_(image_map), + metadata_canvas_(image_map->BeginGeneratingMetadata(bounds)) {} + +DiscardableImageMap::ScopedMetadataGenerator::~ScopedMetadataGenerator() { + image_map_->EndGeneratingMetadata(); +} + +} // namespace cc diff --git a/chromium/cc/playback/discardable_image_map.h b/chromium/cc/playback/discardable_image_map.h new file mode 100644 index 00000000000..e5928f7aedc --- /dev/null +++ b/chromium/cc/playback/discardable_image_map.h @@ -0,0 +1,67 @@ +// 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_DISCARDABLE_IMAGE_MAP_H_ +#define CC_PLAYBACK_DISCARDABLE_IMAGE_MAP_H_ + +#include <utility> +#include <vector> + +#include "base/containers/hash_tables.h" +#include "base/lazy_instance.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "cc/base/rtree.h" +#include "cc/playback/position_image.h" +#include "third_party/skia/include/core/SkPicture.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" + +class SkImage; + +namespace cc { + +class DisplayItemList; + +// This class is used for generating discardable images data (see PositionImage +// for the type of data it stores). It allows the client to query a particular +// rect and get back a list of PositionImages in that rect. +class CC_EXPORT DiscardableImageMap { + public: + using Images = std::vector<PositionImage>; + + class CC_EXPORT ScopedMetadataGenerator { + public: + ScopedMetadataGenerator(DiscardableImageMap* image_map, + const gfx::Size& bounds); + ~ScopedMetadataGenerator(); + + SkCanvas* canvas() { return metadata_canvas_.get(); } + + private: + DiscardableImageMap* image_map_; + scoped_ptr<SkCanvas> metadata_canvas_; + }; + + DiscardableImageMap(); + ~DiscardableImageMap(); + + bool empty() const { return all_images_.empty(); } + void GetDiscardableImagesInRect(const gfx::Rect& rect, + std::vector<PositionImage>* images); + + private: + friend class ScopedMetadataGenerator; + + scoped_ptr<SkCanvas> BeginGeneratingMetadata(const gfx::Size& bounds); + void EndGeneratingMetadata(); + + Images all_images_; + RTree images_rtree_; +}; + +} // namespace cc + +#endif // CC_PLAYBACK_DISCARDABLE_IMAGE_MAP_H_ diff --git a/chromium/cc/playback/discardable_image_map_unittest.cc b/chromium/cc/playback/discardable_image_map_unittest.cc new file mode 100644 index 00000000000..65bf68e4287 --- /dev/null +++ b/chromium/cc/playback/discardable_image_map_unittest.cc @@ -0,0 +1,316 @@ +// 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/discardable_image_map.h" + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/values.h" +#include "cc/base/region.h" +#include "cc/playback/raster_source.h" +#include "cc/test/fake_content_layer_client.h" +#include "cc/test/fake_display_list_recording_source.h" +#include "cc/test/skia_common.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkGraphics.h" +#include "third_party/skia/include/core/SkImageGenerator.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/skia_util.h" + +namespace cc { +namespace { + +class TestImageGenerator : public SkImageGenerator { + public: + explicit TestImageGenerator(const SkImageInfo& info) + : SkImageGenerator(info) {} +}; + +skia::RefPtr<SkImage> CreateDiscardableImage(const gfx::Size& size) { + const SkImageInfo info = + SkImageInfo::MakeN32Premul(size.width(), size.height()); + return skia::AdoptRef( + SkImage::NewFromGenerator(new TestImageGenerator(info))); +} + +TEST(DiscardableImageMapTest, GetDiscardableImagesInRect) { + gfx::Rect visible_rect(2048, 2048); + FakeContentLayerClient content_layer_client; + + // Discardable pixel refs are found in the following grids: + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + skia::RefPtr<SkImage> discardable_image[4][4]; + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + if ((x + y) & 1) { + discardable_image[y][x] = CreateDiscardableImage(gfx::Size(500, 500)); + SkPaint paint; + content_layer_client.add_draw_image( + discardable_image[y][x].get(), gfx::Point(x * 512 + 6, y * 512 + 6), + paint); + } + } + } + + FakeDisplayListRecordingSource recording_source; + Region invalidation(visible_rect); + recording_source.SetGenerateDiscardableImagesMetadata(true); + recording_source.UpdateAndExpandInvalidation( + &content_layer_client, &invalidation, visible_rect.size(), visible_rect, + 1, RecordingSource::RECORD_NORMALLY); + DisplayItemList* display_list = recording_source.display_list(); + + DiscardableImageMap image_map; + { + DiscardableImageMap::ScopedMetadataGenerator generator(&image_map, + visible_rect.size()); + display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f); + } + + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect( + gfx::Rect(x * 512, y * 512, 500, 500), &images); + if ((x + y) & 1) { + EXPECT_EQ(1u, images.size()) << x << " " << y; + EXPECT_TRUE(images[0].image == discardable_image[y][x].get()) + << x << " " << y; + EXPECT_EQ(gfx::RectF(x * 512 + 6, y * 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + } else { + EXPECT_EQ(0u, images.size()) << x << " " << y; + } + } + } + + // Capture 4 pixel refs. + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect(gfx::Rect(512, 512, 2048, 2048), + &images); + EXPECT_EQ(4u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[1][2].get()); + EXPECT_EQ(gfx::RectF(2 * 512 + 6, 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + EXPECT_TRUE(images[1].image == discardable_image[2][1].get()); + EXPECT_EQ(gfx::RectF(512 + 6, 2 * 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[1].image_rect).ToString()); + EXPECT_TRUE(images[2].image == discardable_image[2][3].get()); + EXPECT_EQ(gfx::RectF(3 * 512 + 6, 2 * 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[2].image_rect).ToString()); + EXPECT_TRUE(images[3].image == discardable_image[3][2].get()); + EXPECT_EQ(gfx::RectF(2 * 512 + 6, 3 * 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[3].image_rect).ToString()); +} + +TEST(DiscardableImageMapTest, GetDiscardableImagesInRectNonZeroLayer) { + gfx::Rect visible_rect(1024, 0, 2048, 2048); + // Make sure visible rect fits into the layer size. + gfx::Size layer_size(visible_rect.right(), visible_rect.bottom()); + FakeContentLayerClient content_layer_client; + + // Discardable pixel refs are found in the following grids: + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + skia::RefPtr<SkImage> discardable_image[4][4]; + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + if ((x + y) & 1) { + discardable_image[y][x] = CreateDiscardableImage(gfx::Size(500, 500)); + SkPaint paint; + content_layer_client.add_draw_image( + discardable_image[y][x].get(), + gfx::Point(1024 + x * 512 + 6, y * 512 + 6), paint); + } + } + } + + FakeDisplayListRecordingSource recording_source; + Region invalidation(visible_rect); + recording_source.set_pixel_record_distance(0); + recording_source.SetGenerateDiscardableImagesMetadata(true); + recording_source.UpdateAndExpandInvalidation( + &content_layer_client, &invalidation, layer_size, visible_rect, 1, + RecordingSource::RECORD_NORMALLY); + DisplayItemList* display_list = recording_source.display_list(); + + DiscardableImageMap image_map; + { + DiscardableImageMap::ScopedMetadataGenerator generator(&image_map, + layer_size); + display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f); + } + + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect( + gfx::Rect(1024 + x * 512, y * 512, 500, 500), &images); + if ((x + y) & 1) { + EXPECT_EQ(1u, images.size()) << x << " " << y; + EXPECT_TRUE(images[0].image == discardable_image[y][x].get()) + << x << " " << y; + EXPECT_EQ( + gfx::RectF(1024 + x * 512 + 6, y * 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + } else { + EXPECT_EQ(0u, images.size()) << x << " " << y; + } + } + } + // Capture 4 pixel refs. + { + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect(gfx::Rect(1024 + 512, 512, 2048, 2048), + &images); + EXPECT_EQ(4u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[1][2].get()); + EXPECT_EQ(gfx::RectF(1024 + 2 * 512 + 6, 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + EXPECT_TRUE(images[1].image == discardable_image[2][1].get()); + EXPECT_EQ(gfx::RectF(1024 + 512 + 6, 2 * 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[1].image_rect).ToString()); + EXPECT_TRUE(images[2].image == discardable_image[2][3].get()); + EXPECT_EQ(gfx::RectF(1024 + 3 * 512 + 6, 2 * 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[2].image_rect).ToString()); + EXPECT_TRUE(images[3].image == discardable_image[3][2].get()); + EXPECT_EQ(gfx::RectF(1024 + 2 * 512 + 6, 3 * 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[3].image_rect).ToString()); + } + + // Non intersecting rects + { + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect(gfx::Rect(0, 0, 1000, 1000), &images); + EXPECT_EQ(0u, images.size()); + } + { + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect(gfx::Rect(3500, 0, 1000, 1000), + &images); + EXPECT_EQ(0u, images.size()); + } + { + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect(gfx::Rect(0, 1100, 1000, 1000), + &images); + EXPECT_EQ(0u, images.size()); + } + { + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect(gfx::Rect(3500, 1100, 1000, 1000), + &images); + EXPECT_EQ(0u, images.size()); + } +} + +TEST(DiscardableImageMapTest, GetDiscardableImagesInRectOnePixelQuery) { + gfx::Rect visible_rect(2048, 2048); + FakeContentLayerClient content_layer_client; + + // Discardable pixel refs are found in the following grids: + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + // | | x | | x | + // |---|---|---|---| + // | x | | x | | + // |---|---|---|---| + skia::RefPtr<SkImage> discardable_image[4][4]; + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + if ((x + y) & 1) { + discardable_image[y][x] = CreateDiscardableImage(gfx::Size(500, 500)); + SkPaint paint; + content_layer_client.add_draw_image( + discardable_image[y][x].get(), gfx::Point(x * 512 + 6, y * 512 + 6), + paint); + } + } + } + + FakeDisplayListRecordingSource recording_source; + Region invalidation(visible_rect); + recording_source.SetGenerateDiscardableImagesMetadata(true); + recording_source.UpdateAndExpandInvalidation( + &content_layer_client, &invalidation, visible_rect.size(), visible_rect, + 1, RecordingSource::RECORD_NORMALLY); + DisplayItemList* display_list = recording_source.display_list(); + + DiscardableImageMap image_map; + { + DiscardableImageMap::ScopedMetadataGenerator generator(&image_map, + visible_rect.size()); + display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f); + } + + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect( + gfx::Rect(x * 512 + 256, y * 512 + 256, 1, 1), &images); + if ((x + y) & 1) { + EXPECT_EQ(1u, images.size()) << x << " " << y; + EXPECT_TRUE(images[0].image == discardable_image[y][x].get()) + << x << " " << y; + EXPECT_EQ(gfx::RectF(x * 512 + 6, y * 512 + 6, 500, 500).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + } else { + EXPECT_EQ(0u, images.size()) << x << " " << y; + } + } + } +} + +TEST(DiscardableImageMapTest, GetDiscardableImagesInRectMassiveImage) { + gfx::Rect visible_rect(2048, 2048); + FakeContentLayerClient content_layer_client; + + skia::RefPtr<SkImage> discardable_image; + discardable_image = CreateDiscardableImage(gfx::Size(1 << 25, 1 << 25)); + SkPaint paint; + content_layer_client.add_draw_image(discardable_image.get(), gfx::Point(0, 0), + paint); + + FakeDisplayListRecordingSource recording_source; + Region invalidation(visible_rect); + recording_source.SetGenerateDiscardableImagesMetadata(true); + recording_source.UpdateAndExpandInvalidation( + &content_layer_client, &invalidation, visible_rect.size(), visible_rect, + 1, RecordingSource::RECORD_NORMALLY); + DisplayItemList* display_list = recording_source.display_list(); + + DiscardableImageMap image_map; + { + DiscardableImageMap::ScopedMetadataGenerator generator(&image_map, + visible_rect.size()); + display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f); + } + std::vector<PositionImage> images; + image_map.GetDiscardableImagesInRect(gfx::Rect(0, 0, 1, 1), &images); + EXPECT_EQ(1u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image.get()); + EXPECT_EQ(gfx::RectF(0, 0, 1 << 25, 1 << 25).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/playback/display_item.h b/chromium/cc/playback/display_item.h index d89807dd3ce..bc089138ff9 100644 --- a/chromium/cc/playback/display_item.h +++ b/chromium/cc/playback/display_item.h @@ -8,6 +8,7 @@ #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" #include "cc/debug/traced_value.h" +#include "cc/playback/display_item_list_bounds_calculator.h" #include "third_party/skia/include/core/SkPicture.h" #include "ui/gfx/geometry/rect.h" @@ -31,6 +32,8 @@ class CC_EXPORT DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const = 0; virtual void AsValueInto(base::trace_event::TracedValue* array) const = 0; + virtual void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const = 0; bool is_suitable_for_gpu_rasterization() const { return is_suitable_for_gpu_rasterization_; diff --git a/chromium/cc/playback/display_item_list.cc b/chromium/cc/playback/display_item_list.cc index 08fe71d26e6..a9fbfaa37e0 100644 --- a/chromium/cc/playback/display_item_list.cc +++ b/chromium/cc/playback/display_item_list.cc @@ -12,7 +12,6 @@ #include "cc/base/math_util.h" #include "cc/debug/picture_debug_util.h" #include "cc/debug/traced_display_item_list.h" -#include "cc/debug/traced_picture.h" #include "cc/debug/traced_value.h" #include "cc/playback/display_item_list_settings.h" #include "cc/playback/largest_display_item.h" @@ -25,6 +24,10 @@ namespace cc { namespace { +// We don't perform per-layer solid color analysis when there are too many skia +// operations. +const int kOpCountThatIsOkToAnalyze = 10; + bool DisplayItemsTracingEnabled() { bool tracing_enabled; TRACE_EVENT_CATEGORY_GROUP_ENABLED( @@ -36,17 +39,22 @@ const int kDefaultNumDisplayItemsToReserve = 100; } // namespace +scoped_refptr<DisplayItemList> DisplayItemList::Create( + const gfx::Rect& layer_rect, + const DisplayItemListSettings& settings) { + return make_scoped_refptr(new DisplayItemList( + layer_rect, settings, + !settings.use_cached_picture || DisplayItemsTracingEnabled())); +} + DisplayItemList::DisplayItemList(gfx::Rect layer_rect, const DisplayItemListSettings& settings, bool retain_individual_display_items) - : items_(LargestDisplayItemSize(), - settings.max_sidecar_size, - kDefaultNumDisplayItemsToReserve, - settings.sidecar_destroyer), + : items_(LargestDisplayItemSize(), kDefaultNumDisplayItemsToReserve), use_cached_picture_(settings.use_cached_picture), retain_individual_display_items_(retain_individual_display_items), layer_rect_(layer_rect), - all_items_are_suitable_for_gpu_rasterization_(true), + is_suitable_for_gpu_rasterization_(true), approximate_op_count_(0), picture_memory_usage_(0), external_memory_usage_(0) { @@ -63,34 +71,6 @@ DisplayItemList::DisplayItemList(gfx::Rect layer_rect, } } -DisplayItemList::DisplayItemList(gfx::Rect layer_rect, - const DisplayItemListSettings& settings) - : DisplayItemList( - layer_rect, - settings, - !settings.use_cached_picture || DisplayItemsTracingEnabled()) { -} - -scoped_refptr<DisplayItemList> DisplayItemList::CreateWithoutCachedPicture( - const DisplayItemListSettings& settings) { - DCHECK(!settings.use_cached_picture); - return Create(gfx::Rect(), settings); -} - -scoped_refptr<DisplayItemList> DisplayItemList::Create( - gfx::Rect layer_rect, - bool use_cached_picture) { - DisplayItemListSettings settings; - settings.use_cached_picture = use_cached_picture; - return Create(layer_rect, settings); -} - -scoped_refptr<DisplayItemList> DisplayItemList::Create( - gfx::Rect layer_rect, - const DisplayItemListSettings& settings) { - return make_scoped_refptr(new DisplayItemList(layer_rect, settings)); -} - DisplayItemList::~DisplayItemList() { } @@ -142,13 +122,19 @@ void DisplayItemList::ProcessAppendedItems() { needs_process_ = false; #endif for (const DisplayItem* item : items_) { - all_items_are_suitable_for_gpu_rasterization_ &= - item->is_suitable_for_gpu_rasterization(); - approximate_op_count_ += item->approximate_op_count(); - if (use_cached_picture_) { + // When using a cached picture we will calculate gpu suitability on the + // entire cached picture instead of the items. This is more permissive + // 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. See crbug.com/513016. DCHECK(canvas_); - item->Raster(canvas_.get(), gfx::Rect(), NULL); + approximate_op_count_ += item->approximate_op_count(); + item->Raster(canvas_.get(), gfx::Rect(), nullptr); + } else { + is_suitable_for_gpu_rasterization_ &= + item->is_suitable_for_gpu_rasterization(); + approximate_op_count_ += item->approximate_op_count(); } if (retain_individual_display_items_) { @@ -165,11 +151,9 @@ void DisplayItemList::ProcessAppendedItems() { void DisplayItemList::RasterIntoCanvas(const DisplayItem& item) { DCHECK(canvas_); DCHECK(!retain_individual_display_items_); - all_items_are_suitable_for_gpu_rasterization_ &= - item.is_suitable_for_gpu_rasterization(); approximate_op_count_ += item.approximate_op_count(); - item.Raster(canvas_.get(), gfx::Rect(), NULL); + item.Raster(canvas_.get(), gfx::Rect(), nullptr); } bool DisplayItemList::RetainsIndividualDisplayItems() const { @@ -198,19 +182,14 @@ void DisplayItemList::Finalize() { SkPictureUtils::ApproximateBytesUsed(picture_.get()); recorder_.reset(); canvas_.clear(); + is_suitable_for_gpu_rasterization_ = + picture_->suitableForGpuRasterization(nullptr); } } bool DisplayItemList::IsSuitableForGpuRasterization() const { DCHECK(ProcessAppendedItemsCalled()); - if (use_cached_picture_) - return picture_->suitableForGpuRasterization(NULL); - - // 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. See - // crbug.com/513016. - return all_items_are_suitable_for_gpu_rasterization_; + return is_suitable_for_gpu_rasterization_; } int DisplayItemList::ApproximateOpCount() const { @@ -240,21 +219,26 @@ size_t DisplayItemList::ApproximateMemoryUsage() const { return memory_usage; } +bool DisplayItemList::ShouldBeAnalyzedForSolidColor() const { + return ApproximateOpCount() <= kOpCountThatIsOkToAnalyze; +} + scoped_refptr<base::trace_event::ConvertableToTraceFormat> DisplayItemList::AsValue(bool include_items) const { DCHECK(ProcessAppendedItemsCalled()); scoped_refptr<base::trace_event::TracedValue> state = new base::trace_event::TracedValue(); + state->BeginDictionary("params"); if (include_items) { - state->BeginArray("params.items"); + state->BeginArray("items"); for (const DisplayItem* item : items_) { item->AsValueInto(state.get()); } - state->EndArray(); + state->EndArray(); // "items". } - - state->SetValue("params.layer_rect", MathUtil::AsValue(layer_rect_)); + state->SetValue("layer_rect", MathUtil::AsValue(layer_rect_)); + state->EndDictionary(); // "params". if (!layer_rect_.IsEmpty()) { SkPictureRecorder recorder; @@ -285,20 +269,27 @@ void DisplayItemList::EmitTraceSnapshot() const { DisplayItemsTracingEnabled())); } -void DisplayItemList::GatherPixelRefs(const gfx::Size& grid_cell_size) { +void DisplayItemList::GenerateDiscardableImagesMetadata() { 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)); + DCHECK(image_map_.empty()); if (!picture_->willPlayBackBitmaps()) return; - pixel_refs_->GatherPixelRefsFromPicture(picture_.get()); + // The cached picture is translated by -layer_rect_.origin during record, + // so we need to offset that back in order to get right positioning for + // images. + DiscardableImageMap::ScopedMetadataGenerator generator( + &image_map_, gfx::Size(layer_rect_.right(), layer_rect_.bottom())); + generator.canvas()->translate(layer_rect_.x(), layer_rect_.y()); + generator.canvas()->drawPicture(picture_.get()); } -void* DisplayItemList::GetSidecar(DisplayItem* display_item) { - return items_.GetSidecar(display_item); +void DisplayItemList::GetDiscardableImagesInRect( + const gfx::Rect& rect, + std::vector<PositionImage>* images) { + image_map_.GetDiscardableImagesInRect(rect, images); } } // namespace cc diff --git a/chromium/cc/playback/display_item_list.h b/chromium/cc/playback/display_item_list.h index 35bcb8cc4b6..12ad23cdad5 100644 --- a/chromium/cc/playback/display_item_list.h +++ b/chromium/cc/playback/display_item_list.h @@ -10,10 +10,9 @@ #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/base/sidecar_list_container.h" +#include "cc/base/list_container.h" +#include "cc/playback/discardable_image_map.h" #include "cc/playback/display_item.h" -#include "cc/playback/pixel_ref_map.h" #include "skia/ext/refptr.h" #include "third_party/skia/include/core/SkPicture.h" #include "ui/gfx/geometry/rect.h" @@ -28,16 +27,13 @@ class DisplayItemListSettings; class CC_EXPORT DisplayItemList : public base::RefCountedThreadSafe<DisplayItemList> { public: - static scoped_refptr<DisplayItemList> CreateWithoutCachedPicture( - const DisplayItemListSettings& settings); - - // Creates a display item list with the given cull rect (if picture caching - // is used). The resulting display list will not support sidecar data. - static scoped_refptr<DisplayItemList> Create(gfx::Rect layer_rect, - bool use_cached_picture); - + // Creates a display item list. If picture caching is used, then layer_rect + // specifies the cull rect of the display item list (the picture will not + // exceed this rect). If picture caching is not used, then the given rect can + // be empty. + // TODO(vmpstr): Maybe this cull rect can be part of the settings instead. static scoped_refptr<DisplayItemList> Create( - gfx::Rect layer_rect, + const gfx::Rect& layer_rect, const DisplayItemListSettings& settings); void Raster(SkCanvas* canvas, @@ -71,6 +67,7 @@ class CC_EXPORT DisplayItemList bool IsSuitableForGpuRasterization() const; int ApproximateOpCount() const; size_t ApproximateMemoryUsage() const; + bool ShouldBeAnalyzedForSolidColor() const; bool RetainsIndividualDisplayItems() const; @@ -79,17 +76,14 @@ class CC_EXPORT DisplayItemList void EmitTraceSnapshot() const; - void GatherPixelRefs(const gfx::Size& grid_cell_size); - - // Finds the sidecar for a display item in this list. - void* GetSidecar(DisplayItem* display_item); + void GenerateDiscardableImagesMetadata(); + void GetDiscardableImagesInRect(const gfx::Rect& rect, + std::vector<PositionImage>* images); private: DisplayItemList(gfx::Rect layer_rect, const DisplayItemListSettings& display_list_settings, bool retain_individual_display_items); - DisplayItemList(gfx::Rect layer_rect, - const DisplayItemListSettings& display_list_settings); ~DisplayItemList(); // While appending new items, if they are not being retained, this can process @@ -103,16 +97,16 @@ class CC_EXPORT DisplayItemList bool ProcessAppendedItemsCalled() const { return true; } #endif - SidecarListContainer<DisplayItem> items_; + ListContainer<DisplayItem> items_; skia::RefPtr<SkPicture> picture_; scoped_ptr<SkPictureRecorder> recorder_; skia::RefPtr<SkCanvas> canvas_; - bool use_cached_picture_; + const bool use_cached_picture_; bool retain_individual_display_items_; gfx::Rect layer_rect_; - bool all_items_are_suitable_for_gpu_rasterization_; + bool is_suitable_for_gpu_rasterization_; int approximate_op_count_; // Memory usage due to the cached SkPicture. @@ -121,10 +115,9 @@ class CC_EXPORT DisplayItemList // Memory usage due to external data held by display items. size_t external_memory_usage_; - scoped_ptr<PixelRefMap> pixel_refs_; + DiscardableImageMap image_map_; friend class base::RefCountedThreadSafe<DisplayItemList>; - friend class PixelRefMap::Iterator; FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, ApproximateMemoryUsage); DISALLOW_COPY_AND_ASSIGN(DisplayItemList); }; diff --git a/chromium/cc/playback/display_item_list_bounds_calculator.cc b/chromium/cc/playback/display_item_list_bounds_calculator.cc new file mode 100644 index 00000000000..b6dfdd58871 --- /dev/null +++ b/chromium/cc/playback/display_item_list_bounds_calculator.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/display_item_list_bounds_calculator.h" + +#include "base/logging.h" +#include "ui/gfx/skia_util.h" + +namespace cc { + +DisplayItemListBoundsCalculator::DisplayItemListBoundsCalculator() { + matrix_stack_.push_back(SkMatrix::I()); +} + +DisplayItemListBoundsCalculator::~DisplayItemListBoundsCalculator() {} + +void DisplayItemListBoundsCalculator::AddStartingDisplayItem() { + bounds_.push_back(gfx::RectF()); + started_items_indices_.push_back(bounds_.size() - 1); +} + +void DisplayItemListBoundsCalculator::AddEndingDisplayItem() { + size_t last_start_index = started_items_indices_.back(); + started_items_indices_.pop_back(); + + // Ending bounds match the starting bounds. + bounds_.push_back(bounds_[last_start_index]); + + // The block that ended just now needs to be considered in the bounds of the + // enclosing block. + if (!started_items_indices_.empty()) + bounds_[started_items_indices_.back()].Union(bounds_.back()); +} + +void DisplayItemListBoundsCalculator::AddDisplayItemWithBounds( + const SkRect& rect) { + SkRect target_rect; + matrix()->mapRect(&target_rect, rect); + bounds_.push_back(gfx::SkRectToRectF(target_rect)); + if (!started_items_indices_.empty()) + bounds_[started_items_indices_.back()].Union(bounds_.back()); +} + +void DisplayItemListBoundsCalculator::Save() { + matrix_stack_.push_back(matrix_stack_.back()); +} + +void DisplayItemListBoundsCalculator::Restore() { + DCHECK_GT(matrix_stack_.size(), 1u); + matrix_stack_.pop_back(); +} + +void DisplayItemListBoundsCalculator::Finalize() { + while (!started_items_indices_.empty()) { + bounds_[started_items_indices_.back()].Union(bounds_.back()); + started_items_indices_.pop_back(); + } +} + +} // namespace cc diff --git a/chromium/cc/playback/display_item_list_bounds_calculator.h b/chromium/cc/playback/display_item_list_bounds_calculator.h new file mode 100644 index 00000000000..8a84e346ae2 --- /dev/null +++ b/chromium/cc/playback/display_item_list_bounds_calculator.h @@ -0,0 +1,39 @@ +// 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_DISPLAY_ITEM_LIST_BOUNDS_CALCULATOR_H_ +#define CC_PLAYBACK_DISPLAY_ITEM_LIST_BOUNDS_CALCULATOR_H_ + +#include <vector> + +#include "third_party/skia/include/core/SkMatrix.h" +#include "ui/gfx/geometry/rect_f.h" + +namespace cc { + +class DisplayItemListBoundsCalculator { + public: + DisplayItemListBoundsCalculator(); + ~DisplayItemListBoundsCalculator(); + + void AddStartingDisplayItem(); + void AddEndingDisplayItem(); + void AddDisplayItemWithBounds(const SkRect& rect); + void Finalize(); + + void Save(); + void Restore(); + SkMatrix* matrix() { return &matrix_stack_.back(); } + + void TakeBounds(std::vector<gfx::RectF>* bounds) { bounds->swap(bounds_); } + + private: + std::vector<gfx::RectF> bounds_; + std::vector<size_t> started_items_indices_; + std::vector<SkMatrix> matrix_stack_; +}; + +} // namespace cc + +#endif // CC_PLAYBACK_DISPLAY_ITEM_LIST_BOUNDS_CALCULATOR_H_ diff --git a/chromium/cc/playback/display_item_list_settings.cc b/chromium/cc/playback/display_item_list_settings.cc index e471d7e54ca..c71d9eecc3e 100644 --- a/chromium/cc/playback/display_item_list_settings.cc +++ b/chromium/cc/playback/display_item_list_settings.cc @@ -7,10 +7,7 @@ namespace cc { DisplayItemListSettings::DisplayItemListSettings() - : use_cached_picture(false), - max_sidecar_size(0), - sidecar_destroyer([](void* sidecar) {}) { -} + : use_cached_picture(false) {} DisplayItemListSettings::~DisplayItemListSettings() { } diff --git a/chromium/cc/playback/display_item_list_settings.h b/chromium/cc/playback/display_item_list_settings.h index 277a2ea8da9..85fe8db3fa6 100644 --- a/chromium/cc/playback/display_item_list_settings.h +++ b/chromium/cc/playback/display_item_list_settings.h @@ -18,10 +18,6 @@ class CC_EXPORT DisplayItemListSettings { // If set, a picture will be cached inside the DisplayItemList. bool use_cached_picture; - - // Settings that control sidecar data. - size_t max_sidecar_size; - void (*sidecar_destroyer)(void* sidecar); }; } // namespace cc diff --git a/chromium/cc/playback/display_item_list_unittest.cc b/chromium/cc/playback/display_item_list_unittest.cc index 89d4970da8a..c490bbfab73 100644 --- a/chromium/cc/playback/display_item_list_unittest.cc +++ b/chromium/cc/playback/display_item_list_unittest.cc @@ -20,7 +20,8 @@ #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/core/SkSurface.h" +#include "third_party/skia/include/effects/SkImageSource.h" #include "third_party/skia/include/utils/SkPictureUtils.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/skia_util.h" @@ -37,12 +38,13 @@ TEST(DisplayItemListTest, SingleDrawingItem) { SkPaint red_paint; red_paint.setColor(SK_ColorRED); unsigned char pixels[4 * 100 * 100] = {0}; - const bool use_cached_picture = true; + DisplayItemListSettings settings; + settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = - DisplayItemList::Create(layer_rect, use_cached_picture); + DisplayItemList::Create(layer_rect, settings); gfx::PointF offset(8.f, 9.f); - gfx::RectF recording_rect(offset, layer_rect.size()); + gfx::RectF recording_rect(offset, gfx::SizeF(layer_rect.size())); canvas = skia::SharePtr( recorder.beginRecording(gfx::RectFToSkRect(recording_rect))); canvas->translate(offset.x(), offset.y()); @@ -81,12 +83,13 @@ TEST(DisplayItemListTest, ClipItem) { SkPaint red_paint; red_paint.setColor(SK_ColorRED); unsigned char pixels[4 * 100 * 100] = {0}; - const bool use_cached_picture = true; + DisplayItemListSettings settings; + settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = - DisplayItemList::Create(layer_rect, use_cached_picture); + DisplayItemList::Create(layer_rect, settings); gfx::PointF first_offset(8.f, 9.f); - gfx::RectF first_recording_rect(first_offset, layer_rect.size()); + gfx::RectF first_recording_rect(first_offset, gfx::SizeF(layer_rect.size())); canvas = skia::SharePtr( recorder.beginRecording(gfx::RectFToSkRect(first_recording_rect))); canvas->translate(first_offset.x(), first_offset.y()); @@ -100,7 +103,8 @@ TEST(DisplayItemListTest, ClipItem) { 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()); + gfx::RectF second_recording_rect(second_offset, + gfx::SizeF(layer_rect.size())); canvas = skia::SharePtr( recorder.beginRecording(gfx::RectFToSkRect(second_recording_rect))); canvas->translate(second_offset.x(), second_offset.y()); @@ -142,12 +146,13 @@ TEST(DisplayItemListTest, TransformItem) { SkPaint red_paint; red_paint.setColor(SK_ColorRED); unsigned char pixels[4 * 100 * 100] = {0}; - const bool use_cached_picture = true; + DisplayItemListSettings settings; + settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = - DisplayItemList::Create(layer_rect, use_cached_picture); + DisplayItemList::Create(layer_rect, settings); gfx::PointF first_offset(8.f, 9.f); - gfx::RectF first_recording_rect(first_offset, layer_rect.size()); + gfx::RectF first_recording_rect(first_offset, gfx::SizeF(layer_rect.size())); canvas = skia::SharePtr( recorder.beginRecording(gfx::RectFToSkRect(first_recording_rect))); canvas->translate(first_offset.x(), first_offset.y()); @@ -162,7 +167,8 @@ TEST(DisplayItemListTest, TransformItem) { item2->SetNew(transform); gfx::PointF second_offset(2.f, 3.f); - gfx::RectF second_recording_rect(second_offset, layer_rect.size()); + gfx::RectF second_recording_rect(second_offset, + gfx::SizeF(layer_rect.size())); canvas = skia::SharePtr( recorder.beginRecording(gfx::RectFToSkRect(second_recording_rect))); canvas->translate(second_offset.x(), second_offset.y()); @@ -198,28 +204,31 @@ TEST(DisplayItemListTest, FilterItem) { gfx::Rect layer_rect(100, 100); FilterOperations filters; unsigned char pixels[4 * 100 * 100] = {0}; - const bool use_cached_picture = true; + DisplayItemListSettings settings; + settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = - DisplayItemList::Create(layer_rect, use_cached_picture); + DisplayItemList::Create(layer_rect, settings); - SkBitmap source_bitmap; - source_bitmap.allocN32Pixels(50, 50); - SkCanvas source_canvas(source_bitmap); - source_canvas.clear(SkColorSetRGB(128, 128, 128)); + skia::RefPtr<SkSurface> source_surface = + skia::AdoptRef(SkSurface::NewRasterN32Premul(50, 50)); + SkCanvas* source_canvas = source_surface->getCanvas(); + source_canvas->clear(SkColorSetRGB(128, 128, 128)); + skia::RefPtr<SkImage> source_image = + skia::AdoptRef(source_surface->newImageSnapshot()); // 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 + // SkImageSource), 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 + // SkImageSource filter in |filters|. Here, |src| is |filter_bounds|, defined // below. skia::RefPtr<SkImageFilter> image_filter = - skia::AdoptRef(SkBitmapSource::Create(source_bitmap)); + skia::AdoptRef(SkImageSource::Create(source_image.get())); filters.Append(FilterOperation::CreateReferenceFilter(image_filter)); filters.Append(FilterOperation::CreateBrightnessFilter(0.5f)); gfx::RectF filter_bounds(10.f, 10.f, 50.f, 50.f); @@ -255,11 +264,12 @@ TEST(DisplayItemListTest, CompactingItems) { unsigned char pixels[4 * 100 * 100] = {0}; gfx::PointF offset(8.f, 9.f); - gfx::RectF recording_rect(offset, layer_rect.size()); + gfx::RectF recording_rect(offset, gfx::SizeF(layer_rect.size())); - bool use_cached_picture = false; + DisplayItemListSettings no_caching_settings; + no_caching_settings.use_cached_picture = false; scoped_refptr<DisplayItemList> list_without_caching = - DisplayItemList::Create(layer_rect, use_cached_picture); + DisplayItemList::Create(layer_rect, no_caching_settings); canvas = skia::SharePtr( recorder.beginRecording(gfx::RectFToSkRect(recording_rect))); @@ -273,9 +283,10 @@ TEST(DisplayItemListTest, CompactingItems) { DrawDisplayList(pixels, layer_rect, list_without_caching); unsigned char expected_pixels[4 * 100 * 100] = {0}; - use_cached_picture = true; + DisplayItemListSettings caching_settings; + caching_settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list_with_caching = - DisplayItemList::Create(layer_rect, use_cached_picture); + DisplayItemList::Create(layer_rect, caching_settings); auto* item2 = list_with_caching->CreateAndAppendItem<DrawingDisplayItem>(); item2->SetNew(picture); list_with_caching->Finalize(); @@ -290,9 +301,10 @@ TEST(DisplayItemListTest, IsSuitableForGpuRasterizationWithCachedPicture) { skia::RefPtr<SkCanvas> canvas; skia::RefPtr<SkPicture> picture; - bool use_cached_picture = true; + DisplayItemListSettings settings; + settings.use_cached_picture = true; scoped_refptr<DisplayItemList> list = - DisplayItemList::Create(layer_rect, use_cached_picture); + DisplayItemList::Create(layer_rect, settings); canvas = skia::SharePtr(recorder.beginRecording(gfx::RectToSkRect(layer_rect))); @@ -317,7 +329,7 @@ TEST(DisplayItemListTest, IsSuitableForGpuRasterizationWithCachedPicture) { // a veto. EXPECT_TRUE(list->IsSuitableForGpuRasterization()); - list = DisplayItemList::Create(layer_rect, use_cached_picture); + list = DisplayItemList::Create(layer_rect, settings); canvas = skia::SharePtr(recorder.beginRecording(gfx::RectToSkRect(layer_rect))); for (int i = 0; i < 10; ++i) @@ -331,7 +343,7 @@ TEST(DisplayItemListTest, IsSuitableForGpuRasterizationWithCachedPicture) { // trigger a veto. EXPECT_FALSE(list->IsSuitableForGpuRasterization()); - list = DisplayItemList::Create(layer_rect, use_cached_picture); + list = DisplayItemList::Create(layer_rect, settings); for (int i = 0; i < 10; ++i) { canvas = skia::SharePtr(recorder.beginRecording(gfx::RectToSkRect(layer_rect))); @@ -353,9 +365,10 @@ TEST(DisplayItemListTest, IsSuitableForGpuRasterizationWithoutCachedPicture) { skia::RefPtr<SkCanvas> canvas; skia::RefPtr<SkPicture> picture; - bool use_cached_picture = false; + DisplayItemListSettings settings; + settings.use_cached_picture = false; scoped_refptr<DisplayItemList> list = - DisplayItemList::Create(layer_rect, use_cached_picture); + DisplayItemList::Create(layer_rect, settings); canvas = skia::SharePtr(recorder.beginRecording(gfx::RectToSkRect(layer_rect))); @@ -380,7 +393,7 @@ TEST(DisplayItemListTest, IsSuitableForGpuRasterizationWithoutCachedPicture) { // a veto. EXPECT_TRUE(list->IsSuitableForGpuRasterization()); - list = DisplayItemList::Create(layer_rect, use_cached_picture); + list = DisplayItemList::Create(layer_rect, settings); canvas = skia::SharePtr(recorder.beginRecording(gfx::RectToSkRect(layer_rect))); for (int i = 0; i < 10; ++i) @@ -394,7 +407,7 @@ TEST(DisplayItemListTest, IsSuitableForGpuRasterizationWithoutCachedPicture) { // trigger a veto. EXPECT_FALSE(list->IsSuitableForGpuRasterization()); - list = DisplayItemList::Create(layer_rect, use_cached_picture); + list = DisplayItemList::Create(layer_rect, settings); for (int i = 0; i < 10; ++i) { canvas = skia::SharePtr(recorder.beginRecording(gfx::RectToSkRect(layer_rect))); @@ -421,7 +434,7 @@ TEST(DisplayItemListTest, ApproximateMemoryUsage) { SkPictureRecorder recorder; SkPaint blue_paint; blue_paint.setColor(SK_ColorBLUE); - SkCanvas* canvas = recorder.beginRecording(gfx::RectFToSkRect(layer_rect)); + SkCanvas* canvas = recorder.beginRecording(gfx::RectToSkRect(layer_rect)); for (int i = 0; i < kNumCommandsInTestSkPicture; i++) canvas->drawPaint(blue_paint); skia::RefPtr<SkPicture> picture = @@ -430,7 +443,9 @@ TEST(DisplayItemListTest, ApproximateMemoryUsage) { ASSERT_GE(picture_size, kNumCommandsInTestSkPicture * sizeof(blue_paint)); // Using a cached picture, we should get about the right size. - list = DisplayItemList::Create(layer_rect, true); + DisplayItemListSettings caching_settings; + caching_settings.use_cached_picture = true; + list = DisplayItemList::Create(layer_rect, caching_settings); auto* item = list->CreateAndAppendItem<DrawingDisplayItem>(); item->SetNew(picture); list->Finalize(); @@ -439,7 +454,9 @@ TEST(DisplayItemListTest, ApproximateMemoryUsage) { EXPECT_LE(memory_usage, 2 * picture_size); // Using no cached picture, we should still get the right size. - list = DisplayItemList::Create(layer_rect, false); + DisplayItemListSettings no_caching_settings; + no_caching_settings.use_cached_picture = false; + list = DisplayItemList::Create(layer_rect, no_caching_settings); item = list->CreateAndAppendItem<DrawingDisplayItem>(); item->SetNew(picture); list->Finalize(); @@ -450,9 +467,7 @@ TEST(DisplayItemListTest, ApproximateMemoryUsage) { // 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). - DisplayItemListSettings settings; - settings.use_cached_picture = true; - list = new DisplayItemList(layer_rect, settings, true); + list = new DisplayItemList(layer_rect, caching_settings, true); item = list->CreateAndAppendItem<DrawingDisplayItem>(); item->SetNew(picture); list->Finalize(); diff --git a/chromium/cc/playback/display_list_raster_source.cc b/chromium/cc/playback/display_list_raster_source.cc index 4911e846029..215f7d75a53 100644 --- a/chromium/cc/playback/display_list_raster_source.cc +++ b/chromium/cc/playback/display_list_raster_source.cc @@ -25,20 +25,21 @@ DisplayListRasterSource::CreateFromDisplayListRecordingSource( } DisplayListRasterSource::DisplayListRasterSource() - : background_color_(SK_ColorTRANSPARENT), + : painter_reported_memory_usage_(0), + 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_(false), slow_down_raster_scale_factor_for_debug_(0), - should_attempt_to_use_distance_field_text_(false) { -} + should_attempt_to_use_distance_field_text_(false) {} DisplayListRasterSource::DisplayListRasterSource( const DisplayListRecordingSource* other, bool can_use_lcd_text) : display_list_(other->display_list_), + painter_reported_memory_usage_(other->painter_reported_memory_usage_), background_color_(other->background_color_), requires_clear_(other->requires_clear_), can_use_lcd_text_(can_use_lcd_text), @@ -49,13 +50,13 @@ DisplayListRasterSource::DisplayListRasterSource( clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), slow_down_raster_scale_factor_for_debug_( other->slow_down_raster_scale_factor_for_debug_), - should_attempt_to_use_distance_field_text_(false) { -} + should_attempt_to_use_distance_field_text_(false) {} DisplayListRasterSource::DisplayListRasterSource( const DisplayListRasterSource* other, bool can_use_lcd_text) : display_list_(other->display_list_), + painter_reported_memory_usage_(other->painter_reported_memory_usage_), background_color_(other->background_color_), requires_clear_(other->requires_clear_), can_use_lcd_text_(can_use_lcd_text), @@ -67,8 +68,7 @@ DisplayListRasterSource::DisplayListRasterSource( 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_) { -} + other->should_attempt_to_use_distance_field_text_) {} DisplayListRasterSource::~DisplayListRasterSource() { } @@ -108,7 +108,7 @@ void DisplayListRasterSource::RasterCommon( float contents_scale) const { canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); gfx::Rect content_rect = - gfx::ToEnclosingRect(gfx::ScaleRect(gfx::Rect(size_), contents_scale)); + gfx::ScaleToEnclosingRect(gfx::Rect(size_), contents_scale); content_rect.Intersect(canvas_playback_rect); canvas->clipRect(gfx::RectToSkRect(content_rect), SkRegion::kIntersect_Op); @@ -116,8 +116,11 @@ void DisplayListRasterSource::RasterCommon( DCHECK(display_list_.get()); gfx::Rect canvas_target_playback_rect = canvas_playback_rect - canvas_bitmap_rect.OffsetFromOrigin(); - display_list_->Raster(canvas, callback, canvas_target_playback_rect, - contents_scale); + int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); + for (int i = 0; i < repeat_count; ++i) { + display_list_->Raster(canvas, callback, canvas_target_playback_rect, + contents_scale); + } } skia::RefPtr<SkPicture> DisplayListRasterSource::GetFlattenedPicture() { @@ -138,7 +141,8 @@ skia::RefPtr<SkPicture> DisplayListRasterSource::GetFlattenedPicture() { size_t DisplayListRasterSource::GetPictureMemoryUsage() const { if (!display_list_) return 0; - return display_list_->ApproximateMemoryUsage(); + return display_list_->ApproximateMemoryUsage() + + painter_reported_memory_usage_; } void DisplayListRasterSource::PerformSolidColorAnalysis( @@ -157,31 +161,19 @@ void DisplayListRasterSource::PerformSolidColorAnalysis( 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; - } +void DisplayListRasterSource::GetDiscardableImagesInRect( + const gfx::Rect& layer_rect, + std::vector<PositionImage>* images) const { + DCHECK_EQ(0u, images->size()); + display_list_->GetDiscardableImagesInRect(layer_rect, images); } -bool DisplayListRasterSource::CoversRect(const gfx::Rect& content_rect, - float contents_scale) const { +bool DisplayListRasterSource::CoversRect(const gfx::Rect& layer_rect) 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::Rect bounded_rect = layer_rect; + bounded_rect.Intersect(gfx::Rect(size_)); + return recorded_viewport_.Contains(bounded_rect); } gfx::Size DisplayListRasterSource::GetSize() const { @@ -201,6 +193,10 @@ bool DisplayListRasterSource::HasRecordings() const { return !!display_list_.get(); } +gfx::Rect DisplayListRasterSource::RecordedViewport() const { + return recorded_viewport_; +} + void DisplayListRasterSource::SetShouldAttemptToUseDistanceFieldText() { should_attempt_to_use_distance_field_text_ = true; } diff --git a/chromium/cc/playback/display_list_raster_source.h b/chromium/cc/playback/display_list_raster_source.h index 24faa33c7fc..8b49b670d42 100644 --- a/chromium/cc/playback/display_list_raster_source.h +++ b/chromium/cc/playback/display_list_raster_source.h @@ -40,12 +40,12 @@ class CC_EXPORT DisplayListRasterSource : public RasterSource { 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; + void GetDiscardableImagesInRect( + const gfx::Rect& layer_rect, + std::vector<PositionImage>* images) const override; + bool CoversRect(const gfx::Rect& layer_rect) const override; bool HasRecordings() const override; + gfx::Rect RecordedViewport() const override; void SetShouldAttemptToUseDistanceFieldText() override; bool ShouldAttemptToUseDistanceFieldText() const override; void DidBeginTracing() override; @@ -66,6 +66,7 @@ class CC_EXPORT DisplayListRasterSource : public RasterSource { // 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 size_t painter_reported_memory_usage_; const SkColor background_color_; const bool requires_clear_; const bool can_use_lcd_text_; diff --git a/chromium/cc/playback/display_list_raster_source_unittest.cc b/chromium/cc/playback/display_list_raster_source_unittest.cc index d936af51f9c..9322a765a80 100644 --- a/chromium/cc/playback/display_list_raster_source_unittest.cc +++ b/chromium/cc/playback/display_list_raster_source_unittest.cc @@ -175,10 +175,10 @@ TEST(DisplayListRasterSourceTest, PixelRefIteratorDiscardableRefsOneTile) { scoped_ptr<FakeDisplayListRecordingSource> recording_source = FakeDisplayListRecordingSource::CreateFilledRecordingSource(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[0][1]); - CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][1]); + skia::RefPtr<SkImage> discardable_image[2][2]; + discardable_image[0][0] = CreateDiscardableImage(gfx::Size(32, 32)); + discardable_image[0][1] = CreateDiscardableImage(gfx::Size(32, 32)); + discardable_image[1][1] = CreateDiscardableImage(gfx::Size(32, 32)); // Discardable pixel refs are found in the following cells: // |---|---| @@ -186,12 +186,13 @@ TEST(DisplayListRasterSourceTest, PixelRefIteratorDiscardableRefsOneTile) { // |---|---| // | | x | // |---|---| - 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->add_draw_image(discardable_image[0][0].get(), + gfx::Point(0, 0)); + recording_source->add_draw_image(discardable_image[0][1].get(), + gfx::Point(260, 0)); + recording_source->add_draw_image(discardable_image[1][1].get(), + gfx::Point(260, 260)); + recording_source->SetGenerateDiscardableImagesMetadata(true); recording_source->Rerecord(); scoped_refptr<DisplayListRasterSource> raster = @@ -200,72 +201,42 @@ TEST(DisplayListRasterSourceTest, PixelRefIteratorDiscardableRefsOneTile) { // Tile sized iterators. These should find only one pixel ref. { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 1.0, &pixel_refs); - EXPECT_EQ(1u, pixel_refs.size()); - EXPECT_EQ(discardable_bitmap[0][0].pixelRef(), pixel_refs[0]); - } - { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(0, 0, 512, 512), 2.0, &pixel_refs); - EXPECT_EQ(1u, pixel_refs.size()); - EXPECT_EQ(discardable_bitmap[0][0].pixelRef(), pixel_refs[0]); - } - { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(0, 0, 128, 128), 0.5, &pixel_refs); - EXPECT_EQ(1u, pixel_refs.size()); - EXPECT_EQ(discardable_bitmap[0][0].pixelRef(), pixel_refs[0]); + std::vector<PositionImage> images; + raster->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), &images); + EXPECT_EQ(1u, images.size()); + EXPECT_EQ(discardable_image[0][0].get(), images[0].image); + EXPECT_EQ(gfx::RectF(32, 32).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); } // Shifted tile sized iterators. These should find only one pixel ref. { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(260, 260, 256, 256), 1.0, &pixel_refs); - EXPECT_EQ(1u, pixel_refs.size()); - EXPECT_EQ(discardable_bitmap[1][1].pixelRef(), pixel_refs[0]); - } - { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(520, 520, 512, 512), 2.0, &pixel_refs); - EXPECT_EQ(1u, pixel_refs.size()); - EXPECT_EQ(discardable_bitmap[1][1].pixelRef(), pixel_refs[0]); - } - { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(130, 130, 128, 128), 0.5, &pixel_refs); - EXPECT_EQ(1u, pixel_refs.size()); - EXPECT_EQ(discardable_bitmap[1][1].pixelRef(), pixel_refs[0]); + std::vector<PositionImage> images; + raster->GetDiscardableImagesInRect(gfx::Rect(260, 260, 256, 256), &images); + EXPECT_EQ(1u, images.size()); + EXPECT_EQ(discardable_image[1][1].get(), images[0].image); + EXPECT_EQ(gfx::RectF(260, 260, 32, 32).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); } // Ensure there's no discardable pixel refs in the empty cell { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(0, 256, 256, 256), 1.0, &pixel_refs); - EXPECT_EQ(0u, pixel_refs.size()); + std::vector<PositionImage> images; + raster->GetDiscardableImagesInRect(gfx::Rect(0, 256, 256, 256), &images); + EXPECT_EQ(0u, images.size()); } // Layer sized iterators. These should find three pixel ref. { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(0, 0, 512, 512), 1.0, &pixel_refs); - EXPECT_EQ(3u, pixel_refs.size()); - EXPECT_EQ(discardable_bitmap[0][0].pixelRef(), pixel_refs[0]); - EXPECT_EQ(discardable_bitmap[0][1].pixelRef(), pixel_refs[1]); - EXPECT_EQ(discardable_bitmap[1][1].pixelRef(), pixel_refs[2]); - } - { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(0, 0, 1024, 1024), 2.0, &pixel_refs); - EXPECT_EQ(3u, pixel_refs.size()); - EXPECT_EQ(discardable_bitmap[0][0].pixelRef(), pixel_refs[0]); - EXPECT_EQ(discardable_bitmap[0][1].pixelRef(), pixel_refs[1]); - EXPECT_EQ(discardable_bitmap[1][1].pixelRef(), pixel_refs[2]); - } - { - std::vector<SkPixelRef*> pixel_refs; - raster->GatherPixelRefs(gfx::Rect(0, 0, 256, 256), 0.5, &pixel_refs); - EXPECT_EQ(3u, pixel_refs.size()); - EXPECT_EQ(discardable_bitmap[0][0].pixelRef(), pixel_refs[0]); - EXPECT_EQ(discardable_bitmap[0][1].pixelRef(), pixel_refs[1]); - EXPECT_EQ(discardable_bitmap[1][1].pixelRef(), pixel_refs[2]); + std::vector<PositionImage> images; + raster->GetDiscardableImagesInRect(gfx::Rect(0, 0, 512, 512), &images); + EXPECT_EQ(3u, images.size()); + EXPECT_EQ(discardable_image[0][0].get(), images[0].image); + EXPECT_EQ(discardable_image[0][1].get(), images[1].image); + EXPECT_EQ(discardable_image[1][1].get(), images[2].image); + EXPECT_EQ(gfx::RectF(32, 32).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + EXPECT_EQ(gfx::RectF(260, 0, 32, 32).ToString(), + gfx::SkRectToRectF(images[1].image_rect).ToString()); + EXPECT_EQ(gfx::RectF(260, 260, 32, 32).ToString(), + gfx::SkRectToRectF(images[2].image_rect).ToString()); } } @@ -292,7 +263,7 @@ TEST(DisplayListRasterSourceTest, RasterFullContents) { recording_source.get(), false); gfx::Size content_bounds( - gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale))); + gfx::ScaleToCeiledSize(layer_bounds, contents_scale)); // Simulate drawing into different tiles at different offsets. int step_x = std::ceil(content_bounds.width() / raster_divisions); @@ -357,7 +328,7 @@ TEST(DisplayListRasterSourceTest, RasterPartialContents) { recording_source.get(), false); gfx::Size content_bounds( - gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale))); + gfx::ScaleToCeiledSize(layer_bounds, contents_scale)); SkBitmap bitmap; bitmap.allocN32Pixels(content_bounds.width(), content_bounds.height()); @@ -453,7 +424,7 @@ TEST(DisplayListRasterSourceTest, RasterPartialClear) { recording_source.get(), false); gfx::Size content_bounds( - gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale))); + gfx::ScaleToCeiledSize(layer_bounds, contents_scale)); SkBitmap bitmap; bitmap.allocN32Pixels(content_bounds.width(), content_bounds.height()); @@ -500,8 +471,8 @@ TEST(DisplayListRasterSourceTest, RasterPartialClear) { // We're going to playback from alpha(18) white rectangle into a smaller area // of the recording resulting in a smaller lighter white rectangle over a // darker white background rectangle. - playback_rect = gfx::Rect( - gfx::ToCeiledSize(gfx::ScaleSize(partial_bounds, contents_scale))); + playback_rect = + gfx::Rect(gfx::ScaleToCeiledSize(partial_bounds, contents_scale)); raster->PlaybackToCanvas(&canvas, raster_full_rect, playback_rect, contents_scale); @@ -534,7 +505,7 @@ TEST(DisplayListRasterSourceTest, RasterContentsTransparent) { DisplayListRasterSource::CreateFromDisplayListRecordingSource( recording_source.get(), false); gfx::Size content_bounds( - gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale))); + gfx::ScaleToCeiledSize(layer_bounds, contents_scale)); gfx::Rect canvas_rect(content_bounds); canvas_rect.Inset(0, 0, -1, -1); @@ -552,5 +523,22 @@ TEST(DisplayListRasterSourceTest, RasterContentsTransparent) { } } +TEST(DisplayListRasterSourceTest, + GetPictureMemoryUsageIncludesClientReportedMemory) { + const size_t kReportedMemoryUsageInBytes = 100 * 1024 * 1024; + gfx::Size layer_bounds(5, 3); + scoped_ptr<FakeDisplayListRecordingSource> recording_source = + FakeDisplayListRecordingSource::CreateFilledRecordingSource(layer_bounds); + recording_source->set_reported_memory_usage(kReportedMemoryUsageInBytes); + recording_source->Rerecord(); + + scoped_refptr<DisplayListRasterSource> raster = + DisplayListRasterSource::CreateFromDisplayListRecordingSource( + recording_source.get(), false); + size_t total_memory_usage = raster->GetPictureMemoryUsage(); + EXPECT_GE(total_memory_usage, kReportedMemoryUsageInBytes); + EXPECT_LT(total_memory_usage, 2 * kReportedMemoryUsageInBytes); +} + } // namespace } // namespace cc diff --git a/chromium/cc/playback/display_list_recording_source.cc b/chromium/cc/playback/display_list_recording_source.cc index e88343cb6b7..c790ebebe0f 100644 --- a/chromium/cc/playback/display_list_recording_source.cc +++ b/chromium/cc/playback/display_list_recording_source.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "base/numerics/safe_math.h" #include "cc/base/histograms.h" #include "cc/base/region.h" #include "cc/layers/content_layer_client.h" @@ -18,10 +19,7 @@ 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; +const int kPixelDistanceToRecord = 4000; // This is the distance, in layer space, by which the recorded viewport has to // change before causing a paint of the new content. For example, it means @@ -37,26 +35,23 @@ const bool kDefaultClearCanvasSetting = true; DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER( ScopedDisplayListRecordingSourceUpdateTimer, - "Compositing.DisplayListRecordingSource.UpdateUs", - "Compositing.DisplayListRecordingSource.UpdateInvalidatedAreaPerMs"); + "Compositing.%s.DisplayListRecordingSource.UpdateUs", + "Compositing.%s.DisplayListRecordingSource.UpdateInvalidatedAreaPerMs"); } // namespace namespace cc { -DisplayListRecordingSource::DisplayListRecordingSource( - const gfx::Size& grid_cell_size) +DisplayListRecordingSource::DisplayListRecordingSource() : slow_down_raster_scale_factor_for_debug_(0), - gather_pixel_refs_(false), + generate_discardable_images_metadata_(false), requires_clear_(false), is_solid_color_(false), clear_canvas_with_debug_color_(kDefaultClearCanvasSetting), solid_color_(SK_ColorTRANSPARENT), background_color_(SK_ColorTRANSPARENT), pixel_record_distance_(kPixelDistanceToRecord), - grid_cell_size_(grid_cell_size), - is_suitable_for_gpu_rasterization_(true) { -} + painter_reported_memory_usage_(0) {} DisplayListRecordingSource::~DisplayListRecordingSource() { } @@ -153,8 +148,13 @@ bool DisplayListRecordingSource::UpdateAndExpandInvalidation( // Count the area that is being invalidated. Region recorded_invalidation(*invalidation); recorded_invalidation.Intersect(recorded_viewport_); - for (Region::Iterator it(recorded_invalidation); it.has_rect(); it.next()) - timer.AddArea(it.rect().size().GetArea()); + for (Region::Iterator it(recorded_invalidation); it.has_rect(); it.next()) { + // gfx::Size::GetArea might overflow in this case, so use an explicit + // CheckedNumeric instead. + base::CheckedNumeric<int> checked_area = it.rect().size().width(); + checked_area *= it.rect().size().height(); + timer.AddArea(checked_area); + } if (!updated && !invalidation->Intersects(recorded_viewport_)) return false; @@ -180,23 +180,16 @@ bool DisplayListRecordingSource::UpdateAndExpandInvalidation( 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_ = painter->PaintContentsToDisplayList(recorded_viewport_, - painting_control); - } + // TODO(vmpstr): Add a slow_down_recording_scale_factor_for_debug_ to be able + // to slow down recording. + display_list_ = + painter->PaintContentsToDisplayList(recorded_viewport_, painting_control); + painter_reported_memory_usage_ = painter->GetApproximateUnsharedMemoryUsage(); - is_suitable_for_gpu_rasterization_ = - display_list_->IsSuitableForGpuRasterization(); DetermineIfSolidColor(); display_list_->EmitTraceSnapshot(); - if (gather_pixel_refs_) - display_list_->GatherPixelRefs(grid_cell_size_); + if (generate_discardable_images_metadata_) + display_list_->GenerateDiscardableImagesMetadata(); return true; } @@ -214,8 +207,9 @@ 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::SetGenerateDiscardableImagesMetadata( + bool generate_metadata) { + generate_discardable_images_metadata_ = generate_metadata; } void DisplayListRecordingSource::SetBackgroundColor(SkColor background_color) { @@ -226,12 +220,12 @@ 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_; + // The display list needs to be created (see: UpdateAndExpandInvalidation) + // before checking for suitability. There are cases where an update will not + // create a display list (e.g., if the size is empty). We return true in these + // cases because the gpu suitability bit sticks false. + return !display_list_ || display_list_->IsSuitableForGpuRasterization(); } scoped_refptr<RasterSource> DisplayListRecordingSource::CreateRasterSource( @@ -241,16 +235,12 @@ scoped_refptr<RasterSource> DisplayListRecordingSource::CreateRasterSource( this, can_use_lcd_text)); } -gfx::Size DisplayListRecordingSource::GetTileGridSizeForTesting() const { - return gfx::Size(); -} - void DisplayListRecordingSource::DetermineIfSolidColor() { - DCHECK(display_list_.get()); + DCHECK(display_list_); is_solid_color_ = false; solid_color_ = SK_ColorTRANSPARENT; - if (display_list_->ApproximateOpCount() > kOpCountThatIsOkToAnalyze) + if (!display_list_->ShouldBeAnalyzedForSolidColor()) return; gfx::Size layer_size = GetSize(); @@ -261,7 +251,8 @@ void DisplayListRecordingSource::DetermineIfSolidColor() { void DisplayListRecordingSource::Clear() { recorded_viewport_ = gfx::Rect(); - display_list_ = NULL; + display_list_ = nullptr; + painter_reported_memory_usage_ = 0; is_solid_color_ = false; } diff --git a/chromium/cc/playback/display_list_recording_source.h b/chromium/cc/playback/display_list_recording_source.h index 8d4e52f0cc3..b4250d0b3bb 100644 --- a/chromium/cc/playback/display_list_recording_source.h +++ b/chromium/cc/playback/display_list_recording_source.h @@ -14,7 +14,7 @@ class DisplayListRasterSource; class CC_EXPORT DisplayListRecordingSource : public RecordingSource { public: - explicit DisplayListRecordingSource(const gfx::Size& grid_cell_size); + DisplayListRecordingSource(); ~DisplayListRecordingSource() override; // RecordingSource overrides. @@ -29,12 +29,10 @@ class CC_EXPORT DisplayListRecordingSource : public RecordingSource { gfx::Size GetSize() const final; void SetEmptyBounds() override; void SetSlowdownRasterScaleFactor(int factor) override; - void SetGatherPixelRefs(bool gather_pixel_refs) override; + void SetGenerateDiscardableImagesMetadata(bool generate_metadata) 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; // Returns true if the new recorded viewport exposes enough new area to be // worth re-recording. static bool ExposesEnoughNewArea( @@ -50,24 +48,22 @@ class CC_EXPORT DisplayListRecordingSource : public RecordingSource { gfx::Rect recorded_viewport_; gfx::Size size_; int slow_down_raster_scale_factor_for_debug_; - bool gather_pixel_refs_; + bool generate_discardable_images_metadata_; bool requires_clear_; bool is_solid_color_; bool clear_canvas_with_debug_color_; SkColor solid_color_; SkColor background_color_; int pixel_record_distance_; - gfx::Size grid_cell_size_; scoped_refptr<DisplayItemList> display_list_; + size_t painter_reported_memory_usage_; private: friend class DisplayListRasterSource; void DetermineIfSolidColor(); - bool is_suitable_for_gpu_rasterization_; - DISALLOW_COPY_AND_ASSIGN(DisplayListRecordingSource); }; diff --git a/chromium/cc/playback/display_list_recording_source_unittest.cc b/chromium/cc/playback/display_list_recording_source_unittest.cc index 0ddfb6fc5c8..83d44036305 100644 --- a/chromium/cc/playback/display_list_recording_source_unittest.cc +++ b/chromium/cc/playback/display_list_recording_source_unittest.cc @@ -14,40 +14,55 @@ namespace cc { namespace { -class DisplayListRecordingSourceTest : public testing::Test { - public: - void SetUp() override {} -}; +scoped_ptr<FakeDisplayListRecordingSource> CreateRecordingSource( + const gfx::Rect& viewport) { + gfx::Rect layer_rect(viewport.right(), viewport.bottom()); + scoped_ptr<FakeDisplayListRecordingSource> recording_source = + FakeDisplayListRecordingSource::CreateRecordingSource(viewport, + layer_rect.size()); + return recording_source.Pass(); +} + +scoped_refptr<RasterSource> CreateRasterSource( + FakeDisplayListRecordingSource* recording_source) { + bool can_use_lcd_text = true; + return DisplayListRasterSource::CreateFromDisplayListRecordingSource( + recording_source, can_use_lcd_text); +} -TEST_F(DisplayListRecordingSourceTest, DiscardablePixelRefsWithTransform) { - gfx::Size grid_cell_size(128, 128); +TEST(DisplayListRecordingSourceTest, DiscardableImagesWithTransform) { gfx::Rect recorded_viewport(256, 256); scoped_ptr<FakeDisplayListRecordingSource> recording_source = FakeDisplayListRecordingSource::CreateFilledRecordingSource( recorded_viewport.size()); - recording_source->SetGridCellSize(grid_cell_size); - SkBitmap discardable_bitmap[2][2]; + skia::RefPtr<SkImage> discardable_image[2][2]; gfx::Transform identity_transform; - CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][0]); + discardable_image[0][0] = CreateDiscardableImage(gfx::Size(32, 32)); // 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]); + discardable_image[1][0] = CreateDiscardableImage(gfx::Size(32, 32)); // 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); + discardable_image[1][1] = CreateDiscardableImage(gfx::Size(32, 32)); + + gfx::RectF rect(0, 0, 32, 32); + gfx::RectF translate_rect = rect; + translate_transform.TransformRect(&translate_rect); + gfx::RectF rotate_rect = rect; + rotate_transform.TransformRect(&rotate_rect); + + recording_source->add_draw_image_with_transform(discardable_image[0][0].get(), + identity_transform); + recording_source->add_draw_image_with_transform(discardable_image[1][0].get(), + translate_transform); + recording_source->add_draw_image_with_transform(discardable_image[1][1].get(), + rotate_transform); + recording_source->SetGenerateDiscardableImagesMetadata(true); recording_source->Rerecord(); bool can_use_lcd_text = true; @@ -57,119 +72,60 @@ TEST_F(DisplayListRecordingSourceTest, DiscardablePixelRefsWithTransform) { // 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()); + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 128, 128), + &images); + EXPECT_EQ(2u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[0][0].get()); + EXPECT_TRUE(images[1].image == discardable_image[1][1].get()); + EXPECT_EQ(rect.ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + EXPECT_EQ(rotate_rect.ToString(), + gfx::SkRectToRectF(images[1].image_rect).ToString()); } // 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()); + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(130, 140, 128, 128), + &images); + EXPECT_EQ(1u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[1][1].get()); + EXPECT_EQ(rotate_rect.ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); } // 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()); + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(130, 0, 128, 128), + &images); + EXPECT_EQ(1u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[1][1].get()); + EXPECT_EQ(rotate_rect.ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); } - // 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()); - } + // Layer sized iterators. These should find all pixel refs. { - std::vector<SkPixelRef*> pixel_refs; - raster_source->GatherPixelRefs(gfx::Rect(0, 0, 512, 512), 2.0, &pixel_refs); - EXPECT_FALSE(pixel_refs.empty()); + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), + &images); + EXPECT_EQ(3u, images.size()); // 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()); + EXPECT_TRUE(images[0].image == discardable_image[0][0].get()); + EXPECT_TRUE(images[1].image == discardable_image[1][0].get()); + EXPECT_TRUE(images[2].image == discardable_image[1][1].get()); + EXPECT_EQ(rect.ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + EXPECT_EQ(translate_rect.ToString(), + gfx::SkRectToRectF(images[1].image_rect).ToString()); + EXPECT_EQ(rotate_rect.ToString(), + gfx::SkRectToRectF(images[2].image_rect).ToString()); } } -TEST_F(DisplayListRecordingSourceTest, ExposesEnoughNewAreaEmpty) { +TEST(DisplayListRecordingSourceTest, ExposesEnoughNewAreaEmpty) { gfx::Size layer_size(1000, 1000); // Both empty means there is nothing to do. @@ -185,7 +141,7 @@ TEST_F(DisplayListRecordingSourceTest, ExposesEnoughNewAreaEmpty) { gfx::Rect(1, 1), gfx::Rect(), layer_size)); } -TEST_F(DisplayListRecordingSourceTest, ExposesEnoughNewAreaNotBigEnough) { +TEST(DisplayListRecordingSourceTest, ExposesEnoughNewAreaNotBigEnough) { gfx::Size layer_size(1000, 1000); gfx::Rect current_recorded_viewport(100, 100, 100, 100); EXPECT_FALSE(DisplayListRecordingSource::ExposesEnoughNewArea( @@ -196,8 +152,8 @@ TEST_F(DisplayListRecordingSourceTest, ExposesEnoughNewAreaNotBigEnough) { current_recorded_viewport, gfx::Rect(1, 1, 200, 200), layer_size)); } -TEST_F(DisplayListRecordingSourceTest, - ExposesEnoughNewAreaNotBigEnoughButNewAreaTouchesEdge) { +TEST(DisplayListRecordingSourceTest, + ExposesEnoughNewAreaNotBigEnoughButNewAreaTouchesEdge) { gfx::Size layer_size(500, 500); gfx::Rect current_recorded_viewport(100, 100, 100, 100); @@ -220,8 +176,8 @@ TEST_F(DisplayListRecordingSourceTest, // Verifies that having a current viewport that touches a layer edge does not // force re-recording. -TEST_F(DisplayListRecordingSourceTest, - ExposesEnoughNewAreaCurrentViewportTouchesEdge) { +TEST(DisplayListRecordingSourceTest, + ExposesEnoughNewAreaCurrentViewportTouchesEdge) { gfx::Size layer_size(500, 500); gfx::Rect potential_new_viewport(100, 100, 300, 300); @@ -242,7 +198,7 @@ TEST_F(DisplayListRecordingSourceTest, gfx::Rect(400, 300, 100, 100), potential_new_viewport, layer_size)); } -TEST_F(DisplayListRecordingSourceTest, ExposesEnoughNewAreaScrollScenarios) { +TEST(DisplayListRecordingSourceTest, ExposesEnoughNewAreaScrollScenarios) { gfx::Size layer_size(1000, 1000); gfx::Rect current_recorded_viewport(100, 100, 100, 100); @@ -265,10 +221,9 @@ TEST_F(DisplayListRecordingSourceTest, ExposesEnoughNewAreaScrollScenarios) { // Verifies that UpdateAndExpandInvalidation calls ExposesEnoughNewArea with the // right arguments. -TEST_F(DisplayListRecordingSourceTest, - ExposesEnoughNewAreaCalledWithCorrectArguments) { - gfx::Size grid_cell_size(128, 128); - DisplayListRecordingSource recording_source(grid_cell_size); +TEST(DisplayListRecordingSourceTest, + ExposesEnoughNewAreaCalledWithCorrectArguments) { + DisplayListRecordingSource recording_source; FakeContentLayerClient client; Region invalidation; gfx::Size layer_size(9000, 9000); @@ -277,20 +232,20 @@ TEST_F(DisplayListRecordingSourceTest, recording_source.UpdateAndExpandInvalidation( &client, &invalidation, layer_size, visible_rect, 0, RecordingSource::RECORD_NORMALLY); - EXPECT_EQ(gfx::Rect(0, 0, 8256, 8256), recording_source.recorded_viewport()); + EXPECT_EQ(gfx::Rect(0, 0, 4256, 4256), recording_source.recorded_viewport()); visible_rect.Offset(0, 512); recording_source.UpdateAndExpandInvalidation( &client, &invalidation, layer_size, visible_rect, 0, RecordingSource::RECORD_NORMALLY); - EXPECT_EQ(gfx::Rect(0, 0, 8256, 8256), recording_source.recorded_viewport()); + EXPECT_EQ(gfx::Rect(0, 0, 4256, 4256), recording_source.recorded_viewport()); // Move past the threshold for enough exposed new area. visible_rect.Offset(0, 1); recording_source.UpdateAndExpandInvalidation( &client, &invalidation, layer_size, visible_rect, 0, RecordingSource::RECORD_NORMALLY); - EXPECT_EQ(gfx::Rect(0, 0, 8256, 8769), recording_source.recorded_viewport()); + EXPECT_EQ(gfx::Rect(0, 0, 4256, 4769), recording_source.recorded_viewport()); // Make the bottom of the potential new recorded viewport coincide with the // layer's bottom edge. @@ -298,7 +253,279 @@ TEST_F(DisplayListRecordingSourceTest, recording_source.UpdateAndExpandInvalidation( &client, &invalidation, layer_size, visible_rect, 0, RecordingSource::RECORD_NORMALLY); - EXPECT_EQ(gfx::Rect(0, 0, 8256, 9000), recording_source.recorded_viewport()); + EXPECT_EQ(gfx::Rect(0, 0, 4256, 4769), recording_source.recorded_viewport()); +} + +TEST(DisplayListRecordingSourceTest, NoGatherImageEmptyImages) { + gfx::Rect recorded_viewport(0, 0, 256, 256); + + scoped_ptr<FakeDisplayListRecordingSource> recording_source = + CreateRecordingSource(recorded_viewport); + recording_source->SetGenerateDiscardableImagesMetadata(false); + recording_source->Rerecord(); + + scoped_refptr<RasterSource> raster_source = + CreateRasterSource(recording_source.get()); + + // If recording source do not gather images, raster source is not going to + // get images. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(recorded_viewport, &images); + EXPECT_TRUE(images.empty()); + } +} + +TEST(DisplayListRecordingSourceTest, EmptyImages) { + gfx::Rect recorded_viewport(0, 0, 256, 256); + + scoped_ptr<FakeDisplayListRecordingSource> recording_source = + CreateRecordingSource(recorded_viewport); + recording_source->SetGenerateDiscardableImagesMetadata(true); + recording_source->Rerecord(); + + scoped_refptr<RasterSource> raster_source = + CreateRasterSource(recording_source.get()); + + // Tile sized iterators. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 128, 128), + &images); + EXPECT_TRUE(images.empty()); + } + // Shifted tile sized iterators. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(140, 140, 128, 128), + &images); + EXPECT_TRUE(images.empty()); + } + // Layer sized iterators. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), + &images); + EXPECT_TRUE(images.empty()); + } +} + +TEST(DisplayListRecordingSourceTest, NoDiscardableImages) { + gfx::Rect recorded_viewport(0, 0, 256, 256); + + scoped_ptr<FakeDisplayListRecordingSource> recording_source = + CreateRecordingSource(recorded_viewport); + + SkPaint simple_paint; + simple_paint.setColor(SkColorSetARGB(255, 12, 23, 34)); + + SkBitmap non_discardable_bitmap; + non_discardable_bitmap.allocN32Pixels(128, 128); + non_discardable_bitmap.setImmutable(); + skia::RefPtr<SkImage> non_discardable_image = + skia::AdoptRef(SkImage::NewFromBitmap(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_image(non_discardable_image.get(), + gfx::Point(128, 0)); + recording_source->add_draw_image(non_discardable_image.get(), + gfx::Point(0, 128)); + recording_source->add_draw_image(non_discardable_image.get(), + gfx::Point(150, 150)); + recording_source->SetGenerateDiscardableImagesMetadata(true); + recording_source->Rerecord(); + + scoped_refptr<RasterSource> raster_source = + CreateRasterSource(recording_source.get()); + + // Tile sized iterators. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 128, 128), + &images); + EXPECT_TRUE(images.empty()); + } + // Shifted tile sized iterators. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(140, 140, 128, 128), + &images); + EXPECT_TRUE(images.empty()); + } + // Layer sized iterators. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), + &images); + EXPECT_TRUE(images.empty()); + } +} + +TEST(DisplayListRecordingSourceTest, DiscardableImages) { + gfx::Rect recorded_viewport(0, 0, 256, 256); + + scoped_ptr<FakeDisplayListRecordingSource> recording_source = + CreateRecordingSource(recorded_viewport); + + skia::RefPtr<SkImage> discardable_image[2][2]; + discardable_image[0][0] = CreateDiscardableImage(gfx::Size(32, 32)); + discardable_image[1][0] = CreateDiscardableImage(gfx::Size(32, 32)); + discardable_image[1][1] = CreateDiscardableImage(gfx::Size(32, 32)); + + // Discardable images are found in the following cells: + // |---|---| + // | x | | + // |---|---| + // | x | x | + // |---|---| + recording_source->add_draw_image(discardable_image[0][0].get(), + gfx::Point(0, 0)); + recording_source->add_draw_image(discardable_image[1][0].get(), + gfx::Point(0, 130)); + recording_source->add_draw_image(discardable_image[1][1].get(), + gfx::Point(140, 140)); + recording_source->SetGenerateDiscardableImagesMetadata(true); + recording_source->Rerecord(); + + scoped_refptr<RasterSource> raster_source = + CreateRasterSource(recording_source.get()); + + // Tile sized iterators. These should find only one image. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 128, 128), + &images); + EXPECT_EQ(1u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[0][0].get()); + EXPECT_EQ(gfx::RectF(32, 32).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + } + + // Shifted tile sized iterators. These should find only one image. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(140, 140, 128, 128), + &images); + EXPECT_EQ(1u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[1][1].get()); + EXPECT_EQ(gfx::RectF(140, 140, 32, 32).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + } + + // Ensure there's no discardable images in the empty cell + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(140, 0, 128, 128), + &images); + EXPECT_TRUE(images.empty()); + } + + // Layer sized iterators. These should find all 3 images. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), + &images); + EXPECT_EQ(3u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[0][0].get()); + EXPECT_TRUE(images[1].image == discardable_image[1][0].get()); + EXPECT_TRUE(images[2].image == discardable_image[1][1].get()); + EXPECT_EQ(gfx::RectF(32, 32).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + EXPECT_EQ(gfx::RectF(0, 130, 32, 32).ToString(), + gfx::SkRectToRectF(images[1].image_rect).ToString()); + EXPECT_EQ(gfx::RectF(140, 140, 32, 32).ToString(), + gfx::SkRectToRectF(images[2].image_rect).ToString()); + } +} + +TEST(DisplayListRecordingSourceTest, DiscardableImagesBaseNonDiscardable) { + gfx::Rect recorded_viewport(0, 0, 512, 512); + + scoped_ptr<FakeDisplayListRecordingSource> recording_source = + CreateRecordingSource(recorded_viewport); + + SkBitmap non_discardable_bitmap; + non_discardable_bitmap.allocN32Pixels(512, 512); + non_discardable_bitmap.setImmutable(); + skia::RefPtr<SkImage> non_discardable_image = + skia::AdoptRef(SkImage::NewFromBitmap(non_discardable_bitmap)); + + skia::RefPtr<SkImage> discardable_image[2][2]; + discardable_image[0][0] = CreateDiscardableImage(gfx::Size(128, 128)); + discardable_image[0][1] = CreateDiscardableImage(gfx::Size(128, 128)); + discardable_image[1][1] = CreateDiscardableImage(gfx::Size(128, 128)); + + // One large non-discardable image covers the whole grid. + // Discardable images are found in the following cells: + // |---|---| + // | x | x | + // |---|---| + // | | x | + // |---|---| + recording_source->add_draw_image(non_discardable_image.get(), + gfx::Point(0, 0)); + recording_source->add_draw_image(discardable_image[0][0].get(), + gfx::Point(0, 0)); + recording_source->add_draw_image(discardable_image[0][1].get(), + gfx::Point(260, 0)); + recording_source->add_draw_image(discardable_image[1][1].get(), + gfx::Point(260, 260)); + recording_source->SetGenerateDiscardableImagesMetadata(true); + recording_source->Rerecord(); + + scoped_refptr<RasterSource> raster_source = + CreateRasterSource(recording_source.get()); + + // Tile sized iterators. These should find only one image. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), + &images); + EXPECT_EQ(1u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[0][0].get()); + EXPECT_EQ(gfx::RectF(128, 128).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + } + // Shifted tile sized iterators. These should find only one image. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(260, 260, 256, 256), + &images); + EXPECT_EQ(1u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[1][1].get()); + EXPECT_EQ(gfx::RectF(260, 260, 128, 128).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + } + // Ensure there's no discardable images in the empty cell + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 256, 256, 256), + &images); + EXPECT_TRUE(images.empty()); + } + // Layer sized iterators. These should find three images. + { + std::vector<PositionImage> images; + raster_source->GetDiscardableImagesInRect(gfx::Rect(0, 0, 512, 512), + &images); + EXPECT_EQ(3u, images.size()); + EXPECT_TRUE(images[0].image == discardable_image[0][0].get()); + EXPECT_TRUE(images[1].image == discardable_image[0][1].get()); + EXPECT_TRUE(images[2].image == discardable_image[1][1].get()); + EXPECT_EQ(gfx::RectF(128, 128).ToString(), + gfx::SkRectToRectF(images[0].image_rect).ToString()); + EXPECT_EQ(gfx::RectF(260, 0, 128, 128).ToString(), + gfx::SkRectToRectF(images[1].image_rect).ToString()); + EXPECT_EQ(gfx::RectF(260, 260, 128, 128).ToString(), + gfx::SkRectToRectF(images[2].image_rect).ToString()); + } } } // namespace diff --git a/chromium/cc/playback/drawing_display_item.cc b/chromium/cc/playback/drawing_display_item.cc index 6cebed2ae00..a1f54b42d01 100644 --- a/chromium/cc/playback/drawing_display_item.cc +++ b/chromium/cc/playback/drawing_display_item.cc @@ -51,6 +51,11 @@ void DrawingDisplayItem::Raster(SkCanvas* canvas, canvas->drawPicture(picture_.get()); } +void DrawingDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddDisplayItemWithBounds(picture_->cullRect()); +} + void DrawingDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->BeginDictionary(); diff --git a/chromium/cc/playback/drawing_display_item.h b/chromium/cc/playback/drawing_display_item.h index f94e7c9ca6e..5103bb52484 100644 --- a/chromium/cc/playback/drawing_display_item.h +++ b/chromium/cc/playback/drawing_display_item.h @@ -27,6 +27,8 @@ class CC_EXPORT DrawingDisplayItem : public DisplayItem { const gfx::Rect& canvas_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; void CloneTo(DrawingDisplayItem* item) const; diff --git a/chromium/cc/playback/filter_display_item.cc b/chromium/cc/playback/filter_display_item.cc index fbed01509c8..48fcab33ec1 100644 --- a/chromium/cc/playback/filter_display_item.cc +++ b/chromium/cc/playback/filter_display_item.cc @@ -43,9 +43,14 @@ void FilterDisplayItem::Raster(SkCanvas* canvas, skia::RefPtr<SkImageFilter> image_filter = RenderSurfaceFilters::BuildImageFilter( filters_, gfx::SizeF(bounds_.width(), bounds_.height())); +#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED + // TODO(senorblanco): remove this once callsites updated (crbug.com/525748) SkRect boundaries; image_filter->computeFastBounds( SkRect::MakeWH(bounds_.width(), bounds_.height()), &boundaries); +#else + SkRect boundaries = SkRect::MakeWH(bounds_.width(), bounds_.height()); +#endif SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); @@ -55,6 +60,12 @@ void FilterDisplayItem::Raster(SkCanvas* canvas, canvas->translate(-bounds_.x(), -bounds_.y()); } +void FilterDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddStartingDisplayItem(); + calculator->Save(); +} + void FilterDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString(base::StringPrintf("FilterDisplayItem bounds: [%s]", @@ -76,6 +87,12 @@ void EndFilterDisplayItem::Raster(SkCanvas* canvas, canvas->restore(); } +void EndFilterDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->Restore(); + calculator->AddEndingDisplayItem(); +} + void EndFilterDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString("EndFilterDisplayItem"); diff --git a/chromium/cc/playback/filter_display_item.h b/chromium/cc/playback/filter_display_item.h index 9672878752a..d9714c07cdc 100644 --- a/chromium/cc/playback/filter_display_item.h +++ b/chromium/cc/playback/filter_display_item.h @@ -26,6 +26,8 @@ class CC_EXPORT FilterDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; private: FilterOperations filters_; @@ -45,6 +47,8 @@ class CC_EXPORT EndFilterDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; }; } // namespace cc diff --git a/chromium/cc/playback/float_clip_display_item.cc b/chromium/cc/playback/float_clip_display_item.cc index 8b29fc214c5..5ba79a53f17 100644 --- a/chromium/cc/playback/float_clip_display_item.cc +++ b/chromium/cc/playback/float_clip_display_item.cc @@ -31,6 +31,11 @@ void FloatClipDisplayItem::Raster(SkCanvas* canvas, canvas->clipRect(gfx::RectFToSkRect(clip_rect_)); } +void FloatClipDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddStartingDisplayItem(); +} + void FloatClipDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString(base::StringPrintf("FloatClipDisplayItem rect: [%s]", @@ -52,6 +57,11 @@ void EndFloatClipDisplayItem::Raster( canvas->restore(); } +void EndFloatClipDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddEndingDisplayItem(); +} + void EndFloatClipDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString("EndFloatClipDisplayItem"); diff --git a/chromium/cc/playback/float_clip_display_item.h b/chromium/cc/playback/float_clip_display_item.h index 13d637f85a3..65449b886a8 100644 --- a/chromium/cc/playback/float_clip_display_item.h +++ b/chromium/cc/playback/float_clip_display_item.h @@ -27,6 +27,8 @@ class CC_EXPORT FloatClipDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; private: gfx::RectF clip_rect_; @@ -45,6 +47,8 @@ class CC_EXPORT EndFloatClipDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; }; } // namespace cc diff --git a/chromium/cc/playback/picture.cc b/chromium/cc/playback/picture.cc deleted file mode 100644 index 8ce9c66ff8f..00000000000 --- a/chromium/cc/playback/picture.cc +++ /dev/null @@ -1,338 +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/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/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/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/playback/picture.h b/chromium/cc/playback/picture.h deleted file mode 100644 index b19504b4270..00000000000 --- a/chromium/cc/playback/picture.h +++ /dev/null @@ -1,119 +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_PLAYBACK_PICTURE_H_ -#define CC_PLAYBACK_PICTURE_H_ - -#include "base/basictypes.h" -#include "base/containers/hash_tables.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/SkPicture.h" -#include "ui/gfx/geometry/rect.h" - -class SkPixelRef; - -namespace base { -class Value; -} - -namespace skia { -class AnalysisCanvas; -} - -namespace cc { - -class ContentLayerClient; - -class CC_EXPORT Picture - : public base::RefCountedThreadSafe<Picture> { - public: - static scoped_refptr<Picture> Create( - const gfx::Rect& layer_rect, - ContentLayerClient* client, - const gfx::Size& tile_grid_size, - bool gather_pixels_refs, - RecordingSource::RecordingMode recording_mode); - static scoped_refptr<Picture> CreateFromValue(const base::Value* value); - static scoped_refptr<Picture> CreateFromSkpValue(const base::Value* value); - - gfx::Rect LayerRect() const { return layer_rect_; } - - // Has Record() been called yet? - bool HasRecording() const { return picture_.get() != NULL; } - - bool IsSuitableForGpuRasterization(const char** reason) const; - int ApproximateOpCount() const; - size_t ApproximateMemoryUsage() const; - - bool HasText() const; - - // Apply this scale and raster the negated region into the canvas. - // |negated_content_region| specifies the region to be clipped out of the - // raster operation, i.e., the parts of the canvas which will not get drawn - // to. - int Raster(SkCanvas* canvas, - 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, SkPicture::AbortCallback* callback = NULL); - - scoped_ptr<base::Value> AsValue() const; - - void EmitTraceSnapshot() const; - void EmitTraceSnapshotAlias(Picture* original) const; - - bool WillPlayBackBitmaps() const { return picture_->willPlayBackBitmaps(); } - - PixelRefMap::Iterator GetPixelRefMapIterator( - const gfx::Rect& layer_rect) const; - - private: - 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>&, - const gfx::Rect& layer_rect, - const PixelRefMap& pixel_refs); - // This constructor will call AdoptRef on the SkPicture. - Picture(SkPicture*, const gfx::Rect& layer_rect); - ~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, - RecordingSource::RecordingMode recording_mode); - - // Gather pixel refs from recording. - void GatherPixelRefs(); - - gfx::Rect layer_rect_; - skia::RefPtr<SkPicture> picture_; - - PixelRefMap pixel_refs_; - - scoped_refptr<base::trace_event::ConvertableToTraceFormat> - AsTraceableRasterData(float scale) const; - scoped_refptr<base::trace_event::ConvertableToTraceFormat> - AsTraceableRecordData() const; - - friend class base::RefCountedThreadSafe<Picture>; - friend class PixelRefMap::Iterator; - DISALLOW_COPY_AND_ASSIGN(Picture); -}; - -} // namespace cc - -#endif // CC_PLAYBACK_PICTURE_H_ diff --git a/chromium/cc/playback/picture_pile.cc b/chromium/cc/playback/picture_pile.cc deleted file mode 100644 index 55a5f80997a..00000000000 --- a/chromium/cc/playback/picture_pile.cc +++ /dev/null @@ -1,699 +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/playback/picture_pile.h" - -#include <algorithm> -#include <limits> -#include <vector> - -#include "cc/base/histograms.h" -#include "cc/base/region.h" -#include "cc/playback/picture_pile_impl.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; - -// 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. -const float kDensityThreshold = 0.5f; - -bool rect_sort_y(const gfx::Rect& r1, const gfx::Rect& r2) { - return r1.y() < r2.y() || (r1.y() == r2.y() && r1.x() < r2.x()); -} - -bool rect_sort_x(const gfx::Rect& r1, const gfx::Rect& r2) { - return r1.x() < r2.x() || (r1.x() == r2.x() && r1.y() < r2.y()); -} - -float PerformClustering(const std::vector<gfx::Rect>& tiles, - std::vector<gfx::Rect>* clustered_rects) { - // These variables track the record area and invalid area - // for the entire clustering - int total_record_area = 0; - int total_invalid_area = 0; - - // These variables track the record area and invalid area - // for the current cluster being constructed. - gfx::Rect cur_record_rect; - int cluster_record_area = 0, cluster_invalid_area = 0; - - for (std::vector<gfx::Rect>::const_iterator it = tiles.begin(); - it != tiles.end(); - it++) { - gfx::Rect invalid_tile = *it; - - // For each tile, we consider adding the invalid tile to the - // current record rectangle. Only add it if the amount of empty - // space created is below a density threshold. - int tile_area = invalid_tile.width() * invalid_tile.height(); - - gfx::Rect proposed_union = cur_record_rect; - proposed_union.Union(invalid_tile); - int proposed_area = proposed_union.width() * proposed_union.height(); - float proposed_density = - static_cast<float>(cluster_invalid_area + tile_area) / - static_cast<float>(proposed_area); - - if (proposed_density >= kDensityThreshold) { - // It's okay to add this invalid tile to the - // current recording rectangle. - cur_record_rect = proposed_union; - cluster_record_area = proposed_area; - cluster_invalid_area += tile_area; - total_invalid_area += tile_area; - } else { - // Adding this invalid tile to the current recording rectangle - // would exceed our badness threshold, so put the current rectangle - // in the list of recording rects, and start a new one. - clustered_rects->push_back(cur_record_rect); - total_record_area += cluster_record_area; - cur_record_rect = invalid_tile; - cluster_invalid_area = tile_area; - cluster_record_area = tile_area; - } - } - - DCHECK(!cur_record_rect.IsEmpty()); - clustered_rects->push_back(cur_record_rect); - total_record_area += cluster_record_area;; - - DCHECK_NE(total_record_area, 0); - - return static_cast<float>(total_invalid_area) / - static_cast<float>(total_record_area); -} - -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; - } - - // Sort the invalid tiles by y coordinate. - std::vector<gfx::Rect> invalid_tiles_vertical = invalid_tiles; - std::sort(invalid_tiles_vertical.begin(), - invalid_tiles_vertical.end(), - rect_sort_y); - - std::vector<gfx::Rect> 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; - } - - // Now try again with a horizontal sort, see which one is best - std::vector<gfx::Rect> invalid_tiles_horizontal = invalid_tiles; - std::sort(invalid_tiles_horizontal.begin(), - invalid_tiles_horizontal.end(), - rect_sort_x); - - std::vector<gfx::Rect> horizontal_clustering; - float horizontal_density = - PerformClustering(invalid_tiles_horizontal, &horizontal_clustering); - - if (vertical_density < horizontal_density) { - *record_rects = horizontal_clustering; - return; - } - - *record_rects = vertical_clustering; -} - -#ifdef NDEBUG -const bool kDefaultClearCanvasSetting = false; -#else -const bool kDefaultClearCanvasSetting = true; -#endif - -DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER( - ScopedPicturePileUpdateTimer, - "Compositing.PicturePile.UpdateUs", - "Compositing.PicturePile.UpdateInvalidatedAreaPerMs"); - -} // namespace - -namespace cc { - -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() { -} - -bool PicturePile::UpdateAndExpandInvalidation( - ContentLayerClient* painter, - Region* invalidation, - const gfx::Size& layer_size, - const gfx::Rect& visible_layer_rect, - int frame_number, - RecordingSource::RecordingMode recording_mode) { - ScopedPicturePileUpdateTimer timer; - - 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); - - // Count the area that is being invalidated. - Region recorded_invalidation(*invalidation); - recorded_invalidation.Intersect(recorded_viewport_); - for (Region::Iterator it(recorded_invalidation); it.has_rect(); it.next()) - timer.AddArea(it.rect().size().GetArea()); - - 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 synthetic_invalidation; - gfx::Size old_tiling_size = GetSize(); - if (old_tiling_size != layer_size) { - tiling_.SetTilingSize(layer_size); - updated = true; - } - - gfx::Rect interest_rect_over_tiles = - tiling_.ExpandRectToTileBounds(interest_rect); - - 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 - // changed size. Newly exposed areas are considered invalidated. - // Previously exposed areas that are now outside of bounds also need to - // be invalidated, as they may become part of raster when scale < 1. - std::vector<PictureMapKey> to_erase; - int min_toss_x = tiling_.num_tiles_x(); - if (max_tiling_size.width() > min_tiling_size.width()) { - min_toss_x = - tiling_.FirstBorderTileXIndexFromSrcCoord(min_tiling_size.width()); - } - int min_toss_y = tiling_.num_tiles_y(); - if (max_tiling_size.height() > min_tiling_size.height()) { - min_toss_y = - tiling_.FirstBorderTileYIndexFromSrcCoord(min_tiling_size.height()); - } - 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_ = true; - continue; - } - to_erase.push_back(key); - } - - for (size_t i = 0; i < to_erase.size(); ++i) - picture_map_.erase(to_erase[i]); - - // If a recording is dropped and not re-recorded below, invalidate that - // full recording to cause any raster tiles that would use it to be - // dropped. - // If the recording will be replaced below, invalidate newly exposed - // areas and previously exposed areas to force raster tiles that include the - // old recording to know there is new recording to display. - gfx::Rect min_tiling_rect_over_tiles = - tiling_.ExpandRectToTileBounds(gfx::Rect(min_tiling_size)); - if (min_toss_x < tiling_.num_tiles_x()) { - // The bounds which we want to invalidate are the tiles along the old - // edge of the pile when expanding, or the new edge of the pile when - // shrinking. In either case, it's the difference of the two, so we'll - // call this bounding box the DELTA EDGE RECT. - // - // In the picture below, the delta edge rect would be the bounding box of - // tiles {h,i,j}. |min_toss_x| would be equal to the horizontal index of - // the same tiles. - // - // min pile edge-v max pile edge-v - // ---------------+ - - - - - - - -+ - // mmppssvvyybbeeh|h . - // mmppssvvyybbeeh|h . - // nnqqttwwzzccffi|i . - // nnqqttwwzzccffi|i . - // oorruuxxaaddggj|j . - // oorruuxxaaddggj|j . - // ---------------+ - - - - - - - -+ <- min pile edge - // . - // - - - - - - - - - - - - - - - -+ <- max pile edge - // - // If you were to slide a vertical beam from the left edge of the - // delta edge rect toward the right, it would either hit the right edge - // of the delta edge rect, or the interest rect (expanded to the bounds - // of the tiles it touches). The same is true for a beam parallel to - // any of the four edges, sliding across the delta edge rect. We use - // the union of these four rectangles generated by these beams to - // determine which part of the delta edge rect is outside of the expanded - // interest rect. - // - // Case 1: Intersect rect is outside the delta edge rect. It can be - // either on the left or the right. The |left_rect| and |right_rect|, - // cover this case, one will be empty and one will cover the full - // delta edge rect. In the picture below, |left_rect| would cover the - // delta edge rect, and |right_rect| would be empty. - // +----------------------+ |^^^^^^^^^^^^^^^| - // |===> DELTA EDGE RECT | | | - // |===> | | INTEREST RECT | - // |===> | | | - // |===> | | | - // +----------------------+ |vvvvvvvvvvvvvvv| - // - // Case 2: Interest rect is inside the delta edge rect. It will always - // fill the entire delta edge rect horizontally since the old edge rect - // is a single tile wide, and the interest rect has been expanded to the - // bounds of the tiles it touches. In this case the |left_rect| and - // |right_rect| will be empty, but the case is handled by the |top_rect| - // and |bottom_rect|. In the picture below, neither the |top_rect| nor - // |bottom_rect| would empty, they would each cover the area of the old - // edge rect outside the expanded interest rect. - // +-----------------+ - // |:::::::::::::::::| - // |:::::::::::::::::| - // |vvvvvvvvvvvvvvvvv| - // | | - // +-----------------+ - // | INTEREST RECT | - // | | - // +-----------------+ - // | | - // | DELTA EDGE RECT | - // +-----------------+ - // - // Lastly, we need to consider tiles inside the expanded interest rect. - // For those tiles, we want to invalidate exactly the newly exposed - // pixels. In the picture below the tiles in the delta edge rect have - // been resized and the area covered by periods must be invalidated. The - // |exposed_rect| will cover exactly that area. - // v-min pile edge - // +---------+-------+ - // | ........| - // | ........| - // | DELTA EDGE.RECT.| - // | ........| - // | ........| - // | ........| - // | ........| - // | ........| - // | ........| - // +---------+-------+ - - int left = tiling_.TilePositionX(min_toss_x); - int right = left + tiling_.TileSizeX(min_toss_x); - int top = min_tiling_rect_over_tiles.y(); - int bottom = min_tiling_rect_over_tiles.bottom(); - - int left_until = std::min(interest_rect_over_tiles.x(), right); - int right_until = std::max(interest_rect_over_tiles.right(), left); - int top_until = std::min(interest_rect_over_tiles.y(), bottom); - int bottom_until = std::max(interest_rect_over_tiles.bottom(), top); - - int exposed_left = min_tiling_size.width(); - int exposed_left_until = max_tiling_size.width(); - int exposed_top = top; - int exposed_bottom = max_tiling_size.height(); - DCHECK_GE(exposed_left, left); - - gfx::Rect left_rect(left, top, left_until - left, bottom - top); - gfx::Rect right_rect(right_until, top, right - right_until, bottom - top); - gfx::Rect top_rect(left, top, right - left, top_until - top); - gfx::Rect bottom_rect( - left, bottom_until, right - left, bottom - bottom_until); - gfx::Rect exposed_rect(exposed_left, - exposed_top, - exposed_left_until - exposed_left, - exposed_bottom - exposed_top); - 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 - // rect is the bounding box around the bottom row of tiles in the min - // pile. This would be tiles {o,r,u,x,a,d,g,j} in the above picture. - - int top = tiling_.TilePositionY(min_toss_y); - int bottom = top + tiling_.TileSizeY(min_toss_y); - int left = min_tiling_rect_over_tiles.x(); - int right = min_tiling_rect_over_tiles.right(); - - int top_until = std::min(interest_rect_over_tiles.y(), bottom); - int bottom_until = std::max(interest_rect_over_tiles.bottom(), top); - int left_until = std::min(interest_rect_over_tiles.x(), right); - int right_until = std::max(interest_rect_over_tiles.right(), left); - - int exposed_top = min_tiling_size.height(); - int exposed_top_until = max_tiling_size.height(); - int exposed_left = left; - int exposed_right = max_tiling_size.width(); - DCHECK_GE(exposed_top, top); - - gfx::Rect left_rect(left, top, left_until - left, bottom - top); - gfx::Rect right_rect(right_until, top, right - right_until, bottom - top); - gfx::Rect top_rect(left, top, right - left, top_until - top); - gfx::Rect bottom_rect( - left, bottom_until, right - left, bottom - bottom_until); - gfx::Rect exposed_rect(exposed_left, - exposed_top, - exposed_right - exposed_left, - exposed_top_until - exposed_top); - 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(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 - // be considerered fully invalid, so we can know to not keep around raster - // tiles that intersect with these recording tiles. - Region invalidation_expanded_to_full_tiles; - - for (Region::Iterator i(*invalidation); i.has_rect(); i.next()) { - gfx::Rect invalid_rect = i.rect(); - - // This rect covers the bounds (excluding borders) of all tiles whose - // bounds (including borders) touch the |interest_rect|. This matches - // the iteration of the |invalid_rect| below which includes borders when - // calling Invalidate() on pictures. - gfx::Rect invalid_rect_outside_interest_rect_tiles = - tiling_.ExpandRectToTileBounds(invalid_rect); - // We subtract the |interest_rect_over_tiles| which represents the bounds - // of tiles that will be re-recorded below. This matches the iteration of - // |interest_rect| below which includes borders. - // TODO(danakj): We should have a Rect-subtract-Rect-to-2-rects operator - // instead of using Rect::Subtract which gives you the bounding box of the - // subtraction. - invalid_rect_outside_interest_rect_tiles.Subtract( - interest_rect_over_tiles); - invalidation_expanded_to_full_tiles.Union( - invalid_rect_outside_interest_rect_tiles); - - // Split this inflated invalidation across tile boundaries and apply it - // to all tiles that it touches. - bool include_borders = true; - for (TilingData::Iterator iter(&tiling_, invalid_rect, include_borders); - iter; - ++iter) { - const PictureMapKey& key = iter.index(); - - PictureMap::iterator picture_it = picture_map_.find(key); - if (picture_it == picture_map_.end()) - continue; - - 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) - .Intersects(interest_rect_over_tiles), - invalidation_expanded_to_full_tiles.Contains( - tiling_.TileBounds(key.first, key.second))); - } - } - invalidation->Union(invalidation_expanded_to_full_tiles); - } - - 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. - bool include_borders = true; - for (TilingData::Iterator it(&tiling_, interest_rect, include_borders); it; - ++it) { - const PictureMapKey& key = it.index(); - if (picture_map_.find(key) == picture_map_.end()) - invalid_tiles->push_back(tiling_.TileBounds(key.first, key.second)); - } -} - -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; - - 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(&reason); - - if (!is_suitable_for_gpu_rasterization_) { - TRACE_EVENT_INSTANT1("cc", "GPU Rasterization Veto", - TRACE_EVENT_SCOPE_THREAD, "reason", reason); - } - } - } - - bool found_tile_for_recorded_picture = false; - - bool include_borders = true; - for (TilingData::Iterator it(&tiling_, padded_record_rect, include_borders); - it; ++it) { - const PictureMapKey& key = it.index(); - gfx::Rect tile = PaddedRect(key); - if (padded_record_rect.Contains(tile)) { - picture_map_[key] = picture; - found_tile_for_recorded_picture = true; - } - } - DCHECK(found_tile_for_recorded_picture); - } -} - -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() { - tiling_.SetTilingSize(gfx::Size()); - 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); - tile_iter; ++tile_iter) { - PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); - if (map_iter == picture_map_.end()) - return false; - } - return true; -} - -void PicturePile::DetermineIfSolidColor() { - is_solid_color_ = false; - solid_color_ = SK_ColorTRANSPARENT; - - if (picture_map_.empty()) { - return; - } - - PictureMap::const_iterator it = picture_map_.begin(); - 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. - if (!picture) - return; - - // Don't bother doing more work if the first image is too complicated. - if (picture->ApproximateOpCount() > kOpCountThatIsOkToAnalyze) - return; - - // Make sure all of the mapped images point to the same picture. - for (++it; it != picture_map_.end(); ++it) { - if (it->second.get() != picture) - return; - } - - 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 deleted file mode 100644 index 889e9f5d981..00000000000 --- a/chromium/cc/playback/picture_pile.h +++ /dev/null @@ -1,107 +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_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/playback/picture_pile_impl.cc b/chromium/cc/playback/picture_pile_impl.cc deleted file mode 100644 index 345c24c7093..00000000000 --- a/chromium/cc/playback/picture_pile_impl.cc +++ /dev/null @@ -1,465 +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 <algorithm> -#include <limits> -#include <set> - -#include "base/trace_event/trace_event.h" -#include "cc/base/region.h" -#include "cc/debug/debug_colors.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" -#include "ui/gfx/geometry/rect_conversions.h" - -namespace cc { - -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), - requires_clear_(true), - can_use_lcd_text_(true), - is_solid_color_(false), - solid_color_(SK_ColorTRANSPARENT), - has_any_recordings_(false), - clear_canvas_with_debug_color_(false), - min_contents_scale_(0.f), - slow_down_raster_scale_factor_for_debug_(0), - should_attempt_to_use_distance_field_text_(false), - picture_memory_usage_(0) { -} - -PicturePileImpl::PicturePileImpl(const PicturePile* 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_(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::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); -} - -void PicturePileImpl::PlaybackToCanvas(SkCanvas* canvas, - const gfx::Rect& canvas_bitmap_rect, - const gfx::Rect& canvas_playback_rect, - float contents_scale) const { - RasterSourceHelper::PrepareForPlaybackToCanvas( - canvas, canvas_bitmap_rect, canvas_bitmap_rect, - gfx::Rect(tiling_.tiling_size()), contents_scale, background_color_, - clear_canvas_with_debug_color_, requires_clear_); - RasterCommon(canvas, NULL, canvas_bitmap_rect, contents_scale); -} - -void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect, - const gfx::Rect& content_rect, - float contents_scale, - PictureRegionMap* results) const { - DCHECK(results); - // Rasterize the collection of relevant picture piles. - gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( - content_rect, 1.f / contents_scale); - - // Make sure pictures don't overlap by keeping track of previous right/bottom. - int min_content_left = -1; - int min_content_top = -1; - int last_row_index = -1; - int last_col_index = -1; - gfx::Rect last_content_rect; - - // Coalesce rasters of the same picture into different rects: - // - Compute the clip of each of the pile chunks, - // - Subtract it from the canvas rect to get difference region - // - Later, use the difference region to subtract each of the comprising - // rects from the canvas. - // Note that in essence, we're trying to mimic clipRegion with intersect op - // that also respects the current canvas transform and clip. In order to use - // the canvas transform, we must stick to clipRect operations (clipRegion - // ignores the transform). Intersect then can be written as subtracting the - // negation of the region we're trying to intersect. Luckily, we know that all - // of the rects will have to fit into |content_rect|, so we can start with - // that and subtract chunk rects to get the region that we need to subtract - // from the canvas. Then, we can use clipRect with difference op to subtract - // each rect in the region. - bool include_borders = true; - for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); - tile_iter; - ++tile_iter) { - PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); - if (map_iter == picture_map_.end()) - 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 - // of the picture chunk's layer rect. The min_contents_scale enforces that - // enough buffer pixels have been added such that the enclosed rect - // encompasses all invalidated pixels at any larger scale level. - gfx::Rect chunk_rect = PaddedRect(tile_iter.index()); - gfx::Rect content_clip = - gfx::ScaleToEnclosedRect(chunk_rect, contents_scale); - DCHECK(!content_clip.IsEmpty()) << "Layer rect: " - << picture->LayerRect().ToString() - << "Contents scale: " << contents_scale; - content_clip.Intersect(canvas_rect); - - // Make sure iterator goes top->bottom. - DCHECK_GE(tile_iter.index_y(), last_row_index); - if (tile_iter.index_y() > last_row_index) { - // First tile in a new row. - min_content_left = content_clip.x(); - min_content_top = last_content_rect.bottom(); - } else { - // Make sure iterator goes left->right. - DCHECK_GT(tile_iter.index_x(), last_col_index); - min_content_left = last_content_rect.right(); - min_content_top = last_content_rect.y(); - } - - last_col_index = tile_iter.index_x(); - last_row_index = tile_iter.index_y(); - - // Only inset if the content_clip is less than then previous min. - int inset_left = std::max(0, min_content_left - content_clip.x()); - int inset_top = std::max(0, min_content_top - content_clip.y()); - content_clip.Inset(inset_left, inset_top, 0, 0); - - PictureRegionMap::iterator it = results->find(picture); - Region* clip_region; - if (it == results->end()) { - // The clip for a set of coalesced pictures starts out clipping the entire - // canvas. Each picture added to the set must subtract its own bounds - // from the clip region, poking a hole so that the picture is unclipped. - clip_region = &(*results)[picture]; - *clip_region = canvas_rect; - } else { - clip_region = &it->second; - } - - DCHECK(clip_region->Contains(content_clip)) - << "Content clips should not overlap."; - clip_region->Subtract(content_clip); - last_content_rect = content_clip; - } -} - -void PicturePileImpl::RasterCommon(SkCanvas* canvas, - SkPicture::AbortCallback* callback, - const gfx::Rect& canvas_rect, - float contents_scale) const { - DCHECK(contents_scale >= min_contents_scale_); - - canvas->translate(-canvas_rect.x(), -canvas_rect.y()); - gfx::Rect content_tiling_rect = gfx::ToEnclosingRect( - gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale)); - content_tiling_rect.Intersect(canvas_rect); - - canvas->clipRect(gfx::RectToSkRect(content_tiling_rect), - SkRegion::kIntersect_Op); - - PictureRegionMap picture_region_map; - CoalesceRasters( - canvas_rect, content_tiling_rect, contents_scale, &picture_region_map); - -#ifndef NDEBUG - Region total_clip; -#endif // NDEBUG - - // Iterate the coalesced map and use each picture's region - // to clip the canvas. - for (PictureRegionMap::iterator it = picture_region_map.begin(); - it != picture_region_map.end(); - ++it) { - const Picture* picture = it->first; - Region negated_clip_region = it->second; - -#ifndef NDEBUG - Region positive_clip = content_tiling_rect; - positive_clip.Subtract(negated_clip_region); - // Make sure we never rasterize the same region twice. - DCHECK(!total_clip.Intersects(positive_clip)); - total_clip.Union(positive_clip); -#endif // NDEBUG - - int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); - - for (int j = 0; j < repeat_count; ++j) - picture->Raster(canvas, callback, negated_clip_region, contents_scale); - } - -#ifndef NDEBUG - // Fill the clip with debug color. This allows us to - // distinguish between non painted areas and problems with missing - // pictures. - SkPaint paint; - for (Region::Iterator it(total_clip); it.has_rect(); it.next()) - canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op); - paint.setColor(DebugColors::MissingPictureFillColor()); - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - canvas->drawPaint(paint); -#endif // NDEBUG -} - -skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() { - TRACE_EVENT0("cc", "PicturePileImpl::GetFlattenedPicture"); - - gfx::Rect tiling_rect(tiling_.tiling_size()); - SkPictureRecorder recorder; - SkCanvas* canvas = - recorder.beginRecording(tiling_rect.width(), tiling_rect.height()); - if (!tiling_rect.IsEmpty()) - PlaybackToCanvas(canvas, tiling_rect, tiling_rect, 1.0); - 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, - RasterSource::SolidColorAnalysis* analysis) const { - DCHECK(analysis); - TRACE_EVENT0("cc", "PicturePileImpl::PerformSolidColorAnalysis"); - - gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( - content_rect, 1.0f / contents_scale); - - layer_rect.Intersect(gfx::Rect(tiling_.tiling_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 PicturePileImpl::GatherPixelRefs( - const gfx::Rect& content_rect, - float contents_scale, - std::vector<SkPixelRef*>* pixel_refs) const { - DCHECK_EQ(0u, pixel_refs->size()); - for (PixelRefIterator iter(content_rect, contents_scale, this); iter; - ++iter) { - pixel_refs->push_back(*iter); - } -} - -bool PicturePileImpl::CoversRect(const gfx::Rect& content_rect, - float contents_scale) const { - if (tiling_.tiling_size().IsEmpty()) - return false; - gfx::Rect layer_rect = - gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale); - layer_rect.Intersect(gfx::Rect(tiling_.tiling_size())); - - // Common case inside of viewport to avoid the slower map lookups. - if (recorded_viewport_.Contains(layer_rect)) { - // Sanity check that there are no false positives in recorded_viewport_. - DCHECK(CanRasterSlowTileCheck(layer_rect)); - return true; - } - - 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(), - -buffer_pixels()); - return padded_rect; -} - -bool PicturePileImpl::CanRasterSlowTileCheck( - const gfx::Rect& layer_rect) const { - bool include_borders = false; - for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); - tile_iter; ++tile_iter) { - PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); - if (map_iter == picture_map_.end()) - return false; - } - return true; -} - -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::trace_event::TracedValue* pictures) const { - gfx::Rect tiling_rect(tiling_.tiling_size()); - std::set<const void*> appended_pictures; - bool include_borders = true; - for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders); - tile_iter; ++tile_iter) { - PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); - if (map_iter == picture_map_.end()) - continue; - - 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, - const PicturePileImpl* picture_pile) - : picture_pile_(picture_pile), - layer_rect_( - gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale)), - tile_iterator_(&picture_pile_->tiling_, - layer_rect_, - false /* include_borders */) { - // Early out if there isn't a single tile. - if (!tile_iterator_) - return; - - AdvanceToTilePictureWithPixelRefs(); -} - -PicturePileImpl::PixelRefIterator::~PixelRefIterator() { -} - -PicturePileImpl::PixelRefIterator& - PicturePileImpl::PixelRefIterator::operator++() { - ++pixel_ref_iterator_; - if (pixel_ref_iterator_) - return *this; - - ++tile_iterator_; - AdvanceToTilePictureWithPixelRefs(); - return *this; -} - -void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() { - for (; tile_iterator_; ++tile_iterator_) { - PictureMap::const_iterator it = - picture_pile_->picture_map_.find(tile_iterator_.index()); - if (it == picture_pile_->picture_map_.end()) - continue; - - const Picture* picture = it->second.get(); - if ((processed_pictures_.count(picture) != 0) || - !picture->WillPlayBackBitmaps()) - continue; - - processed_pictures_.insert(picture); - pixel_ref_iterator_ = picture->GetPixelRefMapIterator(layer_rect_); - if (pixel_ref_iterator_) - break; - } -} - -void PicturePileImpl::DidBeginTracing() { - std::set<const void*> processed_pictures; - 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); - } - } -} - -} // namespace cc diff --git a/chromium/cc/playback/picture_pile_impl.h b/chromium/cc/playback/picture_pile_impl.h deleted file mode 100644 index 0e1164b2dff..00000000000 --- a/chromium/cc/playback/picture_pile_impl.h +++ /dev/null @@ -1,160 +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_PLAYBACK_PICTURE_PILE_IMPL_H_ -#define CC_PLAYBACK_PICTURE_PILE_IMPL_H_ - -#include <map> -#include <set> -#include <vector> - -#include "base/time/time.h" -#include "cc/base/cc_export.h" -#include "cc/debug/rendering_stats_instrumentation.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" - -class SkCanvas; -class SkPicture; -class SkPixelRef; - -namespace gfx { -class Rect; -} - -namespace cc { - -class CC_EXPORT PicturePileImpl : public RasterSource { - public: - 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 - // reported rasterize time (in stats_instrumentation) is the minimum measured - // value over all runs. - void PlaybackToCanvas(SkCanvas* canvas, - const gfx::Rect& canvas_bitmap_rect, - const gfx::Rect& canvas_playback_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; - 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; - 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() 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. - class CC_EXPORT PixelRefIterator { - public: - PixelRefIterator(const gfx::Rect& content_rect, - float contents_scale, - const PicturePileImpl* picture_pile); - ~PixelRefIterator(); - - SkPixelRef* operator->() const { return *pixel_ref_iterator_; } - SkPixelRef* operator*() const { return *pixel_ref_iterator_; } - PixelRefIterator& operator++(); - operator bool() const { return pixel_ref_iterator_; } - - private: - void AdvanceToTilePictureWithPixelRefs(); - - const PicturePileImpl* picture_pile_; - gfx::Rect layer_rect_; - TilingData::Iterator tile_iterator_; - PixelRefMap::Iterator pixel_ref_iterator_; - std::set<const void*> processed_pictures_; - }; - - protected: - friend class PicturePile; - friend class PixelRefIterator; - - using PictureMapKey = PicturePile::PictureMapKey; - using PictureMap = PicturePile::PictureMap; - - PicturePileImpl(); - 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(); } - - // 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; - - // Called when analyzing a tile. We can use AnalysisCanvas as - // SkPicture::AbortCallback, which allows us to early out from analysis. - void RasterForAnalysis(skia::AnalysisCanvas* canvas, - const gfx::Rect& canvas_rect, - float contents_scale) const; - - void CoalesceRasters(const gfx::Rect& canvas_rect, - const gfx::Rect& content_rect, - float contents_scale, - PictureRegionMap* result) const; - - void RasterCommon(SkCanvas* canvas, - SkPicture::AbortCallback* 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. - bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const; - - gfx::Rect PaddedRect(const PictureMapKey& key) const; - - DISALLOW_COPY_AND_ASSIGN(PicturePileImpl); -}; - -} // namespace cc - -#endif // CC_PLAYBACK_PICTURE_PILE_IMPL_H_ diff --git a/chromium/cc/playback/picture_pile_impl_perftest.cc b/chromium/cc/playback/picture_pile_impl_perftest.cc deleted file mode 100644 index e1560400f22..00000000000 --- a/chromium/cc/playback/picture_pile_impl_perftest.cc +++ /dev/null @@ -1,84 +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/playback/picture_pile_impl.h" - -#include "cc/debug/lap_timer.h" -#include "cc/test/fake_picture_pile_impl.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 kTileSize = 100; -const int kLayerSize = 1000; - -class PicturePileImplPerfTest : public testing::Test { - public: - PicturePileImplPerfTest() - : timer_(kWarmupRuns, - base::TimeDelta::FromMilliseconds(kTimeLimitMillis), - kTimeCheckInterval) {} - - void RunAnalyzeTest(const std::string& test_name, float contents_scale) { - scoped_refptr<PicturePileImpl> pile = FakePicturePileImpl::CreateFilledPile( - gfx::Size(kTileSize, kTileSize), gfx::Size(kLayerSize, kLayerSize)); - // Content rect that will align with top-left tile at scale 1.0. - gfx::Rect content_rect(0, 0, kTileSize, kTileSize); - - RasterSource::SolidColorAnalysis analysis; - timer_.Reset(); - do { - pile->PerformSolidColorAnalysis(content_rect, contents_scale, &analysis); - timer_.NextLap(); - } while (!timer_.HasTimeLimitExpired()); - - perf_test::PrintResult( - "analyze", "", test_name, timer_.LapsPerSecond(), "runs/s", true); - } - - void RunRasterTest(const std::string& test_name, float contents_scale) { - scoped_refptr<PicturePileImpl> pile = FakePicturePileImpl::CreateFilledPile( - gfx::Size(kTileSize, kTileSize), gfx::Size(kLayerSize, kLayerSize)); - // Content rect that will align with top-left tile at scale 1.0. - gfx::Rect content_rect(0, 0, kTileSize, kTileSize); - - SkBitmap bitmap; - bitmap.allocN32Pixels(1, 1); - SkCanvas canvas(bitmap); - - timer_.Reset(); - do { - pile->PlaybackToCanvas(&canvas, content_rect, content_rect, - contents_scale); - timer_.NextLap(); - } while (!timer_.HasTimeLimitExpired()); - - perf_test::PrintResult( - "raster", "", test_name, timer_.LapsPerSecond(), "runs/s", true); - } - - private: - LapTimer timer_; -}; - -TEST_F(PicturePileImplPerfTest, Analyze) { - RunAnalyzeTest("1", 1.0f); - RunAnalyzeTest("4", 0.5f); - RunAnalyzeTest("100", 0.1f); -} - -TEST_F(PicturePileImplPerfTest, Raster) { - RunRasterTest("1", 1.0f); - RunRasterTest("4", 0.5f); - RunRasterTest("100", 0.1f); -} - -} // namespace -} // namespace cc diff --git a/chromium/cc/playback/picture_pile_impl_unittest.cc b/chromium/cc/playback/picture_pile_impl_unittest.cc deleted file mode 100644 index 81c2aec4713..00000000000 --- a/chromium/cc/playback/picture_pile_impl_unittest.cc +++ /dev/null @@ -1,550 +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 "base/memory/scoped_ptr.h" -#include "cc/test/fake_picture_pile_impl.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/SkPixelRef.h" -#include "third_party/skia/include/core/SkShader.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size_conversions.h" - -namespace cc { -namespace { - -TEST(PicturePileImplTest, AnalyzeIsSolidUnscaled) { - gfx::Size tile_size(100, 100); - gfx::Size layer_bounds(400, 400); - - scoped_ptr<FakePicturePile> recording_source = - FakePicturePile::CreateFilledPile(tile_size, layer_bounds); - - 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); - - 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. - for (int y = 0; y <= 300; y += 100) { - for (int x = 0; x <= 300; x += 100) { - RasterSource::SolidColorAnalysis analysis; - gfx::Rect rect(x, y, 100, 100); - pile->PerformSolidColorAnalysis(rect, 1.0, &analysis); - EXPECT_TRUE(analysis.is_solid_color) << rect.ToString(); - EXPECT_EQ(analysis.solid_color, solid_color) << rect.ToString(); - } - } - - // 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); - EXPECT_FALSE(analysis.is_solid_color); - - pile->PerformSolidColorAnalysis(gfx::Rect(100, 0, 100, 100), 1.0, &analysis); - EXPECT_TRUE(analysis.is_solid_color); - EXPECT_EQ(analysis.solid_color, solid_color); - - // 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); - EXPECT_EQ(analysis.solid_color, solid_color); - - analysis.is_solid_color = false; - pile->PerformSolidColorAnalysis(gfx::Rect(0, 350, 100, 100), 1.0, &analysis); - EXPECT_TRUE(analysis.is_solid_color); - EXPECT_EQ(analysis.solid_color, solid_color); - - analysis.is_solid_color = false; - pile->PerformSolidColorAnalysis(gfx::Rect(350, 350, 100, 100), 1.0, - &analysis); - EXPECT_TRUE(analysis.is_solid_color); - EXPECT_EQ(analysis.solid_color, solid_color); -} - -TEST(PicturePileImplTest, AnalyzeIsSolidScaled) { - gfx::Size tile_size(100, 100); - gfx::Size layer_bounds(400, 400); - - scoped_ptr<FakePicturePile> recording_source = - FakePicturePile::CreateFilledPile(tile_size, layer_bounds); - - SkColor solid_color = SkColorSetARGB(255, 12, 23, 34); - SkPaint solid_paint; - 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); - - 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. - for (int y = 0; y <= 30; y += 10) { - for (int x = 0; x <= 30; x += 10) { - RasterSource::SolidColorAnalysis analysis; - gfx::Rect rect(x, y, 10, 10); - pile->PerformSolidColorAnalysis(rect, 0.1f, &analysis); - EXPECT_TRUE(analysis.is_solid_color) << rect.ToString(); - EXPECT_EQ(analysis.solid_color, solid_color) << rect.ToString(); - } - } - - // 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); - EXPECT_FALSE(analysis.is_solid_color); - - pile->PerformSolidColorAnalysis(gfx::Rect(10, 0, 10, 10), 0.1f, &analysis); - EXPECT_TRUE(analysis.is_solid_color); - EXPECT_EQ(analysis.solid_color, solid_color); - - // 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); - EXPECT_EQ(analysis.solid_color, solid_color); - - analysis.is_solid_color = false; - pile->PerformSolidColorAnalysis(gfx::Rect(0, 35, 10, 10), 0.1f, &analysis); - EXPECT_TRUE(analysis.is_solid_color); - EXPECT_EQ(analysis.solid_color, solid_color); - - analysis.is_solid_color = false; - pile->PerformSolidColorAnalysis(gfx::Rect(35, 35, 10, 10), 0.1f, &analysis); - EXPECT_TRUE(analysis.is_solid_color); - EXPECT_EQ(analysis.solid_color, solid_color); -} - -TEST(PicturePileImplTest, AnalyzeIsSolidEmpty) { - gfx::Size tile_size(100, 100); - gfx::Size layer_bounds(400, 400); - - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); - RasterSource::SolidColorAnalysis analysis; - EXPECT_FALSE(analysis.is_solid_color); - - pile->PerformSolidColorAnalysis(gfx::Rect(0, 0, 400, 400), 1.f, &analysis); - - EXPECT_TRUE(analysis.is_solid_color); - EXPECT_EQ(analysis.solid_color, SkColorSetARGB(0, 0, 0, 0)); -} - -TEST(PicturePileImplTest, PixelRefIteratorDiscardableRefsOneTile) { - gfx::Size tile_size(256, 256); - gfx::Size layer_bounds(512, 512); - - 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]); - CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][1]); - 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[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<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr); - - // 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); - } - - // Copy test. - 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()); - - // copy now points to the same spot as iterator, - // but both can be incremented independently. - PicturePileImpl::PixelRefIterator copy = iterator; - EXPECT_TRUE(++iterator); - EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef()); - EXPECT_FALSE(++iterator); - - EXPECT_TRUE(copy); - EXPECT_TRUE(*copy == discardable_bitmap[0][1].pixelRef()); - EXPECT_TRUE(++copy); - EXPECT_TRUE(*copy == discardable_bitmap[1][1].pixelRef()); - EXPECT_FALSE(++copy); -} - -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; - - 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); - recording_source->add_draw_rect_with_paint(gfx::Rect(layer_bounds), - white_paint); - - 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))); - - // Simulate drawing into different tiles at different offsets. - int step_x = std::ceil(content_bounds.width() / raster_divisions); - int step_y = std::ceil(content_bounds.height() / raster_divisions); - for (int offset_x = 0; offset_x < content_bounds.width(); - offset_x += step_x) { - for (int offset_y = 0; offset_y < content_bounds.height(); - offset_y += step_y) { - gfx::Rect content_rect(offset_x, offset_y, step_x, step_y); - content_rect.Intersect(gfx::Rect(content_bounds)); - - // Simulate a canvas rect larger than the content rect. Every pixel - // up to one pixel outside the content rect is guaranteed to be opaque. - // Outside of that is undefined. - gfx::Rect canvas_rect(content_rect); - canvas_rect.Inset(0, 0, -1, -1); - - SkBitmap bitmap; - bitmap.allocN32Pixels(canvas_rect.width(), canvas_rect.height()); - SkCanvas canvas(bitmap); - canvas.clear(SK_ColorTRANSPARENT); - - pile->PlaybackToCanvas(&canvas, canvas_rect, canvas_rect, contents_scale); - - SkColor* pixels = reinterpret_cast<SkColor*>(bitmap.getPixels()); - int num_pixels = bitmap.width() * bitmap.height(); - bool all_white = true; - for (int i = 0; i < num_pixels; ++i) { - EXPECT_EQ(SkColorGetA(pixels[i]), 255u); - all_white &= (SkColorGetR(pixels[i]) == 255); - all_white &= (SkColorGetG(pixels[i]) == 255); - all_white &= (SkColorGetB(pixels[i]) == 255); - } - - // If the canvas doesn't extend past the edge of the content, - // it should be entirely white. Otherwise, the edge of the content - // will be non-white. - EXPECT_EQ(all_white, gfx::Rect(content_bounds).Contains(canvas_rect)); - } - } -} - -TEST(PicturePileImpl, RasterContentsTransparent) { - gfx::Size tile_size(1000, 1000); - gfx::Size layer_bounds(5, 3); - float contents_scale = 0.5f; - - 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))); - - gfx::Rect canvas_rect(content_bounds); - canvas_rect.Inset(0, 0, -1, -1); - - SkBitmap bitmap; - bitmap.allocN32Pixels(canvas_rect.width(), canvas_rect.height()); - SkCanvas canvas(bitmap); - - pile->PlaybackToCanvas(&canvas, canvas_rect, canvas_rect, contents_scale); - - SkColor* pixels = reinterpret_cast<SkColor*>(bitmap.getPixels()); - int num_pixels = bitmap.width() * bitmap.height(); - for (int i = 0; i < num_pixels; ++i) { - EXPECT_EQ(SkColorGetA(pixels[i]), 0u); - } -} - -class OverlapTest : public ::testing::TestWithParam<float> { - public: - static float MinContentsScale() { return 1.f / 4.f; } -}; - -TEST_P(OverlapTest, NoOverlap) { - gfx::Size tile_size(10, 10); - gfx::Size layer_bounds(30, 30); - gfx::Size bigger_than_layer_bounds(300, 300); - float contents_scale = GetParam(); - // Pick an opaque color to not have to deal with premultiplication off-by-one. - SkColor test_color = SkColorSetARGB(255, 45, 56, 67); - - 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. - 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))); - - SkBitmap bitmap; - bitmap.allocN32Pixels(content_bounds.width(), content_bounds.height()); - SkCanvas canvas(bitmap); - - pile->PlaybackToCanvas(&canvas, gfx::Rect(content_bounds), - gfx::Rect(content_bounds), contents_scale); - - for (int y = 0; y < bitmap.height(); y++) { - for (int x = 0; x < bitmap.width(); x++) { - SkColor color = bitmap.getColor(x, y); - EXPECT_EQ(SkColorGetR(test_color), SkColorGetR(color)) << "x: " << x - << ", y: " << y; - EXPECT_EQ(SkColorGetG(test_color), SkColorGetG(color)) << "x: " << x - << ", y: " << y; - EXPECT_EQ(SkColorGetB(test_color), SkColorGetB(color)) << "x: " << x - << ", y: " << y; - EXPECT_EQ(SkColorGetA(test_color), SkColorGetA(color)) << "x: " << x - << ", y: " << y; - if (test_color != color) - break; - } - } -} - -INSTANTIATE_TEST_CASE_P(PicturePileImpl, - OverlapTest, - ::testing::Values(1.f, 0.873f, 1.f / 4.f, 4.f)); - -TEST(PicturePileImplTest, PixelRefIteratorBorders) { - // 3 tile width / 1 tile height pile - gfx::Size tile_size(128, 128); - gfx::Size layer_bounds(320, 128); - - // 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_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[] = { - 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]); - 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( - bitmap_rects[0].Intersects(pile->tiling().TileBoundsWithBorder(1, 0))); - EXPECT_FALSE(bitmap_rects[0].Intersects(pile->tiling().TileBounds(1, 0))); - EXPECT_TRUE( - bitmap_rects[1].Intersects(pile->tiling().TileBoundsWithBorder(0, 0))); - EXPECT_FALSE(bitmap_rects[1].Intersects(pile->tiling().TileBounds(0, 0))); - EXPECT_TRUE( - bitmap_rects[1].Intersects(pile->tiling().TileBoundsWithBorder(2, 0))); - EXPECT_FALSE(bitmap_rects[1].Intersects(pile->tiling().TileBounds(2, 0))); - EXPECT_TRUE( - bitmap_rects[2].Intersects(pile->tiling().TileBoundsWithBorder(1, 0))); - EXPECT_FALSE(bitmap_rects[2].Intersects(pile->tiling().TileBounds(1, 0))); - - // Tile-sized iterators. - { - // Because tile 0's borders extend onto tile 1, it will include both - // bitmap 0 and 1. However, it should *not* include bitmap 2. - PicturePileImpl::PixelRefIterator iterator( - pile->tiling().TileBounds(0, 0), 1.f, pile.get()); - EXPECT_TRUE(iterator); - EXPECT_TRUE(*iterator == discardable_bitmap[0].pixelRef()); - EXPECT_TRUE(++iterator); - EXPECT_TRUE(*iterator == discardable_bitmap[1].pixelRef()); - EXPECT_FALSE(++iterator); - } - { - // Tile 1 + borders hits all bitmaps. - PicturePileImpl::PixelRefIterator iterator( - pile->tiling().TileBounds(1, 0), 1.f, pile.get()); - EXPECT_TRUE(iterator); - EXPECT_TRUE(*iterator == discardable_bitmap[0].pixelRef()); - EXPECT_TRUE(++iterator); - EXPECT_TRUE(*iterator == discardable_bitmap[1].pixelRef()); - EXPECT_TRUE(++iterator); - EXPECT_TRUE(*iterator == discardable_bitmap[2].pixelRef()); - EXPECT_FALSE(++iterator); - } - { - // Tile 2 should not include bitmap 0, which is only on tile 0 and the - // borders of tile 1. - PicturePileImpl::PixelRefIterator iterator( - pile->tiling().TileBounds(2, 0), 1.f, pile.get()); - EXPECT_TRUE(iterator); - EXPECT_TRUE(*iterator == discardable_bitmap[1].pixelRef()); - EXPECT_TRUE(++iterator); - EXPECT_TRUE(*iterator == discardable_bitmap[2].pixelRef()); - EXPECT_FALSE(++iterator); - } -} - -} // namespace -} // namespace cc diff --git a/chromium/cc/playback/picture_pile_unittest.cc b/chromium/cc/playback/picture_pile_unittest.cc deleted file mode 100644 index f929aeffb0a..00000000000 --- a/chromium/cc/playback/picture_pile_unittest.cc +++ /dev/null @@ -1,1345 +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 <map> -#include <utility> - -#include "cc/playback/picture_pile.h" -#include "cc/test/fake_content_layer_client.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" - -namespace cc { -namespace { - -class PicturePileTestBase { - public: - PicturePileTestBase() - : min_scale_(0.125), - pile_(min_scale_, gfx::Size(1000, 1000)), - frame_number_(0) {} - - void InitializeData() { - pile_.SetTileGridSize(gfx::Size(1000, 1000)); - pile_.SetMinContentsScale(min_scale_); - client_ = FakeContentLayerClient(); - SetTilingSize(pile_.tiling().max_texture_size()); - } - - void SetTilingSize(const gfx::Size& tiling_size) { - Region invalidation; - gfx::Rect viewport_rect(tiling_size); - UpdateAndExpandInvalidation(&invalidation, tiling_size, viewport_rect); - } - - 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, layer_size, - visible_layer_rect, frame_number_, - RecordingSource::RECORD_NORMALLY); - } - - bool UpdateWholePile() { - Region invalidation = tiling_rect(); - bool result = UpdateAndExpandInvalidation(&invalidation, tiling_size(), - tiling_rect()); - EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString()); - return result; - } - - FakeContentLayerClient client_; - float min_scale_; - FakePicturePile pile_; - int frame_number_; -}; - -class PicturePileTest : public PicturePileTestBase, public testing::Test { - public: - void SetUp() override { InitializeData(); } -}; - -TEST_F(PicturePileTest, InvalidationOnTileBorderOutsideInterestRect) { - // Don't expand the interest rect past what we invalidate. - pile_.SetPixelRecordDistance(0); - - gfx::Size tile_size(100, 100); - pile_.tiling().SetMaxTextureSize(tile_size); - - gfx::Size pile_size(400, 400); - SetTilingSize(pile_size); - - // We have multiple tiles. - EXPECT_GT(pile_.tiling().num_tiles_x(), 2); - EXPECT_GT(pile_.tiling().num_tiles_y(), 2); - - // Record everything. - Region invalidation(tiling_rect()); - UpdateAndExpandInvalidation(&invalidation, tiling_size(), tiling_rect()); - - // +----------+-----------------+-----------+ - // | | VVVV 1,0| | - // | | VVVV | | - // | | VVVV | | - // | ...|.................|... | - // | ...|.................|... | - // +----------+-----------------+-----------+ - // | ...| |... | - // | ...| |... | - // | ...| |... | - // | ...| |... | - // | ...| 1,1|... | - // +----------+-----------------+-----------+ - // | ...|.................|... | - // | ...|.................|... | - // +----------+-----------------+-----------+ - // - // .. = border pixels for tile 1,1 - // VV = interest rect (what we will record) - // - // The first invalidation is inside VV, so it does not touch border pixels of - // tile 1,1. - // - // The second invalidation goes below VV into the .. border pixels of 1,1. - - // This is the VV interest rect which will be entirely inside 1,0 and not - // touch the border of 1,1. - gfx::Rect interest_rect( - pile_.tiling().TilePositionX(1) + pile_.tiling().border_texels(), - 0, - 10, - pile_.tiling().TileSizeY(0) - pile_.tiling().border_texels()); - - // Invalidate tile 1,0 only. This is a rect that avoids the borders of any - // other tiles. - gfx::Rect invalidate_tile = interest_rect; - // This should cause the tile 1,0 to be invalidated and re-recorded. The - // invalidation did not need to be expanded. - invalidation = invalidate_tile; - UpdateAndExpandInvalidation(&invalidation, tiling_size(), interest_rect); - EXPECT_EQ(invalidate_tile, invalidation); - - // Invalidate tile 1,0 and 1,1 by invalidating something that only touches the - // border of 1,1 (and is inside the tile bounds of 1,0). This is a 10px wide - // strip from the top of the tiling onto the border pixels of tile 1,1 that - // avoids border pixels of any other tiles. - gfx::Rect invalidate_border = interest_rect; - invalidate_border.Inset(0, 0, 0, -1); - // This should cause the tile 1,0 and 1,1 to be invalidated. The 1,1 tile will - // not be re-recorded since it does not touch the interest rect, so the - // invalidation should be expanded to cover all of 1,1. - invalidation = invalidate_border; - UpdateAndExpandInvalidation(&invalidation, tiling_size(), interest_rect); - Region expected_invalidation = invalidate_border; - expected_invalidation.Union(pile_.tiling().TileBounds(1, 1)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); -} - -TEST_F(PicturePileTest, SmallInvalidateInflated) { - // Invalidate something inside a tile. - Region invalidate_rect(gfx::Rect(50, 50, 1, 1)); - UpdateAndExpandInvalidation(&invalidate_rect, tiling_size(), tiling_rect()); - EXPECT_EQ(gfx::Rect(50, 50, 1, 1).ToString(), invalidate_rect.ToString()); - - EXPECT_EQ(1, pile_.tiling().num_tiles_x()); - EXPECT_EQ(1, pile_.tiling().num_tiles_y()); - - 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(); -} - -TEST_F(PicturePileTest, LargeInvalidateInflated) { - // Invalidate something inside a tile. - Region invalidate_rect(gfx::Rect(50, 50, 100, 100)); - UpdateAndExpandInvalidation(&invalidate_rect, tiling_size(), tiling_rect()); - EXPECT_EQ(gfx::Rect(50, 50, 100, 100).ToString(), invalidate_rect.ToString()); - - EXPECT_EQ(1, pile_.tiling().num_tiles_x()); - EXPECT_EQ(1, pile_.tiling().num_tiles_y()); - - 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(); - - gfx::Rect base_picture_rect(tiling_size()); - base_picture_rect.Inset(-expected_inflation, -expected_inflation); - EXPECT_EQ(base_picture_rect.ToString(), picture->LayerRect().ToString()); -} - -TEST_F(PicturePileTest, ClearingInvalidatesRecordedRect) { - gfx::Rect rect(0, 0, 5, 5); - EXPECT_TRUE(pile_.CanRasterLayerRect(rect)); - EXPECT_TRUE(pile_.CanRasterSlowTileCheck(rect)); - - pile_.Clear(); - - // Make sure both the cache-aware check (using recorded region) and the normal - // check are both false after clearing. - EXPECT_FALSE(pile_.CanRasterLayerRect(rect)); - EXPECT_FALSE(pile_.CanRasterSlowTileCheck(rect)); -} - -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 - // issue because CanRaster checks will go down the slow path. - EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty()); - - // No invalidation, same viewport. - Region invalidation; - UpdateAndExpandInvalidation(&invalidation, tiling_size(), tiling_rect()); - EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty()); - EXPECT_EQ(Region().ToString(), invalidation.ToString()); - - // Partial invalidation, same viewport. - invalidation = gfx::Rect(0, 0, 1, 1); - UpdateAndExpandInvalidation(&invalidation, tiling_size(), tiling_rect()); - EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty()); - EXPECT_EQ(gfx::Rect(0, 0, 1, 1).ToString(), invalidation.ToString()); - - // No invalidation, changing viewport. - invalidation = Region(); - UpdateAndExpandInvalidation(&invalidation, tiling_size(), - gfx::Rect(5, 5, 5, 5)); - EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty()); - EXPECT_EQ(Region().ToString(), invalidation.ToString()); -} - -TEST_F(PicturePileTest, BigFullLayerInvalidation) { - gfx::Size huge_layer_size(100000000, 100000000); - gfx::Rect viewport(300000, 400000, 5000, 6000); - - // Resize the pile. - Region invalidation; - UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); - - // Invalidating a huge layer should be fast. - base::TimeTicks start = base::TimeTicks::Now(); - invalidation = gfx::Rect(huge_layer_size); - UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); - base::TimeTicks end = base::TimeTicks::Now(); - base::TimeDelta length = end - start; - // This is verrrry generous to avoid flake. - EXPECT_LT(length.InSeconds(), 5); -} - -TEST_F(PicturePileTest, BigFullLayerInvalidationWithResizeGrow) { - gfx::Size huge_layer_size(100000000, 100000000); - gfx::Rect viewport(300000, 400000, 5000, 6000); - - // Resize the pile. - Region invalidation; - UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); - - // Resize the pile even larger, while invalidating everything in the old size. - // Invalidating the whole thing should be fast. - base::TimeTicks start = base::TimeTicks::Now(); - gfx::Size bigger_layer_size(huge_layer_size.width() * 2, - huge_layer_size.height() * 2); - invalidation = gfx::Rect(huge_layer_size); - UpdateAndExpandInvalidation(&invalidation, bigger_layer_size, viewport); - base::TimeTicks end = base::TimeTicks::Now(); - base::TimeDelta length = end - start; - // This is verrrry generous to avoid flake. - EXPECT_LT(length.InSeconds(), 5); -} - -TEST_F(PicturePileTest, BigFullLayerInvalidationWithResizeShrink) { - gfx::Size huge_layer_size(100000000, 100000000); - gfx::Rect viewport(300000, 400000, 5000, 6000); - - // Resize the pile. - Region invalidation; - UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); - - // Resize the pile smaller, while invalidating everything in the new size. - // Invalidating the whole thing should be fast. - base::TimeTicks start = base::TimeTicks::Now(); - gfx::Size smaller_layer_size(huge_layer_size.width() - 1000, - huge_layer_size.height() - 1000); - invalidation = gfx::Rect(smaller_layer_size); - UpdateAndExpandInvalidation(&invalidation, smaller_layer_size, viewport); - base::TimeTicks end = base::TimeTicks::Now(); - base::TimeDelta length = end - start; - // This is verrrry generous to avoid flake. - EXPECT_LT(length.InSeconds(), 5); -} - -TEST_F(PicturePileTest, InvalidationOutsideRecordingRect) { - gfx::Size huge_layer_size(10000000, 20000000); - gfx::Rect viewport(300000, 400000, 5000, 6000); - - // Resize the pile and set up the interest rect. - Region invalidation; - UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); - - // Invalidation inside the recording rect does not need to be expanded. - invalidation = viewport; - UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); - EXPECT_EQ(viewport.ToString(), invalidation.ToString()); - - // Invalidation outside the recording rect should expand to the tiles it - // covers. - gfx::Rect recorded_over_tiles = - pile_.tiling().ExpandRectToTileBounds(pile_.recorded_viewport()); - gfx::Rect invalidation_outside( - recorded_over_tiles.right(), recorded_over_tiles.y(), 30, 30); - invalidation = invalidation_outside; - UpdateAndExpandInvalidation(&invalidation, huge_layer_size, viewport); - gfx::Rect expanded_recorded_viewport = - pile_.tiling().ExpandRectToTileBounds(pile_.recorded_viewport()); - Region expected_invalidation = - pile_.tiling().ExpandRectToTileBounds(invalidation_outside); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); -} - -enum Corner { - TOP_LEFT, - TOP_RIGHT, - BOTTOM_LEFT, - BOTTOM_RIGHT, -}; - -class PicturePileResizeCornerTest : public PicturePileTestBase, - public testing::TestWithParam<Corner> { - protected: - void SetUp() override { InitializeData(); } - - static gfx::Rect CornerSinglePixelRect(Corner corner, const gfx::Size& s) { - switch (corner) { - case TOP_LEFT: - return gfx::Rect(0, 0, 1, 1); - case TOP_RIGHT: - return gfx::Rect(s.width() - 1, 0, 1, 1); - case BOTTOM_LEFT: - return gfx::Rect(0, s.height() - 1, 1, 1); - case BOTTOM_RIGHT: - return gfx::Rect(s.width() - 1, s.height() - 1, 1, 1); - } - NOTREACHED(); - return gfx::Rect(); - } -}; - -TEST_P(PicturePileResizeCornerTest, ResizePileOutsideInterestRect) { - Corner corner = GetParam(); - - // This size chosen to be larger than the interest rect size, which is - // at least kPixelDistanceToRecord * 2 in each dimension. - int tile_size = 100000; - // The small number subtracted keeps the last tile in each axis larger than - // the interest rect also. - int offset = -100; - gfx::Size base_tiling_size(6 * tile_size + offset, 6 * tile_size + offset); - gfx::Size grow_down_tiling_size(6 * tile_size + offset, - 8 * tile_size + offset); - gfx::Size grow_right_tiling_size(8 * tile_size + offset, - 6 * tile_size + offset); - gfx::Size grow_both_tiling_size(8 * tile_size + offset, - 8 * tile_size + offset); - - Region invalidation; - Region expected_invalidation; - - pile_.tiling().SetMaxTextureSize(gfx::Size(tile_size, tile_size)); - SetTilingSize(base_tiling_size); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - UpdateAndExpandInvalidation( - &invalidation, - grow_down_tiling_size, - CornerSinglePixelRect(corner, grow_down_tiling_size)); - - // We should have lost all of the recordings in the bottom row as none of them - // are in the current interest rect (which is either the above or below it). - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - EXPECT_EQ(8, pile_.tiling().num_tiles_y()); - for (int i = 0; i < 6; ++i) { - for (int j = 0; j < 6; ++j) { - 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()); - } - } - - // We invalidated all new pixels in the recording. - expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), - gfx::Rect(base_tiling_size)); - // But the new pixels don't cover the whole bottom row. - gfx::Rect bottom_row = gfx::UnionRects(pile_.tiling().TileBounds(0, 5), - pile_.tiling().TileBounds(5, 5)); - EXPECT_FALSE(expected_invalidation.Contains(bottom_row)); - // We invalidated the entire old bottom row. - expected_invalidation.Union(bottom_row); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, - base_tiling_size, - CornerSinglePixelRect(corner, base_tiling_size)); - - // When shrinking, we should have lost all the recordings in the bottom row - // not touching the interest rect. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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: - case TOP_RIGHT: - expect_tile = j < 5; - break; - case BOTTOM_LEFT: - // The interest rect in the bottom left tile means we'll record it. - expect_tile = j < 5 || (j == 5 && i == 0); - break; - case BOTTOM_RIGHT: - // The interest rect in the bottom right tile means we'll record it. - expect_tile = j < 5 || (j == 5 && i == 5); - break; - } - EXPECT_EQ(expect_tile, it != map.end() && it->second.get()); - } - } - - // When shrinking, the previously exposed region is invalidated. - expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), - gfx::Rect(base_tiling_size)); - // The whole bottom row of tiles (except any with the interest rect) are - // dropped. - gfx::Rect bottom_row_minus_existing_corner = gfx::UnionRects( - pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)); - switch (corner) { - case TOP_LEFT: - case TOP_RIGHT: - // No tiles are kept in the changed region because it doesn't - // intersect with the interest rect. - break; - case BOTTOM_LEFT: - bottom_row_minus_existing_corner.Subtract( - pile_.tiling().TileBounds(0, 5)); - break; - case BOTTOM_RIGHT: - bottom_row_minus_existing_corner.Subtract( - pile_.tiling().TileBounds(5, 5)); - break; - } - - expected_invalidation.Union(bottom_row_minus_existing_corner); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation( - &invalidation, - grow_right_tiling_size, - CornerSinglePixelRect(corner, grow_right_tiling_size)); - - // We should have lost all of the recordings in the right column as none of - // them are in the current interest rect (which is either entirely left or - // right of it). - EXPECT_EQ(8, pile_.tiling().num_tiles_x()); - EXPECT_EQ(6, pile_.tiling().num_tiles_y()); - for (int i = 0; i < 6; ++i) { - for (int j = 0; j < 6; ++j) { - 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()); - } - } - - // We invalidated all new pixels in the recording. - expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), - gfx::Rect(base_tiling_size)); - // But the new pixels don't cover the whole right_column. - gfx::Rect right_column = gfx::UnionRects(pile_.tiling().TileBounds(5, 0), - pile_.tiling().TileBounds(5, 5)); - EXPECT_FALSE(expected_invalidation.Contains(right_column)); - // We invalidated the entire old right column. - expected_invalidation.Union(right_column); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, - base_tiling_size, - CornerSinglePixelRect(corner, base_tiling_size)); - - // When shrinking, we should have lost all the recordings in the right column - // not touching the interest rect. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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: - case BOTTOM_LEFT: - // No tiles are kept in the changed region because it doesn't - // intersect with the interest rect. - expect_tile = i < 5; - break; - case TOP_RIGHT: - // The interest rect in the top right tile means we'll record it. - expect_tile = i < 5 || (j == 0 && i == 5); - break; - case BOTTOM_RIGHT: - // The interest rect in the bottom right tile means we'll record it. - expect_tile = i < 5 || (j == 5 && i == 5); - break; - } - EXPECT_EQ(expect_tile, it != map.end() && it->second.get()); - } - } - - // When shrinking, the previously exposed region is invalidated. - expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), - gfx::Rect(base_tiling_size)); - // The whole right column of tiles (except for ones with the interest rect) - // are dropped. - gfx::Rect right_column_minus_existing_corner = gfx::UnionRects( - pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); - switch (corner) { - case TOP_LEFT: - case BOTTOM_LEFT: - break; - case TOP_RIGHT: - right_column_minus_existing_corner.Subtract( - pile_.tiling().TileBounds(5, 0)); - break; - case BOTTOM_RIGHT: - right_column_minus_existing_corner.Subtract( - pile_.tiling().TileBounds(5, 5)); - break; - } - expected_invalidation.Union(right_column_minus_existing_corner); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation( - &invalidation, - grow_both_tiling_size, - CornerSinglePixelRect(corner, grow_both_tiling_size)); - - // We should have lost the recordings in the right column and bottom row. - EXPECT_EQ(8, pile_.tiling().num_tiles_x()); - EXPECT_EQ(8, pile_.tiling().num_tiles_y()); - for (int i = 0; i < 6; ++i) { - for (int j = 0; j < 6; ++j) { - 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()); - } - } - - // We invalidated all new pixels in the recording. - expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), - gfx::Rect(base_tiling_size)); - // But the new pixels don't cover the whole right column or bottom row. - Region right_column_and_bottom_row = - UnionRegions(gfx::UnionRects(pile_.tiling().TileBounds(5, 0), - pile_.tiling().TileBounds(5, 5)), - gfx::UnionRects(pile_.tiling().TileBounds(0, 5), - pile_.tiling().TileBounds(5, 5))); - EXPECT_FALSE(expected_invalidation.Contains(right_column_and_bottom_row)); - // We invalidated the entire old right column and the old bottom row. - expected_invalidation.Union(right_column_and_bottom_row); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, base_tiling_size, - CornerSinglePixelRect(corner, base_tiling_size)); - - // We should have lost the recordings in the right column and bottom row, - // except where it intersects the interest rect. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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: - expect_tile = i < 5 && j < 5; - break; - case TOP_RIGHT: - // The interest rect in the top right tile means we'll record it. - expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5); - break; - case BOTTOM_LEFT: - // The interest rect in the bottom left tile means we'll record it. - expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0); - break; - case BOTTOM_RIGHT: - // The interest rect in the bottom right tile means we'll record it. - expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5); - break; - } - EXPECT_EQ(expect_tile, it != map.end() && it->second.get()) << i << "," - << j; - } - } - - // We invalidated all previous pixels in the recording. - expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), - gfx::Rect(base_tiling_size)); - // The whole right column and bottom row of tiles (except for ones with the - // interest rect) are dropped. - Region right_column_and_bottom_row_minus_existing_corner = - right_column_and_bottom_row; - switch (corner) { - case TOP_LEFT: - break; - case BOTTOM_LEFT: - right_column_and_bottom_row_minus_existing_corner.Subtract( - pile_.tiling().TileBounds(0, 5)); - break; - case TOP_RIGHT: - right_column_and_bottom_row_minus_existing_corner.Subtract( - pile_.tiling().TileBounds(5, 0)); - break; - case BOTTOM_RIGHT: - right_column_and_bottom_row_minus_existing_corner.Subtract( - pile_.tiling().TileBounds(5, 5)); - break; - } - expected_invalidation.Union( - right_column_and_bottom_row_minus_existing_corner); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); -} - -TEST_P(PicturePileResizeCornerTest, SmallResizePileOutsideInterestRect) { - Corner corner = GetParam(); - - // This size chosen to be larger than the interest rect size, which is - // at least kPixelDistanceToRecord * 2 in each dimension. - int tile_size = 100000; - // The small number subtracted keeps the last tile in each axis larger than - // the interest rect also. - int offset = -100; - gfx::Size base_tiling_size(6 * tile_size + offset, 6 * tile_size + offset); - gfx::Size grow_down_tiling_size(6 * tile_size + offset, - 6 * tile_size + offset + 5); - gfx::Size grow_right_tiling_size(6 * tile_size + offset + 5, - 6 * tile_size + offset); - gfx::Size grow_both_tiling_size(6 * tile_size + offset + 5, - 6 * tile_size + offset + 5); - - Region invalidation; - Region expected_invalidation; - - pile_.tiling().SetMaxTextureSize(gfx::Size(tile_size, tile_size)); - SetTilingSize(base_tiling_size); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // In this test (unlike the large resize test), as all growing and shrinking - // happens within tiles, the resulting invalidation is symmetrical, so use - // this enum to repeat the test both ways. - enum ChangeDirection { GROW, SHRINK, LAST_DIRECTION = SHRINK }; - - // Grow downward. - for (int dir = 0; dir <= LAST_DIRECTION; ++dir) { - gfx::Size new_tiling_size = - dir == GROW ? grow_down_tiling_size : base_tiling_size; - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, new_tiling_size, - CornerSinglePixelRect(corner, new_tiling_size)); - - // We should have lost the recordings in the bottom row that do not - // intersect the interest rect. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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: - case TOP_RIGHT: - expect_tile = j < 5; - break; - case BOTTOM_LEFT: - // The interest rect in the bottom left tile means we'll record it. - expect_tile = j < 5 || (j == 5 && i == 0); - break; - case BOTTOM_RIGHT: - // The interest rect in the bottom right tile means we'll record it. - expect_tile = j < 5 || (j == 5 && i == 5); - break; - } - EXPECT_EQ(expect_tile, it != map.end() && it->second.get()); - } - } - - // We invalidated the bottom row outside the new interest rect. The tile - // that insects the interest rect in invalidated only on its newly - // exposed or previously exposed pixels. - if (dir == GROW) { - // Only calculate the expected invalidation while growing, as the tile - // bounds post-growing is the newly exposed / previously exposed sizes. - // Post-shrinking, the tile bounds are smaller, so can't be used. - switch (corner) { - case TOP_LEFT: - case TOP_RIGHT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)); - break; - case BOTTOM_LEFT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(1, 5), pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union(SubtractRects( - pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size))); - break; - case BOTTOM_RIGHT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(4, 5)); - expected_invalidation.Union(SubtractRects( - pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); - break; - } - } - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - } - - // Grow right. - for (int dir = 0; dir <= LAST_DIRECTION; ++dir) { - gfx::Size new_tiling_size = - dir == GROW ? grow_right_tiling_size : base_tiling_size; - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, new_tiling_size, - CornerSinglePixelRect(corner, new_tiling_size)); - - // We should have lost the recordings in the right column. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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: - case BOTTOM_LEFT: - expect_tile = i < 5; - break; - case TOP_RIGHT: - // The interest rect in the top right tile means we'll record it. - expect_tile = i < 5 || (j == 0 && i == 5); - break; - case BOTTOM_RIGHT: - // The interest rect in the bottom right tile means we'll record it. - expect_tile = i < 5 || (j == 5 && i == 5); - break; - } - EXPECT_EQ(expect_tile, it != map.end() && it->second.get()); - } - } - - // We invalidated the right column outside the new interest rect. The tile - // that insects the interest rect in invalidated only on its new or - // previously exposed pixels. - if (dir == GROW) { - // Calculate the expected invalidation the first time through the loop. - switch (corner) { - case TOP_LEFT: - case BOTTOM_LEFT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); - break; - case TOP_RIGHT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union(SubtractRects( - pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size))); - break; - case BOTTOM_RIGHT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4)); - expected_invalidation.Union(SubtractRects( - pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); - break; - } - } - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - } - - // Grow both. - for (int dir = 0; dir <= LAST_DIRECTION; ++dir) { - gfx::Size new_tiling_size = - dir == GROW ? grow_both_tiling_size : base_tiling_size; - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, new_tiling_size, - CornerSinglePixelRect(corner, new_tiling_size)); - - // We should have lost the recordings in the right column and bottom row. - // The tile that insects the interest rect in invalidated only on its new - // or previously exposed pixels. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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: - expect_tile = i < 5 && j < 5; - break; - case TOP_RIGHT: - // The interest rect in the top right tile means we'll record it. - expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5); - break; - case BOTTOM_LEFT: - // The interest rect in the bottom left tile means we'll record it. - expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0); - break; - case BOTTOM_RIGHT: - // The interest rect in the bottom right tile means we'll record it. - expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5); - break; - } - EXPECT_EQ(expect_tile, it != map.end() && it->second.get()) << i << "," - << j; - } - } - - // We invalidated the right column and the bottom row outside the new - // interest rect. The tile that insects the interest rect in invalidated - // only on its new or previous exposed pixels. - if (dir == GROW) { - // Calculate the expected invalidation the first time through the loop. - switch (corner) { - case TOP_LEFT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union( - gfx::UnionRects(pile_.tiling().TileBounds(0, 5), - pile_.tiling().TileBounds(5, 5))); - break; - case TOP_RIGHT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union( - gfx::UnionRects(pile_.tiling().TileBounds(0, 5), - pile_.tiling().TileBounds(5, 5))); - expected_invalidation.Union(SubtractRects( - pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size))); - break; - case BOTTOM_LEFT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5)); - expected_invalidation.Union( - gfx::UnionRects(pile_.tiling().TileBounds(1, 5), - pile_.tiling().TileBounds(5, 5))); - expected_invalidation.Union(SubtractRects( - pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size))); - break; - case BOTTOM_RIGHT: - expected_invalidation = gfx::UnionRects( - pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4)); - expected_invalidation.Union( - gfx::UnionRects(pile_.tiling().TileBounds(0, 5), - pile_.tiling().TileBounds(4, 5))); - expected_invalidation.Union(SubtractRegions( - pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size))); - break; - } - } - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - } -} - -INSTANTIATE_TEST_CASE_P( - PicturePileResizeCornerTests, - PicturePileResizeCornerTest, - ::testing::Values(TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT)); - -TEST_F(PicturePileTest, ResizePileInsideInterestRect) { - // This size chosen to be small enough that all the rects below fit inside the - // the interest rect, so they are smaller than kPixelDistanceToRecord in each - // dimension. - int tile_size = 100; - gfx::Size base_tiling_size(5 * tile_size, 5 * tile_size); - gfx::Size grow_down_tiling_size(5 * tile_size, 7 * tile_size); - gfx::Size grow_right_tiling_size(7 * tile_size, 5 * tile_size); - gfx::Size grow_both_tiling_size(7 * tile_size, 7 * tile_size); - - Region invalidation; - Region expected_invalidation; - - pile_.tiling().SetMaxTextureSize(gfx::Size(tile_size, tile_size)); - SetTilingSize(base_tiling_size); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - UpdateAndExpandInvalidation( - &invalidation, grow_down_tiling_size, gfx::Rect(1, 1)); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the newly exposed pixels on the bottom row of tiles. - expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), - gfx::Rect(base_tiling_size)); - Region bottom_row_new_pixels = - SubtractRegions(gfx::UnionRects(pile_.tiling().TileBounds(0, 5), - pile_.tiling().TileBounds(5, 5)), - gfx::Rect(base_tiling_size)); - EXPECT_TRUE(expected_invalidation.Contains(bottom_row_new_pixels)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1)); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the previously exposed pixels on the bottom row of tiles. - expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), - gfx::Rect(base_tiling_size)); - EXPECT_TRUE(expected_invalidation.Contains(bottom_row_new_pixels)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation( - &invalidation, grow_right_tiling_size, gfx::Rect(1, 1)); - - // We should have a recording for every tile. - EXPECT_EQ(8, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the newly exposed pixels on the right column of tiles. - expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), - gfx::Rect(base_tiling_size)); - Region right_column_new_pixels = - SubtractRegions(gfx::UnionRects(pile_.tiling().TileBounds(5, 0), - pile_.tiling().TileBounds(5, 5)), - gfx::Rect(base_tiling_size)); - EXPECT_TRUE(expected_invalidation.Contains(right_column_new_pixels)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1)); - - // We should have lost the recordings that are now outside the tiling only. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the previously exposed pixels on the right column of tiles. - expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), - gfx::Rect(base_tiling_size)); - EXPECT_TRUE(expected_invalidation.Contains(right_column_new_pixels)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation( - &invalidation, grow_both_tiling_size, gfx::Rect(1, 1)); - - // We should have a recording for every tile. - EXPECT_EQ(8, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the newly exposed pixels on the bottom row and right column - // of tiles. - expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), - gfx::Rect(base_tiling_size)); - Region bottom_row_and_right_column_new_pixels = SubtractRegions( - UnionRegions(gfx::UnionRects(pile_.tiling().TileBounds(0, 5), - pile_.tiling().TileBounds(5, 5)), - gfx::UnionRects(pile_.tiling().TileBounds(5, 0), - pile_.tiling().TileBounds(5, 5))), - gfx::Rect(base_tiling_size)); - EXPECT_TRUE( - expected_invalidation.Contains(bottom_row_and_right_column_new_pixels)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect()); - - // We should have lost the recordings that are now outside the tiling only. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the previously exposed pixels on the bottom row and right - // column of tiles. - expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), - gfx::Rect(base_tiling_size)); - EXPECT_TRUE( - expected_invalidation.Contains(bottom_row_and_right_column_new_pixels)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); -} - -TEST_F(PicturePileTest, SmallResizePileInsideInterestRect) { - // This size chosen to be small enough that all the rects below fit inside the - // the interest rect, so they are smaller than kPixelDistanceToRecord in each - // dimension. - int tile_size = 100; - gfx::Size base_tiling_size(5 * tile_size, 5 * tile_size); - gfx::Size grow_down_tiling_size(5 * tile_size, 5 * tile_size + 5); - gfx::Size grow_right_tiling_size(5 * tile_size + 5, 5 * tile_size); - gfx::Size grow_both_tiling_size(5 * tile_size + 5, 5 * tile_size + 5); - - Region invalidation; - Region expected_invalidation; - - pile_.tiling().SetMaxTextureSize(gfx::Size(tile_size, tile_size)); - SetTilingSize(base_tiling_size); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - UpdateAndExpandInvalidation( - &invalidation, grow_down_tiling_size, gfx::Rect(1, 1)); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the newly exposed pixels. - expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), - gfx::Rect(base_tiling_size)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1)); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the previously exposed pixels. - expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size), - gfx::Rect(base_tiling_size)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation( - &invalidation, grow_right_tiling_size, gfx::Rect(1, 1)); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the newly exposed pixels. - expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), - gfx::Rect(base_tiling_size)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect(1, 1)); - - // We should have lost the recordings that are now outside the tiling only. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the previously exposed pixels. - expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size), - gfx::Rect(base_tiling_size)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation( - &invalidation, grow_both_tiling_size, gfx::Rect(1, 1)); - - // We should have a recording for every tile. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the newly exposed pixels. - expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), - gfx::Rect(base_tiling_size)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); - - UpdateWholePile(); - UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect()); - - // We should have lost the recordings that are now outside the tiling only. - EXPECT_EQ(6, pile_.tiling().num_tiles_x()); - 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) { - 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()); - } - } - - // We invalidated the previously exposed pixels. - expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size), - gfx::Rect(base_tiling_size)); - EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString()); - invalidation.Clear(); -} - -TEST_F(PicturePileTest, SolidRectangleIsSolid) { - // If the client has no contents, the solid state will be true. - Region invalidation1(tiling_rect()); - UpdateAndExpandInvalidation(&invalidation1, tiling_size(), tiling_rect()); - EXPECT_TRUE(pile_.is_solid_color()); - EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), pile_.solid_color()); - - // If there is a single rect that covers the view, the solid - // state will be true. - SkPaint paint; - paint.setColor(SK_ColorCYAN); - client_.add_draw_rect(tiling_rect(), paint); - Region invalidation2(tiling_rect()); - UpdateAndExpandInvalidation(&invalidation2, tiling_size(), tiling_rect()); - EXPECT_TRUE(pile_.is_solid_color()); - EXPECT_EQ(SK_ColorCYAN, pile_.solid_color()); - - // If a second smaller rect is draw that doesn't cover the viewport - // completely, the solid state will be false. - gfx::Rect smallRect = tiling_rect(); - smallRect.Inset(10, 10, 10, 10); - client_.add_draw_rect(smallRect, paint); - Region invalidation3(tiling_rect()); - UpdateAndExpandInvalidation(&invalidation3, tiling_size(), tiling_rect()); - EXPECT_FALSE(pile_.is_solid_color()); - - // If a third rect is drawn over everything, we should be solid again. - paint.setColor(SK_ColorRED); - client_.add_draw_rect(tiling_rect(), paint); - Region invalidation4(tiling_rect()); - UpdateAndExpandInvalidation(&invalidation4, tiling_size(), tiling_rect()); - EXPECT_TRUE(pile_.is_solid_color()); - EXPECT_EQ(SK_ColorRED, pile_.solid_color()); - - // If we draw too many, we don't bother doing the analysis and we should no - // longer be in a solid state. There are 8 rects, two clips and a translate. - client_.add_draw_rect(tiling_rect(), paint); - client_.add_draw_rect(tiling_rect(), paint); - client_.add_draw_rect(tiling_rect(), paint); - client_.add_draw_rect(tiling_rect(), paint); - client_.add_draw_rect(tiling_rect(), paint); - Region invalidation5(tiling_rect()); - UpdateAndExpandInvalidation(&invalidation5, tiling_size(), tiling_rect()); - EXPECT_FALSE(pile_.is_solid_color()); -} - -TEST_F(PicturePileTest, NonSolidRectangleOnOffsettedLayerIsNonSolid) { - gfx::Rect visible_rect(tiling_rect()); - visible_rect.Offset(gfx::Vector2d(1000, 1000)); - // The picture pile requires that the tiling completely encompass the viewport - // to make this test work correctly since the recorded viewport is an - // intersection of the tile size and viewport rect. This is possibly a flaw - // in |PicturePile|. - gfx::Size tiling_size(visible_rect.right(), visible_rect.bottom()); - // |Setup()| will create pictures here that mess with the test, clear it! - pile_.Clear(); - - SkPaint paint; - paint.setColor(SK_ColorCYAN); - - // Add a rect that doesn't cover the viewport completely, the solid state - // will be false. - gfx::Rect smallRect = visible_rect; - smallRect.Inset(10, 10, 10, 10); - client_.add_draw_rect(smallRect, paint); - Region invalidation(visible_rect); - UpdateAndExpandInvalidation(&invalidation, tiling_size, visible_rect); - EXPECT_FALSE(pile_.is_solid_color()); -} - -TEST_F(PicturePileTest, SetEmptyBounds) { - EXPECT_TRUE(pile_.is_solid_color()); - 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_.GetSize().IsEmpty()); - EXPECT_TRUE(pile_.picture_map().empty()); - EXPECT_FALSE(pile_.HasRecordings()); -} - -} // namespace -} // namespace cc diff --git a/chromium/cc/playback/picture_unittest.cc b/chromium/cc/playback/picture_unittest.cc deleted file mode 100644 index 53310e37c81..00000000000 --- a/chromium/cc/playback/picture_unittest.cc +++ /dev/null @@ -1,181 +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/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 deleted file mode 100644 index a5c8f05f453..00000000000 --- a/chromium/cc/playback/pixel_ref_map.cc +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "cc/playback/pixel_ref_map.h" - -#include <algorithm> -#include <limits> - -#include "cc/base/math_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(MathUtil::RoundDown(static_cast<int>(it->pixel_ref_rect.x()), - cell_size_.width()), - MathUtil::RoundDown(static_cast<int>(it->pixel_ref_rect.y()), - cell_size_.height())); - gfx::Point max(MathUtil::RoundDown( - static_cast<int>(std::ceil(it->pixel_ref_rect.right())), - cell_size_.width()), - MathUtil::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(MathUtil::RoundDown(query_rect.x(), cell_size.width()), - MathUtil::RoundDown(query_rect.y(), cell_size.height())); - max_point_ = gfx::Point( - MathUtil::RoundDown(query_rect.right() - 1, cell_size.width()), - MathUtil::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 deleted file mode 100644 index e1545217836..00000000000 --- a/chromium/cc/playback/pixel_ref_map.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CC_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 deleted file mode 100644 index af88b44c873..00000000000 --- a/chromium/cc/playback/pixel_ref_map_unittest.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#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/playback/position_image.h b/chromium/cc/playback/position_image.h new file mode 100644 index 00000000000..662a30ae074 --- /dev/null +++ b/chromium/cc/playback/position_image.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_PLAYBACK_POSITION_IMAGE_H_ +#define CC_PLAYBACK_POSITION_IMAGE_H_ + +#include "third_party/skia/include/core/SkFilterQuality.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkRect.h" + +namespace cc { + +struct PositionImage { + PositionImage(const SkImage* image, + const SkRect& image_rect, + const SkMatrix& matrix, + SkFilterQuality filter_quality) + : image(image), + image_rect(image_rect), + matrix(matrix), + filter_quality(filter_quality) {} + + const SkImage* image; + SkRect image_rect; + SkMatrix matrix; + SkFilterQuality filter_quality; +}; + +} // namespace cc + +#endif // CC_PLAYBACK_POSITION_IMAGE_H_ diff --git a/chromium/cc/playback/raster_source.h b/chromium/cc/playback/raster_source.h index 8d0356fae38..4d0a6f96bf3 100644 --- a/chromium/cc/playback/raster_source.h +++ b/chromium/cc/playback/raster_source.h @@ -10,9 +10,9 @@ #include "base/memory/ref_counted.h" #include "cc/base/cc_export.h" #include "cc/debug/traced_value.h" +#include "cc/playback/discardable_image_map.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" @@ -21,8 +21,6 @@ class SkPicture; namespace cc { -class Picture; - class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> { public: struct CC_EXPORT SolidColorAnalysis { @@ -69,20 +67,22 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> { // 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, - float contents_scale, - std::vector<SkPixelRef*>* pixel_refs) const = 0; + // Populate the given list with all images that may overlap the given + // rect in layer space. + virtual void GetDiscardableImagesInRect( + const gfx::Rect& layer_rect, + std::vector<PositionImage>* images) const = 0; - // Return true iff this raster source can raster the given rect at given - // scale. - virtual bool CoversRect(const gfx::Rect& content_rect, - float contents_scale) const = 0; + // Return true iff this raster source can raster the given rect in layer + // space. + virtual bool CoversRect(const gfx::Rect& layer_rect) const = 0; // Returns true if this raster source has anything to rasterize. virtual bool HasRecordings() const = 0; + // Valid rectangle in which everything is recorded and can be rastered from. + virtual gfx::Rect RecordedViewport() const = 0; + // Informs the raster source that it should attempt to use distance field text // during rasterization. virtual void SetShouldAttemptToUseDistanceFieldText() = 0; diff --git a/chromium/cc/playback/raster_source_helper.cc b/chromium/cc/playback/raster_source_helper.cc index bd5edda07c3..3655ba3cb9e 100644 --- a/chromium/cc/playback/raster_source_helper.cc +++ b/chromium/cc/playback/raster_source_helper.cc @@ -60,7 +60,7 @@ void RasterSourceHelper::PrepareForPlaybackToCanvas( // 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)); + gfx::ScaleToEnclosingRect(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 diff --git a/chromium/cc/playback/recording_source.h b/chromium/cc/playback/recording_source.h index cf8c7c466f5..7d4aba1a43d 100644 --- a/chromium/cc/playback/recording_source.h +++ b/chromium/cc/playback/recording_source.h @@ -48,14 +48,10 @@ class CC_EXPORT RecordingSource { 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 SetGenerateDiscardableImagesMetadata(bool generate_metadata) = 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 diff --git a/chromium/cc/playback/recording_source_unittest.cc b/chromium/cc/playback/recording_source_unittest.cc deleted file mode 100644 index f1506e32ec8..00000000000 --- a/chromium/cc/playback/recording_source_unittest.cc +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#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/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) { - gfx::Rect layer_rect(viewport.right(), viewport.bottom()); - scoped_ptr<FakeDisplayListRecordingSource> recording_source = - FakeDisplayListRecordingSource::CreateRecordingSource(viewport, - layer_rect.size()); - 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 index df7ca1b8e56..b52f138a538 100644 --- a/chromium/cc/playback/transform_display_item.cc +++ b/chromium/cc/playback/transform_display_item.cc @@ -32,6 +32,13 @@ void TransformDisplayItem::Raster(SkCanvas* canvas, canvas->concat(transform_.matrix()); } +void TransformDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->AddStartingDisplayItem(); + calculator->Save(); + calculator->matrix()->postConcat(transform_.matrix()); +} + void TransformDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString(base::StringPrintf("TransformDisplayItem transform: [%s]", @@ -53,6 +60,12 @@ void EndTransformDisplayItem::Raster( canvas->restore(); } +void EndTransformDisplayItem::ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const { + calculator->Restore(); + calculator->AddEndingDisplayItem(); +} + void EndTransformDisplayItem::AsValueInto( base::trace_event::TracedValue* array) const { array->AppendString("EndTransformDisplayItem"); diff --git a/chromium/cc/playback/transform_display_item.h b/chromium/cc/playback/transform_display_item.h index 9d3f9c6da46..1bd69cca3f2 100644 --- a/chromium/cc/playback/transform_display_item.h +++ b/chromium/cc/playback/transform_display_item.h @@ -25,6 +25,8 @@ class CC_EXPORT TransformDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; private: gfx::Transform transform_; @@ -43,6 +45,8 @@ class CC_EXPORT EndTransformDisplayItem : public DisplayItem { const gfx::Rect& canvas_target_playback_rect, SkPicture::AbortCallback* callback) const override; void AsValueInto(base::trace_event::TracedValue* array) const override; + void ProcessForBounds( + DisplayItemListBoundsCalculator* calculator) const override; }; } // namespace cc diff --git a/chromium/cc/quads/checkerboard_draw_quad.cc b/chromium/cc/quads/checkerboard_draw_quad.cc deleted file mode 100644 index 4cd3c2aa18b..00000000000 --- a/chromium/cc/quads/checkerboard_draw_quad.cc +++ /dev/null @@ -1,54 +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/quads/checkerboard_draw_quad.h" - -#include "base/logging.h" -#include "base/trace_event/trace_event_argument.h" -#include "base/values.h" - -namespace cc { - -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, - 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, - const gfx::Rect& rect, - const gfx::Rect& opaque_rect, - const gfx::Rect& visible_rect, - bool needs_blending, - SkColor color, - float scale) { - DrawQuad::SetAll(shared_quad_state, DrawQuad::CHECKERBOARD, rect, opaque_rect, - visible_rect, needs_blending); - this->color = color; - this->scale = scale; -} - -const CheckerboardDrawQuad* CheckerboardDrawQuad::MaterialCast( - const DrawQuad* quad) { - DCHECK(quad->material == DrawQuad::CHECKERBOARD); - return static_cast<const CheckerboardDrawQuad*>(quad); -} - -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 deleted file mode 100644 index fe793675a27..00000000000 --- a/chromium/cc/quads/checkerboard_draw_quad.h +++ /dev/null @@ -1,44 +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_QUADS_CHECKERBOARD_DRAW_QUAD_H_ -#define CC_QUADS_CHECKERBOARD_DRAW_QUAD_H_ - -#include "base/memory/scoped_ptr.h" -#include "cc/base/cc_export.h" -#include "cc/quads/draw_quad.h" -#include "third_party/skia/include/core/SkColor.h" - -namespace cc { - -class CC_EXPORT CheckerboardDrawQuad : public DrawQuad { - public: - CheckerboardDrawQuad(); - - void SetNew(const SharedQuadState* shared_quad_state, - const gfx::Rect& rect, - const gfx::Rect& visible_rect, - 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, - float scale); - - SkColor color; - float scale; - - static const CheckerboardDrawQuad* MaterialCast(const DrawQuad*); - - private: - void ExtendValue(base::trace_event::TracedValue* value) const override; -}; - -} // namespace cc - -#endif // CC_QUADS_CHECKERBOARD_DRAW_QUAD_H_ diff --git a/chromium/cc/quads/content_draw_quad_base.h b/chromium/cc/quads/content_draw_quad_base.h index f80e06c2fcf..da8a472f008 100644 --- a/chromium/cc/quads/content_draw_quad_base.h +++ b/chromium/cc/quads/content_draw_quad_base.h @@ -8,9 +8,13 @@ #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" #include "cc/quads/draw_quad.h" -#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/size.h" +namespace gfx { +class Rect; +} + namespace cc { class CC_EXPORT ContentDrawQuadBase : public DrawQuad { diff --git a/chromium/cc/quads/draw_quad.cc b/chromium/cc/quads/draw_quad.cc index 606d7ab6058..f9bf6fc5874 100644 --- a/chromium/cc/quads/draw_quad.cc +++ b/chromium/cc/quads/draw_quad.cc @@ -9,7 +9,6 @@ #include "base/values.h" #include "cc/base/math_util.h" #include "cc/debug/traced_value.h" -#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" @@ -64,7 +63,7 @@ void DrawQuad::AsValueInto(base::trace_event::TracedValue* value) const { bool rect_is_clipped; gfx::QuadF rect_as_target_space_quad = MathUtil::MapQuad(shared_quad_state->quad_to_target_transform, - gfx::QuadF(rect), &rect_is_clipped); + gfx::QuadF(gfx::RectF(rect)), &rect_is_clipped); MathUtil::AddToTracedValue("rect_as_target_space_quad", rect_as_target_space_quad, value); @@ -73,9 +72,9 @@ void DrawQuad::AsValueInto(base::trace_event::TracedValue* value) const { 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->quad_to_target_transform, - gfx::QuadF(opaque_rect), &opaque_rect_is_clipped); + gfx::QuadF opaque_rect_as_target_space_quad = MathUtil::MapQuad( + shared_quad_state->quad_to_target_transform, + gfx::QuadF(gfx::RectF(opaque_rect)), &opaque_rect_is_clipped); MathUtil::AddToTracedValue("opaque_rect_as_target_space_quad", opaque_rect_as_target_space_quad, value); @@ -84,9 +83,9 @@ void DrawQuad::AsValueInto(base::trace_event::TracedValue* value) const { MathUtil::AddToTracedValue("content_space_visible_rect", visible_rect, value); bool visible_rect_is_clipped; - gfx::QuadF visible_rect_as_target_space_quad = - MathUtil::MapQuad(shared_quad_state->quad_to_target_transform, - gfx::QuadF(visible_rect), &visible_rect_is_clipped); + gfx::QuadF visible_rect_as_target_space_quad = MathUtil::MapQuad( + shared_quad_state->quad_to_target_transform, + gfx::QuadF(gfx::RectF(visible_rect)), &visible_rect_is_clipped); MathUtil::AddToTracedValue("visible_rect_as_target_space_quad", visible_rect_as_target_space_quad, value); diff --git a/chromium/cc/quads/draw_quad.h b/chromium/cc/quads/draw_quad.h index df3bc1213f5..10b0e40d0f0 100644 --- a/chromium/cc/quads/draw_quad.h +++ b/chromium/cc/quads/draw_quad.h @@ -35,7 +35,6 @@ class CC_EXPORT DrawQuad { public: enum Material { INVALID, - CHECKERBOARD, DEBUG_BORDER, IO_SURFACE_CONTENT, PICTURE_CONTENT, diff --git a/chromium/cc/quads/draw_quad_unittest.cc b/chromium/cc/quads/draw_quad_unittest.cc index 833f388aafb..a1d1a9042f7 100644 --- a/chromium/cc/quads/draw_quad_unittest.cc +++ b/chromium/cc/quads/draw_quad_unittest.cc @@ -10,7 +10,6 @@ #include "base/compiler_specific.h" #include "cc/base/math_util.h" #include "cc/output/filter_operations.h" -#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/largest_draw_quad.h" @@ -23,7 +22,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/test/fake_picture_pile_impl.h" +#include "cc/test/fake_display_list_raster_source.h" #include "cc/test/geometry_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/effects/SkBlurImageFilter.h" @@ -361,24 +360,6 @@ void CompareDrawQuad(DrawQuad* quad, } \ SETUP_AND_COPY_QUAD_NEW_RP(Type, quad_new, copy_a); -TEST(DrawQuadTest, CopyCheckerboardDrawQuad) { - gfx::Rect visible_rect(40, 50, 30, 20); - SkColor color = 0xfabb0011; - float scale = 2.3f; - CREATE_SHARED_STATE(); - - CREATE_QUAD_3_NEW(CheckerboardDrawQuad, visible_rect, color, scale); - EXPECT_EQ(DrawQuad::CHECKERBOARD, copy_quad->material); - EXPECT_EQ(visible_rect, copy_quad->visible_rect); - EXPECT_EQ(color, copy_quad->color); - EXPECT_EQ(scale, copy_quad->scale); - - 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) { gfx::Rect visible_rect(40, 50, 30, 20); SkColor color = 0xfabb0011; @@ -403,26 +384,34 @@ TEST(DrawQuadTest, CopyIOSurfaceDrawQuad) { gfx::Size size(58, 95); ResourceId resource_id = 72; IOSurfaceDrawQuad::Orientation orientation = IOSurfaceDrawQuad::UNFLIPPED; + bool allow_overlay = true; CREATE_SHARED_STATE(); - CREATE_QUAD_5_NEW(IOSurfaceDrawQuad, + CREATE_QUAD_6_NEW(IOSurfaceDrawQuad, opaque_rect, visible_rect, size, resource_id, - orientation); + orientation, + allow_overlay); EXPECT_EQ(DrawQuad::IO_SURFACE_CONTENT, copy_quad->material); 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); + EXPECT_EQ(allow_overlay, copy_quad->allow_overlay); - CREATE_QUAD_3_ALL(IOSurfaceDrawQuad, size, resource_id, orientation); + CREATE_QUAD_4_ALL(IOSurfaceDrawQuad, + size, + resource_id, + orientation, + allow_overlay); EXPECT_EQ(DrawQuad::IO_SURFACE_CONTENT, copy_quad->material); EXPECT_EQ(size, copy_quad->io_surface_size); EXPECT_EQ(resource_id, copy_quad->io_surface_resource_id()); EXPECT_EQ(orientation, copy_quad->orientation); + EXPECT_EQ(allow_overlay, copy_quad->allow_overlay); } TEST(DrawQuadTest, CopyRenderPassDrawQuad) { @@ -695,8 +684,7 @@ TEST(DrawQuadTest, CopyPictureDrawQuad) { gfx::Rect content_rect(30, 40, 20, 30); float contents_scale = 3.141592f; scoped_refptr<RasterSource> raster_source = - FakePicturePileImpl::CreateEmptyPile(gfx::Size(100, 100), - gfx::Size(100, 100)); + FakeDisplayListRasterSource::CreateEmpty(gfx::Size(100, 100)); CREATE_SHARED_STATE(); CREATE_QUAD_9_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect, @@ -741,16 +729,6 @@ class DrawQuadIteratorTest : public testing::Test { int num_resources_; }; -TEST_F(DrawQuadIteratorTest, CheckerboardDrawQuad) { - gfx::Rect visible_rect(40, 50, 30, 20); - SkColor color = 0xfabb0011; - float scale = 3.2f; - - CREATE_SHARED_STATE(); - CREATE_QUAD_3_NEW(CheckerboardDrawQuad, visible_rect, color, scale); - EXPECT_EQ(0, IterateAndCount(quad_new)); -} - TEST_F(DrawQuadIteratorTest, DebugBorderDrawQuad) { gfx::Rect visible_rect(40, 50, 30, 20); SkColor color = 0xfabb0011; @@ -767,17 +745,20 @@ TEST_F(DrawQuadIteratorTest, IOSurfaceDrawQuad) { gfx::Size size(58, 95); ResourceId resource_id = 72; IOSurfaceDrawQuad::Orientation orientation = IOSurfaceDrawQuad::UNFLIPPED; + bool allow_overlay = true; CREATE_SHARED_STATE(); - CREATE_QUAD_5_NEW(IOSurfaceDrawQuad, + CREATE_QUAD_6_NEW(IOSurfaceDrawQuad, opaque_rect, visible_rect, size, resource_id, - orientation); + orientation, + allow_overlay); EXPECT_EQ(resource_id, quad_new->io_surface_resource_id()); EXPECT_EQ(1, IterateAndCount(quad_new)); EXPECT_EQ(resource_id + 1, quad_new->io_surface_resource_id()); + EXPECT_EQ(allow_overlay, copy_quad->allow_overlay); } TEST_F(DrawQuadIteratorTest, RenderPassDrawQuad) { @@ -950,8 +931,7 @@ TEST_F(DrawQuadIteratorTest, DISABLED_PictureDrawQuad) { gfx::Rect content_rect(30, 40, 20, 30); float contents_scale = 3.141592f; scoped_refptr<RasterSource> raster_source = - FakePicturePileImpl::CreateEmptyPile(gfx::Size(100, 100), - gfx::Size(100, 100)); + FakeDisplayListRasterSource::CreateEmpty(gfx::Size(100, 100)); CREATE_SHARED_STATE(); CREATE_QUAD_9_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect, @@ -965,9 +945,6 @@ TEST(DrawQuadTest, LargestQuadType) { for (int i = 0; i <= DrawQuad::MATERIAL_LAST; ++i) { switch (static_cast<DrawQuad::Material>(i)) { - case DrawQuad::CHECKERBOARD: - largest = std::max(largest, sizeof(CheckerboardDrawQuad)); - break; case DrawQuad::DEBUG_BORDER: largest = std::max(largest, sizeof(DebugBorderDrawQuad)); break; @@ -1012,9 +989,6 @@ TEST(DrawQuadTest, LargestQuadType) { LOG(ERROR) << "kLargestDrawQuad " << LargestDrawQuadSize(); for (int i = 0; i <= DrawQuad::MATERIAL_LAST; ++i) { switch (static_cast<DrawQuad::Material>(i)) { - case DrawQuad::CHECKERBOARD: - LOG(ERROR) << "CheckerboardDrawQuad " << sizeof(CheckerboardDrawQuad); - break; case DrawQuad::DEBUG_BORDER: LOG(ERROR) << "DebugBorderDrawQuad " << sizeof(DebugBorderDrawQuad); break; diff --git a/chromium/cc/quads/io_surface_draw_quad.cc b/chromium/cc/quads/io_surface_draw_quad.cc index 0ad70fcc6b8..32e2ffc42d4 100644 --- a/chromium/cc/quads/io_surface_draw_quad.cc +++ b/chromium/cc/quads/io_surface_draw_quad.cc @@ -11,7 +11,8 @@ namespace cc { -IOSurfaceDrawQuad::IOSurfaceDrawQuad() : orientation(FLIPPED) { +IOSurfaceDrawQuad::IOSurfaceDrawQuad() + : orientation(FLIPPED), allow_overlay(false) { } void IOSurfaceDrawQuad::SetNew(const SharedQuadState* shared_quad_state, @@ -20,7 +21,8 @@ void IOSurfaceDrawQuad::SetNew(const SharedQuadState* shared_quad_state, const gfx::Rect& visible_rect, const gfx::Size& io_surface_size, unsigned io_surface_resource_id, - Orientation orientation) { + Orientation orientation, + bool allow_overlay) { bool needs_blending = false; DrawQuad::SetAll(shared_quad_state, DrawQuad::IO_SURFACE_CONTENT, rect, opaque_rect, visible_rect, needs_blending); @@ -28,6 +30,7 @@ void IOSurfaceDrawQuad::SetNew(const SharedQuadState* shared_quad_state, resources.ids[kIOSurfaceResourceIdIndex] = io_surface_resource_id; resources.count = 1; this->orientation = orientation; + this->allow_overlay = allow_overlay; } void IOSurfaceDrawQuad::SetAll(const SharedQuadState* shared_quad_state, @@ -37,13 +40,15 @@ void IOSurfaceDrawQuad::SetAll(const SharedQuadState* shared_quad_state, bool needs_blending, const gfx::Size& io_surface_size, unsigned io_surface_resource_id, - Orientation orientation) { + Orientation orientation, + bool allow_overlay) { DrawQuad::SetAll(shared_quad_state, DrawQuad::IO_SURFACE_CONTENT, rect, opaque_rect, visible_rect, needs_blending); this->io_surface_size = io_surface_size; resources.ids[kIOSurfaceResourceIdIndex] = io_surface_resource_id; resources.count = 1; this->orientation = orientation; + this->allow_overlay = allow_overlay; } const IOSurfaceDrawQuad* IOSurfaceDrawQuad::MaterialCast( diff --git a/chromium/cc/quads/io_surface_draw_quad.h b/chromium/cc/quads/io_surface_draw_quad.h index 4a8a072c61c..0374aa9ed1d 100644 --- a/chromium/cc/quads/io_surface_draw_quad.h +++ b/chromium/cc/quads/io_surface_draw_quad.h @@ -28,7 +28,8 @@ class CC_EXPORT IOSurfaceDrawQuad : public DrawQuad { const gfx::Rect& visible_rect, const gfx::Size& io_surface_size, unsigned io_surface_resource_id, - Orientation orientation); + Orientation orientation, + bool allow_overlay); void SetAll(const SharedQuadState* shared_quad_state, const gfx::Rect& rect, @@ -37,10 +38,12 @@ class CC_EXPORT IOSurfaceDrawQuad : public DrawQuad { bool needs_blending, const gfx::Size& io_surface_size, unsigned io_surface_resource_id, - Orientation orientation); + Orientation orientation, + bool allow_overlay); gfx::Size io_surface_size; Orientation orientation; + bool allow_overlay; ResourceId io_surface_resource_id() const { return resources.ids[kIOSurfaceResourceIdIndex]; diff --git a/chromium/cc/quads/largest_draw_quad.cc b/chromium/cc/quads/largest_draw_quad.cc index 894be0fdbe4..b6526384887 100644 --- a/chromium/cc/quads/largest_draw_quad.cc +++ b/chromium/cc/quads/largest_draw_quad.cc @@ -6,7 +6,6 @@ #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" @@ -33,9 +32,6 @@ size_t LargestDrawQuadSize() { // 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."); diff --git a/chromium/cc/quads/render_pass.cc b/chromium/cc/quads/render_pass.cc index 5c4d98a33c9..dc79bb8baf4 100644 --- a/chromium/cc/quads/render_pass.cc +++ b/chromium/cc/quads/render_pass.cc @@ -12,7 +12,6 @@ #include "cc/base/math_util.h" #include "cc/debug/traced_value.h" #include "cc/output/copy_output_request.h" -#include "cc/quads/checkerboard_draw_quad.h" #include "cc/quads/debug_border_draw_quad.h" #include "cc/quads/draw_quad.h" #include "cc/quads/io_surface_draw_quad.h" @@ -145,7 +144,7 @@ void RenderPass::SetNew(RenderPassId id, const gfx::Rect& output_rect, const gfx::Rect& damage_rect, const gfx::Transform& transform_to_root_target) { - DCHECK_GT(id.layer_id, 0); + DCHECK(id.IsValid()); DCHECK(damage_rect.IsEmpty() || output_rect.Contains(damage_rect)) << "damage_rect: " << damage_rect.ToString() << " output_rect: " << output_rect.ToString(); @@ -164,7 +163,7 @@ void RenderPass::SetAll(RenderPassId id, const gfx::Rect& damage_rect, const gfx::Transform& transform_to_root_target, bool has_transparent_background) { - DCHECK_GT(id.layer_id, 0); + DCHECK(id.IsValid()); this->id = id; this->output_rect = output_rect; @@ -226,9 +225,6 @@ DrawQuad* RenderPass::CopyFromAndAppendDrawQuad( const DrawQuad* quad, const SharedQuadState* shared_quad_state) { switch (quad->material) { - case DrawQuad::CHECKERBOARD: - CopyFromAndAppendTypedDrawQuad<CheckerboardDrawQuad>(quad); - break; case DrawQuad::DEBUG_BORDER: CopyFromAndAppendTypedDrawQuad<DebugBorderDrawQuad>(quad); break; diff --git a/chromium/cc/quads/render_pass_draw_quad.cc b/chromium/cc/quads/render_pass_draw_quad.cc index 47c976b96bc..a0070d6991f 100644 --- a/chromium/cc/quads/render_pass_draw_quad.cc +++ b/chromium/cc/quads/render_pass_draw_quad.cc @@ -28,7 +28,7 @@ void RenderPassDrawQuad::SetNew(const SharedQuadState* shared_quad_state, const FilterOperations& filters, const gfx::Vector2dF& filters_scale, const FilterOperations& background_filters) { - DCHECK_GT(render_pass_id.layer_id, 0); + DCHECK(render_pass_id.IsValid()); gfx::Rect opaque_rect; bool needs_blending = false; @@ -58,7 +58,7 @@ void RenderPassDrawQuad::SetAll(const SharedQuadState* shared_quad_state, const FilterOperations& filters, const gfx::Vector2dF& filters_scale, const FilterOperations& background_filters) { - DCHECK_GT(render_pass_id.layer_id, 0); + DCHECK(render_pass_id.IsValid()); DrawQuad::SetAll(shared_quad_state, DrawQuad::RENDER_PASS, rect, opaque_rect, visible_rect, needs_blending); diff --git a/chromium/cc/quads/render_pass_id.h b/chromium/cc/quads/render_pass_id.h index ebf6387e73c..9c36f321dc6 100644 --- a/chromium/cc/quads/render_pass_id.h +++ b/chromium/cc/quads/render_pass_id.h @@ -20,6 +20,8 @@ class CC_EXPORT RenderPassId { RenderPassId(int layer_id, size_t index) : layer_id(layer_id), index(index) {} void* AsTracingId() const; + bool IsValid() const { return layer_id >= 0; } + bool operator==(const RenderPassId& other) const { return layer_id == other.layer_id && index == other.index; } diff --git a/chromium/cc/quads/render_pass_unittest.cc b/chromium/cc/quads/render_pass_unittest.cc index 5ab8c3170c3..dea89cc9248 100644 --- a/chromium/cc/quads/render_pass_unittest.cc +++ b/chromium/cc/quads/render_pass_unittest.cc @@ -7,16 +7,13 @@ #include "cc/base/math_util.h" #include "cc/base/scoped_ptr_vector.h" #include "cc/output/copy_output_request.h" -#include "cc/quads/checkerboard_draw_quad.h" #include "cc/quads/render_pass_draw_quad.h" +#include "cc/quads/solid_color_draw_quad.h" #include "cc/test/geometry_test_utils.h" -#include "cc/test/render_pass_test_common.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/effects/SkBlurImageFilter.h" #include "ui/gfx/transform.h" -using cc::TestRenderPass; - namespace cc { namespace { @@ -73,7 +70,7 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) { gfx::Rect damage_rect(56, 123, 19, 43); bool has_transparent_background = true; - scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); + scoped_ptr<RenderPass> pass = RenderPass::Create(); pass->SetAll(id, output_rect, damage_rect, @@ -92,10 +89,10 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) { SkXfermode::kSrcOver_Mode, 0); - CheckerboardDrawQuad* checkerboard_quad = - pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); - checkerboard_quad->SetNew(pass->shared_quad_state_list.back(), gfx::Rect(), - gfx::Rect(), SkColor(), 1.f); + SolidColorDrawQuad* color_quad = + pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + color_quad->SetNew(pass->shared_quad_state_list.back(), gfx::Rect(), + gfx::Rect(), SkColor(), false); RenderPassId new_id(63, 4); @@ -125,7 +122,7 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) { gfx::Rect damage_rect(56, 123, 19, 43); bool has_transparent_background = true; - scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); + scoped_ptr<RenderPass> pass = RenderPass::Create(); pass->SetAll(id, output_rect, damage_rect, @@ -143,17 +140,17 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) { SkXfermode::kSrcOver_Mode, 0); - 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(), 1.f); + SolidColorDrawQuad* color_quad1 = + pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + color_quad1->SetNew(pass->shared_quad_state_list.back(), + gfx::Rect(1, 1, 1, 1), gfx::Rect(1, 1, 1, 1), SkColor(), + false); - 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(), 1.f); + SolidColorDrawQuad* color_quad2 = + pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + color_quad2->SetNew(pass->shared_quad_state_list.back(), + gfx::Rect(2, 2, 2, 2), gfx::Rect(2, 2, 2, 2), SkColor(), + false); // And two quads using another shared state. SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState(); @@ -166,17 +163,17 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) { SkXfermode::kSrcOver_Mode, 0); - 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(), 1.f); + SolidColorDrawQuad* color_quad3 = + pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + color_quad3->SetNew(pass->shared_quad_state_list.back(), + gfx::Rect(3, 3, 3, 3), gfx::Rect(3, 3, 3, 3), SkColor(), + false); - 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(), 1.f); + SolidColorDrawQuad* color_quad4 = + pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + color_quad4->SetNew(pass->shared_quad_state_list.back(), + gfx::Rect(4, 4, 4, 4), gfx::Rect(4, 4, 4, 4), SkColor(), + false); // A second render pass with a quad. RenderPassId contrib_id(4, 1); @@ -186,7 +183,7 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) { gfx::Rect contrib_damage_rect(11, 16, 10, 15); bool contrib_has_transparent_background = true; - scoped_ptr<TestRenderPass> contrib = TestRenderPass::Create(); + scoped_ptr<RenderPass> contrib = RenderPass::Create(); contrib->SetAll(contrib_id, contrib_output_rect, contrib_damage_rect, @@ -204,11 +201,11 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) { SkXfermode::kSrcOver_Mode, 0); - CheckerboardDrawQuad* contrib_quad = - contrib->CreateAndAppendDrawQuad<CheckerboardDrawQuad>(); + SolidColorDrawQuad* contrib_quad = + contrib->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); contrib_quad->SetNew(contrib->shared_quad_state_list.back(), gfx::Rect(3, 3, 3, 3), gfx::Rect(3, 3, 3, 3), SkColor(), - 1.f); + false); // And a RenderPassDrawQuad for the contributing pass. scoped_ptr<RenderPassDrawQuad> pass_quad = @@ -244,7 +241,7 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) { gfx::Rect damage_rect(56, 123, 19, 43); bool has_transparent_background = true; - scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); + scoped_ptr<RenderPass> pass = RenderPass::Create(); pass->SetAll(id, output_rect, damage_rect, @@ -262,11 +259,11 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) { SkXfermode::kSrcOver_Mode, 0); - 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(), 1.f); + SolidColorDrawQuad* color_quad1 = + pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + color_quad1->SetNew(pass->shared_quad_state_list.back(), + gfx::Rect(1, 1, 1, 1), gfx::Rect(1, 1, 1, 1), SkColor(), + false); // A shared state with no quads, they were culled. SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState(); @@ -301,11 +298,11 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) { SkXfermode::kSrcOver_Mode, 0); - 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(), 1.f); + SolidColorDrawQuad* color_quad2 = + pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + color_quad2->SetNew(pass->shared_quad_state_list.back(), + gfx::Rect(3, 3, 3, 3), gfx::Rect(3, 3, 3, 3), SkColor(), + false); pass_list.push_back(pass.Pass()); diff --git a/chromium/cc/quads/yuv_video_draw_quad.h b/chromium/cc/quads/yuv_video_draw_quad.h index 53ef5710d20..3dfd85bb88b 100644 --- a/chromium/cc/quads/yuv_video_draw_quad.h +++ b/chromium/cc/quads/yuv_video_draw_quad.h @@ -9,6 +9,8 @@ #include "base/memory/scoped_ptr.h" #include "cc/base/cc_export.h" #include "cc/quads/draw_quad.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/geometry/size.h" namespace cc { diff --git a/chromium/cc/raster/bitmap_tile_task_worker_pool.cc b/chromium/cc/raster/bitmap_tile_task_worker_pool.cc index bd6af35215c..034ad0f087b 100644 --- a/chromium/cc/raster/bitmap_tile_task_worker_pool.cc +++ b/chromium/cc/raster/bitmap_tile_task_worker_pool.cc @@ -35,7 +35,8 @@ class RasterBufferImpl : public RasterBuffer { const gfx::Rect& raster_full_rect, const gfx::Rect& raster_dirty_rect, uint64_t new_content_id, - float scale) override { + float scale, + bool include_images) override { gfx::Rect playback_rect = raster_full_rect; if (resource_has_previous_content_) { playback_rect.Intersect(raster_dirty_rect); @@ -46,7 +47,8 @@ class RasterBufferImpl : public RasterBuffer { size_t stride = 0u; TileTaskWorkerPool::PlaybackToMemory( lock_.sk_bitmap().getPixels(), resource_->format(), resource_->size(), - stride, raster_source, raster_full_rect, playback_rect, scale); + stride, raster_source, raster_full_rect, playback_rect, scale, + include_images); } private: @@ -173,18 +175,19 @@ void BitmapTileTaskWorkerPool::CheckForCompletedTasks() { task->WillComplete(); task->CompleteOnOriginThread(this); task->DidComplete(); - - task->RunReplyOnOriginThread(); } completed_tasks_.clear(); } -ResourceFormat BitmapTileTaskWorkerPool::GetResourceFormat() const { +ResourceFormat BitmapTileTaskWorkerPool::GetResourceFormat( + bool must_support_alpha) const { return resource_provider_->best_texture_format(); } -bool BitmapTileTaskWorkerPool::GetResourceRequiresSwizzle() const { - return !PlatformColor::SameComponentOrder(GetResourceFormat()); +bool BitmapTileTaskWorkerPool::GetResourceRequiresSwizzle( + bool must_support_alpha) const { + return !PlatformColor::SameComponentOrder( + GetResourceFormat(must_support_alpha)); } scoped_ptr<RasterBuffer> BitmapTileTaskWorkerPool::AcquireBufferForRaster( diff --git a/chromium/cc/raster/bitmap_tile_task_worker_pool.h b/chromium/cc/raster/bitmap_tile_task_worker_pool.h index 3df206a09bd..fe9c4e81087 100644 --- a/chromium/cc/raster/bitmap_tile_task_worker_pool.h +++ b/chromium/cc/raster/bitmap_tile_task_worker_pool.h @@ -38,8 +38,8 @@ class CC_EXPORT BitmapTileTaskWorkerPool : public TileTaskWorkerPool, void Shutdown() override; void ScheduleTasks(TileTaskQueue* queue) override; void CheckForCompletedTasks() override; - ResourceFormat GetResourceFormat() const override; - bool GetResourceRequiresSwizzle() const override; + ResourceFormat GetResourceFormat(bool must_support_alpha) const override; + bool GetResourceRequiresSwizzle(bool must_support_alpha) const override; // Overridden from TileTaskClient: scoped_ptr<RasterBuffer> AcquireBufferForRaster( diff --git a/chromium/cc/raster/gpu_tile_task_worker_pool.cc b/chromium/cc/raster/gpu_tile_task_worker_pool.cc index 7c21177d527..e8dc102752f 100644 --- a/chromium/cc/raster/gpu_tile_task_worker_pool.cc +++ b/chromium/cc/raster/gpu_tile_task_worker_pool.cc @@ -38,18 +38,17 @@ class RasterBufferImpl : public RasterBuffer { const gfx::Rect& raster_full_rect, const gfx::Rect& raster_dirty_rect, uint64_t new_content_id, - float scale) override { + float scale, + bool include_images) override { TRACE_EVENT0("cc", "RasterBufferImpl::Playback"); + // GPU raster doesn't do low res tiles, so should always include images. + DCHECK(include_images); ContextProvider* context_provider = rasterizer_->resource_provider() ->output_surface() ->worker_context_provider(); + DCHECK(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(); + ContextProvider::ScopedContextLock scoped_context(context_provider); gfx::Rect playback_rect = raster_full_rect; if (resource_has_previous_content_) { @@ -64,10 +63,7 @@ class RasterBufferImpl : public RasterBuffer { playback_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(); + scoped_context.ContextGL()->OrderingBarrierCHROMIUM(); } private: @@ -205,24 +201,24 @@ void GpuTileTaskWorkerPool::CheckForCompletedTasks() { completed_tasks_.clear(); } -ResourceFormat GpuTileTaskWorkerPool::GetResourceFormat() const { +ResourceFormat GpuTileTaskWorkerPool::GetResourceFormat( + bool must_support_alpha) const { return rasterizer_->resource_provider()->best_render_buffer_format(); } -bool GpuTileTaskWorkerPool::GetResourceRequiresSwizzle() const { +bool GpuTileTaskWorkerPool::GetResourceRequiresSwizzle( + bool must_support_alpha) const { // This doesn't require a swizzle because we rasterize to the correct format. return false; } 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(); + TileTask* tile_task = static_cast<TileTask*>(task.get()); - raster_task->RunReplyOnOriginThread(); + tile_task->WillComplete(); + tile_task->CompleteOnOriginThread(this); + tile_task->DidComplete(); } completed_tasks_.clear(); } diff --git a/chromium/cc/raster/gpu_tile_task_worker_pool.h b/chromium/cc/raster/gpu_tile_task_worker_pool.h index 32a9d232550..f9ab24c6fea 100644 --- a/chromium/cc/raster/gpu_tile_task_worker_pool.h +++ b/chromium/cc/raster/gpu_tile_task_worker_pool.h @@ -36,8 +36,8 @@ class CC_EXPORT GpuTileTaskWorkerPool : public TileTaskWorkerPool, void Shutdown() override; void ScheduleTasks(TileTaskQueue* queue) override; void CheckForCompletedTasks() override; - ResourceFormat GetResourceFormat() const override; - bool GetResourceRequiresSwizzle() const override; + ResourceFormat GetResourceFormat(bool must_support_alpha) const override; + bool GetResourceRequiresSwizzle(bool must_support_alpha) const override; // Overridden from TileTaskClient: scoped_ptr<RasterBuffer> AcquireBufferForRaster( diff --git a/chromium/cc/raster/one_copy_tile_task_worker_pool.cc b/chromium/cc/raster/one_copy_tile_task_worker_pool.cc index 78e6b106ce9..86a0561b1ca 100644 --- a/chromium/cc/raster/one_copy_tile_task_worker_pool.cc +++ b/chromium/cc/raster/one_copy_tile_task_worker_pool.cc @@ -8,16 +8,21 @@ #include <limits> #include "base/strings/stringprintf.h" +#include "base/thread_task_runner_handle.h" +#include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event_argument.h" #include "cc/base/math_util.h" #include "cc/debug/traced_value.h" #include "cc/raster/raster_buffer.h" #include "cc/resources/platform_color.h" -#include "cc/resources/resource_pool.h" +#include "cc/resources/resource_format.h" +#include "cc/resources/resource_util.h" #include "cc/resources/scoped_resource.h" +#include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/gles2_interface.h" -#include "ui/gfx/gpu_memory_buffer.h" +#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" +#include "ui/gfx/buffer_format_util.h" namespace cc { namespace { @@ -26,105 +31,140 @@ class RasterBufferImpl : public RasterBuffer { public: RasterBufferImpl(OneCopyTileTaskWorkerPool* worker_pool, ResourceProvider* resource_provider, - ResourcePool* resource_pool, ResourceFormat resource_format, - const Resource* output_resource, + const Resource* resource, uint64_t previous_content_id) : worker_pool_(worker_pool), - resource_provider_(resource_provider), - resource_pool_(resource_pool), - output_resource_(output_resource), - raster_content_id_(0), - sequence_(0) { - if (worker_pool->have_persistent_gpu_memory_buffers() && - previous_content_id) { - raster_resource_ = - resource_pool->TryAcquireResourceWithContentId(previous_content_id); - } - if (raster_resource_) { - raster_content_id_ = previous_content_id; - DCHECK_EQ(resource_format, raster_resource_->format()); - DCHECK_EQ(output_resource->size().ToString(), - raster_resource_->size().ToString()); - } else { - raster_resource_ = resource_pool->AcquireResource(output_resource->size(), - resource_format); - } - - lock_.reset(new ResourceProvider::ScopedWriteLockGpuMemoryBuffer( - resource_provider_, raster_resource_->id())); - } + resource_(resource), + lock_(resource_provider, resource->id()), + previous_content_id_(previous_content_id) {} - ~RasterBufferImpl() override { - // Release write lock in case a copy was never scheduled. - lock_.reset(); - - // Make sure any scheduled copy operations are issued before we release the - // raster resource. - if (sequence_) - worker_pool_->AdvanceLastIssuedCopyTo(sequence_); - - // Return resources to pool so they can be used by another RasterBuffer - // instance. - resource_pool_->ReleaseResource(raster_resource_.Pass(), - raster_content_id_); - } + ~RasterBufferImpl() override {} // Overridden from RasterBuffer: void Playback(const RasterSource* raster_source, const gfx::Rect& raster_full_rect, const gfx::Rect& raster_dirty_rect, uint64_t new_content_id, - float scale) override { - // If there's a raster_content_id_, we are reusing a resource with that - // content id. - bool reusing_raster_resource = raster_content_id_ != 0; - sequence_ = worker_pool_->PlaybackAndScheduleCopyOnWorkerThread( - reusing_raster_resource, lock_.Pass(), raster_resource_.get(), - output_resource_, raster_source, raster_full_rect, raster_dirty_rect, - scale); - // Store the content id of the resource to return to the pool. - raster_content_id_ = new_content_id; + float scale, + bool include_images) override { + worker_pool_->PlaybackAndCopyOnWorkerThread( + resource_, &lock_, raster_source, raster_full_rect, raster_dirty_rect, + scale, include_images, previous_content_id_, new_content_id); } private: OneCopyTileTaskWorkerPool* worker_pool_; - ResourceProvider* resource_provider_; - ResourcePool* resource_pool_; - const Resource* output_resource_; - uint64_t raster_content_id_; - scoped_ptr<ScopedResource> raster_resource_; - scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> lock_; - CopySequenceNumber sequence_; + const Resource* resource_; + ResourceProvider::ScopedWriteLockGL lock_; + uint64_t previous_content_id_; DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); }; -// Number of in-flight copy operations to allow. -const int kMaxCopyOperations = 32; +// Delay between checking for query result to be available. +const int kCheckForQueryResultAvailableTickRateMs = 1; -// Delay been checking for copy operations to complete. -const int kCheckForCompletedCopyOperationsTickRateMs = 1; - -// Number of failed attempts to allow before we perform a check that will -// wait for copy operations to complete if needed. -const int kFailedAttemptsBeforeWaitIfNeeded = 256; +// Number of attempts to allow before we perform a check that will wait for +// query to complete. +const int kMaxCheckForQueryResultAvailableAttempts = 256; // 4MiB is the size of 4 512x512 tiles, which has proven to be a good // default batch size for copy operations. const int kMaxBytesPerCopyOperation = 1024 * 1024 * 4; +// Delay before a staging buffer might be released. +const int kStagingBufferExpirationDelayMs = 1000; + +bool CheckForQueryResult(gpu::gles2::GLES2Interface* gl, unsigned query_id) { + unsigned complete = 1; + gl->GetQueryObjectuivEXT(query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete); + return !!complete; +} + +void WaitForQueryResult(gpu::gles2::GLES2Interface* gl, unsigned query_id) { + TRACE_EVENT0("cc", "WaitForQueryResult"); + + int attempts_left = kMaxCheckForQueryResultAvailableAttempts; + while (attempts_left--) { + if (CheckForQueryResult(gl, query_id)) + break; + + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds( + kCheckForQueryResultAvailableTickRateMs)); + } + + unsigned result = 0; + gl->GetQueryObjectuivEXT(query_id, GL_QUERY_RESULT_EXT, &result); +} + } // namespace -OneCopyTileTaskWorkerPool::CopyOperation::CopyOperation( - scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> src_write_lock, - const Resource* src, - const Resource* dst, - const gfx::Rect& rect) - : src_write_lock(src_write_lock.Pass()), src(src), dst(dst), rect(rect) { +OneCopyTileTaskWorkerPool::StagingBuffer::StagingBuffer(const gfx::Size& size, + ResourceFormat format) + : size(size), + format(format), + texture_id(0), + image_id(0), + query_id(0), + content_id(0) {} + +OneCopyTileTaskWorkerPool::StagingBuffer::~StagingBuffer() { + DCHECK_EQ(texture_id, 0u); + DCHECK_EQ(image_id, 0u); + DCHECK_EQ(query_id, 0u); +} + +void OneCopyTileTaskWorkerPool::StagingBuffer::DestroyGLResources( + gpu::gles2::GLES2Interface* gl) { + if (query_id) { + gl->DeleteQueriesEXT(1, &query_id); + query_id = 0; + } + if (image_id) { + gl->DestroyImageCHROMIUM(image_id); + image_id = 0; + } + if (texture_id) { + gl->DeleteTextures(1, &texture_id); + texture_id = 0; + } } -OneCopyTileTaskWorkerPool::CopyOperation::~CopyOperation() { +void OneCopyTileTaskWorkerPool::StagingBuffer::OnMemoryDump( + base::trace_event::ProcessMemoryDump* pmd, + ResourceFormat format, + bool in_free_list) const { + if (!gpu_memory_buffer) + return; + + gfx::GpuMemoryBufferId buffer_id = gpu_memory_buffer->GetId(); + std::string buffer_dump_name = + base::StringPrintf("cc/one_copy/staging_memory/buffer_%d", buffer_id.id); + base::trace_event::MemoryAllocatorDump* buffer_dump = + pmd->CreateAllocatorDump(buffer_dump_name); + + uint64_t buffer_size_in_bytes = + ResourceUtil::UncheckedSizeInBytes<uint64_t>(size, format); + buffer_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + buffer_size_in_bytes); + buffer_dump->AddScalar("free_size", + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + in_free_list ? buffer_size_in_bytes : 0); + + // Emit an ownership edge towards a global allocator dump node. + const uint64 tracing_process_id = + base::trace_event::MemoryDumpManager::GetInstance() + ->GetTracingProcessId(); + base::trace_event::MemoryAllocatorDumpGuid shared_buffer_guid = + gfx::GetGpuMemoryBufferGUIDForTracing(tracing_process_id, buffer_id); + pmd->CreateSharedGlobalAllocatorDump(shared_buffer_guid); + + // By creating an edge with a higher |importance| (w.r.t. browser-side dumps) + // the tracing UI will account the effective size of the buffer to the child. + const int kImportance = 2; + pmd->AddOwnershipEdge(buffer_dump->guid(), shared_buffer_guid, kImportance); } // static @@ -133,51 +173,54 @@ scoped_ptr<TileTaskWorkerPool> OneCopyTileTaskWorkerPool::Create( TaskGraphRunner* task_graph_runner, ContextProvider* context_provider, ResourceProvider* resource_provider, - ResourcePool* resource_pool, int max_copy_texture_chromium_size, - bool have_persistent_gpu_memory_buffers) { + bool use_persistent_gpu_memory_buffers, + int max_staging_buffer_usage_in_bytes, + bool use_rgba_4444_texture_format) { return make_scoped_ptr<TileTaskWorkerPool>(new OneCopyTileTaskWorkerPool( - task_runner, task_graph_runner, context_provider, resource_provider, - resource_pool, max_copy_texture_chromium_size, - have_persistent_gpu_memory_buffers)); + task_runner, task_graph_runner, resource_provider, + max_copy_texture_chromium_size, use_persistent_gpu_memory_buffers, + max_staging_buffer_usage_in_bytes, use_rgba_4444_texture_format)); } OneCopyTileTaskWorkerPool::OneCopyTileTaskWorkerPool( base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, - ContextProvider* context_provider, ResourceProvider* resource_provider, - ResourcePool* resource_pool, int max_copy_texture_chromium_size, - bool have_persistent_gpu_memory_buffers) + bool use_persistent_gpu_memory_buffers, + int max_staging_buffer_usage_in_bytes, + bool use_rgba_4444_texture_format) : task_runner_(task_runner), task_graph_runner_(task_graph_runner), namespace_token_(task_graph_runner->GetNamespaceToken()), - context_provider_(context_provider), resource_provider_(resource_provider), - resource_pool_(resource_pool), max_bytes_per_copy_operation_( max_copy_texture_chromium_size ? std::min(kMaxBytesPerCopyOperation, max_copy_texture_chromium_size) : kMaxBytesPerCopyOperation), - have_persistent_gpu_memory_buffers_(have_persistent_gpu_memory_buffers), - last_issued_copy_operation_(0), - last_flushed_copy_operation_(0), - lock_(), - copy_operation_count_cv_(&lock_), + use_persistent_gpu_memory_buffers_(use_persistent_gpu_memory_buffers), bytes_scheduled_since_last_flush_(0), - issued_copy_operation_count_(0), - next_copy_operation_sequence_(1), - check_for_completed_copy_operations_pending_(false), - shutdown_(false), + max_staging_buffer_usage_in_bytes_(max_staging_buffer_usage_in_bytes), + use_rgba_4444_texture_format_(use_rgba_4444_texture_format), + staging_buffer_usage_in_bytes_(0), + free_staging_buffer_usage_in_bytes_(0), + staging_buffer_expiration_delay_( + base::TimeDelta::FromMilliseconds(kStagingBufferExpirationDelayMs)), + reduce_memory_usage_pending_(false), weak_ptr_factory_(this), task_set_finished_weak_ptr_factory_(this) { - DCHECK(context_provider_); + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( + this, base::ThreadTaskRunnerHandle::Get()); + reduce_memory_usage_callback_ = + base::Bind(&OneCopyTileTaskWorkerPool::ReduceMemoryUsage, + weak_ptr_factory_.GetWeakPtr()); } OneCopyTileTaskWorkerPool::~OneCopyTileTaskWorkerPool() { - DCHECK_EQ(pending_copy_operations_.size(), 0u); + base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( + this); } TileTaskRunner* OneCopyTileTaskWorkerPool::AsTileTaskRunner() { @@ -191,28 +234,23 @@ void OneCopyTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) { void OneCopyTileTaskWorkerPool::Shutdown() { TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::Shutdown"); - { - base::AutoLock lock(lock_); - - shutdown_ = true; - copy_operation_count_cv_.Signal(); - } - TaskGraph empty; task_graph_runner_->ScheduleTasks(namespace_token_, &empty); task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); + + base::AutoLock lock(lock_); + + if (buffers_.empty()) + return; + + ReleaseBuffersNotUsedSince(base::TimeTicks() + base::TimeDelta::Max()); + DCHECK_EQ(staging_buffer_usage_in_bytes_, 0); + DCHECK_EQ(free_staging_buffer_usage_in_bytes_, 0); } void OneCopyTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) { TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::ScheduleTasks"); -#if DCHECK_IS_ON() - { - base::AutoLock lock(lock_); - DCHECK(!shutdown_); - } -#endif - if (tasks_pending_.none()) TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this); @@ -237,8 +275,6 @@ void OneCopyTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) { task_set_finished_weak_ptr_factory_.GetWeakPtr(), task_set)); } - resource_pool_->CheckBusyResources(false); - for (TileTaskQueue::Item::Vector::const_iterator it = queue->items.begin(); it != queue->items.end(); ++it) { const TileTaskQueue::Item& item = *it; @@ -265,14 +301,19 @@ void OneCopyTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) { } ScheduleTasksOnOriginThread(this, &graph_); + + // Barrier to sync any new resources to the worker context. + 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_); - resource_pool_->ReduceResourceUsage(); - TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state", StateAsValue()); } @@ -290,18 +331,21 @@ void OneCopyTileTaskWorkerPool::CheckForCompletedTasks() { task->WillComplete(); task->CompleteOnOriginThread(this); task->DidComplete(); - - task->RunReplyOnOriginThread(); } completed_tasks_.clear(); } -ResourceFormat OneCopyTileTaskWorkerPool::GetResourceFormat() const { - return resource_provider_->best_texture_format(); +ResourceFormat OneCopyTileTaskWorkerPool::GetResourceFormat( + bool must_support_alpha) const { + return use_rgba_4444_texture_format_ + ? RGBA_4444 + : resource_provider_->best_texture_format(); } -bool OneCopyTileTaskWorkerPool::GetResourceRequiresSwizzle() const { - return !PlatformColor::SameComponentOrder(GetResourceFormat()); +bool OneCopyTileTaskWorkerPool::GetResourceRequiresSwizzle( + bool must_support_alpha) const { + return !PlatformColor::SameComponentOrder( + GetResourceFormat(must_support_alpha)); } scoped_ptr<RasterBuffer> OneCopyTileTaskWorkerPool::AcquireBufferForRaster( @@ -310,11 +354,9 @@ scoped_ptr<RasterBuffer> OneCopyTileTaskWorkerPool::AcquireBufferForRaster( uint64_t previous_content_id) { // TODO(danakj): If resource_content_id != 0, we only need to copy/upload // the dirty rect. - DCHECK_EQ(resource->format(), resource_provider_->best_texture_format()); return make_scoped_ptr<RasterBuffer>( - new RasterBufferImpl(this, resource_provider_, resource_pool_, - resource_provider_->best_texture_format(), resource, - previous_content_id)); + new RasterBufferImpl(this, resource_provider_, resource->format(), + resource, previous_content_id)); } void OneCopyTileTaskWorkerPool::ReleaseBufferForRaster( @@ -322,235 +364,429 @@ void OneCopyTileTaskWorkerPool::ReleaseBufferForRaster( // Nothing to do here. RasterBufferImpl destructor cleans up after itself. } -CopySequenceNumber -OneCopyTileTaskWorkerPool::PlaybackAndScheduleCopyOnWorkerThread( - bool reusing_raster_resource, - scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> - raster_resource_write_lock, - const Resource* raster_resource, - const Resource* output_resource, +void OneCopyTileTaskWorkerPool::PlaybackAndCopyOnWorkerThread( + const Resource* resource, + const ResourceProvider::ScopedWriteLockGL* resource_lock, const RasterSource* raster_source, const gfx::Rect& raster_full_rect, const gfx::Rect& raster_dirty_rect, - float scale) { - gfx::GpuMemoryBuffer* gpu_memory_buffer = - raster_resource_write_lock->GetGpuMemoryBuffer(); - if (gpu_memory_buffer) { - void* data = NULL; - bool rv = gpu_memory_buffer->Map(&data); - DCHECK(rv); - int stride; - gpu_memory_buffer->GetStride(&stride); - // TileTaskWorkerPool::PlaybackToMemory only supports unsigned strides. - DCHECK_GE(stride, 0); + float scale, + bool include_images, + uint64_t previous_content_id, + uint64_t new_content_id) { + base::AutoLock lock(lock_); - gfx::Rect playback_rect = raster_full_rect; - if (reusing_raster_resource) { - playback_rect.Intersect(raster_dirty_rect); + scoped_ptr<StagingBuffer> staging_buffer = + AcquireStagingBuffer(resource, previous_content_id); + DCHECK(staging_buffer); + + { + base::AutoUnlock unlock(lock_); + + // Allocate GpuMemoryBuffer if necessary. + if (!staging_buffer->gpu_memory_buffer) { + staging_buffer->gpu_memory_buffer = + resource_provider_->gpu_memory_buffer_manager() + ->AllocateGpuMemoryBuffer(staging_buffer->size, + BufferFormat(resource->format()), + use_persistent_gpu_memory_buffers_ + ? gfx::BufferUsage::PERSISTENT_MAP + : gfx::BufferUsage::MAP); + DCHECK_EQ(gfx::NumberOfPlanesForBufferFormat( + staging_buffer->gpu_memory_buffer->GetFormat()), + 1u); } - DCHECK(!playback_rect.IsEmpty()) - << "Why are we rastering a tile that's not dirty?"; - TileTaskWorkerPool::PlaybackToMemory( - data, raster_resource->format(), raster_resource->size(), - static_cast<size_t>(stride), raster_source, raster_full_rect, - playback_rect, scale); - gpu_memory_buffer->Unmap(); - } - base::AutoLock lock(lock_); + gfx::Rect playback_rect = raster_full_rect; + if (use_persistent_gpu_memory_buffers_ && previous_content_id) { + // Reduce playback rect to dirty region if the content id of the staging + // buffer matches the prevous content id. + if (previous_content_id == staging_buffer->content_id) + playback_rect.Intersect(raster_dirty_rect); + } - CopySequenceNumber sequence = 0; - int bytes_per_row = (BitsPerPixel(raster_resource->format()) * - raster_resource->size().width()) / - 8; - int chunk_size_in_rows = - std::max(1, max_bytes_per_copy_operation_ / bytes_per_row); - // Align chunk size to 4. Required to support compressed texture formats. - chunk_size_in_rows = MathUtil::RoundUp(chunk_size_in_rows, 4); - int y = 0; - int height = raster_resource->size().height(); - while (y < height) { - int failed_attempts = 0; - while ((pending_copy_operations_.size() + issued_copy_operation_count_) >= - kMaxCopyOperations) { - // Ignore limit when shutdown is set. - if (shutdown_) - break; + if (staging_buffer->gpu_memory_buffer) { + void* data = nullptr; + bool rv = staging_buffer->gpu_memory_buffer->Map(&data); + DCHECK(rv); + int stride; + staging_buffer->gpu_memory_buffer->GetStride(&stride); + // TileTaskWorkerPool::PlaybackToMemory only supports unsigned strides. + DCHECK_GE(stride, 0); + + DCHECK(!playback_rect.IsEmpty()) + << "Why are we rastering a tile that's not dirty?"; + TileTaskWorkerPool::PlaybackToMemory( + data, resource->format(), staging_buffer->size, + static_cast<size_t>(stride), raster_source, raster_full_rect, + playback_rect, scale, include_images); + staging_buffer->gpu_memory_buffer->Unmap(); + staging_buffer->content_id = new_content_id; + } + } - ++failed_attempts; + ContextProvider* context_provider = + resource_provider_->output_surface()->worker_context_provider(); + DCHECK(context_provider); - // Schedule a check that will also wait for operations to complete - // after too many failed attempts. - bool wait_if_needed = failed_attempts > kFailedAttemptsBeforeWaitIfNeeded; + { + ContextProvider::ScopedContextLock scoped_context(context_provider); + + gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); + DCHECK(gl); + + unsigned image_target = + resource_provider_->GetImageTextureTarget(resource->format()); + + // Create and bind staging texture. + if (!staging_buffer->texture_id) { + gl->GenTextures(1, &staging_buffer->texture_id); + gl->BindTexture(image_target, staging_buffer->texture_id); + gl->TexParameteri(image_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl->TexParameteri(image_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl->TexParameteri(image_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(image_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else { + gl->BindTexture(image_target, staging_buffer->texture_id); + } - // Schedule a check for completed copy operations if too many operations - // are currently in-flight. - ScheduleCheckForCompletedCopyOperationsWithLockAcquired(wait_if_needed); + // Create and bind image. + if (!staging_buffer->image_id) { + if (staging_buffer->gpu_memory_buffer) { + staging_buffer->image_id = gl->CreateImageCHROMIUM( + staging_buffer->gpu_memory_buffer->AsClientBuffer(), + staging_buffer->size.width(), staging_buffer->size.height(), + GLInternalFormat(resource->format())); + gl->BindTexImage2DCHROMIUM(image_target, staging_buffer->image_id); + } + } else { + gl->ReleaseTexImage2DCHROMIUM(image_target, staging_buffer->image_id); + gl->BindTexImage2DCHROMIUM(image_target, staging_buffer->image_id); + } - { - TRACE_EVENT0("cc", "WaitingForCopyOperationsToComplete"); + // Unbind staging texture. + gl->BindTexture(image_target, 0); + + if (resource_provider_->use_sync_query()) { + if (!staging_buffer->query_id) + gl->GenQueriesEXT(1, &staging_buffer->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, staging_buffer->query_id); +#else + gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, + staging_buffer->query_id); +#endif + } - // Wait for in-flight copy operations to drop below limit. - copy_operation_count_cv_.Wait(); + int bytes_per_row = + (BitsPerPixel(resource->format()) * resource->size().width()) / 8; + int chunk_size_in_rows = + std::max(1, max_bytes_per_copy_operation_ / bytes_per_row); + // Align chunk size to 4. Required to support compressed texture formats. + chunk_size_in_rows = MathUtil::UncheckedRoundUp(chunk_size_in_rows, 4); + int y = 0; + int height = resource->size().height(); + while (y < height) { + // Copy at most |chunk_size_in_rows|. + int rows_to_copy = std::min(chunk_size_in_rows, height - y); + DCHECK_GT(rows_to_copy, 0); + + gl->CopySubTextureCHROMIUM(GL_TEXTURE_2D, staging_buffer->texture_id, + resource_lock->texture_id(), 0, y, 0, y, + resource->size().width(), rows_to_copy, false, + false, false); + y += rows_to_copy; + + // Increment |bytes_scheduled_since_last_flush_| by the amount of memory + // used for this copy operation. + bytes_scheduled_since_last_flush_ += rows_to_copy * bytes_per_row; + + if (bytes_scheduled_since_last_flush_ >= max_bytes_per_copy_operation_) { + gl->ShallowFlushCHROMIUM(); + bytes_scheduled_since_last_flush_ = 0; } } - // There may be more work available, so wake up another worker thread. - copy_operation_count_cv_.Signal(); - - // Copy at most |chunk_size_in_rows|. - int rows_to_copy = std::min(chunk_size_in_rows, height - y); - DCHECK_GT(rows_to_copy, 0); - - // |raster_resource_write_lock| is passed to the first copy operation as it - // needs to be released before we can issue a copy. - pending_copy_operations_.push_back(make_scoped_ptr(new CopyOperation( - raster_resource_write_lock.Pass(), raster_resource, output_resource, - gfx::Rect(0, y, raster_resource->size().width(), rows_to_copy)))); - y += rows_to_copy; - - // Acquire a sequence number for this copy operation. - sequence = next_copy_operation_sequence_++; - - // Increment |bytes_scheduled_since_last_flush_| by the amount of memory - // used for this copy operation. - bytes_scheduled_since_last_flush_ += rows_to_copy * bytes_per_row; - - // Post task that will advance last flushed copy operation to |sequence| - // when |bytes_scheduled_since_last_flush_| has reached - // |max_bytes_per_copy_operation_|. - if (bytes_scheduled_since_last_flush_ >= max_bytes_per_copy_operation_) { - task_runner_->PostTask( - FROM_HERE, - base::Bind(&OneCopyTileTaskWorkerPool::AdvanceLastFlushedCopyTo, - weak_ptr_factory_.GetWeakPtr(), sequence)); - bytes_scheduled_since_last_flush_ = 0; + if (resource_provider_->use_sync_query()) { +#if defined(OS_CHROMEOS) + gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); +#else + gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM); +#endif } + + // Barrier to sync worker context output to cc context. + gl->OrderingBarrierCHROMIUM(); } - return sequence; + staging_buffer->last_usage = base::TimeTicks::Now(); + busy_buffers_.push_back(staging_buffer.Pass()); + + ScheduleReduceMemoryUsage(); } -void OneCopyTileTaskWorkerPool::AdvanceLastIssuedCopyTo( - CopySequenceNumber sequence) { - if (last_issued_copy_operation_ >= sequence) - return; +bool OneCopyTileTaskWorkerPool::OnMemoryDump( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + base::AutoLock lock(lock_); - IssueCopyOperations(sequence - last_issued_copy_operation_); - last_issued_copy_operation_ = sequence; + for (const auto& buffer : buffers_) { + buffer->OnMemoryDump(pmd, buffer->format, + std::find(free_buffers_.begin(), free_buffers_.end(), + buffer) != free_buffers_.end()); + } + + return true; } -void OneCopyTileTaskWorkerPool::AdvanceLastFlushedCopyTo( - CopySequenceNumber sequence) { - if (last_flushed_copy_operation_ >= sequence) - return; +void OneCopyTileTaskWorkerPool::AddStagingBuffer( + const StagingBuffer* staging_buffer, + ResourceFormat format) { + lock_.AssertAcquired(); + + DCHECK(buffers_.find(staging_buffer) == buffers_.end()); + buffers_.insert(staging_buffer); + int buffer_usage_in_bytes = + ResourceUtil::UncheckedSizeInBytes<int>(staging_buffer->size, format); + staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes; +} - AdvanceLastIssuedCopyTo(sequence); +void OneCopyTileTaskWorkerPool::RemoveStagingBuffer( + const StagingBuffer* staging_buffer) { + lock_.AssertAcquired(); - // Flush all issued copy operations. - context_provider_->ContextGL()->ShallowFlushCHROMIUM(); - last_flushed_copy_operation_ = last_issued_copy_operation_; + DCHECK(buffers_.find(staging_buffer) != buffers_.end()); + buffers_.erase(staging_buffer); + int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>( + staging_buffer->size, staging_buffer->format); + DCHECK_GE(staging_buffer_usage_in_bytes_, buffer_usage_in_bytes); + staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes; } -void OneCopyTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) { - TRACE_EVENT1("cc", "OneCopyTileTaskWorkerPool::OnTaskSetFinished", "task_set", - task_set); +void OneCopyTileTaskWorkerPool::MarkStagingBufferAsFree( + const StagingBuffer* staging_buffer) { + lock_.AssertAcquired(); - 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); + int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>( + staging_buffer->size, staging_buffer->format); + free_staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes; } -void OneCopyTileTaskWorkerPool::IssueCopyOperations(int64 count) { - TRACE_EVENT1("cc", "OneCopyTileTaskWorkerPool::IssueCopyOperations", "count", - count); +void OneCopyTileTaskWorkerPool::MarkStagingBufferAsBusy( + const StagingBuffer* staging_buffer) { + lock_.AssertAcquired(); - CopyOperation::Deque copy_operations; + int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>( + staging_buffer->size, staging_buffer->format); + DCHECK_GE(free_staging_buffer_usage_in_bytes_, buffer_usage_in_bytes); + free_staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes; +} - { - base::AutoLock lock(lock_); +scoped_ptr<OneCopyTileTaskWorkerPool::StagingBuffer> +OneCopyTileTaskWorkerPool::AcquireStagingBuffer(const Resource* resource, + uint64_t previous_content_id) { + lock_.AssertAcquired(); + + scoped_ptr<StagingBuffer> staging_buffer; + + ContextProvider* context_provider = + resource_provider_->output_surface()->worker_context_provider(); + DCHECK(context_provider); - for (int64 i = 0; i < count; ++i) { - DCHECK(!pending_copy_operations_.empty()); - copy_operations.push_back(pending_copy_operations_.take_front()); + ContextProvider::ScopedContextLock scoped_context(context_provider); + + gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); + DCHECK(gl); + + // Check if any busy buffers have become available. + if (resource_provider_->use_sync_query()) { + while (!busy_buffers_.empty()) { + if (!CheckForQueryResult(gl, busy_buffers_.front()->query_id)) + break; + + MarkStagingBufferAsFree(busy_buffers_.front()); + free_buffers_.push_back(busy_buffers_.take_front()); } + } - // Increment |issued_copy_operation_count_| to reflect the transition of - // copy operations from "pending" to "issued" state. - issued_copy_operation_count_ += copy_operations.size(); + // Wait for memory usage of non-free buffers to become less than the limit. + while ( + (staging_buffer_usage_in_bytes_ - free_staging_buffer_usage_in_bytes_) >= + max_staging_buffer_usage_in_bytes_) { + // Stop when there are no more busy buffers to wait for. + if (busy_buffers_.empty()) + break; + + if (resource_provider_->use_sync_query()) { + WaitForQueryResult(gl, busy_buffers_.front()->query_id); + MarkStagingBufferAsFree(busy_buffers_.front()); + free_buffers_.push_back(busy_buffers_.take_front()); + } else { + // Fall-back to glFinish if CHROMIUM_sync_query is not available. + gl->Finish(); + while (!busy_buffers_.empty()) { + MarkStagingBufferAsFree(busy_buffers_.front()); + free_buffers_.push_back(busy_buffers_.take_front()); + } + } } - while (!copy_operations.empty()) { - scoped_ptr<CopyOperation> copy_operation = copy_operations.take_front(); + // Find a staging buffer that allows us to perform partial raster when + // using persistent GpuMemoryBuffers. + if (use_persistent_gpu_memory_buffers_ && previous_content_id) { + StagingBufferDeque::iterator it = + std::find_if(free_buffers_.begin(), free_buffers_.end(), + [previous_content_id](const StagingBuffer* buffer) { + return buffer->content_id == previous_content_id; + }); + if (it != free_buffers_.end()) { + staging_buffer = free_buffers_.take(it); + MarkStagingBufferAsBusy(staging_buffer.get()); + } + } - // Remove the write lock. - copy_operation->src_write_lock.reset(); + // Find staging buffer of correct size and format. + if (!staging_buffer) { + StagingBufferDeque::iterator it = + std::find_if(free_buffers_.begin(), free_buffers_.end(), + [resource](const StagingBuffer* buffer) { + return buffer->size == resource->size() && + buffer->format == resource->format(); + }); + if (it != free_buffers_.end()) { + staging_buffer = free_buffers_.take(it); + MarkStagingBufferAsBusy(staging_buffer.get()); + } + } + + // Create new staging buffer if necessary. + if (!staging_buffer) { + staging_buffer = make_scoped_ptr( + new StagingBuffer(resource->size(), resource->format())); + AddStagingBuffer(staging_buffer.get(), resource->format()); + } + + // Release enough free buffers to stay within the limit. + while (staging_buffer_usage_in_bytes_ > max_staging_buffer_usage_in_bytes_) { + if (free_buffers_.empty()) + break; - // Copy contents of source resource to destination resource. - resource_provider_->CopyResource(copy_operation->src->id(), - copy_operation->dst->id(), - copy_operation->rect); + free_buffers_.front()->DestroyGLResources(gl); + MarkStagingBufferAsBusy(free_buffers_.front()); + RemoveStagingBuffer(free_buffers_.front()); + free_buffers_.take_front(); } + + return staging_buffer.Pass(); } -void OneCopyTileTaskWorkerPool:: - ScheduleCheckForCompletedCopyOperationsWithLockAcquired( - bool wait_if_needed) { +base::TimeTicks OneCopyTileTaskWorkerPool::GetUsageTimeForLRUBuffer() { lock_.AssertAcquired(); - if (check_for_completed_copy_operations_pending_) - return; + if (!free_buffers_.empty()) + return free_buffers_.front()->last_usage; - base::TimeTicks now = base::TimeTicks::Now(); + if (!busy_buffers_.empty()) + return busy_buffers_.front()->last_usage; - // Schedule a check for completed copy operations as soon as possible but - // don't allow two consecutive checks to be scheduled to run less than the - // tick rate apart. - base::TimeTicks next_check_for_completed_copy_operations_time = - std::max(last_check_for_completed_copy_operations_time_ + - base::TimeDelta::FromMilliseconds( - kCheckForCompletedCopyOperationsTickRateMs), - now); + return base::TimeTicks(); +} +void OneCopyTileTaskWorkerPool::ScheduleReduceMemoryUsage() { + lock_.AssertAcquired(); + + if (reduce_memory_usage_pending_) + return; + + reduce_memory_usage_pending_ = true; + + // Schedule a call to ReduceMemoryUsage at the time when the LRU buffer + // should be released. + base::TimeTicks reduce_memory_usage_time = + GetUsageTimeForLRUBuffer() + staging_buffer_expiration_delay_; task_runner_->PostDelayedTask( - FROM_HERE, - 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_ = - next_check_for_completed_copy_operations_time; - check_for_completed_copy_operations_pending_ = true; + FROM_HERE, reduce_memory_usage_callback_, + reduce_memory_usage_time - base::TimeTicks::Now()); } -void OneCopyTileTaskWorkerPool::CheckForCompletedCopyOperations( - bool wait_if_needed) { - TRACE_EVENT1("cc", - "OneCopyTileTaskWorkerPool::CheckForCompletedCopyOperations", - "wait_if_needed", wait_if_needed); +void OneCopyTileTaskWorkerPool::ReduceMemoryUsage() { + base::AutoLock lock(lock_); + + reduce_memory_usage_pending_ = false; + + if (free_buffers_.empty() && busy_buffers_.empty()) + return; - resource_pool_->CheckBusyResources(wait_if_needed); + base::TimeTicks current_time = base::TimeTicks::Now(); + ReleaseBuffersNotUsedSince(current_time - staging_buffer_expiration_delay_); + + if (free_buffers_.empty() && busy_buffers_.empty()) + return; + + reduce_memory_usage_pending_ = true; + + // Schedule another call to ReduceMemoryUsage at the time when the next + // buffer should be released. + base::TimeTicks reduce_memory_usage_time = + GetUsageTimeForLRUBuffer() + staging_buffer_expiration_delay_; + task_runner_->PostDelayedTask(FROM_HERE, reduce_memory_usage_callback_, + reduce_memory_usage_time - current_time); +} + +void OneCopyTileTaskWorkerPool::ReleaseBuffersNotUsedSince( + base::TimeTicks time) { + lock_.AssertAcquired(); + + ContextProvider* context_provider = + resource_provider_->output_surface()->worker_context_provider(); + DCHECK(context_provider); { - base::AutoLock lock(lock_); + ContextProvider::ScopedContextLock scoped_context(context_provider); + + gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); + DCHECK(gl); - DCHECK(check_for_completed_copy_operations_pending_); - check_for_completed_copy_operations_pending_ = false; + // Note: Front buffer is guaranteed to be LRU so we can stop releasing + // buffers as soon as we find a buffer that has been used since |time|. + while (!free_buffers_.empty()) { + if (free_buffers_.front()->last_usage > time) + return; + + free_buffers_.front()->DestroyGLResources(gl); + MarkStagingBufferAsBusy(free_buffers_.front()); + RemoveStagingBuffer(free_buffers_.front()); + free_buffers_.take_front(); + } - // The number of busy resources in the pool reflects the number of issued - // copy operations that have not yet completed. - issued_copy_operation_count_ = resource_pool_->busy_resource_count(); + while (!busy_buffers_.empty()) { + if (busy_buffers_.front()->last_usage > time) + return; - // There may be work blocked on too many in-flight copy operations, so wake - // up a worker thread. - copy_operation_count_cv_.Signal(); + busy_buffers_.front()->DestroyGLResources(gl); + RemoveStagingBuffer(busy_buffers_.front()); + busy_buffers_.take_front(); + } + } +} + +void OneCopyTileTaskWorkerPool::OnTaskSetFinished(TaskSet task_set) { + TRACE_EVENT1("cc", "OneCopyTileTaskWorkerPool::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> @@ -571,20 +807,14 @@ OneCopyTileTaskWorkerPool::StateAsValue() const { void OneCopyTileTaskWorkerPool::StagingStateAsValueInto( base::trace_event::TracedValue* staging_state) const { - staging_state->SetInteger( - "staging_resource_count", - static_cast<int>(resource_pool_->total_resource_count())); - staging_state->SetInteger( - "bytes_used_for_staging_resources", - static_cast<int>(resource_pool_->total_memory_usage_bytes())); - staging_state->SetInteger( - "pending_copy_count", - static_cast<int>(resource_pool_->total_resource_count() - - resource_pool_->acquired_resource_count())); - staging_state->SetInteger( - "bytes_pending_copy", - static_cast<int>(resource_pool_->total_memory_usage_bytes() - - resource_pool_->acquired_memory_usage_bytes())); + base::AutoLock lock(lock_); + + staging_state->SetInteger("staging_buffer_count", + static_cast<int>(buffers_.size())); + staging_state->SetInteger("busy_count", + static_cast<int>(busy_buffers_.size())); + staging_state->SetInteger("free_count", + static_cast<int>(free_buffers_.size())); } } // namespace cc diff --git a/chromium/cc/raster/one_copy_tile_task_worker_pool.h b/chromium/cc/raster/one_copy_tile_task_worker_pool.h index 518aaa2d490..3b02bae062a 100644 --- a/chromium/cc/raster/one_copy_tile_task_worker_pool.h +++ b/chromium/cc/raster/one_copy_tile_task_worker_pool.h @@ -5,8 +5,12 @@ #ifndef CC_RASTER_ONE_COPY_TILE_TASK_WORKER_POOL_H_ #define CC_RASTER_ONE_COPY_TILE_TASK_WORKER_POOL_H_ +#include <set> + #include "base/memory/weak_ptr.h" #include "base/synchronization/lock.h" +#include "base/time/time.h" +#include "base/trace_event/memory_dump_provider.h" #include "base/values.h" #include "cc/base/scoped_ptr_deque.h" #include "cc/output/context_provider.h" @@ -21,15 +25,20 @@ class TracedValue; } } +namespace gpu { +namespace gles2 { +class GLES2Interface; +} +} + namespace cc { class ResourcePool; -class ScopedResource; - -typedef int64 CopySequenceNumber; -class CC_EXPORT OneCopyTileTaskWorkerPool : public TileTaskWorkerPool, - public TileTaskRunner, - public TileTaskClient { +class CC_EXPORT OneCopyTileTaskWorkerPool + : public TileTaskWorkerPool, + public TileTaskRunner, + public TileTaskClient, + public base::trace_event::MemoryDumpProvider { public: ~OneCopyTileTaskWorkerPool() override; @@ -38,9 +47,10 @@ class CC_EXPORT OneCopyTileTaskWorkerPool : public TileTaskWorkerPool, TaskGraphRunner* task_graph_runner, ContextProvider* context_provider, ResourceProvider* resource_provider, - ResourcePool* resource_pool, int max_copy_texture_chromium_size, - bool have_persistent_gpu_memory_buffers); + bool use_persistent_gpu_memory_buffers, + int max_staging_buffer_usage_in_bytes, + bool use_rgba_4444_texture_format); // Overridden from TileTaskWorkerPool: TileTaskRunner* AsTileTaskRunner() override; @@ -50,8 +60,8 @@ class CC_EXPORT OneCopyTileTaskWorkerPool : public TileTaskWorkerPool, void Shutdown() override; void ScheduleTasks(TileTaskQueue* queue) override; void CheckForCompletedTasks() override; - ResourceFormat GetResourceFormat() const override; - bool GetResourceRequiresSwizzle() const override; + ResourceFormat GetResourceFormat(bool must_support_alpha) const override; + bool GetResourceRequiresSwizzle(bool must_support_alpha) const override; // Overridden from TileTaskClient: scoped_ptr<RasterBuffer> AcquireBufferForRaster( @@ -60,60 +70,64 @@ class CC_EXPORT OneCopyTileTaskWorkerPool : public TileTaskWorkerPool, uint64_t previous_content_id) override; void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override; - // Playback raster source and schedule copy of |raster_resource| resource to - // |output_resource|. Returns a non-zero sequence number for this copy - // operation. - CopySequenceNumber PlaybackAndScheduleCopyOnWorkerThread( - bool reusing_raster_resource, - scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> - raster_resource_write_lock, - const Resource* raster_resource, - const Resource* output_resource, + // Overridden from base::trace_event::MemoryDumpProvider: + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) override; + + // Playback raster source and copy result into |resource|. + void PlaybackAndCopyOnWorkerThread( + const Resource* resource, + const ResourceProvider::ScopedWriteLockGL* resource_lock, const RasterSource* raster_source, const gfx::Rect& raster_full_rect, const gfx::Rect& raster_dirty_rect, - float scale); - - // Issues copy operations until |sequence| has been processed. This will - // return immediately if |sequence| has already been processed. - void AdvanceLastIssuedCopyTo(CopySequenceNumber sequence); - - bool have_persistent_gpu_memory_buffers() const { - return have_persistent_gpu_memory_buffers_; - } + float scale, + bool include_images, + uint64_t resource_content_id, + uint64_t previous_content_id); protected: OneCopyTileTaskWorkerPool(base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, - ContextProvider* context_provider, ResourceProvider* resource_provider, - ResourcePool* resource_pool, int max_copy_texture_chromium_size, - bool have_persistent_gpu_memory_buffers); + bool use_persistent_gpu_memory_buffers, + int max_staging_buffer_usage_in_bytes, + bool use_rgba_4444_texture_format); private: - struct CopyOperation { - typedef ScopedPtrDeque<CopyOperation> Deque; - - CopyOperation(scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> - src_write_lock, - const Resource* src, - const Resource* dst, - const gfx::Rect& rect); - ~CopyOperation(); - - scoped_ptr<ResourceProvider::ScopedWriteLockGpuMemoryBuffer> src_write_lock; - const Resource* src; - const Resource* dst; - const gfx::Rect rect; + struct StagingBuffer { + StagingBuffer(const gfx::Size& size, ResourceFormat format); + ~StagingBuffer(); + + void DestroyGLResources(gpu::gles2::GLES2Interface* gl); + void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, + ResourceFormat format, + bool is_free) const; + + const gfx::Size size; + const ResourceFormat format; + scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; + base::TimeTicks last_usage; + unsigned texture_id; + unsigned image_id; + unsigned query_id; + uint64_t content_id; }; + void AddStagingBuffer(const StagingBuffer* staging_buffer, + ResourceFormat format); + void RemoveStagingBuffer(const StagingBuffer* staging_buffer); + void MarkStagingBufferAsFree(const StagingBuffer* staging_buffer); + void MarkStagingBufferAsBusy(const StagingBuffer* staging_buffer); + scoped_ptr<StagingBuffer> AcquireStagingBuffer(const Resource* resource, + uint64_t previous_content_id); + base::TimeTicks GetUsageTimeForLRUBuffer(); + void ScheduleReduceMemoryUsage(); + void ReduceMemoryUsage(); + void ReleaseBuffersNotUsedSince(base::TimeTicks time); + 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::trace_event::ConvertableToTraceFormat> StateAsValue() const; void StagingStateAsValueInto( @@ -123,31 +137,32 @@ class CC_EXPORT OneCopyTileTaskWorkerPool : public TileTaskWorkerPool, TaskGraphRunner* task_graph_runner_; const NamespaceToken namespace_token_; TileTaskRunnerClient* client_; - ContextProvider* context_provider_; - ResourceProvider* resource_provider_; - ResourcePool* resource_pool_; + ResourceProvider* const resource_provider_; const int max_bytes_per_copy_operation_; - const bool have_persistent_gpu_memory_buffers_; + const bool use_persistent_gpu_memory_buffers_; TaskSetCollection tasks_pending_; scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets]; - CopySequenceNumber last_issued_copy_operation_; - CopySequenceNumber last_flushed_copy_operation_; // Task graph used when scheduling tasks and vector used to gather // completed tasks. TaskGraph graph_; Task::Vector completed_tasks_; - base::Lock lock_; + mutable base::Lock lock_; // |lock_| must be acquired when accessing the following members. - base::ConditionVariable copy_operation_count_cv_; + using StagingBufferSet = std::set<const StagingBuffer*>; + StagingBufferSet buffers_; + using StagingBufferDeque = ScopedPtrDeque<StagingBuffer>; + StagingBufferDeque free_buffers_; + StagingBufferDeque busy_buffers_; int bytes_scheduled_since_last_flush_; - size_t issued_copy_operation_count_; - CopyOperation::Deque pending_copy_operations_; - CopySequenceNumber next_copy_operation_sequence_; - bool check_for_completed_copy_operations_pending_; - base::TimeTicks last_check_for_completed_copy_operations_time_; - bool shutdown_; + const int max_staging_buffer_usage_in_bytes_; + bool use_rgba_4444_texture_format_; + int staging_buffer_usage_in_bytes_; + int free_staging_buffer_usage_in_bytes_; + const base::TimeDelta staging_buffer_expiration_delay_; + bool reduce_memory_usage_pending_; + base::Closure reduce_memory_usage_callback_; base::WeakPtrFactory<OneCopyTileTaskWorkerPool> weak_ptr_factory_; // "raster finished" tasks need their own factory as they need to be diff --git a/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.cc b/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.cc deleted file mode 100644 index df79519485d..00000000000 --- a/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.cc +++ /dev/null @@ -1,754 +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/raster/pixel_buffer_tile_task_worker_pool.h" - -#include <algorithm> - -#include "base/containers/stack_container.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/raster/raster_buffer.h" -#include "cc/resources/platform_color.h" -#include "cc/resources/resource.h" -#include "gpu/command_buffer/client/gles2_interface.h" - -namespace cc { -namespace { - -class RasterBufferImpl : public RasterBuffer { - public: - RasterBufferImpl(ResourceProvider* resource_provider, - const Resource* resource) - : resource_provider_(resource_provider), - resource_(resource), - memory_(NULL), - stride_(0) { - resource_provider_->AcquirePixelBuffer(resource_->id()); - memory_ = resource_provider_->MapPixelBuffer(resource_->id(), &stride_); - } - - ~RasterBufferImpl() override { - resource_provider_->ReleasePixelBuffer(resource_->id()); - } - - // Overridden from RasterBuffer: - void Playback(const RasterSource* raster_source, - const gfx::Rect& raster_full_rect, - const gfx::Rect& raster_dirty_rect, - uint64_t new_content_id, - float scale) override { - if (!memory_) - return; - - // TileTaskWorkerPool::PlaybackToMemory only supports unsigned strides. - DCHECK_GE(stride_, 0); - TileTaskWorkerPool::PlaybackToMemory( - memory_, resource_->format(), resource_->size(), - static_cast<size_t>(stride_), raster_source, raster_full_rect, - raster_full_rect, scale); - } - - private: - ResourceProvider* resource_provider_; - const Resource* resource_; - uint8_t* memory_; - int stride_; - - DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); -}; - -const int kCheckForCompletedRasterTasksDelayMs = 6; - -const size_t kMaxScheduledRasterTasks = 48; - -typedef base::StackVector<RasterTask*, kMaxScheduledRasterTasks> - RasterTaskVector; - -TaskSetCollection NonEmptyTaskSetsFromTaskCounts(const size_t* task_counts) { - TaskSetCollection task_sets; - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - if (task_counts[task_set]) - task_sets[task_set] = true; - } - return task_sets; -} - -void AddTaskSetsToTaskCounts(size_t* task_counts, - const TaskSetCollection& task_sets) { - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - if (task_sets[task_set]) - task_counts[task_set]++; - } -} - -void RemoveTaskSetsFromTaskCounts(size_t* task_counts, - const TaskSetCollection& task_sets) { - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - if (task_sets[task_set]) - task_counts[task_set]--; - } -} - -} // namespace - -PixelBufferTileTaskWorkerPool::RasterTaskState::RasterTaskState( - RasterTask* task, - const TaskSetCollection& task_sets) - : type(UNSCHEDULED), task(task), task_sets(task_sets) { -} - -// static -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<TileTaskWorkerPool>(new PixelBufferTileTaskWorkerPool( - task_runner, task_graph_runner, context_provider, resource_provider, - max_transfer_buffer_usage_bytes)); -} - -PixelBufferTileTaskWorkerPool::PixelBufferTileTaskWorkerPool( - base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ContextProvider* context_provider, - ResourceProvider* resource_provider, - size_t max_transfer_buffer_usage_bytes) - : task_runner_(task_runner), - task_graph_runner_(task_graph_runner), - namespace_token_(task_graph_runner->GetNamespaceToken()), - context_provider_(context_provider), - resource_provider_(resource_provider), - shutdown_(false), - scheduled_raster_task_count_(0u), - bytes_pending_upload_(0u), - max_bytes_pending_upload_(max_transfer_buffer_usage_bytes), - has_performed_uploads_since_last_flush_(false), - check_for_completed_raster_task_notifier_( - task_runner, - base::Bind( - &PixelBufferTileTaskWorkerPool::CheckForCompletedRasterTasks, - base::Unretained(this)), - base::TimeDelta::FromMilliseconds( - kCheckForCompletedRasterTasksDelayMs)), - task_set_finished_weak_ptr_factory_(this) { - DCHECK(context_provider_); - std::fill(task_counts_, task_counts_ + kNumberOfTaskSets, 0); -} - -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()); - DCHECK_EQ(0u, completed_image_decode_tasks_.size()); - DCHECK(NonEmptyTaskSetsFromTaskCounts(task_counts_).none()); -} - -TileTaskRunner* PixelBufferTileTaskWorkerPool::AsTileTaskRunner() { - return this; -} - -void PixelBufferTileTaskWorkerPool::SetClient(TileTaskRunnerClient* client) { - client_ = client; -} - -void PixelBufferTileTaskWorkerPool::Shutdown() { - TRACE_EVENT0("cc", "PixelBufferTileTaskWorkerPool::Shutdown"); - - shutdown_ = true; - - TaskGraph empty; - task_graph_runner_->ScheduleTasks(namespace_token_, &empty); - task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); - - CheckForCompletedRasterizerTasks(); - CheckForCompletedUploads(); - - check_for_completed_raster_task_notifier_.Shutdown(); - - for (RasterTaskState::Vector::iterator it = raster_task_states_.begin(); - it != raster_task_states_.end(); ++it) { - RasterTaskState& state = *it; - - // All unscheduled tasks need to be canceled. - if (state.type == RasterTaskState::UNSCHEDULED) { - completed_raster_tasks_.push_back(state.task); - state.type = RasterTaskState::COMPLETED; - } - } - DCHECK_EQ(completed_raster_tasks_.size(), raster_task_states_.size()); -} - -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); - - should_notify_client_if_no_tasks_are_pending_.set(); - std::fill(task_counts_, task_counts_ + kNumberOfTaskSets, 0); - - // Update raster task state and remove items from old queue. - 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. - 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(), - RasterTaskState::TaskComparator(task)); - if (state_it != raster_task_states_.end()) { - RasterTaskState& state = *state_it; - - state.task_sets = item.task_sets; - // |raster_tasks_required_for_activation_count| accounts for all tasks - // that need to complete before we can send a "ready to activate" signal. - // Tasks that have already completed should not be part of this count. - if (state.type != RasterTaskState::COMPLETED) - AddTaskSetsToTaskCounts(task_counts_, item.task_sets); - - continue; - } - - DCHECK(!task->HasBeenScheduled()); - raster_task_states_.push_back(RasterTaskState(task, item.task_sets)); - AddTaskSetsToTaskCounts(task_counts_, item.task_sets); - } - - // Determine what tasks in old queue need to be canceled. - for (TileTaskQueue::Item::Vector::const_iterator it = - raster_tasks_.items.begin(); - 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(), - RasterTaskState::TaskComparator(task)); - // We've already processed completion if we can't find a RasterTaskState for - // this task. - if (state_it == raster_task_states_.end()) - continue; - - RasterTaskState& state = *state_it; - - // Unscheduled task can be canceled. - if (state.type == RasterTaskState::UNSCHEDULED) { - DCHECK(!task->HasBeenScheduled()); - DCHECK(std::find(completed_raster_tasks_.begin(), - completed_raster_tasks_.end(), - task) == completed_raster_tasks_.end()); - completed_raster_tasks_.push_back(task); - state.type = RasterTaskState::COMPLETED; - } - - // No longer in any task set. - state.task_sets.reset(); - } - - raster_tasks_.Swap(queue); - - // Check for completed tasks when ScheduleTasks() is called as - // priorities might have changed and this maximizes the number - // of top priority tasks that are scheduled. - CheckForCompletedRasterizerTasks(); - CheckForCompletedUploads(); - FlushUploads(); - - // Schedule new tasks. - ScheduleMoreTasks(); - - // Reschedule check for completed raster tasks. - check_for_completed_raster_task_notifier_.Schedule(); - - TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, StateName(), - "state", StateAsValue()); -} - -void PixelBufferTileTaskWorkerPool::CheckForCompletedTasks() { - TRACE_EVENT0("cc", "PixelBufferTileTaskWorkerPool::CheckForCompletedTasks"); - - CheckForCompletedRasterizerTasks(); - CheckForCompletedUploads(); - FlushUploads(); - - for (TileTask::Vector::const_iterator it = - completed_image_decode_tasks_.begin(); - 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) { - RasterTask* task = it->get(); - RasterTaskState::Vector::iterator state_it = - 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); - - std::swap(*state_it, raster_task_states_.back()); - raster_task_states_.pop_back(); - - task->RunReplyOnOriginThread(); - } - completed_raster_tasks_.clear(); -} - -ResourceFormat PixelBufferTileTaskWorkerPool::GetResourceFormat() const { - return resource_provider_->memory_efficient_texture_format(); -} - -bool PixelBufferTileTaskWorkerPool::GetResourceRequiresSwizzle() const { - return !PlatformColor::SameComponentOrder(GetResourceFormat()); -} - -scoped_ptr<RasterBuffer> PixelBufferTileTaskWorkerPool::AcquireBufferForRaster( - const Resource* resource, - uint64_t resource_content_id, - uint64_t previous_content_id) { - return make_scoped_ptr<RasterBuffer>( - new RasterBufferImpl(resource_provider_, resource)); -} - -void PixelBufferTileTaskWorkerPool::ReleaseBufferForRaster( - scoped_ptr<RasterBuffer> buffer) { - // Nothing to do here. RasterBufferImpl destructor cleans up after itself. -} - -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]); - - // There's no need to call CheckForCompletedRasterTasks() if the client has - // already been notified. - if (!should_notify_client_if_no_tasks_are_pending_[task_set]) - return; - 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 - // notified. - CheckForCompletedRasterTasks(); -} - -void PixelBufferTileTaskWorkerPool::FlushUploads() { - if (!has_performed_uploads_since_last_flush_) - return; - - context_provider_->ContextGL()->ShallowFlushCHROMIUM(); - has_performed_uploads_since_last_flush_ = false; -} - -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(), - 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); - - // Uploads complete in the order they are issued. - if (!resource_provider_->DidSetPixelsComplete(task->resource()->id())) - break; - - tasks_with_completed_uploads.push_back(task); - raster_tasks_with_pending_upload_.pop_front(); - } - - DCHECK(client_); - TaskSetCollection tasks_that_should_be_forced_to_complete = - client_->TasksThatShouldBeForcedToComplete(); - bool should_force_some_uploads_to_complete = - shutdown_ || tasks_that_should_be_forced_to_complete.any(); - - if (should_force_some_uploads_to_complete) { - RasterTask::Vector tasks_with_uploads_to_force; - RasterTaskDeque::iterator it = raster_tasks_with_pending_upload_.begin(); - 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(), - RasterTaskState::TaskComparator(task)); - DCHECK(state_it != raster_task_states_.end()); - const RasterTaskState& state = *state_it; - - // Force all uploads to complete for which the client requests to do so. - // During shutdown, force all pending uploads to complete. - if (shutdown_ || - (state.task_sets & tasks_that_should_be_forced_to_complete).any()) { - tasks_with_uploads_to_force.push_back(task); - tasks_with_completed_uploads.push_back(task); - it = raster_tasks_with_pending_upload_.erase(it); - continue; - } - - ++it; - } - - // Force uploads in reverse order. Since forcing can cause a wait on - // 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) { - RasterTask* task = it->get(); - - resource_provider_->ForceSetPixelsToComplete(task->resource()->id()); - has_performed_uploads_since_last_flush_ = true; - } - } - - // Release shared memory and move tasks with completed uploads - // to |completed_raster_tasks_|. - for (RasterTask::Vector::const_iterator it = - tasks_with_completed_uploads.begin(); - 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(), - RasterTaskState::TaskComparator(task)); - DCHECK(state_it != raster_task_states_.end()); - RasterTaskState& state = *state_it; - - // We can use UncheckedMemorySizeBytes here, since these tasks come from - // tiles, the size of which is controlled by the compositor. - bytes_pending_upload_ -= Resource::UncheckedMemorySizeBytes( - task->resource()->size(), task->resource()->format()); - - task->WillComplete(); - task->CompleteOnOriginThread(this); - task->DidComplete(); - - DCHECK(std::find(completed_raster_tasks_.begin(), - completed_raster_tasks_.end(), - task) == completed_raster_tasks_.end()); - completed_raster_tasks_.push_back(task); - state.type = RasterTaskState::COMPLETED; - // Triggers if the current task belongs to a set that should be empty. - DCHECK((state.task_sets & ~NonEmptyTaskSetsFromTaskCounts(task_counts_)) - .none()); - RemoveTaskSetsFromTaskCounts(task_counts_, state.task_sets); - } -} - -void PixelBufferTileTaskWorkerPool::CheckForCompletedRasterTasks() { - TRACE_EVENT0("cc", - "PixelBufferTileTaskWorkerPool::CheckForCompletedRasterTasks"); - - // Since this function can be called directly, cancel any pending checks. - check_for_completed_raster_task_notifier_.Cancel(); - - DCHECK(should_notify_client_if_no_tasks_are_pending_.any()); - - CheckForCompletedRasterizerTasks(); - CheckForCompletedUploads(); - FlushUploads(); - - // Determine what client notifications to generate. - TaskSetCollection will_notify_client_that_no_tasks_are_pending = - should_notify_client_if_no_tasks_are_pending_ & - ~task_set_finished_tasks_pending_ & ~PendingTasks(); - - // Adjust the need to generate notifications before scheduling more tasks. - should_notify_client_if_no_tasks_are_pending_ &= - ~will_notify_client_that_no_tasks_are_pending; - - scheduled_raster_task_count_ = 0; - if (PendingRasterTaskCount()) - ScheduleMoreTasks(); - - 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. - if (PendingTasks().any()) - check_for_completed_raster_task_notifier_.Schedule(); - - if (should_notify_client_if_no_tasks_are_pending_.none()) - TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this); - - // Generate client notifications. - 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_->DidFinishRunningTileTasks(task_set); - } - } -} - -void PixelBufferTileTaskWorkerPool::ScheduleMoreTasks() { - TRACE_EVENT0("cc", "PixelBufferTileTaskWorkerPool::ScheduleMoreTasks"); - - RasterTaskVector tasks[kNumberOfTaskSets]; - - size_t priority = kTileTaskPriorityBase; - - graph_.Reset(); - - size_t bytes_pending_upload = bytes_pending_upload_; - TaskSetCollection did_throttle_raster_tasks; - size_t scheduled_raster_task_count = 0; - - for (TileTaskQueue::Item::Vector::const_iterator it = - raster_tasks_.items.begin(); - 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(), - RasterTaskState::TaskComparator(task)); - if (state_it == raster_task_states_.end()) - continue; - - RasterTaskState& state = *state_it; - - // Skip task if completed. - if (state.type == RasterTaskState::COMPLETED) { - DCHECK(std::find(completed_raster_tasks_.begin(), - completed_raster_tasks_.end(), - task) != completed_raster_tasks_.end()); - continue; - } - - // All raster tasks need to be throttled by bytes of pending uploads, - // but if it's the only task allow it to complete no matter what its size, - // to prevent starvation of the task queue. - size_t new_bytes_pending_upload = bytes_pending_upload; - // We can use UncheckedMemorySizeBytes here, since these tasks come from - // tiles, the size of which is controlled by the compositor. - new_bytes_pending_upload += Resource::UncheckedMemorySizeBytes( - task->resource()->size(), task->resource()->format()); - if (new_bytes_pending_upload > max_bytes_pending_upload_ && - bytes_pending_upload) { - did_throttle_raster_tasks |= item.task_sets; - continue; - } - - // If raster has finished, just update |bytes_pending_upload|. - if (state.type == RasterTaskState::UPLOADING) { - DCHECK(!task->HasCompleted()); - bytes_pending_upload = new_bytes_pending_upload; - continue; - } - - // Throttle raster tasks based on kMaxScheduledRasterTasks. - if (scheduled_raster_task_count >= kMaxScheduledRasterTasks) { - did_throttle_raster_tasks |= item.task_sets; - continue; - } - - // Update |bytes_pending_upload| now that task has cleared all - // throttling limits. - bytes_pending_upload = new_bytes_pending_upload; - - DCHECK(state.type == RasterTaskState::UNSCHEDULED || - state.type == RasterTaskState::SCHEDULED); - state.type = RasterTaskState::SCHEDULED; - - InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++); - - ++scheduled_raster_task_count; - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) { - if (item.task_sets[task_set]) - tasks[task_set].container().push_back(task); - } - } - - // Cancel existing OnTaskSetFinished callbacks. - task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs(); - - 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 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_task_set_finished_tasks[task_set] = CreateTaskSetFinishedTask( - task_runner_.get(), - base::Bind(&PixelBufferTileTaskWorkerPool::OnTaskSetFinished, - task_set_finished_weak_ptr_factory_.GetWeakPtr(), - task_set)); - 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) { - graph_.edges.push_back( - TaskGraph::Edge(*it, new_task_set_finished_tasks[task_set].get())); - } - } - } - - DCHECK_LE(scheduled_raster_task_count, PendingRasterTaskCount()); - - ScheduleTasksOnOriginThread(this, &graph_); - task_graph_runner_->ScheduleTasks(namespace_token_, &graph_); - - scheduled_raster_task_count_ = scheduled_raster_task_count; - - std::copy(new_task_set_finished_tasks, - new_task_set_finished_tasks + kNumberOfTaskSets, - task_set_finished_tasks_); -} - -size_t PixelBufferTileTaskWorkerPool::PendingRasterTaskCount() const { - size_t 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 PixelBufferTileTaskWorkerPool::PendingTasks() const { - return NonEmptyTaskSetsFromTaskCounts(task_counts_); -} - -const char* PixelBufferTileTaskWorkerPool::StateName() const { - if (scheduled_raster_task_count_) - return "rasterizing"; - if (PendingRasterTaskCount()) - return "throttled"; - if (!raster_tasks_with_pending_upload_.empty()) - return "waiting_for_uploads"; - - return "finishing"; -} - -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) { - TileTask* task = static_cast<TileTask*>(it->get()); - - RasterTask* raster_task = task->AsRasterTask(); - if (!raster_task) { - task->WillComplete(); - task->CompleteOnOriginThread(this); - task->DidComplete(); - - completed_image_decode_tasks_.push_back(task); - continue; - } - - RasterTaskState::Vector::iterator state_it = - std::find_if(raster_task_states_.begin(), raster_task_states_.end(), - RasterTaskState::TaskComparator(raster_task)); - DCHECK(state_it != raster_task_states_.end()); - - RasterTaskState& state = *state_it; - DCHECK_EQ(RasterTaskState::SCHEDULED, state.type); - - resource_provider_->UnmapPixelBuffer(raster_task->resource()->id()); - - if (!raster_task->HasFinishedRunning()) { - // When priorites change, a raster task can be canceled as a result of - // no longer being of high enough priority to fit in our throttled - // raster task budget. The task has not yet completed in this case. - raster_task->WillComplete(); - raster_task->CompleteOnOriginThread(this); - raster_task->DidComplete(); - - 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; - } - - DCHECK(std::find(completed_raster_tasks_.begin(), - completed_raster_tasks_.end(), - raster_task) == completed_raster_tasks_.end()); - completed_raster_tasks_.push_back(raster_task); - state.type = RasterTaskState::COMPLETED; - // Triggers if the current task belongs to a set that should be empty. - DCHECK((state.task_sets & ~NonEmptyTaskSetsFromTaskCounts(task_counts_)) - .none()); - RemoveTaskSetsFromTaskCounts(task_counts_, state.task_sets); - continue; - } - - resource_provider_->BeginSetPixels(raster_task->resource()->id()); - has_performed_uploads_since_last_flush_ = true; - - // We can use UncheckedMemorySizeBytes here, since these tasks come from - // tiles, the size of which is controlled by the compositor. - bytes_pending_upload_ += Resource::UncheckedMemorySizeBytes( - raster_task->resource()->size(), raster_task->resource()->format()); - raster_tasks_with_pending_upload_.push_back(raster_task); - state.type = RasterTaskState::UPLOADING; - } - completed_tasks_.clear(); -} - -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", - static_cast<int>(completed_raster_tasks_.size())); - state->BeginArray("pending_count"); - for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set) - state->AppendInteger(static_cast<int>(task_counts_[task_set])); - state->EndArray(); - state->SetInteger("pending_upload_count", - static_cast<int>(raster_tasks_with_pending_upload_.size())); - state->BeginDictionary("throttle_state"); - ThrottleStateAsValueInto(state.get()); - state->EndDictionary(); - return state; -} - -void PixelBufferTileTaskWorkerPool::ThrottleStateAsValueInto( - base::trace_event::TracedValue* throttle_state) const { - throttle_state->SetInteger( - "bytes_available_for_upload", - static_cast<int>(max_bytes_pending_upload_ - bytes_pending_upload_)); - throttle_state->SetInteger("bytes_pending_upload", - static_cast<int>(bytes_pending_upload_)); - throttle_state->SetInteger("scheduled_raster_task_count", - static_cast<int>(scheduled_raster_task_count_)); -} - -} // namespace cc diff --git a/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.h b/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.h deleted file mode 100644 index 2c6aeb98228..00000000000 --- a/chromium/cc/raster/pixel_buffer_tile_task_worker_pool.h +++ /dev/null @@ -1,146 +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_RASTER_PIXEL_BUFFER_TILE_TASK_WORKER_POOL_H_ -#define CC_RASTER_PIXEL_BUFFER_TILE_TASK_WORKER_POOL_H_ - -#include <deque> -#include <vector> - -#include "base/memory/weak_ptr.h" -#include "base/values.h" -#include "cc/base/delayed_unique_notifier.h" -#include "cc/output/context_provider.h" -#include "cc/raster/tile_task_runner.h" -#include "cc/raster/tile_task_worker_pool.h" - -namespace base { -namespace trace_event { -class ConvertableToTraceFormat; -class TracedValue; -} -} - -namespace cc { -class ResourceProvider; - -class CC_EXPORT PixelBufferTileTaskWorkerPool : public TileTaskWorkerPool, - public TileTaskRunner, - public TileTaskClient { - public: - ~PixelBufferTileTaskWorkerPool() override; - - 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 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() const override; - bool GetResourceRequiresSwizzle() const override; - - // Overridden from TileTaskClient: - scoped_ptr<RasterBuffer> AcquireBufferForRaster( - const Resource* resource, - uint64_t resource_content_id, - uint64_t previous_content_id) override; - void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override; - - private: - struct RasterTaskState { - class TaskComparator { - public: - explicit TaskComparator(const RasterTask* task) : task_(task) {} - - bool operator()(const RasterTaskState& state) const { - return state.task == task_; - } - - private: - const RasterTask* task_; - }; - - typedef std::vector<RasterTaskState> Vector; - - RasterTaskState(RasterTask* task, const TaskSetCollection& task_sets); - - enum { UNSCHEDULED, SCHEDULED, UPLOADING, COMPLETED } type; - RasterTask* task; - TaskSetCollection task_sets; - }; - - typedef std::deque<scoped_refptr<RasterTask>> RasterTaskDeque; - - PixelBufferTileTaskWorkerPool(base::SequencedTaskRunner* task_runner, - TaskGraphRunner* task_graph_runner, - ContextProvider* context_provider, - ResourceProvider* resource_provider, - size_t max_transfer_buffer_usage_bytes); - - void OnTaskSetFinished(TaskSet task_set); - void FlushUploads(); - void CheckForCompletedUploads(); - void CheckForCompletedRasterTasks(); - void ScheduleMoreTasks(); - size_t PendingRasterTaskCount() const; - TaskSetCollection PendingTasks() const; - void CheckForCompletedRasterizerTasks(); - - const char* StateName() 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_; - TileTaskRunnerClient* client_; - ContextProvider* context_provider_; - ResourceProvider* resource_provider_; - - bool shutdown_; - - TileTaskQueue raster_tasks_; - RasterTaskState::Vector raster_task_states_; - RasterTaskDeque raster_tasks_with_pending_upload_; - RasterTask::Vector completed_raster_tasks_; - TileTask::Vector completed_image_decode_tasks_; - - size_t scheduled_raster_task_count_; - size_t task_counts_[kNumberOfTaskSets]; - size_t bytes_pending_upload_; - size_t max_bytes_pending_upload_; - bool has_performed_uploads_since_last_flush_; - - TaskSetCollection should_notify_client_if_no_tasks_are_pending_; - TaskSetCollection task_set_finished_tasks_pending_; - - DelayedUniqueNotifier check_for_completed_raster_task_notifier_; - - 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<PixelBufferTileTaskWorkerPool> - task_set_finished_weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(PixelBufferTileTaskWorkerPool); -}; - -} // namespace cc - -#endif // CC_RASTER_PIXEL_BUFFER_TILE_TASK_WORKER_POOL_H_ diff --git a/chromium/cc/raster/raster_buffer.h b/chromium/cc/raster/raster_buffer.h index 5af4deca25b..ac4e74ca802 100644 --- a/chromium/cc/raster/raster_buffer.h +++ b/chromium/cc/raster/raster_buffer.h @@ -20,7 +20,8 @@ class CC_EXPORT RasterBuffer { const gfx::Rect& raster_full_rect, const gfx::Rect& raster_dirty_rect, uint64_t new_content_id, - float scale) = 0; + float scale, + bool include_images) = 0; }; } // namespace cc diff --git a/chromium/cc/raster/scoped_gpu_raster.cc b/chromium/cc/raster/scoped_gpu_raster.cc index f548515b698..e6dcf231ba2 100644 --- a/chromium/cc/raster/scoped_gpu_raster.cc +++ b/chromium/cc/raster/scoped_gpu_raster.cc @@ -27,7 +27,7 @@ void ScopedGpuRaster::BeginGpuRaster() { // TODO(alokp): Use a trace macro to push/pop markers. // Using push/pop functions directly incurs cost to evaluate function // arguments even when tracing is disabled. - gl->PushGroupMarkerEXT(0, "GpuRasterization"); + gl->TraceBeginCHROMIUM("ScopedGpuRaster", "GpuRasterization"); class GrContext* gr_context = context_provider_->GrContext(); gr_context->resetContext(); @@ -45,7 +45,7 @@ void ScopedGpuRaster::EndGpuRaster() { // TODO(alokp): Use a trace macro to push/pop markers. // Using push/pop functions directly incurs cost to evaluate function // arguments even when tracing is disabled. - gl->PopGroupMarkerEXT(); + gl->TraceEndCHROMIUM(); } } // namespace cc diff --git a/chromium/cc/raster/task_graph_runner.cc b/chromium/cc/raster/task_graph_runner.cc index c810aa59c0b..4fbf56e31bd 100644 --- a/chromium/cc/raster/task_graph_runner.cc +++ b/chromium/cc/raster/task_graph_runner.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "base/containers/hash_tables.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_restrictions.h" #include "base/trace_event/trace_event.h" @@ -68,34 +69,19 @@ class DependentIterator { TaskGraph::Node* current_node_; }; -class DependencyMismatchComparator { - public: - explicit DependencyMismatchComparator(const TaskGraph* graph) - : graph_(graph) {} - - bool operator()(const TaskGraph::Node& node) const { - return static_cast<size_t>(std::count_if(graph_->edges.begin(), - graph_->edges.end(), - DependentComparator(node.task))) != - node.dependencies; - } - - private: - class DependentComparator { - public: - explicit DependentComparator(const Task* dependent) - : dependent_(dependent) {} +bool DependencyMismatch(const TaskGraph* graph) { + // Value storage will be 0-initialized. + base::hash_map<const Task*, size_t> dependents; + for (const TaskGraph::Edge& edge : graph->edges) + dependents[edge.dependent]++; - bool operator()(const TaskGraph::Edge& edge) const { - return edge.dependent == dependent_; - } - - private: - const Task* dependent_; - }; + for (const TaskGraph::Node& node : graph->nodes) { + if (dependents[node.task] != node.dependencies) + return true; + } - const TaskGraph* graph_; -}; + return false; +} } // namespace @@ -171,10 +157,7 @@ void TaskGraphRunner::ScheduleTasks(NamespaceToken token, TaskGraph* graph) { graph->edges.size()); DCHECK(token.IsValid()); - DCHECK(std::find_if(graph->nodes.begin(), - graph->nodes.end(), - DependencyMismatchComparator(graph)) == - graph->nodes.end()); + DCHECK(!DependencyMismatch(graph)); { base::AutoLock lock(lock_); @@ -349,6 +332,18 @@ void TaskGraphRunner::Shutdown() { has_ready_to_run_tasks_cv_.Signal(); } +void TaskGraphRunner::FlushForTesting() { + base::AutoLock lock(lock_); + + while (std::find_if(namespaces_.begin(), namespaces_.end(), + [](const TaskNamespaceMap::value_type& entry) { + return !HasFinishedRunningTasksInNamespace( + &entry.second); + }) != namespaces_.end()) { + has_namespaces_with_finished_running_tasks_cv_.Wait(); + } +} + void TaskGraphRunner::Run() { base::AutoLock lock(lock_); diff --git a/chromium/cc/raster/task_graph_runner.h b/chromium/cc/raster/task_graph_runner.h index bb55afc19ae..d6d41917998 100644 --- a/chromium/cc/raster/task_graph_runner.h +++ b/chromium/cc/raster/task_graph_runner.h @@ -137,6 +137,9 @@ class CC_EXPORT TaskGraphRunner { // Warning: if the TaskGraphRunner remains busy, it may never quit. void Shutdown(); + // Wait for all the tasks to finish running on all the namespaces. + void FlushForTesting(); + private: struct PrioritizedTask { typedef std::vector<PrioritizedTask> Vector; diff --git a/chromium/cc/raster/tile_task_runner.cc b/chromium/cc/raster/tile_task_runner.cc index 5450c5f777e..ce568f95ab0 100644 --- a/chromium/cc/raster/tile_task_runner.cc +++ b/chromium/cc/raster/tile_task_runner.cc @@ -16,14 +16,6 @@ TileTask::~TileTask() { DCHECK(!did_run_ || did_complete_); } -ImageDecodeTask* TileTask::AsImageDecodeTask() { - return NULL; -} - -RasterTask* TileTask::AsRasterTask() { - return NULL; -} - void TileTask::WillSchedule() { DCHECK(!did_schedule_); } @@ -58,23 +50,13 @@ ImageDecodeTask::ImageDecodeTask() { ImageDecodeTask::~ImageDecodeTask() { } -ImageDecodeTask* ImageDecodeTask::AsImageDecodeTask() { - return this; -} - -RasterTask::RasterTask(const Resource* resource, - ImageDecodeTask::Vector* dependencies) - : resource_(resource) { +RasterTask::RasterTask(ImageDecodeTask::Vector* dependencies) { 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()); diff --git a/chromium/cc/raster/tile_task_runner.h b/chromium/cc/raster/tile_task_runner.h index 9dffee48c74..103da1fa275 100644 --- a/chromium/cc/raster/tile_task_runner.h +++ b/chromium/cc/raster/tile_task_runner.h @@ -36,11 +36,6 @@ class CC_EXPORT TileTask : public Task { virtual void ScheduleOnOriginThread(TileTaskClient* client) = 0; virtual void CompleteOnOriginThread(TileTaskClient* client) = 0; - virtual void RunReplyOnOriginThread() = 0; - - // Type-checking downcast routines. - virtual ImageDecodeTask* AsImageDecodeTask(); - virtual RasterTask* AsRasterTask(); void WillSchedule(); void DidSchedule(); @@ -62,9 +57,6 @@ class CC_EXPORT ImageDecodeTask : public TileTask { public: typedef std::vector<scoped_refptr<ImageDecodeTask>> Vector; - // Overridden from TileTask: - ImageDecodeTask* AsImageDecodeTask() override; - protected: ImageDecodeTask(); ~ImageDecodeTask() override; @@ -74,18 +66,13 @@ class CC_EXPORT RasterTask : public TileTask { public: typedef std::vector<scoped_refptr<RasterTask>> Vector; - // Overridden from TileTask: - RasterTask* AsRasterTask() override; - - const Resource* resource() const { return resource_; } const ImageDecodeTask::Vector& dependencies() const { return dependencies_; } protected: - RasterTask(const Resource* resource, ImageDecodeTask::Vector* dependencies); + explicit RasterTask(ImageDecodeTask::Vector* dependencies); ~RasterTask() override; private: - const Resource* resource_; ImageDecodeTask::Vector dependencies_; }; @@ -100,7 +87,6 @@ typedef std::bitset<kNumberOfTaskSets> TaskSetCollection; class CC_EXPORT TileTaskRunnerClient { public: virtual void DidFinishRunningTileTasks(TaskSet task_set) = 0; - virtual TaskSetCollection TasksThatShouldBeForcedToComplete() const = 0; protected: virtual ~TileTaskRunnerClient() {} @@ -163,10 +149,10 @@ class CC_EXPORT TileTaskRunner { virtual void CheckForCompletedTasks() = 0; // Returns the format to use for the tiles. - virtual ResourceFormat GetResourceFormat() const = 0; + virtual ResourceFormat GetResourceFormat(bool must_support_alpha) const = 0; // Determine if the resource requires swizzling. - virtual bool GetResourceRequiresSwizzle() const = 0; + virtual bool GetResourceRequiresSwizzle(bool must_support_alpha) const = 0; protected: virtual ~TileTaskRunner() {} diff --git a/chromium/cc/raster/tile_task_worker_pool.cc b/chromium/cc/raster/tile_task_worker_pool.cc index d349514c4e8..b1d7b70a229 100644 --- a/chromium/cc/raster/tile_task_worker_pool.cc +++ b/chromium/cc/raster/tile_task_worker_pool.cc @@ -10,6 +10,7 @@ #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/SkDrawFilter.h" #include "third_party/skia/include/core/SkSurface.h" namespace cc { @@ -32,7 +33,6 @@ class TaskSetFinishedTaskImpl : public TileTask { // Overridden from TileTask: void ScheduleOnOriginThread(TileTaskClient* client) override {} void CompleteOnOriginThread(TileTaskClient* client) override {} - void RunReplyOnOriginThread() override {} protected: ~TaskSetFinishedTaskImpl() override {} @@ -153,6 +153,17 @@ static bool IsSupportedPlaybackToMemoryFormat(ResourceFormat format) { return false; } +class SkipImageFilter : public SkDrawFilter { + public: + bool filter(SkPaint* paint, Type type) override { + if (type == kBitmap_Type) + return false; + + SkShader* shader = paint->getShader(); + return !shader || !shader->isABitmap(); + } +}; + // static void TileTaskWorkerPool::PlaybackToMemory(void* memory, ResourceFormat format, @@ -161,7 +172,10 @@ void TileTaskWorkerPool::PlaybackToMemory(void* memory, const RasterSource* raster_source, const gfx::Rect& canvas_bitmap_rect, const gfx::Rect& canvas_playback_rect, - float scale) { + float scale, + bool include_images) { + TRACE_EVENT0("cc", "TileTaskWorkerPool::PlaybackToMemory"); + DCHECK(IsSupportedPlaybackToMemoryFormat(format)) << format; // Uses kPremul_SkAlphaType since the result is not known to be opaque. @@ -181,10 +195,15 @@ void TileTaskWorkerPool::PlaybackToMemory(void* memory, stride = info.minRowBytes(); DCHECK_GT(stride, 0u); + skia::RefPtr<SkDrawFilter> image_filter; + if (!include_images) + image_filter = skia::AdoptRef(new SkipImageFilter); + if (!needs_copy) { skia::RefPtr<SkSurface> surface = skia::AdoptRef( SkSurface::NewRasterDirect(info, memory, stride, &surface_props)); skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas()); + canvas->setDrawFilter(image_filter.get()); raster_source->PlaybackToCanvas(canvas.get(), canvas_bitmap_rect, canvas_playback_rect, scale); return; @@ -193,19 +212,26 @@ void TileTaskWorkerPool::PlaybackToMemory(void* memory, skia::RefPtr<SkSurface> surface = skia::AdoptRef(SkSurface::NewRaster(info, &surface_props)); skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas()); + canvas->setDrawFilter(image_filter.get()); + // TODO(reveman): Improve partial raster support by reducing the size of + // playback rect passed to PlaybackToCanvas. crbug.com/519070 raster_source->PlaybackToCanvas(canvas.get(), canvas_bitmap_rect, - canvas_playback_rect, scale); - - SkImageInfo dst_info = - SkImageInfo::Make(info.width(), info.height(), buffer_color_type, - info.alphaType(), info.profileType()); - // 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); + canvas_bitmap_rect, scale); + + { + TRACE_EVENT0("cc", "TileTaskWorkerPool::PlaybackToMemory::ConvertPixels"); + + SkImageInfo dst_info = + SkImageInfo::Make(info.width(), info.height(), buffer_color_type, + info.alphaType(), info.profileType()); + // 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/raster/tile_task_worker_pool.h b/chromium/cc/raster/tile_task_worker_pool.h index ff001890507..0fc9d3f35e9 100644 --- a/chromium/cc/raster/tile_task_worker_pool.h +++ b/chromium/cc/raster/tile_task_worker_pool.h @@ -66,7 +66,8 @@ class CC_EXPORT TileTaskWorkerPool { const RasterSource* raster_source, const gfx::Rect& canvas_bitmap_rect, const gfx::Rect& canvas_playback_rect, - float scale); + float scale, + bool include_images); // Type-checking downcast routine. virtual TileTaskRunner* AsTileTaskRunner() = 0; diff --git a/chromium/cc/raster/tile_task_worker_pool_perftest.cc b/chromium/cc/raster/tile_task_worker_pool_perftest.cc index b49c498ac05..2605064799e 100644 --- a/chromium/cc/raster/tile_task_worker_pool_perftest.cc +++ b/chromium/cc/raster/tile_task_worker_pool_perftest.cc @@ -12,7 +12,6 @@ #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" @@ -114,7 +113,6 @@ class PerfContextProvider : public ContextProvider { }; 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, @@ -134,8 +132,7 @@ class PerfImageDecodeTaskImpl : public ImageDecodeTask { // Overridden from TileTask: void ScheduleOnOriginThread(TileTaskClient* client) override {} - void CompleteOnOriginThread(TileTaskClient* client) override {} - void RunReplyOnOriginThread() override { Reset(); } + void CompleteOnOriginThread(TileTaskClient* client) override { Reset(); } void Reset() { did_run_ = false; @@ -153,7 +150,7 @@ class PerfRasterTaskImpl : public RasterTask { public: PerfRasterTaskImpl(scoped_ptr<ScopedResource> resource, ImageDecodeTask::Vector* dependencies) - : RasterTask(resource.get(), dependencies), resource_(resource.Pass()) {} + : RasterTask(dependencies), resource_(resource.Pass()) {} // Overridden from Task: void RunOnWorkerThread() override {} @@ -161,12 +158,12 @@ class PerfRasterTaskImpl : public RasterTask { // Overridden from TileTask: void ScheduleOnOriginThread(TileTaskClient* client) override { // No tile ids are given to support partial updates. - raster_buffer_ = client->AcquireBufferForRaster(resource(), 0, 0); + raster_buffer_ = client->AcquireBufferForRaster(resource_.get(), 0, 0); } void CompleteOnOriginThread(TileTaskClient* client) override { client->ReleaseBufferForRaster(raster_buffer_.Pass()); + Reset(); } - void RunReplyOnOriginThread() override { Reset(); } void Reset() { did_run_ = false; @@ -250,28 +247,19 @@ class TileTaskWorkerPoolPerfTest // Overridden from testing::Test: void SetUp() override { switch (GetParam()) { - case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER: - Create3dOutputSurfaceAndResourceProvider(); - 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 TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY: Create3dOutputSurfaceAndResourceProvider(); tile_task_worker_pool_ = ZeroCopyTileTaskWorkerPool::Create( task_runner_.get(), task_graph_runner_.get(), - resource_provider_.get()); + resource_provider_.get(), false); break; case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY: Create3dOutputSurfaceAndResourceProvider(); - 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(), std::numeric_limits<int>::max(), - false); + std::numeric_limits<int>::max(), false, + std::numeric_limits<int>::max(), false); break; case TILE_TASK_WORKER_POOL_TYPE_GPU: Create3dOutputSurfaceAndResourceProvider(); @@ -299,9 +287,6 @@ class TileTaskWorkerPoolPerfTest void DidFinishRunningTileTasks(TaskSet task_set) override { tile_task_worker_pool_->AsTileTaskRunner()->CheckForCompletedTasks(); } - TaskSetCollection TasksThatShouldBeForcedToComplete() const override { - return TaskSetCollection(); - } void RunMessageLoopUntilAllTasksHaveCompleted() { task_graph_runner_->RunUntilIdle(); @@ -416,8 +401,6 @@ class TileTaskWorkerPoolPerfTest std::string TestModifierString() const { switch (GetParam()) { - 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: @@ -431,7 +414,6 @@ class TileTaskWorkerPoolPerfTest return std::string(); } - scoped_ptr<ResourcePool> staging_resource_pool_; scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_; TestGpuMemoryBufferManager gpu_memory_buffer_manager_; TestSharedBitmapManager shared_bitmap_manager_; @@ -464,14 +446,12 @@ TEST_P(TileTaskWorkerPoolPerfTest, ScheduleAndExecuteTasks) { RunScheduleAndExecuteTasksTest("32_4", 32, 4); } -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)); +INSTANTIATE_TEST_CASE_P(TileTaskWorkerPoolPerfTests, + TileTaskWorkerPoolPerfTest, + ::testing::Values(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 { diff --git a/chromium/cc/raster/tile_task_worker_pool_unittest.cc b/chromium/cc/raster/tile_task_worker_pool_unittest.cc index 76e5fe4d56f..515035bed83 100644 --- a/chromium/cc/raster/tile_task_worker_pool_unittest.cc +++ b/chromium/cc/raster/tile_task_worker_pool_unittest.cc @@ -12,22 +12,19 @@ #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/test/fake_display_list_raster_source.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/fake_resource_provider.h" #include "cc/test/test_gpu_memory_buffer_manager.h" #include "cc/test/test_shared_bitmap_manager.h" @@ -39,15 +36,10 @@ namespace cc { namespace { -const size_t kMaxTransferBufferUsageBytes = 10000U; const size_t kMaxBytesPerCopyOperation = 1000U; - -// A resource of this dimension^2 * 4 must be greater than the above transfer -// buffer constant. -const size_t kLargeResourceDimension = 1000U; +const size_t kMaxStagingBuffers = 32U; 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, @@ -62,28 +54,27 @@ class TestRasterTaskImpl : public RasterTask { TestRasterTaskImpl(const Resource* resource, const Reply& reply, ImageDecodeTask::Vector* dependencies) - : RasterTask(resource, dependencies), + : RasterTask(dependencies), + resource_(resource), reply_(reply), - picture_pile_(FakePicturePileImpl::CreateEmptyPile(gfx::Size(1, 1), - gfx::Size(1, 1))) {} + raster_source_( + FakeDisplayListRasterSource::CreateFilled(gfx::Size(1, 1))) {} // Overridden from Task: void RunOnWorkerThread() override { uint64_t new_content_id = 0; - raster_buffer_->Playback(picture_pile_.get(), gfx::Rect(1, 1), - gfx::Rect(1, 1), new_content_id, 1.f); + raster_buffer_->Playback(raster_source_.get(), gfx::Rect(1, 1), + gfx::Rect(1, 1), new_content_id, 1.f, true); } // Overridden from TileTask: void ScheduleOnOriginThread(TileTaskClient* client) override { // The raster buffer has no tile ids associated with it for partial update, // so doesn't need to provide a valid dirty rect. - raster_buffer_ = client->AcquireBufferForRaster(resource(), 0, 0); + raster_buffer_ = client->AcquireBufferForRaster(resource_, 0, 0); } void CompleteOnOriginThread(TileTaskClient* client) override { client->ReleaseBufferForRaster(raster_buffer_.Pass()); - } - void RunReplyOnOriginThread() override { reply_.Run(RasterSource::SolidColorAnalysis(), !HasFinishedRunning()); } @@ -91,9 +82,10 @@ class TestRasterTaskImpl : public RasterTask { ~TestRasterTaskImpl() override {} private: + const Resource* resource_; const Reply reply_; scoped_ptr<RasterBuffer> raster_buffer_; - scoped_refptr<PicturePileImpl> picture_pile_; + scoped_refptr<RasterSource> raster_source_; DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl); }; @@ -112,9 +104,6 @@ class BlockingTestRasterTaskImpl : public TestRasterTaskImpl { TestRasterTaskImpl::RunOnWorkerThread(); } - // Overridden from TileTask: - void RunReplyOnOriginThread() override {} - protected: ~BlockingTestRasterTaskImpl() override {} @@ -139,9 +128,10 @@ class TileTaskWorkerPoolTest TileTaskWorkerPoolTest() : context_provider_(TestContextProvider::Create()), - worker_context_provider_(TestContextProvider::Create()), + worker_context_provider_(TestContextProvider::CreateWorker()), all_tile_tasks_finished_( - base::ThreadTaskRunnerHandle::Get().get(), + base::ThreadTaskRunnerHandle::Get() + .get(), base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished, base::Unretained(this))), timeout_seconds_(5), @@ -150,27 +140,18 @@ class TileTaskWorkerPoolTest // Overridden from testing::Test: void SetUp() override { switch (GetParam()) { - case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER: - Create3dOutputSurfaceAndResourceProvider(); - tile_task_worker_pool_ = PixelBufferTileTaskWorkerPool::Create( - base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_, - context_provider_.get(), resource_provider_.get(), - kMaxTransferBufferUsageBytes); - break; case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY: Create3dOutputSurfaceAndResourceProvider(); tile_task_worker_pool_ = ZeroCopyTileTaskWorkerPool::Create( base::ThreadTaskRunnerHandle::Get().get(), &task_graph_runner_, - resource_provider_.get()); + resource_provider_.get(), false); break; case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY: Create3dOutputSurfaceAndResourceProvider(); - 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(), kMaxBytesPerCopyOperation, false); + kMaxBytesPerCopyOperation, false, kMaxStagingBuffers, false); break; case TILE_TASK_WORKER_POOL_TYPE_GPU: Create3dOutputSurfaceAndResourceProvider(); @@ -210,10 +191,6 @@ class TileTaskWorkerPoolTest } } - TaskSetCollection TasksThatShouldBeForcedToComplete() const override { - return TaskSetCollection(); - } - void RunMessageLoopUntilAllTasksHaveCompleted() { if (timeout_seconds_) { timeout_.Reset(base::Bind(&TileTaskWorkerPoolTest::OnTimeout, @@ -332,7 +309,6 @@ class TileTaskWorkerPoolTest FakeOutputSurfaceClient output_surface_client_; scoped_ptr<FakeOutputSurface> output_surface_; scoped_ptr<ResourceProvider> resource_provider_; - scoped_ptr<ResourcePool> staging_resource_pool_; scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_; TestGpuMemoryBufferManager gpu_memory_buffer_manager_; TestSharedBitmapManager shared_bitmap_manager_; @@ -397,30 +373,6 @@ TEST_P(TileTaskWorkerPoolTest, FalseThrottling) { RunMessageLoopUntilAllTasksHaveCompleted(); } -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::TEXTURE_HINT_IMMUTABLE, - RGBA_8888); - EXPECT_GE(Resource::UncheckedMemorySizeBytes(resource->size(), - resource->format()), - kMaxTransferBufferUsageBytes); - } - - AppendTask(0u, size); - AppendTask(1u, size); - AppendTask(2u, size); - ScheduleTasks(); - - // This will time out if a resource that is larger than the throttle limit - // never gets scheduled. - RunMessageLoopUntilAllTasksHaveCompleted(); -} - TEST_P(TileTaskWorkerPoolTest, LostContext) { LoseContext(output_surface_->context_provider()); LoseContext(output_surface_->worker_context_provider()); @@ -451,14 +403,12 @@ TEST_P(TileTaskWorkerPoolTest, ScheduleEmptyStillTriggersCallback) { EXPECT_TRUE(completed_task_sets_[ALL]); } -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)); +INSTANTIATE_TEST_CASE_P(TileTaskWorkerPoolTests, + TileTaskWorkerPoolTest, + ::testing::Values(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 index 64fc5f453b3..0a6e80e7d1c 100644 --- a/chromium/cc/raster/zero_copy_tile_task_worker_pool.cc +++ b/chromium/cc/raster/zero_copy_tile_task_worker_pool.cc @@ -13,6 +13,7 @@ #include "cc/raster/raster_buffer.h" #include "cc/resources/platform_color.h" #include "cc/resources/resource.h" +#include "ui/gfx/buffer_format_util.h" #include "ui/gfx/gpu_memory_buffer.h" namespace cc { @@ -29,10 +30,13 @@ class RasterBufferImpl : public RasterBuffer { const gfx::Rect& raster_full_rect, const gfx::Rect& raster_dirty_rect, uint64_t new_content_id, - float scale) override { + float scale, + bool include_images) override { gfx::GpuMemoryBuffer* gpu_memory_buffer = lock_.GetGpuMemoryBuffer(); if (!gpu_memory_buffer) return; + DCHECK_EQ( + 1u, gfx::NumberOfPlanesForBufferFormat(gpu_memory_buffer->GetFormat())); void* data = NULL; bool rv = gpu_memory_buffer->Map(&data); DCHECK(rv); @@ -44,7 +48,7 @@ class RasterBufferImpl : public RasterBuffer { TileTaskWorkerPool::PlaybackToMemory( data, resource_->format(), resource_->size(), static_cast<size_t>(stride), raster_source, raster_full_rect, - raster_full_rect, scale); + raster_full_rect, scale, include_images); gpu_memory_buffer->Unmap(); } @@ -61,21 +65,24 @@ class RasterBufferImpl : public RasterBuffer { scoped_ptr<TileTaskWorkerPool> ZeroCopyTileTaskWorkerPool::Create( base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider) { + ResourceProvider* resource_provider, + bool use_rgba_4444_texture_format) { return make_scoped_ptr<TileTaskWorkerPool>(new ZeroCopyTileTaskWorkerPool( - task_runner, task_graph_runner, resource_provider)); + task_runner, task_graph_runner, resource_provider, + use_rgba_4444_texture_format)); } ZeroCopyTileTaskWorkerPool::ZeroCopyTileTaskWorkerPool( base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider) + ResourceProvider* resource_provider, + bool use_rgba_4444_texture_format) : 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) { -} + use_rgba_4444_texture_format_(use_rgba_4444_texture_format), + task_set_finished_weak_ptr_factory_(this) {} ZeroCopyTileTaskWorkerPool::~ZeroCopyTileTaskWorkerPool() { } @@ -171,18 +178,21 @@ void ZeroCopyTileTaskWorkerPool::CheckForCompletedTasks() { task->WillComplete(); task->CompleteOnOriginThread(this); task->DidComplete(); - - task->RunReplyOnOriginThread(); } completed_tasks_.clear(); } -ResourceFormat ZeroCopyTileTaskWorkerPool::GetResourceFormat() const { - return resource_provider_->best_texture_format(); +ResourceFormat ZeroCopyTileTaskWorkerPool::GetResourceFormat( + bool must_support_alpha) const { + return use_rgba_4444_texture_format_ + ? RGBA_4444 + : resource_provider_->best_texture_format(); } -bool ZeroCopyTileTaskWorkerPool::GetResourceRequiresSwizzle() const { - return !PlatformColor::SameComponentOrder(GetResourceFormat()); +bool ZeroCopyTileTaskWorkerPool::GetResourceRequiresSwizzle( + bool must_support_alpha) const { + return !PlatformColor::SameComponentOrder( + GetResourceFormat(must_support_alpha)); } scoped_ptr<RasterBuffer> ZeroCopyTileTaskWorkerPool::AcquireBufferForRaster( diff --git a/chromium/cc/raster/zero_copy_tile_task_worker_pool.h b/chromium/cc/raster/zero_copy_tile_task_worker_pool.h index 7dcdff0a686..b1015593245 100644 --- a/chromium/cc/raster/zero_copy_tile_task_worker_pool.h +++ b/chromium/cc/raster/zero_copy_tile_task_worker_pool.h @@ -28,7 +28,8 @@ class CC_EXPORT ZeroCopyTileTaskWorkerPool : public TileTaskWorkerPool, static scoped_ptr<TileTaskWorkerPool> Create( base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider); + ResourceProvider* resource_provider, + bool use_rgba_4444_texture_format); // Overridden from TileTaskWorkerPool: TileTaskRunner* AsTileTaskRunner() override; @@ -38,8 +39,8 @@ class CC_EXPORT ZeroCopyTileTaskWorkerPool : public TileTaskWorkerPool, void Shutdown() override; void ScheduleTasks(TileTaskQueue* queue) override; void CheckForCompletedTasks() override; - ResourceFormat GetResourceFormat() const override; - bool GetResourceRequiresSwizzle() const override; + ResourceFormat GetResourceFormat(bool must_support_alpha) const override; + bool GetResourceRequiresSwizzle(bool must_support_alpha) const override; // Overridden from TileTaskClient: scoped_ptr<RasterBuffer> AcquireBufferForRaster( @@ -51,7 +52,8 @@ class CC_EXPORT ZeroCopyTileTaskWorkerPool : public TileTaskWorkerPool, protected: ZeroCopyTileTaskWorkerPool(base::SequencedTaskRunner* task_runner, TaskGraphRunner* task_graph_runner, - ResourceProvider* resource_provider); + ResourceProvider* resource_provider, + bool use_rgba_4444_texture_format); private: void OnTaskSetFinished(TaskSet task_set); @@ -64,6 +66,8 @@ class CC_EXPORT ZeroCopyTileTaskWorkerPool : public TileTaskWorkerPool, TileTaskRunnerClient* client_; ResourceProvider* resource_provider_; + bool use_rgba_4444_texture_format_; + TaskSetCollection tasks_pending_; scoped_refptr<TileTask> task_set_finished_tasks_[kNumberOfTaskSets]; diff --git a/chromium/cc/resources/resource.h b/chromium/cc/resources/resource.h index f9138fbb876..549a314d48e 100644 --- a/chromium/cc/resources/resource.h +++ b/chromium/cc/resources/resource.h @@ -5,9 +5,9 @@ #ifndef CC_RESOURCES_RESOURCE_H_ #define CC_RESOURCES_RESOURCE_H_ -#include "base/numerics/safe_math.h" #include "cc/base/cc_export.h" #include "cc/resources/resource_provider.h" +#include "cc/resources/resource_util.h" #include "ui/gfx/geometry/size.h" namespace cc { @@ -24,37 +24,6 @@ class CC_EXPORT Resource { gfx::Size size() const { return size_; } ResourceFormat format() const { return format_; } - // Return true if the call to UncheckedMemorySizeBytes would return a value - // that fits in a size_t. - static bool VerifySizeInBytes(const gfx::Size& size, ResourceFormat format) { - base::CheckedNumeric<size_t> checked_value = BitsPerPixel(format); - checked_value *= size.width(); - checked_value *= size.height(); - if (!checked_value.IsValid()) - return false; - size_t value = checked_value.ValueOrDie(); - if ((value % 8) != 0) - return false; - return true; - } - - static size_t CheckedMemorySizeBytes(const gfx::Size& size, - ResourceFormat format) { - DCHECK(VerifySizeInBytes(size, format)); - base::CheckedNumeric<size_t> checked_value = BitsPerPixel(format); - checked_value *= size.width(); - checked_value *= size.height(); - checked_value /= 8; - return checked_value.ValueOrDie(); - } - - inline static size_t UncheckedMemorySizeBytes(const gfx::Size& size, - ResourceFormat format) { - DCHECK(VerifySizeInBytes(size, format)); - return static_cast<size_t>(BitsPerPixel(format)) * size.width() * - size.height() / 8; - } - protected: void set_id(ResourceId id) { id_ = id; } void set_dimensions(const gfx::Size& size, ResourceFormat format) { diff --git a/chromium/cc/resources/resource_format.cc b/chromium/cc/resources/resource_format.cc index 45581b800f1..c62ae934d72 100644 --- a/chromium/cc/resources/resource_format.cc +++ b/chromium/cc/resources/resource_format.cc @@ -4,6 +4,9 @@ #include "cc/resources/resource_format.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" + namespace cc { SkColorType ResourceFormatToSkColorType(ResourceFormat format) { @@ -25,4 +28,82 @@ SkColorType ResourceFormatToSkColorType(ResourceFormat format) { return kN32_SkColorType; } +int BitsPerPixel(ResourceFormat 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; +} + +GLenum GLDataType(ResourceFormat format) { + DCHECK_LE(format, RESOURCE_FORMAT_MAX); + static const GLenum format_gl_data_type[] = { + 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 + }; + static_assert(arraysize(format_gl_data_type) == (RESOURCE_FORMAT_MAX + 1), + "format_gl_data_type does not handle all cases."); + + return format_gl_data_type[format]; +} + +GLenum GLDataFormat(ResourceFormat format) { + DCHECK_LE(format, RESOURCE_FORMAT_MAX); + static const GLenum format_gl_data_format[] = { + 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 + }; + static_assert(arraysize(format_gl_data_format) == (RESOURCE_FORMAT_MAX + 1), + "format_gl_data_format does not handle all cases."); + + return format_gl_data_format[format]; +} + +GLenum GLInternalFormat(ResourceFormat format) { + return GLDataFormat(format); +} + +gfx::BufferFormat BufferFormat(ResourceFormat format) { + switch (format) { + case RGBA_8888: + return gfx::BufferFormat::RGBA_8888; + case BGRA_8888: + return gfx::BufferFormat::BGRA_8888; + case RGBA_4444: + return gfx::BufferFormat::RGBA_4444; + case ALPHA_8: + case LUMINANCE_8: + case RGB_565: + case ETC1: + case RED_8: + break; + } + NOTREACHED(); + return gfx::BufferFormat::RGBA_8888; +} + } // namespace cc diff --git a/chromium/cc/resources/resource_format.h b/chromium/cc/resources/resource_format.h index d785ab7382b..79b815fcd29 100644 --- a/chromium/cc/resources/resource_format.h +++ b/chromium/cc/resources/resource_format.h @@ -6,7 +6,14 @@ #define CC_RESOURCES_RESOURCE_FORMAT_H_ #include "base/logging.h" +#include "cc/base/cc_export.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/gpu_memory_buffer.h" + +// TODO(prashant.n): Including third_party/khronos/GLES2/gl2.h causes +// redefinition errors as macros/functions defined in it conflict with +// macros/functions defined in ui/gl/gl_bindings.h. (http://crbug.com/512833). +typedef unsigned int GLenum; namespace cc { @@ -25,6 +32,12 @@ enum ResourceFormat { SkColorType ResourceFormatToSkColorType(ResourceFormat format); +CC_EXPORT int BitsPerPixel(ResourceFormat format); +CC_EXPORT GLenum GLDataType(ResourceFormat format); +CC_EXPORT GLenum GLDataFormat(ResourceFormat format); +CC_EXPORT GLenum GLInternalFormat(ResourceFormat format); +CC_EXPORT gfx::BufferFormat BufferFormat(ResourceFormat format); + } // namespace cc #endif // CC_RESOURCES_RESOURCE_FORMAT_H_ diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc index 7b65d344ab3..835c37d6c32 100644 --- a/chromium/cc/resources/resource_pool.cc +++ b/chromium/cc/resources/resource_pool.cc @@ -4,41 +4,96 @@ #include "cc/resources/resource_pool.h" +#include <algorithm> + +#include "base/format_macros.h" +#include "base/strings/stringprintf.h" +#include "base/thread_task_runner_handle.h" +#include "base/trace_event/memory_dump_manager.h" #include "cc/resources/resource_provider.h" +#include "cc/resources/resource_util.h" #include "cc/resources/scoped_resource.h" namespace cc { +namespace { + +// Delay before a resource is considered expired. +const int kResourceExpirationDelayMs = 1000; + +} // namespace + +void ResourcePool::PoolResource::OnMemoryDump( + base::trace_event::ProcessMemoryDump* pmd, + const ResourceProvider* resource_provider, + bool is_free) const { + // Resource IDs are not process-unique, so log with the ResourceProvider's + // unique id. + std::string parent_node = + base::StringPrintf("cc/resource_memory/provider_%d/resource_%d", + resource_provider->tracing_id(), id()); + + std::string dump_name = + base::StringPrintf("cc/tile_memory/provider_%d/resource_%d", + resource_provider->tracing_id(), id()); + base::trace_event::MemoryAllocatorDump* dump = + pmd->CreateAllocatorDump(dump_name); + + pmd->AddSuballocation(dump->guid(), parent_node); + + uint64_t total_bytes = + ResourceUtil::UncheckedSizeInBytesAligned<size_t>(size(), format()); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + total_bytes); -ResourcePool::ResourcePool(ResourceProvider* resource_provider, GLenum target) + if (is_free) { + dump->AddScalar("free_size", + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + total_bytes); + } +} + +ResourcePool::ResourcePool(ResourceProvider* resource_provider, + base::SingleThreadTaskRunner* task_runner, + GLenum target) : resource_provider_(resource_provider), target_(target), max_memory_usage_bytes_(0), - max_unused_memory_usage_bytes_(0), max_resource_count_(0), - memory_usage_bytes_(0), - unused_memory_usage_bytes_(0), - resource_count_(0) {} + in_use_memory_usage_bytes_(0), + total_memory_usage_bytes_(0), + total_resource_count_(0), + task_runner_(task_runner), + evict_expired_resources_pending_(false), + resource_expiration_delay_( + base::TimeDelta::FromMilliseconds(kResourceExpirationDelayMs)), + weak_ptr_factory_(this) { + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( + this, task_runner_.get()); +} ResourcePool::~ResourcePool() { + base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( + this); + + DCHECK_EQ(0u, in_use_resources_.size()); + while (!busy_resources_.empty()) { - auto const& front = busy_resources_.front(); - DidFinishUsingResource(front.resource, front.content_id); - busy_resources_.pop_front(); + DidFinishUsingResource(busy_resources_.take_front()); } - SetResourceUsageLimits(0, 0, 0); + SetResourceUsageLimits(0, 0); DCHECK_EQ(0u, unused_resources_.size()); - DCHECK_EQ(0u, memory_usage_bytes_); - DCHECK_EQ(0u, unused_memory_usage_bytes_); - DCHECK_EQ(0u, resource_count_); + DCHECK_EQ(0u, in_use_memory_usage_bytes_); + DCHECK_EQ(0u, total_memory_usage_bytes_); + DCHECK_EQ(0u, total_resource_count_); } -scoped_ptr<ScopedResource> ResourcePool::AcquireResource( - const gfx::Size& size, ResourceFormat format) { - for (ResourceList::iterator it = unused_resources_.begin(); - it != unused_resources_.end(); - ++it) { - ScopedResource* resource = it->resource; +Resource* ResourcePool::AcquireResource(const gfx::Size& size, + ResourceFormat format) { + for (ResourceDeque::iterator it = unused_resources_.begin(); + it != unused_resources_.end(); ++it) { + ScopedResource* resource = *it; DCHECK(resource_provider_->CanLockForWrite(resource->id())); if (resource->format() != format) @@ -46,53 +101,73 @@ scoped_ptr<ScopedResource> ResourcePool::AcquireResource( if (resource->size() != size) continue; - unused_resources_.erase(it); - unused_memory_usage_bytes_ -= - Resource::UncheckedMemorySizeBytes(size, format); - return make_scoped_ptr(resource); + // Transfer resource to |in_use_resources_|. + in_use_resources_.set(resource->id(), unused_resources_.take(it)); + in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( + resource->size(), resource->format()); + return resource; } - scoped_ptr<ScopedResource> resource = - ScopedResource::Create(resource_provider_); - resource->AllocateManaged(size, target_, format); + scoped_ptr<PoolResource> pool_resource = + PoolResource::Create(resource_provider_); + GLenum target = + target_ ? target_ : resource_provider_->GetImageTextureTarget(format); + pool_resource->AllocateManaged(size, target, format); + + DCHECK(ResourceUtil::VerifySizeInBytes<size_t>(pool_resource->size(), + pool_resource->format())); + total_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( + pool_resource->size(), pool_resource->format()); + ++total_resource_count_; - DCHECK(Resource::VerifySizeInBytes(resource->size(), resource->format())); - memory_usage_bytes_ += - Resource::UncheckedMemorySizeBytes(resource->size(), resource->format()); - ++resource_count_; - return resource.Pass(); + Resource* resource = pool_resource.get(); + in_use_resources_.set(resource->id(), pool_resource.Pass()); + in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( + resource->size(), resource->format()); + return resource; } -scoped_ptr<ScopedResource> ResourcePool::TryAcquireResourceWithContentId( - uint64_t content_id) { +Resource* ResourcePool::TryAcquireResourceWithContentId(uint64_t content_id) { DCHECK(content_id); auto it = std::find_if(unused_resources_.begin(), unused_resources_.end(), - [content_id](const PoolResource& pool_resource) { - return pool_resource.content_id == content_id; + [content_id](const PoolResource* pool_resource) { + return pool_resource->content_id() == content_id; }); if (it == unused_resources_.end()) return nullptr; - ScopedResource* resource = it->resource; + Resource* resource = *it; DCHECK(resource_provider_->CanLockForWrite(resource->id())); - unused_resources_.erase(it); - unused_memory_usage_bytes_ -= - Resource::UncheckedMemorySizeBytes(resource->size(), resource->format()); - return make_scoped_ptr(resource); + // Transfer resource to |in_use_resources_|. + in_use_resources_.set(resource->id(), unused_resources_.take(it)); + in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>( + resource->size(), resource->format()); + return resource; } -void ResourcePool::ReleaseResource(scoped_ptr<ScopedResource> resource, - uint64_t content_id) { - busy_resources_.push_back(PoolResource(resource.release(), content_id)); +void ResourcePool::ReleaseResource(Resource* resource, uint64_t content_id) { + auto it = in_use_resources_.find(resource->id()); + DCHECK(it != in_use_resources_.end()); + + PoolResource* pool_resource = it->second; + pool_resource->set_content_id(content_id); + pool_resource->set_last_usage(base::TimeTicks::Now()); + + // Transfer resource to |busy_resources_|. + busy_resources_.push_back(in_use_resources_.take_and_erase(it)); + in_use_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>( + pool_resource->size(), pool_resource->format()); + + // Now that we have evictable resources, schedule an eviction call for this + // resource if necessary. + ScheduleEvictExpiredResourcesIn(resource_expiration_delay_); } void ResourcePool::SetResourceUsageLimits(size_t max_memory_usage_bytes, - size_t max_unused_memory_usage_bytes, size_t max_resource_count) { max_memory_usage_bytes_ = max_memory_usage_bytes; - max_unused_memory_usage_bytes_ = max_unused_memory_usage_bytes; max_resource_count_ = max_resource_count; ReduceResourceUsage(); @@ -110,59 +185,121 @@ void ResourcePool::ReduceResourceUsage() { // can't be locked for write might also not be truly free-able. // We can free the resource here but it doesn't mean that the // memory is necessarily returned to the OS. - ScopedResource* resource = unused_resources_.front().resource; - unused_resources_.pop_front(); - unused_memory_usage_bytes_ -= Resource::UncheckedMemorySizeBytes( - resource->size(), resource->format()); - DeleteResource(resource); + DeleteResource(unused_resources_.take_front()); } } bool ResourcePool::ResourceUsageTooHigh() { - if (resource_count_ > max_resource_count_) + if (total_resource_count_ > max_resource_count_) return true; - if (memory_usage_bytes_ > max_memory_usage_bytes_) - return true; - if (unused_memory_usage_bytes_ > max_unused_memory_usage_bytes_) + if (total_memory_usage_bytes_ > max_memory_usage_bytes_) return true; return false; } -void ResourcePool::DeleteResource(ScopedResource* resource) { - size_t resource_bytes = - Resource::UncheckedMemorySizeBytes(resource->size(), resource->format()); - memory_usage_bytes_ -= resource_bytes; - --resource_count_; - delete resource; +void ResourcePool::DeleteResource(scoped_ptr<PoolResource> resource) { + size_t resource_bytes = ResourceUtil::UncheckedSizeInBytes<size_t>( + resource->size(), resource->format()); + total_memory_usage_bytes_ -= resource_bytes; + --total_resource_count_; } -void ResourcePool::CheckBusyResources(bool wait_if_needed) { - ResourceList::iterator it = busy_resources_.begin(); - - while (it != busy_resources_.end()) { - ScopedResource* resource = it->resource; - - if (wait_if_needed) - resource_provider_->WaitReadLockIfNeeded(resource->id()); +void ResourcePool::CheckBusyResources() { + for (size_t i = 0; i < busy_resources_.size();) { + ResourceDeque::iterator it(busy_resources_.begin() + i); + PoolResource* resource = *it; if (resource_provider_->CanLockForWrite(resource->id())) { - DidFinishUsingResource(resource, it->content_id); - it = busy_resources_.erase(it); + DidFinishUsingResource(busy_resources_.take(it)); } else if (resource_provider_->IsLost(resource->id())) { // Remove lost resources from pool. - DeleteResource(resource); - it = busy_resources_.erase(it); + DeleteResource(busy_resources_.take(it)); } else { - ++it; + ++i; } } } -void ResourcePool::DidFinishUsingResource(ScopedResource* resource, - uint64_t content_id) { - unused_memory_usage_bytes_ += - Resource::UncheckedMemorySizeBytes(resource->size(), resource->format()); - unused_resources_.push_back(PoolResource(resource, content_id)); +void ResourcePool::DidFinishUsingResource(scoped_ptr<PoolResource> resource) { + unused_resources_.push_back(resource.Pass()); +} + +void ResourcePool::ScheduleEvictExpiredResourcesIn( + base::TimeDelta time_from_now) { + if (evict_expired_resources_pending_) + return; + + evict_expired_resources_pending_ = true; + + task_runner_->PostDelayedTask(FROM_HERE, + base::Bind(&ResourcePool::EvictExpiredResources, + weak_ptr_factory_.GetWeakPtr()), + time_from_now); +} + +void ResourcePool::EvictExpiredResources() { + evict_expired_resources_pending_ = false; + base::TimeTicks current_time = base::TimeTicks::Now(); + + EvictResourcesNotUsedSince(current_time - resource_expiration_delay_); + + if (unused_resources_.empty() && busy_resources_.empty()) { + // Nothing is evictable. + return; + } + + // If we still have evictable resources, schedule a call to + // EvictExpiredResources at the time when the LRU buffer expires. + ScheduleEvictExpiredResourcesIn(GetUsageTimeForLRUResource() + + resource_expiration_delay_ - current_time); +} + +void ResourcePool::EvictResourcesNotUsedSince(base::TimeTicks time_limit) { + while (!unused_resources_.empty()) { + // |unused_resources_| is not strictly ordered with regards to last_usage, + // as this may not exactly line up with the time a resource became non-busy. + // However, this should be roughly ordered, and will only introduce slight + // delays in freeing expired resources. + if (unused_resources_.front()->last_usage() > time_limit) + return; + + DeleteResource(unused_resources_.take_front()); + } + + // Also free busy resources older than the delay. With a sufficiently large + // delay, such as the 1 second used here, any "busy" resources which have + // expired are not likely to be busy. Additionally, freeing a "busy" resource + // has no downside other than incorrect accounting. + while (!busy_resources_.empty()) { + if (busy_resources_.front()->last_usage() > time_limit) + return; + + DeleteResource(busy_resources_.take_front()); + } +} + +base::TimeTicks ResourcePool::GetUsageTimeForLRUResource() const { + if (!unused_resources_.empty()) { + return unused_resources_.front()->last_usage(); + } + + // This is only called when we have at least one evictable resource. + DCHECK(!busy_resources_.empty()); + return busy_resources_.front()->last_usage(); +} + +bool ResourcePool::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + for (const auto& resource : unused_resources_) { + resource->OnMemoryDump(pmd, resource_provider_, true /* is_free */); + } + for (const auto& resource : busy_resources_) { + resource->OnMemoryDump(pmd, resource_provider_, false /* is_free */); + } + for (const auto& entry : in_use_resources_) { + entry.second->OnMemoryDump(pmd, resource_provider_, false /* is_free */); + } + return true; } } // namespace cc diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h index 88816aa73d4..c1db254e052 100644 --- a/chromium/cc/resources/resource_pool.h +++ b/chromium/cc/resources/resource_pool.h @@ -7,77 +7,129 @@ #include <deque> +#include "base/containers/scoped_ptr_map.h" #include "base/memory/scoped_ptr.h" +#include "base/trace_event/memory_dump_provider.h" #include "cc/base/cc_export.h" +#include "cc/base/scoped_ptr_deque.h" #include "cc/output/renderer.h" #include "cc/resources/resource.h" #include "cc/resources/resource_format.h" +#include "cc/resources/scoped_resource.h" namespace cc { -class ScopedResource; -class CC_EXPORT ResourcePool { +class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider { public: - static scoped_ptr<ResourcePool> Create(ResourceProvider* resource_provider, - GLenum target) { - return make_scoped_ptr(new ResourcePool(resource_provider, target)); + static scoped_ptr<ResourcePool> Create( + ResourceProvider* resource_provider, + base::SingleThreadTaskRunner* task_runner) { + return make_scoped_ptr( + new ResourcePool(resource_provider, task_runner, 0 /* target */)); } - virtual ~ResourcePool(); + static scoped_ptr<ResourcePool> Create( + ResourceProvider* resource_provider, + base::SingleThreadTaskRunner* task_runner, + GLenum target) { + DCHECK_NE(0u, target); + return make_scoped_ptr( + new ResourcePool(resource_provider, task_runner, target)); + } + + ~ResourcePool() override; - scoped_ptr<ScopedResource> AcquireResource(const gfx::Size& size, - ResourceFormat format); - scoped_ptr<ScopedResource> TryAcquireResourceWithContentId(uint64 content_id); - void ReleaseResource(scoped_ptr<ScopedResource> resource, - uint64_t content_id); + Resource* AcquireResource(const gfx::Size& size, ResourceFormat format); + Resource* TryAcquireResourceWithContentId(uint64 content_id); + void ReleaseResource(Resource* resource, uint64_t content_id); void SetResourceUsageLimits(size_t max_memory_usage_bytes, - size_t max_unused_memory_usage_bytes, size_t max_resource_count); void ReduceResourceUsage(); - // This might block if |wait_if_needed| is true and one of the currently - // busy resources has a read lock fence that needs to be waited upon before - // it can be locked for write again. - void CheckBusyResources(bool wait_if_needed); - - size_t total_memory_usage_bytes() const { return memory_usage_bytes_; } - size_t acquired_memory_usage_bytes() const { - return memory_usage_bytes_ - unused_memory_usage_bytes_; + void CheckBusyResources(); + + size_t memory_usage_bytes() const { return in_use_memory_usage_bytes_; } + size_t resource_count() const { return in_use_resources_.size(); } + + // Overridden from base::trace_event::MemoryDumpProvider: + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) override; + + size_t GetTotalMemoryUsageForTesting() const { + return total_memory_usage_bytes_; + } + size_t GetTotalResourceCountForTesting() const { + return total_resource_count_; } - size_t total_resource_count() const { return resource_count_; } - size_t acquired_resource_count() const { - return resource_count_ - unused_resources_.size(); + size_t GetBusyResourceCountForTesting() const { + return busy_resources_.size(); + } + void SetResourceExpirationDelayForTesting(base::TimeDelta delay) { + resource_expiration_delay_ = delay; } - size_t busy_resource_count() const { return busy_resources_.size(); } protected: - ResourcePool(ResourceProvider* resource_provider, GLenum target); + ResourcePool(ResourceProvider* resource_provider, + base::SingleThreadTaskRunner* task_runner, + GLenum target); bool ResourceUsageTooHigh(); private: - void DidFinishUsingResource(ScopedResource* resource, uint64_t content_id); - void DeleteResource(ScopedResource* resource); + class PoolResource : public ScopedResource { + public: + static scoped_ptr<PoolResource> Create( + ResourceProvider* resource_provider) { + return make_scoped_ptr(new PoolResource(resource_provider)); + } + void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, + const ResourceProvider* resource_provider, + bool is_free) const; + + uint64_t content_id() const { return content_id_; } + void set_content_id(uint64_t content_id) { content_id_ = content_id; } + + base::TimeTicks last_usage() const { return last_usage_; } + void set_last_usage(base::TimeTicks time) { last_usage_ = time; } + + private: + explicit PoolResource(ResourceProvider* resource_provider) + : ScopedResource(resource_provider), content_id_(0) {} + uint64_t content_id_; + base::TimeTicks last_usage_; + }; + + void DidFinishUsingResource(scoped_ptr<PoolResource> resource); + void DeleteResource(scoped_ptr<PoolResource> resource); + + // Functions which manage periodic eviction of expired resources. + void ScheduleEvictExpiredResourcesIn(base::TimeDelta time_from_now); + void EvictExpiredResources(); + void EvictResourcesNotUsedSince(base::TimeTicks time_limit); + bool HasEvictableResources() const; + base::TimeTicks GetUsageTimeForLRUResource() const; ResourceProvider* resource_provider_; const GLenum target_; size_t max_memory_usage_bytes_; - size_t max_unused_memory_usage_bytes_; size_t max_resource_count_; - size_t memory_usage_bytes_; - size_t unused_memory_usage_bytes_; - size_t resource_count_; - - struct PoolResource { - PoolResource(ScopedResource* resource, uint64_t content_id) - : resource(resource), content_id(content_id) {} - ScopedResource* resource; - uint64_t content_id; - }; - typedef std::deque<PoolResource> ResourceList; - ResourceList unused_resources_; - ResourceList busy_resources_; + size_t in_use_memory_usage_bytes_; + size_t total_memory_usage_bytes_; + size_t total_resource_count_; + + using ResourceDeque = ScopedPtrDeque<PoolResource>; + ResourceDeque unused_resources_; + ResourceDeque busy_resources_; + + using ResourceMap = base::ScopedPtrMap<ResourceId, scoped_ptr<PoolResource>>; + ResourceMap in_use_resources_; + + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + bool evict_expired_resources_pending_; + base::TimeDelta resource_expiration_delay_; + + base::WeakPtrFactory<ResourcePool> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ResourcePool); }; diff --git a/chromium/cc/resources/resource_pool_unittest.cc b/chromium/cc/resources/resource_pool_unittest.cc index 96e7591ab8c..bde9d748b7e 100644 --- a/chromium/cc/resources/resource_pool_unittest.cc +++ b/chromium/cc/resources/resource_pool_unittest.cc @@ -4,6 +4,9 @@ #include "cc/resources/resource_pool.h" +#include "base/run_loop.h" +#include "base/thread_task_runner_handle.h" +#include "cc/resources/resource_util.h" #include "cc/resources/scoped_resource.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" @@ -22,8 +25,9 @@ class ResourcePoolTest : public testing::Test { shared_bitmap_manager_.reset(new TestSharedBitmapManager()); resource_provider_ = FakeResourceProvider::Create( output_surface_.get(), shared_bitmap_manager_.get()); - resource_pool_ = - ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D); + task_runner_ = base::ThreadTaskRunnerHandle::Get(); + resource_pool_ = ResourcePool::Create(resource_provider_.get(), + task_runner_.get(), GL_TEXTURE_2D); } protected: @@ -31,89 +35,86 @@ class ResourcePoolTest : public testing::Test { scoped_ptr<FakeOutputSurface> output_surface_; scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; scoped_ptr<ResourceProvider> resource_provider_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; scoped_ptr<ResourcePool> resource_pool_; }; TEST_F(ResourcePoolTest, AcquireRelease) { gfx::Size size(100, 100); ResourceFormat format = RGBA_8888; - scoped_ptr<ScopedResource> resource = - resource_pool_->AcquireResource(size, format); + Resource* resource = resource_pool_->AcquireResource(size, format); EXPECT_EQ(size, resource->size()); EXPECT_EQ(format, resource->format()); EXPECT_TRUE(resource_provider_->CanLockForWrite(resource->id())); - resource_pool_->ReleaseResource(resource.Pass(), 0u); + resource_pool_->ReleaseResource(resource, 0u); } TEST_F(ResourcePoolTest, AccountingSingleResource) { // Limits high enough to not be hit by this test. size_t bytes_limit = 10 * 1024 * 1024; size_t count_limit = 100; - resource_pool_->SetResourceUsageLimits(bytes_limit, bytes_limit, count_limit); + resource_pool_->SetResourceUsageLimits(bytes_limit, count_limit); gfx::Size size(100, 100); ResourceFormat format = RGBA_8888; - size_t resource_bytes = Resource::UncheckedMemorySizeBytes(size, format); - scoped_ptr<ScopedResource> resource = - resource_pool_->AcquireResource(size, format); - - EXPECT_EQ(resource_bytes, resource_pool_->total_memory_usage_bytes()); - EXPECT_EQ(resource_bytes, resource_pool_->acquired_memory_usage_bytes()); - EXPECT_EQ(1u, resource_pool_->total_resource_count()); - EXPECT_EQ(1u, resource_pool_->acquired_resource_count()); - EXPECT_EQ(0u, resource_pool_->busy_resource_count()); - - resource_pool_->ReleaseResource(resource.Pass(), 0u); - EXPECT_EQ(resource_bytes, resource_pool_->total_memory_usage_bytes()); - EXPECT_EQ(1u, resource_pool_->total_resource_count()); - EXPECT_EQ(1u, resource_pool_->busy_resource_count()); - - bool wait_if_needed = false; - resource_pool_->CheckBusyResources(wait_if_needed); - EXPECT_EQ(resource_bytes, resource_pool_->total_memory_usage_bytes()); - EXPECT_EQ(0u, resource_pool_->acquired_memory_usage_bytes()); - EXPECT_EQ(1u, resource_pool_->total_resource_count()); - EXPECT_EQ(0u, resource_pool_->acquired_resource_count()); - EXPECT_EQ(0u, resource_pool_->busy_resource_count()); - - resource_pool_->SetResourceUsageLimits(0u, 0u, 0u); + size_t resource_bytes = + ResourceUtil::UncheckedSizeInBytes<size_t>(size, format); + Resource* resource = resource_pool_->AcquireResource(size, format); + + EXPECT_EQ(resource_bytes, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(resource_bytes, resource_pool_->memory_usage_bytes()); + EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); + EXPECT_EQ(1u, resource_pool_->resource_count()); + EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting()); + + resource_pool_->ReleaseResource(resource, 0u); + EXPECT_EQ(resource_bytes, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); + EXPECT_EQ(1u, resource_pool_->GetBusyResourceCountForTesting()); + + resource_pool_->CheckBusyResources(); + EXPECT_EQ(resource_bytes, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(0u, resource_pool_->memory_usage_bytes()); + EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); + EXPECT_EQ(0u, resource_pool_->resource_count()); + EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting()); + + resource_pool_->SetResourceUsageLimits(0u, 0u); resource_pool_->ReduceResourceUsage(); - EXPECT_EQ(0u, resource_pool_->total_memory_usage_bytes()); - EXPECT_EQ(0u, resource_pool_->acquired_memory_usage_bytes()); - EXPECT_EQ(0u, resource_pool_->total_resource_count()); - EXPECT_EQ(0u, resource_pool_->acquired_resource_count()); - EXPECT_EQ(0u, resource_pool_->busy_resource_count()); + EXPECT_EQ(0u, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(0u, resource_pool_->memory_usage_bytes()); + EXPECT_EQ(0u, resource_pool_->GetTotalResourceCountForTesting()); + EXPECT_EQ(0u, resource_pool_->resource_count()); + EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting()); } TEST_F(ResourcePoolTest, SimpleResourceReuse) { // Limits high enough to not be hit by this test. size_t bytes_limit = 10 * 1024 * 1024; size_t count_limit = 100; - resource_pool_->SetResourceUsageLimits(bytes_limit, bytes_limit, count_limit); + resource_pool_->SetResourceUsageLimits(bytes_limit, count_limit); gfx::Size size(100, 100); ResourceFormat format = RGBA_8888; - bool wait_if_needed = false; - scoped_ptr<ScopedResource> resource = - resource_pool_->AcquireResource(size, format); - resource_pool_->ReleaseResource(resource.Pass(), 0u); - resource_pool_->CheckBusyResources(wait_if_needed); + Resource* resource = resource_pool_->AcquireResource(size, format); + resource_pool_->ReleaseResource(resource, 0u); + resource_pool_->CheckBusyResources(); EXPECT_EQ(1u, resource_provider_->num_resources()); // Same size/format should re-use resource. resource = resource_pool_->AcquireResource(size, format); EXPECT_EQ(1u, resource_provider_->num_resources()); - resource_pool_->ReleaseResource(resource.Pass(), 0u); - resource_pool_->CheckBusyResources(wait_if_needed); + resource_pool_->ReleaseResource(resource, 0u); + resource_pool_->CheckBusyResources(); EXPECT_EQ(1u, resource_provider_->num_resources()); // Different size/format should alloate new resource. resource = resource_pool_->AcquireResource(gfx::Size(50, 50), LUMINANCE_8); EXPECT_EQ(2u, resource_provider_->num_resources()); - resource_pool_->ReleaseResource(resource.Pass(), 0u); - resource_pool_->CheckBusyResources(wait_if_needed); + resource_pool_->ReleaseResource(resource, 0u); + resource_pool_->CheckBusyResources(); EXPECT_EQ(2u, resource_provider_->num_resources()); } @@ -121,21 +122,101 @@ TEST_F(ResourcePoolTest, LostResource) { // Limits high enough to not be hit by this test. size_t bytes_limit = 10 * 1024 * 1024; size_t count_limit = 100; - resource_pool_->SetResourceUsageLimits(bytes_limit, bytes_limit, count_limit); + resource_pool_->SetResourceUsageLimits(bytes_limit, count_limit); gfx::Size size(100, 100); ResourceFormat format = RGBA_8888; - bool wait_if_needed = false; - scoped_ptr<ScopedResource> resource = - resource_pool_->AcquireResource(size, format); + Resource* resource = resource_pool_->AcquireResource(size, format); EXPECT_EQ(1u, resource_provider_->num_resources()); resource_provider_->LoseResourceForTesting(resource->id()); - resource_pool_->ReleaseResource(resource.Pass(), 0u); - resource_pool_->CheckBusyResources(wait_if_needed); + resource_pool_->ReleaseResource(resource, 0u); + resource_pool_->CheckBusyResources(); EXPECT_EQ(0u, resource_provider_->num_resources()); } +TEST_F(ResourcePoolTest, BusyResourcesEventuallyFreed) { + // Limits high enough to not be hit by this test. + size_t bytes_limit = 10 * 1024 * 1024; + size_t count_limit = 100; + resource_pool_->SetResourceUsageLimits(bytes_limit, count_limit); + + // Set a quick resource expiration delay so that this test doesn't take long + // to run. + resource_pool_->SetResourceExpirationDelayForTesting( + base::TimeDelta::FromMilliseconds(10)); + + gfx::Size size(100, 100); + ResourceFormat format = RGBA_8888; + + Resource* resource = resource_pool_->AcquireResource(size, format); + EXPECT_EQ(1u, resource_provider_->num_resources()); + EXPECT_EQ(40000u, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(1u, resource_pool_->resource_count()); + + resource_pool_->ReleaseResource(resource, 0u); + EXPECT_EQ(1u, resource_provider_->num_resources()); + EXPECT_EQ(40000u, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(0u, resource_pool_->memory_usage_bytes()); + EXPECT_EQ(1u, resource_pool_->GetBusyResourceCountForTesting()); + + // Wait for our resource pool to evict resources. We expect resources to be + // released within 10 ms, give the thread up to 200. + base::RunLoop run_loop; + task_runner_->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), + base::TimeDelta::FromMillisecondsD(200)); + run_loop.Run(); + + EXPECT_EQ(0u, resource_provider_->num_resources()); + EXPECT_EQ(0u, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(0u, resource_pool_->memory_usage_bytes()); +} + +TEST_F(ResourcePoolTest, UnusedResourcesEventuallyFreed) { + // Limits high enough to not be hit by this test. + size_t bytes_limit = 10 * 1024 * 1024; + size_t count_limit = 100; + resource_pool_->SetResourceUsageLimits(bytes_limit, count_limit); + + // Set a quick resource expiration delay so that this test doesn't take long + // to run. + resource_pool_->SetResourceExpirationDelayForTesting( + base::TimeDelta::FromMilliseconds(100)); + + gfx::Size size(100, 100); + ResourceFormat format = RGBA_8888; + + Resource* resource = resource_pool_->AcquireResource(size, format); + EXPECT_EQ(1u, resource_provider_->num_resources()); + EXPECT_EQ(40000u, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); + EXPECT_EQ(1u, resource_pool_->resource_count()); + + resource_pool_->ReleaseResource(resource, 0u); + EXPECT_EQ(1u, resource_provider_->num_resources()); + EXPECT_EQ(40000u, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); + EXPECT_EQ(1u, resource_pool_->GetBusyResourceCountForTesting()); + + // Transfer the resource from the busy pool to the unused pool. + resource_pool_->CheckBusyResources(); + EXPECT_EQ(1u, resource_provider_->num_resources()); + EXPECT_EQ(40000u, resource_pool_->GetTotalMemoryUsageForTesting()); + EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting()); + EXPECT_EQ(0u, resource_pool_->resource_count()); + EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting()); + + // Wait for our resource pool to evict resources. We expect resources to be + // released within 100 ms, give the thread up to 200. + base::RunLoop run_loop; + task_runner_->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), + base::TimeDelta::FromMillisecondsD(200)); + run_loop.Run(); + + EXPECT_EQ(0u, resource_provider_->num_resources()); + EXPECT_EQ(0u, resource_pool_->GetTotalMemoryUsageForTesting()); +} + } // namespace } // namespace cc diff --git a/chromium/cc/resources/resource_provider.cc b/chromium/cc/resources/resource_provider.cc index 9f680669c08..083b4868a5d 100644 --- a/chromium/cc/resources/resource_provider.cc +++ b/chromium/cc/resources/resource_provider.cc @@ -7,19 +7,24 @@ #include <algorithm> #include <limits> +#include "base/atomic_sequence_num.h" #include "base/containers/hash_tables.h" #include "base/metrics/histogram.h" #include "base/numerics/safe_math.h" #include "base/stl_util.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/thread_task_runner_handle.h" +#include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/trace_event.h" -#include "cc/base/math_util.h" #include "cc/resources/platform_color.h" +#include "cc/resources/resource_util.h" #include "cc/resources/returned_resource.h" #include "cc/resources/shared_bitmap_manager.h" #include "cc/resources/transferable_resource.h" #include "gpu/GLES2/gl2extchromium.h" +#include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" #include "third_party/khronos/GLES2/gl2.h" @@ -29,7 +34,7 @@ #include "third_party/skia/include/gpu/GrTextureProvider.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/vector2d.h" -#include "ui/gfx/gpu_memory_buffer.h" +#include "ui/gl/trace_util.h" using gpu::gles2::GLES2Interface; @@ -113,25 +118,6 @@ GrPixelConfig ToGrPixelConfig(ResourceFormat format) { return kSkia8888_GrPixelConfig; } -gfx::GpuMemoryBuffer::Format ToGpuMemoryBufferFormat(ResourceFormat format) { - switch (format) { - case RGBA_8888: - return gfx::GpuMemoryBuffer::RGBA_8888; - case BGRA_8888: - return gfx::GpuMemoryBuffer::BGRA_8888; - case RGBA_4444: - return gfx::GpuMemoryBuffer::RGBA_4444; - case ALPHA_8: - case LUMINANCE_8: - case RGB_565: - case ETC1: - case RED_8: - break; - } - NOTREACHED(); - return gfx::GpuMemoryBuffer::RGBA_8888; -} - class ScopedSetActiveTexture { public: ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit) @@ -202,45 +188,9 @@ class BufferIdAllocator : public IdAllocator { DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator); }; -// 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: - CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id) - : gl_(gl), query_id_(query_id) {} - - // Overridden from ResourceProvider::Fence: - void Set() override {} - bool HasPassed() override { - unsigned available = 1; - gl_->GetQueryObjectuivEXT( - query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available); - if (!available) - return false; - - ProcessResult(); - return true; - } - void Wait() override { - // ProcessResult() will wait for result to become available. - ProcessResult(); - } - - private: - ~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(CopyTextureFence); -}; +// Generates process-unique IDs to use for tracing a ResourceProvider's +// resources. +base::StaticAtomicSequenceNumber g_next_resource_provider_tracing_id; } // namespace @@ -268,8 +218,6 @@ ResourceProvider::Resource::Resource(GLuint texture_id, 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), @@ -311,8 +259,6 @@ ResourceProvider::Resource::Resource(uint8_t* pixels, 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(!!bitmap), @@ -355,8 +301,6 @@ ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id, 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(true), @@ -391,19 +335,20 @@ scoped_ptr<ResourceProvider> ResourceProvider::Create( gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, BlockingTaskRunner* blocking_main_thread_task_runner, int highp_threshold_min, - bool use_rgba_4444_texture_format, size_t id_allocation_chunk_size, - bool use_persistent_map_for_gpu_memory_buffers) { + const std::vector<unsigned>& use_image_texture_targets) { 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, - use_persistent_map_for_gpu_memory_buffers)); + id_allocation_chunk_size, use_image_texture_targets)); resource_provider->Initialize(); return resource_provider; } ResourceProvider::~ResourceProvider() { + base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( + this); + while (!children_.empty()) DestroyChildInternal(children_.begin(), FOR_SHUTDOWN); while (!resources_.empty()) @@ -593,7 +538,7 @@ void ResourceProvider::DeleteResource(ResourceId id) { Resource* resource = &it->second; DCHECK(!resource->marked_for_deletion); DCHECK_EQ(resource->imported_count, 0); - DCHECK(resource->pending_set_pixels || !resource->locked_for_write); + DCHECK(!resource->locked_for_write); if (resource->exported_count > 0 || resource->lock_for_read_count > 0 || !ReadLockFenceHasPassed(resource)) { @@ -717,20 +662,16 @@ void ResourceProvider::CopyToResource(ResourceId id, 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); gl->BindTexture(GL_TEXTURE_2D, resource->gl_id); if (resource->format == ETC1) { - base::CheckedNumeric<int> num_bytes = BitsPerPixel(ETC1); - num_bytes *= image_size.width(); - num_bytes *= image_size.height(); - num_bytes /= 8; + int image_bytes = ResourceUtil::CheckedSizeInBytes<int>(image_size, ETC1); gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1), image_size.width(), image_size.height(), 0, - num_bytes.ValueOrDie(), image); + image_bytes, image); } else { gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(), image_size.height(), GLDataFormat(resource->format), @@ -758,10 +699,8 @@ ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) { const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) { Resource* resource = GetResource(id); - DCHECK(!resource->locked_for_write || - resource->set_pixels_completion_forced) << - "locked for write: " << resource->locked_for_write << - " pixels completion forced: " << resource->set_pixels_completion_forced; + DCHECK(!resource->locked_for_write) << "locked for write: " + << resource->locked_for_write; DCHECK_EQ(resource->exported_count, 0); // Uninitialized! Call SetPixels or LockForWrite first. DCHECK(resource->allocated); @@ -989,13 +928,9 @@ gfx::GpuMemoryBuffer* ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() { if (gpu_memory_buffer_) return gpu_memory_buffer_; - gfx::GpuMemoryBuffer::Usage usage = - resource_provider_->use_persistent_map_for_gpu_memory_buffers() - ? gfx::GpuMemoryBuffer::PERSISTENT_MAP - : gfx::GpuMemoryBuffer::MAP; scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer = gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer( - size_, ToGpuMemoryBufferFormat(format_), usage); + size_, BufferFormat(format_), gfx::BufferUsage::MAP); gpu_memory_buffer_ = gpu_memory_buffer.release(); return gpu_memory_buffer_; } @@ -1085,9 +1020,8 @@ ResourceProvider::ResourceProvider( gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, BlockingTaskRunner* blocking_main_thread_task_runner, int highp_threshold_min, - bool use_rgba_4444_texture_format, size_t id_allocation_chunk_size, - bool use_persistent_map_for_gpu_memory_buffers) + const std::vector<unsigned>& use_image_texture_targets) : output_surface_(output_surface), shared_bitmap_manager_(shared_bitmap_manager), gpu_memory_buffer_manager_(gpu_memory_buffer_manager), @@ -1105,11 +1039,10 @@ ResourceProvider::ResourceProvider( max_texture_size_(0), best_texture_format_(RGBA_8888), best_render_buffer_format_(RGBA_8888), - use_rgba_4444_texture_format_(use_rgba_4444_texture_format), id_allocation_chunk_size_(id_allocation_chunk_size), use_sync_query_(false), - use_persistent_map_for_gpu_memory_buffers_( - use_persistent_map_for_gpu_memory_buffers) { + use_image_texture_targets_(use_image_texture_targets), + tracing_id_(g_next_resource_provider_tracing_id.GetNext()) { DCHECK(output_surface_->HasClient()); DCHECK(id_allocation_chunk_size_); } @@ -1117,6 +1050,14 @@ ResourceProvider::ResourceProvider( void ResourceProvider::Initialize() { DCHECK(thread_checker_.CalledOnValidThread()); + // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview). + // Don't register a dump provider in these cases. + // TODO(ericrk): Get this working in Android Webview. crbug.com/517156 + if (base::ThreadTaskRunnerHandle::IsSet()) { + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( + this, base::ThreadTaskRunnerHandle::Get()); + } + GLES2Interface* gl = ContextGL(); if (!gl) { default_resource_type_ = RESOURCE_TYPE_BITMAP; @@ -1514,108 +1455,6 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( } } -void ResourceProvider::AcquirePixelBuffer(ResourceId id) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "ResourceProvider::AcquirePixelBuffer"); - - Resource* resource = GetResource(id); - DCHECK(resource->origin == Resource::INTERNAL); - DCHECK_EQ(resource->exported_count, 0); - DCHECK(!resource->image_id); - DCHECK_NE(ETC1, resource->format); - - DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - if (!resource->gl_pixel_buffer_id) - resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId(); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); - unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8; - gl->BufferData( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->size.height() * - MathUtil::RoundUp(bytes_per_pixel * resource->size.width(), 4u), - NULL, GL_DYNAMIC_DRAW); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); -} - -void ResourceProvider::ReleasePixelBuffer(ResourceId id) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "ResourceProvider::ReleasePixelBuffer"); - - Resource* resource = GetResource(id); - DCHECK(resource->origin == Resource::INTERNAL); - DCHECK_EQ(resource->exported_count, 0); - DCHECK(!resource->image_id); - - // The pixel buffer can be released while there is a pending "set pixels" - // if completion has been forced. Any shared memory associated with this - // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM - // command has been processed on the service side. It is also safe to - // reuse any query id associated with this resource before they complete - // as each new query has a unique submit count. - if (resource->pending_set_pixels) { - DCHECK(resource->set_pixels_completion_forced); - resource->pending_set_pixels = false; - resource->locked_for_write = false; - } - - DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); - if (!resource->gl_pixel_buffer_id) - return; - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); - gl->BufferData( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); -} - -uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "ResourceProvider::MapPixelBuffer"); - - Resource* resource = GetResource(id); - DCHECK(resource->origin == Resource::INTERNAL); - DCHECK_EQ(resource->exported_count, 0); - DCHECK(!resource->image_id); - - *stride = 0; - DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - DCHECK(resource->gl_pixel_buffer_id); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); - uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM( - GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY)); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); - // Buffer is required to be 4-byte aligned. - CHECK(!(reinterpret_cast<intptr_t>(image) & 3)); - return image; -} - -void ResourceProvider::UnmapPixelBuffer(ResourceId id) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "ResourceProvider::UnmapPixelBuffer"); - - Resource* resource = GetResource(id); - DCHECK(resource->origin == Resource::INTERNAL); - DCHECK_EQ(resource->exported_count, 0); - DCHECK(!resource->image_id); - - DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - DCHECK(resource->gl_pixel_buffer_id); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); - gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); -} - GLenum ResourceProvider::BindForSampling(ResourceId resource_id, GLenum unit, GLenum filter) { @@ -1625,7 +1464,7 @@ GLenum ResourceProvider::BindForSampling(ResourceId resource_id, DCHECK(it != resources_.end()); Resource* resource = &it->second; DCHECK(resource->lock_for_read_count); - DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced); + DCHECK(!resource->locked_for_write); ScopedSetActiveTexture scoped_active_tex(gl, unit); GLenum target = resource->target; @@ -1642,115 +1481,6 @@ GLenum ResourceProvider::BindForSampling(ResourceId resource_id, return target; } -void ResourceProvider::BeginSetPixels(ResourceId id) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "ResourceProvider::BeginSetPixels"); - - Resource* resource = GetResource(id); - DCHECK(!resource->pending_set_pixels); - - LazyCreate(resource); - DCHECK(resource->origin == Resource::INTERNAL); - DCHECK(resource->gl_id || resource->allocated); - DCHECK(ReadLockFenceHasPassed(resource)); - DCHECK(!resource->image_id); - - bool allocate = !resource->allocated; - resource->allocated = true; - LockForWrite(id); - - DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); - DCHECK(resource->gl_id); - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - DCHECK(resource->gl_pixel_buffer_id); - DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); - gl->BindTexture(GL_TEXTURE_2D, resource->gl_id); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, - resource->gl_pixel_buffer_id); - if (!resource->gl_upload_query_id) - gl->GenQueriesEXT(1, &resource->gl_upload_query_id); - gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM, - resource->gl_upload_query_id); - if (allocate) { - gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D, - 0, /* level */ - GLInternalFormat(resource->format), - resource->size.width(), - resource->size.height(), - 0, /* border */ - GLDataFormat(resource->format), - GLDataType(resource->format), - NULL); - } else { - gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D, - 0, /* level */ - 0, /* x */ - 0, /* y */ - resource->size.width(), - resource->size.height(), - GLDataFormat(resource->format), - GLDataType(resource->format), - NULL); - } - gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM); - gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); - - resource->pending_set_pixels = true; - resource->set_pixels_completion_forced = false; -} - -void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "ResourceProvider::ForceSetPixelsToComplete"); - - Resource* resource = GetResource(id); - - DCHECK(resource->locked_for_write); - DCHECK(resource->pending_set_pixels); - DCHECK(!resource->set_pixels_completion_forced); - - if (resource->gl_id) { - GLES2Interface* gl = ContextGL(); - 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; -} - -bool ResourceProvider::DidSetPixelsComplete(ResourceId id) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "ResourceProvider::DidSetPixelsComplete"); - - Resource* resource = GetResource(id); - - DCHECK(resource->locked_for_write); - DCHECK(resource->pending_set_pixels); - - if (resource->gl_id) { - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - DCHECK(resource->gl_upload_query_id); - GLuint complete = 1; - gl->GetQueryObjectuivEXT( - resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete); - if (!complete) - return false; - } - - resource->pending_set_pixels = false; - UnlockForWrite(resource); - - // Async set pixels commands are not necessarily processed in-sequence with - // drawing commands. Read lock fences are required to ensure that async - // commands don't access the resource while used for drawing. - resource->read_lock_fences_enabled = true; - - return true; -} - void ResourceProvider::CreateForTesting(ResourceId id) { LazyCreate(GetResource(id)); } @@ -1837,79 +1567,6 @@ void ResourceProvider::BindImageForSampling(Resource* resource) { resource->dirty_image = false; } -void ResourceProvider::CopyResource(ResourceId source_id, - ResourceId dest_id, - const gfx::Rect& rect) { - TRACE_EVENT0("cc", "ResourceProvider::CopyResource"); - - Resource* source_resource = GetResource(source_id); - DCHECK(!source_resource->lock_for_read_count); - DCHECK(source_resource->origin == Resource::INTERNAL); - DCHECK_EQ(source_resource->exported_count, 0); - DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type); - LazyAllocate(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_EQ(dest_resource->exported_count, 0); - 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); - DCHECK(source_resource->size == dest_resource->size); - DCHECK(gfx::Rect(dest_resource->size).Contains(rect)); - - GLES2Interface* gl = ContextGL(); - DCHECK(gl); - if (source_resource->image_id && source_resource->dirty_image) { - gl->BindTexture(source_resource->target, source_resource->gl_id); - BindImageForSampling(source_resource); - } - 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->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id, - dest_resource->gl_id, rect.x(), rect.y(), rect.x(), - rect.y(), rect.width(), rect.height(), - false, false, false); - if (source_resource->gl_read_lock_query_id) { - // End query and create a read lock fence that will prevent access to -// 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 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 - // possible as that reduce the number of times we have to synchronize with - // the GL. - if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized()) - synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl)); - source_resource->read_lock_fence = synchronous_fence_; - source_resource->read_lock_fence->Set(); - } -} - void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) { Resource* resource = GetResource(id); DCHECK_EQ(resource->exported_count, 0); @@ -1925,21 +1582,19 @@ void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) { resource->mailbox.set_sync_point(0); } -void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) { - Resource* resource = GetResource(id); - DCHECK_EQ(resource->exported_count, 0); - if (!resource->read_lock_fence.get()) - return; - - resource->read_lock_fence->Wait(); -} - GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) { GLint active_unit = 0; gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit); return active_unit; } +GLenum ResourceProvider::GetImageTextureTarget(ResourceFormat format) { + gfx::BufferFormat buffer_format = BufferFormat(format); + DCHECK_GT(use_image_texture_targets_.size(), + static_cast<size_t>(buffer_format)); + return use_image_texture_targets_[static_cast<size_t>(buffer_format)]; +} + void ResourceProvider::ValidateResource(ResourceId id) const { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(id); @@ -1958,4 +1613,57 @@ class GrContext* ResourceProvider::GrContext(bool worker_context) const { return context_provider ? context_provider->GrContext() : NULL; } +bool ResourceProvider::OnMemoryDump( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + DCHECK(thread_checker_.CalledOnValidThread()); + + const uint64 tracing_process_id = + base::trace_event::MemoryDumpManager::GetInstance() + ->GetTracingProcessId(); + + for (const auto& resource_entry : resources_) { + const auto& resource = resource_entry.second; + + // Resource IDs are not process-unique, so log with the ResourceProvider's + // unique id. + std::string dump_name = + base::StringPrintf("cc/resource_memory/provider_%d/resource_%d", + tracing_id_, resource_entry.first); + base::trace_event::MemoryAllocatorDump* dump = + pmd->CreateAllocatorDump(dump_name); + + uint64_t total_bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>( + resource.size, resource.format); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + static_cast<uint64_t>(total_bytes)); + + // Resources which are shared across processes require a shared GUID to + // prevent double counting the memory. We currently support shared GUIDs for + // GpuMemoryBuffer, SharedBitmap, and GL backed resources. + base::trace_event::MemoryAllocatorDumpGuid guid; + if (resource.gpu_memory_buffer) { + guid = gfx::GetGpuMemoryBufferGUIDForTracing( + tracing_process_id, resource.gpu_memory_buffer->GetHandle().id); + } else if (resource.shared_bitmap) { + guid = GetSharedBitmapGUIDForTracing(resource.shared_bitmap->id()); + } else if (resource.gl_id && resource.allocated) { + guid = gfx::GetGLTextureClientGUIDForTracing( + output_surface_->context_provider() + ->ContextSupport() + ->ShareGroupTracingGUID(), + resource.gl_id); + } + + if (!guid.empty()) { + const int kImportance = 2; + pmd->CreateSharedGlobalAllocatorDump(guid); + pmd->AddOwnershipEdge(dump->guid(), guid, kImportance); + } + } + + return true; +} + } // namespace cc diff --git a/chromium/cc/resources/resource_provider.h b/chromium/cc/resources/resource_provider.h index fbed140aa00..4af135eab57 100644 --- a/chromium/cc/resources/resource_provider.h +++ b/chromium/cc/resources/resource_provider.h @@ -17,6 +17,8 @@ #include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" #include "base/threading/thread_checker.h" +#include "base/trace_event/memory_allocator_dump.h" +#include "base/trace_event/memory_dump_provider.h" #include "cc/base/cc_export.h" #include "cc/base/resource_id.h" #include "cc/output/context_provider.h" @@ -33,6 +35,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/gpu_memory_buffer.h" class GrContext; @@ -44,7 +47,6 @@ class GLES2Interface; } namespace gfx { -class GpuMemoryBuffer; class Rect; class Vector2d; } @@ -57,7 +59,8 @@ class SharedBitmapManager; // This class is not thread-safe and can only be called from the thread it was // created on (in practice, the impl thread). -class CC_EXPORT ResourceProvider { +class CC_EXPORT ResourceProvider + : public base::trace_event::MemoryDumpProvider { private: struct Resource; @@ -83,25 +86,21 @@ class CC_EXPORT ResourceProvider { gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, BlockingTaskRunner* blocking_main_thread_task_runner, int highp_threshold_min, - bool use_rgba_4444_texture_format, size_t id_allocation_chunk_size, - bool use_persistent_map_for_gpu_memory_buffers); - virtual ~ResourceProvider(); + const std::vector<unsigned>& use_image_texture_targets); + ~ResourceProvider() override; void DidLoseOutputSurface() { lost_output_surface_ = true; } int max_texture_size() const { return max_texture_size_; } - ResourceFormat memory_efficient_texture_format() const { - return use_rgba_4444_texture_format_ ? RGBA_4444 : best_texture_format_; - } ResourceFormat best_texture_format() const { return best_texture_format_; } ResourceFormat best_render_buffer_format() const { return best_render_buffer_format_; } ResourceFormat yuv_resource_format() const { return yuv_resource_format_; } bool use_sync_query() const { return use_sync_query_; } - bool use_persistent_map_for_gpu_memory_buffers() const { - return use_persistent_map_for_gpu_memory_buffers_; + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager() { + return gpu_memory_buffer_manager_; } size_t num_resources() const { return resources_.size(); } @@ -423,30 +422,30 @@ class CC_EXPORT ResourceProvider { // Indicates if we can currently lock this resource for write. bool CanLockForWrite(ResourceId id); - // Copy |rect| pixels from source to destination. - void CopyResource(ResourceId source_id, - ResourceId dest_id, - const gfx::Rect& rect); - void WaitSyncPointIfNeeded(ResourceId id); - void WaitReadLockIfNeeded(ResourceId id); - static GLint GetActiveTextureUnit(gpu::gles2::GLES2Interface* gl); OutputSurface* output_surface() { return output_surface_; } void ValidateResource(ResourceId id) const; + GLenum GetImageTextureTarget(ResourceFormat format); + + // base::trace_event::MemoryDumpProvider implementation. + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) override; + + int tracing_id() const { return tracing_id_; } + protected: ResourceProvider(OutputSurface* output_surface, SharedBitmapManager* shared_bitmap_manager, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, BlockingTaskRunner* blocking_main_thread_task_runner, int highp_threshold_min, - bool use_rgba_4444_texture_format, size_t id_allocation_chunk_size, - bool use_persistent_map_for_gpu_memory_buffers); + const std::vector<unsigned>& use_image_texture_targets); void Initialize(); private: @@ -493,8 +492,6 @@ class CC_EXPORT ResourceProvider { bool locked_for_write : 1; bool lost : 1; bool marked_for_deletion : 1; - bool pending_set_pixels : 1; - bool set_pixels_completion_forced : 1; bool allocated : 1; bool read_lock_fences_enabled : 1; bool has_shared_bitmap_id : 1; @@ -594,75 +591,21 @@ class CC_EXPORT ResourceProvider { base::ThreadChecker thread_checker_; scoped_refptr<Fence> current_read_lock_fence_; - bool use_rgba_4444_texture_format_; const size_t id_allocation_chunk_size_; scoped_ptr<IdAllocator> texture_id_allocator_; scoped_ptr<IdAllocator> buffer_id_allocator_; bool use_sync_query_; - bool use_persistent_map_for_gpu_memory_buffers_; - // Fence used for CopyResource if CHROMIUM_sync_query is not supported. - scoped_refptr<SynchronousFence> synchronous_fence_; + std::vector<unsigned> use_image_texture_targets_; + + // A process-unique ID used for disambiguating memory dumps from different + // resource providers. + int tracing_id_; 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 int BitsPerPixel(ResourceFormat 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 // RED_8 - }; - return format_gl_data_type[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_RED_EXT // RED_8 - }; - return format_gl_data_format[format]; -} - -inline GLenum GLInternalFormat(ResourceFormat format) { - return GLDataFormat(format); -} - } // namespace cc #endif // CC_RESOURCES_RESOURCE_PROVIDER_H_ diff --git a/chromium/cc/resources/resource_provider_unittest.cc b/chromium/cc/resources/resource_provider_unittest.cc index 136855847db..bc4c89e39ea 100644 --- a/chromium/cc/resources/resource_provider_unittest.cc +++ b/chromium/cc/resources/resource_provider_unittest.cc @@ -7,6 +7,7 @@ #include <algorithm> #include <map> #include <set> +#include <vector> #include "base/bind.h" #include "base/containers/hash_tables.h" @@ -420,12 +421,12 @@ class ResourceProviderTest resource_provider_ = ResourceProvider::Create( output_surface_.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(), 0, - false, 1, false); + gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(), 0, 1, + use_image_texture_targets_); child_resource_provider_ = ResourceProvider::Create( child_output_surface_.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(), 0, - false, 1, false); + gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(), 0, 1, + use_image_texture_targets_); } ResourceProviderTest() : ResourceProviderTest(true) {} @@ -485,7 +486,13 @@ class ResourceProviderTest } } + public: + static std::vector<unsigned> use_image_texture_targets() { + return use_image_texture_targets_; + } + protected: + static std::vector<unsigned> use_image_texture_targets_; scoped_ptr<ContextSharedData> shared_data_; ResourceProviderContext* context3d_; ResourceProviderContext* child_context_; @@ -500,6 +507,10 @@ class ResourceProviderTest scoped_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_; }; +std::vector<unsigned> ResourceProviderTest::use_image_texture_targets_ = + std::vector<unsigned>(static_cast<size_t>(gfx::BufferFormat::LAST) + 1, + GL_TEXTURE_2D); + void CheckCreateResource(ResourceProvider::ResourceType expected_default_type, ResourceProvider* resource_provider, ResourceProviderContext* context) { @@ -1367,7 +1378,8 @@ TEST_P(ResourceProviderTest, TransferGLToSoftware) { scoped_ptr<ResourceProvider> child_resource_provider(ResourceProvider::Create( child_output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -1850,8 +1862,8 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { scoped_ptr<ResourceProvider> child_resource_provider( ResourceProvider::Create(child_output_surface.get(), - shared_bitmap_manager.get(), NULL, NULL, 0, - false, 1, false)); + shared_bitmap_manager.get(), NULL, NULL, 0, 1, + use_image_texture_targets_)); scoped_ptr<TextureStateTrackingContext> parent_context_owned( new TextureStateTrackingContext); @@ -1864,8 +1876,8 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { scoped_ptr<ResourceProvider> parent_resource_provider( ResourceProvider::Create(parent_output_surface.get(), - shared_bitmap_manager.get(), NULL, NULL, 0, - false, 1, false)); + shared_bitmap_manager.get(), NULL, NULL, 0, 1, + use_image_texture_targets_)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -2497,7 +2509,8 @@ TEST_P(ResourceProviderTest, ScopedSampler) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -2579,7 +2592,8 @@ TEST_P(ResourceProviderTest, ManagedResource) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -2626,7 +2640,8 @@ TEST_P(ResourceProviderTest, TextureWrapMode) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -2676,7 +2691,8 @@ TEST_P(ResourceProviderTest, TextureHint) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); gfx::Size size(1, 1); ResourceFormat format = RGBA_8888; @@ -2740,8 +2756,8 @@ TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) { 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, false)); + gpu_memory_buffer_manager_.get(), main_thread_task_runner_.get(), 0, 1, + use_image_texture_targets_)); uint32 release_sync_point = 0; bool lost_resource = false; @@ -2790,7 +2806,7 @@ class ResourceProviderTestTextureMailboxGLFilters scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager, gpu_memory_buffer_manager, - main_thread_task_runner, 0, false, 1, false)); + main_thread_task_runner, 0, 1, use_image_texture_targets_)); unsigned texture_id = 1; uint32 sync_point = 30; @@ -2933,7 +2949,8 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); uint32 sync_point = 30; unsigned target = GL_TEXTURE_EXTERNAL_OES; @@ -3002,7 +3019,8 @@ TEST_P(ResourceProviderTest, scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); uint32 sync_point = 30; unsigned target = GL_TEXTURE_2D; @@ -3055,7 +3073,8 @@ TEST_P(ResourceProviderTest, TextureMailbox_WaitSyncPointIfNeeded_NoSyncPoint) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); uint32 sync_point = 0; unsigned target = GL_TEXTURE_2D; @@ -3175,7 +3194,8 @@ TEST_P(ResourceProviderTest, TextureAllocation) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); gfx::Size size(2, 2); gfx::Vector2d offset(0, 0); @@ -3211,25 +3231,6 @@ TEST_P(ResourceProviderTest, TextureAllocation) { resource_provider->DeleteResource(id); Mock::VerifyAndClearExpectations(context); - - // Same for async version. - id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format); - resource_provider->AcquirePixelBuffer(id); - - EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); - EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); - EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _)) - .Times(1); - resource_provider->BeginSetPixels(id); - ASSERT_TRUE(resource_provider->DidSetPixelsComplete(id)); - - resource_provider->ReleasePixelBuffer(id); - - EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); - resource_provider->DeleteResource(id); - - Mock::VerifyAndClearExpectations(context); } TEST_P(ResourceProviderTest, TextureAllocationHint) { @@ -3249,7 +3250,8 @@ TEST_P(ResourceProviderTest, TextureAllocationHint) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); gfx::Size size(2, 2); @@ -3304,7 +3306,8 @@ TEST_P(ResourceProviderTest, TextureAllocationHint_BGRA) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); gfx::Size size(2, 2); const ResourceFormat formats[2] = {RGBA_8888, BGRA_8888}; @@ -3339,126 +3342,6 @@ TEST_P(ResourceProviderTest, TextureAllocationHint_BGRA) { } } -TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) { - if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) - return; - scoped_ptr<AllocationTrackingContext3D> context_owned( - new StrictMock<AllocationTrackingContext3D>); - AllocationTrackingContext3D* 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)); - - gfx::Size size(2, 2); - ResourceFormat format = RGBA_8888; - ResourceId id = 0; - int texture_id = 123; - - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); - - id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format); - resource_provider->AcquirePixelBuffer(id); - - EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); - EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); - EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _)) - .Times(1); - resource_provider->BeginSetPixels(id); - - EXPECT_TRUE(resource_provider->DidSetPixelsComplete(id)); - - resource_provider->ReleasePixelBuffer(id); - - EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); - resource_provider->DeleteResource(id); - - Mock::VerifyAndClearExpectations(context); -} - -TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) { - // Only for GL textures. - if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) - return; - scoped_ptr<AllocationTrackingContext3D> context_owned( - new StrictMock<AllocationTrackingContext3D>); - AllocationTrackingContext3D* 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)); - - gfx::Size size(2, 2); - ResourceFormat format = RGBA_8888; - ResourceId id = 0; - int texture_id = 123; - - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); - - id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format); - resource_provider->AcquirePixelBuffer(id); - - EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id)); - EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); - EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _)) - .Times(1); - resource_provider->BeginSetPixels(id); - - EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1); - EXPECT_CALL(*context, waitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D)).Times(1); - EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, 0)).Times(1); - resource_provider->ForceSetPixelsToComplete(id); - - resource_provider->ReleasePixelBuffer(id); - - EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1); - resource_provider->DeleteResource(id); - - Mock::VerifyAndClearExpectations(context); -} - -TEST_P(ResourceProviderTest, PixelBufferLostContext) { - scoped_ptr<AllocationTrackingContext3D> context_owned( - new NiceMock<AllocationTrackingContext3D>); - AllocationTrackingContext3D* 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)); - - gfx::Size size(2, 2); - ResourceFormat format = RGBA_8888; - ResourceId id = 0; - int texture_id = 123; - - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); - - EXPECT_CALL(*context, NextTextureId()).WillRepeatedly(Return(texture_id)); - - id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format); - context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, - GL_INNOCENT_CONTEXT_RESET_ARB); - - resource_provider->AcquirePixelBuffer(id); - int stride; - void* buffer = resource_provider->MapPixelBuffer(id, &stride); - EXPECT_FALSE(buffer); - resource_provider->UnmapPixelBuffer(id); - Mock::VerifyAndClearExpectations(context); -} - TEST_P(ResourceProviderTest, Image_GLTexture) { // Only for GL textures. if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) @@ -3482,7 +3365,8 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format); @@ -3542,87 +3426,6 @@ TEST_P(ResourceProviderTest, Image_GLTexture) { .RetiresOnSaturation(); } -TEST_P(ResourceProviderTest, CopyResource_GLTexture) { - if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) - return; - scoped_ptr<AllocationTrackingContext3D> context_owned( - new StrictMock<AllocationTrackingContext3D>); - AllocationTrackingContext3D* context = context_owned.get(); - context_owned->set_support_sync_query(true); - - FakeOutputSurfaceClient output_surface_client; - scoped_ptr<OutputSurface> output_surface( - FakeOutputSurface::Create3d(context_owned.Pass())); - ASSERT_TRUE(output_surface->BindToClient(&output_surface_client)); - - const int kWidth = 2; - const int kHeight = 2; - gfx::Size size(kWidth, kHeight); - ResourceFormat format = RGBA_8888; - ResourceId source_id = 0; - ResourceId dest_id = 0; - const unsigned kSourceTextureId = 123u; - const unsigned kDestTextureId = 321u; - const unsigned kImageId = 234u; - - scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); - - source_id = resource_provider->CreateResource( - size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format); - - EXPECT_CALL(*context, NextTextureId()) - .WillOnce(Return(kSourceTextureId)) - .RetiresOnSaturation(); - EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kSourceTextureId)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*context, createImageCHROMIUM(_, kWidth, kHeight, GL_RGBA)) - .WillOnce(Return(kImageId)) - .RetiresOnSaturation(); - { - ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock( - resource_provider.get(), source_id); - EXPECT_TRUE(lock.GetGpuMemoryBuffer()); - } - Mock::VerifyAndClearExpectations(context); - - dest_id = resource_provider->CreateResource( - 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, bindTexture(GL_TEXTURE_2D, kSourceTextureId)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId)) - .Times(1) - .RetiresOnSaturation(); - resource_provider->CopyResource(source_id, dest_id, gfx::Rect(size)); - Mock::VerifyAndClearExpectations(context); - - EXPECT_CALL(*context, destroyImageCHROMIUM(kImageId)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*context, RetireTextureId(kSourceTextureId)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*context, RetireTextureId(kDestTextureId)) - .Times(1) - .RetiresOnSaturation(); - resource_provider->DeleteResource(source_id); - resource_provider->DeleteResource(dest_id); -} - TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) { if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) return; @@ -3640,7 +3443,8 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) { gfx::Size size(4, 4); scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); int texture_id = 123; ResourceId id = resource_provider->CreateResource( @@ -3671,7 +3475,8 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1Upload) { gfx::Size size(4, 4); scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( output_surface.get(), shared_bitmap_manager_.get(), - gpu_memory_buffer_manager_.get(), NULL, 0, false, 1, false)); + gpu_memory_buffer_manager_.get(), NULL, 0, 1, + use_image_texture_targets_)); int texture_id = 123; uint8_t pixels[8]; @@ -3726,8 +3531,9 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) { { size_t kTextureAllocationChunkSize = 1; scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager.get(), NULL, NULL, 0, false, - kTextureAllocationChunkSize, false)); + output_surface.get(), shared_bitmap_manager.get(), NULL, NULL, 0, + kTextureAllocationChunkSize, + ResourceProviderTest::use_image_texture_targets())); ResourceId id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, @@ -3742,8 +3548,9 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) { { size_t kTextureAllocationChunkSize = 8; scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create( - output_surface.get(), shared_bitmap_manager.get(), NULL, NULL, 0, false, - kTextureAllocationChunkSize, false)); + output_surface.get(), shared_bitmap_manager.get(), NULL, NULL, 0, + kTextureAllocationChunkSize, + ResourceProviderTest::use_image_texture_targets())); ResourceId id = resource_provider->CreateResource( size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, diff --git a/chromium/cc/resources/resource_util.h b/chromium/cc/resources/resource_util.h new file mode 100644 index 00000000000..9d9905b47d5 --- /dev/null +++ b/chromium/cc/resources/resource_util.h @@ -0,0 +1,222 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_RESOURCES_RESOURCE_UTIL_H_ +#define CC_RESOURCES_RESOURCE_UTIL_H_ + +#include <limits> + +#include "base/numerics/safe_math.h" +#include "cc/base/cc_export.h" +#include "cc/base/math_util.h" +#include "cc/resources/resource_format.h" +#include "ui/gfx/geometry/size.h" + +namespace cc { + +class CC_EXPORT ResourceUtil { + public: + // Returns true if the width is valid and fits in bytes, false otherwise. + template <typename T> + static bool VerifyWidthInBytes(int width, ResourceFormat format); + // Returns true if the size is valid and fits in bytes, false otherwise. + template <typename T> + static bool VerifySizeInBytes(const gfx::Size& size, ResourceFormat format); + + // Dies with a CRASH() if the width can not be represented as a positive + // number of bytes. + template <typename T> + static T CheckedWidthInBytes(int width, ResourceFormat format); + // Dies with a CRASH() if the size can not be represented as a positive + // number of bytes. + template <typename T> + static T CheckedSizeInBytes(const gfx::Size& size, ResourceFormat format); + + // Returns the width in bytes but may overflow or return 0. Only do this for + // computing widths for sizes that have already been checked. + template <typename T> + static T UncheckedWidthInBytes(int width, ResourceFormat format); + // Returns the size in bytes but may overflow or return 0. Only do this for + // sizes that have already been checked. + template <typename T> + static T UncheckedSizeInBytes(const gfx::Size& size, ResourceFormat format); + // Returns the width in bytes aligned but may overflow or return 0. Only do + // this for computing widths for sizes that have already been checked. + template <typename T> + static T UncheckedWidthInBytesAligned(int width, ResourceFormat format); + // Returns the size in bytes aligned but may overflow or return 0. Only do + // this for sizes that have already been checked. + template <typename T> + static T UncheckedSizeInBytesAligned(const gfx::Size& size, + ResourceFormat format); + + private: + // TODO(prashant.n): Replace IsSameType with std::is_same once C++11 is used + // on all platforms. + template <typename T, typename U> + struct IsSameType { + static const bool value = false; + }; + + template <typename T> + struct IsSameType<T, T> { + static const bool value = true; + }; + + template <typename T> + static inline void VerifyType(); + + template <typename T> + static bool VerifyFitsInBytesInternal(int width, + int height, + ResourceFormat format, + bool verify_size, + bool aligned); + + template <typename T> + static T BytesInternal(int width, + int height, + ResourceFormat format, + bool verify_size, + bool aligned); + + DISALLOW_COPY_AND_ASSIGN(ResourceUtil); +}; + +template <typename T> +bool ResourceUtil::VerifyWidthInBytes(int width, ResourceFormat format) { + VerifyType<T>(); + return VerifyFitsInBytesInternal<T>(width, 0, format, false, false); +} + +template <typename T> +bool ResourceUtil::VerifySizeInBytes(const gfx::Size& size, + ResourceFormat format) { + VerifyType<T>(); + return VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true, + false); +} + +template <typename T> +T ResourceUtil::CheckedWidthInBytes(int width, ResourceFormat format) { + VerifyType<T>(); + DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false)); + base::CheckedNumeric<T> checked_value = BitsPerPixel(format); + checked_value *= width; + checked_value = MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8); + checked_value /= 8; + return checked_value.ValueOrDie(); +} + +template <typename T> +T ResourceUtil::CheckedSizeInBytes(const gfx::Size& size, + ResourceFormat format) { + VerifyType<T>(); + DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true, + false)); + base::CheckedNumeric<T> checked_value = BitsPerPixel(format); + checked_value *= size.width(); + checked_value = MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8); + checked_value /= 8; + checked_value *= size.height(); + return checked_value.ValueOrDie(); +} + +template <typename T> +T ResourceUtil::UncheckedWidthInBytes(int width, ResourceFormat format) { + VerifyType<T>(); + DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false)); + return BytesInternal<T>(width, 0, format, false, false); +} + +template <typename T> +T ResourceUtil::UncheckedSizeInBytes(const gfx::Size& size, + ResourceFormat format) { + VerifyType<T>(); + DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true, + false)); + return BytesInternal<T>(size.width(), size.height(), format, true, false); +} + +template <typename T> +T ResourceUtil::UncheckedWidthInBytesAligned(int width, ResourceFormat format) { + VerifyType<T>(); + DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, true)); + return BytesInternal<T>(width, 0, format, false, true); +} + +template <typename T> +T ResourceUtil::UncheckedSizeInBytesAligned(const gfx::Size& size, + ResourceFormat format) { + VerifyType<T>(); + DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true, + true)); + return BytesInternal<T>(size.width(), size.height(), format, true, true); +} + +template <typename T> +void ResourceUtil::VerifyType() { + static_assert( + std::numeric_limits<T>::is_integer && !IsSameType<T, bool>::value, + "T must be non-bool integer type. Preferred type is size_t."); +} + +template <typename T> +bool ResourceUtil::VerifyFitsInBytesInternal(int width, + int height, + ResourceFormat format, + bool verify_size, + bool aligned) { + base::CheckedNumeric<T> checked_value = BitsPerPixel(format); + checked_value *= width; + if (!checked_value.IsValid()) + return false; + + // Roundup bits to byte (8 bits) boundary. If width is 3 and BitsPerPixel is + // 4, then it should return 16, so that row pixels do not get truncated. + checked_value = MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 8); + + // If aligned is true, bytes are aligned on 4-bytes boundaries for upload + // performance, assuming that GL_PACK_ALIGNMENT or GL_UNPACK_ALIGNMENT have + // not changed from default. + if (aligned) { + checked_value /= 8; + if (!checked_value.IsValid()) + return false; + checked_value = + MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 4); + checked_value *= 8; + } + + if (verify_size) + checked_value *= height; + if (!checked_value.IsValid()) + return false; + T value = checked_value.ValueOrDie(); + if ((value % 8) != 0) + return false; + return true; +} + +template <typename T> +T ResourceUtil::BytesInternal(int width, + int height, + ResourceFormat format, + bool verify_size, + bool aligned) { + T bytes = BitsPerPixel(format); + bytes *= width; + bytes = MathUtil::UncheckedRoundUp<T>(bytes, 8); + bytes /= 8; + if (aligned) + bytes = MathUtil::UncheckedRoundUp<T>(bytes, 4); + if (verify_size) + bytes *= height; + + return bytes; +} + +} // namespace cc + +#endif // CC_RESOURCES_RESOURCE_UTIL_H_ diff --git a/chromium/cc/resources/resource_util_unittest.cc b/chromium/cc/resources/resource_util_unittest.cc new file mode 100644 index 00000000000..1fabc3b4f66 --- /dev/null +++ b/chromium/cc/resources/resource_util_unittest.cc @@ -0,0 +1,167 @@ +// 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/resources/resource_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +struct TestFormat { + ResourceFormat format; + size_t expected_bytes; + size_t expected_bytes_aligned; +}; + +// Modify this constant as per TestFormat variables defined in following tests. +const int kTestFormats = 4; + +class ResourceUtilTest : public testing::Test { + public: + void TestVerifyWidthInBytes(int width, const TestFormat* test_formats) { + for (int i = 0; i < kTestFormats; ++i) { + EXPECT_TRUE(ResourceUtil::VerifyWidthInBytes<size_t>( + width, test_formats[i].format)); + } + } + + void TestCheckedWidthInBytes(int width, const TestFormat* test_formats) { + for (int i = 0; i < kTestFormats; ++i) { + size_t bytes = ResourceUtil::CheckedWidthInBytes<size_t>( + width, test_formats[i].format); + EXPECT_EQ(bytes, test_formats[i].expected_bytes); + } + } + + void TestUncheckedWidthInBytes(int width, const TestFormat* test_formats) { + for (int i = 0; i < kTestFormats; ++i) { + size_t bytes = ResourceUtil::UncheckedWidthInBytes<size_t>( + width, test_formats[i].format); + EXPECT_EQ(bytes, test_formats[i].expected_bytes); + } + } + + void TestUncheckedWidthInBytesAligned(int width, + const TestFormat* test_formats) { + for (int i = 0; i < kTestFormats; ++i) { + size_t bytes = ResourceUtil::UncheckedWidthInBytesAligned<size_t>( + width, test_formats[i].format); + EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned); + } + } + + void TestVerifySizeInBytes(const gfx::Size& size, + const TestFormat* test_formats) { + for (int i = 0; i < kTestFormats; ++i) { + EXPECT_TRUE(ResourceUtil::VerifySizeInBytes<size_t>( + size, test_formats[i].format)); + } + } + + void TestCheckedSizeInBytes(const gfx::Size& size, + const TestFormat* test_formats) { + for (int i = 0; i < kTestFormats; ++i) { + size_t bytes = ResourceUtil::CheckedSizeInBytes<size_t>( + size, test_formats[i].format); + EXPECT_EQ(bytes, test_formats[i].expected_bytes); + } + } + + void TestUncheckedSizeInBytes(const gfx::Size& size, + const TestFormat* test_formats) { + for (int i = 0; i < kTestFormats; ++i) { + size_t bytes = ResourceUtil::UncheckedSizeInBytes<size_t>( + size, test_formats[i].format); + EXPECT_EQ(bytes, test_formats[i].expected_bytes); + } + } + + void TestUncheckedSizeInBytesAligned(const gfx::Size& size, + const TestFormat* test_formats) { + for (int i = 0; i < kTestFormats; ++i) { + size_t bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>( + size, test_formats[i].format); + EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned); + } + } +}; + +TEST_F(ResourceUtilTest, WidthInBytes) { + // Check bytes for even width. + int width = 10; + TestFormat test_formats[] = { + {RGBA_8888, 40, 40}, // for 32 bits + {RGBA_4444, 20, 20}, // for 16 bits + {ALPHA_8, 10, 12}, // for 8 bits + {ETC1, 5, 8} // for 4 bits + }; + + TestVerifyWidthInBytes(width, test_formats); + TestCheckedWidthInBytes(width, test_formats); + TestUncheckedWidthInBytes(width, test_formats); + TestUncheckedWidthInBytesAligned(width, test_formats); + + // Check bytes for odd width. + int width_odd = 11; + TestFormat test_formats_odd[] = { + {RGBA_8888, 44, 44}, // for 32 bits + {RGBA_4444, 22, 24}, // for 16 bits + {ALPHA_8, 11, 12}, // for 8 bits + {ETC1, 6, 8} // for 4 bits + }; + + TestVerifyWidthInBytes(width_odd, test_formats_odd); + TestCheckedWidthInBytes(width_odd, test_formats_odd); + TestUncheckedWidthInBytes(width_odd, test_formats_odd); + TestUncheckedWidthInBytesAligned(width_odd, test_formats_odd); +} + +TEST_F(ResourceUtilTest, SizeInBytes) { + // Check bytes for even size. + gfx::Size size(10, 10); + TestFormat test_formats[] = { + {RGBA_8888, 400, 400}, // for 32 bits + {RGBA_4444, 200, 200}, // for 16 bits + {ALPHA_8, 100, 120}, // for 8 bits + {ETC1, 50, 80} // for 4 bits + }; + + TestVerifySizeInBytes(size, test_formats); + TestCheckedSizeInBytes(size, test_formats); + TestUncheckedSizeInBytes(size, test_formats); + TestUncheckedSizeInBytesAligned(size, test_formats); + + // Check bytes for odd size. + gfx::Size size_odd(11, 11); + TestFormat test_formats_odd[] = { + {RGBA_8888, 484, 484}, // for 32 bits + {RGBA_4444, 242, 264}, // for 16 bits + {ALPHA_8, 121, 132}, // for 8 bits + {ETC1, 66, 88} // for 4 bits + }; + + TestVerifySizeInBytes(size_odd, test_formats_odd); + TestCheckedSizeInBytes(size_odd, test_formats_odd); + TestUncheckedSizeInBytes(size_odd, test_formats_odd); + TestUncheckedSizeInBytesAligned(size_odd, test_formats_odd); +} + +TEST_F(ResourceUtilTest, WidthInBytesOverflow) { + int width = 10; + // 10 * 16 = 160 bits, overflows in char, but fits in unsigned char. + EXPECT_FALSE(ResourceUtil::VerifyWidthInBytes<signed char>(width, RGBA_4444)); + EXPECT_TRUE( + ResourceUtil::VerifyWidthInBytes<unsigned char>(width, RGBA_4444)); +} + +TEST_F(ResourceUtilTest, SizeInBytesOverflow) { + gfx::Size size(10, 10); + // 10 * 16 * 10 = 1600 bits, overflows in char, but fits in int. + EXPECT_FALSE(ResourceUtil::VerifySizeInBytes<signed char>(size, RGBA_4444)); + EXPECT_TRUE(ResourceUtil::VerifySizeInBytes<int>(size, RGBA_4444)); +} + +} // namespace +} // namespace cc diff --git a/chromium/cc/resources/returned_resource.h b/chromium/cc/resources/returned_resource.h index 767d16f8dee..94a574e9813 100644 --- a/chromium/cc/resources/returned_resource.h +++ b/chromium/cc/resources/returned_resource.h @@ -13,11 +13,30 @@ namespace cc { +// A ReturnedResource is a struct passed along to a child compositor from a +// parent compositor that corresponds to a TransferableResource that was +// first passed to the parent compositor. struct CC_EXPORT ReturnedResource { ReturnedResource() : id(0), sync_point(0), count(0), lost(false) {} + // |id| is an identifier generated by the child compositor that uniquely + // identifies a resource. This is the same ID space as TransferableResource. ResourceId id; + + // A |sync_point| is an identifier for a point in the parent compositor's + // command buffer. The child compositor then issues a WaitSyncPointCHROMIUM + // command with this |sync_point| as a parameter into its own command buffer. + // This ensures that uses of the resource submitted by the parent compositor + // are executed before commands submitted by the child. unsigned sync_point; + + // |count| is a reference count for this resource. A resource may be used + // by mulitple compositor frames submitted to the parent compositor. |count| + // is the number of references being returned back to the child compositor. int count; + + // If the resource is lost, then the returner cannot give a sync point for it, + // and so it has taken ownership of the resource. The receiver cannot do + // anything with the resource except delete it. bool lost; }; diff --git a/chromium/cc/resources/scoped_resource_unittest.cc b/chromium/cc/resources/scoped_resource_unittest.cc index 197fa1f3b8d..cb41bf6fc8a 100644 --- a/chromium/cc/resources/scoped_resource_unittest.cc +++ b/chromium/cc/resources/scoped_resource_unittest.cc @@ -31,8 +31,8 @@ TEST(ScopedResourceTest, NewScopedResource) { // New scoped textures do not have a size yet. EXPECT_EQ(gfx::Size(), texture->size()); - EXPECT_EQ(0u, Resource::UncheckedMemorySizeBytes(texture->size(), - texture->format())); + EXPECT_EQ(0u, ResourceUtil::UncheckedSizeInBytes<size_t>(texture->size(), + texture->format())); } TEST(ScopedResourceTest, CreateScopedResource) { @@ -51,7 +51,7 @@ TEST(ScopedResourceTest, CreateScopedResource) { // The texture has an allocated byte-size now. size_t expected_bytes = 30 * 30 * 4; - EXPECT_EQ(expected_bytes, Resource::UncheckedMemorySizeBytes( + EXPECT_EQ(expected_bytes, ResourceUtil::UncheckedSizeInBytes<size_t>( texture->size(), texture->format())); EXPECT_LT(0u, texture->id()); diff --git a/chromium/cc/resources/shared_bitmap.cc b/chromium/cc/resources/shared_bitmap.cc index 1ac03233dfb..fc15736315b 100644 --- a/chromium/cc/resources/shared_bitmap.cc +++ b/chromium/cc/resources/shared_bitmap.cc @@ -7,6 +7,8 @@ #include "base/logging.h" #include "base/numerics/safe_math.h" #include "base/rand_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" namespace cc { @@ -66,4 +68,11 @@ SharedBitmapId SharedBitmap::GenerateId() { return id; } +base::trace_event::MemoryAllocatorDumpGuid GetSharedBitmapGUIDForTracing( + const SharedBitmapId& bitmap_id) { + auto bitmap_id_hex = base::HexEncode(bitmap_id.name, sizeof(bitmap_id.name)); + return base::trace_event::MemoryAllocatorDumpGuid( + base::StringPrintf("sharedbitmap-x-process/%s", bitmap_id_hex.c_str())); +} + } // namespace cc diff --git a/chromium/cc/resources/shared_bitmap.h b/chromium/cc/resources/shared_bitmap.h index 6980afbc112..04dab7456fa 100644 --- a/chromium/cc/resources/shared_bitmap.h +++ b/chromium/cc/resources/shared_bitmap.h @@ -6,6 +6,7 @@ #define CC_RESOURCES_SHARED_BITMAP_H_ #include "base/basictypes.h" +#include "base/trace_event/memory_allocator_dump.h" #include "cc/base/cc_export.h" #include "gpu/command_buffer/common/mailbox.h" #include "ui/gfx/geometry/size.h" @@ -13,6 +14,9 @@ namespace cc { typedef gpu::Mailbox SharedBitmapId; +CC_EXPORT base::trace_event::MemoryAllocatorDumpGuid +GetSharedBitmapGUIDForTracing(const SharedBitmapId& bitmap_id); + class CC_EXPORT SharedBitmap { public: SharedBitmap(uint8* pixels, const SharedBitmapId& id); diff --git a/chromium/cc/resources/video_resource_updater.cc b/chromium/cc/resources/video_resource_updater.cc index e973a3d5240..3dc89ac79bf 100644 --- a/chromium/cc/resources/video_resource_updater.cc +++ b/chromium/cc/resources/video_resource_updater.cc @@ -25,6 +25,50 @@ namespace { const ResourceFormat kRGBResourceFormat = RGBA_8888; +VideoFrameExternalResources::ResourceType ResourceTypeForVideoFrame( + media::VideoFrame* video_frame) { + switch (video_frame->format()) { + case media::PIXEL_FORMAT_ARGB: + case media::PIXEL_FORMAT_XRGB: + case media::PIXEL_FORMAT_UYVY: + switch (video_frame->mailbox_holder(0).texture_target) { + case GL_TEXTURE_2D: + return (video_frame->format() == media::PIXEL_FORMAT_XRGB) + ? VideoFrameExternalResources::RGB_RESOURCE + : VideoFrameExternalResources::RGBA_RESOURCE; + case GL_TEXTURE_EXTERNAL_OES: + return VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE; + case GL_TEXTURE_RECTANGLE_ARB: + return VideoFrameExternalResources::IO_SURFACE; + default: + NOTREACHED(); + break; + } + break; + case media::PIXEL_FORMAT_I420: + return VideoFrameExternalResources::YUV_RESOURCE; + break; + case media::PIXEL_FORMAT_NV12: + DCHECK_EQ(static_cast<uint32_t>(GL_TEXTURE_RECTANGLE_ARB), + video_frame->mailbox_holder(0).texture_target); + return VideoFrameExternalResources::IO_SURFACE; + break; + case media::PIXEL_FORMAT_YV12: + case media::PIXEL_FORMAT_YV16: + case media::PIXEL_FORMAT_YV24: + case media::PIXEL_FORMAT_YV12A: + case media::PIXEL_FORMAT_NV21: + case media::PIXEL_FORMAT_YUY2: + case media::PIXEL_FORMAT_RGB24: + case media::PIXEL_FORMAT_RGB32: + case media::PIXEL_FORMAT_MJPEG: + case media::PIXEL_FORMAT_MT21: + case media::PIXEL_FORMAT_UNKNOWN: + break; + } + return VideoFrameExternalResources::NONE; +} + class SyncPointClientImpl : public media::VideoFrame::SyncPointClient { public: explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl, @@ -139,7 +183,14 @@ void VideoResourceUpdater::DeleteResource(ResourceList::iterator resource_it) { VideoFrameExternalResources VideoResourceUpdater:: CreateExternalResourcesFromVideoFrame( const scoped_refptr<media::VideoFrame>& video_frame) { - if (video_frame->format() == media::VideoFrame::UNKNOWN) +#if defined(VIDEO_HOLE) + if (video_frame->storage_type() == media::VideoFrame::STORAGE_HOLE) { + VideoFrameExternalResources external_resources; + external_resources.type = VideoFrameExternalResources::HOLE; + return external_resources; + } +#endif // defined(VIDEO_HOLE) + if (video_frame->format() == media::PIXEL_FORMAT_UNKNOWN) return VideoFrameExternalResources(); DCHECK(video_frame->HasTextures() || video_frame->IsMappable()); if (video_frame->HasTextures()) @@ -164,19 +215,11 @@ static gfx::Size SoftwarePlaneDimension( VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( const scoped_refptr<media::VideoFrame>& video_frame) { TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes"); - const media::VideoFrame::Format input_frame_format = video_frame->format(); - -#if defined(VIDEO_HOLE) - if (video_frame->storage_type() == media::VideoFrame::STORAGE_HOLE) { - VideoFrameExternalResources external_resources; - external_resources.type = VideoFrameExternalResources::HOLE; - return external_resources; - } -#endif // defined(VIDEO_HOLE) + const media::VideoPixelFormat input_frame_format = video_frame->format(); // Only YUV software video frames are supported. - if (!media::VideoFrame::IsYuvPlanar(input_frame_format)) { - NOTREACHED() << media::VideoFrame::FormatToString(input_frame_format); + if (!media::IsYuvPlanar(input_frame_format)) { + NOTREACHED() << media::VideoPixelFormatToString(input_frame_format); return VideoFrameExternalResources(); } @@ -305,16 +348,19 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( 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); + int video_stride_pixels = video_frame->stride(i); - size_t bytes_per_pixel = BitsPerPixel(plane_resource.resource_format) / 8; + size_t bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>( + resource_size_pixels.width(), plane_resource.resource_format); // 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 = MathUtil::RoundUp<size_t>( - bytes_per_pixel * resource_size_pixels.width(), 4u); + size_t upload_image_stride = + MathUtil::UncheckedRoundUp<size_t>(bytes_per_row, 4u); const uint8_t* pixels; - if (upload_image_stride == video_stride_pixels * bytes_per_pixel) { + size_t video_bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>( + video_stride_pixels, plane_resource.resource_format); + if (upload_image_stride == video_bytes_per_row) { pixels = video_frame->data(i); } else { // Avoid malloc for each frame/plane if possible. @@ -324,9 +370,9 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes( 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); + const uint8_t* src = + video_frame->data(i) + (video_bytes_per_row * row); + memcpy(dst, src, bytes_per_row); } pixels = &upload_pixels_[0]; } @@ -372,52 +418,21 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( if (!context_provider_) return VideoFrameExternalResources(); - const size_t textures = media::VideoFrame::NumPlanes(video_frame->format()); - DCHECK_GE(textures, 1u); VideoFrameExternalResources external_resources; external_resources.read_lock_fences_enabled = true; - switch (video_frame->format()) { - case media::VideoFrame::ARGB: - case media::VideoFrame::XRGB: - DCHECK_EQ(1u, textures); - switch (video_frame->mailbox_holder(0).texture_target) { - case GL_TEXTURE_2D: - external_resources.type = - (video_frame->format() == media::VideoFrame::XRGB) - ? VideoFrameExternalResources::RGB_RESOURCE - : 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 media::VideoFrame::I420: - external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; - break; -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) - case media::VideoFrame::NV12: -#endif - case media::VideoFrame::YV12: - case media::VideoFrame::YV16: - case media::VideoFrame::YV24: - case media::VideoFrame::YV12A: - case media::VideoFrame::UNKNOWN: - DLOG(ERROR) << "Unsupported Texture format" - << media::VideoFrame::FormatToString(video_frame->format()); - return external_resources; + + external_resources.type = ResourceTypeForVideoFrame(video_frame.get()); + if (external_resources.type == VideoFrameExternalResources::NONE) { + DLOG(ERROR) << "Unsupported Texture format" + << media::VideoPixelFormatToString(video_frame->format()); + return external_resources; } - DCHECK_NE(VideoFrameExternalResources::NONE, external_resources.type); - for (size_t i = 0; i < textures; ++i) { + const size_t num_planes = media::VideoFrame::NumPlanes(video_frame->format()); + for (size_t i = 0; i < num_planes; ++i) { const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i); + if (mailbox_holder.mailbox.IsZero()) + break; external_resources.mailboxes.push_back( TextureMailbox(mailbox_holder.mailbox, mailbox_holder.texture_target, mailbox_holder.sync_point, video_frame->coded_size(), diff --git a/chromium/cc/resources/video_resource_updater_unittest.cc b/chromium/cc/resources/video_resource_updater_unittest.cc index 3e4574d989c..3d4bf1778ba 100644 --- a/chromium/cc/resources/video_resource_updater_unittest.cc +++ b/chromium/cc/resources/video_resource_updater_unittest.cc @@ -4,7 +4,6 @@ #include "cc/resources/video_resource_updater.h" -#include "base/memory/shared_memory.h" #include "cc/resources/resource_provider.h" #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" @@ -87,17 +86,17 @@ class VideoResourceUpdaterTest : public testing::Test { static uint8 v_data[kDimension * kDimension / 2] = { 0 }; return media::VideoFrame::WrapExternalYuvData( - media::VideoFrame::YV16, // format - size, // coded_size - gfx::Rect(size), // visible_rect - size, // natural_size - size.width(), // y_stride - size.width() / 2, // u_stride - size.width() / 2, // v_stride - y_data, // y_data - u_data, // u_data - v_data, // v_data - base::TimeDelta()); // timestamp + media::PIXEL_FORMAT_YV16, // format + size, // coded_size + gfx::Rect(size), // visible_rect + size, // natural_size + size.width(), // y_stride + size.width() / 2, // u_stride + size.width() / 2, // v_stride + y_data, // y_data + u_data, // u_data + v_data, // v_data + base::TimeDelta()); // timestamp } static void ReleaseMailboxCB(unsigned sync_point) {} @@ -112,7 +111,7 @@ class VideoResourceUpdaterTest : public testing::Test { const unsigned sync_point = 7; const unsigned target = GL_TEXTURE_2D; return media::VideoFrame::WrapNativeTexture( - media::VideoFrame::ARGB, + media::PIXEL_FORMAT_ARGB, gpu::MailboxHolder(mailbox, target, sync_point), base::Bind(&ReleaseMailboxCB), size, // coded_size diff --git a/chromium/cc/scheduler/begin_frame_source_unittest.cc b/chromium/cc/scheduler/begin_frame_source_unittest.cc index 1f85622878e..2c12ca90fcc 100644 --- a/chromium/cc/scheduler/begin_frame_source_unittest.cc +++ b/chromium/cc/scheduler/begin_frame_source_unittest.cc @@ -6,7 +6,6 @@ #include <string> #include "base/basictypes.h" -#include "base/gtest_prod_util.h" #include "base/test/test_simple_task_runner.h" #include "cc/scheduler/begin_frame_source.h" #include "cc/test/begin_frame_args_test.h" diff --git a/chromium/cc/scheduler/compositor_timing_history.cc b/chromium/cc/scheduler/compositor_timing_history.cc index b46c8a15cbe..34726d5ddf8 100644 --- a/chromium/cc/scheduler/compositor_timing_history.cc +++ b/chromium/cc/scheduler/compositor_timing_history.cc @@ -8,21 +8,194 @@ #include "base/trace_event/trace_event.h" #include "cc/debug/rendering_stats_instrumentation.h" -// The estimates that affect the compositors deadline use the 100th percentile -// to avoid missing the Browser's deadline. -// The estimates related to main-thread responsiveness affect whether -// we attempt to recovery latency or not and use the 50th percentile. +namespace cc { + +class CompositorTimingHistory::UMAReporter { + public: + virtual ~UMAReporter() {} + + virtual void AddBeginMainFrameToCommitDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) = 0; + virtual void AddCommitToReadyToActivateDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) = 0; + virtual void AddPrepareTilesDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) = 0; + virtual void AddActivateDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) = 0; + virtual void AddDrawDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) = 0; +}; + +namespace { + +// Using the 90th percentile will disable latency recovery +// if we are missing the deadline approximately ~6 times per +// second. // TODO(brianderson): Fine tune the percentiles below. const size_t kDurationHistorySize = 60; -const double kBeginMainFrameToCommitEstimationPercentile = 50.0; -const double kCommitToReadyToActivateEstimationPercentile = 50.0; -const double kPrepareTilesEstimationPercentile = 100.0; -const double kActivateEstimationPercentile = 100.0; -const double kDrawEstimationPercentile = 100.0; +const double kBeginMainFrameToCommitEstimationPercentile = 90.0; +const double kCommitToReadyToActivateEstimationPercentile = 90.0; +const double kPrepareTilesEstimationPercentile = 90.0; +const double kActivateEstimationPercentile = 90.0; +const double kDrawEstimationPercentile = 90.0; + +const int kUmaDurationMinMicros = 1; +const int64 kUmaDurationMaxMicros = 1 * base::Time::kMicrosecondsPerSecond; +const size_t kUmaDurationBucketCount = 100; + +// Deprecated because they combine Browser and Renderer stats and have low +// precision. +// TODO(brianderson): Remove. +void DeprecatedDrawDurationUMA(base::TimeDelta duration, + base::TimeDelta estimate) { + base::TimeDelta duration_overestimate; + base::TimeDelta duration_underestimate; + if (duration > estimate) + duration_underestimate = duration - estimate; + else + duration_overestimate = estimate - duration; + UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDuration", duration, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(100), 50); + UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationUnderestimate", + duration_underestimate, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(100), 50); + UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationOverestimate", + duration_overestimate, + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromMilliseconds(100), 50); +} -namespace cc { +#define UMA_HISTOGRAM_CUSTOM_TIMES_MICROS(name, sample) \ + UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample.InMicroseconds(), \ + kUmaDurationMinMicros, kUmaDurationMaxMicros, \ + kUmaDurationBucketCount); + +#define REPORT_COMPOSITOR_TIMING_HISTORY_UMA(category, subcategory) \ + do { \ + base::TimeDelta duration_overestimate; \ + base::TimeDelta duration_underestimate; \ + if (duration > estimate) \ + duration_underestimate = duration - estimate; \ + else \ + duration_overestimate = estimate - duration; \ + UMA_HISTOGRAM_CUSTOM_TIMES_MICROS( \ + "Scheduling." category "." subcategory "Duration", duration); \ + UMA_HISTOGRAM_CUSTOM_TIMES_MICROS("Scheduling." category "." subcategory \ + "Duration.Underestimate", \ + duration_underestimate); \ + UMA_HISTOGRAM_CUSTOM_TIMES_MICROS("Scheduling." category "." subcategory \ + "Duration.Overestimate", \ + duration_overestimate); \ + if (!affects_estimate) { \ + UMA_HISTOGRAM_CUSTOM_TIMES_MICROS("Scheduling." category "." subcategory \ + "Duration.NotUsedForEstimate", \ + duration); \ + } \ + } while (false) + +class RendererUMAReporter : public CompositorTimingHistory::UMAReporter { + public: + ~RendererUMAReporter() override {} + + void AddBeginMainFrameToCommitDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Renderer", "BeginMainFrameToCommit"); + } + + void AddCommitToReadyToActivateDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Renderer", "CommitToReadyToActivate"); + } + + void AddPrepareTilesDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Renderer", "PrepareTiles"); + } + + void AddActivateDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Renderer", "Activate"); + } + + void AddDrawDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Renderer", "Draw"); + DeprecatedDrawDurationUMA(duration, estimate); + } +}; + +class BrowserUMAReporter : public CompositorTimingHistory::UMAReporter { + public: + ~BrowserUMAReporter() override {} + + void AddBeginMainFrameToCommitDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Browser", "BeginMainFrameToCommit"); + } + + void AddCommitToReadyToActivateDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Browser", "CommitToReadyToActivate"); + } + + void AddPrepareTilesDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Browser", "PrepareTiles"); + } + + void AddActivateDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Browser", "Activate"); + } + + void AddDrawDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override { + REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Browser", "Draw"); + DeprecatedDrawDurationUMA(duration, estimate); + } +}; + +class NullUMAReporter : public CompositorTimingHistory::UMAReporter { + public: + ~NullUMAReporter() override {} + void AddPrepareTilesDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override {} + void AddBeginMainFrameToCommitDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override {} + void AddCommitToReadyToActivateDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override {} + void AddActivateDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override {} + void AddDrawDuration(base::TimeDelta duration, + base::TimeDelta estimate, + bool affects_estimate) override {} +}; + +} // namespace CompositorTimingHistory::CompositorTimingHistory( + UMACategory uma_category, RenderingStatsInstrumentation* rendering_stats_instrumentation) : enabled_(false), begin_main_frame_to_commit_duration_history_(kDurationHistorySize), @@ -30,23 +203,40 @@ CompositorTimingHistory::CompositorTimingHistory( prepare_tiles_duration_history_(kDurationHistorySize), activate_duration_history_(kDurationHistorySize), draw_duration_history_(kDurationHistorySize), - rendering_stats_instrumentation_(rendering_stats_instrumentation) { -} + uma_reporter_(CreateUMAReporter(uma_category)), + rendering_stats_instrumentation_(rendering_stats_instrumentation) {} CompositorTimingHistory::~CompositorTimingHistory() { } +scoped_ptr<CompositorTimingHistory::UMAReporter> +CompositorTimingHistory::CreateUMAReporter(UMACategory category) { + switch (category) { + case RENDERER_UMA: + return make_scoped_ptr(new RendererUMAReporter); + break; + case BROWSER_UMA: + return make_scoped_ptr(new BrowserUMAReporter); + break; + case NULL_UMA: + return make_scoped_ptr(new NullUMAReporter); + break; + } + NOTREACHED(); + return make_scoped_ptr<CompositorTimingHistory::UMAReporter>(nullptr); +} + void CompositorTimingHistory::AsValueInto( base::trace_event::TracedValue* state) const { - state->SetDouble("begin_main_frame_to_commit_duration_estimate_ms", + state->SetDouble("begin_main_frame_to_commit_estimate_ms", BeginMainFrameToCommitDurationEstimate().InMillisecondsF()); - state->SetDouble("commit_to_ready_to_activate_duration_estimate_ms", + state->SetDouble("commit_to_ready_to_activate_estimate_ms", CommitToReadyToActivateDurationEstimate().InMillisecondsF()); - state->SetDouble("prepare_tiles_duration_estimate_ms", + state->SetDouble("prepare_tiles_estimate_ms", PrepareTilesDurationEstimate().InMillisecondsF()); - state->SetDouble("activate_duration_estimate_ms", + state->SetDouble("activate_estimate_ms", ActivateDurationEstimate().InMillisecondsF()); - state->SetDouble("draw_duration_estimate_ms", + state->SetDouble("draw_estimate_ms", DrawDurationEstimate().InMillisecondsF()); } @@ -103,9 +293,13 @@ void CompositorTimingHistory::DidCommit() { // 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 // of our predictions. + base::TimeDelta begin_main_frame_to_commit_estimate = + BeginMainFrameToCommitDurationEstimate(); + uma_reporter_->AddBeginMainFrameToCommitDuration( + begin_main_frame_to_commit_duration, begin_main_frame_to_commit_estimate, + enabled_); rendering_stats_instrumentation_->AddBeginMainFrameToCommitDuration( - begin_main_frame_to_commit_duration, - BeginMainFrameToCommitDurationEstimate()); + begin_main_frame_to_commit_duration, begin_main_frame_to_commit_estimate); if (enabled_) { begin_main_frame_to_commit_duration_history_.InsertSample( @@ -123,10 +317,11 @@ void CompositorTimingHistory::WillPrepareTiles() { void CompositorTimingHistory::DidPrepareTiles() { DCHECK_NE(base::TimeTicks(), start_prepare_tiles_time_); - if (enabled_) { - base::TimeDelta prepare_tiles_duration = Now() - start_prepare_tiles_time_; + base::TimeDelta prepare_tiles_duration = Now() - start_prepare_tiles_time_; + uma_reporter_->AddPrepareTilesDuration( + prepare_tiles_duration, PrepareTilesDurationEstimate(), enabled_); + if (enabled_) prepare_tiles_duration_history_.InsertSample(prepare_tiles_duration); - } start_prepare_tiles_time_ = base::TimeTicks(); } @@ -142,8 +337,13 @@ void CompositorTimingHistory::ReadyToActivate() { // 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 // of our predictions. + + base::TimeDelta commit_to_ready_to_activate_estimate = + CommitToReadyToActivateDurationEstimate(); + uma_reporter_->AddCommitToReadyToActivateDuration( + time_since_commit, commit_to_ready_to_activate_estimate, enabled_); rendering_stats_instrumentation_->AddCommitToActivateDuration( - time_since_commit, CommitToReadyToActivateDurationEstimate()); + time_since_commit, commit_to_ready_to_activate_estimate); if (enabled_) { commit_to_ready_to_activate_duration_history_.InsertSample( @@ -160,10 +360,13 @@ void CompositorTimingHistory::WillActivate() { void CompositorTimingHistory::DidActivate() { DCHECK_NE(base::TimeTicks(), start_activate_time_); - if (enabled_) { - base::TimeDelta activate_duration = Now() - start_activate_time_; + base::TimeDelta activate_duration = Now() - start_activate_time_; + + uma_reporter_->AddActivateDuration(activate_duration, + ActivateDurationEstimate(), enabled_); + if (enabled_) activate_duration_history_.InsertSample(activate_duration); - } + start_activate_time_ = base::TimeTicks(); } @@ -179,11 +382,11 @@ void CompositorTimingHistory::DidDraw() { // 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 // of our predictions. - base::TimeDelta draw_duration_estimate = DrawDurationEstimate(); + base::TimeDelta draw_estimate = DrawDurationEstimate(); rendering_stats_instrumentation_->AddDrawDuration(draw_duration, - draw_duration_estimate); + draw_estimate); - AddDrawDurationUMA(draw_duration, draw_duration_estimate); + uma_reporter_->AddDrawDuration(draw_duration, draw_estimate, enabled_); if (enabled_) { draw_duration_history_.InsertSample(draw_duration); @@ -192,26 +395,4 @@ void CompositorTimingHistory::DidDraw() { start_draw_time_ = base::TimeTicks(); } -void CompositorTimingHistory::AddDrawDurationUMA( - base::TimeDelta draw_duration, - base::TimeDelta draw_duration_estimate) { - base::TimeDelta draw_duration_overestimate; - base::TimeDelta draw_duration_underestimate; - if (draw_duration > draw_duration_estimate) - draw_duration_underestimate = draw_duration - draw_duration_estimate; - else - draw_duration_overestimate = draw_duration_estimate - draw_duration; - UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDuration", draw_duration, - base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMilliseconds(100), 50); - UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationUnderestimate", - draw_duration_underestimate, - base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMilliseconds(100), 50); - UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationOverestimate", - draw_duration_overestimate, - base::TimeDelta::FromMilliseconds(1), - base::TimeDelta::FromMilliseconds(100), 50); -} - } // namespace cc diff --git a/chromium/cc/scheduler/compositor_timing_history.h b/chromium/cc/scheduler/compositor_timing_history.h index d64c38f1cbe..e580c5e3d5b 100644 --- a/chromium/cc/scheduler/compositor_timing_history.h +++ b/chromium/cc/scheduler/compositor_timing_history.h @@ -5,6 +5,7 @@ #ifndef CC_SCHEDULER_COMPOSITOR_TIMING_HISTORY_H_ #define CC_SCHEDULER_COMPOSITOR_TIMING_HISTORY_H_ +#include "base/memory/scoped_ptr.h" #include "cc/base/rolling_time_delta_history.h" namespace base { @@ -19,7 +20,15 @@ class RenderingStatsInstrumentation; class CC_EXPORT CompositorTimingHistory { public: - explicit CompositorTimingHistory( + enum UMACategory { + RENDERER_UMA, + BROWSER_UMA, + NULL_UMA, + }; + class UMAReporter; + + CompositorTimingHistory( + UMACategory uma_category, RenderingStatsInstrumentation* rendering_stats_instrumentation); virtual ~CompositorTimingHistory(); @@ -45,11 +54,9 @@ class CC_EXPORT CompositorTimingHistory { void DidDraw(); protected: + static scoped_ptr<UMAReporter> CreateUMAReporter(UMACategory category); virtual base::TimeTicks Now() const; - void AddDrawDurationUMA(base::TimeDelta draw_duration, - base::TimeDelta draw_duration_estimate); - bool enabled_; RollingTimeDeltaHistory begin_main_frame_to_commit_duration_history_; @@ -64,6 +71,7 @@ class CC_EXPORT CompositorTimingHistory { base::TimeTicks start_activate_time_; base::TimeTicks start_draw_time_; + scoped_ptr<UMAReporter> uma_reporter_; RenderingStatsInstrumentation* rendering_stats_instrumentation_; private: diff --git a/chromium/cc/scheduler/compositor_timing_history_unittest.cc b/chromium/cc/scheduler/compositor_timing_history_unittest.cc index 6045e3a960a..5ffd68e95d2 100644 --- a/chromium/cc/scheduler/compositor_timing_history_unittest.cc +++ b/chromium/cc/scheduler/compositor_timing_history_unittest.cc @@ -16,7 +16,7 @@ class TestCompositorTimingHistory : public CompositorTimingHistory { public: TestCompositorTimingHistory(CompositorTimingHistoryTest* test, RenderingStatsInstrumentation* rendering_stats) - : CompositorTimingHistory(rendering_stats), test_(test) {} + : CompositorTimingHistory(NULL_UMA, rendering_stats), test_(test) {} protected: base::TimeTicks Now() const override; diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc index 2b668e83011..082fbee328e 100644 --- a/chromium/cc/scheduler/scheduler.cc +++ b/chromium/cc/scheduler/scheduler.cc @@ -19,6 +19,13 @@ namespace cc { +namespace { +// This is a fudge factor we subtract from the deadline to account +// for message latency and kernel scheduling variability. +const base::TimeDelta kDeadlineFudgeFactor = + base::TimeDelta::FromMicroseconds(1000); +} + scoped_ptr<Scheduler> Scheduler::Create( SchedulerClient* client, const SchedulerSettings& settings, @@ -162,8 +169,8 @@ void Scheduler::SetThrottleFrameProduction(bool throttle) { ProcessScheduledActions(); } -void Scheduler::SetNeedsCommit() { - state_machine_.SetNeedsCommit(); +void Scheduler::SetNeedsBeginMainFrame() { + state_machine_.SetNeedsBeginMainFrame(); ProcessScheduledActions(); } @@ -183,11 +190,6 @@ void Scheduler::SetNeedsPrepareTiles() { ProcessScheduledActions(); } -void Scheduler::SetWaitForReadyToDraw() { - state_machine_.SetWaitForReadyToDraw(); - ProcessScheduledActions(); -} - void Scheduler::SetMaxSwapsPending(int max) { state_machine_.SetMaxSwapsPending(max); } @@ -450,15 +452,16 @@ void Scheduler::PostBeginRetroFrameIfNeeded() { void Scheduler::BeginImplFrameWithDeadline(const BeginFrameArgs& args) { bool main_thread_is_in_high_latency_mode = - state_machine_.MainThreadIsInHighLatencyMode(); + state_machine_.main_thread_missed_last_deadline(); TRACE_EVENT2("cc,benchmark", "Scheduler::BeginImplFrame", "args", - args.AsValue(), "main_thread_is_high_latency", + args.AsValue(), "main_thread_missed_last_deadline", main_thread_is_in_high_latency_mode); TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), "MainThreadLatency", main_thread_is_in_high_latency_mode); BeginFrameArgs adjusted_args = args; adjusted_args.deadline -= compositor_timing_history_->DrawDurationEstimate(); + adjusted_args.deadline -= kDeadlineFudgeFactor; if (ShouldRecoverMainLatency(adjusted_args)) { TRACE_EVENT_INSTANT0("cc", "SkipBeginMainFrameToReduceLatency", @@ -632,17 +635,18 @@ void Scheduler::ProcessScheduledActions() { "SchedulerStateMachine", "state", AsValue()); - state_machine_.UpdateState(action); base::AutoReset<SchedulerStateMachine::Action> mark_inside_action(&inside_action_, action); switch (action) { case SchedulerStateMachine::ACTION_NONE: break; case SchedulerStateMachine::ACTION_ANIMATE: + state_machine_.WillAnimate(); client_->ScheduledActionAnimate(); break; case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: compositor_timing_history_->WillBeginMainFrame(); + state_machine_.WillSendBeginMainFrame(); client_->ScheduledActionSendBeginMainFrame(); break; case SchedulerStateMachine::ACTION_COMMIT: { @@ -651,11 +655,14 @@ void Scheduler::ProcessScheduledActions() { tracked_objects::ScopedTracker tracking_profile4( FROM_HERE_WITH_EXPLICIT_FUNCTION( "461509 Scheduler::ProcessScheduledActions4")); + bool commit_has_no_updates = false; + state_machine_.WillCommit(commit_has_no_updates); client_->ScheduledActionCommit(); break; } case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE: compositor_timing_history_->WillActivate(); + state_machine_.WillActivate(); client_->ScheduledActionActivateSyncTree(); compositor_timing_history_->DidActivate(); break; @@ -665,23 +672,34 @@ void Scheduler::ProcessScheduledActions() { tracked_objects::ScopedTracker tracking_profile6( FROM_HERE_WITH_EXPLICIT_FUNCTION( "461509 Scheduler::ProcessScheduledActions6")); + bool did_request_swap = true; + state_machine_.WillDraw(did_request_swap); DrawAndSwapIfPossible(); break; } - case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: { + bool did_request_swap = true; + state_machine_.WillDraw(did_request_swap); DrawAndSwapForced(); break; - case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: + } + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: { // No action is actually performed, but this allows the state machine to // advance out of its waiting to draw state without actually drawing. + bool did_request_swap = false; + state_machine_.WillDraw(did_request_swap); break; + } case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: + state_machine_.WillBeginOutputSurfaceCreation(); client_->ScheduledActionBeginOutputSurfaceCreation(); break; case SchedulerStateMachine::ACTION_PREPARE_TILES: + state_machine_.WillPrepareTiles(); client_->ScheduledActionPrepareTiles(); break; case SchedulerStateMachine::ACTION_INVALIDATE_OUTPUT_SURFACE: { + state_machine_.WillInvalidateOutputSurface(); client_->ScheduledActionInvalidateOutputSurface(); break; } @@ -754,7 +772,7 @@ void Scheduler::UpdateCompositorTimingHistoryRecordingEnabled() { bool Scheduler::ShouldRecoverMainLatency(const BeginFrameArgs& args) const { DCHECK(!settings_.using_synchronous_renderer_compositor); - if (!state_machine_.MainThreadIsInHighLatencyMode()) + if (!state_machine_.main_thread_missed_last_deadline()) return false; // When prioritizing impl thread latency, we currently put the @@ -768,6 +786,12 @@ bool Scheduler::ShouldRecoverMainLatency(const BeginFrameArgs& args) const { bool Scheduler::ShouldRecoverImplLatency(const BeginFrameArgs& args) const { DCHECK(!settings_.using_synchronous_renderer_compositor); + // Disable impl thread latency recovery when using the unthrottled + // begin frame source since we will always get a BeginFrame before + // the swap ack and our heuristics below will not work. + if (!throttle_frame_production_) + return false; + // If we are swap throttled at the BeginFrame, that means the impl thread is // very likely in a high latency mode. bool impl_thread_is_likely_high_latency = state_machine_.SwapThrottled(); @@ -808,10 +832,10 @@ bool Scheduler::CanCommitAndActivateBeforeDeadline( } bool Scheduler::IsBeginMainFrameSentOrStarted() const { - return (state_machine_.commit_state() == - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || - state_machine_.commit_state() == - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); + return (state_machine_.begin_main_frame_state() == + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT || + state_machine_.begin_main_frame_state() == + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_STARTED); } } // namespace cc diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h index d6fc074c541..8e9abce8971 100644 --- a/chromium/cc/scheduler/scheduler.h +++ b/chromium/cc/scheduler/scheduler.h @@ -83,7 +83,7 @@ class CC_EXPORT Scheduler : public BeginFrameObserverBase { void NotifyReadyToDraw(); void SetThrottleFrameProduction(bool throttle); - void SetNeedsCommit(); + void SetNeedsBeginMainFrame(); void SetNeedsRedraw(); @@ -91,8 +91,6 @@ class CC_EXPORT Scheduler : public BeginFrameObserverBase { void SetNeedsPrepareTiles(); - void SetWaitForReadyToDraw(); - void SetMaxSwapsPending(int max); void DidSwapBuffers(); void DidSwapBuffersComplete(); @@ -136,10 +134,6 @@ class CC_EXPORT Scheduler : public BeginFrameObserverBase { 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); - } - void SetChildrenNeedBeginFrames(bool children_need_begin_frames); void SetVideoNeedsBeginFrames(bool video_needs_begin_frames); diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc index d83599c8c71..8c617561858 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.cc +++ b/chromium/cc/scheduler/scheduler_state_machine.cc @@ -17,7 +17,7 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) : settings_(settings), output_surface_state_(OUTPUT_SURFACE_LOST), begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE), - commit_state_(COMMIT_STATE_IDLE), + begin_main_frame_state_(BEGIN_MAIN_FRAME_STATE_IDLE), forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), commit_count_(0), current_frame_number_(0), @@ -38,7 +38,7 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) needs_redraw_(false), needs_animate_(false), needs_prepare_tiles_(false), - needs_commit_(false), + needs_begin_main_frame_(false), visible_(false), can_start_(false), can_draw_(false), @@ -47,16 +47,15 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) active_tree_needs_first_draw_(false), did_create_and_initialize_first_output_surface_(false), impl_latency_takes_priority_(false), + main_thread_missed_last_deadline_(false), skip_next_begin_main_frame_to_reduce_latency_(false), - continuous_painting_(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), + wait_for_ready_to_draw_(false), did_request_swap_in_last_frame_(false), - did_perform_swap_in_last_draw_(false) { -} + did_perform_swap_in_last_draw_(false) {} const char* SchedulerStateMachine::OutputSurfaceStateToString( OutputSurfaceState state) { @@ -110,20 +109,21 @@ const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString( return "???"; } -const char* SchedulerStateMachine::CommitStateToString(CommitState state) { +const char* SchedulerStateMachine::BeginMainFrameStateToString( + BeginMainFrameState state) { switch (state) { - case COMMIT_STATE_IDLE: - return "COMMIT_STATE_IDLE"; - case COMMIT_STATE_BEGIN_MAIN_FRAME_SENT: - return "COMMIT_STATE_BEGIN_MAIN_FRAME_SENT"; - case COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED: - return "COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED"; - case COMMIT_STATE_READY_TO_COMMIT: - 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"; + case BEGIN_MAIN_FRAME_STATE_IDLE: + return "BEGIN_MAIN_FRAME_STATE_IDLE"; + case BEGIN_MAIN_FRAME_STATE_SENT: + return "BEGIN_MAIN_FRAME_STATE_SENT"; + case BEGIN_MAIN_FRAME_STATE_STARTED: + return "BEGIN_MAIN_FRAME_STATE_STARTED"; + case BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT: + return "BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT"; + case BEGIN_MAIN_FRAME_STATE_WAITING_FOR_ACTIVATION: + return "BEGIN_MAIN_FRAME_STATE_WAITING_FOR_ACTIVATION"; + case BEGIN_MAIN_FRAME_STATE_WAITING_FOR_DRAW: + return "BEGIN_MAIN_FRAME_STATE_WAITING_FOR_DRAW"; } NOTREACHED(); return "???"; @@ -188,7 +188,8 @@ void SchedulerStateMachine::AsValueInto( state->SetString("next_action", ActionToString(NextAction())); state->SetString("begin_impl_frame_state", BeginImplFrameStateToString(begin_impl_frame_state_)); - state->SetString("commit_state", CommitStateToString(commit_state_)); + state->SetString("begin_main_frame_state", + BeginMainFrameStateToString(begin_main_frame_state_)); state->SetString("output_surface_state_", OutputSurfaceStateToString(output_surface_state_)); state->SetString("forced_redraw_state", @@ -222,7 +223,7 @@ void SchedulerStateMachine::AsValueInto( state->SetBoolean("needs_redraw", needs_redraw_); state->SetBoolean("needs_animate_", needs_animate_); state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); - state->SetBoolean("needs_commit", needs_commit_); + state->SetBoolean("needs_begin_main_frame", needs_begin_main_frame_); state->SetBoolean("visible", visible_); state->SetBoolean("can_start", can_start_); state->SetBoolean("can_draw", can_draw_); @@ -231,17 +232,15 @@ void SchedulerStateMachine::AsValueInto( pending_tree_is_ready_for_activation_); state->SetBoolean("active_tree_needs_first_draw", active_tree_needs_first_draw_); - state->SetBoolean("wait_for_active_tree_ready_to_draw", - wait_for_active_tree_ready_to_draw_); + state->SetBoolean("wait_for_ready_to_draw", wait_for_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", impl_latency_takes_priority_); - state->SetBoolean("main_thread_is_in_high_latency_mode", - MainThreadIsInHighLatencyMode()); + state->SetBoolean("main_thread_missed_last_deadline", + main_thread_missed_last_deadline_); 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("children_need_begin_frames", children_need_begin_frames_); state->SetBoolean("video_needs_begin_frames", video_needs_begin_frames_); state->SetBoolean("defer_commits", defer_commits_); @@ -254,19 +253,21 @@ void SchedulerStateMachine::AsValueInto( } bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { + // Normally when |visible_| is false, pending activations will be forced and + // draws will be aborted. However, when the embedder is Android WebView, + // software draws could be scheduled by the Android OS at any time and draws + // should not be aborted in this case. + bool is_output_surface_lost = (output_surface_state_ == OUTPUT_SURFACE_LOST); + if (settings_.using_synchronous_renderer_compositor) + return is_output_surface_lost || !can_draw_; + // 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, // we might deadlock with the main thread. // This should be a superset of PendingActivationsShouldBeForced() since // activation of the pending tree is blocked by drawing of the active tree and // the main thread might be blocked on activation of the most recent commit. - if (PendingActivationsShouldBeForced()) - return true; - - // Additional states where we should abort draws. - if (!can_draw_) - return true; - return false; + return is_output_surface_lost || !can_draw_ || !visible_; } bool SchedulerStateMachine::PendingActivationsShouldBeForced() const { @@ -290,13 +291,16 @@ bool SchedulerStateMachine::PendingActivationsShouldBeForced() const { } bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const { + if (!visible_) + return false; + // Don't try to initialize too early. if (!can_start_) return false; // We only want to start output surface initialization after the // previous commit is complete. - if (commit_state_ != COMMIT_STATE_IDLE) + if (begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE) return false; // Make sure the BeginImplFrame from any previous OutputSurfaces @@ -387,7 +391,7 @@ bool SchedulerStateMachine::ShouldAnimate() const { } bool SchedulerStateMachine::CouldSendBeginMainFrame() const { - if (!needs_commit_) + if (!needs_begin_main_frame_) return false; // We can not perform commits if we are not visible. @@ -426,7 +430,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { // Other parts of the state machine indirectly defer the BeginMainFrame // by transitioning to WAITING commit states rather than going // immediately to IDLE. - if (commit_state_ != COMMIT_STATE_IDLE) + if (begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE) return false; // Don't send BeginMainFrame early if we are prioritizing the active tree @@ -482,7 +486,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { } bool SchedulerStateMachine::ShouldCommit() const { - if (commit_state_ != COMMIT_STATE_READY_TO_COMMIT) + if (begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT) return false; // We must not finish the commit until the pending tree is free. @@ -559,57 +563,7 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { return ACTION_NONE; } -void SchedulerStateMachine::UpdateState(Action action) { - switch (action) { - case ACTION_NONE: - return; - - case ACTION_ACTIVATE_SYNC_TREE: - UpdateStateOnActivation(); - return; - - case ACTION_ANIMATE: - UpdateStateOnAnimate(); - return; - - case ACTION_SEND_BEGIN_MAIN_FRAME: - UpdateStateOnSendBeginMainFrame(); - return; - - case ACTION_COMMIT: { - bool commit_has_no_updates = false; - UpdateStateOnCommit(commit_has_no_updates); - return; - } - - case ACTION_DRAW_AND_SWAP_FORCED: - case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: { - bool did_request_swap = true; - UpdateStateOnDraw(did_request_swap); - return; - } - - case ACTION_DRAW_AND_SWAP_ABORT: { - bool did_request_swap = false; - UpdateStateOnDraw(did_request_swap); - return; - } - - case ACTION_BEGIN_OUTPUT_SURFACE_CREATION: - UpdateStateOnBeginOutputSurfaceCreation(); - return; - - case ACTION_PREPARE_TILES: - UpdateStateOnPrepareTiles(); - return; - - case ACTION_INVALIDATE_OUTPUT_SURFACE: - UpdateStateOnInvalidateOutputSurface(); - return; - } -} - -void SchedulerStateMachine::UpdateStateOnAnimate() { +void SchedulerStateMachine::WillAnimate() { DCHECK(!animate_funnel_); last_frame_number_animate_performed_ = current_frame_number_; animate_funnel_ = true; @@ -618,17 +572,17 @@ void SchedulerStateMachine::UpdateStateOnAnimate() { SetNeedsRedraw(); } -void SchedulerStateMachine::UpdateStateOnSendBeginMainFrame() { +void SchedulerStateMachine::WillSendBeginMainFrame() { 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; + begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_SENT; + needs_begin_main_frame_ = 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) { +void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) { commit_count_++; // Animate after commit even if we've already animated. @@ -636,14 +590,17 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { animate_funnel_ = false; if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) { - commit_state_ = COMMIT_STATE_IDLE; + begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE; } else { - commit_state_ = COMMIT_STATE_WAITING_FOR_ACTIVATION; + begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_WAITING_FOR_ACTIVATION; } // If the commit was aborted, then there is no pending tree. has_pending_tree_ = !commit_has_no_updates; + wait_for_ready_to_draw_ = + !commit_has_no_updates && settings_.commit_to_active_tree; + // Update state related to forced draws. if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) { forced_redraw_state_ = has_pending_tree_ @@ -658,15 +615,14 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION; } else { output_surface_state_ = OUTPUT_SURFACE_ACTIVE; - needs_redraw_ = true; } } - // 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_has_no_updates || - forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) { + // Update state if there's no updates heading for the active tree, but we need + // to do a forced draw. + if (commit_has_no_updates && + forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) { + DCHECK(!has_pending_tree_); needs_redraw_ = true; active_tree_needs_first_draw_ = true; } @@ -674,16 +630,15 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { // This post-commit work is common to both completed and aborted commits. pending_tree_is_ready_for_activation_ = false; - 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_ = settings_.commit_to_active_tree - ? COMMIT_STATE_WAITING_FOR_DRAW - : COMMIT_STATE_IDLE; +void SchedulerStateMachine::WillActivate() { + if (begin_main_frame_state_ == + BEGIN_MAIN_FRAME_STATE_WAITING_FOR_ACTIVATION) { + begin_main_frame_state_ = settings_.commit_to_active_tree + ? BEGIN_MAIN_FRAME_STATE_WAITING_FOR_DRAW + : BEGIN_MAIN_FRAME_STATE_IDLE; } if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION) @@ -698,12 +653,12 @@ void SchedulerStateMachine::UpdateStateOnActivation() { needs_redraw_ = true; } -void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) { +void SchedulerStateMachine::WillDraw(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; + if (begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_WAITING_FOR_DRAW) + begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE; needs_redraw_ = false; active_tree_needs_first_draw_ = false; @@ -716,23 +671,23 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) { } } -void SchedulerStateMachine::UpdateStateOnPrepareTiles() { +void SchedulerStateMachine::WillPrepareTiles() { needs_prepare_tiles_ = false; } -void SchedulerStateMachine::UpdateStateOnBeginOutputSurfaceCreation() { +void SchedulerStateMachine::WillBeginOutputSurfaceCreation() { 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_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_IDLE); DCHECK(!has_pending_tree_); DCHECK(!active_tree_needs_first_draw_); } -void SchedulerStateMachine::UpdateStateOnInvalidateOutputSurface() { +void SchedulerStateMachine::WillInvalidateOutputSurface() { DCHECK(!invalidate_output_surface_funnel_); invalidate_output_surface_funnel_ = true; last_frame_number_invalidate_output_surface_performed_ = @@ -754,6 +709,7 @@ void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() { bool SchedulerStateMachine::BeginFrameRequiredForChildren() const { return children_need_begin_frames_; } + bool SchedulerStateMachine::BeginFrameNeededForVideo() const { return video_needs_begin_frames_; } @@ -794,7 +750,8 @@ bool SchedulerStateMachine::BeginFrameRequiredForAction() const { if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) return true; - return needs_animate_ || needs_redraw_ || (needs_commit_ && !defer_commits_); + return needs_animate_ || needs_redraw_ || + (needs_begin_main_frame_ && !defer_commits_); } // These are cases where we are very likely want a BeginFrame message in the @@ -813,7 +770,8 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const { // 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_) + if ((begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE) && + !defer_commits_) return true; // If the pending tree activates quickly, we'll want a BeginImplFrame soon @@ -883,6 +841,11 @@ void SchedulerStateMachine::OnBeginImplFrameIdle() { skip_next_begin_main_frame_to_reduce_latency_ = false; + // If a new or undrawn active tree is pending after the deadline, + // then the main thread is in a high latency mode. + main_thread_missed_last_deadline_ = + CommitPending() || has_pending_tree_ || active_tree_needs_first_draw_; + // If we're entering a state where we won't get BeginFrames set all the // funnels so that we don't perform any actions that we shouldn't. if (!BeginFrameNeeded()) @@ -894,12 +857,12 @@ 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_) { + } else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { + return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE; + } else if (wait_for_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_ && !SwapThrottled()) { // 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. @@ -915,13 +878,15 @@ SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() const { - if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) - return false; - // If we just forced activation, we should end the deadline right now. if (PendingActivationsShouldBeForced() && !has_pending_tree_) return true; + // Do not trigger deadline immediately if we're waiting for READY_TO_DRAW + // unless it's one of the forced cases. + if (wait_for_ready_to_draw_) + return false; + // SwapAck throttle the deadline since we wont draw and swap anyway. if (SwapThrottled()) return false; @@ -937,7 +902,8 @@ bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() // don't have a pending tree -- otherwise we should give it a chance to // activate. // TODO(skyostil): Revisit this when we have more accurate deadline estimates. - if (commit_state_ == COMMIT_STATE_IDLE && !has_pending_tree_) + if (begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_IDLE && + !has_pending_tree_) return true; // Prioritize impl-thread draws in impl_latency_takes_priority_ mode. @@ -947,45 +913,8 @@ bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() return false; } -bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { - // If a commit is pending before the previous commit has been drawn, we - // are definitely in a high latency mode. - if (CommitPending() && (active_tree_needs_first_draw_ || has_pending_tree_)) - return true; - - // If we just sent a BeginMainFrame and haven't hit the deadline yet, the main - // thread is in a low latency mode. - 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; - - // If there's a commit in progress it must either be from the previous frame - // or it started after the impl thread's deadline. In either case the main - // thread is in high latency mode. - if (CommitPending()) - return true; - - // Similarly, if there's a pending tree the main thread is in high latency - // mode, because either - // it's from the previous frame - // or - // we're currently drawing the active tree and the pending tree will thus - // only be drawn in the next frame. - if (has_pending_tree_) - return true; - - if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) { - // 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_ || 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 - // main thread is in a high latency mode. - return active_tree_needs_first_draw_; +bool SchedulerStateMachine::main_thread_missed_last_deadline() const { + return main_thread_missed_last_deadline_; } bool SchedulerStateMachine::SwapThrottled() const { @@ -993,9 +922,17 @@ bool SchedulerStateMachine::SwapThrottled() const { } void SchedulerStateMachine::SetVisible(bool visible) { + if (visible_ == visible) + return; + visible_ = visible; + + if (visible) + main_thread_missed_last_deadline_ = false; + // TODO(sunnyps): Change the funnel to a bool to avoid hacks like this. prepare_tiles_funnel_ = 0; + wait_for_ready_to_draw_ = false; } void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; } @@ -1006,14 +943,12 @@ void SchedulerStateMachine::SetNeedsAnimate() { needs_animate_ = true; } -void SchedulerStateMachine::SetWaitForReadyToDraw() { - wait_for_active_tree_ready_to_draw_ = true; -} - bool SchedulerStateMachine::OnlyImplSideUpdatesExpected() const { bool has_impl_updates = needs_redraw_ || needs_animate_; bool main_updates_expected = - needs_commit_ || commit_state_ != COMMIT_STATE_IDLE || has_pending_tree_; + needs_begin_main_frame_ || + begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE || + has_pending_tree_; return has_impl_updates && !main_updates_expected; } @@ -1069,7 +1004,7 @@ void SchedulerStateMachine::DidDrawIfPossibleCompleted(DrawResult result) { if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE) return; - needs_commit_ = true; + needs_begin_main_frame_ = true; consecutive_checkerboard_animations_++; if (settings_.timeout_and_draw_when_animation_checkerboards && consecutive_checkerboard_animations_ >= @@ -1085,19 +1020,19 @@ void SchedulerStateMachine::DidDrawIfPossibleCompleted(DrawResult result) { // pictures (which requires a commit) or because of memory pressure // removing textures (which might not). To be safe, request a commit // anyway. - needs_commit_ = true; + needs_begin_main_frame_ = true; break; } } -void SchedulerStateMachine::SetNeedsCommit() { - needs_commit_ = true; +void SchedulerStateMachine::SetNeedsBeginMainFrame() { + needs_begin_main_frame_ = true; } void SchedulerStateMachine::NotifyReadyToCommit() { - DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED) + DCHECK(begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_STARTED) << AsValue()->ToString(); - commit_state_ = COMMIT_STATE_READY_TO_COMMIT; + begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT; // In commit_to_active_tree mode, commit should happen right after // BeginFrame, meaning when this function is called, next action should be // commit. @@ -1106,17 +1041,17 @@ void SchedulerStateMachine::NotifyReadyToCommit() { } void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) { - DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); + DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_SENT); switch (reason) { case CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST: case CommitEarlyOutReason::ABORTED_NOT_VISIBLE: case CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT: - commit_state_ = COMMIT_STATE_IDLE; - SetNeedsCommit(); + begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE; + SetNeedsBeginMainFrame(); return; case CommitEarlyOutReason::FINISHED_NO_UPDATES: bool commit_has_no_updates = true; - UpdateStateOnCommit(commit_has_no_updates); + WillCommit(commit_has_no_updates); return; } } @@ -1133,7 +1068,7 @@ void SchedulerStateMachine::DidLoseOutputSurface() { return; output_surface_state_ = OUTPUT_SURFACE_LOST; needs_redraw_ = false; - wait_for_active_tree_ready_to_draw_ = false; + wait_for_ready_to_draw_ = false; } void SchedulerStateMachine::NotifyReadyToActivate() { @@ -1142,7 +1077,7 @@ void SchedulerStateMachine::NotifyReadyToActivate() { } void SchedulerStateMachine::NotifyReadyToDraw() { - wait_for_active_tree_ready_to_draw_ = false; + wait_for_ready_to_draw_ = false; } void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() { @@ -1152,16 +1087,17 @@ void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() { if (did_create_and_initialize_first_output_surface_) { // TODO(boliu): See if we can remove this when impl-side painting is always // on. Does anything on the main thread need to update after recreate? - needs_commit_ = true; + needs_begin_main_frame_ = true; } did_create_and_initialize_first_output_surface_ = true; pending_swaps_ = 0; swaps_with_current_output_surface_ = 0; + main_thread_missed_last_deadline_ = false; } void SchedulerStateMachine::NotifyBeginMainFrameStarted() { - DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); - commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED; + DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_SENT); + begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_STARTED; } bool SchedulerStateMachine::HasInitializedOutputSurface() const { diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h index cf1ab8c5568..d84211abc47 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.h +++ b/chromium/cc/scheduler/scheduler_state_machine.h @@ -72,15 +72,15 @@ class CC_EXPORT SchedulerStateMachine { 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, + enum BeginMainFrameState { + BEGIN_MAIN_FRAME_STATE_IDLE, + BEGIN_MAIN_FRAME_STATE_SENT, + BEGIN_MAIN_FRAME_STATE_STARTED, + BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT, + BEGIN_MAIN_FRAME_STATE_WAITING_FOR_ACTIVATION, + BEGIN_MAIN_FRAME_STATE_WAITING_FOR_DRAW, }; - static const char* CommitStateToString(CommitState state); + static const char* BeginMainFrameStateToString(BeginMainFrameState state); enum ForcedRedrawOnTimeoutState { FORCED_REDRAW_STATE_IDLE, @@ -92,11 +92,13 @@ class CC_EXPORT SchedulerStateMachine { ForcedRedrawOnTimeoutState state); bool CommitPending() const { - return commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || - commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED || - commit_state_ == COMMIT_STATE_READY_TO_COMMIT; + return begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_SENT || + begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_STARTED || + begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT; + } + BeginMainFrameState begin_main_frame_state() const { + return begin_main_frame_state_; } - CommitState commit_state() const { return commit_state_; } bool RedrawPending() const { return needs_redraw_; } bool PrepareTilesPending() const { return needs_prepare_tiles_; } @@ -120,7 +122,14 @@ class CC_EXPORT SchedulerStateMachine { void AsValueInto(base::trace_event::TracedValue* dict) const; Action NextAction() const; - void UpdateState(Action action); + void WillAnimate(); + void WillSendBeginMainFrame(); + void WillCommit(bool commit_had_no_updates); + void WillActivate(); + void WillDraw(bool did_request_swap); + void WillBeginOutputSurfaceCreation(); + void WillPrepareTiles(); + void WillInvalidateOutputSurface(); // Indicates whether the impl thread needs a BeginImplFrame callback in order // to make progress. @@ -143,7 +152,7 @@ class CC_EXPORT SchedulerStateMachine { // 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; + bool main_thread_missed_last_deadline() const; bool SwapThrottled() const; @@ -165,9 +174,6 @@ class CC_EXPORT SchedulerStateMachine { // 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); @@ -195,11 +201,11 @@ class CC_EXPORT SchedulerStateMachine { // Indicates whether ACTION_DRAW_AND_SWAP_IF_POSSIBLE drew to the screen. void DidDrawIfPossibleCompleted(DrawResult result); - // Indicates that a new commit flow needs to be performed, either to pull - // updates from the main thread to the impl, or to push deltas from the impl - // thread to main. - void SetNeedsCommit(); - bool needs_commit() const { return needs_commit_; } + // Indicates that a new begin main frame flow needs to be performed, either + // to pull updates from the main thread to the impl, or to push deltas from + // the impl thread to main. + void SetNeedsBeginMainFrame(); + bool needs_begin_main_frame() const { return needs_begin_main_frame_; } // Call this only in response to receiving an ACTION_SEND_BEGIN_MAIN_FRAME // from NextAction. @@ -245,10 +251,6 @@ class CC_EXPORT SchedulerStateMachine { // True if we need to abort draws to make forward progress. bool PendingDrawsShouldBeAborted() const; - void SetContinuousPainting(bool continuous_painting) { - continuous_painting_ = continuous_painting; - } - bool CouldSendBeginMainFrame() const; void SetDeferCommits(bool defer_commits); @@ -270,6 +272,7 @@ class CC_EXPORT SchedulerStateMachine { bool ShouldTriggerBeginImplFrameDeadlineImmediately() const; // True if we need to force activations to make forward progress. + // TODO(sunnyps): Rename this to ShouldAbortCurrentFrame or similar. bool PendingActivationsShouldBeForced() const; // TODO(brianderson): Remove this once NPAPI support is removed. @@ -284,20 +287,11 @@ class CC_EXPORT SchedulerStateMachine { bool ShouldPrepareTiles() const; bool ShouldInvalidateOutputSurface() const; - void UpdateStateOnAnimate(); - void UpdateStateOnSendBeginMainFrame(); - void UpdateStateOnCommit(bool commit_had_no_updates); - void UpdateStateOnActivation(); - void UpdateStateOnDraw(bool did_request_swap); - void UpdateStateOnBeginOutputSurfaceCreation(); - void UpdateStateOnPrepareTiles(); - void UpdateStateOnInvalidateOutputSurface(); - const SchedulerSettings settings_; OutputSurfaceState output_surface_state_; BeginImplFrameState begin_impl_frame_state_; - CommitState commit_state_; + BeginMainFrameState begin_main_frame_state_; ForcedRedrawOnTimeoutState forced_redraw_state_; // These are used for tracing only. @@ -328,7 +322,7 @@ class CC_EXPORT SchedulerStateMachine { bool needs_redraw_; bool needs_animate_; bool needs_prepare_tiles_; - bool needs_commit_; + bool needs_begin_main_frame_; bool visible_; bool can_start_; bool can_draw_; @@ -337,13 +331,13 @@ class CC_EXPORT SchedulerStateMachine { bool active_tree_needs_first_draw_; bool did_create_and_initialize_first_output_surface_; bool impl_latency_takes_priority_; + bool main_thread_missed_last_deadline_; bool skip_next_begin_main_frame_to_reduce_latency_; - bool continuous_painting_; 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 wait_for_ready_to_draw_; bool did_request_swap_in_last_frame_; bool did_perform_swap_in_last_draw_; diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc index da40cc15017..6d00594dc86 100644 --- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc @@ -25,8 +25,9 @@ state.begin_impl_frame_state()) \ << state.AsValue()->ToString() -#define EXPECT_COMMIT_STATE(expected) \ - EXPECT_ENUM_EQ(CommitStateToString, expected, state.CommitState()) +#define EXPECT_MAIN_FRAME_STATE(expected) \ + EXPECT_ENUM_EQ(BeginMainFrameStateToString, expected, \ + state.BeginMainFrameState()) #define EXPECT_ACTION(expected) \ EXPECT_ENUM_EQ(ActionToString, expected, state.NextAction()) \ @@ -39,7 +40,7 @@ EXPECT_IMPL_FRAME_STATE( \ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); \ } \ - state.UpdateState(action); \ + WillPerformAction(&state, action); \ if (action == SchedulerStateMachine::ACTION_NONE) { \ if (state.begin_impl_frame_state() == \ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) \ @@ -49,30 +50,83 @@ state.OnBeginImplFrameIdle(); \ } -#define SET_UP_STATE(state) \ - state.SetCanStart(); \ - state.UpdateState(state.NextAction()); \ - state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); \ - state.SetVisible(true); \ +#define SET_UP_STATE(state) \ + state.SetCanStart(); \ + state.SetVisible(true); \ + EXPECT_ACTION_UPDATE_STATE( \ + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); \ + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); \ + state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); \ state.SetCanDraw(true); namespace cc { namespace { +void WillPerformAction(SchedulerStateMachine* sm, + SchedulerStateMachine::Action action) { + switch (action) { + case SchedulerStateMachine::ACTION_NONE: + return; + + case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE: + sm->WillActivate(); + return; + + case SchedulerStateMachine::ACTION_ANIMATE: + sm->WillAnimate(); + return; + + case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: + sm->WillSendBeginMainFrame(); + return; + + case SchedulerStateMachine::ACTION_COMMIT: { + bool commit_has_no_updates = false; + sm->WillCommit(commit_has_no_updates); + return; + } + + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: { + bool did_request_swap = true; + sm->WillDraw(did_request_swap); + return; + } + + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: { + bool did_request_swap = false; + sm->WillDraw(did_request_swap); + return; + } + + case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: + sm->WillBeginOutputSurfaceCreation(); + return; + + case SchedulerStateMachine::ACTION_PREPARE_TILES: + sm->WillPrepareTiles(); + return; + + case SchedulerStateMachine::ACTION_INVALIDATE_OUTPUT_SURFACE: + sm->WillInvalidateOutputSurface(); + return; + } +} + const SchedulerStateMachine::BeginImplFrameState all_begin_impl_frame_states[] = {SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE, SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME, SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, }; -const SchedulerStateMachine::CommitState all_commit_states[] = { - SchedulerStateMachine::COMMIT_STATE_IDLE, - 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_DRAW}; +const SchedulerStateMachine::BeginMainFrameState begin_main_frame_states[] = { + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE, + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT, + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_STARTED, + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT, + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_WAITING_FOR_ACTIVATION, + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_WAITING_FOR_DRAW}; // Exposes the protected state fields of the SchedulerStateMachine for testing class StateMachine : public SchedulerStateMachine { @@ -85,8 +139,12 @@ class StateMachine : public SchedulerStateMachine { output_surface_state_ = OUTPUT_SURFACE_ACTIVE; } - void SetCommitState(CommitState cs) { commit_state_ = cs; } - CommitState CommitState() const { return commit_state_; } + void SetBeginMainFrameState(BeginMainFrameState cs) { + begin_main_frame_state_ = cs; + } + BeginMainFrameState BeginMainFrameState() const { + return begin_main_frame_state_; + } ForcedRedrawOnTimeoutState ForcedRedrawState() const { return forced_redraw_state_; @@ -104,11 +162,11 @@ class StateMachine : public SchedulerStateMachine { return output_surface_state_; } - void SetNeedsCommitForTest(bool needs_commit) { - needs_commit_ = needs_commit; + void SetNeedsBeginMainFrameForTest(bool needs_begin_main_frame) { + needs_begin_main_frame_ = needs_begin_main_frame; } - bool NeedsCommit() const { return needs_commit_; } + bool NeedsCommit() const { return needs_begin_main_frame_; } void SetNeedsAnimateForTest(bool needs_animate) { needs_animate_ = needs_animate; @@ -141,20 +199,22 @@ class StateMachine : public SchedulerStateMachine { using SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately; using SchedulerStateMachine::ProactiveBeginFrameWanted; - using SchedulerStateMachine::UpdateStateOnCommit; + using SchedulerStateMachine::WillCommit; }; TEST(SchedulerStateMachineTest, BeginFrameNeeded) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); + state.SetVisible(true); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION) + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); - state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE); + state.SetBeginMainFrameState( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); // Don't request BeginFrames if we are idle. - state.SetVisible(true); state.SetNeedsRedraw(false); state.SetNeedsAnimateForTest(false); EXPECT_FALSE(state.BeginFrameNeeded()); @@ -175,7 +235,7 @@ TEST(SchedulerStateMachineTest, BeginFrameNeeded) { state.SetVisible(true); state.SetNeedsRedraw(false); state.SetNeedsAnimateForTest(false); - state.SetNeedsCommitForTest(true); + state.SetNeedsBeginMainFrameForTest(true); EXPECT_TRUE(state.BeginFrameNeeded()); // Don't request BeginFrames when commit is pending if @@ -183,7 +243,7 @@ TEST(SchedulerStateMachineTest, BeginFrameNeeded) { state.SetVisible(true); state.SetNeedsRedraw(false); state.SetNeedsAnimateForTest(false); - state.SetNeedsCommitForTest(true); + state.SetNeedsBeginMainFrameForTest(true); state.SetDeferCommits(true); EXPECT_FALSE(state.BeginFrameNeeded()); } @@ -195,12 +255,14 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { { StateMachine state(default_scheduler_settings); state.SetCanStart(); + state.SetVisible(true); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION) + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); - state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE); + state.SetBeginMainFrameState( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); state.SetNeedsRedraw(false); - state.SetVisible(true); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_FALSE(state.NeedsCommit()); @@ -216,10 +278,11 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { // If commit requested but can_start is still false, do nothing. { StateMachine state(default_scheduler_settings); - state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE); + state.SetBeginMainFrameState( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); state.SetNeedsRedraw(false); state.SetVisible(true); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.NeedsCommit()); @@ -235,17 +298,20 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { // If commit requested, begin a main frame. { StateMachine state(default_scheduler_settings); - state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE); + state.SetBeginMainFrameState( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetNeedsRedraw(false); - state.SetVisible(true); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); // Expect nothing to happen until after OnBeginImplFrame. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); EXPECT_TRUE(state.NeedsCommit()); EXPECT_TRUE(state.BeginFrameNeeded()); @@ -253,34 +319,35 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) { state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); - EXPECT_COMMIT_STATE( - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); EXPECT_FALSE(state.NeedsCommit()); } // If commit requested and can't draw, still begin a main frame. { StateMachine state(default_scheduler_settings); - state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE); + state.SetBeginMainFrameState( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetNeedsRedraw(false); - state.SetVisible(true); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.SetCanDraw(false); // Expect nothing to happen until after OnBeginImplFrame. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); EXPECT_TRUE(state.BeginFrameNeeded()); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); - EXPECT_COMMIT_STATE( - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); EXPECT_FALSE(state.NeedsCommit()); } } @@ -290,10 +357,11 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) { SchedulerSettings scheduler_settings; scheduler_settings.main_frame_before_activation_enabled = true; StateMachine state(scheduler_settings); - state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE); + state.SetBeginMainFrameState( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); SET_UP_STATE(state) state.SetNeedsRedraw(false); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_TRUE(state.BeginFrameNeeded()); @@ -307,13 +375,13 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) { state.NotifyReadyToCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_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.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -340,7 +408,7 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) { state.DidSwapBuffers(); state.DidSwapBuffersComplete(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); } TEST(SchedulerStateMachineTest, @@ -449,7 +517,7 @@ TEST(SchedulerStateMachineTest, SET_UP_STATE(state) // Start a commit. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( @@ -508,7 +576,7 @@ TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) { SET_UP_STATE(state) // Start a commit. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( @@ -643,30 +711,34 @@ TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginImplFrame) { // When not in BeginImplFrame deadline, or in BeginImplFrame deadline // but not visible, don't draw. - size_t num_commit_states = - sizeof(all_commit_states) / sizeof(SchedulerStateMachine::CommitState); + size_t num_begin_main_frame_states = + sizeof(begin_main_frame_states) / + sizeof(SchedulerStateMachine::BeginMainFrameState); size_t num_begin_impl_frame_states = sizeof(all_begin_impl_frame_states) / sizeof(SchedulerStateMachine::BeginImplFrameState); - for (size_t i = 0; i < num_commit_states; ++i) { + for (size_t i = 0; i < num_begin_main_frame_states; ++i) { for (size_t j = 0; j < num_begin_impl_frame_states; ++j) { StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); - state.SetCommitState(all_commit_states[i]); + state.SetBeginMainFrameState(begin_main_frame_states[i]); state.SetBeginImplFrameState(all_begin_impl_frame_states[j]); bool visible = (all_begin_impl_frame_states[j] != SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); state.SetVisible(visible); - // Case 1: needs_commit=false + // Case 1: needs_begin_main_frame=false EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE, state.NextAction()); - // Case 2: needs_commit=true - state.SetNeedsCommit(); + // Case 2: needs_begin_main_frame=true + state.SetNeedsBeginMainFrame(); EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE, state.NextAction()) << state.AsValue()->ToString(); @@ -675,51 +747,56 @@ TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginImplFrame) { // When in BeginImplFrame deadline we should always draw for SetNeedsRedraw // except if we're ready to commit, in which case we expect a commit first. - for (size_t i = 0; i < num_commit_states; ++i) { + for (size_t i = 0; i < num_begin_main_frame_states; ++i) { StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetCanDraw(true); - state.SetCommitState(all_commit_states[i]); + state.SetBeginMainFrameState(begin_main_frame_states[i]); state.SetBeginImplFrameState( SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); state.SetNeedsRedraw(true); - state.SetVisible(true); SchedulerStateMachine::Action expected_action; - if (all_commit_states[i] == - SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT) { + if (begin_main_frame_states[i] == + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT) { expected_action = SchedulerStateMachine::ACTION_COMMIT; } else { expected_action = SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE; - EXPECT_ACTION(SchedulerStateMachine::ACTION_ANIMATE); - state.UpdateState(state.NextAction()); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); } - // Case 1: needs_commit=false. + // Case 1: needs_begin_main_frame=false. EXPECT_ACTION(expected_action); - // Case 2: needs_commit=true. - state.SetNeedsCommit(); + // Case 2: needs_begin_main_frame=true. + state.SetNeedsBeginMainFrame(); EXPECT_ACTION(expected_action); } } -TEST(SchedulerStateMachineTest, TestNoCommitStatesRedrawWhenInvisible) { +TEST(SchedulerStateMachineTest, TestNoBeginMainFrameStatesRedrawWhenInvisible) { SchedulerSettings default_scheduler_settings; - size_t num_commit_states = - sizeof(all_commit_states) / sizeof(SchedulerStateMachine::CommitState); - for (size_t i = 0; i < num_commit_states; ++i) { + size_t num_begin_main_frame_states = + sizeof(begin_main_frame_states) / + sizeof(SchedulerStateMachine::BeginMainFrameState); + for (size_t i = 0; i < num_begin_main_frame_states; ++i) { // There shouldn't be any drawing regardless of BeginImplFrame. for (size_t j = 0; j < 2; ++j) { StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); - state.SetCommitState(all_commit_states[i]); + state.SetBeginMainFrameState(begin_main_frame_states[i]); state.SetVisible(false); state.SetNeedsRedraw(true); if (j == 1) { @@ -727,12 +804,12 @@ TEST(SchedulerStateMachineTest, TestNoCommitStatesRedrawWhenInvisible) { SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); } - // Case 1: needs_commit=false. + // Case 1: needs_begin_main_frame=false. EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE, state.NextAction()); - // Case 2: needs_commit=true. - state.SetNeedsCommit(); + // Case 2: needs_begin_main_frame=true. + state.SetNeedsBeginMainFrame(); EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE, state.NextAction()) << state.AsValue()->ToString(); @@ -743,16 +820,20 @@ TEST(SchedulerStateMachineTest, TestNoCommitStatesRedrawWhenInvisible) { TEST(SchedulerStateMachineTest, TestCanRedraw_StopsDraw) { SchedulerSettings default_scheduler_settings; - size_t num_commit_states = - sizeof(all_commit_states) / sizeof(SchedulerStateMachine::CommitState); - for (size_t i = 0; i < num_commit_states; ++i) { + size_t num_begin_main_frame_states = + sizeof(begin_main_frame_states) / + sizeof(SchedulerStateMachine::BeginMainFrameState); + for (size_t i = 0; i < num_begin_main_frame_states; ++i) { // There shouldn't be any drawing regardless of BeginImplFrame. for (size_t j = 0; j < 2; ++j) { StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); - state.SetCommitState(all_commit_states[i]); + state.SetBeginMainFrameState(begin_main_frame_states[i]); state.SetVisible(false); state.SetNeedsRedraw(true); if (j == 1) @@ -770,13 +851,15 @@ TEST(SchedulerStateMachineTest, SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetActiveTreeNeedsFirstDraw(true); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.SetNeedsRedraw(true); - state.SetVisible(true); state.SetCanDraw(false); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); @@ -795,11 +878,11 @@ TEST(SchedulerStateMachineTest, EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } -TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost) { +TEST(SchedulerStateMachineTest, TestSetNeedsBeginMainFrameIsNotLost) { SchedulerSettings scheduler_settings; StateMachine state(scheduler_settings); SET_UP_STATE(state) - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_TRUE(state.BeginFrameNeeded()); @@ -807,17 +890,17 @@ TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost) { state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); - EXPECT_COMMIT_STATE( - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); // Now, while the frame is in progress, set another commit. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_TRUE(state.NeedsCommit()); // Let the frame finish. state.NotifyBeginMainFrameStarted(); state.NotifyReadyToCommit(); - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT); + EXPECT_MAIN_FRAME_STATE( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT); // Expect to commit regardless of BeginImplFrame state. EXPECT_IMPL_FRAME_STATE( @@ -870,21 +953,21 @@ TEST(SchedulerStateMachineTest, TestFullCycle) { SET_UP_STATE(state) // Start clean and set commit. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); // 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_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_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); + EXPECT_MAIN_FRAME_STATE( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT); // Commit. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); @@ -909,7 +992,7 @@ TEST(SchedulerStateMachineTest, TestFullCycle) { // Should be synchronized, no draw needed, no action needed. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); EXPECT_FALSE(state.needs_redraw()); } @@ -919,7 +1002,7 @@ TEST(SchedulerStateMachineTest, CommitWithoutDrawWithPendingTree) { SET_UP_STATE(state) // Start clean and set commit. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); // Make a main frame, commit and activate it. But don't draw it. state.OnBeginImplFrame(); @@ -934,7 +1017,7 @@ TEST(SchedulerStateMachineTest, CommitWithoutDrawWithPendingTree) { // Try to make a new main frame before drawing. Since we will commit it to a // pending tree and not clobber the active tree, we're able to start a new // begin frame and commit it. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( @@ -951,7 +1034,7 @@ TEST(SchedulerStateMachineTest, DontCommitWithoutDrawWithoutPendingTree) { SET_UP_STATE(state) // Start clean and set commit. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); // Make a main frame, commit and activate it. But don't draw it. state.OnBeginImplFrame(); @@ -965,7 +1048,7 @@ TEST(SchedulerStateMachineTest, DontCommitWithoutDrawWithoutPendingTree) { // Try to make a new main frame before drawing, but since we would clobber the // active tree, we will not do so. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -978,33 +1061,33 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { SET_UP_STATE(state) // Start clean and set commit. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); // 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_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_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); + EXPECT_MAIN_FRAME_STATE( + SchedulerStateMachine::BEGIN_MAIN_FRAME_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); + EXPECT_MAIN_FRAME_STATE( + SchedulerStateMachine::BEGIN_MAIN_FRAME_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.SetNeedsBeginMainFrame(); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( @@ -1013,8 +1096,8 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { // Cannot BeginMainFrame yet since last commit is not yet activated and drawn. state.OnBeginImplFrame(); - EXPECT_COMMIT_STATE( - SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION); + EXPECT_MAIN_FRAME_STATE( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_WAITING_FOR_ACTIVATION); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Now activate sync tree. @@ -1023,7 +1106,8 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { 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); + EXPECT_MAIN_FRAME_STATE( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_WAITING_FOR_DRAW); // Swap throttled. Do not draw. state.DidSwapBuffers(); @@ -1046,7 +1130,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { state.DidSwapBuffersComplete(); // Now will be able to start main frame. - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); EXPECT_FALSE(state.needs_redraw()); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -1058,25 +1142,25 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) { SET_UP_STATE(state) // Start clean and set commit. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); // 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_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); EXPECT_FALSE(state.NeedsCommit()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Request another commit while the commit is in flight. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); 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); + EXPECT_MAIN_FRAME_STATE( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT); // First commit and activate. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); @@ -1099,7 +1183,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) { // Should be synchronized, no draw needed, no action needed. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); EXPECT_FALSE(state.needs_redraw()); // Next BeginImplFrame should initiate second commit. @@ -1108,16 +1192,40 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) { SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } -TEST(SchedulerStateMachineTest, TestRequestCommitInvisible) { +TEST(SchedulerStateMachineTest, TestNoRequestCommitWhenInvisible) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); - state.SetNeedsCommit(); + state.SetVisible(false); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } +TEST(SchedulerStateMachineTest, TestNoRequestOutputSurfaceWhenInvisible) { + SchedulerSettings default_scheduler_settings; + StateMachine state(default_scheduler_settings); + state.SetCanStart(); + // We should not request an OutputSurface when we are still invisible. + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); + state.SetVisible(false); + state.DidLoseOutputSurface(); + state.SetNeedsBeginMainFrame(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); +} + // See ThreadProxy::BeginMainFrame "EarlyOut_NotVisible" / // "EarlyOut_OutputSurfaceLost" cases. TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) { @@ -1126,14 +1234,13 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) { SET_UP_STATE(state) // Start clean and set commit. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); // Begin the frame while visible. state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); - EXPECT_COMMIT_STATE( - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); EXPECT_FALSE(state.NeedsCommit()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1146,7 +1253,7 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) { EXPECT_TRUE(state.NeedsCommit()); // We should now be back in the idle state as if we never started the frame. - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // We shouldn't do anything on the BeginImplFrame deadline. @@ -1158,7 +1265,7 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) { // Although we have aborted on this frame and haven't cancelled the commit // (i.e. need another), don't send another BeginMainFrame yet. - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.NeedsCommit()); @@ -1168,8 +1275,7 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseInvisible) { SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); // We should be starting the commit now. - EXPECT_COMMIT_STATE( - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } @@ -1178,18 +1284,19 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); - state.DidCreateAndInitializeOutputSurface(); state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.DidCreateAndInitializeOutputSurface(); state.SetCanDraw(true); // Get into a begin frame / commit state. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); - EXPECT_COMMIT_STATE( - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); EXPECT_FALSE(state.NeedsCommit()); EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE); @@ -1200,19 +1307,14 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) { // NeedsCommit should now be false because the commit was actually handled. EXPECT_FALSE(state.NeedsCommit()); - // Even though the commit was aborted, we still expect to draw the new frame. - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); + // Since the commit was aborted, we don't need to try and draw. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE( - 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_FALSE(state.NeedsCommit()); - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1220,8 +1322,8 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Verify another commit can start if requested, though. - state.SetNeedsCommit(); - EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE); + state.SetNeedsBeginMainFrame(); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE); state.OnBeginImplFrame(); EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } @@ -1238,14 +1340,14 @@ TEST(SchedulerStateMachineTest, TestFirstContextCreation) { state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - // Check that the first init does not SetNeedsCommit. + // Check that the first init does not SetNeedsBeginMainFrame. 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.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -1260,8 +1362,9 @@ TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) { state.NextAction()); state.DidLoseOutputSurface(); - EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); - state.UpdateState(state.NextAction()); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Once context recreation begins, nothing should happen. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1298,7 +1401,7 @@ TEST(SchedulerStateMachineTest, EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // While context is recreating, commits shouldn't begin. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -1319,8 +1422,7 @@ TEST(SchedulerStateMachineTest, EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_COMMIT_STATE( - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); + EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); // Until that commit finishes, we shouldn't be drawing or animate. state.OnBeginImplFrameDeadline(); @@ -1374,7 +1476,7 @@ TEST(SchedulerStateMachineTest, // 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.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( @@ -1405,7 +1507,7 @@ TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) { SET_UP_STATE(state) // Get a commit in flight. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); // Set damage and expect a draw. state.SetNeedsRedraw(true); @@ -1467,7 +1569,7 @@ TEST(SchedulerStateMachineTest, SET_UP_STATE(state) // Get a commit in flight. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Set damage and expect a draw. @@ -1489,7 +1591,7 @@ TEST(SchedulerStateMachineTest, // Ask for another draw and also set needs commit. Expect nothing happens. state.SetNeedsRedraw(true); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Finish the frame, and commit and activate. @@ -1557,8 +1659,9 @@ TEST(SchedulerStateMachineTest, DontDrawBeforeCommitAfterLostOutputSurface) { // Cause a lost output surface, and restore it. state.DidLoseOutputSurface(); - EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); - state.UpdateState(state.NextAction()); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.DidCreateAndInitializeOutputSurface(); EXPECT_FALSE(state.RedrawPending()); @@ -1572,8 +1675,8 @@ TEST(SchedulerStateMachineTest, StateMachine state(default_scheduler_settings); SET_UP_STATE(state) - state.SetCommitState( - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); + state.SetBeginMainFrameState( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); // Cause a lost context. state.DidLoseOutputSurface(); @@ -1593,9 +1696,11 @@ TEST(SchedulerStateMachineTest, TestNoBeginFrameNeededWhenInvisible) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); - state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); EXPECT_FALSE(state.BeginFrameNeeded()); state.SetNeedsRedraw(true); @@ -1612,10 +1717,13 @@ TEST(SchedulerStateMachineTest, TestNoBeginMainFrameWhenInvisible) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetVisible(false); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE); EXPECT_FALSE(state.BeginFrameNeeded()); @@ -1631,30 +1739,32 @@ TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); state.SetCanStart(); - state.UpdateState(state.NextAction()); + state.SetVisible(true); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); state.SetVisible(false); - state.SetCommitState( - SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); - state.SetNeedsCommit(); + state.SetBeginMainFrameState( + SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_SENT); + state.SetNeedsBeginMainFrame(); + // After the commit completes, activation and draw happen immediately + // because we are not visible. state.NotifyBeginMainFrameStarted(); state.NotifyReadyToCommit(); - EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT); - state.UpdateState(state.NextAction()); - state.NotifyReadyToActivate(); - EXPECT_ACTION(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE); - state.UpdateState(state.NextAction()); - + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE); EXPECT_TRUE(state.active_tree_needs_first_draw()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); SET_UP_STATE(state) - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.DidLoseOutputSurface(); // When we are visible, we normally want to begin output surface creation @@ -1696,6 +1806,35 @@ TEST(SchedulerStateMachineTest, ReportIfNotDrawing) { EXPECT_FALSE(state.PendingDrawsShouldBeAborted()); } +TEST(SchedulerStateMachineTest, ForceDrawForSynchronousCompositor) { + SchedulerSettings scheduler_settings; + scheduler_settings.using_synchronous_renderer_compositor = true; + StateMachine state(scheduler_settings); + SET_UP_STATE(state) + EXPECT_FALSE(state.PendingDrawsShouldBeAborted()); + + state.SetVisible(false); + state.DidLoseOutputSurface(); + + state.SetCanDraw(false); + state.WillBeginOutputSurfaceCreation(); + state.DidCreateAndInitializeOutputSurface(); + EXPECT_TRUE(state.PendingDrawsShouldBeAborted()); + + state.SetCanDraw(true); + state.DidLoseOutputSurface(); + EXPECT_TRUE(state.PendingDrawsShouldBeAborted()); + + state.SetCanDraw(true); + state.WillBeginOutputSurfaceCreation(); + state.DidCreateAndInitializeOutputSurface(); + EXPECT_FALSE(state.PendingDrawsShouldBeAborted()); + + state.SetCanDraw(false); + state.DidLoseOutputSurface(); + EXPECT_TRUE(state.PendingDrawsShouldBeAborted()); +} + TEST(SchedulerStateMachineTest, TestTriggerDeadlineImmediatelyAfterAbortedCommit) { SchedulerSettings default_scheduler_settings; @@ -1709,7 +1848,7 @@ TEST(SchedulerStateMachineTest, // As a response the compositor requests a redraw and a commit to tell the // main thread about the new scroll offset. state.SetNeedsRedraw(true); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); // We should start the commit normally. EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); @@ -1758,7 +1897,7 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) { // This test ensures that impl-draws are prioritized over main thread updates // in prefer impl latency mode. state.SetNeedsRedraw(true); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( @@ -1780,7 +1919,7 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) { state.DidSwapBuffersComplete(); // Request a new commit and finish the previous one. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); FinishPreviousCommitAndDrawWithoutExitingDeadline(&state); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -1794,7 +1933,7 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) { // Verify we do not send another BeginMainFrame if was are swap throttled // and did not just swap. - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1809,7 +1948,7 @@ TEST(SchedulerStateMachineTest, StateMachine state(default_scheduler_settings); SET_UP_STATE(state) - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( @@ -1828,7 +1967,7 @@ TEST(SchedulerStateMachineTest, TestTriggerDeadlineImmediatelyWhenInvisible) { StateMachine state(default_scheduler_settings); SET_UP_STATE(state) - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE( @@ -1868,7 +2007,7 @@ TEST(SchedulerStateMachineTest, TestAnimateBeforeCommit) { // Check that animations are updated before we start a commit. state.SetNeedsAnimate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.BeginFrameNeeded()); @@ -1891,7 +2030,7 @@ TEST(SchedulerStateMachineTest, TestAnimateAfterCommitBeforeDraw) { // Check that animations are updated before we start a commit. state.SetNeedsAnimate(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.BeginFrameNeeded()); @@ -1950,7 +2089,7 @@ TEST(SchedulerStateMachineTest, TestDeferCommit) { state.SetDeferCommits(true); - state.SetNeedsCommit(); + state.SetNeedsBeginMainFrame(); EXPECT_FALSE(state.BeginFrameNeeded()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1973,7 +2112,7 @@ TEST(SchedulerStateMachineTest, EarlyOutCommitWantsProactiveBeginFrame) { EXPECT_FALSE(state.ProactiveBeginFrameWanted()); bool commit_has_no_updates = true; - state.UpdateStateOnCommit(commit_has_no_updates); + state.WillCommit(commit_has_no_updates); EXPECT_TRUE(state.ProactiveBeginFrameWanted()); state.OnBeginImplFrame(); EXPECT_FALSE(state.ProactiveBeginFrameWanted()); diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc index 42a23d423e6..669ed3b5d99 100644 --- a/chromium/cc/scheduler/scheduler_unittest.cc +++ b/chromium/cc/scheduler/scheduler_unittest.cc @@ -8,7 +8,6 @@ #include <vector> #include "base/logging.h" -#include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" #include "base/numerics/safe_conversions.h" #include "base/run_loop.h" @@ -300,7 +299,7 @@ class SchedulerTest : public testing::Test { // We don't see anything happening until the first impl frame. scheduler_->DidCreateAndInitializeOutputSurface(); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_TRUE(client_->needs_begin_frames()); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); client_->Reset(); @@ -312,6 +311,7 @@ class SchedulerTest : public testing::Test { scheduler_->NotifyBeginMainFrameStarted(); scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); + scheduler_->NotifyReadyToDraw(); EXPECT_FALSE(scheduler_->CommitPending()); @@ -426,7 +426,7 @@ TEST_F(SchedulerTest, SendBeginFramesToChildren) { SetUpScheduler(true); EXPECT_FALSE(client_->begin_frame_is_sent_to_children()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); EXPECT_TRUE(client_->needs_begin_frames()); @@ -518,8 +518,8 @@ TEST_F(SchedulerTest, RequestCommit) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -584,7 +584,7 @@ TEST_F(SchedulerTest, RequestCommitAfterSetDeferCommit) { scheduler_->SetDeferCommits(true); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_NO_ACTION(client_); client_->Reset(); @@ -611,7 +611,7 @@ TEST_F(SchedulerTest, DeferCommitWithRedraw) { scheduler_->SetDeferCommits(true); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_NO_ACTION(client_); // The SetNeedsRedraw will override the SetDeferCommits(true), to allow a @@ -641,8 +641,8 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -654,8 +654,9 @@ TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) { EXPECT_TRUE(client_->needs_begin_frames()); client_->Reset(); - // Now SetNeedsCommit again. Calling here means we need a second commit. - scheduler_->SetNeedsCommit(); + // Now SetNeedsBeginMainFrame again. Calling here means we need a second + // commit. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_EQ(client_->num_actions_(), 0); client_->Reset(); @@ -824,15 +825,16 @@ TEST_F(SchedulerTest, RequestRedrawInsideFailedDraw) { EXPECT_TRUE(client->needs_begin_frames()); } -class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { +class SchedulerClientThatSetNeedsBeginMainFrameInsideDraw + : public FakeSchedulerClient { public: - SchedulerClientThatSetNeedsCommitInsideDraw() + SchedulerClientThatSetNeedsBeginMainFrameInsideDraw() : set_needs_commit_on_next_draw_(false) {} DrawResult ScheduledActionDrawAndSwapIfPossible() override { - // Only SetNeedsCommit the first time this is called + // Only SetNeedsBeginMainFrame the first time this is called if (set_needs_commit_on_next_draw_) { - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); set_needs_commit_on_next_draw_ = false; } return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible(); @@ -843,17 +845,19 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient { return DRAW_SUCCESS; } - void SetNeedsCommitOnNextDraw() { set_needs_commit_on_next_draw_ = true; } + void SetNeedsBeginMainFrameOnNextDraw() { + set_needs_commit_on_next_draw_ = true; + } private: bool set_needs_commit_on_next_draw_; }; -// Tests for the scheduler infinite-looping on SetNeedsCommit requests that -// happen inside a ScheduledActionDrawAndSwap +// Tests for the scheduler infinite-looping on SetNeedsBeginMainFrame requests +// that happen inside a ScheduledActionDrawAndSwap TEST_F(SchedulerTest, RequestCommitInsideDraw) { - SchedulerClientThatSetNeedsCommitInsideDraw* client = - new SchedulerClientThatSetNeedsCommitInsideDraw; + SchedulerClientThatSetNeedsBeginMainFrameInsideDraw* client = + new SchedulerClientThatSetNeedsBeginMainFrameInsideDraw; scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(make_scoped_ptr(client).Pass(), true); @@ -864,9 +868,9 @@ TEST_F(SchedulerTest, RequestCommitInsideDraw) { EXPECT_EQ(0, client->num_draws()); EXPECT_TRUE(client->needs_begin_frames()); - client->SetNeedsCommitOnNextDraw(); + client->SetNeedsBeginMainFrameOnNextDraw(); EXPECT_SCOPED(AdvanceFrame()); - client->SetNeedsCommitOnNextDraw(); + client->SetNeedsBeginMainFrameOnNextDraw(); task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(1, client->num_draws()); EXPECT_TRUE(scheduler_->CommitPending()); @@ -938,8 +942,8 @@ TEST_F(SchedulerTest, RequestCommitInsideFailedDraw) { } TEST_F(SchedulerTest, NoSwapWhenDrawFails) { - SchedulerClientThatSetNeedsCommitInsideDraw* client = - new SchedulerClientThatSetNeedsCommitInsideDraw; + SchedulerClientThatSetNeedsBeginMainFrameInsideDraw* client = + new SchedulerClientThatSetNeedsBeginMainFrameInsideDraw; scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(make_scoped_ptr(client).Pass(), true); @@ -949,7 +953,7 @@ TEST_F(SchedulerTest, NoSwapWhenDrawFails) { EXPECT_EQ(0, client->num_draws()); // Draw successfully, this starts a new frame. - client->SetNeedsCommitOnNextDraw(); + client->SetNeedsBeginMainFrameOnNextDraw(); EXPECT_SCOPED(AdvanceFrame()); task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(1, client->num_draws()); @@ -960,7 +964,7 @@ TEST_F(SchedulerTest, NoSwapWhenDrawFails) { // Fail to draw, this should not start a frame. client->SetDrawWillHappen(false); - client->SetNeedsCommitOnNextDraw(); + client->SetNeedsBeginMainFrameOnNextDraw(); EXPECT_SCOPED(AdvanceFrame()); task_runner().RunPendingTasks(); // Run posted deadline. EXPECT_EQ(2, client->num_draws()); @@ -1247,10 +1251,11 @@ TEST_F(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) { SchedulerClientNeedsPrepareTilesInDraw* client = new SchedulerClientNeedsPrepareTilesInDraw; scheduler_settings_.use_external_begin_frame_source = true; + scheduler_settings_.commit_to_active_tree = true; SetUpScheduler(make_scoped_ptr(client).Pass(), true); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -1268,9 +1273,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) { 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(); + // Scheduler won't post deadline in the mode. client_->Reset(); task_runner().RunPendingTasks(); // Try to run posted deadline. // There is no posted deadline. @@ -1288,10 +1291,11 @@ TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostOutputSurface) { SchedulerClientNeedsPrepareTilesInDraw* client = new SchedulerClientNeedsPrepareTilesInDraw; scheduler_settings_.use_external_begin_frame_source = true; + scheduler_settings_.commit_to_active_tree = true; SetUpScheduler(make_scoped_ptr(client).Pass(), true); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -1309,9 +1313,7 @@ TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostOutputSurface) { 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(); + // Scheduler won't post deadline in the mode. client_->Reset(); task_runner().RunPendingTasks(); // Try to run posted deadline. // There is no posted deadline. @@ -1330,12 +1332,12 @@ TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostOutputSurface) { void SchedulerTest::CheckMainFrameSkippedAfterLateCommit( bool expect_send_begin_main_frame) { // Impl thread hits deadline before commit finishes. - scheduler_->SetNeedsCommit(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + scheduler_->SetNeedsBeginMainFrame(); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->NotifyBeginMainFrameStarted(); scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); @@ -1344,16 +1346,16 @@ void SchedulerTest::CheckMainFrameSkippedAfterLateCommit( EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 5); EXPECT_ACTION("ScheduledActionCommit", client_, 3, 5); EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 4, 5); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); client_->Reset(); - scheduler_->SetNeedsCommit(); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + scheduler_->SetNeedsBeginMainFrame(); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); EXPECT_EQ(expect_send_begin_main_frame, - scheduler_->MainThreadIsInHighLatencyMode()); + scheduler_->MainThreadMissedLastDeadline()); EXPECT_EQ(expect_send_begin_main_frame, client_->HasAction("ScheduledActionSendBeginMainFrame")); } @@ -1449,9 +1451,9 @@ void SchedulerTest::ImplFrameSkippedAfterLateSwapAck( // Draw and swap for first BeginFrame client_->Reset(); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 4); EXPECT_ACTION("WillBeginImplFrame", client_, 1, 4); @@ -1462,7 +1464,7 @@ void SchedulerTest::ImplFrameSkippedAfterLateSwapAck( scheduler_->NotifyBeginMainFrameStarted(); scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); EXPECT_ACTION("ScheduledActionCommit", client_, 0, 4); EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 4); @@ -1475,14 +1477,14 @@ void SchedulerTest::ImplFrameSkippedAfterLateSwapAck( // Not calling scheduler_->DidSwapBuffersComplete() until after next // BeginImplFrame puts the impl thread in high latency mode. client_->Reset(); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); // Verify that we skip the BeginImplFrame EXPECT_NO_ACTION(client_); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); // Verify that we do not perform any actions after we are no longer // swap throttled. @@ -1501,7 +1503,7 @@ void SchedulerTest::ImplFrameSkippedAfterLateSwapAck( // Verify that we start the next BeginImplFrame and continue normally // after having just skipped a BeginImplFrame. client_->Reset(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); @@ -1582,14 +1584,14 @@ TEST_F(SchedulerTest, // Draw and swap for first BeginFrame client_->Reset(); scheduler_->SetNeedsRedraw(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3); EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3); EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 3); client_->Reset(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_); @@ -1600,12 +1602,12 @@ TEST_F(SchedulerTest, // BeginImplFrame puts the impl thread in high latency mode. client_->Reset(); scheduler_->SetNeedsRedraw(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); // Verify that we skip the BeginImplFrame EXPECT_NO_ACTION(client_); EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); // Verify that we do not perform any actions after we are no longer // swap throttled. @@ -1616,7 +1618,7 @@ TEST_F(SchedulerTest, // Verify that we start the next BeginImplFrame and continue normally // after having just skipped a BeginImplFrame. client_->Reset(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2); @@ -1637,8 +1639,8 @@ void SchedulerTest::ImplFrameIsNotSkippedAfterLateSwapAck() { // Draw and swap for first BeginFrame client_->Reset(); - scheduler_->SetNeedsCommit(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + scheduler_->SetNeedsBeginMainFrame(); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3); EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3); @@ -1648,7 +1650,7 @@ void SchedulerTest::ImplFrameIsNotSkippedAfterLateSwapAck() { scheduler_->NotifyBeginMainFrameStarted(); scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); EXPECT_ACTION("ScheduledActionCommit", client_, 0, 4); EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 4); @@ -1661,12 +1663,12 @@ void SchedulerTest::ImplFrameIsNotSkippedAfterLateSwapAck() { // Not calling scheduler_->DidSwapBuffersComplete() until after next frame // puts the impl thread in high latency mode. client_->Reset(); - scheduler_->SetNeedsCommit(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + scheduler_->SetNeedsBeginMainFrame(); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_); EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending()); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); client_->Reset(); scheduler_->DidSwapBuffersComplete(); @@ -1747,18 +1749,18 @@ TEST_F(SchedulerTest, client_->SetAutomaticSwapAck(false); // Impl thread hits deadline before commit finishes to make - // MainThreadIsInHighLatencyMode true + // MainThreadMissedLastDeadline true client_->Reset(); - scheduler_->SetNeedsCommit(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + scheduler_->SetNeedsBeginMainFrame(); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->NotifyBeginMainFrameStarted(); scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 5); EXPECT_ACTION("WillBeginImplFrame", client_, 1, 5); @@ -1768,10 +1770,10 @@ TEST_F(SchedulerTest, // Draw and swap for first commit, start second commit. client_->Reset(); - scheduler_->SetNeedsCommit(); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + scheduler_->SetNeedsBeginMainFrame(); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); scheduler_->NotifyBeginMainFrameStarted(); scheduler_->NotifyReadyToCommit(); @@ -1787,11 +1789,10 @@ TEST_F(SchedulerTest, // Don't call scheduler_->DidSwapBuffersComplete() until after next frame // to put the impl thread in a high latency mode. client_->Reset(); - scheduler_->SetNeedsCommit(); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); - EXPECT_TRUE(scheduler_->SwapThrottled()); + scheduler_->SetNeedsBeginMainFrame(); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); EXPECT_SCOPED(AdvanceFrame()); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); @@ -1800,7 +1801,7 @@ TEST_F(SchedulerTest, // swap ack backpressure, not because of latency recovery. EXPECT_FALSE(client_->HasAction("ScheduledActionSendBeginMainFrame")); EXPECT_FALSE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible")); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); // Lower estimates so that the scheduler will attempt latency recovery. auto fast_duration = base::TimeDelta::FromMilliseconds(1); @@ -1813,14 +1814,14 @@ TEST_F(SchedulerTest, // Verify we skip BeginMainFrame first. client_->Reset(); // Previous commit request is still outstanding. - EXPECT_TRUE(scheduler_->NeedsCommit()); + EXPECT_TRUE(scheduler_->NeedsBeginMainFrame()); EXPECT_TRUE(scheduler_->SwapThrottled()); SendNextBeginFrame(); - EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->DidSwapBuffersComplete(); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3); EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3); EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3); @@ -1828,30 +1829,30 @@ TEST_F(SchedulerTest, // Verify we skip the BeginImplFrame second. client_->Reset(); // Previous commit request is still outstanding. - EXPECT_TRUE(scheduler_->NeedsCommit()); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->NeedsBeginMainFrame()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->DidSwapBuffersComplete(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); EXPECT_NO_ACTION(client_); // Then verify we operate in a low latency mode. client_->Reset(); // Previous commit request is still outstanding. - EXPECT_TRUE(scheduler_->NeedsCommit()); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_TRUE(scheduler_->NeedsBeginMainFrame()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); SendNextBeginFrame(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->NotifyBeginMainFrameStarted(); scheduler_->NotifyReadyToCommit(); scheduler_->NotifyReadyToActivate(); task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true)); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); scheduler_->DidSwapBuffersComplete(); - EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); + EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline()); EXPECT_ACTION("WillBeginImplFrame", client_, 0, 6); EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 6); @@ -1880,7 +1881,7 @@ TEST_F( // in a swap throttled state. client_->Reset(); EXPECT_FALSE(scheduler_->CommitPending()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); EXPECT_SCOPED(AdvanceFrame()); EXPECT_TRUE(scheduler_->CommitPending()); @@ -1902,7 +1903,7 @@ TEST_F( // Make sure that we can finish the next commit even while swap throttled. client_->Reset(); EXPECT_FALSE(scheduler_->CommitPending()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SCOPED(AdvanceFrame()); scheduler_->NotifyBeginMainFrameStarted(); scheduler_->NotifyReadyToCommit(); @@ -1920,7 +1921,7 @@ TEST_F( // we have both a pending tree and an active tree. client_->Reset(); EXPECT_FALSE(scheduler_->CommitPending()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SCOPED(AdvanceFrame()); EXPECT_FALSE(scheduler_->CommitPending()); task_runner().RunPendingTasks(); // Run posted deadline. @@ -1951,7 +1952,7 @@ TEST_F(SchedulerTest, // activation. client_->Reset(); EXPECT_FALSE(scheduler_->CommitPending()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); EXPECT_SCOPED(AdvanceFrame()); EXPECT_TRUE(scheduler_->CommitPending()); @@ -1973,7 +1974,7 @@ TEST_F(SchedulerTest, // Enter a swap throttled state. client_->Reset(); EXPECT_FALSE(scheduler_->CommitPending()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); EXPECT_SCOPED(AdvanceFrame()); EXPECT_TRUE(scheduler_->CommitPending()); @@ -2002,7 +2003,7 @@ TEST_F(SchedulerTest, // it's first draw. client_->Reset(); EXPECT_FALSE(scheduler_->CommitPending()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SCOPED(AdvanceFrame()); EXPECT_FALSE(scheduler_->CommitPending()); task_runner().RunPendingTasks(); // Run posted deadline. @@ -2032,7 +2033,7 @@ TEST_F( // activation. client_->Reset(); EXPECT_FALSE(scheduler_->CommitPending()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); EXPECT_SCOPED(AdvanceFrame()); EXPECT_TRUE(scheduler_->CommitPending()); @@ -2053,7 +2054,7 @@ TEST_F( // Start another commit while we still have an active tree. client_->Reset(); EXPECT_FALSE(scheduler_->CommitPending()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); EXPECT_SCOPED(AdvanceFrame()); EXPECT_TRUE(scheduler_->CommitPending()); @@ -2084,8 +2085,8 @@ TEST_F(SchedulerTest, BeginRetroFrame) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -2165,9 +2166,9 @@ TEST_F(SchedulerTest, BeginRetroFrame_SwapThrottled) { scheduler_->SetMaxSwapsPending(1); client_->SetAutomaticSwapAck(false); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. client_->Reset(); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -2209,7 +2210,7 @@ TEST_F(SchedulerTest, BeginRetroFrame_SwapThrottled) { // While swap throttled, BeginRetroFrames should trigger BeginImplFrames // but not a BeginMainFrame or draw. - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); // Run posted BeginRetroFrame. task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(false)); @@ -2245,7 +2246,7 @@ TEST_F(SchedulerTest, RetroFrameDoesNotExpireTooEarly) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_TRUE(client_->needs_begin_frames()); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); @@ -2306,7 +2307,7 @@ TEST_F(SchedulerTest, RetroFrameExpiresOnTime) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_TRUE(client_->needs_begin_frames()); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); @@ -2359,7 +2360,7 @@ TEST_F(SchedulerTest, MissedFrameDoesNotExpireTooEarly) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_TRUE(client_->needs_begin_frames()); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); @@ -2384,7 +2385,7 @@ TEST_F(SchedulerTest, MissedFrameExpiresOnTime) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_TRUE(client_->needs_begin_frames()); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); @@ -2413,9 +2414,9 @@ void SchedulerTest::BeginFramesNotFromClient( scheduler_settings_.throttle_frame_production = throttle_frame_production; SetUpScheduler(true); - // SetNeedsCommit should begin the frame on the next BeginImplFrame + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame // without calling SetNeedsBeginFrame. - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_NO_ACTION(client_); client_->Reset(); @@ -2506,9 +2507,9 @@ void SchedulerTest::BeginFramesNotFromClient_SwapThrottled( scheduler_->SetMaxSwapsPending(1); client_->SetAutomaticSwapAck(false); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. client_->Reset(); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_NO_ACTION(client_); client_->Reset(); @@ -2540,7 +2541,7 @@ void SchedulerTest::BeginFramesNotFromClient_SwapThrottled( // While swap throttled, BeginFrames should trigger BeginImplFrames, // but not a BeginMainFrame or draw. - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); scheduler_->SetNeedsRedraw(); EXPECT_SCOPED(AdvanceFrame()); // Run posted BeginFrame. EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2); @@ -2615,8 +2616,8 @@ TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -2648,8 +2649,8 @@ TEST_F(SchedulerTest, scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -2692,8 +2693,8 @@ TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -2751,8 +2752,8 @@ TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); // Create a BeginFrame with a long deadline to avoid race conditions. @@ -2811,8 +2812,8 @@ TEST_F(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); // Create a BeginFrame with a long deadline to avoid race conditions. @@ -2885,9 +2886,9 @@ TEST_F(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) { TEST_F(SchedulerTest, DidLoseOutputSurfaceWithSyntheticBeginFrameSource) { SetUpScheduler(true); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. EXPECT_FALSE(scheduler_->frame_source().NeedsBeginFrames()); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames()); client_->Reset(); @@ -2927,8 +2928,8 @@ TEST_F(SchedulerTest, DidLoseOutputSurfaceWhenIdle) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -2963,8 +2964,8 @@ TEST_F(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -3111,8 +3112,8 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - // SetNeedsCommit should begin the frame on the next BeginImplFrame. - scheduler_->SetNeedsCommit(); + // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -3222,7 +3223,7 @@ TEST_F(SchedulerTest, SynchronousCompositorCommit) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -3279,7 +3280,7 @@ TEST_F(SchedulerTest, SynchronousCompositorDoubleCommitWithoutDraw) { scheduler_settings_.use_external_begin_frame_source = true; SetUpScheduler(true); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_); client_->Reset(); @@ -3302,7 +3303,7 @@ TEST_F(SchedulerTest, SynchronousCompositorDoubleCommitWithoutDraw) { client_->Reset(); // Ask for another commit. - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); AdvanceFrame(); EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4); @@ -3404,8 +3405,8 @@ TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) { EXPECT_FALSE(scheduler_->PrepareTilesPending()); client_->Reset(); - // Simulate SetNeedsCommit due to input event. - scheduler_->SetNeedsCommit(); + // Simulate SetNeedsBeginMainFrame due to input event. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client_); client_->Reset(); @@ -3433,19 +3434,36 @@ TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) { EXPECT_FALSE(scheduler_->PrepareTilesPending()); client_->Reset(); - // Simulate SetNeedsCommit due to input event. - scheduler_->SetNeedsCommit(); + // Simulate SetNeedsBeginMainFrame due to input event. + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client_); client_->Reset(); } +TEST_F(SchedulerTest, SynchronousCompositorOnDrawWhenInvisible) { + scheduler_settings_.using_synchronous_renderer_compositor = true; + scheduler_settings_.use_external_begin_frame_source = true; + SetUpScheduler(true); + + scheduler_->SetVisible(false); + + scheduler_->SetNeedsRedraw(); + scheduler_->OnDrawForOutputSurface(); + // Action animate is the result of SetNeedsRedraw. + EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2); + // SynchronousCompositor has to draw regardless of visibility. + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2); + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); + client_->Reset(); +} + TEST_F(SchedulerTest, AuthoritativeVSyncInterval) { SetUpScheduler(true); base::TimeDelta initial_interval = scheduler_->BeginImplFrameInterval(); base::TimeDelta authoritative_interval = base::TimeDelta::FromMilliseconds(33); - scheduler_->SetNeedsCommit(); + scheduler_->SetNeedsBeginMainFrame(); EXPECT_SCOPED(AdvanceFrame()); EXPECT_EQ(initial_interval, scheduler_->BeginImplFrameInterval()); diff --git a/chromium/cc/surfaces/BUILD.gn b/chromium/cc/surfaces/BUILD.gn index 0f2c9509f4b..6dd7240bc1f 100644 --- a/chromium/cc/surfaces/BUILD.gn +++ b/chromium/cc/surfaces/BUILD.gn @@ -31,6 +31,8 @@ component("surfaces") { "surface_factory.cc", "surface_factory.h", "surface_factory_client.h", + "surface_hittest.cc", + "surface_hittest.h", "surface_id_allocator.cc", "surface_id_allocator.h", "surface_manager.cc", @@ -55,7 +57,7 @@ component("surfaces") { ] if (is_android && !is_debug) { - configs -= [ "//build/config/compiler:optimize" ] + configs -= [ "//build/config/compiler:default_optimization" ] configs += [ "//build/config/compiler:optimize_max" ] } } diff --git a/chromium/cc/surfaces/display.cc b/chromium/cc/surfaces/display.cc index 37a9756950c..dd776fb1bc4 100644 --- a/chromium/cc/surfaces/display.cc +++ b/chromium/cc/surfaces/display.cc @@ -20,6 +20,7 @@ #include "cc/surfaces/surface_aggregator.h" #include "cc/surfaces/surface_manager.h" #include "gpu/command_buffer/client/gles2_interface.h" +#include "ui/gfx/buffer_types.h" namespace cc { @@ -62,17 +63,22 @@ void Display::SetSurfaceId(SurfaceId id, float device_scale_factor) { if (current_surface_id_ == id && device_scale_factor_ == device_scale_factor) return; + TRACE_EVENT0("cc", "Display::SetSurfaceId"); + current_surface_id_ = id; device_scale_factor_ = device_scale_factor; UpdateRootSurfaceResourcesLocked(); if (scheduler_) - scheduler_->EntireDisplayDamaged(id); + scheduler_->SetNewRootSurface(id); } void Display::Resize(const gfx::Size& size) { if (size == current_surface_size_) return; + + TRACE_EVENT0("cc", "Display::Resize"); + // Need to ensure all pending swaps have executed before the window is // resized, or D3D11 will scale the swap output. if (settings_.finish_rendering_on_resize) { @@ -85,7 +91,7 @@ void Display::Resize(const gfx::Size& size) { swapped_since_resize_ = false; current_surface_size_ = size; if (scheduler_) - scheduler_->EntireDisplayDamaged(current_surface_id_); + scheduler_->DisplayResized(); } void Display::SetExternalClip(const gfx::Rect& clip) { @@ -96,13 +102,12 @@ void Display::InitializeRenderer() { if (resource_provider_) return; - // Display does not use GpuMemoryBuffers, so persistent map is not relevant. - bool use_persistent_map_for_gpu_memory_buffers = false; scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create( output_surface_.get(), bitmap_manager_, gpu_memory_buffer_manager_, - nullptr, settings_.highp_threshold_min, settings_.use_rgba_4444_textures, + nullptr, settings_.highp_threshold_min, settings_.texture_id_allocation_chunk_size, - use_persistent_map_for_gpu_memory_buffers); + std::vector<unsigned>(static_cast<size_t>(gfx::BufferFormat::LAST) + 1, + GL_TEXTURE_2D)); if (!resource_provider) return; @@ -122,7 +127,12 @@ void Display::InitializeRenderer() { } resource_provider_ = resource_provider.Pass(); - aggregator_.reset(new SurfaceAggregator(manager_, resource_provider_.get())); + // TODO(jbauman): Outputting an incomplete quad list doesn't work when using + // overlays. + bool output_partial_list = renderer_->Capabilities().using_partial_swap && + !output_surface_->GetOverlayCandidateValidator(); + aggregator_.reset(new SurfaceAggregator(manager_, resource_provider_.get(), + output_partial_list)); } void Display::DidLoseOutputSurface() { @@ -141,19 +151,26 @@ void Display::UpdateRootSurfaceResourcesLocked() { } bool Display::DrawAndSwap() { - if (current_surface_id_.is_null()) + TRACE_EVENT0("cc", "Display::DrawAndSwap"); + + if (current_surface_id_.is_null()) { + TRACE_EVENT_INSTANT0("cc", "No root surface.", TRACE_EVENT_SCOPE_THREAD); return false; + } InitializeRenderer(); - if (!output_surface_) + if (!output_surface_) { + TRACE_EVENT_INSTANT0("cc", "No output surface", TRACE_EVENT_SCOPE_THREAD); return false; + } scoped_ptr<CompositorFrame> frame = aggregator_->Aggregate(current_surface_id_); - if (!frame) + if (!frame) { + TRACE_EVENT_INSTANT0("cc", "Empty aggregated frame.", + TRACE_EVENT_SCOPE_THREAD); return false; - - TRACE_EVENT0("cc", "Display::DrawAndSwap"); + } // Run callbacks early to allow pipelining. for (const auto& id_entry : aggregator_->previous_contained_surfaces()) { @@ -161,6 +178,7 @@ bool Display::DrawAndSwap() { if (surface) surface->RunDrawCallbacks(SurfaceDrawStatus::DRAWN); } + DelegatedFrameData* frame_data = frame->delegated_frame_data.get(); frame->metadata.latency_info.insert(frame->metadata.latency_info.end(), @@ -179,9 +197,13 @@ bool Display::DrawAndSwap() { have_damage = !frame_data->render_pass_list.back()->damage_rect.size().IsEmpty(); } - bool avoid_swap = surface_size != current_surface_size_; + + bool size_matches = surface_size == current_surface_size_; + if (!size_matches) + TRACE_EVENT_INSTANT0("cc", "Size missmatch.", TRACE_EVENT_SCOPE_THREAD); + bool should_draw = !frame->metadata.latency_info.empty() || - have_copy_requests || (have_damage && !avoid_swap); + have_copy_requests || (have_damage && size_matches); // If the surface is suspended then the resources to be used by the draw are // likely destroyed. @@ -202,20 +224,25 @@ bool Display::DrawAndSwap() { renderer_->DrawFrame(&frame_data->render_pass_list, device_scale_factor_, device_viewport_rect, device_clip_rect, disable_picture_quad_image_filtering); + } else { + TRACE_EVENT_INSTANT0("cc", "Draw skipped.", TRACE_EVENT_SCOPE_THREAD); } - if (should_draw && !avoid_swap) { + bool should_swap = should_draw && size_matches; + if (should_swap) { swapped_since_resize_ = true; for (auto& latency : frame->metadata.latency_info) { - TRACE_EVENT_FLOW_STEP0( - "input,benchmark", - "LatencyInfo.Flow", - TRACE_ID_DONT_MANGLE(latency.trace_id), - "Display::DrawAndSwap"); + TRACE_EVENT_WITH_FLOW1("input,benchmark", "LatencyInfo.Flow", + TRACE_ID_DONT_MANGLE(latency.trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "step", "Display::DrawAndSwap"); } benchmark_instrumentation::IssueDisplayRenderingStatsEvent(); renderer_->SwapBuffers(frame->metadata); } else { + if (have_damage && !size_matches) + aggregator_->SetFullDamageForSurface(current_surface_id_); + TRACE_EVENT_INSTANT0("cc", "Swap skipped.", TRACE_EVENT_SCOPE_THREAD); stored_latency_info_.insert(stored_latency_info_.end(), frame->metadata.latency_info.begin(), frame->metadata.latency_info.end()); @@ -250,7 +277,9 @@ void Display::OnDraw() { } void Display::SetNeedsRedrawRect(const gfx::Rect& damage_rect) { - NOTREACHED(); + aggregator_->SetFullDamageForSurface(current_surface_id_); + if (scheduler_) + scheduler_->SurfaceDamaged(current_surface_id_); } void Display::ReclaimResources(const CompositorFrameAck* ack) { diff --git a/chromium/cc/surfaces/display_scheduler.cc b/chromium/cc/surfaces/display_scheduler.cc index 3810e148864..033632ec9ca 100644 --- a/chromium/cc/surfaces/display_scheduler.cc +++ b/chromium/cc/surfaces/display_scheduler.cc @@ -23,7 +23,7 @@ DisplayScheduler::DisplayScheduler(DisplaySchedulerClient* client, root_surface_resources_locked_(true), inside_begin_frame_deadline_interval_(false), needs_draw_(false), - entire_display_damaged_(false), + expecting_root_surface_damage_because_of_resize_(false), all_active_child_surfaces_ready_to_draw_(false), pending_swaps_(0), max_pending_swaps_(max_pending_swaps), @@ -42,28 +42,34 @@ DisplayScheduler::~DisplayScheduler() { // If we try to draw when the root surface resources are locked, the // draw will fail. void DisplayScheduler::SetRootSurfaceResourcesLocked(bool locked) { + TRACE_EVENT1("cc", "DisplayScheduler::SetRootSurfaceResourcesLocked", + "locked", locked); root_surface_resources_locked_ = locked; ScheduleBeginFrameDeadline(); } // This is used to force an immediate swap before a resize. void DisplayScheduler::ForceImmediateSwapIfPossible() { + TRACE_EVENT0("cc", "DisplayScheduler::ForceImmediateSwapIfPossible"); bool in_begin = inside_begin_frame_deadline_interval_; AttemptDrawAndSwap(); if (in_begin) begin_frame_source_->DidFinishFrame(0); } +void DisplayScheduler::DisplayResized() { + expecting_root_surface_damage_because_of_resize_ = true; + expect_damage_from_root_surface_ = true; + needs_draw_ = true; + ScheduleBeginFrameDeadline(); +} + // Notification that there was a resize or the root surface changed and // that we should just draw immediately. -void DisplayScheduler::EntireDisplayDamaged(SurfaceId root_surface_id) { - TRACE_EVENT0("cc", "DisplayScheduler::EntireDisplayDamaged"); - needs_draw_ = true; - entire_display_damaged_ = true; +void DisplayScheduler::SetNewRootSurface(SurfaceId root_surface_id) { + TRACE_EVENT0("cc", "DisplayScheduler::SetNewRootSurface"); root_surface_id_ = root_surface_id; - - begin_frame_source_->SetNeedsBeginFrames(!output_surface_lost_); - ScheduleBeginFrameDeadline(); + SurfaceDamaged(root_surface_id); } // Indicates that there was damage to one of the surfaces. @@ -77,6 +83,7 @@ void DisplayScheduler::SurfaceDamaged(SurfaceId surface_id) { if (surface_id == root_surface_id_) { root_surface_damaged_ = true; + expecting_root_surface_damage_because_of_resize_ = false; } else { child_surface_ids_damaged_.insert(surface_id); @@ -113,7 +120,6 @@ void DisplayScheduler::DrawAndSwap() { child_surface_ids_damaged_.clear(); needs_draw_ = false; - entire_display_damaged_ = false; all_active_child_surfaces_ready_to_draw_ = child_surface_ids_to_expect_damage_from_.empty(); @@ -150,7 +156,8 @@ base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { if (pending_swaps_ >= max_pending_swaps_) { TRACE_EVENT_INSTANT0("cc", "Swap throttled", TRACE_EVENT_SCOPE_THREAD); - return current_begin_frame_args_.deadline; + return current_begin_frame_args_.frame_time + + current_begin_frame_args_.interval; } if (!needs_draw_) { @@ -166,13 +173,6 @@ base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { current_begin_frame_args_.interval; } - // TODO(mithro): Be smarter about resize deadlines. - if (entire_display_damaged_) { - TRACE_EVENT_INSTANT0("cc", "Entire display damaged", - TRACE_EVENT_SCOPE_THREAD); - return base::TimeTicks(); - } - bool root_ready_to_draw = !expect_damage_from_root_surface_ || root_surface_damaged_; @@ -182,6 +182,14 @@ base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { return base::TimeTicks(); } + // TODO(mithro): Be smarter about resize deadlines. + if (expecting_root_surface_damage_because_of_resize_) { + TRACE_EVENT_INSTANT0("cc", "Entire display damaged", + TRACE_EVENT_SCOPE_THREAD); + return current_begin_frame_args_.frame_time + + current_begin_frame_args_.interval; + } + // Use an earlier deadline if we are only waiting for the root surface // in case our expect_damage_from_root_surface heuristic is incorrect. // TODO(mithro): Replace this with SetNeedsBeginFrame and SwapAbort diff --git a/chromium/cc/surfaces/display_scheduler.h b/chromium/cc/surfaces/display_scheduler.h index bc509c7b1ca..4ffc6ea8d56 100644 --- a/chromium/cc/surfaces/display_scheduler.h +++ b/chromium/cc/surfaces/display_scheduler.h @@ -36,7 +36,8 @@ class CC_SURFACES_EXPORT DisplayScheduler : public BeginFrameObserverBase { void SetRootSurfaceResourcesLocked(bool locked); void ForceImmediateSwapIfPossible(); - virtual void EntireDisplayDamaged(SurfaceId root_surface_id); + virtual void DisplayResized(); + virtual void SetNewRootSurface(SurfaceId root_surface_id); virtual void SurfaceDamaged(SurfaceId surface_id); virtual void DidSwapBuffers(); @@ -68,7 +69,7 @@ class CC_SURFACES_EXPORT DisplayScheduler : public BeginFrameObserverBase { bool inside_begin_frame_deadline_interval_; bool needs_draw_; - bool entire_display_damaged_; + bool expecting_root_surface_damage_because_of_resize_; bool all_active_child_surfaces_ready_to_draw_; int pending_swaps_; diff --git a/chromium/cc/surfaces/display_scheduler_unittest.cc b/chromium/cc/surfaces/display_scheduler_unittest.cc index 43a0c9a5cba..0f2725dbc71 100644 --- a/chromium/cc/surfaces/display_scheduler_unittest.cc +++ b/chromium/cc/surfaces/display_scheduler_unittest.cc @@ -107,14 +107,73 @@ class DisplaySchedulerTest : public testing::Test { scoped_ptr<TestDisplayScheduler> scheduler_; }; -TEST_F(DisplaySchedulerTest, EntireDisplayDamagedDrawsImmediately) { +TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilNewRootSurface) { + SurfaceId root_surface_id1(1); + SurfaceId root_surface_id2(2); + SurfaceId sid1(3); + base::TimeTicks late_deadline; + + // Go trough an initial BeginFrame cycle with the root surface. + BeginFrameForTest(); + scheduler_->SetNewRootSurface(root_surface_id1); + scheduler_->BeginFrameDeadlineForTest(); + + // Resize on the next begin frame cycle should cause the deadline to wait + // for a new root surface. + late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); + BeginFrameForTest(); + scheduler_->SurfaceDamaged(sid1); + EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + scheduler_->DisplayResized(); + EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + scheduler_->SetNewRootSurface(root_surface_id2); + EXPECT_GE(now_src().NowTicks(), + scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + scheduler_->BeginFrameDeadlineForTest(); + + // Verify deadline goes back to normal after resize. + late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); + BeginFrameForTest(); + scheduler_->SurfaceDamaged(sid1); + EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + scheduler_->SurfaceDamaged(root_surface_id2); + EXPECT_GE(now_src().NowTicks(), + scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + scheduler_->BeginFrameDeadlineForTest(); +} + +TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilDamagedSurface) { SurfaceId root_surface_id(1); + SurfaceId sid1(2); + base::TimeTicks late_deadline; + + // Go trough an initial BeginFrame cycle with the root surface. BeginFrameForTest(); - EXPECT_LT(now_src().NowTicks(), + scheduler_->SetNewRootSurface(root_surface_id); + scheduler_->BeginFrameDeadlineForTest(); + + // Resize on the next begin frame cycle should cause the deadline to wait + // for a new root surface. + late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); + BeginFrameForTest(); + scheduler_->SurfaceDamaged(sid1); + EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + scheduler_->DisplayResized(); + EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + scheduler_->SurfaceDamaged(root_surface_id); + EXPECT_GE(now_src().NowTicks(), scheduler_->DesiredBeginFrameDeadlineTimeForTest()); - scheduler_->EntireDisplayDamaged(root_surface_id); + scheduler_->BeginFrameDeadlineForTest(); + + // Verify deadline goes back to normal after resize. + late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); + BeginFrameForTest(); + scheduler_->SurfaceDamaged(sid1); + EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + scheduler_->SurfaceDamaged(root_surface_id); EXPECT_GE(now_src().NowTicks(), scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + scheduler_->BeginFrameDeadlineForTest(); } TEST_F(DisplaySchedulerTest, SurfaceDamaged) { @@ -123,7 +182,7 @@ TEST_F(DisplaySchedulerTest, SurfaceDamaged) { SurfaceId sid2(2); // Set the root surface - scheduler_->EntireDisplayDamaged(root_surface_id); + scheduler_->SetNewRootSurface(root_surface_id); // Get scheduler to detect surface 1 as active by drawing // two frames in a row with damage from surface 1. @@ -208,6 +267,25 @@ TEST_F(DisplaySchedulerTest, OutputSurfaceLost) { EXPECT_EQ(1, client_->draw_and_swap_count()); } +TEST_F(DisplaySchedulerTest, ResizeCausesSwap) { + SurfaceId sid1(1); + + // DrawAndSwap normally. + BeginFrameForTest(); + EXPECT_LT(now_src().NowTicks(), + scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + EXPECT_EQ(0, client_->draw_and_swap_count()); + scheduler_->SurfaceDamaged(sid1); + scheduler_->BeginFrameDeadlineForTest(); + EXPECT_EQ(1, client_->draw_and_swap_count()); + + scheduler_->DisplayResized(); + BeginFrameForTest(); + // DisplayResized should trigger a swap to happen. + scheduler_->BeginFrameDeadlineForTest(); + EXPECT_EQ(2, client_->draw_and_swap_count()); +} + TEST_F(DisplaySchedulerTest, RootSurfaceResourcesLocked) { SurfaceId sid1(1); base::TimeTicks late_deadline; @@ -252,7 +330,6 @@ TEST_F(DisplaySchedulerTest, RootSurfaceResourcesLocked) { TEST_F(DisplaySchedulerTest, DidSwapBuffers) { SurfaceId sid1(1); SurfaceId sid2(2); - base::TimeTicks expected_deadline; // Get scheduler to detect surface 1 and 2 as active. BeginFrameForTest(); @@ -275,16 +352,14 @@ TEST_F(DisplaySchedulerTest, DidSwapBuffers) { EXPECT_EQ(3, client_->draw_and_swap_count()); scheduler_->DidSwapBuffers(); - // Deadline triggers normally when swap throttled. - expected_deadline = - fake_begin_frame_source_.TestLastUsedBeginFrameArgs().deadline - - BeginFrameArgs::DefaultEstimatedParentDrawTime(); + // Deadline triggers late when swap throttled. + base::TimeTicks late_deadline = + now_src().NowTicks() + BeginFrameArgs::DefaultInterval(); BeginFrameForTest(); // Damage surface 1, but not surface 2 so we avoid triggering deadline // early because all surfaces are ready. scheduler_->SurfaceDamaged(sid1); - EXPECT_EQ(expected_deadline, - scheduler_->DesiredBeginFrameDeadlineTimeForTest()); + EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest()); // Don't draw and swap in deadline while swap throttled. EXPECT_EQ(3, client_->draw_and_swap_count()); @@ -293,7 +368,7 @@ TEST_F(DisplaySchedulerTest, DidSwapBuffers) { // Deadline triggers normally once not swap throttled. // Damage from previous BeginFrame should cary over, so don't damage again. - expected_deadline = + base::TimeTicks expected_deadline = fake_begin_frame_source_.TestLastUsedBeginFrameArgs().deadline - BeginFrameArgs::DefaultEstimatedParentDrawTime(); scheduler_->DidSwapBuffersComplete(); @@ -330,7 +405,10 @@ TEST_F(DisplaySchedulerTest, ScheduleBeginFrameDeadline) { scheduler_->DidSwapBuffersComplete(); EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); - scheduler_->EntireDisplayDamaged(root_surface_id); + scheduler_->DisplayResized(); + EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); + + scheduler_->SetNewRootSurface(root_surface_id); EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count()); scheduler_->SurfaceDamaged(sid1); diff --git a/chromium/cc/surfaces/display_unittest.cc b/chromium/cc/surfaces/display_unittest.cc index 93ff0f85af1..6058f159b22 100644 --- a/chromium/cc/surfaces/display_unittest.cc +++ b/chromium/cc/surfaces/display_unittest.cc @@ -31,10 +31,19 @@ class EmptySurfaceFactoryClient : public SurfaceFactoryClient { void ReturnResources(const ReturnedResourceArray& resources) override {} }; +class TestSoftwareOutputDevice : public SoftwareOutputDevice { + public: + TestSoftwareOutputDevice() {} + + gfx::Rect damage_rect() const { return damage_rect_; } + gfx::Size viewport_pixel_size() const { return viewport_pixel_size_; } +}; + class DisplayTest : public testing::Test { public: DisplayTest() : factory_(&manager_, &empty_client_), + software_output_device_(nullptr), task_runner_(new base::NullTaskRunner) {} protected: @@ -43,27 +52,30 @@ class DisplayTest : public testing::Test { output_surface_ = FakeOutputSurface::Create3d( TestContextProvider::Create(context.Pass())); } else { - output_surface_ = FakeOutputSurface::CreateSoftware( - make_scoped_ptr(new SoftwareOutputDevice)); + scoped_ptr<TestSoftwareOutputDevice> output_device( + new TestSoftwareOutputDevice); + software_output_device_ = output_device.get(); + output_surface_ = FakeOutputSurface::CreateSoftware(output_device.Pass()); } shared_bitmap_manager_.reset(new TestSharedBitmapManager); output_surface_ptr_ = output_surface_.get(); } - void SubmitFrame(RenderPassList* pass_list, SurfaceId surface_id) { + void SubmitCompositorFrame(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()); + factory_.SubmitCompositorFrame(surface_id, frame.Pass(), + SurfaceFactory::DrawCallback()); } SurfaceManager manager_; EmptySurfaceFactoryClient empty_client_; SurfaceFactory factory_; + TestSoftwareOutputDevice* software_output_device_; scoped_ptr<FakeOutputSurface> output_surface_; FakeOutputSurface* output_surface_ptr_; FakeBeginFrameSource fake_begin_frame_source_; @@ -89,13 +101,16 @@ class TestDisplayScheduler : public DisplayScheduler { base::NullTaskRunner* task_runner) : DisplayScheduler(client, begin_frame_source, task_runner, 1), damaged(false), - entire_display_damaged(false), + display_resized_(false), + has_new_root_surface(false), swapped(false) {} ~TestDisplayScheduler() override {} - void EntireDisplayDamaged(SurfaceId root_surface_id) override { - entire_display_damaged = true; + void DisplayResized() override { display_resized_ = true; } + + void SetNewRootSurface(SurfaceId root_surface_id) override { + has_new_root_surface = true; } void SurfaceDamaged(SurfaceId surface_id) override { @@ -107,11 +122,13 @@ class TestDisplayScheduler : public DisplayScheduler { void ResetDamageForTest() { damaged = false; - entire_display_damaged = false; + display_resized_ = false; + has_new_root_surface = false; } bool damaged; - bool entire_display_damaged; + bool display_resized_; + bool has_new_root_surface; bool swapped; }; @@ -135,15 +152,17 @@ TEST_F(DisplayTest, DisplayDamaged) { SurfaceId surface_id(7u); EXPECT_FALSE(scheduler.damaged); - EXPECT_FALSE(scheduler.entire_display_damaged); + EXPECT_FALSE(scheduler.has_new_root_surface); display.SetSurfaceId(surface_id, 1.f); EXPECT_FALSE(scheduler.damaged); - EXPECT_TRUE(scheduler.entire_display_damaged); + EXPECT_FALSE(scheduler.display_resized_); + EXPECT_TRUE(scheduler.has_new_root_surface); scheduler.ResetDamageForTest(); display.Resize(gfx::Size(100, 100)); EXPECT_FALSE(scheduler.damaged); - EXPECT_TRUE(scheduler.entire_display_damaged); + EXPECT_TRUE(scheduler.display_resized_); + EXPECT_FALSE(scheduler.has_new_root_surface); factory_.Create(surface_id); @@ -156,21 +175,19 @@ TEST_F(DisplayTest, DisplayDamaged) { pass_list.push_back(pass.Pass()); scheduler.ResetDamageForTest(); - SubmitFrame(&pass_list, surface_id); + SubmitCompositorFrame(&pass_list, surface_id); EXPECT_TRUE(scheduler.damaged); - EXPECT_FALSE(scheduler.entire_display_damaged); + EXPECT_FALSE(scheduler.display_resized_); + EXPECT_FALSE(scheduler.has_new_root_surface); EXPECT_FALSE(scheduler.swapped); EXPECT_EQ(0u, output_surface_ptr_->num_sent_frames()); display.DrawAndSwap(); EXPECT_TRUE(scheduler.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()); + EXPECT_EQ(gfx::Size(100, 100), + software_output_device_->viewport_pixel_size()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), software_output_device_->damage_rect()); { // Only damaged portion should be swapped. @@ -181,20 +198,18 @@ TEST_F(DisplayTest, DisplayDamaged) { pass_list.push_back(pass.Pass()); scheduler.ResetDamageForTest(); - SubmitFrame(&pass_list, surface_id); + SubmitCompositorFrame(&pass_list, surface_id); EXPECT_TRUE(scheduler.damaged); - EXPECT_FALSE(scheduler.entire_display_damaged); + EXPECT_FALSE(scheduler.display_resized_); + EXPECT_FALSE(scheduler.has_new_root_surface); scheduler.swapped = false; display.DrawAndSwap(); EXPECT_TRUE(scheduler.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()); + EXPECT_EQ(gfx::Size(100, 100), + software_output_device_->viewport_pixel_size()); + EXPECT_EQ(gfx::Rect(10, 10, 1, 1), software_output_device_->damage_rect()); } { @@ -206,9 +221,10 @@ TEST_F(DisplayTest, DisplayDamaged) { pass_list.push_back(pass.Pass()); scheduler.ResetDamageForTest(); - SubmitFrame(&pass_list, surface_id); + SubmitCompositorFrame(&pass_list, surface_id); EXPECT_TRUE(scheduler.damaged); - EXPECT_FALSE(scheduler.entire_display_damaged); + EXPECT_FALSE(scheduler.display_resized_); + EXPECT_FALSE(scheduler.has_new_root_surface); scheduler.swapped = false; display.DrawAndSwap(); @@ -225,9 +241,10 @@ TEST_F(DisplayTest, DisplayDamaged) { pass_list.push_back(pass.Pass()); scheduler.ResetDamageForTest(); - SubmitFrame(&pass_list, surface_id); + SubmitCompositorFrame(&pass_list, surface_id); EXPECT_TRUE(scheduler.damaged); - EXPECT_FALSE(scheduler.entire_display_damaged); + EXPECT_FALSE(scheduler.display_resized_); + EXPECT_FALSE(scheduler.has_new_root_surface); scheduler.swapped = false; display.DrawAndSwap(); @@ -236,6 +253,28 @@ TEST_F(DisplayTest, DisplayDamaged) { } { + // Previous frame wasn't swapped, so next swap should have full damage. + 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()); + scheduler.ResetDamageForTest(); + SubmitCompositorFrame(&pass_list, surface_id); + EXPECT_TRUE(scheduler.damaged); + EXPECT_FALSE(scheduler.display_resized_); + EXPECT_FALSE(scheduler.has_new_root_surface); + + scheduler.swapped = false; + display.DrawAndSwap(); + EXPECT_TRUE(scheduler.swapped); + EXPECT_EQ(3u, output_surface_ptr_->num_sent_frames()); + EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + software_output_device_->damage_rect()); + } + + { // Pass has copy output request so should be swapped. pass = RenderPass::Create(); pass->output_rect = gfx::Rect(0, 0, 100, 100); @@ -247,14 +286,15 @@ TEST_F(DisplayTest, DisplayDamaged) { pass_list.push_back(pass.Pass()); scheduler.ResetDamageForTest(); - SubmitFrame(&pass_list, surface_id); + SubmitCompositorFrame(&pass_list, surface_id); EXPECT_TRUE(scheduler.damaged); - EXPECT_FALSE(scheduler.entire_display_damaged); + EXPECT_FALSE(scheduler.display_resized_); + EXPECT_FALSE(scheduler.has_new_root_surface); scheduler.swapped = false; display.DrawAndSwap(); EXPECT_TRUE(scheduler.swapped); - EXPECT_EQ(3u, output_surface_ptr_->num_sent_frames()); + EXPECT_EQ(4u, output_surface_ptr_->num_sent_frames()); EXPECT_TRUE(copy_called); } @@ -274,15 +314,16 @@ TEST_F(DisplayTest, DisplayDamaged) { frame->delegated_frame_data = frame_data.Pass(); frame->metadata.latency_info.push_back(ui::LatencyInfo()); - factory_.SubmitFrame(surface_id, frame.Pass(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(surface_id, frame.Pass(), + SurfaceFactory::DrawCallback()); EXPECT_TRUE(scheduler.damaged); - EXPECT_FALSE(scheduler.entire_display_damaged); + EXPECT_FALSE(scheduler.display_resized_); + EXPECT_FALSE(scheduler.has_new_root_surface); scheduler.swapped = false; display.DrawAndSwap(); EXPECT_TRUE(scheduler.swapped); - EXPECT_EQ(4u, output_surface_ptr_->num_sent_frames()); + EXPECT_EQ(5u, output_surface_ptr_->num_sent_frames()); } // Resize should cause a swap if no frame was swapped at the previous size. @@ -290,7 +331,7 @@ TEST_F(DisplayTest, DisplayDamaged) { scheduler.swapped = false; display.Resize(gfx::Size(200, 200)); EXPECT_FALSE(scheduler.swapped); - EXPECT_EQ(4u, output_surface_ptr_->num_sent_frames()); + EXPECT_EQ(5u, output_surface_ptr_->num_sent_frames()); pass = RenderPass::Create(); pass->output_rect = gfx::Rect(0, 0, 200, 200); @@ -305,15 +346,16 @@ TEST_F(DisplayTest, DisplayDamaged) { scoped_ptr<CompositorFrame> frame(new CompositorFrame); frame->delegated_frame_data = frame_data.Pass(); - factory_.SubmitFrame(surface_id, frame.Pass(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(surface_id, frame.Pass(), + SurfaceFactory::DrawCallback()); EXPECT_TRUE(scheduler.damaged); - EXPECT_FALSE(scheduler.entire_display_damaged); + EXPECT_FALSE(scheduler.display_resized_); + EXPECT_FALSE(scheduler.has_new_root_surface); scheduler.swapped = false; display.Resize(gfx::Size(100, 100)); EXPECT_TRUE(scheduler.swapped); - EXPECT_EQ(5u, output_surface_ptr_->num_sent_frames()); + EXPECT_EQ(6u, output_surface_ptr_->num_sent_frames()); } factory_.Destroy(surface_id); @@ -355,7 +397,7 @@ TEST_F(DisplayTest, Finish) { pass->id = RenderPassId(1, 1); pass_list.push_back(pass.Pass()); - SubmitFrame(&pass_list, surface_id); + SubmitCompositorFrame(&pass_list, surface_id); } display.DrawAndSwap(); @@ -381,7 +423,7 @@ TEST_F(DisplayTest, Finish) { pass->id = RenderPassId(1, 1); pass_list.push_back(pass.Pass()); - SubmitFrame(&pass_list, surface_id); + SubmitCompositorFrame(&pass_list, surface_id); } display.DrawAndSwap(); diff --git a/chromium/cc/surfaces/onscreen_display_client.cc b/chromium/cc/surfaces/onscreen_display_client.cc index 2bd58fe4ca1..29a2a7a8ab2 100644 --- a/chromium/cc/surfaces/onscreen_display_client.cc +++ b/chromium/cc/surfaces/onscreen_display_client.cc @@ -29,7 +29,7 @@ OnscreenDisplayClient::OnscreenDisplayClient( settings)), task_runner_(task_runner), output_surface_lost_(false), - disable_gpu_vsync_(settings.disable_gpu_vsync) { + disable_display_vsync_(settings.disable_display_vsync) { } OnscreenDisplayClient::~OnscreenDisplayClient() { @@ -42,7 +42,7 @@ bool OnscreenDisplayClient::Initialize() { max_frames_pending = OutputSurface::DEFAULT_MAX_FRAMES_PENDING; BeginFrameSource* frame_source; - if (disable_gpu_vsync_) { + if (disable_display_vsync_) { unthrottled_frame_source_ = BackToBackBeginFrameSource::Create(task_runner_.get()); frame_source = unthrottled_frame_source_.get(); diff --git a/chromium/cc/surfaces/onscreen_display_client.h b/chromium/cc/surfaces/onscreen_display_client.h index c2f69f1bf2c..4c4245d4161 100644 --- a/chromium/cc/surfaces/onscreen_display_client.h +++ b/chromium/cc/surfaces/onscreen_display_client.h @@ -60,7 +60,7 @@ class CC_SURFACES_EXPORT OnscreenDisplayClient scoped_refptr<base::SingleThreadTaskRunner> task_runner_; SurfaceDisplayOutputSurface* surface_display_output_surface_; bool output_surface_lost_; - bool disable_gpu_vsync_; + bool disable_display_vsync_; private: DISALLOW_COPY_AND_ASSIGN(OnscreenDisplayClient); diff --git a/chromium/cc/surfaces/surface.h b/chromium/cc/surfaces/surface.h index d9099f3122b..8ef332ecb79 100644 --- a/chromium/cc/surfaces/surface.h +++ b/chromium/cc/surfaces/surface.h @@ -23,7 +23,7 @@ #include "ui/gfx/geometry/size.h" namespace ui { -struct LatencyInfo; +class LatencyInfo; } namespace cc { diff --git a/chromium/cc/surfaces/surface_aggregator.cc b/chromium/cc/surfaces/surface_aggregator.cc index ddfac7670b4..69618ba8b4c 100644 --- a/chromium/cc/surfaces/surface_aggregator.cc +++ b/chromium/cc/surfaces/surface_aggregator.cc @@ -41,8 +41,12 @@ void MoveMatchingRequests( } // namespace SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager, - ResourceProvider* provider) - : manager_(manager), provider_(provider), next_render_pass_id_(1) { + ResourceProvider* provider, + bool aggregate_only_damaged) + : manager_(manager), + provider_(provider), + next_render_pass_id_(1), + aggregate_only_damaged_(aggregate_only_damaged) { DCHECK(manager_); } @@ -154,11 +158,8 @@ void SurfaceAggregator::HandleSurfaceQuad( if (referenced_surfaces_.count(surface_id)) return; Surface* surface = manager_->GetSurfaceForId(surface_id); - if (!surface) { - contained_surfaces_[surface_id] = 0; + if (!surface) return; - } - contained_surfaces_[surface_id] = surface->frame_index(); const CompositorFrame* frame = surface->GetEligibleFrame(); if (!frame) return; @@ -251,11 +252,10 @@ void SurfaceAggregator::HandleSurfaceQuad( } 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->shared_quad_state_list.back(); + CopySharedQuadState(surface_quad->shared_quad_state, target_transform, + clip_rect, dest_pass); + RenderPassDrawQuad* quad = dest_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); quad->SetNew(shared_quad_state, @@ -270,11 +270,10 @@ void SurfaceAggregator::HandleSurfaceQuad( FilterOperations()); } - referenced_surfaces_.erase(it); } -void SurfaceAggregator::CopySharedQuadState( +SharedQuadState* SurfaceAggregator::CopySharedQuadState( const SharedQuadState* source_sqs, const gfx::Transform& target_transform, const ClipData& clip_rect, @@ -296,6 +295,21 @@ void SurfaceAggregator::CopySharedQuadState( target_transform); copy_shared_quad_state->is_clipped = new_clip_rect.is_clipped; copy_shared_quad_state->clip_rect = new_clip_rect.rect; + return copy_shared_quad_state; +} + +static gfx::Rect CalculateQuadSpaceDamageRect( + const gfx::Transform& quad_to_target_transform, + const gfx::Transform& target_to_root_transform, + const gfx::Rect& root_damage_rect) { + gfx::Transform quad_to_root_transform(target_to_root_transform, + quad_to_target_transform); + gfx::Transform inverse_transform(gfx::Transform::kSkipInitialization); + bool inverse_valid = quad_to_root_transform.GetInverse(&inverse_transform); + DCHECK(inverse_valid); + + return MathUtil::ProjectEnclosingClippedRect(inverse_transform, + root_damage_rect); } void SurfaceAggregator::CopyQuadsToPass( @@ -306,26 +320,65 @@ void SurfaceAggregator::CopyQuadsToPass( const ClipData& clip_rect, RenderPass* dest_pass, SurfaceId surface_id) { - const SharedQuadState* last_copied_source_shared_quad_state = NULL; - + const SharedQuadState* last_copied_source_shared_quad_state = nullptr; + const SharedQuadState* dest_shared_quad_state = nullptr; + // If the current frame has copy requests then aggregate the entire + // thing, as otherwise parts of the copy requests may be ignored. + const bool ignore_undamaged = aggregate_only_damaged_ && !has_copy_requests_; + // Damage rect in the quad space of the current shared quad state. + // TODO(jbauman): This rect may contain unnecessary area if + // transform isn't axis-aligned. + gfx::Rect damage_rect_in_quad_space; + +#if DCHECK_IS_ON() + // If quads have come in with SharedQuadState out of order, or when quads have + // invalid SharedQuadState pointer, it should DCHECK. SharedQuadStateList::ConstIterator sqs_iter = source_shared_quad_state_list.begin(); for (const auto& quad : source_quad_list) { - while (quad->shared_quad_state != *sqs_iter) { + while (sqs_iter != source_shared_quad_state_list.end() && + quad->shared_quad_state != *sqs_iter) { ++sqs_iter; - DCHECK(sqs_iter != source_shared_quad_state_list.end()); } - DCHECK_EQ(quad->shared_quad_state, *sqs_iter); + DCHECK(sqs_iter != source_shared_quad_state_list.end()); + } +#endif + for (const auto& quad : source_quad_list) { if (quad->material == DrawQuad::SURFACE_CONTENT) { const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad); + // HandleSurfaceQuad may add other shared quad state, so reset the + // current data. + last_copied_source_shared_quad_state = nullptr; + + if (ignore_undamaged) { + gfx::Transform quad_to_target_transform( + target_transform, + quad->shared_quad_state->quad_to_target_transform); + damage_rect_in_quad_space = CalculateQuadSpaceDamageRect( + quad_to_target_transform, dest_pass->transform_to_root_target, + root_damage_rect_); + if (!damage_rect_in_quad_space.Intersects(quad->visible_rect)) + continue; + } 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, target_transform, - clip_rect, dest_pass); + dest_shared_quad_state = CopySharedQuadState( + quad->shared_quad_state, target_transform, clip_rect, dest_pass); last_copied_source_shared_quad_state = quad->shared_quad_state; + if (aggregate_only_damaged_ && !has_copy_requests_) { + damage_rect_in_quad_space = CalculateQuadSpaceDamageRect( + dest_shared_quad_state->quad_to_target_transform, + dest_pass->transform_to_root_target, root_damage_rect_); + } } + + if (ignore_undamaged) { + if (!damage_rect_in_quad_space.Intersects(quad->visible_rect)) + continue; + } + DrawQuad* dest_quad; if (quad->material == DrawQuad::RENDER_PASS) { const RenderPassDrawQuad* pass_quad = @@ -335,11 +388,10 @@ void SurfaceAggregator::CopyQuadsToPass( RemapPassId(original_pass_id, surface_id); dest_quad = dest_pass->CopyFromAndAppendRenderPassDrawQuad( - pass_quad, dest_pass->shared_quad_state_list.back(), - remapped_pass_id); + pass_quad, dest_shared_quad_state, remapped_pass_id); } else { - dest_quad = dest_pass->CopyFromAndAppendDrawQuad( - quad, dest_pass->shared_quad_state_list.back()); + dest_quad = + dest_pass->CopyFromAndAppendDrawQuad(quad, dest_shared_quad_state); } if (!child_to_parent_map.empty()) { for (ResourceId& resource_id : dest_quad->resources) { @@ -415,15 +467,18 @@ void SurfaceAggregator::RemoveUnreferencedChildren() { } } -// Validate the resources of the current surface and its descendants, and -// calculate their combined damage rect. -gfx::Rect SurfaceAggregator::ValidateAndCalculateDamageRect( - SurfaceId surface_id) { +// Walk the Surface tree from surface_id. Validate the resources of the current +// surface and its descendants, check if there are any copy requests, and +// return the combined damage rect. +gfx::Rect SurfaceAggregator::PrewalkTree(SurfaceId surface_id) { if (referenced_surfaces_.count(surface_id)) return gfx::Rect(); Surface* surface = manager_->GetSurfaceForId(surface_id); - if (!surface) + if (!surface) { + contained_surfaces_[surface_id] = 0; return gfx::Rect(); + } + contained_surfaces_[surface_id] = surface->frame_index(); const CompositorFrame* surface_frame = surface->GetEligibleFrame(); if (!surface_frame) return gfx::Rect(); @@ -467,8 +522,8 @@ gfx::Rect SurfaceAggregator::ValidateAndCalculateDamageRect( const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad); gfx::Transform target_to_surface_transform( - surface_quad->shared_quad_state->quad_to_target_transform, - render_pass->transform_to_root_target); + render_pass->transform_to_root_target, + surface_quad->shared_quad_state->quad_to_target_transform); child_surfaces.push_back(std::make_pair(surface_quad->surface_id, target_to_surface_transform)); } @@ -492,11 +547,14 @@ gfx::Rect SurfaceAggregator::ValidateAndCalculateDamageRect( if (provider_) provider_->DeclareUsedResourcesFromChild(child_id, referenced_resources); + for (const auto& render_pass : frame_data->render_pass_list) + has_copy_requests_ |= !render_pass->copy_requests.empty(); + gfx::Rect damage_rect; if (!frame_data->render_pass_list.empty()) { + RenderPass* last_pass = frame_data->render_pass_list.back(); damage_rect = - DamageRectForSurface(surface, *frame_data->render_pass_list.back(), - frame_data->render_pass_list.back()->output_rect); + DamageRectForSurface(surface, *last_pass, last_pass->output_rect); } // Avoid infinite recursion by adding current surface to @@ -504,8 +562,7 @@ gfx::Rect SurfaceAggregator::ValidateAndCalculateDamageRect( SurfaceSet::iterator it = referenced_surfaces_.insert(surface->surface_id()).first; for (const auto& surface_info : child_surfaces) { - gfx::Rect surface_damage = - ValidateAndCalculateDamageRect(surface_info.first); + gfx::Rect surface_damage = PrewalkTree(surface_info.first); damage_rect.Union( MathUtil::MapEnclosingClippedRect(surface_info.second, surface_damage)); } @@ -531,7 +588,8 @@ scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) { dest_pass_list_ = &frame->delegated_frame_data->render_pass_list; valid_surfaces_.clear(); - gfx::Rect damage_rect = ValidateAndCalculateDamageRect(surface_id); + has_copy_requests_ = false; + root_damage_rect_ = PrewalkTree(surface_id); SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first; CopyPasses(root_surface_frame->delegated_frame_data.get(), surface); @@ -541,7 +599,7 @@ scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) { if (dest_pass_list_->empty()) return nullptr; - dest_pass_list_->back()->damage_rect = damage_rect; + dest_pass_list_->back()->damage_rect = root_damage_rect_; dest_pass_list_ = NULL; RemoveUnreferencedChildren(); diff --git a/chromium/cc/surfaces/surface_aggregator.h b/chromium/cc/surfaces/surface_aggregator.h index 17ea4c43125..1ff4a45804b 100644 --- a/chromium/cc/surfaces/surface_aggregator.h +++ b/chromium/cc/surfaces/surface_aggregator.h @@ -29,7 +29,9 @@ class CC_SURFACES_EXPORT SurfaceAggregator { public: typedef base::hash_map<SurfaceId, int> SurfaceIndexMap; - SurfaceAggregator(SurfaceManager* manager, ResourceProvider* provider); + SurfaceAggregator(SurfaceManager* manager, + ResourceProvider* provider, + bool aggregate_only_damaged); ~SurfaceAggregator(); scoped_ptr<CompositorFrame> Aggregate(SurfaceId surface_id); @@ -60,10 +62,10 @@ class CC_SURFACES_EXPORT SurfaceAggregator { const gfx::Transform& target_transform, const ClipData& clip_rect, RenderPass* dest_pass); - void CopySharedQuadState(const SharedQuadState* source_sqs, - const gfx::Transform& target_transform, - const ClipData& clip_rect, - RenderPass* dest_render_pass); + SharedQuadState* CopySharedQuadState(const SharedQuadState* source_sqs, + 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, @@ -72,7 +74,7 @@ class CC_SURFACES_EXPORT SurfaceAggregator { const ClipData& clip_rect, RenderPass* dest_pass, SurfaceId surface_id); - gfx::Rect ValidateAndCalculateDamageRect(SurfaceId surface_id); + gfx::Rect PrewalkTree(SurfaceId surface_id); void CopyPasses(const DelegatedFrameData* frame_data, Surface* surface); // Remove Surfaces that were referenced before but aren't currently @@ -92,6 +94,7 @@ class CC_SURFACES_EXPORT SurfaceAggregator { RenderPassIdAllocatorMap; RenderPassIdAllocatorMap render_pass_allocator_map_; int next_render_pass_id_; + const bool aggregate_only_damaged_; typedef base::hash_map<SurfaceId, int> SurfaceToResourceChildIdMap; SurfaceToResourceChildIdMap surface_id_to_resource_child_id_; @@ -116,6 +119,13 @@ class CC_SURFACES_EXPORT SurfaceAggregator { // This is the pass list for the aggregated frame. RenderPassList* dest_pass_list_; + // The root damage rect of the currently-aggregating frame. + gfx::Rect root_damage_rect_; + + // True if the frame that's currently being aggregated has copy requests. + // This is valid during Aggregate after PrewalkTree is called. + bool has_copy_requests_; + // Resource list for the aggregated frame. TransferableResourceArray* dest_resource_list_; diff --git a/chromium/cc/surfaces/surface_aggregator_perftest.cc b/chromium/cc/surfaces/surface_aggregator_perftest.cc index b5fddf51dc6..71589edd7ec 100644 --- a/chromium/cc/surfaces/surface_aggregator_perftest.cc +++ b/chromium/cc/surfaces/surface_aggregator_perftest.cc @@ -36,14 +36,16 @@ class SurfaceAggregatorPerfTest : public testing::Test { resource_provider_ = FakeResourceProvider::Create( output_surface_.get(), shared_bitmap_manager_.get()); - aggregator_.reset( - new SurfaceAggregator(&manager_, resource_provider_.get())); } void RunTest(int num_surfaces, int num_textures, float opacity, + bool optimize_damage, + bool full_damage, const std::string& name) { + aggregator_.reset(new SurfaceAggregator(&manager_, resource_provider_.get(), + optimize_damage)); for (int i = 1; i <= num_surfaces; i++) { factory_.Create(SurfaceId(i)); scoped_ptr<RenderPass> pass(RenderPass::Create()); @@ -60,7 +62,9 @@ class SurfaceAggregatorPerfTest : public testing::Test { 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); + // Half of rects should be visible with partial damage. + gfx::Rect visible_rect = + j % 2 == 0 ? gfx::Rect(0, 0, 1, 1) : gfx::Rect(1, 1, 1, 1); bool needs_blending = false; bool premultiplied_alpha = false; const gfx::PointF uv_top_left; @@ -86,20 +90,42 @@ class SurfaceAggregatorPerfTest : public testing::Test { 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()); + factory_.SubmitCompositorFrame(SurfaceId(i), frame.Pass(), + SurfaceFactory::DrawCallback()); } + factory_.Create(SurfaceId(num_surfaces + 1)); timer_.Reset(); do { + scoped_ptr<RenderPass> pass(RenderPass::Create()); + scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); + + SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState(); + SurfaceDrawQuad* surface_quad = + pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>(); + surface_quad->SetNew(sqs, gfx::Rect(0, 0, 100, 100), + gfx::Rect(0, 0, 100, 100), SurfaceId(num_surfaces)); + + if (full_damage) + pass->damage_rect = gfx::Rect(0, 0, 100, 100); + else + pass->damage_rect = gfx::Rect(0, 0, 1, 1); + + frame_data->render_pass_list.push_back(pass.Pass()); + scoped_ptr<CompositorFrame> frame(new CompositorFrame); + frame->delegated_frame_data = frame_data.Pass(); + factory_.SubmitCompositorFrame(SurfaceId(num_surfaces + 1), frame.Pass(), + SurfaceFactory::DrawCallback()); + scoped_ptr<CompositorFrame> aggregated = - aggregator_->Aggregate(SurfaceId(num_surfaces)); + aggregator_->Aggregate(SurfaceId(num_surfaces + 1)); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); perf_test::PrintResult("aggregator_speed", "", name, timer_.LapsPerSecond(), "runs/s", true); + factory_.Destroy(SurfaceId(num_surfaces + 1)); for (int i = 1; i <= num_surfaces; i++) factory_.Destroy(SurfaceId(i)); } @@ -117,15 +143,31 @@ class SurfaceAggregatorPerfTest : public testing::Test { }; TEST_F(SurfaceAggregatorPerfTest, ManySurfacesOpaque) { - RunTest(20, 100, 1.f, "many_surfaces_opaque"); + RunTest(20, 100, 1.f, false, true, "many_surfaces_opaque"); } TEST_F(SurfaceAggregatorPerfTest, ManySurfacesTransparent) { - RunTest(20, 100, .5f, "many_surfaces_transparent"); + RunTest(20, 100, .5f, false, true, "many_surfaces_transparent"); } TEST_F(SurfaceAggregatorPerfTest, FewSurfaces) { - RunTest(3, 1000, 1.f, "few_surfaces"); + RunTest(3, 1000, 1.f, false, true, "few_surfaces"); +} + +TEST_F(SurfaceAggregatorPerfTest, ManySurfacesOpaqueDamageCalc) { + RunTest(20, 100, 1.f, true, true, "many_surfaces_opaque_damage_calc"); +} + +TEST_F(SurfaceAggregatorPerfTest, ManySurfacesTransparentDamageCalc) { + RunTest(20, 100, .5f, true, true, "many_surfaces_transparent_damage_calc"); +} + +TEST_F(SurfaceAggregatorPerfTest, FewSurfacesDamageCalc) { + RunTest(3, 1000, 1.f, true, true, "few_surfaces_damage_calc"); +} + +TEST_F(SurfaceAggregatorPerfTest, FewSurfacesAggregateDamaged) { + RunTest(3, 1000, 1.f, true, false, "few_surfaces_aggregate_damaged"); } } // namespace diff --git a/chromium/cc/surfaces/surface_aggregator_test_helpers.cc b/chromium/cc/surfaces/surface_aggregator_test_helpers.cc index f7da1a25c84..45b57d0ffe7 100644 --- a/chromium/cc/surfaces/surface_aggregator_test_helpers.cc +++ b/chromium/cc/surfaces/surface_aggregator_test_helpers.cc @@ -14,7 +14,6 @@ #include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/surface_draw_quad.h" #include "cc/surfaces/surface.h" -#include "cc/test/render_pass_test_common.h" #include "cc/test/render_pass_test_utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkXfermode.h" @@ -22,10 +21,10 @@ namespace cc { namespace test { -void AddTestSurfaceQuad(TestRenderPass* pass, - const gfx::Size& surface_size, - float opacity, - SurfaceId surface_id) { +void AddSurfaceQuad(RenderPass* pass, + const gfx::Size& surface_size, + float opacity, + SurfaceId surface_id) { gfx::Transform layer_to_target_transform; gfx::Size layer_bounds = surface_size; gfx::Rect visible_layer_rect = gfx::Rect(surface_size); @@ -46,7 +45,7 @@ void AddTestSurfaceQuad(TestRenderPass* pass, gfx::Rect(surface_size), surface_id); } -void AddTestRenderPassQuad(TestRenderPass* pass, RenderPassId render_pass_id) { +void AddRenderPassQuad(RenderPass* pass, RenderPassId render_pass_id) { gfx::Rect output_rect = gfx::Rect(0, 0, 5, 5); SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState(); shared_state->SetAll(gfx::Transform(), @@ -71,16 +70,16 @@ void AddTestRenderPassQuad(TestRenderPass* pass, RenderPassId render_pass_id) { FilterOperations()); } -void AddQuadInPass(TestRenderPass* pass, Quad desc) { +void AddQuadInPass(RenderPass* pass, Quad desc) { switch (desc.material) { case DrawQuad::SOLID_COLOR: AddQuad(pass, gfx::Rect(0, 0, 5, 5), desc.color); break; case DrawQuad::SURFACE_CONTENT: - AddTestSurfaceQuad(pass, gfx::Size(5, 5), desc.opacity, desc.surface_id); + AddSurfaceQuad(pass, gfx::Size(5, 5), desc.opacity, desc.surface_id); break; case DrawQuad::RENDER_PASS: - AddTestRenderPassQuad(pass, desc.render_pass_id); + AddRenderPassQuad(pass, desc.render_pass_id); break; default: NOTREACHED(); @@ -94,7 +93,7 @@ void AddPasses(RenderPassList* pass_list, gfx::Transform root_transform; for (size_t i = 0; i < pass_count; ++i) { Pass pass = passes[i]; - TestRenderPass* test_pass = + RenderPass* test_pass = AddRenderPass(pass_list, pass.id, output_rect, root_transform); for (size_t j = 0; j < pass.quad_count; ++j) { AddQuadInPass(test_pass, pass.quads[j]); diff --git a/chromium/cc/surfaces/surface_aggregator_unittest.cc b/chromium/cc/surfaces/surface_aggregator_unittest.cc index e4ade82116e..b2476d9df57 100644 --- a/chromium/cc/surfaces/surface_aggregator_unittest.cc +++ b/chromium/cc/surfaces/surface_aggregator_unittest.cc @@ -20,7 +20,6 @@ #include "cc/test/fake_output_surface.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_resource_provider.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 "testing/gmock/include/gmock/gmock.h" @@ -48,8 +47,11 @@ class EmptySurfaceFactoryClient : public SurfaceFactoryClient { class SurfaceAggregatorTest : public testing::Test { public: - SurfaceAggregatorTest() - : factory_(&manager_, &empty_client_), aggregator_(&manager_, NULL) {} + explicit SurfaceAggregatorTest(bool use_damage_rect) + : factory_(&manager_, &empty_client_), + aggregator_(&manager_, NULL, use_damage_rect) {} + + SurfaceAggregatorTest() : SurfaceAggregatorTest(false) {} protected: SurfaceManager manager_; @@ -68,7 +70,12 @@ TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) { class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest { public: - SurfaceAggregatorValidSurfaceTest() : allocator_(1u), child_allocator_(2u) {} + explicit SurfaceAggregatorValidSurfaceTest(bool use_damage_rect) + : SurfaceAggregatorTest(use_damage_rect), + allocator_(1u), + child_allocator_(2u) {} + SurfaceAggregatorValidSurfaceTest() + : SurfaceAggregatorValidSurfaceTest(false) {} void SetUp() override { SurfaceAggregatorTest::SetUp(); @@ -112,20 +119,23 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest { } } - void SubmitFrame(test::Pass* passes, - size_t pass_count, - SurfaceId surface_id) { - RenderPassList pass_list; - AddPasses(&pass_list, gfx::Rect(SurfaceSize()), passes, pass_count); - + void SubmitPassListAsFrame(SurfaceId surface_id, RenderPassList* pass_list) { scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); - pass_list.swap(frame_data->render_pass_list); + 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()); + factory_.SubmitCompositorFrame(surface_id, frame.Pass(), + SurfaceFactory::DrawCallback()); + } + + void SubmitCompositorFrame(test::Pass* passes, + size_t pass_count, + SurfaceId surface_id) { + RenderPassList pass_list; + AddPasses(&pass_list, gfx::Rect(SurfaceSize()), passes, pass_count); + SubmitPassListAsFrame(surface_id, &pass_list); } void QueuePassAsFrame(scoped_ptr<RenderPass> pass, SurfaceId surface_id) { @@ -135,8 +145,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(surface_id, child_frame.Pass(), + SurfaceFactory::DrawCallback()); } protected: @@ -152,7 +162,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleFrame) { test::Quad::SolidColorQuad(SK_ColorBLUE)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; - SubmitFrame(passes, arraysize(passes), root_surface_id_); + SubmitCompositorFrame(passes, arraysize(passes), root_surface_id_); SurfaceId ids[] = {root_surface_id_}; AggregateAndVerify(passes, arraysize(passes), ids, arraysize(ids)); @@ -167,12 +177,13 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) { test::Pass embedded_passes[] = { test::Pass(embedded_quads, arraysize(embedded_quads))}; - SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id); + SubmitCompositorFrame(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_); + SubmitCompositorFrame(passes, arraysize(passes), root_surface_id_); scoped_ptr<CompositorFrame> aggregated_frame = aggregator_.Aggregate(root_surface_id_); @@ -207,7 +218,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) { test::Pass(quads[0], arraysize(quads[0]), RenderPassId(1, 1)), test::Pass(quads[1], arraysize(quads[1]), RenderPassId(1, 2))}; - SubmitFrame(passes, arraysize(passes), root_surface_id_); + SubmitCompositorFrame(passes, arraysize(passes), root_surface_id_); SurfaceId ids[] = {root_surface_id_}; AggregateAndVerify(passes, arraysize(passes), ids, arraysize(ids)); @@ -225,14 +236,15 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) { test::Pass embedded_passes[] = { test::Pass(embedded_quads, arraysize(embedded_quads))}; - SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id); + SubmitCompositorFrame(embedded_passes, arraysize(embedded_passes), + embedded_surface_id); test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE), test::Quad::SurfaceQuad(embedded_surface_id, 1.f), test::Quad::SolidColorQuad(SK_ColorBLACK)}; test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; - SubmitFrame(root_passes, arraysize(root_passes), root_surface_id_); + SubmitCompositorFrame(root_passes, arraysize(root_passes), root_surface_id_); test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE), test::Quad::SolidColorQuad(SK_ColorGREEN), @@ -254,7 +266,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) { test::Pass embedded_passes[] = { test::Pass(embedded_quads, arraysize(embedded_quads))}; - SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id); + SubmitCompositorFrame(embedded_passes, arraysize(embedded_passes), + embedded_surface_id); scoped_ptr<CopyOutputRequest> copy_request( CopyOutputRequest::CreateEmptyRequest()); CopyOutputRequest* copy_request_ptr = copy_request.get(); @@ -265,7 +278,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) { test::Quad::SolidColorQuad(SK_ColorBLACK)}; test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; - SubmitFrame(root_passes, arraysize(root_passes), root_surface_id_); + SubmitCompositorFrame(root_passes, arraysize(root_passes), root_surface_id_); scoped_ptr<CompositorFrame> aggregated_frame = aggregator_.Aggregate(root_surface_id_); @@ -311,7 +324,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) { test::Pass embedded_passes[] = { test::Pass(embedded_quads, arraysize(embedded_quads))}; - SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id); + SubmitCompositorFrame(embedded_passes, arraysize(embedded_passes), + embedded_surface_id); scoped_ptr<CopyOutputRequest> copy_request( CopyOutputRequest::CreateEmptyRequest()); CopyOutputRequest* copy_request_ptr = copy_request.get(); @@ -341,8 +355,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(root_surface_id_, frame.Pass(), + SurfaceFactory::DrawCallback()); } scoped_ptr<CompositorFrame> aggregated_frame = @@ -408,7 +422,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) { test::Pass(embedded_quads[1], arraysize(embedded_quads[1]), pass_ids[1]), test::Pass(embedded_quads[2], arraysize(embedded_quads[2]), pass_ids[2])}; - SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id); + SubmitCompositorFrame(embedded_passes, arraysize(embedded_passes), + embedded_surface_id); test::Quad root_quads[][2] = { {test::Quad::SolidColorQuad(5), test::Quad::SolidColorQuad(6)}, @@ -420,7 +435,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) { test::Pass(root_quads[1], arraysize(root_quads[1]), pass_ids[1]), test::Pass(root_quads[2], arraysize(root_quads[2]), pass_ids[2])}; - SubmitFrame(root_passes, arraysize(root_passes), root_surface_id_); + SubmitCompositorFrame(root_passes, arraysize(root_passes), root_surface_id_); scoped_ptr<CompositorFrame> aggregated_frame = aggregator_.Aggregate(root_surface_id_); @@ -537,7 +552,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) { test::Quad::SolidColorQuad(SK_ColorBLUE)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; - SubmitFrame(passes, arraysize(passes), root_surface_id_); + SubmitCompositorFrame(passes, arraysize(passes), root_surface_id_); test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), test::Quad::SolidColorQuad(SK_ColorBLUE)}; @@ -558,7 +573,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) { test::Quad::SolidColorQuad(SK_ColorBLUE)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; - SubmitFrame(passes, arraysize(passes), root_surface_id_); + SubmitCompositorFrame(passes, arraysize(passes), root_surface_id_); test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), test::Quad::SolidColorQuad(SK_ColorBLUE)}; @@ -577,7 +592,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) { test::Quad::SolidColorQuad(SK_ColorYELLOW)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; - SubmitFrame(passes, arraysize(passes), root_surface_id_); + SubmitCompositorFrame(passes, arraysize(passes), root_surface_id_); test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorYELLOW)}; test::Pass expected_passes[] = { @@ -598,14 +613,16 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) { test::Pass parent_passes[] = { test::Pass(parent_quads, arraysize(parent_quads))}; - SubmitFrame(parent_passes, arraysize(parent_passes), root_surface_id_); + SubmitCompositorFrame(parent_passes, arraysize(parent_passes), + root_surface_id_); test::Quad child_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), test::Quad::SurfaceQuad(root_surface_id_, 1.f), test::Quad::SolidColorQuad(SK_ColorMAGENTA)}; test::Pass child_passes[] = {test::Pass(child_quads, arraysize(child_quads))}; - SubmitFrame(child_passes, arraysize(child_passes), child_surface_id); + SubmitCompositorFrame(child_passes, arraysize(child_passes), + child_surface_id); // The child surface's reference to the root_surface_ will be dropped, so // we'll end up with: @@ -638,7 +655,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) { test::Pass(child_quad[0], arraysize(child_quad[0]), child_pass_id[0]), test::Pass(child_quad[1], arraysize(child_quad[1]), child_pass_id[1])}; - SubmitFrame(surface_passes, arraysize(surface_passes), child_surface_id); + SubmitCompositorFrame(surface_passes, arraysize(surface_passes), + child_surface_id); // Pass IDs from the parent surface may collide with ones from the child. RenderPassId parent_pass_id[] = {RenderPassId(2, 1), RenderPassId(1, 2)}; @@ -649,7 +667,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) { test::Pass(parent_quad[0], arraysize(parent_quad[0]), parent_pass_id[0]), test::Pass(parent_quad[1], arraysize(parent_quad[1]), parent_pass_id[1])}; - SubmitFrame(parent_passes, arraysize(parent_passes), root_surface_id_); + SubmitCompositorFrame(parent_passes, arraysize(parent_passes), + root_surface_id_); scoped_ptr<CompositorFrame> aggregated_frame = aggregator_.Aggregate(root_surface_id_); @@ -896,8 +915,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) { 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_.SubmitCompositorFrame(child_surface_id, child_frame.Pass(), + SurfaceFactory::DrawCallback()); } // Middle child surface. @@ -927,8 +946,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) { 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()); + factory_.SubmitCompositorFrame(middle_surface_id, middle_frame.Pass(), + SurfaceFactory::DrawCallback()); } // Root surface. @@ -963,8 +982,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(root_surface_id_, root_frame.Pass(), + SurfaceFactory::DrawCallback()); scoped_ptr<CompositorFrame> aggregated_frame = aggregator_.Aggregate(root_surface_id_); @@ -1072,8 +1091,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) { SurfaceId child_surface_id = allocator_.GenerateId(); factory_.Create(child_surface_id); - factory_.SubmitFrame(child_surface_id, child_frame.Pass(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(child_surface_id, child_frame.Pass(), + SurfaceFactory::DrawCallback()); test::Quad parent_surface_quads[] = { test::Quad::SurfaceQuad(child_surface_id, 1.f)}; @@ -1098,8 +1117,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) { SurfaceId parent_surface_id = allocator_.GenerateId(); factory_.Create(parent_surface_id); - factory_.SubmitFrame(parent_surface_id, parent_surface_frame.Pass(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(parent_surface_id, parent_surface_frame.Pass(), + SurfaceFactory::DrawCallback()); test::Quad root_surface_quads[] = { test::Quad::SurfaceQuad(parent_surface_id, 1.f)}; @@ -1130,8 +1149,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(root_surface_id_, root_frame.Pass(), + SurfaceFactory::DrawCallback()); scoped_ptr<CompositorFrame> aggregated_frame = aggregator_.Aggregate(root_surface_id_); @@ -1167,8 +1186,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(child_surface_id, child_frame.Pass(), + SurfaceFactory::DrawCallback()); scoped_ptr<CompositorFrame> aggregated_frame = aggregator_.Aggregate(root_surface_id_); @@ -1207,8 +1226,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(root_surface_id_, root_frame.Pass(), + SurfaceFactory::DrawCallback()); } { @@ -1229,8 +1248,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(root_surface_id_, root_frame.Pass(), + SurfaceFactory::DrawCallback()); scoped_ptr<CompositorFrame> aggregated_frame = aggregator_.Aggregate(root_surface_id_); @@ -1293,6 +1312,196 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) { factory_.Destroy(child_surface_id); } +class SurfaceAggregatorPartialSwapTest + : public SurfaceAggregatorValidSurfaceTest { + public: + SurfaceAggregatorPartialSwapTest() + : SurfaceAggregatorValidSurfaceTest(true) {} +}; + +// Tests that quads outside the damage rect are ignored. +TEST_F(SurfaceAggregatorPartialSwapTest, IgnoreOutside) { + SurfaceId child_surface_id = allocator_.GenerateId(); + factory_.Create(child_surface_id); + // The child surface has two quads, one with a visible rect of 13,13 4x4 and + // the other other with a visible rect of 10,10 2x2 (relative to root target + // space). + { + RenderPassId child_pass_id = RenderPassId(1, 1); + test::Quad child_quads1[] = {test::Quad::RenderPassQuad(child_pass_id)}; + test::Quad child_quads2[] = {test::Quad::RenderPassQuad(child_pass_id)}; + test::Pass child_passes[] = { + test::Pass(child_quads1, arraysize(child_quads1), child_pass_id), + test::Pass(child_quads2, arraysize(child_quads2), child_pass_id)}; + + RenderPassList child_pass_list; + AddPasses(&child_pass_list, gfx::Rect(SurfaceSize()), child_passes, + arraysize(child_passes)); + + child_pass_list.at(0u)->quad_list.ElementAt(0)->visible_rect = + gfx::Rect(1, 1, 2, 2); + SharedQuadState* child_sqs = + child_pass_list.at(0u)->shared_quad_state_list.ElementAt(0u); + child_sqs->quad_to_target_transform.Translate(1, 1); + child_sqs->quad_to_target_transform.Scale(2, 2); + + child_pass_list.at(1u)->quad_list.ElementAt(0)->visible_rect = + gfx::Rect(0, 0, 2, 2); + + SubmitPassListAsFrame(child_surface_id, &child_pass_list); + } + + { + test::Quad root_quads[] = {test::Quad::SurfaceQuad(child_surface_id, 1.f)}; + + test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; + + RenderPassList root_pass_list; + AddPasses(&root_pass_list, gfx::Rect(SurfaceSize()), root_passes, + arraysize(root_passes)); + + RenderPass* root_pass = root_pass_list.at(0u); + root_pass->shared_quad_state_list.front() + ->quad_to_target_transform.Translate(10, 10); + root_pass->damage_rect = gfx::Rect(0, 0, 1, 1); + + SubmitPassListAsFrame(root_surface_id_, &root_pass_list); + } + + 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()); + + // Damage rect for first aggregation should contain entire root surface. + EXPECT_EQ(gfx::Rect(0, 0, 15, 15), aggregated_pass_list[1]->damage_rect); + EXPECT_EQ(1u, aggregated_pass_list[0]->quad_list.size()); + EXPECT_EQ(1u, aggregated_pass_list[1]->quad_list.size()); + + // Create a root surface with a smaller damage rect. + { + test::Quad root_quads[] = {test::Quad::SurfaceQuad(child_surface_id, 1.f)}; + + test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; + + RenderPassList root_pass_list; + AddPasses(&root_pass_list, gfx::Rect(SurfaceSize()), root_passes, + arraysize(root_passes)); + + RenderPass* root_pass = root_pass_list.at(0u); + root_pass->shared_quad_state_list.front() + ->quad_to_target_transform.Translate(10, 10); + root_pass->damage_rect = gfx::Rect(10, 10, 2, 2); + SubmitPassListAsFrame(root_surface_id_, &root_pass_list); + } + + { + 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()); + + // Only first quad from surface is inside damage rect and should be + // included. + EXPECT_EQ(gfx::Rect(10, 10, 2, 2), aggregated_pass_list[1]->damage_rect); + EXPECT_EQ(0u, aggregated_pass_list[0]->quad_list.size()); + EXPECT_EQ(1u, aggregated_pass_list[1]->quad_list.size()); + EXPECT_EQ(gfx::Rect(0, 0, 2, 2), + aggregated_pass_list[1]->quad_list.back()->visible_rect); + } + + // New child frame has same content and no damage, but has a + // CopyOutputRequest. + { + RenderPassId child_pass_id = RenderPassId(1, 1); + test::Quad child_quads1[] = {test::Quad::RenderPassQuad(child_pass_id)}; + test::Quad child_quads2[] = {test::Quad::RenderPassQuad(child_pass_id)}; + test::Pass child_passes[] = { + test::Pass(child_quads1, arraysize(child_quads1), child_pass_id), + test::Pass(child_quads2, arraysize(child_quads2), child_pass_id)}; + + RenderPassList child_pass_list; + AddPasses(&child_pass_list, gfx::Rect(SurfaceSize()), child_passes, + arraysize(child_passes)); + + child_pass_list.at(0u)->quad_list.ElementAt(0)->visible_rect = + gfx::Rect(1, 1, 2, 2); + SharedQuadState* child_sqs = + child_pass_list.at(0u)->shared_quad_state_list.ElementAt(0u); + child_sqs->quad_to_target_transform.Translate(1, 1); + child_sqs->quad_to_target_transform.Scale(2, 2); + + child_pass_list.at(1u)->quad_list.ElementAt(0)->visible_rect = + gfx::Rect(0, 0, 2, 2); + + RenderPass* child_root_pass = child_pass_list.at(1u); + + child_root_pass->copy_requests.push_back( + CopyOutputRequest::CreateEmptyRequest()); + child_root_pass->damage_rect = gfx::Rect(); + SubmitPassListAsFrame(child_surface_id, &child_pass_list); + } + + { + 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; + + // Output frame should have no damage, but all quads included. + ASSERT_EQ(3u, aggregated_pass_list.size()); + + EXPECT_TRUE(aggregated_pass_list[1]->damage_rect.IsEmpty()); + ASSERT_EQ(1u, aggregated_pass_list[0]->quad_list.size()); + ASSERT_EQ(1u, aggregated_pass_list[1]->quad_list.size()); + EXPECT_EQ(gfx::Rect(1, 1, 2, 2), + aggregated_pass_list[0]->quad_list.ElementAt(0)->visible_rect); + EXPECT_EQ(gfx::Rect(0, 0, 2, 2), + aggregated_pass_list[1]->quad_list.ElementAt(0)->visible_rect); + } + + { + 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; + // There were no changes since last aggregation, so output should be empty + // and have no damage. + ASSERT_EQ(1u, aggregated_pass_list.size()); + EXPECT_TRUE(aggregated_pass_list[0]->damage_rect.IsEmpty()); + ASSERT_EQ(0u, aggregated_pass_list[0]->quad_list.size()); + } + + factory_.Destroy(child_surface_id); +} + class SurfaceAggregatorWithResourcesTest : public testing::Test { public: void SetUp() override { @@ -1305,7 +1514,7 @@ class SurfaceAggregatorWithResourcesTest : public testing::Test { output_surface_.get(), shared_bitmap_manager_.get()); aggregator_.reset( - new SurfaceAggregator(&manager_, resource_provider_.get())); + new SurfaceAggregator(&manager_, resource_provider_.get(), false)); } protected: @@ -1336,12 +1545,12 @@ class ResourceTrackingSurfaceFactoryClient : public SurfaceFactoryClient { DISALLOW_COPY_AND_ASSIGN(ResourceTrackingSurfaceFactoryClient); }; -void SubmitFrameWithResources(ResourceId* resource_ids, - size_t num_resource_ids, - bool valid, - SurfaceId child_id, - SurfaceFactory* factory, - SurfaceId surface_id) { +void SubmitCompositorFrameWithResources(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); @@ -1380,8 +1589,8 @@ void SubmitFrameWithResources(ResourceId* resource_ids, 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()); + factory->SubmitCompositorFrame(surface_id, frame.Pass(), + SurfaceFactory::DrawCallback()); } TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) { @@ -1391,15 +1600,16 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) { factory.Create(surface_id); ResourceId ids[] = {11, 12, 13}; - SubmitFrameWithResources(ids, arraysize(ids), true, SurfaceId(), &factory, - surface_id); + SubmitCompositorFrameWithResources(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, true, SurfaceId(), &factory, surface_id); + SubmitCompositorFrameWithResources(NULL, 0u, true, SurfaceId(), &factory, + surface_id); frame = aggregator_->Aggregate(surface_id); @@ -1431,7 +1641,8 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeInvalidResources) { 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()); + factory.SubmitCompositorFrame(surface_id, frame.Pass(), + SurfaceFactory::DrawCallback()); scoped_ptr<CompositorFrame> returned_frame = aggregator_->Aggregate(surface_id); @@ -1439,7 +1650,8 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeInvalidResources) { // Nothing should be available to be returned yet. EXPECT_TRUE(client.returned_resources().empty()); - SubmitFrameWithResources(NULL, 0, true, SurfaceId(), &factory, surface_id); + SubmitCompositorFrameWithResources(NULL, 0, true, SurfaceId(), &factory, + surface_id); ASSERT_EQ(1u, client.returned_resources().size()); EXPECT_EQ(11u, client.returned_resources()[0].id); @@ -1455,15 +1667,16 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TwoSurfaces) { factory.Create(surface_id2); ResourceId ids[] = {11, 12, 13}; - SubmitFrameWithResources(ids, arraysize(ids), true, SurfaceId(), &factory, - surface_id); + SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(), + &factory, surface_id); ResourceId ids2[] = {14, 15, 16}; - SubmitFrameWithResources(ids2, arraysize(ids2), true, SurfaceId(), &factory, - surface_id2); + SubmitCompositorFrameWithResources(ids2, arraysize(ids2), true, SurfaceId(), + &factory, surface_id2); scoped_ptr<CompositorFrame> frame = aggregator_->Aggregate(surface_id); - SubmitFrameWithResources(NULL, 0, true, SurfaceId(), &factory, surface_id); + SubmitCompositorFrameWithResources(NULL, 0, true, SurfaceId(), &factory, + surface_id); // Nothing should be available to be returned yet. EXPECT_TRUE(client.returned_resources().empty()); @@ -1496,16 +1709,18 @@ TEST_F(SurfaceAggregatorWithResourcesTest, InvalidChildSurface) { factory.Create(child_surface_id); ResourceId ids[] = {14, 15, 16}; - SubmitFrameWithResources(ids, arraysize(ids), true, SurfaceId(), &factory, - child_surface_id); + SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(), + &factory, child_surface_id); ResourceId ids2[] = {17, 18, 19}; - SubmitFrameWithResources(ids2, arraysize(ids2), false, child_surface_id, - &factory, middle_surface_id); + SubmitCompositorFrameWithResources(ids2, arraysize(ids2), false, + child_surface_id, &factory, + middle_surface_id); ResourceId ids3[] = {20, 21, 22}; - SubmitFrameWithResources(ids3, arraysize(ids3), true, middle_surface_id, - &factory, root_surface_id); + SubmitCompositorFrameWithResources(ids3, arraysize(ids3), true, + middle_surface_id, &factory, + root_surface_id); scoped_ptr<CompositorFrame> frame; frame = aggregator_->Aggregate(root_surface_id); @@ -1515,8 +1730,9 @@ TEST_F(SurfaceAggregatorWithResourcesTest, InvalidChildSurface) { 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); + SubmitCompositorFrameWithResources(ids2, arraysize(ids), true, + child_surface_id, &factory, + middle_surface_id); frame = aggregator_->Aggregate(root_surface_id); diff --git a/chromium/cc/surfaces/surface_display_output_surface.cc b/chromium/cc/surfaces/surface_display_output_surface.cc index e21d15d8afb..ed26b491bf0 100644 --- a/chromium/cc/surfaces/surface_display_output_surface.cc +++ b/chromium/cc/surfaces/surface_display_output_surface.cc @@ -17,8 +17,9 @@ namespace cc { SurfaceDisplayOutputSurface::SurfaceDisplayOutputSurface( SurfaceManager* surface_manager, SurfaceIdAllocator* allocator, - const scoped_refptr<ContextProvider>& context_provider) - : OutputSurface(context_provider), + const scoped_refptr<ContextProvider>& context_provider, + const scoped_refptr<ContextProvider>& worker_context_provider) + : OutputSurface(context_provider, worker_context_provider), display_client_(NULL), factory_(surface_manager, this), allocator_(allocator) { @@ -63,7 +64,7 @@ void SurfaceDisplayOutputSurface::SwapBuffers(CompositorFrame* frame) { scoped_ptr<CompositorFrame> frame_copy(new CompositorFrame()); frame->AssignTo(frame_copy.get()); - factory_.SubmitFrame( + factory_.SubmitCompositorFrame( surface_id_, frame_copy.Pass(), base::Bind(&SurfaceDisplayOutputSurface::SwapBuffersComplete, base::Unretained(this))); @@ -80,7 +81,8 @@ bool SurfaceDisplayOutputSurface::BindToClient(OutputSurfaceClient* client) { void SurfaceDisplayOutputSurface::ForceReclaimResources() { if (!surface_id_.is_null()) - factory_.SubmitFrame(surface_id_, nullptr, SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(surface_id_, nullptr, + SurfaceFactory::DrawCallback()); } void SurfaceDisplayOutputSurface::ReturnResources( diff --git a/chromium/cc/surfaces/surface_display_output_surface.h b/chromium/cc/surfaces/surface_display_output_surface.h index c11bb86075d..2cdaadc7830 100644 --- a/chromium/cc/surfaces/surface_display_output_surface.h +++ b/chromium/cc/surfaces/surface_display_output_surface.h @@ -27,7 +27,8 @@ class CC_SURFACES_EXPORT SurfaceDisplayOutputSurface SurfaceDisplayOutputSurface( SurfaceManager* surface_manager, SurfaceIdAllocator* allocator, - const scoped_refptr<ContextProvider>& context_provider); + const scoped_refptr<ContextProvider>& context_provider, + const scoped_refptr<ContextProvider>& worker_context_provider); ~SurfaceDisplayOutputSurface() override; void set_display_client(OnscreenDisplayClient* display_client) { diff --git a/chromium/cc/surfaces/surface_display_output_surface_unittest.cc b/chromium/cc/surfaces/surface_display_output_surface_unittest.cc index 922dd9e8d5f..daabafec7f0 100644 --- a/chromium/cc/surfaces/surface_display_output_surface_unittest.cc +++ b/chromium/cc/surfaces/surface_display_output_surface_unittest.cc @@ -60,7 +60,8 @@ class SurfaceDisplayOutputSurfaceTest : public testing::Test { context_provider_(TestContextProvider::Create()), surface_display_output_surface_(&surface_manager_, &allocator_, - context_provider_) { + context_provider_, + nullptr) { output_surface_ = display_client_.output_surface(); display_client_.set_surface_output_surface( &surface_display_output_surface_); diff --git a/chromium/cc/surfaces/surface_factory.cc b/chromium/cc/surfaces/surface_factory.cc index 9bb50ace4c2..3e83c8cfd73 100644 --- a/chromium/cc/surfaces/surface_factory.cc +++ b/chromium/cc/surfaces/surface_factory.cc @@ -4,6 +4,7 @@ #include "cc/surfaces/surface_factory.h" +#include "base/trace_event/trace_event.h" #include "cc/output/compositor_frame.h" #include "cc/output/copy_output_request.h" #include "cc/surfaces/surface.h" @@ -47,15 +48,18 @@ void SurfaceFactory::Destroy(SurfaceId surface_id) { manager_->Destroy(surface_map_.take_and_erase(it)); } -void SurfaceFactory::SubmitFrame(SurfaceId surface_id, - scoped_ptr<CompositorFrame> frame, - const DrawCallback& callback) { +void SurfaceFactory::SubmitCompositorFrame(SurfaceId surface_id, + scoped_ptr<CompositorFrame> frame, + const DrawCallback& callback) { + TRACE_EVENT0("cc", "SurfaceFactory::SubmitCompositorFrame"); 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); - if (!manager_->SurfaceModified(surface_id)) + if (!manager_->SurfaceModified(surface_id)) { + TRACE_EVENT_INSTANT0("cc", "Damage not visible.", TRACE_EVENT_SCOPE_THREAD); 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 0e812de5e23..5af8d2e0eb7 100644 --- a/chromium/cc/surfaces/surface_factory.h +++ b/chromium/cc/surfaces/surface_factory.h @@ -11,6 +11,7 @@ #include "base/containers/scoped_ptr_hash_map.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "cc/output/compositor_frame.h" #include "cc/surfaces/surface_id.h" #include "cc/surfaces/surface_resource_holder.h" #include "cc/surfaces/surface_sequence.h" @@ -21,7 +22,6 @@ class Size; } namespace cc { -class CompositorFrame; class CopyOutputRequest; class Surface; class SurfaceFactoryClient; @@ -49,9 +49,9 @@ class CC_SURFACES_EXPORT SurfaceFactory // although the frame may reference surfaces created by other factories. // 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 DrawCallback& callback); + void SubmitCompositorFrame(SurfaceId surface_id, + scoped_ptr<CompositorFrame> frame, + const DrawCallback& callback); void RequestCopyOfSurface(SurfaceId surface_id, scoped_ptr<CopyOutputRequest> copy_request); diff --git a/chromium/cc/surfaces/surface_factory_unittest.cc b/chromium/cc/surfaces/surface_factory_unittest.cc index c2951aead48..c7ce96403e2 100644 --- a/chromium/cc/surfaces/surface_factory_unittest.cc +++ b/chromium/cc/surfaces/surface_factory_unittest.cc @@ -49,8 +49,8 @@ class SurfaceFactoryTest : public testing::Test { factory_.Destroy(surface_id_); } - void SubmitFrameWithResources(ResourceId* resource_ids, - size_t num_resource_ids) { + void SubmitCompositorFrameWithResources(ResourceId* resource_ids, + size_t num_resource_ids) { scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); for (size_t i = 0u; i < num_resource_ids; ++i) { TransferableResource resource; @@ -60,8 +60,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(surface_id_, frame.Pass(), + SurfaceFactory::DrawCallback()); } void UnrefResources(ResourceId* ids_to_unref, @@ -108,7 +108,8 @@ class SurfaceFactoryTest : public testing::Test { // with no resource provider action in between. TEST_F(SurfaceFactoryTest, ResourceLifetimeSimple) { ResourceId first_frame_ids[] = {1, 2, 3}; - SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + SubmitCompositorFrameWithResources(first_frame_ids, + arraysize(first_frame_ids)); // All of the resources submitted in the first frame are still in use at this // time by virtue of being in the pending frame, so none can be returned to @@ -118,7 +119,7 @@ TEST_F(SurfaceFactoryTest, ResourceLifetimeSimple) { // The second frame references no resources and thus should make all resources // available to be returned. - SubmitFrameWithResources(NULL, 0); + SubmitCompositorFrameWithResources(NULL, 0); ResourceId expected_returned_ids[] = {1, 2, 3}; int expected_returned_counts[] = {1, 1, 1}; @@ -131,7 +132,8 @@ TEST_F(SurfaceFactoryTest, ResourceLifetimeSimple) { // with the resource provider holding everything alive. TEST_F(SurfaceFactoryTest, ResourceLifetimeSimpleWithProviderHoldingAlive) { ResourceId first_frame_ids[] = {1, 2, 3}; - SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + SubmitCompositorFrameWithResources(first_frame_ids, + arraysize(first_frame_ids)); // All of the resources submitted in the first frame are still in use at this // time by virtue of being in the pending frame, so none can be returned to @@ -144,7 +146,7 @@ TEST_F(SurfaceFactoryTest, ResourceLifetimeSimpleWithProviderHoldingAlive) { // The second frame references no resources and thus should make all resources // available to be returned as soon as the resource provider releases them. - SubmitFrameWithResources(NULL, 0); + SubmitCompositorFrameWithResources(NULL, 0); EXPECT_EQ(0u, client_.returned_resources().size()); client_.clear_returned_resources(); @@ -163,16 +165,18 @@ TEST_F(SurfaceFactoryTest, ResourceLifetimeSimpleWithProviderHoldingAlive) { // before returning it to the client. TEST_F(SurfaceFactoryTest, ResourceReusedBeforeReturn) { ResourceId first_frame_ids[] = {7}; - SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + SubmitCompositorFrameWithResources(first_frame_ids, + arraysize(first_frame_ids)); // This removes all references to resource id 7. - SubmitFrameWithResources(NULL, 0); + SubmitCompositorFrameWithResources(NULL, 0); // This references id 7 again. - SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + SubmitCompositorFrameWithResources(first_frame_ids, + arraysize(first_frame_ids)); // This removes it again. - SubmitFrameWithResources(NULL, 0); + SubmitCompositorFrameWithResources(NULL, 0); // Now it should be returned. // We don't care how many entries are in the returned array for 7, so long as @@ -190,14 +194,16 @@ TEST_F(SurfaceFactoryTest, ResourceReusedBeforeReturn) { // multiple providers. TEST_F(SurfaceFactoryTest, ResourceRefMultipleTimes) { ResourceId first_frame_ids[] = {3, 4}; - SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + SubmitCompositorFrameWithResources(first_frame_ids, + arraysize(first_frame_ids)); // Ref resources from the first frame twice. RefCurrentFrameResources(); RefCurrentFrameResources(); ResourceId second_frame_ids[] = {4, 5}; - SubmitFrameWithResources(second_frame_ids, arraysize(second_frame_ids)); + SubmitCompositorFrameWithResources(second_frame_ids, + arraysize(second_frame_ids)); // Ref resources from the second frame 3 times. RefCurrentFrameResources(); @@ -206,7 +212,7 @@ TEST_F(SurfaceFactoryTest, ResourceRefMultipleTimes) { // Submit a frame with no resources to remove all current frame refs from // submitted resources. - SubmitFrameWithResources(NULL, 0); + SubmitCompositorFrameWithResources(NULL, 0); EXPECT_EQ(0u, client_.returned_resources().size()); client_.clear_returned_resources(); @@ -267,7 +273,8 @@ TEST_F(SurfaceFactoryTest, ResourceRefMultipleTimes) { TEST_F(SurfaceFactoryTest, ResourceLifetime) { ResourceId first_frame_ids[] = {1, 2, 3}; - SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + SubmitCompositorFrameWithResources(first_frame_ids, + arraysize(first_frame_ids)); // All of the resources submitted in the first frame are still in use at this // time by virtue of being in the pending frame, so none can be returned to @@ -279,7 +286,8 @@ TEST_F(SurfaceFactoryTest, ResourceLifetime) { // ones. We expect to receive back resource 1 with a count of 1 since it was // only referenced by the first frame. ResourceId second_frame_ids[] = {2, 3, 4}; - SubmitFrameWithResources(second_frame_ids, arraysize(second_frame_ids)); + SubmitCompositorFrameWithResources(second_frame_ids, + arraysize(second_frame_ids)); { SCOPED_TRACE("second frame"); @@ -295,7 +303,8 @@ TEST_F(SurfaceFactoryTest, ResourceLifetime) { // and 3 will have counts of 2, since they were used in both frames, and // resource ID 4 will have a count of 1. ResourceId third_frame_ids[] = {10, 11, 12, 13}; - SubmitFrameWithResources(third_frame_ids, arraysize(third_frame_ids)); + SubmitCompositorFrameWithResources(third_frame_ids, + arraysize(third_frame_ids)); { SCOPED_TRACE("third frame"); @@ -310,7 +319,8 @@ TEST_F(SurfaceFactoryTest, ResourceLifetime) { RefCurrentFrameResources(); ResourceId fourth_frame_ids[] = {12, 13}; - SubmitFrameWithResources(fourth_frame_ids, arraysize(fourth_frame_ids)); + SubmitCompositorFrameWithResources(fourth_frame_ids, + arraysize(fourth_frame_ids)); EXPECT_EQ(0u, client_.returned_resources().size()); @@ -348,7 +358,7 @@ TEST_F(SurfaceFactoryTest, ResourceLifetime) { EXPECT_EQ(0u, client_.returned_resources().size()); // If we submit an empty frame, however, they should become available. - SubmitFrameWithResources(NULL, 0u); + SubmitCompositorFrameWithResources(NULL, 0u); { SCOPED_TRACE("fourth frame, second unref"); @@ -369,8 +379,8 @@ TEST_F(SurfaceFactoryTest, BlankNoIndexIncrement) { scoped_ptr<CompositorFrame> frame(new CompositorFrame); frame->delegated_frame_data.reset(new DelegatedFrameData); - factory_.SubmitFrame(surface_id, frame.Pass(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(surface_id, frame.Pass(), + SurfaceFactory::DrawCallback()); EXPECT_EQ(2, surface->frame_index()); factory_.Destroy(surface_id); } @@ -397,8 +407,8 @@ TEST_F(SurfaceFactoryTest, DestroyAll) { uint32 execute_count = 0; SurfaceDrawStatus drawn = SurfaceDrawStatus::DRAW_SKIPPED; - factory_.SubmitFrame(id, frame.Pass(), - base::Bind(&DrawCallback, &execute_count, &drawn)); + factory_.SubmitCompositorFrame( + id, frame.Pass(), base::Bind(&DrawCallback, &execute_count, &drawn)); surface_id_ = SurfaceId(); factory_.DestroyAll(); @@ -423,8 +433,8 @@ 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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(surface_id_, frame.Pass(), + SurfaceFactory::DrawCallback()); DCHECK(!manager_.GetSurfaceForId(id2)); // Check that waiting after the sequence is satisfied works. @@ -475,7 +485,8 @@ TEST_F(SurfaceFactoryTest, DestroyCycle) { frame_data->render_pass_list.push_back(render_pass.Pass()); scoped_ptr<CompositorFrame> frame(new CompositorFrame); frame->delegated_frame_data = frame_data.Pass(); - factory_.SubmitFrame(id2, frame.Pass(), SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(id2, frame.Pass(), + SurfaceFactory::DrawCallback()); } factory_.Destroy(id2); @@ -487,8 +498,8 @@ TEST_F(SurfaceFactoryTest, DestroyCycle) { frame_data->render_pass_list.push_back(render_pass.Pass()); scoped_ptr<CompositorFrame> frame(new CompositorFrame); frame->delegated_frame_data = frame_data.Pass(); - factory_.SubmitFrame(surface_id_, frame.Pass(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(surface_id_, frame.Pass(), + SurfaceFactory::DrawCallback()); } factory_.Destroy(surface_id_); EXPECT_TRUE(manager_.GetSurfaceForId(id2)); diff --git a/chromium/cc/surfaces/surface_hittest.cc b/chromium/cc/surfaces/surface_hittest.cc new file mode 100644 index 00000000000..3a3864ecdb8 --- /dev/null +++ b/chromium/cc/surfaces/surface_hittest.cc @@ -0,0 +1,175 @@ +// 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_hittest.h" + +#include "cc/output/compositor_frame.h" +#include "cc/output/delegated_frame_data.h" +#include "cc/quads/draw_quad.h" +#include "cc/quads/render_pass_draw_quad.h" +#include "cc/quads/surface_draw_quad.h" +#include "cc/surfaces/surface.h" +#include "cc/surfaces/surface_manager.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/transform.h" + +namespace cc { +namespace { +} + +SurfaceHittest::SurfaceHittest(SurfaceManager* manager) : manager_(manager) {} + +SurfaceHittest::~SurfaceHittest() {} + +SurfaceId SurfaceHittest::GetTargetSurfaceAtPoint(SurfaceId surface_id, + const gfx::Point& point, + gfx::Transform* transform) { + SurfaceId hittest_surface_id = surface_id; + // Reset the output transform to identity. + if (transform) + *transform = gfx::Transform(); + + std::set<const RenderPass*> referenced_passes; + GetTargetSurfaceAtPointInternal(surface_id, RenderPassId(), point, + &referenced_passes, &hittest_surface_id, + transform); + + return hittest_surface_id; +} + +bool SurfaceHittest::GetTargetSurfaceAtPointInternal( + SurfaceId surface_id, + const RenderPassId& render_pass_id, + const gfx::Point& point_in_root_target, + std::set<const RenderPass*>* referenced_passes, + SurfaceId* out_surface_id, + gfx::Transform* out_transform) { + const RenderPass* render_pass = + GetRenderPassForSurfaceById(surface_id, render_pass_id); + if (!render_pass) + return false; + + // To avoid an infinite recursion, we need to skip the RenderPass if it's + // already been referenced. + if (referenced_passes->find(render_pass) != referenced_passes->end()) + return false; + + referenced_passes->insert(render_pass); + + // The |transform_to_root_target| matrix cannot be inverted if it has a + // z-scale of 0 or due to floating point errors. + gfx::Transform transform_from_root_target; + if (!render_pass->transform_to_root_target.GetInverse( + &transform_from_root_target)) { + return false; + } + + gfx::Point point_in_render_pass_space(point_in_root_target); + transform_from_root_target.TransformPoint(&point_in_render_pass_space); + + for (const DrawQuad* quad : render_pass->quad_list) { + gfx::Transform target_to_quad_transform; + gfx::Point point_in_quad_space; + if (!PointInQuad(quad, point_in_render_pass_space, + &target_to_quad_transform, &point_in_quad_space)) { + continue; + } + + if (quad->material == DrawQuad::SURFACE_CONTENT) { + // We've hit a SurfaceDrawQuad, we need to recurse into this + // Surface. + const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad); + + gfx::Transform transform_to_child_space; + if (GetTargetSurfaceAtPointInternal( + surface_quad->surface_id, RenderPassId(), point_in_quad_space, + referenced_passes, out_surface_id, &transform_to_child_space)) { + *out_transform = transform_to_child_space * target_to_quad_transform * + transform_from_root_target; + return true; + } + + continue; + } + + if (quad->material == DrawQuad::RENDER_PASS) { + // We've hit a RenderPassDrawQuad, we need to recurse into this + // RenderPass. + const RenderPassDrawQuad* render_quad = + RenderPassDrawQuad::MaterialCast(quad); + + gfx::Transform transform_to_child_space; + if (GetTargetSurfaceAtPointInternal( + surface_id, render_quad->render_pass_id, point_in_root_target, + referenced_passes, out_surface_id, &transform_to_child_space)) { + *out_transform = transform_to_child_space; + return true; + } + + continue; + } + + // We've hit a different type of quad in the current Surface. There's no + // need to iterate anymore, this is the quad that receives the event. + *out_surface_id = surface_id; + return true; + } + + // No quads were found beneath the provided |point|. + return false; +} + +const RenderPass* SurfaceHittest::GetRenderPassForSurfaceById( + SurfaceId surface_id, + const RenderPassId& render_pass_id) { + Surface* surface = manager_->GetSurfaceForId(surface_id); + if (!surface) + return nullptr; + + const CompositorFrame* surface_frame = surface->GetEligibleFrame(); + if (!surface_frame) + return nullptr; + + const DelegatedFrameData* frame_data = + surface_frame->delegated_frame_data.get(); + if (frame_data->render_pass_list.empty()) + return nullptr; + + if (!render_pass_id.IsValid()) + return frame_data->render_pass_list.back(); + + for (const auto* render_pass : frame_data->render_pass_list) { + if (render_pass->id == render_pass_id) + return render_pass; + } + + return nullptr; +} + +bool SurfaceHittest::PointInQuad(const DrawQuad* quad, + const gfx::Point& point_in_render_pass_space, + gfx::Transform* target_to_quad_transform, + gfx::Point* point_in_quad_space) { + // First we test against the clip_rect. The clip_rect is in target space, so + // we can test the point directly. + if (quad->shared_quad_state->is_clipped && + !quad->shared_quad_state->clip_rect.Contains( + point_in_render_pass_space)) { + return false; + } + + // We now transform the point to content space and test if it hits the + // rect. + if (!quad->shared_quad_state->quad_to_target_transform.GetInverse( + target_to_quad_transform)) { + return false; + } + + *point_in_quad_space = point_in_render_pass_space; + target_to_quad_transform->TransformPoint(point_in_quad_space); + + return quad->rect.Contains(*point_in_quad_space); +} + +} // namespace cc diff --git a/chromium/cc/surfaces/surface_hittest.h b/chromium/cc/surfaces/surface_hittest.h new file mode 100644 index 00000000000..b5e1a672494 --- /dev/null +++ b/chromium/cc/surfaces/surface_hittest.h @@ -0,0 +1,60 @@ +// 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_SURFACES_SURFACE_HITTEST_H_ +#define CC_SURFACES_SURFACE_HITTEST_H_ + +#include <set> + +#include "cc/surfaces/surface_id.h" +#include "cc/surfaces/surfaces_export.h" + +namespace gfx { +class Point; +class Transform; +} + +namespace cc { +class DrawQuad; +class QuadList; +class RenderPass; +class RenderPassId; +class SurfaceManager; + +// Performs a hittest in surface quads. +class CC_SURFACES_EXPORT SurfaceHittest { + public: + explicit SurfaceHittest(SurfaceManager* manager); + ~SurfaceHittest(); + + // Hittests against Surface with SurfaceId |surface_id|, return the contained + // surface that the point is hitting and the |transformed_point| in the + // surface space. + SurfaceId GetTargetSurfaceAtPoint(SurfaceId surface_id, + const gfx::Point& point, + gfx::Transform* transform); + + private: + bool GetTargetSurfaceAtPointInternal( + SurfaceId surface_id, + const RenderPassId& render_pass_id, + const gfx::Point& point_in_root_target, + std::set<const RenderPass*>* referenced_passes, + SurfaceId* out_surface_id, + gfx::Transform* out_transform); + + const RenderPass* GetRenderPassForSurfaceById( + SurfaceId surface_id, + const RenderPassId& render_pass_id); + + bool PointInQuad(const DrawQuad* quad, + const gfx::Point& point_in_render_pass_space, + gfx::Transform* target_to_quad_transform, + gfx::Point* point_in_quad_space); + + SurfaceManager* const manager_; +}; +} // namespace cc + +#endif // CC_SURFACES_SURFACE_HITTEST_H_ diff --git a/chromium/cc/surfaces/surface_hittest_unittest.cc b/chromium/cc/surfaces/surface_hittest_unittest.cc new file mode 100644 index 00000000000..a7f373fff10 --- /dev/null +++ b/chromium/cc/surfaces/surface_hittest_unittest.cc @@ -0,0 +1,487 @@ +// 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/delegated_frame_data.h" +#include "cc/quads/render_pass.h" +#include "cc/quads/render_pass_draw_quad.h" +#include "cc/quads/render_pass_id.h" +#include "cc/quads/solid_color_draw_quad.h" +#include "cc/quads/surface_draw_quad.h" +#include "cc/surfaces/surface.h" +#include "cc/surfaces/surface_factory.h" +#include "cc/surfaces/surface_factory_client.h" +#include "cc/surfaces/surface_hittest.h" +#include "cc/surfaces/surface_id_allocator.h" +#include "cc/surfaces/surface_manager.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/geometry/size.h" + +namespace cc { + +namespace { + +class EmptySurfaceFactoryClient : public SurfaceFactoryClient { + public: + void ReturnResources(const ReturnedResourceArray& resources) override {} +}; + +void CreateSharedQuadState(RenderPass* pass, + const gfx::Transform& transform, + const gfx::Rect& root_rect) { + SharedQuadState* child_shared_state = + pass->CreateAndAppendSharedQuadState(); + child_shared_state->SetAll(transform, + root_rect.size(), + root_rect, root_rect, false, 1.0f, + SkXfermode::kSrcOver_Mode, 0); +} + +void CreateSolidColorDrawQuad(RenderPass* pass, + const gfx::Transform& transform, + const gfx::Rect& root_rect, + const gfx::Rect& quad_rect) { + CreateSharedQuadState(pass, transform, root_rect); + SolidColorDrawQuad* color_quad = + pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); + color_quad->SetNew(pass->shared_quad_state_list.back(), + quad_rect, quad_rect, + SK_ColorYELLOW, false); +} + +void CreateRenderPassDrawQuad(RenderPass* pass, + const gfx::Transform& transform, + const gfx::Rect& root_rect, + const gfx::Rect& quad_rect, + const RenderPassId& render_pass_id) { + CreateSharedQuadState(pass, transform, root_rect); + RenderPassDrawQuad* render_pass_quad = + pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>(); + render_pass_quad->SetNew(pass->shared_quad_state_list.back(), + quad_rect, quad_rect, + render_pass_id, + ResourceId(), + gfx::Vector2dF(), + gfx::Size(), + FilterOperations(), + gfx::Vector2dF(), + FilterOperations()); +} + +void CreateSurfaceDrawQuad(RenderPass* pass, + const gfx::Transform& transform, + const gfx::Rect& root_rect, + const gfx::Rect& quad_rect, + SurfaceId surface_id) { + CreateSharedQuadState(pass, transform, root_rect); + SurfaceDrawQuad* surface_quad = + pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>(); + surface_quad->SetNew(pass->shared_quad_state_list.back(), + quad_rect, quad_rect, + surface_id); +} + +void CreateRenderPass(const RenderPassId& render_pass_id, + const gfx::Rect& rect, + const gfx::Transform& transform_to_root_target, + RenderPassList* render_pass_list) { + scoped_ptr<RenderPass> render_pass = RenderPass::Create(); + render_pass->SetNew(render_pass_id, rect, rect, transform_to_root_target); + render_pass_list->push_back(render_pass.Pass()); +} + +scoped_ptr<CompositorFrame> CreateCompositorFrameWithRenderPassList( + RenderPassList* render_pass_list) { + scoped_ptr<DelegatedFrameData> root_delegated_frame_data( + new DelegatedFrameData); + root_delegated_frame_data->render_pass_list.swap(*render_pass_list); + scoped_ptr<CompositorFrame> root_frame(new CompositorFrame); + root_frame->delegated_frame_data = root_delegated_frame_data.Pass(); + return root_frame.Pass(); +} + +scoped_ptr<CompositorFrame> CreateCompositorFrame( + const gfx::Rect& root_rect, + RenderPass** render_pass) { + RenderPassList render_pass_list; + RenderPassId root_id(1, 1); + CreateRenderPass(root_id, root_rect, gfx::Transform(), &render_pass_list); + + scoped_ptr<CompositorFrame> root_frame = + CreateCompositorFrameWithRenderPassList(&render_pass_list); + + *render_pass = root_frame->delegated_frame_data->render_pass_list.back(); + return root_frame.Pass(); +} + +} // namespace + +// This test verifies that hit testing on a surface that does not exist does +// not crash. +TEST(SurfaceHittestTest, Hittest_BadCompositorFrameDoesNotCrash) { + SurfaceManager manager; + EmptySurfaceFactoryClient client; + SurfaceFactory factory(&manager, &client); + + // Creates a root surface. + gfx::Rect root_rect(300, 300); + RenderPass* root_pass = nullptr; + scoped_ptr<CompositorFrame> root_frame = + CreateCompositorFrame(root_rect, &root_pass); + + // Add a reference to a non-existant child surface on the root surface. + SurfaceIdAllocator child_allocator(3); + SurfaceId child_surface_id; + child_surface_id.id = 0xdeadbeef; + gfx::Rect child_rect(200, 200); + CreateSurfaceDrawQuad(root_pass, + gfx::Transform(), + root_rect, + child_rect, + child_surface_id); + + // Submit the root frame. + SurfaceIdAllocator root_allocator(2); + SurfaceId root_surface_id = root_allocator.GenerateId(); + factory.Create(root_surface_id); + factory.SubmitCompositorFrame(root_surface_id, root_frame.Pass(), + SurfaceFactory::DrawCallback()); + + { + SurfaceHittest hittest(&manager); + // It is expected this test will complete without crashes. + gfx::Transform transform; + EXPECT_EQ(root_surface_id, + hittest.GetTargetSurfaceAtPoint( + root_surface_id, gfx::Point(100, 100), &transform)); + } + + factory.Destroy(root_surface_id); +} + +TEST(SurfaceHittestTest, Hittest_SingleSurface) { + SurfaceManager manager; + EmptySurfaceFactoryClient client; + SurfaceFactory factory(&manager, &client); + + // Creates a root surface. + gfx::Rect root_rect(300, 300); + RenderPass* root_pass = nullptr; + scoped_ptr<CompositorFrame> root_frame = + CreateCompositorFrame(root_rect, &root_pass); + + // Submit the root frame. + SurfaceIdAllocator root_allocator(2); + SurfaceId root_surface_id = root_allocator.GenerateId(); + factory.Create(root_surface_id); + factory.SubmitCompositorFrame(root_surface_id, root_frame.Pass(), + SurfaceFactory::DrawCallback()); + + { + SurfaceHittest hittest(&manager); + gfx::Point point(100, 100); + gfx::Transform transform; + EXPECT_EQ(root_surface_id, hittest.GetTargetSurfaceAtPoint( + root_surface_id, point, &transform)); + transform.TransformPoint(&point); + EXPECT_EQ(gfx::Point(100, 100), point); + } + + factory.Destroy(root_surface_id); +} + +TEST(SurfaceHittestTest, Hittest_ChildSurface) { + SurfaceManager manager; + EmptySurfaceFactoryClient client; + SurfaceFactory factory(&manager, &client); + + // Creates a root surface. + gfx::Rect root_rect(300, 300); + RenderPass* root_pass = nullptr; + scoped_ptr<CompositorFrame> root_frame = + CreateCompositorFrame(root_rect, &root_pass); + + // Add a reference to the child surface on the root surface. + SurfaceIdAllocator child_allocator(3); + SurfaceId child_surface_id = child_allocator.GenerateId(); + gfx::Rect child_rect(200, 200); + CreateSurfaceDrawQuad(root_pass, + gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, + 0.0f, 1.0f, 0.0f, 50.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f), + root_rect, + child_rect, + child_surface_id); + + // Submit the root frame. + SurfaceIdAllocator root_allocator(2); + SurfaceId root_surface_id = root_allocator.GenerateId(); + factory.Create(root_surface_id); + factory.SubmitCompositorFrame(root_surface_id, root_frame.Pass(), + SurfaceFactory::DrawCallback()); + + // Creates a child surface. + RenderPass* child_pass = nullptr; + scoped_ptr<CompositorFrame> child_frame = + CreateCompositorFrame(child_rect, &child_pass); + + // Add a solid quad in the child surface. + gfx::Rect child_solid_quad_rect(100, 100); + CreateSolidColorDrawQuad( + child_pass, + gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), + root_rect, child_solid_quad_rect); + + // Submit the frame. + factory.Create(child_surface_id); + factory.SubmitCompositorFrame(child_surface_id, child_frame.Pass(), + SurfaceFactory::DrawCallback()); + + struct Test { + SurfaceId input_surface_id; + gfx::Point input_point; + SurfaceId expected_output_surface_id; + gfx::Point expected_output_point; + } tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id, + gfx::Point(10, 10)}, + {root_surface_id, gfx::Point(99, 99), root_surface_id, + gfx::Point(99, 99)}, + {root_surface_id, gfx::Point(100, 100), child_surface_id, + gfx::Point(50, 50)}, + {root_surface_id, gfx::Point(199, 199), child_surface_id, + gfx::Point(149, 149)}, + {root_surface_id, gfx::Point(200, 200), root_surface_id, + gfx::Point(200, 200)}, + {root_surface_id, gfx::Point(290, 290), root_surface_id, + gfx::Point(290, 290)}}; + + SurfaceHittest hittest(&manager); + for (const auto& test : tests) { + gfx::Point point(test.input_point); + gfx::Transform transform; + EXPECT_EQ(test.expected_output_surface_id, + hittest.GetTargetSurfaceAtPoint(test.input_surface_id, point, + &transform)); + transform.TransformPoint(&point); + EXPECT_EQ(test.expected_output_point, point); + } + + factory.Destroy(root_surface_id); + factory.Destroy(child_surface_id); +} + +// This test verifies that hit testing will progress to the next quad if it +// encounters an invalid RenderPassDrawQuad for whatever reason. +TEST(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) { + SurfaceManager manager; + EmptySurfaceFactoryClient client; + SurfaceFactory factory(&manager, &client); + + // Creates a root surface. + gfx::Rect root_rect(300, 300); + RenderPass* root_pass = nullptr; + scoped_ptr<CompositorFrame> root_frame = + CreateCompositorFrame(root_rect, &root_pass); + + // Create a RenderPassDrawQuad to a non-existant RenderPass. + CreateRenderPassDrawQuad(root_pass, + gfx::Transform(), + root_rect, + root_rect, + RenderPassId(1337, 1337)); + + // Add a reference to the child surface on the root surface. + SurfaceIdAllocator child_allocator(3); + SurfaceId child_surface_id = child_allocator.GenerateId(); + gfx::Rect child_rect(200, 200); + CreateSurfaceDrawQuad(root_pass, + gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, + 0.0f, 1.0f, 0.0f, 50.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f), + root_rect, + child_rect, + child_surface_id); + + // Submit the root frame. + SurfaceIdAllocator root_allocator(2); + SurfaceId root_surface_id = root_allocator.GenerateId(); + factory.Create(root_surface_id); + factory.SubmitCompositorFrame(root_surface_id, root_frame.Pass(), + SurfaceFactory::DrawCallback()); + + // Creates a child surface. + RenderPass* child_pass = nullptr; + scoped_ptr<CompositorFrame> child_frame = + CreateCompositorFrame(child_rect, &child_pass); + + // Add a solid quad in the child surface. + gfx::Rect child_solid_quad_rect(100, 100); + CreateSolidColorDrawQuad(child_pass, + gfx::Transform(1.0f, 0.0f, 0.0f, 50.0f, + 0.0f, 1.0f, 0.0f, 50.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f), + root_rect, + child_solid_quad_rect); + + // Submit the frame. + factory.Create(child_surface_id); + factory.SubmitCompositorFrame(child_surface_id, child_frame.Pass(), + SurfaceFactory::DrawCallback()); + + struct Test { + SurfaceId input_surface_id; + gfx::Point input_point; + SurfaceId expected_output_surface_id; + gfx::Point expected_output_point; + } tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id, + gfx::Point(10, 10)}, + {root_surface_id, gfx::Point(99, 99), root_surface_id, + gfx::Point(99, 99)}, + {root_surface_id, gfx::Point(100, 100), child_surface_id, + gfx::Point(50, 50)}, + {root_surface_id, gfx::Point(199, 199), child_surface_id, + gfx::Point(149, 149)}, + {root_surface_id, gfx::Point(200, 200), root_surface_id, + gfx::Point(200, 200)}, + {root_surface_id, gfx::Point(290, 290), root_surface_id, + gfx::Point(290, 290)}}; + + SurfaceHittest hittest(&manager); + for (const auto& test : tests) { + gfx::Point point(test.input_point); + gfx::Transform transform; + EXPECT_EQ(test.expected_output_surface_id, + hittest.GetTargetSurfaceAtPoint(test.input_surface_id, point, + &transform)); + transform.TransformPoint(&point); + EXPECT_EQ(test.expected_output_point, point); + } + + factory.Destroy(root_surface_id); + factory.Destroy(child_surface_id); +} + +TEST(SurfaceHittestTest, Hittest_RenderPassDrawQuad) { + SurfaceManager manager; + EmptySurfaceFactoryClient client; + SurfaceFactory factory(&manager, &client); + + // Create a CompostiorFrame with two RenderPasses. + gfx::Rect root_rect(300, 300); + RenderPassList render_pass_list; + + // Create a child RenderPass. + RenderPassId child_render_pass_id(1, 3); + gfx::Transform transform_to_root_target(1.0f, 0.0f, 0.0f, 50.0f, + 0.0f, 1.0f, 0.0f, 50.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + CreateRenderPass(child_render_pass_id, + gfx::Rect(100, 100), + transform_to_root_target, + &render_pass_list); + + // Create the root RenderPass. + RenderPassId root_render_pass_id(1, 2); + CreateRenderPass(root_render_pass_id, root_rect, gfx::Transform(), + &render_pass_list); + + RenderPass* root_pass = nullptr; + scoped_ptr<CompositorFrame> root_frame = + CreateCompositorFrameWithRenderPassList(&render_pass_list); + root_pass = root_frame->delegated_frame_data->render_pass_list.back(); + + // Create a RenderPassDrawQuad. + gfx::Rect render_pass_quad_rect(100, 100); + CreateRenderPassDrawQuad(root_pass, + transform_to_root_target, + root_rect, + render_pass_quad_rect, + child_render_pass_id); + + // Add a solid quad in the child render pass. + RenderPass* child_render_pass = + root_frame->delegated_frame_data->render_pass_list.front(); + gfx::Rect child_solid_quad_rect(100, 100); + CreateSolidColorDrawQuad(child_render_pass, + gfx::Transform(), + gfx::Rect(100, 100), + child_solid_quad_rect); + + // Submit the root frame. + SurfaceIdAllocator root_allocator(1); + SurfaceId root_surface_id = root_allocator.GenerateId(); + factory.Create(root_surface_id); + factory.SubmitCompositorFrame(root_surface_id, root_frame.Pass(), + SurfaceFactory::DrawCallback()); + + struct Test { + SurfaceId input_surface_id; + gfx::Point input_point; + SurfaceId expected_output_surface_id; + gfx::Point expected_output_point; + } tests[] = { + // These tests just miss the RenderPassDrawQuad. + { + root_surface_id, + gfx::Point(49, 49), + root_surface_id, + gfx::Point(49, 49) + }, + { + root_surface_id, + gfx::Point(150, 150), + root_surface_id, + gfx::Point(150, 150) + }, + // These tests just hit the boundaries of the + // RenderPassDrawQuad. + { + root_surface_id, + gfx::Point(50, 50), + root_surface_id, + gfx::Point(50, 50) + }, + { + root_surface_id, + gfx::Point(149, 149), + root_surface_id, + gfx::Point(149, 149) + }, + // These tests fall somewhere in the center of the + // RenderPassDrawQuad. + { + root_surface_id, + gfx::Point(99, 99), + root_surface_id, + gfx::Point(99, 99) + }, + { + root_surface_id, + gfx::Point(100, 100), + root_surface_id, + gfx::Point(100, 100) + } + }; + + SurfaceHittest hittest(&manager); + for (const auto& test : tests) { + gfx::Point point(test.input_point); + gfx::Transform transform; + EXPECT_EQ(test.expected_output_surface_id, + hittest.GetTargetSurfaceAtPoint(test.input_surface_id, point, + &transform)); + transform.TransformPoint(&point); + EXPECT_EQ(test.expected_output_point, point); + } + + factory.Destroy(root_surface_id); +} + +} // namespace cc diff --git a/chromium/cc/surfaces/surfaces_pixeltest.cc b/chromium/cc/surfaces/surfaces_pixeltest.cc index bf8ad57fb91..a584f7c806d 100644 --- a/chromium/cc/surfaces/surfaces_pixeltest.cc +++ b/chromium/cc/surfaces/surfaces_pixeltest.cc @@ -80,10 +80,10 @@ TEST_F(SurfacesPixelTest, DrawSimpleFrame) { SurfaceId root_surface_id = allocator_.GenerateId(); factory_.Create(root_surface_id); - factory_.SubmitFrame(root_surface_id, root_frame.Pass(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(root_surface_id, root_frame.Pass(), + SurfaceFactory::DrawCallback()); - SurfaceAggregator aggregator(&manager_, resource_provider_.get()); + SurfaceAggregator aggregator(&manager_, resource_provider_.get(), true); scoped_ptr<CompositorFrame> aggregated_frame = aggregator.Aggregate(root_surface_id); factory_.Destroy(root_surface_id); @@ -135,8 +135,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(root_surface_id, root_frame.Pass(), + SurfaceFactory::DrawCallback()); } { @@ -163,11 +163,11 @@ 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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(child_surface_id, child_frame.Pass(), + SurfaceFactory::DrawCallback()); } - SurfaceAggregator aggregator(&manager_, resource_provider_.get()); + SurfaceAggregator aggregator(&manager_, resource_provider_.get(), true); scoped_ptr<CompositorFrame> aggregated_frame = aggregator.Aggregate(root_surface_id); @@ -234,8 +234,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(root_surface_id, root_frame.Pass(), + SurfaceFactory::DrawCallback()); } { @@ -270,8 +270,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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(left_child_id, child_frame.Pass(), + SurfaceFactory::DrawCallback()); } { @@ -306,11 +306,11 @@ 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(), - SurfaceFactory::DrawCallback()); + factory_.SubmitCompositorFrame(right_child_id, child_frame.Pass(), + SurfaceFactory::DrawCallback()); } - SurfaceAggregator aggregator(&manager_, resource_provider_.get()); + SurfaceAggregator aggregator(&manager_, resource_provider_.get(), true); scoped_ptr<CompositorFrame> aggregated_frame = aggregator.Aggregate(root_surface_id); diff --git a/chromium/cc/tiles/image_decode_controller.cc b/chromium/cc/tiles/image_decode_controller.cc new file mode 100644 index 00000000000..19e16c47ec6 --- /dev/null +++ b/chromium/cc/tiles/image_decode_controller.cc @@ -0,0 +1,120 @@ +// 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/image_decode_controller.h" + +#include "cc/debug/devtools_instrumentation.h" + +namespace cc { +namespace { + +class ImageDecodeTaskImpl : public ImageDecodeTask { + public: + ImageDecodeTaskImpl(ImageDecodeController* controller, + const SkImage* image, + int layer_id, + uint64_t source_prepare_tiles_id) + : controller_(controller), + image_(skia::SharePtr(image)), + layer_id_(layer_id), + source_prepare_tiles_id_(source_prepare_tiles_id) {} + + // Overridden from Task: + void RunOnWorkerThread() override { + TRACE_EVENT1("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", + "source_prepare_tiles_id", source_prepare_tiles_id_); + devtools_instrumentation::ScopedImageDecodeTask image_decode_task( + image_.get()); + controller_->DecodeImage(image_.get()); + + // Release the reference after decoding image to ensure that it is not kept + // alive unless needed. + image_.clear(); + } + + // Overridden from TileTask: + void ScheduleOnOriginThread(TileTaskClient* client) override {} + void CompleteOnOriginThread(TileTaskClient* client) override { + controller_->OnImageDecodeTaskCompleted(layer_id_, image_.get(), + !HasFinishedRunning()); + } + + protected: + ~ImageDecodeTaskImpl() override {} + + private: + ImageDecodeController* controller_; + skia::RefPtr<const SkImage> image_; + int layer_id_; + uint64_t source_prepare_tiles_id_; + + DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl); +}; + +} // namespace + +ImageDecodeController::ImageDecodeController() {} + +ImageDecodeController::~ImageDecodeController() {} + +scoped_refptr<ImageDecodeTask> ImageDecodeController::GetTaskForImage( + const PositionImage& image, + int layer_id, + uint64_t prepare_tiles_id) { + uint32_t generation_id = image.image->uniqueID(); + scoped_refptr<ImageDecodeTask>& decode_task = + image_decode_tasks_[layer_id][generation_id]; + if (!decode_task) + decode_task = CreateTaskForImage(image.image, layer_id, prepare_tiles_id); + return decode_task; +} + +scoped_refptr<ImageDecodeTask> ImageDecodeController::CreateTaskForImage( + const SkImage* image, + int layer_id, + uint64_t prepare_tiles_id) { + return make_scoped_refptr( + new ImageDecodeTaskImpl(this, image, layer_id, prepare_tiles_id)); +} + +void ImageDecodeController::DecodeImage(const SkImage* image) { + image->preroll(); +} + +void ImageDecodeController::AddLayerUsedCount(int layer_id) { + ++used_layer_counts_[layer_id]; +} + +void ImageDecodeController::SubtractLayerUsedCount(int layer_id) { + if (--used_layer_counts_[layer_id]) + return; + + // Clean up decode tasks once a layer is no longer used. + used_layer_counts_.erase(layer_id); + image_decode_tasks_.erase(layer_id); +} + +void ImageDecodeController::OnImageDecodeTaskCompleted(int layer_id, + const SkImage* image, + bool was_canceled) { + // If the task has successfully finished, then keep the task until the layer + // is no longer in use. This ensures that we only decode a image once. + // TODO(vmpstr): Remove this when decode lifetime is controlled by cc. + if (!was_canceled) + return; + + // Otherwise, we have to clean up the task so that a new one can be created if + // we need to decode the image again. + LayerImageTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id); + if (layer_it == image_decode_tasks_.end()) + return; + + ImageTaskMap& image_tasks = layer_it->second; + ImageTaskMap::iterator task_it = image_tasks.find(image->uniqueID()); + if (task_it == image_tasks.end()) + return; + image_tasks.erase(task_it); +} + +} // namespace cc diff --git a/chromium/cc/tiles/image_decode_controller.h b/chromium/cc/tiles/image_decode_controller.h new file mode 100644 index 00000000000..e2016482b19 --- /dev/null +++ b/chromium/cc/tiles/image_decode_controller.h @@ -0,0 +1,53 @@ +// 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_IMAGE_DECODE_CONTROLLER_H_ +#define CC_TILES_IMAGE_DECODE_CONTROLLER_H_ + +#include "base/containers/hash_tables.h" +#include "base/memory/ref_counted.h" +#include "cc/base/cc_export.h" +#include "cc/playback/discardable_image_map.h" +#include "cc/raster/tile_task_runner.h" +#include "skia/ext/refptr.h" + +namespace cc { + +class ImageDecodeController { + public: + ImageDecodeController(); + ~ImageDecodeController(); + + scoped_refptr<ImageDecodeTask> GetTaskForImage(const PositionImage& image, + int layer_id, + uint64_t prepare_tiles_id); + + // Note that this function has to remain thread safe. + void DecodeImage(const SkImage* image); + + // TODO(vmpstr): This should go away once the controller is decoding images + // based on priority and memory. + void AddLayerUsedCount(int layer_id); + void SubtractLayerUsedCount(int layer_id); + + void OnImageDecodeTaskCompleted(int layer_id, + const SkImage* image, + bool was_canceled); + + private: + scoped_refptr<ImageDecodeTask> CreateTaskForImage(const SkImage* image, + int layer_id, + uint64_t prepare_tiles_id); + + using ImageTaskMap = base::hash_map<uint32_t, scoped_refptr<ImageDecodeTask>>; + using LayerImageTaskMap = base::hash_map<int, ImageTaskMap>; + LayerImageTaskMap image_decode_tasks_; + + using LayerCountMap = base::hash_map<int, int>; + LayerCountMap used_layer_counts_; +}; + +} // namespace cc + +#endif // CC_TILES_IMAGE_DECODE_CONTROLLER_H_ diff --git a/chromium/cc/tiles/picture_layer_tiling.cc b/chromium/cc/tiles/picture_layer_tiling.cc index ef31f58256b..be8a7940f70 100644 --- a/chromium/cc/tiles/picture_layer_tiling.cc +++ b/chromium/cc/tiles/picture_layer_tiling.cc @@ -38,11 +38,11 @@ scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( float contents_scale, scoped_refptr<RasterSource> raster_source, PictureLayerTilingClient* client, - size_t max_tiles_for_interest_area, + size_t tiling_interest_area_padding, 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, max_tiles_for_interest_area, + tree, contents_scale, raster_source, client, tiling_interest_area_padding, skewport_target_time_in_seconds, skewport_extrapolation_limit_in_content_pixels)); } @@ -52,10 +52,10 @@ PictureLayerTiling::PictureLayerTiling( float contents_scale, scoped_refptr<RasterSource> raster_source, PictureLayerTilingClient* client, - size_t max_tiles_for_interest_area, + size_t tiling_interest_area_padding, float skewport_target_time_in_seconds, int skewport_extrapolation_limit_in_content_pixels) - : max_tiles_for_interest_area_(max_tiles_for_interest_area), + : tiling_interest_area_padding_(tiling_interest_area_padding), skewport_target_time_in_seconds_(skewport_target_time_in_seconds), skewport_extrapolation_limit_in_content_pixels_( skewport_extrapolation_limit_in_content_pixels), @@ -64,6 +64,7 @@ PictureLayerTiling::PictureLayerTiling( tree_(tree), raster_source_(raster_source), resolution_(NON_IDEAL_RESOLUTION), + may_contain_low_resolution_tiles_(false), tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels), can_require_tiles_for_activation_(false), current_content_to_screen_scale_(0.f), @@ -73,12 +74,12 @@ PictureLayerTiling::PictureLayerTiling( has_eventually_rect_tiles_(false), all_tiles_done_(true) { DCHECK(!raster_source->IsSolidColor()); - gfx::Size content_bounds = gfx::ToCeiledSize( - gfx::ScaleSize(raster_source_->GetSize(), contents_scale)); + gfx::Size content_bounds = + gfx::ScaleToCeiledSize(raster_source_->GetSize(), contents_scale); gfx::Size tile_size = client_->CalculateTileSize(content_bounds); - DCHECK(!gfx::ToFlooredSize(gfx::ScaleSize(raster_source_->GetSize(), - contents_scale)).IsEmpty()) + DCHECK(!gfx::ScaleToFlooredSize(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; @@ -101,26 +102,29 @@ float PictureLayerTiling::CalculateSoonBorderDistance( max_dimension * kSoonBorderDistanceViewportPercentage); } -Tile* PictureLayerTiling::CreateTile(int i, int j) { +Tile* PictureLayerTiling::CreateTile(const Tile::CreateInfo& info) { + const int i = info.tiling_i_index; + const int j = info.tiling_j_index; 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_)) + if (!raster_source_->CoversRect(info.enclosing_layer_rect)) return nullptr; all_tiles_done_ = false; - ScopedTilePtr tile = client_->CreateTile(contents_scale_, tile_rect); + ScopedTilePtr tile = client_->CreateTile(info); Tile* raw_ptr = tile.get(); - tile->set_tiling_index(i, j); tiles_.add(key, tile.Pass()); return raw_ptr; } void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() { + const PictureLayerTiling* active_twin = + tree_ == PENDING_TREE ? client_->GetPendingOrActiveTwinTiling(this) + : nullptr; + const Region* invalidation = + active_twin ? client_->GetPendingInvalidation() : nullptr; + bool include_borders = false; for (TilingData::Iterator iter(&tiling_data_, live_tiles_rect_, include_borders); @@ -130,8 +134,29 @@ void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() { if (find != tiles_.end()) continue; - if (ShouldCreateTileAt(key.index_x, key.index_y)) - CreateTile(key.index_x, key.index_y); + Tile::CreateInfo info = CreateInfoForTile(key.index_x, key.index_y); + if (ShouldCreateTileAt(info)) { + Tile* tile = CreateTile(info); + + // If this is the pending tree, then the active twin tiling may contain + // the previous content ID of these tiles. In that case, we need only + // partially raster the tile content. + if (tile && invalidation && TilingMatchesTileIndices(active_twin)) { + if (const Tile* old_tile = + active_twin->TileAt(key.index_x, key.index_y)) { + gfx::Rect tile_rect = tile->content_rect(); + gfx::Rect invalidated; + for (Region::Iterator iter(*invalidation); iter.has_rect(); + iter.next()) { + gfx::Rect invalid_content_rect = + gfx::ScaleToEnclosingRect(iter.rect(), contents_scale_); + invalid_content_rect.Intersect(tile_rect); + invalidated.Union(invalid_content_rect); + } + tile->SetInvalidated(invalidated, old_tile->id()); + } + } + } } VerifyLiveTilesRect(false); } @@ -186,7 +211,7 @@ void PictureLayerTiling::SetRasterSourceAndResize( 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::ScaleToCeiledSize(new_layer_bounds, contents_scale_); gfx::Size tile_size = client_->CalculateTileSize(content_bounds); if (tile_size != tiling_data_.max_texture_size()) { @@ -242,15 +267,17 @@ void PictureLayerTiling::SetRasterSourceAndResize( 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); + Tile::CreateInfo info = CreateInfoForTile(after_right, j); + if (ShouldCreateTileAt(info)) + CreateTile(info); } } 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); + Tile::CreateInfo info = CreateInfoForTile(i, after_bottom); + if (ShouldCreateTileAt(info)) + CreateTile(info); } } } @@ -310,13 +337,26 @@ void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_invalidation, // tiles from knowing the invalidation rect and content id. crbug.com/490847 ScopedTilePtr old_tile = TakeTileAt(key.index_x, key.index_y); if (recreate_tiles && old_tile) { - if (Tile* tile = CreateTile(key.index_x, key.index_y)) + Tile::CreateInfo info = CreateInfoForTile(key.index_x, key.index_y); + if (Tile* tile = CreateTile(info)) tile->SetInvalidated(invalid_content_rect, old_tile->id()); } } } -bool PictureLayerTiling::ShouldCreateTileAt(int i, int j) const { +Tile::CreateInfo PictureLayerTiling::CreateInfoForTile(int i, int j) const { + gfx::Rect tile_rect = tiling_data_.TileBoundsWithBorder(i, j); + tile_rect.set_size(tiling_data_.max_texture_size()); + gfx::Rect enclosing_layer_rect = + gfx::ScaleToEnclosingRect(tile_rect, 1.f / contents_scale_); + return Tile::CreateInfo(i, j, enclosing_layer_rect, tile_rect, + contents_scale_); +} + +bool PictureLayerTiling::ShouldCreateTileAt( + const Tile::CreateInfo& info) const { + const int i = info.tiling_i_index; + const int j = info.tiling_j_index; // 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 @@ -337,21 +377,16 @@ bool PictureLayerTiling::ShouldCreateTileAt(int i, int j) const { 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())) + if (!active_twin->raster_source()->CoversRect(info.enclosing_layer_rect)) 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)) + if (layer_invalidation && + layer_invalidation->Intersects(info.enclosing_layer_rect)) return true; // If the active tree doesn't have a tile here, but it's in the pending tree's @@ -359,7 +394,8 @@ bool PictureLayerTiling::ShouldCreateTileAt(int i, int j) const { // 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)) + if (!active_twin->TileAt(i, j) && + current_visible_rect_.Intersects(info.content_rect)) return true; // In all other cases, the pending tree doesn't need to create a tile. @@ -456,11 +492,10 @@ PictureLayerTiling::CoverageIterator::operator++() { 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_); + gfx::ScaleToEnclosingRect(content_rect, 1 / dest_to_content_scale_); current_geometry_rect_.Intersect(dest_rect_); + DCHECK(!current_geometry_rect_.IsEmpty()); if (first_time) return *this; @@ -503,7 +538,7 @@ gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const { 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())); + texture_rect.Intersect(gfx::RectF(gfx::SizeF(tiling_->tiling_size()))); if (texture_rect.IsEmpty()) return texture_rect; texture_rect.Offset(-tex_origin.OffsetFromOrigin()); @@ -626,22 +661,24 @@ bool PictureLayerTiling::ComputeTilePriorityRects( // Calculate the eventually/live tiles rect. 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)) + float content_to_screen_scale = ideal_contents_scale / contents_scale_; + int pad_in_content_space = + static_cast<int>(tiling_interest_area_padding_ / content_to_screen_scale); + gfx::Rect eventually_rect = visible_rect_in_content_space; + // If the visible rect is empty, keep the eventually rect as empty. + if (!eventually_rect.IsEmpty()) { + eventually_rect.Inset(-pad_in_content_space, -pad_in_content_space); + eventually_rect = + tiling_data_.ExpandRectIgnoringBordersToTileBounds(eventually_rect); + } + + DCHECK_IMPLIES(!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); @@ -696,13 +733,21 @@ void PictureLayerTiling::SetLiveTilesRect( RemoveTileAt(iter.index_x(), iter.index_y()); } + // We don't rasterize non ideal resolution tiles, so there is no need to + // create any new tiles. + if (resolution_ == NON_IDEAL_RESOLUTION) { + live_tiles_rect_.Intersect(new_live_tiles_rect); + VerifyLiveTilesRect(false); + return; + } + // 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.index_x, key.index_y)) - CreateTile(key.index_x, key.index_y); + Tile::CreateInfo info = CreateInfoForTile(iter.index_x(), iter.index_y()); + if (ShouldCreateTileAt(info)) + CreateTile(info); } live_tiles_rect_ = new_live_tiles_rect; @@ -853,11 +898,11 @@ PrioritizedTile PictureLayerTiling::MakePrioritizedTile( Tile* tile, PriorityRectType priority_rect_type) const { DCHECK(tile); - DCHECK( - raster_source()->CoversRect(tile->content_rect(), tile->contents_scale())) + DCHECK(raster_source()->CoversRect(tile->enclosing_layer_rect())) << "Recording rect: " << gfx::ScaleToEnclosingRect(tile->content_rect(), - 1.f / tile->contents_scale()).ToString(); + 1.f / tile->contents_scale()) + .ToString(); return PrioritizedTile(tile, raster_source(), ComputePriorityForTile(tile, priority_rect_type), @@ -966,155 +1011,4 @@ size_t PictureLayerTiling::GPUMemoryUsageInBytes() const { 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/tiles/picture_layer_tiling.h b/chromium/cc/tiles/picture_layer_tiling.h index 721f9e1e340..08380b1d78c 100644 --- a/chromium/cc/tiles/picture_layer_tiling.h +++ b/chromium/cc/tiles/picture_layer_tiling.h @@ -36,8 +36,7 @@ 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 ScopedTilePtr CreateTile(float contents_scale, - const gfx::Rect& content_rect) = 0; + virtual ScopedTilePtr CreateTile(const Tile::CreateInfo& info) = 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 @@ -98,7 +97,7 @@ class CC_EXPORT PictureLayerTiling { float contents_scale, scoped_refptr<RasterSource> raster_source, PictureLayerTilingClient* client, - size_t max_tiles_for_interest_area, + size_t tiling_interest_area_padding, float skewport_target_time_in_seconds, int skewport_extrapolation_limit_in_content_pixels); @@ -111,8 +110,17 @@ class CC_EXPORT PictureLayerTiling { bool IsTileRequiredForActivation(const Tile* tile) const; bool IsTileRequiredForDraw(const Tile* tile) const; - void set_resolution(TileResolution resolution) { resolution_ = resolution; } + void set_resolution(TileResolution resolution) { + resolution_ = resolution; + may_contain_low_resolution_tiles_ |= resolution == LOW_RESOLUTION; + } TileResolution resolution() const { return resolution_; } + bool may_contain_low_resolution_tiles() const { + return may_contain_low_resolution_tiles_; + } + void reset_may_contain_low_resolution_tiles() { + may_contain_low_resolution_tiles_ = false; + } void set_can_require_tiles_for_activation(bool can_require_tiles) { can_require_tiles_for_activation_ = can_require_tiles; } @@ -240,22 +248,6 @@ class CC_EXPORT PictureLayerTiling { void AsValueInto(base::trace_event::TracedValue* array) const; size_t GPUMemoryUsageInBytes() const; - struct RectExpansionCache { - RectExpansionCache(); - - gfx::Rect previous_start; - gfx::Rect previous_bounds; - gfx::Rect previous_result; - int64 previous_target; - }; - - static - gfx::Rect ExpandRectEquallyToAreaBoundedBy( - const gfx::Rect& starting_rect, - int64 target_area, - const gfx::Rect& bounding_rect, - RectExpansionCache* cache); - protected: friend class CoverageIterator; friend class PrioritizedTile; @@ -287,12 +279,12 @@ class CC_EXPORT PictureLayerTiling { float contents_scale, scoped_refptr<RasterSource> raster_source, PictureLayerTilingClient* client, - size_t max_tiles_for_interest_area, + size_t tiling_interest_area_padding, float skewport_target_time_in_seconds, int skewport_extrapolation_limit_in_content_pixels); void SetLiveTilesRect(const gfx::Rect& live_tiles_rect); void VerifyLiveTilesRect(bool is_on_recycle_tree) const; - Tile* CreateTile(int i, int j); + Tile* CreateTile(const Tile::CreateInfo& info); ScopedTilePtr TakeTileAt(int i, int j); // Returns true if the Tile existed and was removed from the tiling. bool RemoveTileAt(int i, int j); @@ -333,7 +325,8 @@ class CC_EXPORT PictureLayerTiling { visible_rect_history_[1] = visible_rect_history_[0]; } bool IsTileOccludedOnCurrentTree(const Tile* tile) const; - bool ShouldCreateTileAt(int i, int j) const; + Tile::CreateInfo CreateInfoForTile(int i, int j) const; + bool ShouldCreateTileAt(const Tile::CreateInfo& info) const; bool IsTileOccluded(const Tile* tile) const; void UpdateRequiredStatesOnTile(Tile* tile) const; PrioritizedTile MakePrioritizedTile( @@ -375,7 +368,7 @@ class CC_EXPORT PictureLayerTiling { } void RemoveTilesInRegion(const Region& layer_region, bool recreate_tiles); - const size_t max_tiles_for_interest_area_; + const size_t tiling_interest_area_padding_; const float skewport_target_time_in_seconds_; const int skewport_extrapolation_limit_in_content_pixels_; @@ -385,6 +378,7 @@ class CC_EXPORT PictureLayerTiling { const WhichTree tree_; scoped_refptr<RasterSource> raster_source_; TileResolution resolution_; + bool may_contain_low_resolution_tiles_; // Internal data. TilingData tiling_data_; @@ -414,8 +408,6 @@ class CC_EXPORT PictureLayerTiling { private: DISALLOW_ASSIGN(PictureLayerTiling); - - RectExpansionCache expansion_cache_; }; } // namespace cc diff --git a/chromium/cc/tiles/picture_layer_tiling_perftest.cc b/chromium/cc/tiles/picture_layer_tiling_perftest.cc index f27c227edcc..f996edc1792 100644 --- a/chromium/cc/tiles/picture_layer_tiling_perftest.cc +++ b/chromium/cc/tiles/picture_layer_tiling_perftest.cc @@ -5,10 +5,10 @@ #include "cc/debug/lap_timer.h" #include "cc/resources/resource_provider.h" #include "cc/resources/scoped_resource.h" +#include "cc/test/fake_display_list_raster_source.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/fake_resource_provider.h" #include "cc/test/test_context_provider.h" #include "cc/test/test_shared_bitmap_manager.h" @@ -44,12 +44,12 @@ class PictureLayerTilingPerfTest : public testing::Test { void SetUp() override { LayerTreeSettings defaults; picture_layer_tiling_client_.SetTileSize(gfx::Size(256, 256)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled( gfx::Size(256 * 50, 256 * 50)); picture_layer_tiling_ = PictureLayerTiling::Create( - PENDING_TREE, 1.f, pile, &picture_layer_tiling_client_, - defaults.max_tiles_for_interest_area, + PENDING_TREE, 1.f, raster_source, &picture_layer_tiling_client_, + defaults.tiling_interest_area_padding, defaults.skewport_target_time_in_seconds, defaults.skewport_extrapolation_limit_in_content_pixels); picture_layer_tiling_->CreateAllTilesForTesting(); diff --git a/chromium/cc/tiles/picture_layer_tiling_set.cc b/chromium/cc/tiles/picture_layer_tiling_set.cc index c820e81ce1a..a9e16f58a73 100644 --- a/chromium/cc/tiles/picture_layer_tiling_set.cc +++ b/chromium/cc/tiles/picture_layer_tiling_set.cc @@ -33,11 +33,11 @@ inline float LargerRatio(float float1, float float2) { scoped_ptr<PictureLayerTilingSet> PictureLayerTilingSet::Create( WhichTree tree, PictureLayerTilingClient* client, - size_t max_tiles_for_interest_area, + size_t tiling_interest_area_padding, float skewport_target_time_in_seconds, int skewport_extrapolation_limit_in_content_pixels) { return make_scoped_ptr(new PictureLayerTilingSet( - tree, client, max_tiles_for_interest_area, + tree, client, tiling_interest_area_padding, skewport_target_time_in_seconds, skewport_extrapolation_limit_in_content_pixels)); } @@ -45,16 +45,15 @@ scoped_ptr<PictureLayerTilingSet> PictureLayerTilingSet::Create( PictureLayerTilingSet::PictureLayerTilingSet( WhichTree tree, PictureLayerTilingClient* client, - size_t max_tiles_for_interest_area, + size_t tiling_interest_area_padding, float skewport_target_time_in_seconds, int skewport_extrapolation_limit_in_content_pixels) - : max_tiles_for_interest_area_(max_tiles_for_interest_area), + : tiling_interest_area_padding_(tiling_interest_area_padding), 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) { -} + client_(client) {} PictureLayerTilingSet::~PictureLayerTilingSet() { } @@ -78,7 +77,7 @@ void PictureLayerTilingSet::CopyTilingsAndPropertiesFromPendingTwin( if (!this_tiling) { scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create( tree_, contents_scale, raster_source, client_, - max_tiles_for_interest_area_, skewport_target_time_in_seconds_, + tiling_interest_area_padding_, skewport_target_time_in_seconds_, skewport_extrapolation_limit_in_content_pixels_); tilings_.push_back(new_tiling.Pass()); this_tiling = tilings_.back(); @@ -120,8 +119,12 @@ void PictureLayerTilingSet::UpdateTilingsToCurrentRasterSourceForActivation( 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); + // it is now NON_IDEAL_RESOLUTION. The exception is for LOW_RESOLUTION + // tilings, which are computed and created entirely on the active tree. + // Since the pending tree does not have them, we should just leave them as + // low resolution to not lose them. + if (tiling->resolution() != LOW_RESOLUTION) + tiling->set_resolution(NON_IDEAL_RESOLUTION); } VerifyTilings(pending_twin_set); @@ -197,16 +200,7 @@ 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) { - 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. @@ -215,12 +209,9 @@ void PictureLayerTilingSet::CleanUpTilings( 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)) { + // Keep low resolution tilings. + if (tiling->resolution() == LOW_RESOLUTION) continue; - } // Don't remove tilings that are required. if (std::find(needed_tilings.begin(), needed_tilings.end(), tiling) != @@ -259,7 +250,7 @@ PictureLayerTiling* PictureLayerTilingSet::AddTiling( tilings_.push_back(PictureLayerTiling::Create( tree_, contents_scale, raster_source, client_, - max_tiles_for_interest_area_, skewport_target_time_in_seconds_, + tiling_interest_area_padding_, skewport_target_time_in_seconds_, skewport_extrapolation_limit_in_content_pixels_)); PictureLayerTiling* appended = tilings_.back(); diff --git a/chromium/cc/tiles/picture_layer_tiling_set.h b/chromium/cc/tiles/picture_layer_tiling_set.h index dcaf77586ff..b3e22fe34af 100644 --- a/chromium/cc/tiles/picture_layer_tiling_set.h +++ b/chromium/cc/tiles/picture_layer_tiling_set.h @@ -40,7 +40,7 @@ class CC_EXPORT PictureLayerTilingSet { static scoped_ptr<PictureLayerTilingSet> Create( WhichTree tree, PictureLayerTilingClient* client, - size_t max_tiles_for_interest_area, + size_t tiling_interest_area_padding, float skewport_target_time_in_seconds, int skewport_extrapolation_limit_in_content); @@ -51,7 +51,6 @@ class CC_EXPORT PictureLayerTilingSet { 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); void RemoveNonIdealTilings(); @@ -175,7 +174,7 @@ class CC_EXPORT PictureLayerTilingSet { explicit PictureLayerTilingSet( WhichTree tree, PictureLayerTilingClient* client, - size_t max_tiles_for_interest_area, + size_t tiling_interest_area_padding, float skewport_target_time_in_seconds, int skewport_extrapolation_limit_in_content_pixels); @@ -190,7 +189,7 @@ class CC_EXPORT PictureLayerTilingSet { ScopedPtrVector<PictureLayerTiling> tilings_; - const size_t max_tiles_for_interest_area_; + const size_t tiling_interest_area_padding_; const float skewport_target_time_in_seconds_; const int skewport_extrapolation_limit_in_content_pixels_; WhichTree tree_; diff --git a/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc index e7593cde80b..a8afd820547 100644 --- a/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc +++ b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc @@ -8,10 +8,10 @@ #include <vector> #include "cc/resources/resource_provider.h" +#include "cc/test/fake_display_list_raster_source.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/fake_resource_provider.h" #include "cc/test/test_shared_bitmap_manager.h" #include "cc/trees/layer_tree_settings.h" @@ -25,7 +25,7 @@ scoped_ptr<PictureLayerTilingSet> CreateTilingSet( PictureLayerTilingClient* client) { LayerTreeSettings defaults; return PictureLayerTilingSet::Create( - ACTIVE_TREE, client, defaults.max_tiles_for_interest_area, + ACTIVE_TREE, client, defaults.tiling_interest_area_padding, defaults.skewport_target_time_in_seconds, defaults.skewport_extrapolation_limit_in_content_pixels); } @@ -36,16 +36,16 @@ TEST(PictureLayerTilingSetTest, NoResources) { scoped_ptr<PictureLayerTilingSet> set = CreateTilingSet(&client); client.SetTileSize(gfx::Size(256, 256)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateEmptyPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateEmpty(layer_bounds); - set->AddTiling(1.0, pile); - set->AddTiling(1.5, pile); - set->AddTiling(2.0, pile); + set->AddTiling(1.0, raster_source); + set->AddTiling(1.5, raster_source); + set->AddTiling(2.0, raster_source); float contents_scale = 2.0; gfx::Size content_bounds( - gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale))); + gfx::ScaleToCeiledSize(layer_bounds, contents_scale)); gfx::Rect content_rect(content_bounds); Region remaining(content_rect); @@ -74,17 +74,17 @@ TEST(PictureLayerTilingSetTest, TilingRange) { PictureLayerTiling* high_res_tiling; PictureLayerTiling* low_res_tiling; - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); scoped_ptr<PictureLayerTilingSet> set = CreateTilingSet(&client); - set->AddTiling(2.0, pile); - high_res_tiling = set->AddTiling(1.0, pile); + set->AddTiling(2.0, raster_source); + high_res_tiling = set->AddTiling(1.0, raster_source); high_res_tiling->set_resolution(HIGH_RESOLUTION); - set->AddTiling(0.5, pile); - low_res_tiling = set->AddTiling(0.25, pile); + set->AddTiling(0.5, raster_source); + low_res_tiling = set->AddTiling(0.25, raster_source); low_res_tiling->set_resolution(LOW_RESOLUTION); - set->AddTiling(0.125, pile); + set->AddTiling(0.125, raster_source); higher_than_high_res_range = set->GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); @@ -111,11 +111,11 @@ TEST(PictureLayerTilingSetTest, TilingRange) { 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); + set_without_low_res->AddTiling(2.0, raster_source); + high_res_tiling = set_without_low_res->AddTiling(1.0, raster_source); high_res_tiling->set_resolution(HIGH_RESOLUTION); - set_without_low_res->AddTiling(0.5, pile); - set_without_low_res->AddTiling(0.25, pile); + set_without_low_res->AddTiling(0.5, raster_source); + set_without_low_res->AddTiling(0.25, raster_source); higher_than_high_res_range = set_without_low_res->GetTilingRange( PictureLayerTilingSet::HIGHER_THAN_HIGH_RES); @@ -142,9 +142,11 @@ TEST(PictureLayerTilingSetTest, TilingRange) { 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_with_only_high_and_low_res->AddTiling(1.0, raster_source); 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_with_only_high_and_low_res->AddTiling(0.5, raster_source); low_res_tiling->set_resolution(LOW_RESOLUTION); higher_than_high_res_range = set_with_only_high_and_low_res->GetTilingRange( @@ -174,7 +176,7 @@ TEST(PictureLayerTilingSetTest, TilingRange) { 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_with_only_high_res->AddTiling(1.0, raster_source); high_res_tiling->set_resolution(HIGH_RESOLUTION); higher_than_high_res_range = set_with_only_high_res->GetTilingRange( @@ -223,12 +225,13 @@ class PictureLayerTilingSetTestWithResources : public testing::Test { 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); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); float scale = min_scale; for (int i = 0; i < num_tilings; ++i, scale += scale_increment) { - PictureLayerTiling* tiling = set->AddTiling(scale, pile); + PictureLayerTiling* tiling = set->AddTiling(scale, raster_source); + tiling->set_resolution(HIGH_RESOLUTION); tiling->CreateAllTilesForTesting(); std::vector<Tile*> tiles = tiling->AllTilesForTesting(); client.tile_manager()->InitializeTilesWithResourcesForTesting(tiles); @@ -236,7 +239,7 @@ class PictureLayerTilingSetTestWithResources : public testing::Test { float max_contents_scale = scale; gfx::Size content_bounds( - gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, max_contents_scale))); + gfx::ScaleToCeiledSize(layer_bounds, max_contents_scale)); gfx::Rect content_rect(content_bounds); Region remaining(content_rect); @@ -302,15 +305,15 @@ TEST(PictureLayerTilingSetTest, TileSizeChange) { ACTIVE_TREE, &active_client, 1000, 1.f, 1000); gfx::Size layer_bounds(100, 100); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(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); + pending_set->AddTiling(1.f, raster_source); // New tilings get the correct tile size. EXPECT_EQ(tile_size1, pending_set->tiling_at(0)->tile_size()); @@ -335,11 +338,11 @@ TEST(PictureLayerTilingSetTest, TileSizeChange) { // activation, since we can't set the raster source twice on the pending tree // without activating. For test, just remove and add a new tiling instead. pending_set->RemoveAllTilings(); - pending_set->AddTiling(1.f, pile); + pending_set->AddTiling(1.f, raster_source); pending_set->tiling_at(0)->set_resolution(HIGH_RESOLUTION); pending_client.SetTileSize(tile_size2); - pending_set->UpdateTilingsToCurrentRasterSourceForCommit(pile.get(), Region(), - 1.f, 1.f); + pending_set->UpdateTilingsToCurrentRasterSourceForCommit(raster_source.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()); @@ -357,7 +360,7 @@ TEST(PictureLayerTilingSetTest, TileSizeChange) { // 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); + raster_source.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()); @@ -370,8 +373,8 @@ TEST(PictureLayerTilingSetTest, TileSizeChange) { // A new source frame with a new tile size. pending_client.SetTileSize(tile_size3); - pending_set->UpdateTilingsToCurrentRasterSourceForCommit(pile.get(), Region(), - 1.f, 1.f); + pending_set->UpdateTilingsToCurrentRasterSourceForCommit(raster_source.get(), + Region(), 1.f, 1.f); // The tiling gets the new size correctly. EXPECT_EQ(tile_size3, pending_set->tiling_at(0)->tile_size()); @@ -389,7 +392,7 @@ TEST(PictureLayerTilingSetTest, TileSizeChange) { // 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); + raster_source.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()); @@ -409,13 +412,13 @@ TEST(PictureLayerTilingSetTest, MaxContentScale) { ACTIVE_TREE, &active_client, 1000, 1.f, 1000); gfx::Size layer_bounds(100, 105); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateEmptyPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateEmpty(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); + pending_set->AddTiling(1.f, raster_source); + pending_set->AddTiling(2.f, raster_source); + pending_set->AddTiling(3.f, raster_source); // Set some expected things for the tiling set to function. pending_set->tiling_at(0)->set_resolution(HIGH_RESOLUTION); @@ -425,14 +428,14 @@ TEST(PictureLayerTilingSetTest, MaxContentScale) { // everything. float max_content_scale = 3.f; pending_set->UpdateTilingsToCurrentRasterSourceForCommit( - pile.get(), Region(), 1.f, max_content_scale); + raster_source.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); + raster_source.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()); @@ -440,7 +443,7 @@ TEST(PictureLayerTilingSetTest, MaxContentScale) { // tiling. max_content_scale = 2.9f; pending_set->UpdateTilingsToCurrentRasterSourceForCommit( - pile.get(), Region(), 1.f, max_content_scale); + raster_source.get(), Region(), 1.f, max_content_scale); // All the tilings are there still. EXPECT_EQ(2u, pending_set->num_tilings()); @@ -448,7 +451,7 @@ TEST(PictureLayerTilingSetTest, MaxContentScale) { // 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); + raster_source.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()); } diff --git a/chromium/cc/tiles/picture_layer_tiling_unittest.cc b/chromium/cc/tiles/picture_layer_tiling_unittest.cc index 1c8a3978eb2..ec3b87024d7 100644 --- a/chromium/cc/tiles/picture_layer_tiling_unittest.cc +++ b/chromium/cc/tiles/picture_layer_tiling_unittest.cc @@ -6,10 +6,10 @@ #include <set> #include "cc/base/math_util.h" +#include "cc/test/fake_display_list_raster_source.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" @@ -31,9 +31,8 @@ static gfx::Rect ViewportInLayerSpace( if (!transform.GetInverse(&inverse)) return gfx::Rect(); - gfx::RectF viewport_in_layer_space = MathUtil::ProjectClippedRect( - inverse, gfx::RectF(gfx::Point(0, 0), device_viewport)); - return ToEnclosingRect(viewport_in_layer_space); + return MathUtil::ProjectEnclosingClippedRect(inverse, + gfx::Rect(device_viewport)); } class TestablePictureLayerTiling : public PictureLayerTiling { @@ -49,7 +48,7 @@ class TestablePictureLayerTiling : public PictureLayerTiling { const LayerTreeSettings& settings) { return make_scoped_ptr(new TestablePictureLayerTiling( tree, contents_scale, raster_source, client, - settings.max_tiles_for_interest_area, + settings.tiling_interest_area_padding, settings.skewport_target_time_in_seconds, settings.skewport_extrapolation_limit_in_content_pixels)); } @@ -64,14 +63,14 @@ class TestablePictureLayerTiling : public PictureLayerTiling { float contents_scale, scoped_refptr<RasterSource> raster_source, PictureLayerTilingClient* client, - size_t max_tiles_for_interest_area, + size_t tiling_interest_area_padding, float skewport_target_time, int skewport_extrapolation_limit) : PictureLayerTiling(tree, contents_scale, raster_source, client, - max_tiles_for_interest_area, + tiling_interest_area_padding, skewport_target_time, skewport_extrapolation_limit) {} }; @@ -85,20 +84,24 @@ class PictureLayerTilingIteratorTest : public testing::Test { float contents_scale, const gfx::Size& layer_bounds) { client_.SetTileSize(tile_size); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); - tiling_ = TestablePictureLayerTiling::Create( - PENDING_TREE, contents_scale, pile, &client_, LayerTreeSettings()); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + tiling_ = TestablePictureLayerTiling::Create(PENDING_TREE, contents_scale, + raster_source, &client_, + LayerTreeSettings()); + tiling_->set_resolution(HIGH_RESOLUTION); } 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()); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + tiling_ = TestablePictureLayerTiling::Create(ACTIVE_TREE, contents_scale, + raster_source, &client_, + LayerTreeSettings()); + tiling_->set_resolution(HIGH_RESOLUTION); } void SetLiveRectAndVerifyTiles(const gfx::Rect& live_tiles_rect) { @@ -209,12 +212,13 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeDeletesTiles) { // Stop creating tiles so that any invalidations are left as holes. gfx::Size new_layer_size(200, 200); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateEmptyPileWithDefaultTileSize(new_layer_size); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreatePartiallyFilled(new_layer_size, + gfx::Rect()); Region invalidation = SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size)); - tiling_->SetRasterSourceAndResize(pile); + tiling_->SetRasterSourceAndResize(raster_source); EXPECT_TRUE(tiling_->TileAt(0, 0)); tiling_->Invalidate(invalidation); EXPECT_FALSE(tiling_->TileAt(0, 0)); @@ -270,14 +274,14 @@ 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. - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled( gfx::Size(right + 1, bottom + 1)); - tiling_->SetRasterSourceAndResize(pile); + tiling_->SetRasterSourceAndResize(raster_source); EXPECT_EQ(2, tiling_->TilingDataForTesting().num_tiles_x()); EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y()); - // The live tiles rect was clamped to the pile size. + // The live tiles rect was clamped to the raster source size. EXPECT_EQ(gfx::Rect(right + 1, bottom + 1), tiling_->live_tiles_rect()); // Since the row/column is gone, the tiles should be gone too. @@ -290,9 +294,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. - pile = FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( + raster_source = FakeDisplayListRasterSource::CreateFilled( gfx::Size(right + 2, bottom + 2)); - tiling_->SetRasterSourceAndResize(pile); + tiling_->SetRasterSourceAndResize(raster_source); EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x()); EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y()); @@ -424,10 +428,10 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeOverBorderPixelsDeletesTiles) { EXPECT_TRUE(tiling_->TileAt(0, 0)); // Stop creating tiles so that any invalidations are left as holes. - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateEmptyPileWithDefaultTileSize( - gfx::Size(200, 200)); - tiling_->SetRasterSourceAndResize(pile); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreatePartiallyFilled(gfx::Size(200, 200), + gfx::Rect()); + tiling_->SetRasterSourceAndResize(raster_source); Region invalidation = SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size)); @@ -499,7 +503,7 @@ TEST_F(PictureLayerTilingIteratorTest, IteratorCoversLayerBoundsBothScale) { float scale = 6.7f; gfx::Size bounds(800, 600); - gfx::Rect full_rect(gfx::ToCeiledSize(gfx::ScaleSize(bounds, scale))); + gfx::Rect full_rect(gfx::ScaleToCeiledSize(bounds, scale)); Initialize(gfx::Size(256, 512), 5.2f, bounds); VerifyTilesExactlyCoverRect(scale, full_rect); VerifyTilesExactlyCoverRect(scale, gfx::Rect(2014, 1579, 867, 1033)); @@ -550,14 +554,13 @@ TEST(PictureLayerTilingTest, SkewportLimits) { client.SetTileSize(gfx::Size(100, 100)); LayerTreeSettings settings; - settings.max_tiles_for_interest_area = 10000; settings.skewport_extrapolation_limit_in_content_pixels = 75; - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - settings); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, settings); tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion()); @@ -637,11 +640,11 @@ TEST(PictureLayerTilingTest, ComputeSkewportExtremeCases) { gfx::Size layer_bounds(200, 200); client.SetTileSize(gfx::Size(100, 100)); LayerTreeSettings settings; - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - settings); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, settings); gfx::Rect viewport1(-1918, 255860, 4010, 2356); gfx::Rect viewport2(-7088, -91738, 14212, 8350); @@ -663,11 +666,11 @@ TEST(PictureLayerTilingTest, ComputeSkewport) { client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - LayerTreeSettings()); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, LayerTreeSettings()); tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion()); @@ -725,11 +728,11 @@ TEST(PictureLayerTilingTest, SkewportThroughUpdateTilePriorities) { client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - LayerTreeSettings()); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, LayerTreeSettings()); tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion()); @@ -793,20 +796,20 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { client.SetTileSize(gfx::Size(10, 10)); LayerTreeSettings settings; - settings.max_tiles_for_interest_area = 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. - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 0.25f, pile, &client, - settings); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 0.25f, raster_source, + &client, settings); + tiling->set_resolution(HIGH_RESOLUTION); gfx::Rect viewport_in_content_space = - gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f)); + gfx::ScaleToEnclosedRect(viewport, 0.25f); tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion()); auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting(); @@ -881,8 +884,7 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { // Move the viewport down 40 pixels. viewport = gfx::Rect(0, 40, 100, 100); - viewport_in_content_space = - gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f)); + viewport_in_content_space = gfx::ScaleToEnclosedRect(viewport, 0.25f); gfx::Rect skewport = tiling->ComputeSkewport(2.0, viewport_in_content_space); // Compute the soon border. @@ -961,8 +963,9 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { EXPECT_FLOAT_EQ(8.f, priority.distance_to_visible); // Test additional scales. - tiling = TestablePictureLayerTiling::Create(ACTIVE_TREE, 0.2f, pile, &client, - LayerTreeSettings()); + tiling = TestablePictureLayerTiling::Create(ACTIVE_TREE, 0.2f, raster_source, + &client, LayerTreeSettings()); + tiling->set_resolution(HIGH_RESOLUTION); tiling->ComputeTilePriorityRects(viewport, 1.0f, 4.0, Occlusion()); prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting(); @@ -988,228 +991,6 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) { EXPECT_FLOAT_EQ(30.f, priority.distance_to_visible); } -TEST(PictureLayerTilingTest, ExpandRectEqual) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(-1000, -1000, 10000, 10000); - int64 target_area = 100 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(in.ToString(), out.ToString()); -} - -TEST(PictureLayerTilingTest, ExpandRectSmaller) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(-1000, -1000, 10000, 10000); - int64 target_area = 100 * 100; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); - EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); - EXPECT_EQ(out.width() - in.width(), out.height() - in.height()); - - // |in| represents the visible rect, and |out| represents the eventually rect. - // If the eventually rect doesn't contain the visible rect, we will start - // losing tiles. - EXPECT_TRUE(out.Contains(in)); - EXPECT_TRUE(bounds.Contains(out)); -} - -TEST(PictureLayerTilingTest, ExpandRectUnbounded) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(-1000, -1000, 10000, 10000); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); - EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); - EXPECT_EQ(out.width() - in.width(), out.height() - in.height()); - EXPECT_NEAR(200 * 200, out.width() * out.height(), 100); - EXPECT_TRUE(bounds.Contains(out)); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedSmaller) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(50, 60, 40, 30); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(bounds.ToString(), out.ToString()); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedEqual) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds = in; - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(bounds.ToString(), out.ToString()); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedSmallerStretchVertical) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(45, 0, 90, 300); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(bounds.ToString(), out.ToString()); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedEqualStretchVertical) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(40, 0, 100, 300); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(bounds.ToString(), out.ToString()); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedSmallerStretchHorizontal) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(0, 55, 180, 190); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(bounds.ToString(), out.ToString()); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedEqualStretchHorizontal) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(0, 50, 180, 200); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(bounds.ToString(), out.ToString()); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedLeft) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(20, -1000, 10000, 10000); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); - EXPECT_EQ(out.bottom() - in.bottom(), out.right() - in.right()); - EXPECT_LE(out.width() * out.height(), target_area); - EXPECT_GT(out.width() * out.height(), - target_area - out.width() - out.height() * 2); - EXPECT_TRUE(bounds.Contains(out)); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedRight) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(-1000, -1000, 1000+120, 10000); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); - EXPECT_EQ(out.bottom() - in.bottom(), in.x() - out.x()); - EXPECT_LE(out.width() * out.height(), target_area); - EXPECT_GT(out.width() * out.height(), - target_area - out.width() - out.height() * 2); - EXPECT_TRUE(bounds.Contains(out)); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedTop) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(-1000, 30, 10000, 10000); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); - EXPECT_EQ(out.right() - in.right(), out.bottom() - in.bottom()); - EXPECT_LE(out.width() * out.height(), target_area); - EXPECT_GT(out.width() * out.height(), - target_area - out.width() * 2 - out.height()); - EXPECT_TRUE(bounds.Contains(out)); -} - -TEST(PictureLayerTilingTest, ExpandRectBoundedBottom) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(-1000, -1000, 10000, 1000 + 220); - int64 target_area = 200 * 200; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); - EXPECT_EQ(out.right() - in.right(), in.y() - out.y()); - EXPECT_LE(out.width() * out.height(), target_area); - EXPECT_GT(out.width() * out.height(), - target_area - out.width() * 2 - out.height()); - EXPECT_TRUE(bounds.Contains(out)); -} - -TEST(PictureLayerTilingTest, ExpandRectSquishedHorizontally) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(0, -4000, 100+40+20, 100000); - int64 target_area = 400 * 400; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(20, out.right() - in.right()); - EXPECT_EQ(40, in.x() - out.x()); - EXPECT_EQ(out.bottom() - in.bottom(), in.y() - out.y()); - EXPECT_LE(out.width() * out.height(), target_area); - EXPECT_GT(out.width() * out.height(), - target_area - out.width() * 2); - EXPECT_TRUE(bounds.Contains(out)); -} - -TEST(PictureLayerTilingTest, ExpandRectSquishedVertically) { - gfx::Rect in(40, 50, 100, 200); - gfx::Rect bounds(-4000, 0, 100000, 200+50+30); - int64 target_area = 400 * 400; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(30, out.bottom() - in.bottom()); - EXPECT_EQ(50, in.y() - out.y()); - EXPECT_EQ(out.right() - in.right(), in.x() - out.x()); - EXPECT_LE(out.width() * out.height(), target_area); - EXPECT_GT(out.width() * out.height(), - target_area - out.height() * 2); - EXPECT_TRUE(bounds.Contains(out)); -} - -TEST(PictureLayerTilingTest, ExpandRectOutOfBoundsFarAway) { - gfx::Rect in(400, 500, 100, 200); - gfx::Rect bounds(0, 0, 10, 10); - int64 target_area = 400 * 400; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_TRUE(out.IsEmpty()); -} - -TEST(PictureLayerTilingTest, ExpandRectOutOfBoundsExpandedFullyCover) { - gfx::Rect in(40, 50, 100, 100); - gfx::Rect bounds(0, 0, 10, 10); - int64 target_area = 400 * 400; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(bounds.ToString(), out.ToString()); -} - -TEST(PictureLayerTilingTest, ExpandRectOutOfBoundsExpandedPartlyCover) { - gfx::Rect in(600, 600, 100, 100); - gfx::Rect bounds(0, 0, 500, 500); - int64 target_area = 400 * 400; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_EQ(bounds.right(), out.right()); - EXPECT_EQ(bounds.bottom(), out.bottom()); - EXPECT_LE(out.width() * out.height(), target_area); - EXPECT_GT(out.width() * out.height(), - target_area - out.width() - out.height()); - EXPECT_TRUE(bounds.Contains(out)); -} - -TEST(PictureLayerTilingTest, EmptyStartingRect) { - // If a layer has a non-invertible transform, then the starting rect - // for the layer would be empty. - gfx::Rect in(40, 40, 0, 0); - gfx::Rect bounds(0, 0, 10, 10); - int64 target_area = 400 * 400; - gfx::Rect out = PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( - in, target_area, bounds, NULL); - EXPECT_TRUE(out.IsEmpty()); -} - static void TileExists(bool exists, Tile* tile, const gfx::Rect& geometry_rect) { EXPECT_EQ(exists, tile != NULL) << geometry_rect.ToString(); @@ -1293,12 +1074,13 @@ TEST_F(PictureLayerTilingIteratorTest, gfx::Size layer_bounds(10000, 10000); client_.SetTileSize(gfx::Size(100, 100)); LayerTreeSettings settings; - settings.max_tiles_for_interest_area = 1; + settings.tiling_interest_area_padding = 1; - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); - tiling_ = TestablePictureLayerTiling::Create(PENDING_TREE, 1.f, pile, + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + tiling_ = TestablePictureLayerTiling::Create(PENDING_TREE, 1.f, raster_source, &client_, settings); + tiling_->set_resolution(HIGH_RESOLUTION); VerifyTilesExactlyCoverRect(1.f, gfx::Rect(layer_bounds)); VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, false)); @@ -1330,12 +1112,12 @@ TEST(ComputeTilePriorityRectsTest, VisibleTiles) { client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - current_layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(current_layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - LayerTreeSettings()); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, LayerTreeSettings()); + tiling->set_resolution(HIGH_RESOLUTION); tiling->ComputeTilePriorityRects(viewport_in_layer_space, current_layer_contents_scale, @@ -1385,12 +1167,12 @@ TEST(ComputeTilePriorityRectsTest, OffscreenTiles) { client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - current_layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(current_layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - LayerTreeSettings()); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, LayerTreeSettings()); + tiling->set_resolution(HIGH_RESOLUTION); tiling->ComputeTilePriorityRects(viewport_in_layer_space, current_layer_contents_scale, @@ -1450,12 +1232,12 @@ TEST(ComputeTilePriorityRectsTest, PartiallyOffscreenLayer) { client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - current_layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(current_layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - LayerTreeSettings()); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, LayerTreeSettings()); + tiling->set_resolution(HIGH_RESOLUTION); tiling->ComputeTilePriorityRects(viewport_in_layer_space, current_layer_contents_scale, @@ -1509,12 +1291,12 @@ TEST(ComputeTilePriorityRectsTest, PartiallyOffscreenRotatedLayer) { client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - current_layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(current_layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - LayerTreeSettings()); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, LayerTreeSettings()); + tiling->set_resolution(HIGH_RESOLUTION); tiling->ComputeTilePriorityRects(viewport_in_layer_space, current_layer_contents_scale, @@ -1593,12 +1375,12 @@ TEST(ComputeTilePriorityRectsTest, PerspectiveLayer) { client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - current_layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(current_layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - LayerTreeSettings()); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, LayerTreeSettings()); + tiling->set_resolution(HIGH_RESOLUTION); tiling->ComputeTilePriorityRects(viewport_in_layer_space, current_layer_contents_scale, @@ -1687,12 +1469,12 @@ TEST(ComputeTilePriorityRectsTest, PerspectiveLayerClippedByW) { client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - current_layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(current_layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - LayerTreeSettings()); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, LayerTreeSettings()); + tiling->set_resolution(HIGH_RESOLUTION); tiling->ComputeTilePriorityRects(viewport_in_layer_space, current_layer_contents_scale, @@ -1750,14 +1532,13 @@ TEST(ComputeTilePriorityRectsTest, BasicMotion) { client.SetTileSize(gfx::Size(100, 100)); LayerTreeSettings settings; - settings.max_tiles_for_interest_area = 10000; - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - current_layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(current_layer_bounds); scoped_ptr<TestablePictureLayerTiling> tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - settings); + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, settings); + tiling->set_resolution(HIGH_RESOLUTION); // previous ("last") frame tiling->ComputeTilePriorityRects(viewport_in_layer_space, @@ -1830,11 +1611,11 @@ TEST(ComputeTilePriorityRectsTest, RotationMotion) { client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - current_layer_bounds); - tiling = TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, &client, - LayerTreeSettings()); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(current_layer_bounds); + tiling = TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, + &client, LayerTreeSettings()); + tiling->set_resolution(HIGH_RESOLUTION); // previous ("last") frame tiling->ComputeTilePriorityRects(viewport_in_layer_space, @@ -1880,14 +1661,13 @@ TEST(PictureLayerTilingTest, RecycledTilesCleared) { active_client.SetTileSize(gfx::Size(100, 100)); LayerTreeSettings settings; - settings.max_tiles_for_interest_area = 10; - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - gfx::Size(10000, 10000)); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(gfx::Size(10000, 10000)); scoped_ptr<TestablePictureLayerTiling> active_tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, &active_client, settings); + active_tiling->set_resolution(HIGH_RESOLUTION); // Create all tiles on this tiling. active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion()); @@ -1896,11 +1676,12 @@ TEST(PictureLayerTilingTest, RecycledTilesCleared) { recycle_client.SetTileSize(gfx::Size(100, 100)); recycle_client.set_twin_tiling(active_tiling.get()); - pile = FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - gfx::Size(10000, 10000)); + raster_source = + FakeDisplayListRasterSource::CreateFilled(gfx::Size(10000, 10000)); scoped_ptr<TestablePictureLayerTiling> recycle_tiling = - TestablePictureLayerTiling::Create(PENDING_TREE, 1.0f, pile, + TestablePictureLayerTiling::Create(PENDING_TREE, 1.0f, raster_source, &recycle_client, settings); + recycle_tiling->set_resolution(HIGH_RESOLUTION); // Create all tiles on the second tiling. All tiles should be shared. recycle_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, @@ -1933,12 +1714,12 @@ TEST(PictureLayerTilingTest, RecycledTilesClearedOnReset) { FakePictureLayerTilingClient active_client; active_client.SetTileSize(gfx::Size(100, 100)); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - gfx::Size(100, 100)); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(gfx::Size(100, 100)); scoped_ptr<TestablePictureLayerTiling> active_tiling = - TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, pile, + TestablePictureLayerTiling::Create(ACTIVE_TREE, 1.0f, raster_source, &active_client, LayerTreeSettings()); + active_tiling->set_resolution(HIGH_RESOLUTION); // Create all tiles on this tiling. active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion()); @@ -1948,13 +1729,13 @@ TEST(PictureLayerTilingTest, RecycledTilesClearedOnReset) { recycle_client.set_twin_tiling(active_tiling.get()); LayerTreeSettings settings; - settings.max_tiles_for_interest_area = 10; - pile = FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - gfx::Size(100, 100)); + raster_source = + FakeDisplayListRasterSource::CreateFilled(gfx::Size(100, 100)); scoped_ptr<TestablePictureLayerTiling> recycle_tiling = - TestablePictureLayerTiling::Create(PENDING_TREE, 1.0f, pile, + TestablePictureLayerTiling::Create(PENDING_TREE, 1.0f, raster_source, &recycle_client, settings); + recycle_tiling->set_resolution(HIGH_RESOLUTION); // Create all tiles on the recycle tiling. All tiles should be shared. recycle_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, @@ -1988,10 +1769,9 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeTilesAndUpdateToCurrent) { 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); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(gfx::Size(250, 150)); + tiling_->SetRasterSourceAndResize(raster_source); // Tile size in the tiling should be resized to 250x200. EXPECT_EQ(250, tiling_->TilingDataForTesting().max_texture_size().width()); @@ -1999,5 +1779,22 @@ TEST_F(PictureLayerTilingIteratorTest, ResizeTilesAndUpdateToCurrent) { EXPECT_EQ(0u, tiling_->AllTilesForTesting().size()); } +// This test runs into floating point issues because of big numbers. +TEST_F(PictureLayerTilingIteratorTest, GiantRect) { + gfx::Size tile_size(256, 256); + gfx::Size layer_size(33554432, 33554432); + float contents_scale = 1.f; + + client_.SetTileSize(tile_size); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateEmpty(layer_size); + tiling_ = TestablePictureLayerTiling::Create(PENDING_TREE, contents_scale, + raster_source, &client_, + LayerTreeSettings()); + + gfx::Rect content_rect(25554432, 25554432, 950, 860); + VerifyTilesExactlyCoverRect(contents_scale, content_rect); +} + } // namespace } // namespace cc diff --git a/chromium/cc/tiles/prioritized_tile.cc b/chromium/cc/tiles/prioritized_tile.cc index 67f33c9dbc8..2e0246c34c9 100644 --- a/chromium/cc/tiles/prioritized_tile.cc +++ b/chromium/cc/tiles/prioritized_tile.cc @@ -33,6 +33,7 @@ void PrioritizedTile::AsValueInto(base::trace_event::TracedValue* value) const { value->BeginDictionary("combined_priority"); priority().AsValueInto(value); + value->SetBoolean("is_occluded", is_occluded_); value->EndDictionary(); value->SetString("resolution", TileResolutionToString(priority().resolution)); diff --git a/chromium/cc/tiles/raster_tile_priority_queue_all.cc b/chromium/cc/tiles/raster_tile_priority_queue_all.cc index 8f7bdbf0436..ea3c14f8dd0 100644 --- a/chromium/cc/tiles/raster_tile_priority_queue_all.cc +++ b/chromium/cc/tiles/raster_tile_priority_queue_all.cc @@ -136,13 +136,14 @@ RasterTilePriorityQueueAll::GetNextQueues() const { 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) { + // If we're down to eventually bin tiles on the active tree and there + // is a pending tree, process the entire pending tree to allow tiles + // required for activation to be initialized when memory policy only + // allows prepaint. The eventually bin tiles on the active tree are + // lowest priority since that work is likely to be thrown away when + // we activate. + if (active_priority.priority_bin == TilePriority::EVENTUALLY) return pending_queues_; - } return active_queues_; } case NEW_CONTENT_TAKES_PRIORITY: { diff --git a/chromium/cc/tiles/tile.cc b/chromium/cc/tiles/tile.cc index 6052e5e0457..87ec3f7befd 100644 --- a/chromium/cc/tiles/tile.cc +++ b/chromium/cc/tiles/tile.cc @@ -14,30 +14,25 @@ namespace cc { -Tile::Id Tile::s_next_id_ = 1; - Tile::Tile(TileManager* tile_manager, - const gfx::Size& desired_texture_size, - const gfx::Rect& content_rect, - float contents_scale, + const CreateInfo& info, 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), + content_rect_(info.content_rect), + enclosing_layer_rect_(info.enclosing_layer_rect), + contents_scale_(info.contents_scale), layer_id_(layer_id), source_frame_number_(source_frame_number), flags_(flags), - tiling_i_index_(-1), - tiling_j_index_(-1), + tiling_i_index_(info.tiling_i_index), + tiling_j_index_(info.tiling_j_index), required_for_activation_(false), required_for_draw_(false), - id_(s_next_id_++), + id_(tile_manager->GetUniqueTileId()), invalidated_id_(0), - scheduled_priority_(0) { -} + scheduled_priority_(0) {} Tile::~Tile() { TRACE_EVENT_OBJECT_DELETED_WITH_ID( @@ -71,15 +66,14 @@ size_t Tile::GPUMemoryUsageInBytes() const { if (draw_info_.resource_) { // We can use UncheckedSizeInBytes, since the tile size is determined by the // compositor. - return Resource::UncheckedMemorySizeBytes(draw_info_.resource_->size(), - draw_info_.resource_->format()); + return ResourceUtil::UncheckedSizeInBytes<size_t>( + draw_info_.resource_->size(), draw_info_.resource_->format()); } return 0; } void Tile::Deleter::operator()(Tile* tile) const { - TileManager* tile_manager = tile->tile_manager_; - tile_manager->Release(tile); + tile->tile_manager_->Release(tile); } } // namespace cc diff --git a/chromium/cc/tiles/tile.h b/chromium/cc/tiles/tile.h index e53c2ac52f8..e245e0111d9 100644 --- a/chromium/cc/tiles/tile.h +++ b/chromium/cc/tiles/tile.h @@ -23,7 +23,27 @@ class CC_EXPORT Tile { void operator()(Tile* tile) const; }; - enum TileRasterFlags { USE_PICTURE_ANALYSIS = 1 << 0 }; + class CC_EXPORT CreateInfo { + public: + int tiling_i_index; + int tiling_j_index; + gfx::Rect enclosing_layer_rect; + gfx::Rect content_rect; + float contents_scale; + + CreateInfo(int tiling_i_index, + int tiling_j_index, + const gfx::Rect& enclosing_layer_rect, + const gfx::Rect& content_rect, + float contents_scale) + : tiling_i_index(tiling_i_index), + tiling_j_index(tiling_j_index), + enclosing_layer_rect(enclosing_layer_rect), + content_rect(content_rect), + contents_scale(contents_scale) {} + }; + + enum TileRasterFlags { USE_PICTURE_ANALYSIS = 1 << 0, IS_OPAQUE = 1 << 1 }; typedef uint64 Id; @@ -45,13 +65,18 @@ class CC_EXPORT Tile { return !!(flags_ & USE_PICTURE_ANALYSIS); } + bool is_opaque() const { return !!(flags_ & IS_OPAQUE); } + 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_; } + const gfx::Rect& content_rect() const { return content_rect_; } + const gfx::Rect& enclosing_layer_rect() const { + return enclosing_layer_rect_; + } int layer_id() const { return layer_id_; } @@ -59,12 +84,8 @@ class CC_EXPORT Tile { size_t GPUMemoryUsageInBytes() const; - gfx::Size desired_texture_size() const { return desired_texture_size_; } + const gfx::Size& desired_texture_size() const { return content_rect_.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_; } @@ -86,9 +107,7 @@ class CC_EXPORT Tile { // Methods called by by tile manager. Tile(TileManager* tile_manager, - const gfx::Size& desired_texture_size, - const gfx::Rect& content_rect, - float contents_scale, + const CreateInfo& info, int layer_id, int source_frame_number, int flags); @@ -96,23 +115,22 @@ class CC_EXPORT Tile { bool HasRasterTask() const { return !!raster_task_.get(); } - TileManager* tile_manager_; - gfx::Size desired_texture_size_; - gfx::Rect content_rect_; - float contents_scale_; + TileManager* const tile_manager_; + const gfx::Rect content_rect_; + const gfx::Rect enclosing_layer_rect_; + const float contents_scale_; TileDrawInfo draw_info_; - int layer_id_; - int source_frame_number_; - int flags_; - int tiling_i_index_; - int tiling_j_index_; + const int layer_id_; + const int source_frame_number_; + const int flags_; + const int tiling_i_index_; + const int tiling_j_index_; bool required_for_activation_ : 1; bool required_for_draw_ : 1; Id id_; - static Id s_next_id_; // The rect bounding the changes in this Tile vs the previous tile it // replaced. diff --git a/chromium/cc/tiles/tile_draw_info.cc b/chromium/cc/tiles/tile_draw_info.cc index 6b12e73f5c6..c1042ceff3d 100644 --- a/chromium/cc/tiles/tile_draw_info.cc +++ b/chromium/cc/tiles/tile_draw_info.cc @@ -12,10 +12,10 @@ namespace cc { TileDrawInfo::TileDrawInfo() : mode_(RESOURCE_MODE), solid_color_(SK_ColorWHITE), + resource_(nullptr), contents_swizzled_(false), was_ever_ready_to_draw_(false), - was_ever_used_to_draw_(false) { -} + was_ever_used_to_draw_(false) {} TileDrawInfo::~TileDrawInfo() { DCHECK(!resource_); diff --git a/chromium/cc/tiles/tile_draw_info.h b/chromium/cc/tiles/tile_draw_info.h index dcb755ad34e..05596ba9216 100644 --- a/chromium/cc/tiles/tile_draw_info.h +++ b/chromium/cc/tiles/tile_draw_info.h @@ -74,9 +74,6 @@ class CC_EXPORT TileDrawInfo { 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; @@ -98,7 +95,7 @@ class CC_EXPORT TileDrawInfo { Mode mode_; SkColor solid_color_; - scoped_ptr<ScopedResource> resource_; + Resource* resource_; bool contents_swizzled_; // Used for gathering UMA stats. diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc index 23d2eca12bc..b9d3ab7fd15 100644 --- a/chromium/cc/tiles/tile_manager.cc +++ b/chromium/cc/tiles/tile_manager.cc @@ -33,8 +33,8 @@ const bool kUseColorEstimator = true; DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER( ScopedRasterTaskTimer, - "Compositing.RasterTask.RasterUs", - "Compositing.RasterTask.RasterPixelsPerMs"); + "Compositing.%s.RasterTask.RasterUs", + "Compositing.%s.RasterTask.RasterPixelsPerMs"); class RasterTaskImpl : public RasterTask { public: @@ -56,7 +56,8 @@ class RasterTaskImpl : public RasterTask { const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>& reply, ImageDecodeTask::Vector* dependencies) - : RasterTask(resource, dependencies), + : RasterTask(dependencies), + resource_(resource), raster_source_(raster_source), content_rect_(content_rect), invalid_content_rect_(invalid_content_rect), @@ -93,13 +94,10 @@ class RasterTaskImpl : public RasterTask { void ScheduleOnOriginThread(TileTaskClient* client) override { DCHECK(!raster_buffer_); raster_buffer_ = client->AcquireBufferForRaster( - resource(), resource_content_id_, previous_content_id_); + resource_, resource_content_id_, previous_content_id_); } void CompleteOnOriginThread(TileTaskClient* client) override { client->ReleaseBufferForRaster(raster_buffer_.Pass()); - } - void RunReplyOnOriginThread() override { - DCHECK(!raster_buffer_); reply_.Run(analysis_, !HasFinishedRunning()); } @@ -127,11 +125,13 @@ class RasterTaskImpl : public RasterTask { DCHECK(raster_source); + bool include_images = tile_resolution_ != LOW_RESOLUTION; raster_buffer_->Playback(raster_source_.get(), content_rect_, invalid_content_rect_, new_content_id_, - contents_scale_); + contents_scale_, include_images); } + const Resource* resource_; RasterSource::SolidColorAnalysis analysis_; scoped_refptr<RasterSource> raster_source_; gfx::Rect content_rect_; @@ -153,47 +153,6 @@ class RasterTaskImpl : public RasterTask { DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl); }; -class ImageDecodeTaskImpl : public ImageDecodeTask { - public: - ImageDecodeTaskImpl(SkPixelRef* pixel_ref, - uint64_t source_prepare_tiles_id, - const base::Callback<void(bool was_canceled)>& reply) - : pixel_ref_(skia::SharePtr(pixel_ref)), - source_prepare_tiles_id_(source_prepare_tiles_id), - reply_(reply) {} - - // Overridden from Task: - void RunOnWorkerThread() override { - TRACE_EVENT1("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", - "source_prepare_tiles_id", source_prepare_tiles_id_); - - devtools_instrumentation::ScopedImageDecodeTask image_decode_task( - pixel_ref_.get()); - // 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 TileTask: - void ScheduleOnOriginThread(TileTaskClient* client) override {} - void CompleteOnOriginThread(TileTaskClient* client) override {} - void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); } - - protected: - ~ImageDecodeTaskImpl() override {} - - private: - skia::RefPtr<SkPixelRef> pixel_ref_; - uint64_t source_prepare_tiles_id_; - 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: @@ -253,8 +212,8 @@ TileManager::TileManager( base::Bind(&TileManager::CheckAndIssueSignals, base::Unretained(this))), has_scheduled_tile_tasks_(false), - prepare_tiles_count_(0u) { -} + prepare_tiles_count_(0u), + next_tile_id_(0u) {} TileManager::~TileManager() { FinishTasksAndCleanUp(); @@ -300,13 +259,6 @@ void TileManager::Release(Tile* tile) { released_tiles_.push_back(tile); } -TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const { - TaskSetCollection tasks_that_should_be_forced_to_complete; - if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY) - tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true; - return tasks_that_should_be_forced_to_complete; -} - void TileManager::FreeResourcesForReleasedTiles() { for (auto* tile : released_tiles_) FreeResourcesForTile(tile); @@ -324,14 +276,7 @@ void TileManager::CleanUpReleasedTiles() { DCHECK(tiles_.find(tile->id()) != tiles_.end()); tiles_.erase(tile->id()); - LayerCountMap::iterator layer_it = - used_layer_counts_.find(tile->layer_id()); - DCHECK_GT(layer_it->second, 0); - if (--layer_it->second == 0) { - used_layer_counts_.erase(layer_it); - image_decode_tasks_.erase(tile->layer_id()); - } - + image_decode_controller_.SubtractLayerUsedCount(tile->layer_id()); delete tile; } released_tiles_.swap(tiles_to_retain); @@ -347,9 +292,8 @@ void TileManager::DidFinishRunningTileTasks(TaskSet task_set) { case ALL: { has_scheduled_tile_tasks_ = false; - bool memory_usage_above_limit = - resource_pool_->total_memory_usage_bytes() > - global_state_.soft_memory_limit_in_bytes; + bool memory_usage_above_limit = resource_pool_->memory_usage_bytes() > + global_state_.soft_memory_limit_in_bytes; if (all_tiles_that_need_to_be_rasterized_are_scheduled_ && !memory_usage_above_limit) { @@ -423,10 +367,6 @@ bool TileManager::PrepareTiles( TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD, "state", BasicStateAsValue()); - - TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this, - resource_pool_->total_memory_usage_bytes() - - resource_pool_->acquired_memory_usage_bytes()); return true; } @@ -541,7 +481,7 @@ void TileManager::AssignGpuMemoryToTiles( // 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); + resource_pool_->CheckBusyResources(); // Now give memory out to the tiles until we're out, and build // the needs-to-be-rasterized queue. @@ -553,8 +493,8 @@ void TileManager::AssignGpuMemoryToTiles( global_state_.num_resources_limit); MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes, global_state_.num_resources_limit); - MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(), - resource_pool_->acquired_resource_count()); + MemoryUsage memory_usage(resource_pool_->memory_usage_bytes(), + resource_pool_->resource_count()); scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue; for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) { @@ -587,7 +527,7 @@ void TileManager::AssignGpuMemoryToTiles( MemoryUsage memory_required_by_tile_to_be_scheduled; if (!tile->raster_task_.get()) { memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig( - tile->desired_texture_size(), tile_task_runner_->GetResourceFormat()); + tile->desired_texture_size(), DetermineResourceFormat(tile)); } bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW; @@ -646,8 +586,10 @@ void TileManager::AssignGpuMemoryToTiles( void TileManager::FreeResourcesForTile(Tile* tile) { TileDrawInfo& draw_info = tile->draw_info(); - if (draw_info.resource_) - resource_pool_->ReleaseResource(draw_info.resource_.Pass(), tile->id()); + if (draw_info.resource_) { + resource_pool_->ReleaseResource(draw_info.resource_, tile->id()); + draw_info.resource_ = nullptr; + } } void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw( @@ -712,21 +654,11 @@ void TileManager::ScheduleTasks( did_check_for_completed_tasks_since_last_schedule_tasks_ = false; } -scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask( - Tile* tile, - SkPixelRef* pixel_ref) { - return make_scoped_refptr(new ImageDecodeTaskImpl( - pixel_ref, prepare_tiles_count_, - base::Bind(&TileManager::OnImageDecodeTaskCompleted, - base::Unretained(this), tile->layer_id(), - base::Unretained(pixel_ref)))); -} - scoped_refptr<RasterTask> TileManager::CreateRasterTask( const PrioritizedTile& prioritized_tile) { Tile* tile = prioritized_tile.tile(); uint64_t resource_content_id = 0; - scoped_ptr<ScopedResource> resource; + Resource* resource = nullptr; if (tile->invalidated_id()) { // TODO(danakj): For resources that are in use, we should still grab them // and copy from them instead of rastering everything. crbug.com/492754 @@ -735,73 +667,39 @@ scoped_refptr<RasterTask> TileManager::CreateRasterTask( } if (resource) { resource_content_id = tile->invalidated_id(); - DCHECK_EQ(tile_task_runner_->GetResourceFormat(), resource->format()); + DCHECK_EQ(DetermineResourceFormat(tile), resource->format()); DCHECK_EQ(tile->desired_texture_size().ToString(), resource->size().ToString()); } else { - resource = resource_pool_->AcquireResource( - tile->desired_texture_size(), tile_task_runner_->GetResourceFormat()); + resource = resource_pool_->AcquireResource(tile->desired_texture_size(), + DetermineResourceFormat(tile)); } - 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; - 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(); - - // Append existing image decode task if available. - PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id); - if (decode_task_it != existing_pixel_refs.end()) { - decode_tasks.push_back(decode_task_it->second); - continue; - } - - // Create and append new image decode task for this pixel ref. - scoped_refptr<ImageDecodeTask> decode_task = - CreateImageDecodeTask(tile, pixel_ref); - decode_tasks.push_back(decode_task); - existing_pixel_refs[id] = decode_task; + std::vector<PositionImage> images; + prioritized_tile.raster_source()->GetDiscardableImagesInRect( + tile->enclosing_layer_rect(), &images); + for (const auto& image : images) { + decode_tasks.push_back(image_decode_controller_.GetTaskForImage( + image, tile->layer_id(), prepare_tiles_count_)); } return make_scoped_refptr(new RasterTaskImpl( - const_resource, prioritized_tile.raster_source(), tile->content_rect(), + resource, prioritized_tile.raster_source(), tile->content_rect(), tile->invalidated_content_rect(), tile->contents_scale(), prioritized_tile.priority().resolution, tile->layer_id(), prepare_tiles_count_, static_cast<const void*>(tile), tile->id(), tile->invalidated_id(), resource_content_id, tile->source_frame_number(), tile->use_picture_analysis(), base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this), - tile->id(), base::Passed(&resource)), + tile->id(), resource), &decode_tasks)); } -void TileManager::OnImageDecodeTaskCompleted(int layer_id, - SkPixelRef* pixel_ref, - bool was_canceled) { - // If the task was canceled, we need to clean it up - // from |image_decode_tasks_|. - if (!was_canceled) - return; - - LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id); - if (layer_it == image_decode_tasks_.end()) - return; - - PixelRefTaskMap& pixel_ref_tasks = layer_it->second; - PixelRefTaskMap::iterator task_it = - pixel_ref_tasks.find(pixel_ref->getGenerationID()); - - if (task_it != pixel_ref_tasks.end()) - pixel_ref_tasks.erase(task_it); -} - void TileManager::OnRasterTaskCompleted( Tile::Id tile_id, - scoped_ptr<ScopedResource> resource, + Resource* resource, const RasterSource::SolidColorAnalysis& analysis, bool was_canceled) { DCHECK(tiles_.find(tile_id) != tiles_.end()); @@ -813,16 +711,20 @@ void TileManager::OnRasterTaskCompleted( if (was_canceled) { ++flush_stats_.canceled_count; - resource_pool_->ReleaseResource(resource.Pass(), tile->invalidated_id()); + // TODO(ericrk): If more partial raster work is done in the future, it may + // be worth returning the resource to the pool with its previous ID (not + // currently tracked). crrev.com/1370333002/#ps40001 has a possible method + // of achieving this. + resource_pool_->ReleaseResource(resource, 0 /* content_id */); return; } - UpdateTileDrawInfo(tile, resource.Pass(), analysis); + UpdateTileDrawInfo(tile, resource, analysis); } void TileManager::UpdateTileDrawInfo( Tile* tile, - scoped_ptr<ScopedResource> resource, + Resource* resource, const RasterSource::SolidColorAnalysis& analysis) { TileDrawInfo& draw_info = tile->draw_info(); @@ -831,16 +733,17 @@ void TileManager::UpdateTileDrawInfo( if (analysis.is_solid_color) { draw_info.set_solid_color(analysis.solid_color); if (resource) { - // Pass the old tile id here because the tile is solid color so we did not - // raster anything into the tile resource. - resource_pool_->ReleaseResource(resource.Pass(), tile->invalidated_id()); + // TODO(ericrk): If more partial raster work is done in the future, it may + // be worth returning the resource to the pool with its previous ID (not + // currently tracked). crrev.com/1370333002/#ps40001 has a possible method + // of achieving this. + resource_pool_->ReleaseResource(resource, 0 /* content_id */); } } else { DCHECK(resource); draw_info.set_use_resource(); - draw_info.resource_ = resource.Pass(); - draw_info.contents_swizzled_ = - tile_task_runner_->GetResourceRequiresSwizzle(); + draw_info.resource_ = resource; + draw_info.contents_swizzled_ = DetermineResourceRequiresSwizzle(tile); } DCHECK(draw_info.IsReadyToDraw()); draw_info.set_was_ever_ready_to_draw(); @@ -848,22 +751,19 @@ void TileManager::UpdateTileDrawInfo( client_->NotifyTileStateChanged(tile); } -ScopedTilePtr TileManager::CreateTile(const gfx::Size& desired_texture_size, - const gfx::Rect& content_rect, - float contents_scale, +ScopedTilePtr TileManager::CreateTile(const Tile::CreateInfo& info, int layer_id, int source_frame_number, int flags) { // We need to have a tile task worker pool to do anything meaningful with // tiles. DCHECK(tile_task_runner_); - ScopedTilePtr tile(new Tile(this, desired_texture_size, content_rect, - contents_scale, layer_id, source_frame_number, - flags)); + ScopedTilePtr tile( + new Tile(this, info, layer_id, source_frame_number, flags)); DCHECK(tiles_.find(tile->id()) == tiles_.end()); tiles_[tile->id()] = tile.get(); - used_layer_counts_[tile->layer_id()]++; + image_decode_controller_.AddLayerUsedCount(tile->layer_id()); return tile; } @@ -1024,6 +924,14 @@ void TileManager::CheckIfMoreTilesNeedToBePrepared() { signals_check_notifier_.Schedule(); } +ResourceFormat TileManager::DetermineResourceFormat(const Tile* tile) const { + return tile_task_runner_->GetResourceFormat(!tile->is_opaque()); +} + +bool TileManager::DetermineResourceRequiresSwizzle(const Tile* tile) const { + return tile_task_runner_->GetResourceRequiresSwizzle(!tile->is_opaque()); +} + TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) { } @@ -1045,9 +953,10 @@ TileManager::MemoryUsage::MemoryUsage(size_t memory_bytes, TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig( const gfx::Size& size, ResourceFormat format) { - // We can use UncheckedMemorySizeBytes here since this is used with a tile + // We can use UncheckedSizeInBytes here since this is used with a tile // size which is determined by the compositor (it's at most max texture size). - return MemoryUsage(Resource::UncheckedMemorySizeBytes(size, format), 1); + return MemoryUsage(ResourceUtil::UncheckedSizeInBytes<size_t>(size, format), + 1); } // static diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h index a69e5a27dcf..d0ba944b32d 100644 --- a/chromium/cc/tiles/tile_manager.h +++ b/chromium/cc/tiles/tile_manager.h @@ -20,6 +20,7 @@ #include "cc/resources/memory_history.h" #include "cc/resources/resource_pool.h" #include "cc/tiles/eviction_tile_priority_queue.h" +#include "cc/tiles/image_decode_controller.h" #include "cc/tiles/raster_tile_priority_queue.h" #include "cc/tiles/tile.h" #include "cc/tiles/tile_draw_info.h" @@ -132,9 +133,7 @@ class CC_EXPORT TileManager : public TileTaskRunnerClient { // date draw information. void Flush(); - ScopedTilePtr CreateTile(const gfx::Size& desired_texture_size, - const gfx::Rect& content_rect, - float contents_scale, + ScopedTilePtr CreateTile(const Tile::CreateInfo& info, int layer_id, int source_frame_number, int flags); @@ -155,7 +154,7 @@ class CC_EXPORT TileManager : public TileTaskRunnerClient { TileDrawInfo& draw_info = tiles[i]->draw_info(); draw_info.resource_ = resource_pool_->AcquireResource( tiles[i]->desired_texture_size(), - tile_task_runner_->GetResourceFormat()); + tile_task_runner_->GetResourceFormat(false)); } } @@ -214,10 +213,10 @@ class CC_EXPORT TileManager : public TileTaskRunnerClient { friend class Tile; // Virtual for testing. virtual void Release(Tile* tile); + Tile::Id GetUniqueTileId() { return ++next_tile_id_; } // Overriden from TileTaskRunnerClient: void DidFinishRunningTileTasks(TaskSet task_set) override; - TaskSetCollection TasksThatShouldBeForcedToComplete() const override; typedef std::vector<PrioritizedTile> PrioritizedTileVector; typedef std::set<Tile*> TileSet; @@ -252,21 +251,16 @@ class CC_EXPORT TileManager : public TileTaskRunnerClient { int resource_count_; }; - void OnImageDecodeTaskCompleted(int layer_id, - SkPixelRef* pixel_ref, - bool was_canceled); void OnRasterTaskCompleted(Tile::Id tile, - scoped_ptr<ScopedResource> resource, + Resource* resource, const RasterSource::SolidColorAnalysis& analysis, bool was_canceled); void UpdateTileDrawInfo(Tile* tile, - scoped_ptr<ScopedResource> resource, + Resource* 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( const PrioritizedTile& prioritized_tile); @@ -286,6 +280,9 @@ class CC_EXPORT TileManager : public TileTaskRunnerClient { void CheckIfMoreTilesNeedToBePrepared(); void CheckAndIssueSignals(); + ResourceFormat DetermineResourceFormat(const Tile* tile) const; + bool DetermineResourceRequiresSwizzle(const Tile* tile) const; + TileManagerClient* client_; scoped_refptr<base::SequencedTaskRunner> task_runner_; ResourcePool* resource_pool_; @@ -302,13 +299,7 @@ class CC_EXPORT TileManager : public TileTaskRunnerClient { bool did_check_for_completed_tasks_since_last_schedule_tasks_; bool did_oom_on_last_assign_; - typedef base::hash_map<uint32_t, scoped_refptr<ImageDecodeTask>> - PixelRefTaskMap; - typedef base::hash_map<int, PixelRefTaskMap> LayerPixelRefTaskMap; - LayerPixelRefTaskMap image_decode_tasks_; - - typedef base::hash_map<int, int> LayerCountMap; - LayerCountMap used_layer_counts_; + ImageDecodeController image_decode_controller_; RasterTaskCompletionStats flush_stats_; @@ -339,6 +330,7 @@ class CC_EXPORT TileManager : public TileTaskRunnerClient { bool has_scheduled_tile_tasks_; uint64_t prepare_tiles_count_; + uint64_t next_tile_id_; DISALLOW_COPY_AND_ASSIGN(TileManager); }; diff --git a/chromium/cc/tiles/tile_manager_perftest.cc b/chromium/cc/tiles/tile_manager_perftest.cc index eea9b94922b..c7337cfbbad 100644 --- a/chromium/cc/tiles/tile_manager_perftest.cc +++ b/chromium/cc/tiles/tile_manager_perftest.cc @@ -2,18 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/lazy_instance.h" #include "base/location.h" #include "base/thread_task_runner_handle.h" #include "base/time/time.h" #include "cc/debug/lap_timer.h" #include "cc/raster/raster_buffer.h" #include "cc/test/begin_frame_args_test.h" +#include "cc/test/fake_display_list_raster_source.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/fake_tile_manager_client.h" #include "cc/test/test_shared_bitmap_manager.h" @@ -59,14 +60,15 @@ class FakeTileTaskRunnerImpl : public TileTaskRunner, public TileTaskClient { task->WillComplete(); task->CompleteOnOriginThread(this); task->DidComplete(); - - task->RunReplyOnOriginThread(); } completed_tasks_.clear(); } - ResourceFormat GetResourceFormat() const override { return RGBA_8888; } - bool GetResourceRequiresSwizzle() const override { - return !PlatformColor::SameComponentOrder(GetResourceFormat()); + ResourceFormat GetResourceFormat(bool must_support_alpha) const override { + return RGBA_8888; + } + bool GetResourceRequiresSwizzle(bool must_support_alpha) const override { + return !PlatformColor::SameComponentOrder( + GetResourceFormat(must_support_alpha)); } // Overridden from TileTaskClient: @@ -91,6 +93,7 @@ class TileManagerPerfTest : public testing::Test { max_tiles_(10000), id_(7), proxy_(base::ThreadTaskRunnerHandle::Get()), + output_surface_(FakeOutputSurface::Create3d()), host_impl_(LayerTreeSettings(), &proxy_, &shared_bitmap_manager_, @@ -111,7 +114,7 @@ class TileManagerPerfTest : public testing::Test { global_state_ = state; host_impl_.resource_pool()->SetResourceUsageLimits( - state.soft_memory_limit_in_bytes, 0, state.num_resources_limit); + state.soft_memory_limit_in_bytes, state.num_resources_limit); host_impl_.tile_manager()->SetGlobalStateForTesting(state); } @@ -121,18 +124,18 @@ class TileManagerPerfTest : public testing::Test { } virtual void InitializeRenderer() { - host_impl_.InitializeRenderer(FakeOutputSurface::Create3d().Pass()); + host_impl_.InitializeRenderer(output_surface_.get()); tile_manager()->SetTileTaskRunnerForTesting( g_fake_tile_task_runner.Pointer()); } void SetupDefaultTrees(const gfx::Size& layer_bounds) { - scoped_refptr<FakePicturePileImpl> pending_pile = - FakePicturePileImpl::CreateFilledPile(kDefaultTileSize, layer_bounds); - scoped_refptr<FakePicturePileImpl> active_pile = - FakePicturePileImpl::CreateFilledPile(kDefaultTileSize, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupTrees(pending_pile, active_pile); + SetupTrees(pending_raster_source, active_raster_source); } void ActivateTree() { @@ -150,21 +153,22 @@ class TileManagerPerfTest : public testing::Test { active_root_layer_->set_fixed_tile_size(tile_size); } - void SetupTrees(scoped_refptr<PicturePileImpl> pending_pile, - scoped_refptr<PicturePileImpl> active_pile) { - SetupPendingTree(active_pile); + void SetupTrees(scoped_refptr<RasterSource> pending_raster_source, + scoped_refptr<RasterSource> active_raster_source) { + SetupPendingTree(active_raster_source); ActivateTree(); - SetupPendingTree(pending_pile); + SetupPendingTree(pending_raster_source); } - void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) { + void SetupPendingTree(scoped_refptr<RasterSource> raster_source) { host_impl_.CreatePendingTree(); LayerTreeImpl* pending_tree = host_impl_.pending_tree(); // Clear recycled tree. pending_tree->DetachLayerTree(); scoped_ptr<FakePictureLayerImpl> pending_layer = - FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, pile); + FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, + raster_source); pending_layer->SetDrawsContent(true); pending_layer->SetHasRenderSurface(true); pending_tree->SetRootLayer(pending_layer.Pass()); @@ -346,12 +350,12 @@ class TileManagerPerfTest : public testing::Test { int next_id = id_ + 1; // Create the rest of the layers as children of the root layer. - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPile(kDefaultTileSize, layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); while (static_cast<int>(layers.size()) < layer_count) { scoped_ptr<FakePictureLayerImpl> layer = FakePictureLayerImpl::CreateWithRasterSource( - host_impl_.pending_tree(), next_id, pile); + host_impl_.pending_tree(), next_id, raster_source); layer->SetBounds(layer_bounds); layer->SetDrawsContent(true); layers.push_back(layer.get()); @@ -414,17 +418,14 @@ class TileManagerPerfTest : public testing::Test { int max_tiles_; int id_; FakeImplProxy proxy_; + scoped_ptr<OutputSurface> output_surface_; FakeLayerTreeHostImpl host_impl_; FakePictureLayerImpl* pending_root_layer_; FakePictureLayerImpl* active_root_layer_; LapTimer timer_; LayerTreeSettings settings_; - - static const gfx::Size kDefaultTileSize; }; -const gfx::Size TileManagerPerfTest::kDefaultTileSize(100, 100); - TEST_F(TileManagerPerfTest, PrepareTiles) { RunPrepareTilesTest("2_100", 2, 100); RunPrepareTilesTest("2_500", 2, 500); diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc index 4a663cefaf5..e68ea1ff779 100644 --- a/chromium/cc/tiles/tile_manager_unittest.cc +++ b/chromium/cc/tiles/tile_manager_unittest.cc @@ -4,16 +4,21 @@ #include "base/run_loop.h" #include "base/thread_task_runner_handle.h" +#include "cc/playback/display_list_raster_source.h" +#include "cc/playback/display_list_recording_source.h" +#include "cc/raster/raster_buffer.h" #include "cc/resources/resource_pool.h" #include "cc/test/begin_frame_args_test.h" +#include "cc/test/fake_display_list_raster_source.h" +#include "cc/test/fake_display_list_recording_source.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/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_tile_priorities.h" @@ -25,6 +30,7 @@ #include "cc/trees/layer_tree_impl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkSurface.h" namespace cc { namespace { @@ -42,10 +48,12 @@ class TileManagerTilePriorityQueueTest : public testing::Test { ready_to_activate_(false), id_(7), proxy_(base::ThreadTaskRunnerHandle::Get()), + output_surface_(FakeOutputSurface::Create3d()), host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_, - &task_graph_runner_) {} + &task_graph_runner_, + &gpu_memory_buffer_manager_) {} void SetTreePriority(TreePriority tree_priority) { GlobalStateThatImpactsTilePriority state; @@ -60,7 +68,6 @@ class TileManagerTilePriorityQueueTest : public testing::Test { 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); } @@ -71,26 +78,27 @@ class TileManagerTilePriorityQueueTest : public testing::Test { } virtual void InitializeRenderer() { - host_impl_.InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl_.InitializeRenderer(output_surface_.get()); } 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); + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> active_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); - SetupTrees(pending_pile, active_pile); + SetupTrees(pending_raster_source, active_raster_source); } + // This matches picture_layer_impl_unittest's ActivateTree. void ActivateTree() { host_impl_.ActivateSyncTree(); CHECK(!host_impl_.pending_tree()); pending_layer_ = NULL; 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, @@ -100,14 +108,14 @@ class TileManagerTilePriorityQueueTest : public testing::Test { active_layer_->set_fixed_tile_size(tile_size); } - void SetupTrees(scoped_refptr<PicturePileImpl> pending_pile, - scoped_refptr<PicturePileImpl> active_pile) { - SetupPendingTree(active_pile); + void SetupTrees(scoped_refptr<RasterSource> pending_raster_source, + scoped_refptr<RasterSource> active_raster_source) { + SetupPendingTree(active_raster_source); ActivateTree(); - SetupPendingTree(pending_pile); + SetupPendingTree(pending_raster_source); } - void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) { + void SetupPendingTree(scoped_refptr<RasterSource> raster_source) { host_impl_.CreatePendingTree(); LayerTreeImpl* pending_tree = host_impl_.pending_tree(); @@ -119,14 +127,14 @@ class TileManagerTilePriorityQueueTest : public testing::Test { if (old_pending_root) { pending_layer.reset( static_cast<FakePictureLayerImpl*>(old_pending_root.release())); - pending_layer->SetRasterSourceOnPending(pile, Region()); + pending_layer->SetRasterSourceOnPending(raster_source, Region()); } else { - pending_layer = - FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, pile); + pending_layer = FakePictureLayerImpl::CreateWithRasterSource( + pending_tree, id_, raster_source); pending_layer->SetDrawsContent(true); pending_layer->SetHasRenderSurface(true); } - // The bounds() just mirror the pile size. + // The bounds() just mirror the raster source size. pending_layer->SetBounds(pending_layer->raster_source()->GetSize()); pending_tree->SetRootLayer(pending_layer.Pass()); @@ -145,11 +153,13 @@ class TileManagerTilePriorityQueueTest : public testing::Test { TestSharedBitmapManager shared_bitmap_manager_; TestTaskGraphRunner task_graph_runner_; + TestGpuMemoryBufferManager gpu_memory_buffer_manager_; TileMemoryLimitPolicy memory_limit_policy_; int max_tiles_; bool ready_to_activate_; int id_; FakeImplProxy proxy_; + scoped_ptr<OutputSurface> output_surface_; FakeLayerTreeHostImpl host_impl_; FakePictureLayerImpl* pending_layer_; FakePictureLayerImpl* active_layer_; @@ -225,14 +235,11 @@ TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueue) { // 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, @@ -248,11 +255,6 @@ TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueue) { 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) { @@ -501,8 +503,6 @@ TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueInvalidation) { 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. @@ -602,12 +602,11 @@ TEST_F(TileManagerTilePriorityQueueTest, ActivationComesBeforeEventually) { 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_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); scoped_ptr<FakePictureLayerImpl> pending_child = - FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), - id_ + 1, pending_pile); + FakePictureLayerImpl::CreateWithRasterSource( + host_impl_.pending_tree(), id_ + 1, pending_raster_source); FakePictureLayerImpl* pending_child_raw = pending_child.get(); pending_child_raw->SetDrawsContent(true); pending_layer_->AddChild(pending_child.Pass()); @@ -646,6 +645,10 @@ TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) { const gfx::Size layer_bounds(1000, 1000); host_impl_.SetViewportSize(layer_bounds); SetupDefaultTrees(layer_bounds); + ASSERT_TRUE(active_layer_->HighResTiling()); + ASSERT_TRUE(active_layer_->LowResTiling()); + ASSERT_TRUE(pending_layer_->HighResTiling()); + EXPECT_FALSE(pending_layer_->LowResTiling()); scoped_ptr<EvictionTilePriorityQueue> empty_queue( host_impl_.BuildEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES)); @@ -693,15 +696,12 @@ TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) { pending_layer_->set_invalidation(invalidation); pending_layer_->HighResTiling()->Invalidate(invalidation); pending_layer_->HighResTiling()->CreateMissingTilesInLiveTilesRect(); - pending_layer_->LowResTiling()->Invalidate(invalidation); - pending_layer_->LowResTiling()->CreateMissingTilesInLiveTilesRect(); + EXPECT_FALSE(pending_layer_->LowResTiling()); // 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, @@ -714,11 +714,6 @@ TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) { 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) @@ -772,7 +767,7 @@ TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) { // Ensure that the distance is decreasing many more times than increasing. EXPECT_EQ(3, distance_increasing); - EXPECT_EQ(17, distance_decreasing); + EXPECT_EQ(16, distance_decreasing); EXPECT_EQ(tile_count, smoothness_tiles.size()); EXPECT_EQ(all_tiles, smoothness_tiles); @@ -813,7 +808,7 @@ TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) { // Ensure that the distance is decreasing many more times than increasing. EXPECT_EQ(3, distance_increasing); - EXPECT_EQ(17, distance_decreasing); + EXPECT_EQ(16, distance_decreasing); EXPECT_EQ(tile_count, new_content_tiles.size()); EXPECT_EQ(all_tiles, new_content_tiles); } @@ -822,18 +817,17 @@ TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueueWithOcclusion) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - 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_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(pending_raster_source); scoped_ptr<FakePictureLayerImpl> pending_child = FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 2, - pending_pile); + pending_raster_source); pending_layer_->AddChild(pending_child.Pass()); FakePictureLayerImpl* pending_child_layer = @@ -845,7 +839,7 @@ TEST_F(TileManagerTilePriorityQueueTest, host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text); ActivateTree(); - SetupPendingTree(pending_pile); + SetupPendingTree(pending_raster_source); FakePictureLayerImpl* active_child_layer = static_cast<FakePictureLayerImpl*>(active_layer_->children()[0]); @@ -867,12 +861,8 @@ TEST_F(TileManagerTilePriorityQueueTest, 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()); @@ -890,24 +880,12 @@ TEST_F(TileManagerTilePriorityQueueTest, 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())); @@ -947,8 +925,7 @@ TEST_F(TileManagerTilePriorityQueueTest, last_tile = prioritized_tile; queue->Pop(); } - size_t expected_occluded_count = - pending_child_high_res_tiles.size() + pending_child_low_res_tiles.size(); + size_t expected_occluded_count = pending_child_high_res_tiles.size(); EXPECT_EQ(expected_occluded_count, occluded_count); } @@ -956,16 +933,15 @@ TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueueWithTransparentLayer) { host_impl_.AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1)); - 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_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + SetupPendingTree(pending_raster_source); scoped_ptr<FakePictureLayerImpl> pending_child = FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 2, - pending_pile); + pending_raster_source); FakePictureLayerImpl* pending_child_layer = pending_child.get(); pending_layer_->AddChild(pending_child.Pass()); @@ -986,12 +962,8 @@ TEST_F(TileManagerTilePriorityQueueTest, 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; @@ -1001,12 +973,6 @@ TEST_F(TileManagerTilePriorityQueueTest, 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(); @@ -1014,12 +980,6 @@ TEST_F(TileManagerTilePriorityQueueTest, 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()); @@ -1161,16 +1121,15 @@ TEST_F(TileManagerTilePriorityQueueTest, client.SetTileSize(gfx::Size(30, 30)); LayerTreeSettings settings; - settings.max_tiles_for_interest_area = 10000; scoped_ptr<PictureLayerTilingSet> tiling_set = PictureLayerTilingSet::Create( - ACTIVE_TREE, &client, settings.max_tiles_for_interest_area, + ACTIVE_TREE, &client, settings.tiling_interest_area_padding, 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); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + PictureLayerTiling* tiling = tiling_set->AddTiling(1.0f, raster_source); tiling->set_resolution(HIGH_RESOLUTION); tiling_set->UpdateTilePriorities(viewport, 1.0f, 1.0, Occlusion(), true); @@ -1271,16 +1230,15 @@ TEST_F(TileManagerTilePriorityQueueTest, client.SetTileSize(gfx::Size(30, 30)); LayerTreeSettings settings; - settings.max_tiles_for_interest_area = 10000; scoped_ptr<PictureLayerTilingSet> tiling_set = PictureLayerTilingSet::Create( - ACTIVE_TREE, &client, settings.max_tiles_for_interest_area, + ACTIVE_TREE, &client, settings.tiling_interest_area_padding, 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); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); + PictureLayerTiling* tiling = tiling_set->AddTiling(1.0f, raster_source); tiling->set_resolution(HIGH_RESOLUTION); tiling_set->UpdateTilePriorities(viewport, 1.0f, 1.0, Occlusion(), true); @@ -1388,22 +1346,21 @@ TEST_F(TileManagerTilePriorityQueueTest, EXPECT_EQ(RGBA_8888, host_impl_.resource_provider()->best_texture_format()); ManagedMemoryPolicy policy = host_impl_.ActualManagedMemoryPolicy(); - policy.bytes_limit_when_visible = - Resource::UncheckedMemorySizeBytes(gfx::Size(256, 256), RGBA_8888); + policy.bytes_limit_when_visible = ResourceUtil::UncheckedSizeInBytes<size_t>( + 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); + Resource* 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(), 0); + host_impl_.resource_pool()->ReleaseResource(resource, 0); } TEST_F(TileManagerTilePriorityQueueTest, RasterQueueAllUsesCorrectTileBounds) { @@ -1411,20 +1368,20 @@ TEST_F(TileManagerTilePriorityQueueTest, RasterQueueAllUsesCorrectTileBounds) { // tile iteration. gfx::Size layer_bounds(1, 1); - scoped_refptr<FakePicturePileImpl> pile = - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds); + scoped_refptr<FakeDisplayListRasterSource> raster_source = + FakeDisplayListRasterSource::CreateFilled(layer_bounds); FakePictureLayerTilingClient pending_client; pending_client.SetTileSize(gfx::Size(64, 64)); - auto tiling_set = PictureLayerTilingSet::Create( + scoped_ptr<PictureLayerTilingSet> tiling_set = PictureLayerTilingSet::Create( WhichTree::ACTIVE_TREE, &pending_client, 1.0f, 1.0f, 1000); pending_client.set_twin_tiling_set(tiling_set.get()); - auto tiling = tiling_set->AddTiling(1.0f, pile); + auto* tiling = tiling_set->AddTiling(1.0f, raster_source); - tiling->CreateAllTilesForTesting(); tiling->set_resolution(HIGH_RESOLUTION); + tiling->CreateAllTilesForTesting(); // The tile is (0, 0, 1, 1), create an intersecting and non-intersecting // rectangle to test the advance phase with. The tile size is (64, 64), so @@ -1467,7 +1424,13 @@ TEST_F(TileManagerTilePriorityQueueTest, RasterQueueAllUsesCorrectTileBounds) { class TileManagerTest : public testing::Test { public: TileManagerTest() - : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {} + : output_surface_(FakeOutputSurface::CreateSoftware( + make_scoped_ptr(new SoftwareOutputDevice))), + host_impl_(new MockLayerTreeHostImpl(&proxy_, + &shared_bitmap_manager_, + &task_graph_runner_)) { + host_impl_->InitializeRenderer(output_surface_.get()); + } protected: // MockLayerTreeHostImpl allows us to intercept tile manager callbacks. @@ -1476,9 +1439,7 @@ class TileManagerTest : public testing::Test { MockLayerTreeHostImpl(Proxy* proxy, SharedBitmapManager* manager, TaskGraphRunner* task_graph_runner) - : FakeLayerTreeHostImpl(proxy, manager, task_graph_runner) { - InitializeRenderer(FakeOutputSurface::Create3d()); - } + : FakeLayerTreeHostImpl(proxy, manager, task_graph_runner) {} MOCK_METHOD0(NotifyAllTileTasksCompleted, void()); }; @@ -1486,7 +1447,8 @@ class TileManagerTest : public testing::Test { TestSharedBitmapManager shared_bitmap_manager_; TestTaskGraphRunner task_graph_runner_; FakeImplProxy proxy_; - MockLayerTreeHostImpl host_impl_; + scoped_ptr<OutputSurface> output_surface_; + scoped_ptr<MockLayerTreeHostImpl> host_impl_; }; // Test to ensure that we call NotifyAllTileTasksCompleted when PrepareTiles is @@ -1495,11 +1457,11 @@ TEST_F(TileManagerTest, AllWorkFinishedTest) { // Check with no tile work enqueued. { base::RunLoop run_loop; - EXPECT_FALSE(host_impl_.tile_manager()->HasScheduledTileTasksForTesting()); - EXPECT_CALL(host_impl_, NotifyAllTileTasksCompleted()) + EXPECT_FALSE(host_impl_->tile_manager()->HasScheduledTileTasksForTesting()); + EXPECT_CALL(*host_impl_, NotifyAllTileTasksCompleted()) .WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); })); - host_impl_.tile_manager()->PrepareTiles(host_impl_.global_tile_state()); - EXPECT_TRUE(host_impl_.tile_manager()->HasScheduledTileTasksForTesting()); + host_impl_->tile_manager()->PrepareTiles(host_impl_->global_tile_state()); + EXPECT_TRUE(host_impl_->tile_manager()->HasScheduledTileTasksForTesting()); run_loop.Run(); } @@ -1507,15 +1469,189 @@ TEST_F(TileManagerTest, AllWorkFinishedTest) { // callback. { base::RunLoop run_loop; - EXPECT_FALSE(host_impl_.tile_manager()->HasScheduledTileTasksForTesting()); - EXPECT_CALL(host_impl_, NotifyAllTileTasksCompleted()) + EXPECT_FALSE(host_impl_->tile_manager()->HasScheduledTileTasksForTesting()); + EXPECT_CALL(*host_impl_, NotifyAllTileTasksCompleted()) + .WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); })); + host_impl_->tile_manager()->PrepareTiles(host_impl_->global_tile_state()); + host_impl_->tile_manager()->SetMoreTilesNeedToBeRasterizedForTesting(); + EXPECT_TRUE(host_impl_->tile_manager()->HasScheduledTileTasksForTesting()); + run_loop.Run(); + } +} + +TEST_F(TileManagerTest, LowResHasNoImage) { + gfx::Size size(10, 12); + TileResolution resolutions[] = {HIGH_RESOLUTION, LOW_RESOLUTION}; + + for (size_t i = 0; i < arraysize(resolutions); ++i) { + SCOPED_TRACE(resolutions[i]); + + // Make a RasterSource that will draw a blue bitmap image. + skia::RefPtr<SkSurface> surface = skia::AdoptRef( + SkSurface::NewRasterN32Premul(size.width(), size.height())); + ASSERT_NE(surface, nullptr); + surface->getCanvas()->clear(SK_ColorBLUE); + skia::RefPtr<SkImage> blue_image = + skia::AdoptRef(surface->newImageSnapshot()); + + scoped_ptr<FakeDisplayListRecordingSource> recording_source = + FakeDisplayListRecordingSource::CreateFilledRecordingSource(size); + recording_source->SetBackgroundColor(SK_ColorTRANSPARENT); + recording_source->SetRequiresClear(true); + recording_source->SetClearCanvasWithDebugColor(false); + SkPaint paint; + paint.setColor(SK_ColorGREEN); + recording_source->add_draw_rect_with_paint(gfx::Rect(size), paint); + recording_source->add_draw_image(blue_image.get(), gfx::Point()); + recording_source->Rerecord(); + scoped_refptr<DisplayListRasterSource> raster = + DisplayListRasterSource::CreateFromDisplayListRecordingSource( + recording_source.get(), false); + + FakePictureLayerTilingClient tiling_client; + tiling_client.SetTileSize(size); + + scoped_ptr<PictureLayerImpl> layer = + PictureLayerImpl::Create(host_impl_->active_tree(), 1, false, nullptr); + PictureLayerTilingSet* tiling_set = layer->picture_layer_tiling_set(); + + auto* tiling = tiling_set->AddTiling(1.0f, raster); + tiling->set_resolution(resolutions[i]); + tiling->CreateAllTilesForTesting(); + tiling->SetTilePriorityRectsForTesting( + gfx::Rect(size), // Visible rect. + gfx::Rect(size), // Skewport rect. + gfx::Rect(size), // Soon rect. + gfx::Rect(size)); // Eventually rect. + + // SMOOTHNESS_TAKES_PRIORITY ensures that we will actually raster + // LOW_RESOLUTION tiles, otherwise they are skipped. + host_impl_->SetTreePriority(SMOOTHNESS_TAKES_PRIORITY); + + // Call PrepareTiles and wait for it to complete. + auto* tile_manager = host_impl_->tile_manager(); + base::RunLoop run_loop; + EXPECT_CALL(*host_impl_, NotifyAllTileTasksCompleted()) .WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); })); - host_impl_.tile_manager()->PrepareTiles(host_impl_.global_tile_state()); - host_impl_.tile_manager()->SetMoreTilesNeedToBeRasterizedForTesting(); - EXPECT_TRUE(host_impl_.tile_manager()->HasScheduledTileTasksForTesting()); + tile_manager->PrepareTiles(host_impl_->global_tile_state()); run_loop.Run(); + tile_manager->Flush(); + + Tile* tile = tiling->TileAt(0, 0); + // The tile in the tiling was rastered. + EXPECT_EQ(TileDrawInfo::RESOURCE_MODE, tile->draw_info().mode()); + EXPECT_TRUE(tile->draw_info().IsReadyToDraw()); + + ResourceProvider::ScopedReadLockSoftware lock( + host_impl_->resource_provider(), tile->draw_info().resource_id()); + const SkBitmap* bitmap = lock.sk_bitmap(); + for (int x = 0; x < size.width(); ++x) { + for (int y = 0; y < size.height(); ++y) { + SCOPED_TRACE(y); + SCOPED_TRACE(x); + if (resolutions[i] == LOW_RESOLUTION) { + // Since it's low res, the bitmap was not drawn, and the background + // (green) is visible instead. + ASSERT_EQ(SK_ColorGREEN, bitmap->getColor(x, y)); + } else { + EXPECT_EQ(HIGH_RESOLUTION, resolutions[i]); + // Since it's high res, the bitmap (blue) was drawn, and the + // background is not visible. + ASSERT_EQ(SK_ColorBLUE, bitmap->getColor(x, y)); + } + } + } } } +// Fake TileTaskRunner that just cancels all scheduled tasks immediately. +class CancellingTileTaskRunner : public TileTaskRunner, public TileTaskClient { + public: + CancellingTileTaskRunner() {} + + // TileTaskRunner methods. + void SetClient(TileTaskRunnerClient* client) override {} + void Shutdown() override {} + void CheckForCompletedTasks() override {} + ResourceFormat GetResourceFormat(bool must_support_alpha) const override { + return ResourceFormat::RGBA_8888; + } + bool GetResourceRequiresSwizzle(bool must_support_alpha) const override { + return false; + } + + void ScheduleTasks(TileTaskQueue* queue) override { + // Just call CompleteOnOriginThread on each item in the queue. As none of + // these items have run yet, they will be treated as cancelled tasks. + for (const auto& task : queue->items) { + task.task->CompleteOnOriginThread(this); + } + } + + // TileTaskClient methods. + scoped_ptr<RasterBuffer> AcquireBufferForRaster( + const Resource* resource, + uint64_t resource_content_id, + uint64_t previous_content_id) override { + NOTREACHED(); + return nullptr; + } + void ReleaseBufferForRaster(scoped_ptr<RasterBuffer> buffer) override {} + + ~CancellingTileTaskRunner() override {} +}; + +// Ensures that if a raster task is cancelled, it gets returned to the resource +// pool with an invalid content ID, not with its invalidated content ID. +TEST_F(TileManagerTest, CancelledTasksHaveNoContentId) { + // Create a CancellingTaskRunner and set it on the tile manager so that all + // scheduled work is immediately cancelled. + CancellingTileTaskRunner cancelling_runner; + host_impl_->tile_manager()->SetTileTaskRunnerForTesting(&cancelling_runner); + + // Pick arbitrary IDs - they don't really matter as long as they're constant. + int layer_id = 7; + int invalidated_id = 43; + + scoped_refptr<FakeDisplayListRasterSource> pending_raster_source = + FakeDisplayListRasterSource::CreateFilled(gfx::Size(128, 128)); + host_impl_->CreatePendingTree(); + LayerTreeImpl* pending_tree = host_impl_->pending_tree(); + + // Steal from the recycled tree. + scoped_ptr<FakePictureLayerImpl> pending_layer = + FakePictureLayerImpl::CreateWithRasterSource(pending_tree, layer_id, + pending_raster_source); + pending_layer->SetDrawsContent(true); + pending_layer->SetHasRenderSurface(true); + + // The bounds() just mirror the raster source size. + pending_layer->SetBounds(pending_layer->raster_source()->GetSize()); + pending_tree->SetRootLayer(pending_layer.Pass()); + + // Add tilings/tiles for the layer. + host_impl_->pending_tree()->UpdateDrawProperties(false /* update_lcd_text */); + + // Build the raster queue and invalidate the top tile. + scoped_ptr<RasterTilePriorityQueue> queue(host_impl_->BuildRasterQueue( + SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL)); + EXPECT_FALSE(queue->IsEmpty()); + queue->Top().tile()->SetInvalidated(gfx::Rect(), invalidated_id); + + // PrepareTiles to schedule tasks. Due to the CancellingTileTaskRunner, these + // tasks will immediately be canceled. + host_impl_->tile_manager()->PrepareTiles(host_impl_->global_tile_state()); + + // Make sure that the tile we invalidated above was not returned to the pool + // with its invalidated resource ID. + host_impl_->resource_pool()->CheckBusyResources(); + EXPECT_FALSE(host_impl_->resource_pool()->TryAcquireResourceWithContentId( + invalidated_id)); + + // Free our host_impl_ before the cancelling_runner we passed it, as it will + // use that class in clean up. + host_impl_ = nullptr; +} + } // namespace } // namespace cc diff --git a/chromium/cc/trees/channel_impl.h b/chromium/cc/trees/channel_impl.h new file mode 100644 index 00000000000..dcaf41687af --- /dev/null +++ b/chromium/cc/trees/channel_impl.h @@ -0,0 +1,27 @@ +// 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_TREES_CHANNEL_IMPL_H_ +#define CC_TREES_CHANNEL_IMPL_H_ + +#include "cc/base/cc_export.h" + +namespace cc { + +// Channel used to send commands to and receive commands from ProxyMain. +// The ChannelImpl implementation creates and owns ProxyImpl on receiving the +// InitializeImpl call from ChannelMain. +// See channel_main.h +class CC_EXPORT ChannelImpl { + public: + // Interface for commands sent to ProxyMain + virtual void DidCompleteSwapBuffers() = 0; + + protected: + virtual ~ChannelImpl() {} +}; + +} // namespace cc + +#endif // CC_TREES_CHANNEL_IMPL_H_ diff --git a/chromium/cc/trees/channel_main.h b/chromium/cc/trees/channel_main.h new file mode 100644 index 00000000000..964d1aa5db9 --- /dev/null +++ b/chromium/cc/trees/channel_main.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_TREES_CHANNEL_MAIN_H_ +#define CC_TREES_CHANNEL_MAIN_H_ + +#include "cc/base/cc_export.h" + +namespace cc { + +// ChannelMain and ChannelImpl provide an abstract communication layer for +// the main and impl side of the compositor. +// +// The communication sequence between the 2 sides is: +// +// LayerTreeHost<-->ProxyMain<-->ChannelMain +// | +// | +// ChannelImpl<-->ProxyImpl<-->LayerTreeHostImpl + +class CC_EXPORT ChannelMain { + public: + // Interface for commands sent to the ProxyImpl + virtual void SetThrottleFrameProductionOnImpl(bool throttle) = 0; + virtual void SetLayerTreeHostClientReadyOnImpl() = 0; + + virtual ~ChannelMain() {} +}; + +} // namespace cc + +#endif // CC_TREES_CHANNEL_MAIN_H_ diff --git a/chromium/cc/trees/damage_tracker.cc b/chromium/cc/trees/damage_tracker.cc index de11b47c1a9..65d3fd32172 100644 --- a/chromium/cc/trees/damage_tracker.cc +++ b/chromium/cc/trees/damage_tracker.cc @@ -142,13 +142,7 @@ void DamageTracker::UpdateDamageTrackingState( damage_rect_for_this_update.Union(damage_from_surface_mask); damage_rect_for_this_update.Union(damage_from_leftover_rects); - if (filters.HasReferenceFilter()) { - // TODO(senorblanco): Once SkImageFilter reports its outsets, use - // those here to limit damage. - damage_rect_for_this_update = target_surface_content_rect; - } else if (filters.HasFilterThatMovesPixels()) { - ExpandRectWithFilters(&damage_rect_for_this_update, filters); - } + ExpandRectWithFilters(&damage_rect_for_this_update, filters); } // Damage accumulates until we are notified that we actually did draw on that @@ -286,10 +280,6 @@ void DamageTracker::ExtendDamageForLayer(LayerImpl* layer, gfx::Rect rect_in_target_space = layer->GetEnclosingRectInTargetSpace(); data.Update(rect_in_target_space, mailboxId_); - gfx::RectF damage_rect = - gfx::UnionRects(layer->update_rect(), layer->damage_rect()); - damage_rect.Intersect(gfx::RectF(layer->bounds())); - if (layer_is_new || layer->LayerPropertyChanged()) { // If a layer is new or has changed, then its entire layer rect affects the // target surface. @@ -298,11 +288,17 @@ void DamageTracker::ExtendDamageForLayer(LayerImpl* layer, // The layer's old region is now exposed on the target surface, too. // Note old_rect_in_target_space is already in target space. target_damage_rect->Union(old_rect_in_target_space); - } else if (!damage_rect.IsEmpty()) { - // If the layer properties haven't changed, then the the target surface is - // only affected by the layer's damaged area, which could be empty. - gfx::Rect damage_rect_in_target_space = gfx::ToEnclosingRect( - MathUtil::MapClippedRect(layer->draw_transform(), damage_rect)); + return; + } + + // If the layer properties haven't changed, then the the target surface is + // only affected by the layer's damaged area, which could be empty. + gfx::Rect damage_rect = + gfx::UnionRects(layer->update_rect(), layer->damage_rect()); + damage_rect.Intersect(gfx::Rect(layer->bounds())); + if (!damage_rect.IsEmpty()) { + gfx::Rect damage_rect_in_target_space = + MathUtil::MapEnclosingClippedRect(layer->draw_transform(), damage_rect); target_damage_rect->Union(damage_rect_in_target_space); } } diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc index 831b1f718ec..9935e8603fd 100644 --- a/chromium/cc/trees/damage_tracker_unittest.cc +++ b/chromium/cc/trees/damage_tracker_unittest.cc @@ -266,7 +266,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) { // CASE 1: Adding the layer damage rect should cause the corresponding damage // to the surface. ClearDamageForAllSurfaces(root.get()); - child->AddDamageRect(gfx::RectF(10.f, 11.f, 12.f, 13.f)); + child->AddDamageRect(gfx::Rect(10, 11, 12, 13)); EmulateDrawingOneFrame(root.get()); // Damage position on the surface should be: position of layer damage_rect @@ -278,7 +278,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) { // CASE 2: The same layer damage rect twice in a row still produces the same // damage. ClearDamageForAllSurfaces(root.get()); - child->AddDamageRect(gfx::RectF(10.f, 11.f, 12.f, 13.f)); + child->AddDamageRect(gfx::Rect(10, 11, 12, 13)); EmulateDrawingOneFrame(root.get()); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -287,7 +287,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) { // CASE 3: Adding a different layer damage rect should cause damage on the // new damaged region, but no additional exposed old region. ClearDamageForAllSurfaces(root.get()); - child->AddDamageRect(gfx::RectF(20.f, 25.f, 1.f, 2.f)); + child->AddDamageRect(gfx::Rect(20, 25, 1, 2)); EmulateDrawingOneFrame(root.get()); // Damage position on the surface should be: position of layer damage_rect @@ -299,8 +299,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) { // CASE 4: Adding multiple layer damage rects should cause a unified // damage on root damage rect. ClearDamageForAllSurfaces(root.get()); - child->AddDamageRect(gfx::RectF(20.f, 25.f, 1.f, 2.f)); - child->AddDamageRect(gfx::RectF(10.f, 15.f, 3.f, 4.f)); + child->AddDamageRect(gfx::Rect(20, 25, 1, 2)); + child->AddDamageRect(gfx::Rect(10, 15, 3, 4)); EmulateDrawingOneFrame(root.get()); // Damage position on the surface should be: position of layer damage_rect @@ -318,7 +318,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) { // CASE 1: Adding the layer damage rect and update rect should cause the // corresponding damage to the surface. ClearDamageForAllSurfaces(root.get()); - child->AddDamageRect(gfx::RectF(5.f, 6.f, 12.f, 13.f)); + child->AddDamageRect(gfx::Rect(5, 6, 12, 13)); child->SetUpdateRect(gfx::Rect(15, 16, 14, 10)); EmulateDrawingOneFrame(root.get()); @@ -332,7 +332,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) { // CASE 2: The same layer damage rect and update rect twice in a row still // produces the same damage. ClearDamageForAllSurfaces(root.get()); - child->AddDamageRect(gfx::RectF(10.f, 11.f, 12.f, 13.f)); + child->AddDamageRect(gfx::Rect(10, 11, 12, 13)); child->SetUpdateRect(gfx::Rect(10, 11, 14, 15)); EmulateDrawingOneFrame(root.get()); root_damage_rect = @@ -342,7 +342,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) { // CASE 3: Adding a different layer damage rect and update rect should cause // damage on the new damaged region, but no additional exposed old region. ClearDamageForAllSurfaces(root.get()); - child->AddDamageRect(gfx::RectF(20.f, 25.f, 2.f, 3.f)); + child->AddDamageRect(gfx::Rect(20, 25, 2, 3)); child->SetUpdateRect(gfx::Rect(5, 10, 7, 8)); EmulateDrawingOneFrame(root.get()); @@ -535,6 +535,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) { SkBlurImageFilter::Create(SkIntToScalar(2), SkIntToScalar(2))); FilterOperations filters; filters.Append(FilterOperation::CreateReferenceFilter(filter)); + int outset_top, outset_right, outset_bottom, outset_left; + filters.GetOutsets(&outset_top, &outset_right, &outset_bottom, &outset_left); // Setting the filter will damage the whole surface. ClearDamageForAllSurfaces(root.get()); @@ -547,7 +549,11 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) { child->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(gfx::Rect(100, 100, 30, 30).ToString(), root_damage_rect.ToString()); - EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString()); + EXPECT_EQ( + gfx::Rect(-outset_left, -outset_top, 30 + (outset_left + outset_right), + 30 + (outset_top + outset_bottom)) + .ToString(), + child_damage_rect.ToString()); // CASE 1: Setting the update rect should damage the whole surface (for now) ClearDamageForAllSurfaces(root.get()); @@ -558,9 +564,16 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) { root->render_surface()->damage_tracker()->current_damage_rect(); child_damage_rect = child->render_surface()->damage_tracker()->current_damage_rect(); - EXPECT_EQ(gfx::Rect(100, 100, 30, 30).ToString(), + + int expect_width = 1 + outset_left + outset_right; + int expect_height = 1 + outset_top + outset_bottom; + EXPECT_EQ(gfx::Rect(100 - outset_left, 100 - outset_top, expect_width, + expect_height) + .ToString(), root_damage_rect.ToString()); - EXPECT_EQ(gfx::Rect(30.f, 30.f).ToString(), child_damage_rect.ToString()); + EXPECT_EQ(gfx::Rect(-outset_left, -outset_top, expect_width, expect_height) + .ToString(), + child_damage_rect.ToString()); } TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) { diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc index 9f63421ed94..9975fad8b21 100644 --- a/chromium/cc/trees/draw_property_utils.cc +++ b/chromium/cc/trees/draw_property_utils.cc @@ -7,8 +7,10 @@ #include <vector> #include "cc/base/math_util.h" +#include "cc/layers/draw_properties.h" #include "cc/layers/layer.h" #include "cc/layers/layer_impl.h" +#include "cc/layers/render_surface_draw_properties.h" #include "cc/trees/layer_tree_impl.h" #include "cc/trees/property_tree.h" #include "cc/trees/property_tree_builder.h" @@ -33,63 +35,73 @@ void CalculateVisibleRects(const std::vector<LayerType*>& visible_layer_list, 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()); + const TransformNode* target_node = + transform_tree.Node(transform_node->data.content_target_id); + // The clip node stores clip rect in its target space. If required, + // this clip rect should be mapped to the current layer's target space. gfx::Rect clip_rect_in_target_space; - gfx::Transform clip_to_target; + gfx::Rect combined_clip_rect_in_target_space; bool success = true; - if (clip_transform_node->data.target_id == target_node->id) { - clip_to_target = clip_transform_node->data.to_target; - } else { + if (clip_node->data.target_id != target_node->id) { + gfx::Transform clip_to_target; success = transform_tree.ComputeTransformWithDestinationSublayerScale( - clip_transform_node->id, target_node->id, &clip_to_target); - } - - if (target_node->id > clip_node->data.transform_id) { + clip_node->data.target_id, target_node->id, &clip_to_target); 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)); + layer->set_clip_rect_in_target_space_from_property_trees(gfx::Rect()); continue; } - + DCHECK_LT(clip_node->data.target_id, target_node->id); + combined_clip_rect_in_target_space = + gfx::ToEnclosingRect(MathUtil::ProjectClippedRect( + clip_to_target, clip_node->data.combined_clip_in_target_space)); clip_rect_in_target_space = gfx::ToEnclosingRect(MathUtil::ProjectClippedRect( - clip_to_target, clip_node->data.combined_clip)); + clip_to_target, clip_node->data.clip_in_target_space)); } 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::ToEnclosingRect(clip_node->data.clip_in_target_space); + combined_clip_rect_in_target_space = + gfx::ToEnclosingRect(clip_node->data.combined_clip_in_target_space); } + if (!clip_rect_in_target_space.IsEmpty()) { + layer->set_clip_rect_in_target_space_from_property_trees( + clip_rect_in_target_space); + } else { + layer->set_clip_rect_in_target_space_from_property_trees(gfx::Rect()); + } + + // The clip rect should be intersected with layer rect in target space. + 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 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()) { + combined_clip_rect_in_target_space.Intersect( + layer_content_bounds_in_target_space); + if (combined_clip_rect_in_target_space.IsEmpty()) { layer->set_visible_rect_from_property_trees(gfx::Rect()); continue; } + // If the layer is fully contained within the clip, treat it as fully + // visible. Since clip_rect_in_target_space has already been intersected + // with layer_content_bounds_in_target_space, the layer is fully contained + // within the clip iff these rects are equal. + if (combined_clip_rect_in_target_space == + layer_content_bounds_in_target_space) { + layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds)); + continue; + } + gfx::Transform target_to_content; gfx::Transform target_to_layer; @@ -102,8 +114,6 @@ void CalculateVisibleRects(const std::vector<LayerType*>& visible_layer_list, } 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. @@ -116,13 +126,15 @@ void CalculateVisibleRects(const std::vector<LayerType*>& visible_layer_list, target_to_content.PreconcatTransform(target_to_layer); gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect( - target_to_content, clip_rect_in_target_space); + target_to_content, combined_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)); + layer->set_clip_rect_in_target_space_from_property_trees( + gfx::Rect(layer_bounds)); } } } @@ -137,7 +149,8 @@ static bool IsRootLayerOfNewRenderingContext(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> @@ -170,6 +183,28 @@ static bool IsLayerBackFaceVisible(LayerType* layer, } template <typename LayerType> +static bool IsSurfaceBackFaceVisible(LayerType* layer, + const TransformTree& tree) { + if (LayerIsInExisting3DRenderingContext(layer)) { + const TransformNode* node = tree.Node(layer->transform_tree_index()); + // Draw transform as a contributing render surface. + // TODO(enne): we shouldn't walk the tree during a tree walk. + gfx::Transform surface_draw_transform; + tree.ComputeTransform(node->id, node->data.target_id, + &surface_draw_transform); + return surface_draw_transform.IsBackFaceVisible(); + } + + if (IsRootLayerOfNewRenderingContext(layer)) + return layer->transform().IsBackFaceVisible(); + + // If the render_surface is not part of a new or existing rendering context, + // then the layers that contribute to this surface will decide back-face + // visibility for themselves. + return false; +} + +template <typename LayerType> static bool IsAnimatingTransformToScreen(LayerType* layer, const TransformTree& tree) { const TransformNode* node = tree.Node(layer->transform_tree_index()); @@ -188,11 +223,13 @@ static inline bool TransformToScreenIsKnown(LayerImpl* layer, template <typename LayerType> static bool HasInvertibleOrAnimatedTransform(LayerType* layer) { - return layer->transform_is_invertible() || layer->TransformIsAnimating(); + return layer->transform_is_invertible() || + layer->HasPotentiallyRunningTransformAnimation(); } static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, - bool layer_is_drawn) { + bool layer_is_drawn, + const TransformTree& tree) { // 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 @@ -202,22 +239,36 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, // 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) + if (layer->num_layer_or_descendants_with_copy_request() > 0) 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) + // Though we don't need visible rect for hit testing, we need render surface's + // drawable content rect which depends on layer's drawable content rect which + // in turn depends on layer's clip rect that is computed while computing + // visible rects. + if (layer->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->render_surface() && !layer->double_sided() && + IsSurfaceBackFaceVisible(layer, tree)) + 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()) + if (layer->layer_tree_impl()->IsPendingTree() && + layer->HasPotentiallyRunningOpacityAnimation()) + return false; + + // If layer has a background filter, don't skip the layer, even it the + // opacity is 0. + if (!layer->background_filters().IsEmpty()) return false; // The opacity of a layer always applies to its children (either implicitly @@ -226,32 +277,40 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, return !layer->opacity(); } -static inline bool SubtreeShouldBeSkipped(Layer* layer, bool layer_is_drawn) { +static inline bool SubtreeShouldBeSkipped(Layer* layer, + bool layer_is_drawn, + const TransformTree& tree) { // If the layer transform is not invertible, it should not be drawn. - if (!layer->transform_is_invertible() && !layer->TransformIsAnimating()) + if (!layer->transform_is_invertible() && + !layer->HasPotentiallyRunningTransformAnimation()) 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) + if (layer->num_layer_or_descendants_with_copy_request() > 0) return false; // If the layer is not drawn, then skip it and its subtree. if (!layer_is_drawn) return true; + if (layer->has_render_surface() && !layer->double_sided() && + !layer->HasPotentiallyRunningTransformAnimation() && + IsSurfaceBackFaceVisible(layer, tree)) + return true; + + // If layer has a background filter, don't skip the layer, even it the + // opacity is 0. + if (!layer->background_filters().IsEmpty()) + return false; + // 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() && + return !layer->opacity() && !layer->HasPotentiallyRunningOpacityAnimation() && !layer->OpacityCanAnimateOnImplThread(); } @@ -309,7 +368,7 @@ void FindLayersThatNeedUpdates( layer->HasCopyRequest() || (subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree()); - if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn)) + if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn, tree)) return; if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree)) { @@ -341,19 +400,30 @@ void ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree) { for (int i = 0; i < static_cast<int>(clip_tree->size()); ++i) { ClipNode* clip_node = clip_tree->Node(i); + if (clip_node->id == 0) { + clip_node->data.combined_clip_in_target_space = clip_node->data.clip; + clip_node->data.clip_in_target_space = clip_node->data.clip; + continue; + } + const TransformNode* transform_node = + transform_tree.Node(clip_node->data.transform_id); + // 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; + clip_node->data.clip_in_target_space = MathUtil::MapClippedRect( + transform_node->data.to_target, clip_node->data.clip); + clip_node->data.combined_clip_in_target_space = + clip_node->data.clip_in_target_space; continue; } ClipNode* parent_clip_node = clip_tree->parent(clip_node); + gfx::Transform parent_to_current; 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); + bool success = true; // 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 @@ -362,62 +432,75 @@ void ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree) { // 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 { + // must combine clips. For each clip node, we save the clip rects in its + // target space. So, we need to get the ancestor clip rect in the current + // clip node's target space. + gfx::RectF parent_combined_clip_in_target_space = + parent_clip_node->data.combined_clip_in_target_space; + if (parent_clip_node->data.target_id != clip_node->data.target_id) { 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); + parent_clip_node->data.target_id, clip_node->data.target_id, + &parent_to_current); + if (parent_transform_node->data.sublayer_scale.x() > 0 && + parent_transform_node->data.sublayer_scale.y() > 0) + parent_to_current.Scale( + 1.f / parent_transform_node->data.sublayer_scale.x(), + 1.f / parent_transform_node->data.sublayer_scale.y()); + // 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; + parent_combined_clip_in_target_space = MathUtil::ProjectClippedRect( + parent_to_current, + parent_clip_node->data.combined_clip_in_target_space); } - 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; + if (clip_node->data.use_only_parent_clip) { + clip_node->data.combined_clip_in_target_space = + parent_combined_clip_in_target_space; + if (!clip_node->data.render_surface_is_clipped) { + clip_node->data.clip_in_target_space = + parent_combined_clip_in_target_space; + } else { + // Render Surface applies clip and the owning layer itself applies + // no clip. So, clip_in_target_space is not used and hence we can set + // it to an empty rect. + clip_node->data.clip_in_target_space = gfx::RectF(); + } } 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; + gfx::Transform source_to_target; - // 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); + if (transform_node->data.content_target_id == clip_node->data.target_id) { + source_to_target = transform_node->data.to_target; + } else { + success = transform_tree.ComputeTransformWithDestinationSublayerScale( + transform_node->id, clip_node->data.target_id, &source_to_target); + // source_to_target computation should be successful as target is an + // ancestor of the transform node. + DCHECK(success); + } - gfx::RectF intersected_in_target_space = gfx::IntersectRects( - inherited_clip_in_target_space, clip_in_target_space); + gfx::RectF source_clip_in_target_space = + MathUtil::MapClippedRect(source_to_target, clip_node->data.clip); - clip_node->data.combined_clip = MathUtil::ProjectClippedRect( - target_to_clip, intersected_in_target_space); + if (!clip_node->data.layer_clipping_uses_only_local_clip) { + gfx::RectF parent_clip_in_target_space = MathUtil::ProjectClippedRect( + parent_to_current, parent_clip_node->data.clip_in_target_space); + clip_node->data.clip_in_target_space = gfx::IntersectRects( + parent_clip_in_target_space, source_clip_in_target_space); + } else { + clip_node->data.clip_in_target_space = source_clip_in_target_space; + } - clip_node->data.combined_clip.Intersect(clip_node->data.clip); + if (clip_node->data.layer_visibility_uses_only_local_clip) { + clip_node->data.combined_clip_in_target_space = + source_clip_in_target_space; + } else { + clip_node->data.combined_clip_in_target_space = gfx::IntersectRects( + parent_combined_clip_in_target_space, source_clip_in_target_space); + } + } } clip_tree->set_needs_update(false); } @@ -430,12 +513,12 @@ void ComputeTransforms(TransformTree* transform_tree) { transform_tree->set_needs_update(false); } -void ComputeOpacities(OpacityTree* opacity_tree) { - if (!opacity_tree->needs_update()) +void ComputeOpacities(EffectTree* effect_tree) { + if (!effect_tree->needs_update()) return; - for (int i = 1; i < static_cast<int>(opacity_tree->size()); ++i) - opacity_tree->UpdateOpacities(i); - opacity_tree->set_needs_update(false); + for (int i = 1; i < static_cast<int>(effect_tree->size()); ++i) + effect_tree->UpdateOpacities(i); + effect_tree->set_needs_update(false); } template <typename LayerType> @@ -447,7 +530,7 @@ void ComputeVisibleRectsUsingPropertyTreesInternal( property_trees->clip_tree.set_needs_update(true); ComputeTransforms(&property_trees->transform_tree); ComputeClips(&property_trees->clip_tree, property_trees->transform_tree); - ComputeOpacities(&property_trees->opacity_tree); + ComputeOpacities(&property_trees->effect_tree); const bool subtree_is_visible_from_ancestor = true; std::vector<LayerType*> visible_layer_list; @@ -514,11 +597,10 @@ void ComputeVisibleRectsUsingPropertyTrees(LayerImpl* root_layer, template <typename LayerType> gfx::Transform DrawTransformFromPropertyTreesInternal( const LayerType* layer, - const TransformTree& tree) { - const TransformNode* node = tree.Node(layer->transform_tree_index()); - + const TransformNode* node) { gfx::Transform xform; - const bool owns_non_root_surface = layer->parent() && layer->render_surface(); + const bool owns_non_root_surface = + layer->parent() && layer->has_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. @@ -536,51 +618,100 @@ gfx::Transform DrawTransformFromPropertyTreesInternal( gfx::Transform DrawTransformFromPropertyTrees(const Layer* layer, const TransformTree& tree) { - return DrawTransformFromPropertyTreesInternal(layer, tree); + return DrawTransformFromPropertyTreesInternal( + layer, tree.Node(layer->transform_tree_index())); } gfx::Transform DrawTransformFromPropertyTrees(const LayerImpl* layer, const TransformTree& tree) { - return DrawTransformFromPropertyTreesInternal(layer, tree); + return DrawTransformFromPropertyTreesInternal( + layer, tree.Node(layer->transform_tree_index())); +} + +gfx::Transform SurfaceDrawTransform(const RenderSurfaceImpl* render_surface, + const TransformTree& tree) { + const TransformNode* node = tree.Node(render_surface->TransformTreeIndex()); + gfx::Transform render_surface_transform; + // The draw transform of root render surface is identity tranform. + if (node->id == 1) + return render_surface_transform; + const TransformNode* target_node = tree.Node(node->data.target_id); + tree.ComputeTransformWithDestinationSublayerScale(node->id, target_node->id, + &render_surface_transform); + if (node->data.sublayer_scale.x() != 0.0 && + node->data.sublayer_scale.y() != 0.0) + render_surface_transform.Scale(1.0 / node->data.sublayer_scale.x(), + 1.0 / node->data.sublayer_scale.y()); + return render_surface_transform; +} + +bool SurfaceIsClipped(const RenderSurfaceImpl* render_surface, + const ClipNode* clip_node) { + // If the render surface's owning layer doesn't form a clip node, it is not + // clipped. + if (render_surface->OwningLayerId() != clip_node->owner_id) + return false; + return clip_node->data.render_surface_is_clipped; +} + +gfx::Rect SurfaceClipRect(const RenderSurfaceImpl* render_surface, + const ClipNode* parent_clip_node, + bool is_clipped) { + if (!is_clipped) + return gfx::Rect(); + return gfx::ToEnclosingRect(parent_clip_node->data.clip_in_target_space); +} + +gfx::Transform SurfaceScreenSpaceTransform( + const RenderSurfaceImpl* render_surface, + const TransformTree& tree) { + const TransformNode* node = tree.Node(render_surface->TransformTreeIndex()); + gfx::Transform screen_space_transform; + // The screen space transform of root render surface is identity tranform. + if (node->id == 1) + return screen_space_transform; + screen_space_transform = node->data.to_screen; + if (node->data.sublayer_scale.x() != 0.0 && + node->data.sublayer_scale.y() != 0.0) + screen_space_transform.Scale(1.0 / node->data.sublayer_scale.x(), + 1.0 / node->data.sublayer_scale.y()); + return screen_space_transform; } template <typename LayerType> gfx::Transform ScreenSpaceTransformFromPropertyTreesInternal( LayerType* layer, - const TransformTree& tree) { + const TransformNode* node) { 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(); - } + gfx::Transform ssxform = node->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); + return ScreenSpaceTransformFromPropertyTreesInternal( + layer, tree.Node(layer->transform_tree_index())); } gfx::Transform ScreenSpaceTransformFromPropertyTrees( const LayerImpl* layer, const TransformTree& tree) { - return ScreenSpaceTransformFromPropertyTreesInternal(layer, tree); + return ScreenSpaceTransformFromPropertyTreesInternal( + layer, tree.Node(layer->transform_tree_index())); } -template <typename LayerType> -float DrawOpacityFromPropertyTreesInternal(LayerType layer, - const OpacityTree& tree) { +float LayerDrawOpacity(const LayerImpl* layer, const EffectTree& 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()); + const EffectNode* target_node = + tree.Node(layer->render_target()->effect_tree_index()); + const EffectNode* node = tree.Node(layer->effect_tree_index()); if (node == target_node) return 1.f; @@ -592,35 +723,35 @@ float DrawOpacityFromPropertyTreesInternal(LayerType layer, 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); +float SurfaceDrawOpacity(RenderSurfaceImpl* render_surface, + const EffectTree& tree) { + const EffectNode* node = tree.Node(render_surface->EffectTreeIndex()); + float target_opacity_tree_index = render_surface->TargetEffectTreeIndex(); + if (target_opacity_tree_index < 0) + return node->data.screen_space_opacity; + const EffectNode* target_node = tree.Node(target_opacity_tree_index); + float draw_opacity = 1.f; + while (node != target_node) { + draw_opacity *= node->data.opacity; + node = tree.parent(node); + } + return draw_opacity; } -bool CanUseLcdTextFromPropertyTrees(const LayerImpl* layer, - bool layers_always_allowed_lcd_text, - bool can_use_lcd_text, - PropertyTrees* property_trees) { +bool LayerCanUseLcdText(const LayerImpl* layer, + bool layers_always_allowed_lcd_text, + bool can_use_lcd_text, + const TransformNode* transform_node, + const EffectNode* effect_node) { if (layers_always_allowed_lcd_text) return true; if (!can_use_lcd_text) return false; if (!layer->contents_opaque()) return false; - DCHECK(!property_trees->transform_tree.needs_update()); - DCHECK(!property_trees->opacity_tree.needs_update()); - const OpacityNode* opacity_node = - property_trees->opacity_tree.Node(layer->opacity_tree_index()); - if (opacity_node->data.screen_space_opacity != 1.f) + if (effect_node->data.screen_space_opacity != 1.f) return false; - const TransformNode* transform_node = - property_trees->transform_tree.Node(layer->transform_tree_index()); if (!transform_node->data.node_and_ancestors_have_only_integer_translation) return false; if (static_cast<int>(layer->offset_to_transform_parent().x()) != @@ -632,4 +763,129 @@ bool CanUseLcdTextFromPropertyTrees(const LayerImpl* layer, return true; } +gfx::Rect LayerDrawableContentRect( + const LayerImpl* layer, + const gfx::Rect& layer_bounds_in_target_space, + const gfx::Rect& clip_rect) { + if (layer->is_clipped()) + return IntersectRects(layer_bounds_in_target_space, clip_rect); + + return layer_bounds_in_target_space; +} + +gfx::Transform ReplicaToSurfaceTransform( + const RenderSurfaceImpl* render_surface, + const TransformTree& tree) { + gfx::Transform replica_to_surface; + if (!render_surface->HasReplica()) + return replica_to_surface; + const LayerImpl* replica_layer = render_surface->ReplicaLayer(); + const TransformNode* surface_transform_node = + tree.Node(render_surface->TransformTreeIndex()); + replica_to_surface.Scale(surface_transform_node->data.sublayer_scale.x(), + surface_transform_node->data.sublayer_scale.y()); + replica_to_surface.Translate(replica_layer->offset_to_transform_parent().x(), + replica_layer->offset_to_transform_parent().y()); + gfx::Transform replica_transform_node_to_surface; + tree.ComputeTransform(replica_layer->transform_tree_index(), + render_surface->TransformTreeIndex(), + &replica_transform_node_to_surface); + replica_to_surface.PreconcatTransform(replica_transform_node_to_surface); + if (surface_transform_node->data.sublayer_scale.x() != 0 && + surface_transform_node->data.sublayer_scale.y() != 0) { + replica_to_surface.Scale( + 1.0 / surface_transform_node->data.sublayer_scale.x(), + 1.0 / surface_transform_node->data.sublayer_scale.y()); + } + return replica_to_surface; +} + +gfx::Rect LayerClipRect(const LayerImpl* layer, + const gfx::Rect& layer_bounds_in_target_space) { + if (layer->is_clipped()) + return layer->clip_rect_in_target_space_from_property_trees(); + + return layer_bounds_in_target_space; +} + +void ComputeLayerDrawPropertiesUsingPropertyTrees( + const LayerImpl* layer, + const PropertyTrees* property_trees, + bool layers_always_allowed_lcd_text, + bool can_use_lcd_text, + DrawProperties* draw_properties) { + draw_properties->visible_layer_rect = + layer->visible_rect_from_property_trees(); + + const TransformNode* transform_node = + property_trees->transform_tree.Node(layer->transform_tree_index()); + const EffectNode* effect_node = + property_trees->effect_tree.Node(layer->effect_tree_index()); + const ClipNode* clip_node = + property_trees->clip_tree.Node(layer->clip_tree_index()); + + draw_properties->target_space_transform = + DrawTransformFromPropertyTreesInternal(layer, transform_node); + draw_properties->screen_space_transform = + ScreenSpaceTransformFromPropertyTreesInternal(layer, transform_node); + draw_properties->screen_space_transform_is_animating = + transform_node->data.to_screen_is_animated; + if (layer->layer_tree_impl() + ->settings() + .layer_transforms_should_scale_layer_contents) { + draw_properties->maximum_animation_contents_scale = + transform_node->data.combined_maximum_animation_target_scale; + draw_properties->starting_animation_contents_scale = + transform_node->data.combined_starting_animation_scale; + } else { + draw_properties->maximum_animation_contents_scale = 0.f; + draw_properties->starting_animation_contents_scale = 0.f; + } + + draw_properties->opacity = + LayerDrawOpacity(layer, property_trees->effect_tree); + draw_properties->can_use_lcd_text = + LayerCanUseLcdText(layer, layers_always_allowed_lcd_text, + can_use_lcd_text, transform_node, effect_node); + draw_properties->is_clipped = clip_node->data.layers_are_clipped; + + gfx::Rect bounds_in_target_space = MathUtil::MapEnclosingClippedRect( + draw_properties->target_space_transform, gfx::Rect(layer->bounds())); + draw_properties->clip_rect = LayerClipRect(layer, bounds_in_target_space); + draw_properties->drawable_content_rect = LayerDrawableContentRect( + layer, bounds_in_target_space, draw_properties->clip_rect); +} + +void ComputeSurfaceDrawPropertiesUsingPropertyTrees( + RenderSurfaceImpl* render_surface, + const PropertyTrees* property_trees, + RenderSurfaceDrawProperties* draw_properties) { + const ClipNode* clip_node = + property_trees->clip_tree.Node(render_surface->ClipTreeIndex()); + + draw_properties->is_clipped = SurfaceIsClipped(render_surface, clip_node); + draw_properties->draw_opacity = + SurfaceDrawOpacity(render_surface, property_trees->effect_tree); + draw_properties->draw_transform = + SurfaceDrawTransform(render_surface, property_trees->transform_tree); + draw_properties->screen_space_transform = SurfaceScreenSpaceTransform( + render_surface, property_trees->transform_tree); + + if (render_surface->HasReplica()) { + gfx::Transform replica_to_surface = ReplicaToSurfaceTransform( + render_surface, property_trees->transform_tree); + draw_properties->replica_draw_transform = + draw_properties->draw_transform * replica_to_surface; + draw_properties->replica_screen_space_transform = + draw_properties->screen_space_transform * replica_to_surface; + } else { + draw_properties->replica_draw_transform.MakeIdentity(); + draw_properties->replica_screen_space_transform.MakeIdentity(); + } + + draw_properties->clip_rect = SurfaceClipRect( + render_surface, property_trees->clip_tree.parent(clip_node), + draw_properties->is_clipped); +} + } // namespace cc diff --git a/chromium/cc/trees/draw_property_utils.h b/chromium/cc/trees/draw_property_utils.h index 952bef1a691..1291e0f30ba 100644 --- a/chromium/cc/trees/draw_property_utils.h +++ b/chromium/cc/trees/draw_property_utils.h @@ -16,9 +16,12 @@ class Transform; namespace cc { class ClipTree; +struct DrawProperties; class Layer; class LayerImpl; -class OpacityTree; +struct RenderSurfaceDrawProperties; +class RenderSurfaceImpl; +class EffectTree; class TransformTree; class PropertyTrees; @@ -34,7 +37,7 @@ ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree); void CC_EXPORT ComputeTransforms(TransformTree* transform_tree); // Computes screen space opacity for every node in the opacity tree. -void CC_EXPORT ComputeOpacities(OpacityTree* opacity_tree); +void CC_EXPORT ComputeOpacities(EffectTree* effect_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 @@ -73,6 +76,18 @@ ComputeVisibleRectsUsingPropertyTrees(LayerImpl* root_layer, PropertyTrees* property_trees, LayerImplList* update_layer_list); +void CC_EXPORT ComputeLayerDrawPropertiesUsingPropertyTrees( + const LayerImpl* layer, + const PropertyTrees* property_trees, + bool layers_always_allowed_lcd_text, + bool can_use_lcd_text, + DrawProperties* draw_properties); + +void CC_EXPORT ComputeSurfaceDrawPropertiesUsingPropertyTrees( + RenderSurfaceImpl* render_surface, + const PropertyTrees* property_trees, + RenderSurfaceDrawProperties* draw_properties); + gfx::Transform CC_EXPORT DrawTransformFromPropertyTrees(const Layer* layer, const TransformTree& tree); @@ -88,18 +103,6 @@ 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); - -bool CC_EXPORT -CanUseLcdTextFromPropertyTrees(const LayerImpl* layer, - bool layers_always_allowed_lcd_text, - bool can_use_lcd_text, - PropertyTrees* property_trees); - } // namespace cc #endif // CC_TREES_DRAW_PROPERTY_UTILS_H_ diff --git a/chromium/cc/trees/latency_info_swap_promise_monitor.cc b/chromium/cc/trees/latency_info_swap_promise_monitor.cc index c63ac5b0a04..a57ae4c8c41 100644 --- a/chromium/cc/trees/latency_info_swap_promise_monitor.cc +++ b/chromium/cc/trees/latency_info_swap_promise_monitor.cc @@ -30,7 +30,7 @@ bool AddForwardingScrollUpdateToMainComponent(ui::LatencyInfo* latency_info) { return false; latency_info->AddLatencyNumber( ui::INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT, 0, - latency_info->trace_id); + latency_info->trace_id()); return true; } @@ -59,7 +59,12 @@ void LatencyInfoSwapPromiseMonitor::OnSetNeedsCommitOnMain() { void LatencyInfoSwapPromiseMonitor::OnSetNeedsRedrawOnImpl() { if (AddRenderingScheduledComponent(latency_, false /* on_main */)) { scoped_ptr<SwapPromise> swap_promise(new LatencyInfoSwapPromise(*latency_)); - layer_tree_host_impl_->active_tree()->QueueSwapPromise(swap_promise.Pass()); + // Queue a pinned swap promise on the active tree. This will allow + // measurement of the time to the next SwapBuffers(). The swap + // promise is pinned so that it is not interrupted by new incoming + // activations (which would otherwise break the swap promise). + layer_tree_host_impl_->active_tree()->QueuePinnedSwapPromise( + swap_promise.Pass()); } } @@ -67,8 +72,8 @@ void LatencyInfoSwapPromiseMonitor::OnForwardScrollUpdateToMainThreadOnImpl() { if (AddForwardingScrollUpdateToMainComponent(latency_)) { int64 new_sequence_number = 0; for (ui::LatencyInfo::LatencyMap::const_iterator it = - latency_->latency_components.begin(); - it != latency_->latency_components.end(); ++it) { + latency_->latency_components().begin(); + 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) ^ diff --git a/chromium/cc/trees/latency_info_swap_promise_monitor.h b/chromium/cc/trees/latency_info_swap_promise_monitor.h index c1d9973911e..2f5e0e5d339 100644 --- a/chromium/cc/trees/latency_info_swap_promise_monitor.h +++ b/chromium/cc/trees/latency_info_swap_promise_monitor.h @@ -9,7 +9,7 @@ #define CC_TREES_LATENCY_INFO_SWAP_PROMISE_MONITOR_H_ namespace ui { -struct LatencyInfo; +class LatencyInfo; } // namespace ui namespace cc { diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc index a348301ba49..f42311604d6 100644 --- a/chromium/cc/trees/layer_tree_host.cc +++ b/chromium/cc/trees/layer_tree_host.cc @@ -35,7 +35,6 @@ #include "cc/layers/layer.h" #include "cc/layers/layer_iterator.h" #include "cc/layers/painted_scrollbar_layer.h" -#include "cc/layers/render_surface.h" #include "cc/resources/ui_resource_request.h" #include "cc/scheduler/begin_frame_source.h" #include "cc/trees/draw_property_utils.h" @@ -88,7 +87,6 @@ scoped_ptr<LayerTreeHost> LayerTreeHost::CreateSingleThreaded( LayerTreeHost::LayerTreeHost(InitParams* params) : micro_benchmark_controller_(this), next_ui_resource_id_(1), - inside_begin_main_frame_(false), needs_full_tree_sync_(true), needs_meta_info_recomputation_(true), client_(params->client), @@ -101,6 +99,7 @@ LayerTreeHost::LayerTreeHost(InitParams* params) top_controls_shrink_blink_size_(false), top_controls_height_(0.f), top_controls_shown_ratio_(0.f), + hide_pinch_scrollbars_near_min_scale_(false), device_scale_factor_(1.f), visible_(true), page_scale_factor_(1.f), @@ -223,9 +222,7 @@ void LayerTreeHost::BeginMainFrameNotExpectedSoon() { } void LayerTreeHost::BeginMainFrame(const BeginFrameArgs& args) { - inside_begin_main_frame_ = true; client_->BeginMainFrame(args); - inside_begin_main_frame_ = false; } void LayerTreeHost::DidStopFlinging() { @@ -236,11 +233,6 @@ void LayerTreeHost::Layout() { client_->Layout(); } -void LayerTreeHost::BeginCommitOnImplThread(LayerTreeHostImpl* host_impl) { - DCHECK(proxy_->IsImplThread()); - TRACE_EVENT0("cc", "LayerTreeHost::CommitTo"); -} - // This function commits the LayerTreeHost to an impl tree. When modifying // this function, keep in mind that the function *runs* on the impl thread! Any // code that is logically a main thread operation, e.g. deletion of a Layer, @@ -301,6 +293,10 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) { // Setting property trees must happen before pushing the page scale. sync_tree->SetPropertyTrees(property_trees_); + + sync_tree->set_hide_pinch_scrollbars_near_min_scale( + hide_pinch_scrollbars_near_min_scale_); + sync_tree->PushPageScaleFromMainThread( page_scale_factor_, min_page_scale_factor_, max_page_scale_factor_); sync_tree->elastic_overscroll()->PushFromMainThread(elastic_overscroll_); @@ -320,7 +316,10 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) { RecordGpuRasterizationHistogram(); host_impl->SetViewportSize(device_viewport_size_); - host_impl->SetDeviceScaleFactor(device_scale_factor_); + // TODO(senorblanco): Move this up so that it happens before GPU rasterization + // properties are set, since those trigger an update of GPU rasterization + // status, which depends on the device scale factor. (crbug.com/535700) + sync_tree->SetDeviceScaleFactor(device_scale_factor_); host_impl->SetDebugState(debug_state_); if (pending_page_scale_animation_) { sync_tree->SetPendingPageScaleAnimation( @@ -389,7 +388,18 @@ void LayerTreeHost::SetOutputSurface(scoped_ptr<OutputSurface> surface) { DCHECK(output_surface_lost_); DCHECK(surface); - proxy_->SetOutputSurface(surface.Pass()); + DCHECK(!new_output_surface_); + new_output_surface_ = surface.Pass(); + proxy_->SetOutputSurface(new_output_surface_.get()); +} + +scoped_ptr<OutputSurface> LayerTreeHost::ReleaseOutputSurface() { + DCHECK(!visible_); + DCHECK(!output_surface_lost_); + + DidLoseOutputSurface(); + proxy_->ReleaseOutputSurface(); + return current_output_surface_.Pass(); } void LayerTreeHost::RequestNewOutputSurface() { @@ -397,16 +407,20 @@ void LayerTreeHost::RequestNewOutputSurface() { } void LayerTreeHost::DidInitializeOutputSurface() { + DCHECK(new_output_surface_); output_surface_lost_ = false; - if (root_layer()) { - LayerTreeHostCommon::CallFunctionForSubtree( - root_layer(), [](Layer* layer) { layer->OnOutputSurfaceCreated(); }); - } + current_output_surface_ = new_output_surface_.Pass(); client_->DidInitializeOutputSurface(); } void LayerTreeHost::DidFailToInitializeOutputSurface() { DCHECK(output_surface_lost_); + DCHECK(new_output_surface_); + // Note: It is safe to drop all output surface references here as + // LayerTreeHostImpl will not keep a pointer to either the old or + // new output surface after failing to initialize the new one. + current_output_surface_ = nullptr; + new_output_surface_ = nullptr; client_->DidFailToInitializeOutputSurface(); } @@ -475,6 +489,11 @@ void LayerTreeHost::SetNeedsUpdateLayers() { NotifySwapPromiseMonitorsOfSetNeedsCommit(); } +void LayerTreeHost::SetPropertyTreesNeedRebuild() { + property_trees_.needs_rebuild = true; + SetNeedsUpdateLayers(); +} + void LayerTreeHost::SetNeedsCommit() { proxy_->SetNeedsCommit(); NotifySwapPromiseMonitorsOfSetNeedsCommit(); @@ -515,6 +534,7 @@ void LayerTreeHost::SetNextCommitWaitsForActivation() { void LayerTreeHost::SetNextCommitForcesRedraw() { next_commit_forces_redraw_ = true; + proxy_->SetNeedsUpdateLayers(); } void LayerTreeHost::SetAnimationEvents( @@ -562,7 +582,6 @@ void LayerTreeHost::SetDebugState(const LayerTreeDebugState& debug_state) { debug_state_.RecordRenderingStats()); SetNeedsCommit(); - proxy_->SetDebugState(debug_state); } void LayerTreeHost::SetHasGpuRasterizationTrigger(bool has_trigger) { @@ -583,7 +602,7 @@ void LayerTreeHost::SetViewportSize(const gfx::Size& device_viewport_size) { device_viewport_size_ = device_viewport_size; - property_trees_.needs_rebuild = true; + SetPropertyTreesNeedRebuild(); SetNeedsCommit(); } @@ -610,7 +629,7 @@ void LayerTreeHost::ApplyPageScaleDeltaFromImplSide(float page_scale_delta) { if (page_scale_delta == 1.f) return; page_scale_factor_ *= page_scale_delta; - property_trees_.needs_rebuild = true; + SetPropertyTreesNeedRebuild(); } void LayerTreeHost::SetPageScaleFactorAndLimits(float page_scale_factor, @@ -624,7 +643,7 @@ 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; + SetPropertyTreesNeedRebuild(); SetNeedsCommit(); } @@ -632,8 +651,6 @@ void LayerTreeHost::SetVisible(bool visible) { if (visible_ == visible) return; visible_ = visible; - if (!visible) - ReduceMemoryUsage(); proxy_->SetVisible(visible); } @@ -710,7 +727,9 @@ static Layer* FindFirstScrollableLayer(Layer* layer) { } void LayerTreeHost::RecordGpuRasterizationHistogram() { - if (gpu_rasterization_histogram_recorded_) + // Gpu rasterization is only supported for Renderer compositors. + // Checking for proxy_->HasImplThread() to exclude Browser compositors. + if (gpu_rasterization_histogram_recorded_ || !proxy_->HasImplThread()) return; // Record how widely gpu rasterization is enabled. @@ -741,8 +760,6 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) { TRACE_EVENT1("cc", "LayerTreeHost::DoUpdateLayers", "source_frame_number", source_frame_number()); - RenderSurfaceLayerList render_surface_layer_list; - UpdateHudLayer(); Layer* root_scroll = FindFirstScrollableLayer(root_layer); @@ -756,21 +773,6 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) { } 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, - inner_viewport_scroll_layer_.get(), outer_viewport_scroll_layer_.get(), - 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_); TRACE_EVENT0("cc", "LayerTreeHost::UpdateLayers::CalcDrawProps"); @@ -799,9 +801,6 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) { 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_layer_rect = - layer->visible_rect_from_property_trees(); did_paint_content |= layer->Update(); content_is_suitable_for_gpu_rasterization_ &= layer->IsSuitableForGpuRasterization(); @@ -809,22 +808,15 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) { return did_paint_content; } -void LayerTreeHost::ReduceMemoryUsage() { - if (!root_layer()) - return; - - LayerTreeHostCommon::CallFunctionForSubtree( - root_layer(), [](Layer* layer) { layer->ReduceMemoryUsage(); }); -} - void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) { ScopedPtrVector<SwapPromise>::iterator it = info->swap_promises.begin(); for (; it != info->swap_promises.end(); ++it) { scoped_ptr<SwapPromise> swap_promise(info->swap_promises.take(it)); - TRACE_EVENT_FLOW_STEP0("input", + TRACE_EVENT_WITH_FLOW1("input,benchmark", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(swap_promise->TraceId()), - "Main thread scroll update"); + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "step", "Main thread scroll update"); QueueSwapPromise(swap_promise.Pass()); } @@ -846,6 +838,7 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) { gfx::ScrollOffsetWithDelta(layer->scroll_offset(), info->scrolls[i].scroll_delta)); } + SetNeedsUpdateLayers(); } } @@ -877,33 +870,10 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) { inner_viewport_scroll_delta, outer_viewport_scroll_delta, info->elastic_overscroll_delta, info->page_scale_delta, info->top_controls_delta); + SetNeedsUpdateLayers(); } } -void LayerTreeHost::StartRateLimiter() { - if (inside_begin_main_frame_) - return; - - if (!rate_limit_timer_.IsRunning()) { - rate_limit_timer_.Start(FROM_HERE, - base::TimeDelta(), - this, - &LayerTreeHost::RateLimit); - } -} - -void LayerTreeHost::StopRateLimiter() { - rate_limit_timer_.Stop(); -} - -void LayerTreeHost::RateLimit() { - // Force a no-op command on the compositor context, so that any ratelimiting - // commands will wait for the compositing context, and therefore for the - // SwapBuffers. - proxy_->ForceSerializeOnSwapBuffers(); - client_->RateLimitSharedMainThreadContext(); -} - void LayerTreeHost::SetDeviceScaleFactor(float device_scale_factor) { if (device_scale_factor == device_scale_factor_) return; @@ -1002,6 +972,8 @@ void LayerTreeHost::RegisterViewportLayers( scoped_refptr<Layer> page_scale_layer, scoped_refptr<Layer> inner_viewport_scroll_layer, scoped_refptr<Layer> outer_viewport_scroll_layer) { + DCHECK_IMPLIES(inner_viewport_scroll_layer, + inner_viewport_scroll_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; @@ -1111,7 +1083,7 @@ void LayerTreeHost::UnregisterLayer(Layer* layer) { } bool LayerTreeHost::IsLayerInTree(int layer_id, LayerTreeType tree_type) const { - return tree_type == LayerTreeType::ACTIVE; + return tree_type == LayerTreeType::ACTIVE && LayerById(layer_id); } void LayerTreeHost::SetMutatorsNeedCommit() { @@ -1151,6 +1123,15 @@ void LayerTreeHost::SetLayerScrollOffsetMutated( layer->OnScrollOffsetAnimated(scroll_offset); } +void LayerTreeHost::LayerTransformIsPotentiallyAnimatingChanged( + int layer_id, + LayerTreeType tree_type, + bool is_animating) { + LayerAnimationValueObserver* layer = LayerById(layer_id); + DCHECK(layer); + layer->OnTransformIsPotentiallyAnimatingChanged(is_animating); +} + gfx::ScrollOffset LayerTreeHost::GetScrollOffsetForAnimation( int layer_id) const { LayerAnimationValueProvider* layer = LayerById(layer_id); @@ -1167,19 +1148,30 @@ bool LayerTreeHost::ScrollOffsetAnimationWasInterrupted( bool LayerTreeHost::IsAnimatingFilterProperty(const Layer* layer) const { return animation_host_ - ? animation_host_->IsAnimatingFilterProperty(layer->id()) + ? animation_host_->IsAnimatingFilterProperty(layer->id(), + LayerTreeType::ACTIVE) : false; } bool LayerTreeHost::IsAnimatingOpacityProperty(const Layer* layer) const { return animation_host_ - ? animation_host_->IsAnimatingOpacityProperty(layer->id()) + ? animation_host_->IsAnimatingOpacityProperty( + layer->id(), LayerTreeType::ACTIVE) : false; } bool LayerTreeHost::IsAnimatingTransformProperty(const Layer* layer) const { return animation_host_ - ? animation_host_->IsAnimatingTransformProperty(layer->id()) + ? animation_host_->IsAnimatingTransformProperty( + layer->id(), LayerTreeType::ACTIVE) + : false; +} + +bool LayerTreeHost::HasPotentiallyRunningFilterAnimation( + const Layer* layer) const { + return animation_host_ + ? animation_host_->HasPotentiallyRunningFilterAnimation( + layer->id(), LayerTreeType::ACTIVE) : false; } @@ -1187,7 +1179,7 @@ bool LayerTreeHost::HasPotentiallyRunningOpacityAnimation( const Layer* layer) const { return animation_host_ ? animation_host_->HasPotentiallyRunningOpacityAnimation( - layer->id()) + layer->id(), LayerTreeType::ACTIVE) : false; } @@ -1195,7 +1187,39 @@ bool LayerTreeHost::HasPotentiallyRunningTransformAnimation( const Layer* layer) const { return animation_host_ ? animation_host_->HasPotentiallyRunningTransformAnimation( - layer->id()) + layer->id(), LayerTreeType::ACTIVE) + : false; +} + +bool LayerTreeHost::HasOnlyTranslationTransforms(const Layer* layer) const { + return animation_host_ + ? animation_host_->HasOnlyTranslationTransforms( + layer->id(), LayerTreeType::ACTIVE) + : false; +} + +bool LayerTreeHost::MaximumTargetScale(const Layer* layer, + float* max_scale) const { + return animation_host_ + ? animation_host_->MaximumTargetScale( + layer->id(), LayerTreeType::ACTIVE, max_scale) + : false; +} + +bool LayerTreeHost::AnimationStartScale(const Layer* layer, + float* start_scale) const { + return animation_host_ + ? animation_host_->AnimationStartScale( + layer->id(), LayerTreeType::ACTIVE, start_scale) + : false; +} + +bool LayerTreeHost::HasAnyAnimationTargetingProperty( + const Layer* layer, + Animation::TargetProperty property) const { + return animation_host_ + ? animation_host_->HasAnyAnimationTargetingProperty(layer->id(), + property) : false; } diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h index 4f38352f9c6..5c92f97689c 100644 --- a/chromium/cc/trees/layer_tree_host.h +++ b/chromium/cc/trees/layer_tree_host.h @@ -17,7 +17,6 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" -#include "base/timer/timer.h" #include "cc/animation/animation_events.h" #include "cc/base/cc_export.h" #include "cc/base/scoped_ptr_vector.h" @@ -107,11 +106,11 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void AnimateLayers(base::TimeTicks monotonic_frame_begin_time); void DidStopFlinging(); void Layout(); - void BeginCommitOnImplThread(LayerTreeHostImpl* host_impl); void FinishCommitOnImplThread(LayerTreeHostImpl* host_impl); void WillCommit(); void CommitComplete(); void SetOutputSurface(scoped_ptr<OutputSurface> output_surface); + scoped_ptr<OutputSurface> ReleaseOutputSurface(); void RequestNewOutputSurface(); void DidInitializeOutputSurface(); void DidFailToInitializeOutputSurface(); @@ -211,6 +210,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void SetTopControlsHeight(float height, bool shrink); void SetTopControlsShownRatio(float ratio); + void set_hide_pinch_scrollbars_near_min_scale(bool hide) { + hide_pinch_scrollbars_near_min_scale_ = hide; + } + gfx::Size device_viewport_size() const { return device_viewport_size_; } void ApplyPageScaleDeltaFromImplSide(float page_scale_delta); @@ -240,12 +243,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void ApplyScrollAndScale(ScrollAndScaleSet* info); void SetImplTransform(const gfx::Transform& transform); - // Virtual for tests. - virtual void StartRateLimiter(); - virtual void StopRateLimiter(); - - void RateLimit(); - void SetDeviceScaleFactor(float device_scale_factor); float device_scale_factor() const { return device_scale_factor_; } @@ -339,6 +336,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { int layer_id, LayerTreeType tree_type, const gfx::ScrollOffset& scroll_offset) override; + void LayerTransformIsPotentiallyAnimatingChanged(int layer_id, + LayerTreeType tree_type, + bool is_animating) override; void ScrollOffsetAnimationFinished() override {} gfx::ScrollOffset GetScrollOffsetForAnimation(int layer_id) const override; @@ -346,8 +346,15 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { bool IsAnimatingFilterProperty(const Layer* layer) const; bool IsAnimatingOpacityProperty(const Layer* layer) const; bool IsAnimatingTransformProperty(const Layer* layer) const; + bool HasPotentiallyRunningFilterAnimation(const Layer* layer) const; bool HasPotentiallyRunningOpacityAnimation(const Layer* layer) const; bool HasPotentiallyRunningTransformAnimation(const Layer* layer) const; + bool HasOnlyTranslationTransforms(const Layer* layer) const; + bool MaximumTargetScale(const Layer* layer, float* max_scale) const; + bool AnimationStartScale(const Layer* layer, float* start_scale) const; + bool HasAnyAnimationTargetingProperty( + const Layer* layer, + Animation::TargetProperty property) const; bool AnimationsPreserveAxisAlignment(const Layer* layer) const; bool HasAnyAnimation(const Layer* layer) const; bool HasActiveAnimation(const Layer* layer) const; @@ -388,8 +395,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { bool DoUpdateLayers(Layer* root_layer); void UpdateHudLayer(); - void ReduceMemoryUsage(); - bool AnimateLayersRecursive(Layer* current, base::TimeTicks time); struct UIResourceClientData { @@ -410,7 +415,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void NotifySwapPromiseMonitorsOfSetNeedsCommit(); - bool inside_begin_main_frame_; + void SetPropertyTreesNeedRebuild(); + bool needs_full_tree_sync_; bool needs_meta_info_recomputation_; @@ -421,6 +427,13 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { int meta_information_sequence_number_; scoped_ptr<RenderingStatsInstrumentation> rendering_stats_instrumentation_; + // |current_output_surface_| can't be updated until we've successfully + // initialized a new output surface. |new_output_surface_| contains the + // new output surface that is currently being initialized. If initialization + // is successful then |new_output_surface_| replaces + // |current_output_surface_|. + scoped_ptr<OutputSurface> new_output_surface_; + scoped_ptr<OutputSurface> current_output_surface_; bool output_surface_lost_; scoped_refptr<Layer> root_layer_; @@ -436,12 +449,11 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { bool top_controls_shrink_blink_size_; float top_controls_height_; float top_controls_shown_ratio_; + bool hide_pinch_scrollbars_near_min_scale_; float device_scale_factor_; bool visible_; - base::OneShotTimer<LayerTreeHost> rate_limit_timer_; - float page_scale_factor_; float min_page_scale_factor_; float max_page_scale_factor_; diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h index 56a128f4bad..3bc70c5e13b 100644 --- a/chromium/cc/trees/layer_tree_host_client.h +++ b/chromium/cc/trees/layer_tree_host_client.h @@ -58,12 +58,6 @@ class LayerTreeHostClient { // 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() {} - protected: virtual ~LayerTreeHostClient() {} }; diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc index 427a3c825e1..2d2bd3e7caa 100644 --- a/chromium/cc/trees/layer_tree_host_common.cc +++ b/chromium/cc/trees/layer_tree_host_common.cc @@ -12,7 +12,7 @@ #include "cc/layers/layer.h" #include "cc/layers/layer_impl.h" #include "cc/layers/layer_iterator.h" -#include "cc/layers/render_surface.h" +#include "cc/layers/render_surface_draw_properties.h" #include "cc/layers/render_surface_impl.h" #include "cc/trees/draw_property_utils.h" #include "cc/trees/layer_tree_host.h" @@ -24,14 +24,130 @@ namespace cc { +LayerTreeHostCommon::CalcDrawPropsMainInputs::CalcDrawPropsMainInputs( + Layer* root_layer, + const gfx::Size& device_viewport_size, + const gfx::Transform& device_transform, + float device_scale_factor, + float page_scale_factor, + const Layer* page_scale_layer, + const Layer* inner_viewport_scroll_layer, + const Layer* outer_viewport_scroll_layer) + : 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_layer(page_scale_layer), + inner_viewport_scroll_layer(inner_viewport_scroll_layer), + outer_viewport_scroll_layer(outer_viewport_scroll_layer) {} + +LayerTreeHostCommon::CalcDrawPropsMainInputs::CalcDrawPropsMainInputs( + Layer* root_layer, + const gfx::Size& device_viewport_size, + const gfx::Transform& device_transform) + : CalcDrawPropsMainInputs(root_layer, + device_viewport_size, + device_transform, + 1.f, + 1.f, + NULL, + NULL, + NULL) {} + +LayerTreeHostCommon::CalcDrawPropsMainInputs::CalcDrawPropsMainInputs( + Layer* root_layer, + const gfx::Size& device_viewport_size) + : CalcDrawPropsMainInputs(root_layer, + device_viewport_size, + gfx::Transform()) {} + +LayerTreeHostCommon::CalcDrawPropsImplInputs::CalcDrawPropsImplInputs( + LayerImpl* root_layer, + const gfx::Size& device_viewport_size, + const gfx::Transform& device_transform, + float device_scale_factor, + float page_scale_factor, + const LayerImpl* page_scale_layer, + const LayerImpl* inner_viewport_scroll_layer, + const LayerImpl* outer_viewport_scroll_layer, + const gfx::Vector2dF& elastic_overscroll, + const LayerImpl* 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, + LayerImplList* render_surface_layer_list, + 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_layer(page_scale_layer), + inner_viewport_scroll_layer(inner_viewport_scroll_layer), + outer_viewport_scroll_layer(outer_viewport_scroll_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), + property_trees(property_trees) {} + +LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting:: + CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer, + const gfx::Size& device_viewport_size, + const gfx::Transform& device_transform, + LayerImplList* render_surface_layer_list) + : CalcDrawPropsImplInputs(root_layer, + device_viewport_size, + device_transform, + 1.f, + 1.f, + NULL, + NULL, + NULL, + gfx::Vector2dF(), + NULL, + std::numeric_limits<int>::max() / 2, + false, + false, + true, + false, + true, + render_surface_layer_list, + 0, + GetPropertyTrees(root_layer)) { + DCHECK(root_layer); + DCHECK(render_surface_layer_list); +} + +LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting:: + CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer, + const gfx::Size& device_viewport_size, + LayerImplList* render_surface_layer_list) + : CalcDrawPropsImplInputsForTesting(root_layer, + device_viewport_size, + gfx::Transform(), + render_surface_layer_list) {} + ScrollAndScaleSet::ScrollAndScaleSet() : page_scale_delta(1.f), top_controls_delta(0.f) { } ScrollAndScaleSet::~ScrollAndScaleSet() {} -template <typename LayerType> -static gfx::Vector2dF GetEffectiveScrollDelta(LayerType* layer) { +static gfx::Vector2dF GetEffectiveScrollDelta(LayerImpl* layer) { // 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. @@ -51,8 +167,7 @@ static gfx::Vector2dF GetEffectiveScrollDelta(LayerType* layer) { return scroll_delta; } -template <typename LayerType> -static gfx::ScrollOffset GetEffectiveCurrentScrollOffset(LayerType* layer) { +static gfx::ScrollOffset GetEffectiveCurrentScrollOffset(LayerImpl* 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 @@ -112,8 +227,7 @@ gfx::Rect LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_bound_rect, layer_in_surface_space, transform); } -template <typename LayerType> -static LayerType* NextTargetSurface(LayerType* layer) { +static const LayerImpl* NextTargetSurface(const LayerImpl* layer) { return layer->parent() ? layer->parent()->render_target() : 0; } @@ -122,18 +236,17 @@ static LayerType* NextTargetSurface(LayerType* layer) { // translation components of the draw transforms of each target between the // ancestor and descendant. These transforms must be 2D translations, and this // requirement is enforced at every step. -template <typename LayerType> static gfx::Vector2dF ComputeChangeOfBasisTranslation( - const LayerType& ancestor_layer, - const LayerType& descendant_layer) { + const LayerImpl& ancestor_layer, + const LayerImpl& descendant_layer) { DCHECK(descendant_layer.HasAncestor(&ancestor_layer)); - const LayerType* descendant_target = descendant_layer.render_target(); + const LayerImpl* descendant_target = descendant_layer.render_target(); DCHECK(descendant_target); - const LayerType* ancestor_target = ancestor_layer.render_target(); + const LayerImpl* ancestor_target = ancestor_layer.render_target(); DCHECK(ancestor_target); gfx::Vector2dF translation; - for (const LayerType* target = descendant_target; target != ancestor_target; + for (const LayerImpl* target = descendant_target; target != ancestor_target; target = NextTargetSurface(target)) { const gfx::Transform& trans = target->render_surface()->draw_transform(); // Ensure that this translation is truly 2d. @@ -150,30 +263,29 @@ enum TranslateRectDirection { TRANSLATE_RECT_DIRECTION_TO_DESCENDANT }; -template <typename LayerType> -static gfx::Rect TranslateRectToTargetSpace(const LayerType& ancestor_layer, - const LayerType& descendant_layer, +static gfx::Rect TranslateRectToTargetSpace(const LayerImpl& ancestor_layer, + const LayerImpl& descendant_layer, const gfx::Rect& rect, TranslateRectDirection direction) { - gfx::Vector2dF translation = ComputeChangeOfBasisTranslation<LayerType>( - ancestor_layer, descendant_layer); + gfx::Vector2dF translation = + ComputeChangeOfBasisTranslation(ancestor_layer, descendant_layer); if (direction == TRANSLATE_RECT_DIRECTION_TO_DESCENDANT) translation.Scale(-1.f); + gfx::RectF rect_f = gfx::RectF(rect); return gfx::ToEnclosingRect( - gfx::RectF(rect.origin() + translation, rect.size())); + gfx::RectF(rect_f.origin() + translation, rect_f.size())); } // Attempts to update the clip rects for the given layer. If the layer has a // clip_parent, it may not inherit its immediate ancestor's clip. -template <typename LayerType> static void UpdateClipRectsForClipChild( - const LayerType* layer, + const LayerImpl* layer, gfx::Rect* clip_rect_in_parent_target_space, bool* subtree_should_be_clipped) { // If the layer has no clip_parent, or the ancestor is the same as its actual // parent, then we don't need special clip rects. Bail now and leave the out // parameters untouched. - const LayerType* clip_parent = layer->scroll_parent(); + const LayerImpl* clip_parent = layer->scroll_parent(); if (!clip_parent) clip_parent = layer->clip_parent(); @@ -195,7 +307,7 @@ static void UpdateClipRectsForClipChild( // CalculateDrawPropertiesInternal. If we, say, create a render surface, these // 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_rect_in_parent_target_space = TranslateRectToTargetSpace( *clip_parent, *layer->parent(), *clip_rect_in_parent_target_space, TRANSLATE_RECT_DIRECTION_TO_DESCENDANT); } else { @@ -203,7 +315,7 @@ static void UpdateClipRectsForClipChild( // 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>( + *clip_rect_in_parent_target_space = TranslateRectToTargetSpace( *layer->parent(), *clip_parent, *clip_rect_in_parent_target_space, TRANSLATE_RECT_DIRECTION_TO_ANCESTOR); } @@ -216,9 +328,8 @@ static void UpdateClipRectsForClipChild( // and its parent. // // NB: we accumulate the layer's *clipped* drawable content rect. -template <typename LayerType> struct AccumulatedSurfaceState { - explicit AccumulatedSurfaceState(LayerType* render_target) + explicit AccumulatedSurfaceState(LayerImpl* render_target) : render_target(render_target) {} // The accumulated drawable content rect for the surface associated with the @@ -229,15 +340,18 @@ struct AccumulatedSurfaceState { // surface so that we can DCHECK that the surface's draw transform is simply // a translation when |render_target| reports that it has no unclipped // descendants). - LayerType* render_target; + LayerImpl* render_target; }; template <typename LayerType> +static inline bool IsRootLayer(LayerType* layer) { + return !layer->parent(); +} + void UpdateAccumulatedSurfaceState( - LayerType* layer, + LayerImpl* layer, const gfx::Rect& drawable_content_rect, - std::vector<AccumulatedSurfaceState<LayerType>>* - accumulated_surface_state) { + std::vector<AccumulatedSurfaceState>* accumulated_surface_state) { if (IsRootLayer(layer)) return; @@ -248,7 +362,7 @@ void UpdateAccumulatedSurfaceState( // render surface and we'll want to add our rect to our *surface's* target, or // we're not and our target is the same as our parent's. In both cases, the // parent's target gives us what we want. - LayerType* render_target = layer->clip_parent() + LayerImpl* render_target = layer->clip_parent() ? layer->clip_parent()->render_target() : layer->parent()->render_target(); @@ -266,9 +380,9 @@ void UpdateAccumulatedSurfaceState( // If the layer has a clip parent, the clip rect may be in the wrong space, // 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, - TRANSLATE_RECT_DIRECTION_TO_DESCENDANT); + clip_rect = + TranslateRectToTargetSpace(*layer->clip_parent(), *layer, clip_rect, + TRANSLATE_RECT_DIRECTION_TO_DESCENDANT); } target_rect.Intersect(clip_rect); } @@ -276,9 +390,8 @@ void UpdateAccumulatedSurfaceState( // We must have at least one entry in the vector for the root. DCHECK_LT(0ul, accumulated_surface_state->size()); - typedef typename std::vector<AccumulatedSurfaceState<LayerType>> - AccumulatedSurfaceStateVector; - typedef typename AccumulatedSurfaceStateVector::reverse_iterator + typedef std::vector<AccumulatedSurfaceState> AccumulatedSurfaceStateVector; + typedef AccumulatedSurfaceStateVector::reverse_iterator AccumulatedSurfaceStateIterator; AccumulatedSurfaceStateIterator current_state = accumulated_surface_state->rbegin(); @@ -296,7 +409,7 @@ void UpdateAccumulatedSurfaceState( } // Transform rect from the current target's space to the next. - LayerType* current_target = current_state->render_target; + LayerImpl* current_target = current_state->render_target; DCHECK(current_target->render_surface()); const gfx::Transform& current_draw_transform = current_target->render_surface()->draw_transform(); @@ -305,8 +418,8 @@ void UpdateAccumulatedSurfaceState( DCHECK_IMPLIES(current_target->num_unclipped_descendants(), current_draw_transform.IsIdentityOrTranslation()); - target_rect = gfx::ToEnclosingRect( - MathUtil::MapClippedRect(current_draw_transform, target_rect)); + target_rect = + MathUtil::MapEnclosingClippedRect(current_draw_transform, target_rect); } // It is an error to not reach |render_target|. If this happens, it means that @@ -315,10 +428,6 @@ void UpdateAccumulatedSurfaceState( DCHECK(found_render_target); } -template <typename LayerType> static inline bool IsRootLayer(LayerType* layer) { - return !layer->parent(); -} - template <typename LayerType> static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) { return layer->Is3dSorted() && layer->parent() && @@ -326,16 +435,14 @@ static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) { (layer->parent()->sorting_context_id() == layer->sorting_context_id()); } -template <typename LayerType> -static bool IsRootLayerOfNewRenderingContext(LayerType* layer) { +static bool IsRootLayerOfNewRenderingContext(LayerImpl* layer) { if (layer->parent()) return !layer->parent()->Is3dSorted() && layer->Is3dSorted(); return layer->Is3dSorted(); } -template <typename LayerType> -static bool IsLayerBackFaceVisible(LayerType* layer) { +static bool IsLayerBackFaceVisible(LayerImpl* layer) { // 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 @@ -349,8 +456,7 @@ static bool IsLayerBackFaceVisible(LayerType* layer) { return layer->transform().IsBackFaceVisible(); } -template <typename LayerType> -static bool IsSurfaceBackFaceVisible(LayerType* layer, +static bool IsSurfaceBackFaceVisible(LayerImpl* layer, const gfx::Transform& draw_transform) { if (LayerIsInExisting3DRenderingContext(layer)) return draw_transform.IsBackFaceVisible(); @@ -369,9 +475,8 @@ static inline bool LayerClipsSubtree(LayerType* layer) { return layer->masks_to_bounds() || layer->mask_layer(); } -template <typename LayerType> static gfx::Rect CalculateVisibleLayerRect( - LayerType* layer, + LayerImpl* layer, const gfx::Rect& clip_rect_of_target_surface_in_target_space, const gfx::Rect& layer_rect_in_target_space) { DCHECK(layer->render_target()); @@ -407,20 +512,7 @@ static gfx::Rect CalculateVisibleLayerRect( layer_rect_in_target_space, layer->draw_transform()); } -static inline bool TransformToParentIsKnown(LayerImpl* layer) { return true; } - -static inline bool TransformToParentIsKnown(Layer* layer) { - return !layer->TransformIsAnimating(); -} - -static inline bool TransformToScreenIsKnown(LayerImpl* layer) { return true; } - -static inline bool TransformToScreenIsKnown(Layer* layer) { - return !layer->screen_space_transform_is_animating(); -} - -template <typename LayerType> -static bool LayerShouldBeSkipped(LayerType* layer, bool layer_is_drawn) { +static bool LayerShouldBeSkipped(LayerImpl* layer, bool layer_is_drawn) { // 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). @@ -444,7 +536,7 @@ static bool LayerShouldBeSkipped(LayerType* layer, bool layer_is_drawn) { if (!layer->DrawsContent() || layer->bounds().IsEmpty()) return true; - LayerType* backface_test_layer = layer; + LayerImpl* backface_test_layer = layer; if (layer->use_parent_backface_visibility()) { DCHECK(layer->parent()); DCHECK(!layer->parent()->use_parent_backface_visibility()); @@ -454,7 +546,6 @@ static bool LayerShouldBeSkipped(LayerType* layer, bool layer_is_drawn) { // 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) && IsLayerBackFaceVisible(backface_test_layer)) return true; @@ -463,7 +554,8 @@ static bool LayerShouldBeSkipped(LayerType* layer, bool layer_is_drawn) { template <typename LayerType> static bool HasInvertibleOrAnimatedTransform(LayerType* layer) { - return layer->transform_is_invertible() || layer->TransformIsAnimating(); + return layer->transform_is_invertible() || + layer->HasPotentiallyRunningTransformAnimation(); } static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, @@ -477,12 +569,12 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, // 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) + if (layer->num_layer_or_descendants_with_copy_request() > 0) 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) + if (layer->layer_or_descendant_has_input_handler()) return false; // If the layer is not drawn, then skip it and its subtree. @@ -492,7 +584,13 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, // 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()) + if (layer->layer_tree_impl()->IsPendingTree() && + layer->HasPotentiallyRunningOpacityAnimation()) + return false; + + // If layer has a background filter, don't skip the layer, even it the + // opacity is 0. + if (!layer->background_filters().IsEmpty()) return false; // The opacity of a layer always applies to its children (either implicitly @@ -501,46 +599,8 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer, 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(); -} - static inline void SavePaintPropertiesLayer(LayerImpl* layer) {} -static inline void SavePaintPropertiesLayer(Layer* layer) { - layer->SavePaintProperties(); - - if (layer->mask_layer()) - layer->mask_layer()->SavePaintProperties(); - if (layer->replica_layer() && layer->replica_layer()->mask_layer()) - layer->replica_layer()->mask_layer()->SavePaintProperties(); -} - static bool SubtreeShouldRenderToSeparateSurface( Layer* layer, bool axis_aligned_with_respect_to_parent) { @@ -576,7 +636,7 @@ static bool SubtreeShouldRenderToSeparateSurface( // 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()) { + if (layer->HasPotentiallyRunningFilterAnimation()) { DCHECK(!is_root); return true; } @@ -679,10 +739,9 @@ 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( - LayerType* layer, - LayerType* container, + LayerImpl* layer, + LayerImpl* container, const gfx::Vector2dF& position_offset) { gfx::Transform result_transform; @@ -697,11 +756,11 @@ gfx::Transform ComputeSizeDeltaCompensation( gfx::Transform target_surface_space_to_container_layer_space; // Calculate step 1a - 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)) { + LayerImpl* container_target_surface = container->render_target(); + for (const LayerImpl* current_target_surface = NextTargetSurface(layer); + current_target_surface && + current_target_surface != container_target_surface; + current_target_surface = NextTargetSurface(current_target_surface)) { // Note: Concat is used here to convert the result coordinate space from // current render surface to the next render surface. target_surface_space_to_container_layer_space.ConcatTransform( @@ -742,12 +801,10 @@ gfx::Transform ComputeSizeDeltaCompensation( return result_transform; } -template <typename LayerType> -void ApplyPositionAdjustment( - LayerType* layer, - LayerType* container, - const gfx::Transform& scroll_compensation, - gfx::Transform* combined_transform) { +void ApplyPositionAdjustment(LayerImpl* layer, + LayerImpl* container, + const gfx::Transform& scroll_compensation, + gfx::Transform* combined_transform) { if (!layer->position_constraint().is_fixed_position()) return; @@ -776,9 +833,8 @@ void ApplyPositionAdjustment( ComputeSizeDeltaCompensation(layer, container, position_offset)); } -template <typename LayerType> gfx::Transform ComputeScrollCompensationForThisLayer( - LayerType* scrolling_layer, + LayerImpl* 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 @@ -816,9 +872,8 @@ gfx::Transform ComputeScrollCompensationForThisLayer( return scroll_compensation_for_this_layer; } -template <typename LayerType> gfx::Transform ComputeScrollCompensationMatrixForChildren( - LayerType* layer, + LayerImpl* layer, const gfx::Transform& parent_matrix, const gfx::Transform& current_scroll_compensation_matrix, const gfx::Vector2dF& scroll_delta) { @@ -903,9 +958,8 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren( return next_scroll_compensation_matrix; } -template <typename LayerType> static inline void UpdateLayerScaleDrawProperties( - LayerType* layer, + LayerImpl* layer, float maximum_animation_contents_scale, float starting_animation_contents_scale) { layer->draw_properties().maximum_animation_contents_scale = @@ -915,23 +969,10 @@ static inline void UpdateLayerScaleDrawProperties( } static inline void CalculateAnimationContentsScale( - Layer* layer, - bool ancestor_is_animating_scale, - float ancestor_maximum_animation_contents_scale, - const gfx::Transform& parent_transform, - const gfx::Transform& combined_transform, - bool* combined_is_animating_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( LayerImpl* layer, bool ancestor_is_animating_scale, float ancestor_maximum_animation_contents_scale, + float ancestor_starting_animation_contents_scale, const gfx::Transform& ancestor_transform, const gfx::Transform& combined_transform, bool* combined_is_animating_scale, @@ -987,11 +1028,12 @@ static inline void CalculateAnimationContentsScale( if (!layer_is_animating_scale) { gfx::Vector2dF layer_transform_scales = MathUtil::ComputeTransform2dScaleComponents(layer->transform(), 0.f); - *combined_maximum_animation_contents_scale = - ancestor_maximum_animation_contents_scale * + float max_layer_scale = std::max(layer_transform_scales.x(), layer_transform_scales.y()); + *combined_maximum_animation_contents_scale = + ancestor_maximum_animation_contents_scale * max_layer_scale; *combined_starting_animation_contents_scale = - *combined_maximum_animation_contents_scale; + ancestor_starting_animation_contents_scale * max_layer_scale; return; } @@ -1016,9 +1058,8 @@ static inline void CalculateAnimationContentsScale( layer_start_animated_scale * max_scale_xy; } -template <typename LayerTypePtr> static inline void MarkLayerWithRenderSurfaceLayerListId( - LayerTypePtr layer, + LayerImpl* layer, int current_render_surface_layer_list_id) { layer->draw_properties().last_drawn_render_surface_layer_list_id = current_render_surface_layer_list_id; @@ -1026,9 +1067,8 @@ static inline void MarkLayerWithRenderSurfaceLayerListId( !!current_render_surface_layer_list_id); } -template <typename LayerTypePtr> static inline void MarkMasksWithRenderSurfaceLayerListId( - LayerTypePtr layer, + LayerImpl* layer, int current_render_surface_layer_list_id) { if (layer->mask_layer()) { MarkLayerWithRenderSurfaceLayerListId(layer->mask_layer(), @@ -1040,13 +1080,11 @@ static inline void MarkMasksWithRenderSurfaceLayerListId( } } -template <typename LayerListType> static inline void MarkLayerListWithRenderSurfaceLayerListId( - LayerListType* layer_list, + LayerImplList* layer_list, int current_render_surface_layer_list_id) { - for (typename LayerListType::iterator it = layer_list->begin(); - it != layer_list->end(); - ++it) { + for (LayerImplList::iterator it = layer_list->begin(); + it != layer_list->end(); ++it) { MarkLayerWithRenderSurfaceLayerListId(*it, current_render_surface_layer_list_id); MarkMasksWithRenderSurfaceLayerListId(*it, @@ -1054,10 +1092,9 @@ static inline void MarkLayerListWithRenderSurfaceLayerListId( } } -template <typename LayerType> static inline void RemoveSurfaceForEarlyExit( - LayerType* layer_to_remove, - typename LayerType::RenderSurfaceListType* render_surface_layer_list) { + LayerImpl* layer_to_remove, + LayerImplList* render_surface_layer_list) { DCHECK(layer_to_remove->render_surface()); // Technically, we know that the layer we want to remove should be // at the back of the render_surface_layer_list. However, we have had @@ -1136,8 +1173,12 @@ static void PreCalculateMetaInformationInternal( PreCalculateMetaInformationRecursiveData* recursive_data) { ValidateRenderSurface(layer); + if (!IsMetaInformationRecomputationNeeded(layer)) { + DCHECK(IsRootLayer(layer)); + return; + } + layer->set_sorted_for_recursion(false); - layer->draw_properties().has_child_with_a_scroll_parent = false; layer->set_layer_or_descendant_is_drawn(false); layer->set_visited(false); @@ -1147,26 +1188,14 @@ static void PreCalculateMetaInformationInternal( return; } - if (!IsMetaInformationRecomputationNeeded(layer)) { - DCHECK(IsRootLayer(layer)); - return; - } - if (layer->clip_parent()) recursive_data->num_unclipped_descendants++; - layer->set_num_children_with_scroll_parent(0); 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); - - if (child_layer->scroll_parent()) { - layer->draw_properties().has_child_with_a_scroll_parent = true; - layer->set_num_children_with_scroll_parent( - layer->num_children_with_scroll_parent() + 1); - } recursive_data->Merge(data_for_child); } @@ -1183,16 +1212,10 @@ static void PreCalculateMetaInformationInternal( 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( + layer->set_num_unclipped_descendants( + recursive_data->num_unclipped_descendants); + layer->set_num_layer_or_descendant_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); @@ -1243,10 +1266,12 @@ static void PreCalculateMetaInformationInternal( 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_layer_or_descendant_has_input_handler( + (recursive_data->num_layer_or_descendants_with_input_handler != 0)); + // TODO(enne): this should be synced from the main thread, so is only + // for tests constructing layers on the compositor thread. + layer->set_num_layer_or_descendant_with_copy_request( + recursive_data->num_layer_or_descendants_with_copy_request); } void LayerTreeHostCommon::PreCalculateMetaInformation(Layer* root_layer) { @@ -1267,20 +1292,18 @@ void LayerTreeHostCommon::PreCalculateMetaInformationForTesting( PreCalculateMetaInformationInternal(root_layer, &recursive_data); } -template <typename LayerType> struct SubtreeGlobals { int max_texture_size; float device_scale_factor; float page_scale_factor; - const LayerType* page_scale_layer; + const LayerImpl* page_scale_layer; gfx::Vector2dF elastic_overscroll; - const LayerType* elastic_overscroll_application_layer; + const LayerImpl* elastic_overscroll_application_layer; bool can_adjust_raster_scales; bool can_render_to_separate_surface; bool layers_always_allowed_lcd_text; }; -template<typename LayerType> struct DataForRecursion { // The accumulated sequence of transforms a layer will use to determine its // own draw transform. @@ -1297,7 +1320,7 @@ struct DataForRecursion { // The ancestor that would be the container for any fixed-position / sticky // layers. - LayerType* fixed_container; + LayerImpl* fixed_container; // This is the normal clip rect that is propagated from parent to child. gfx::Rect clip_rect_in_target_space; @@ -1313,22 +1336,25 @@ struct DataForRecursion { gfx::Rect clip_rect_of_target_surface_in_target_space; // The maximum amount by which this layer will be scaled during the lifetime - // of currently running animations. + // of currently running animations, considering only scales at keyframes not + // including the starting keyframe of each animation. float maximum_animation_contents_scale; + // The maximum amout by which this layer will be scaled during the lifetime of + // currently running animations, consdering only the starting scale of each + // animation. + float starting_animation_contents_scale; + bool ancestor_is_animating_scale; bool ancestor_clips_subtree; - typename LayerType::RenderSurfaceType* - nearest_occlusion_immune_ancestor_surface; bool in_subtree_of_page_scale_layer; bool subtree_can_use_lcd_text; bool subtree_is_visible_from_ancestor; }; -template <typename LayerType> -static LayerType* GetChildContainingLayer(const LayerType& parent, - LayerType* layer) { - for (LayerType* ancestor = layer; ancestor; ancestor = ancestor->parent()) { +static LayerImpl* GetChildContainingLayer(const LayerImpl& parent, + LayerImpl* layer) { + for (LayerImpl* ancestor = layer; ancestor; ancestor = ancestor->parent()) { if (ancestor->parent() == &parent) return ancestor; } @@ -1336,10 +1362,9 @@ static LayerType* GetChildContainingLayer(const LayerType& parent, return 0; } -template <typename LayerType> -static void AddScrollParentChain(std::vector<LayerType*>* out, - const LayerType& parent, - LayerType* layer) { +static void AddScrollParentChain(std::vector<LayerImpl*>* out, + const LayerImpl& parent, + LayerImpl* layer) { // At a high level, this function walks up the chain of scroll parents // recursively, and once we reach the end of the chain, we add the child // of |parent| containing each scroll ancestor as we unwind. The result is @@ -1367,11 +1392,11 @@ static void AddScrollParentChain(std::vector<LayerType*>* out, // So our first task at this step of the recursion is to determine the layer // that we will potentionally add to the list. That is, the child of parent // containing |layer|. - LayerType* child = GetChildContainingLayer(parent, layer); + LayerImpl* child = GetChildContainingLayer(parent, layer); if (child->sorted_for_recursion()) return; - if (LayerType* scroll_parent = child->scroll_parent()) + if (LayerImpl* scroll_parent = child->scroll_parent()) AddScrollParentChain(out, parent, scroll_parent); out->push_back(child); @@ -1379,13 +1404,12 @@ static void AddScrollParentChain(std::vector<LayerType*>* out, child->set_sorted_for_recursion(sorted_for_recursion); } -template <typename LayerType> -static bool SortChildrenForRecursion(std::vector<LayerType*>* out, - const LayerType& parent) { +static bool SortChildrenForRecursion(std::vector<LayerImpl*>* out, + const LayerImpl& parent) { out->reserve(parent.children().size()); bool order_changed = false; for (size_t i = 0; i < parent.children().size(); ++i) { - LayerType* current = + LayerImpl* current = LayerTreeHostCommon::get_layer_as_raw_ptr(parent.children(), i); if (current->sorted_for_recursion()) { @@ -1400,69 +1424,13 @@ static bool SortChildrenForRecursion(std::vector<LayerType*>* out, return order_changed; } -template <typename LayerType> -static void GetNewDescendantsStartIndexAndCount(LayerType* layer, - size_t* start_index, - size_t* count) { - *start_index = layer->draw_properties().index_of_first_descendants_addition; - *count = layer->draw_properties().num_descendants_added; -} - -template <typename LayerType> -static void GetNewRenderSurfacesStartIndexAndCount(LayerType* layer, - size_t* start_index, - size_t* count) { - *start_index = layer->draw_properties() - .index_of_first_render_surface_layer_list_addition; - *count = layer->draw_properties().num_render_surfaces_added; -} - -// We need to extract a list from the the two flavors of RenderSurfaceListType -// for use in the sorting function below. -static LayerList* GetLayerListForSorting(RenderSurfaceLayerList* rsll) { - return &rsll->AsLayerList(); -} - -static LayerImplList* GetLayerListForSorting(LayerImplList* layer_list) { - return layer_list; -} - -template <typename LayerType, typename GetIndexAndCountType> -static void SortLayerListContributions( - const LayerType& parent, - typename LayerType::LayerListType* unsorted, - size_t start_index_for_all_contributions, - GetIndexAndCountType get_index_and_count) { - typename LayerType::LayerListType buffer; - for (size_t i = 0; i < parent.children().size(); ++i) { - LayerType* child = - LayerTreeHostCommon::get_layer_as_raw_ptr(parent.children(), i); - - size_t start_index = 0; - size_t count = 0; - get_index_and_count(child, &start_index, &count); - for (size_t j = start_index; j < start_index + count; ++j) - buffer.push_back(unsorted->at(j)); - } - - DCHECK_EQ(buffer.size(), - unsorted->size() - start_index_for_all_contributions); - - for (size_t i = 0; i < buffer.size(); ++i) - (*unsorted)[i + start_index_for_all_contributions] = buffer[i]; -} - // Recursively walks the layer tree starting at the given node and computes all // the necessary transformations, clip rects, render surfaces, etc. -template <typename LayerType> static void CalculateDrawPropertiesInternal( - LayerType* layer, - const SubtreeGlobals<LayerType>& globals, - const DataForRecursion<LayerType>& data_from_ancestor, - typename LayerType::RenderSurfaceListType* render_surface_layer_list, - typename LayerType::LayerListType* layer_list, - std::vector<AccumulatedSurfaceState<LayerType>>* accumulated_surface_state, - int current_render_surface_layer_list_id) { + LayerImpl* layer, + const SubtreeGlobals& globals, + const DataForRecursion& data_from_ancestor, + std::vector<AccumulatedSurfaceState>* accumulated_surface_state) { // This function computes the new matrix transformations recursively for this // layer and all its descendants. It also computes the appropriate render // surfaces. @@ -1586,10 +1554,7 @@ static void CalculateDrawPropertiesInternal( bool visited = true; layer->set_visited(visited); - DataForRecursion<LayerType> data_for_children; - typename LayerType::RenderSurfaceType* - nearest_occlusion_immune_ancestor_surface = - data_from_ancestor.nearest_occlusion_immune_ancestor_surface; + DataForRecursion data_for_children; data_for_children.in_subtree_of_page_scale_layer = data_from_ancestor.in_subtree_of_page_scale_layer; data_for_children.subtree_can_use_lcd_text = @@ -1606,9 +1571,6 @@ static void CalculateDrawPropertiesInternal( // The root layer cannot skip CalcDrawProperties. if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_drawn)) { - if (layer->render_surface()) - layer->ClearRenderSurfaceLayerList(); - layer->draw_properties().render_target = nullptr; return; } @@ -1623,14 +1585,14 @@ static void CalculateDrawPropertiesInternal( // Update our clipping state. If we have a clip parent we will need to pull // from the clip state cache rather than using the clip state passed from our // immediate ancestor. - UpdateClipRectsForClipChild<LayerType>( - layer, &ancestor_clip_rect_in_target_space, &ancestor_clips_subtree); + UpdateClipRectsForClipChild(layer, &ancestor_clip_rect_in_target_space, + &ancestor_clips_subtree); // As this function proceeds, these are the properties for the current // layer that actually get computed. To avoid unnecessary copies // (particularly for matrices), we do computations directly on these values // when possible. - DrawProperties<LayerType>& layer_draw_properties = layer->draw_properties(); + DrawProperties& layer_draw_properties = layer->draw_properties(); gfx::Rect clip_rect_in_target_space; bool layer_or_ancestor_clips_descendants = false; @@ -1643,20 +1605,12 @@ static void CalculateDrawPropertiesInternal( gfx::Rect clip_rect_of_target_surface_in_target_space; float accumulated_draw_opacity = layer->opacity(); - bool animating_opacity_to_target = layer->OpacityIsAnimating(); - bool animating_opacity_to_screen = animating_opacity_to_target; - if (layer->parent()) { + if (layer->parent()) accumulated_draw_opacity *= layer->parent()->draw_opacity(); - animating_opacity_to_target |= layer->parent()->draw_opacity_is_animating(); - animating_opacity_to_screen |= - layer->parent()->screen_space_opacity_is_animating(); - } - bool animating_transform_to_target = layer->TransformIsAnimating(); - bool animating_transform_to_screen = animating_transform_to_target; + bool animating_transform_to_screen = + layer->HasPotentiallyRunningTransformAnimation(); if (layer->parent()) { - animating_transform_to_target |= - layer->parent()->draw_transform_is_animating(); animating_transform_to_screen |= layer->parent()->screen_space_transform_is_animating(); } @@ -1681,7 +1635,7 @@ static void CalculateDrawPropertiesInternal( } gfx::Vector2dF effective_scroll_delta = GetEffectiveScrollDelta(layer); - if (!animating_transform_to_target && layer->scrollable() && + if (!animating_transform_to_screen && layer->scrollable() && combined_transform.IsScaleOrTranslation()) { // Align the scrollable layer's position to screen space pixels to avoid // blurriness. To avoid side-effects, do this only if the transform is @@ -1715,6 +1669,7 @@ static void CalculateDrawPropertiesInternal( CalculateAnimationContentsScale( layer, data_from_ancestor.ancestor_is_animating_scale, data_from_ancestor.maximum_animation_contents_scale, + data_from_ancestor.starting_animation_contents_scale, data_from_ancestor.parent_matrix, combined_transform, &combined_is_animating_scale, &combined_maximum_animation_contents_scale, @@ -1723,6 +1678,8 @@ static void CalculateDrawPropertiesInternal( data_for_children.ancestor_is_animating_scale = combined_is_animating_scale; data_for_children.maximum_animation_contents_scale = combined_maximum_animation_contents_scale; + data_for_children.starting_animation_contents_scale = + combined_starting_animation_contents_scale; // Compute the 2d scale components of the transform hierarchy up to the target // surface. From there, we can decide on a contents scale for the layer. @@ -1738,14 +1695,14 @@ static void CalculateDrawPropertiesInternal( combined_maximum_animation_contents_scale, combined_starting_animation_contents_scale); - LayerType* mask_layer = layer->mask_layer(); + LayerImpl* mask_layer = layer->mask_layer(); if (mask_layer) { UpdateLayerScaleDrawProperties(mask_layer, combined_maximum_animation_contents_scale, combined_starting_animation_contents_scale); } - LayerType* replica_mask_layer = + LayerImpl* replica_mask_layer = layer->replica_layer() ? layer->replica_layer()->mask_layer() : NULL; if (replica_mask_layer) { UpdateLayerScaleDrawProperties(replica_mask_layer, @@ -1800,27 +1757,18 @@ static void CalculateDrawPropertiesInternal( DCHECK(layer->render_surface()); // Check back-face visibility before continuing with this surface and its // subtree - if (!layer->double_sided() && TransformToParentIsKnown(layer) && + if (!layer->double_sided() && IsSurfaceBackFaceVisible(layer, combined_transform)) { - layer->ClearRenderSurfaceLayerList(); - layer->draw_properties().render_target = nullptr; return; } - typename LayerType::RenderSurfaceType* render_surface = - layer->render_surface(); - layer->ClearRenderSurfaceLayerList(); + RenderSurfaceImpl* render_surface = layer->render_surface(); - 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 // forward top-level transforms to the rest of the tree. data_for_children.parent_matrix = combined_transform; - - // The root surface does not contribute to any other surface, it has no - // target. - layer->render_surface()->set_contributes_to_drawn_surface(false); } else { // The owning layer's draw transform has a scale from content to layer // space which we do not want; so here we use the combined_transform @@ -1848,31 +1796,14 @@ static void CalculateDrawPropertiesInternal( DCHECK(data_for_children.parent_matrix.IsIdentity()); 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|. - layer->render_surface()->set_contributes_to_drawn_surface( - layer_is_visible); } // The opacity value is moved from the layer to its surface, so that the // entire subtree properly inherits opacity. render_surface->SetDrawOpacity(accumulated_draw_opacity); - 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; - - render_surface->SetTargetSurfaceTransformsAreAnimating( - animating_transform_to_target); - render_surface->SetScreenSpaceTransformsAreAnimating( - animating_transform_to_screen); - animating_transform_to_target = false; - layer_draw_properties.target_space_transform_is_animating = - animating_transform_to_target; + DCHECK_EQ(layer->draw_blend_mode(), SkXfermode::kSrcOver_Mode); + layer_draw_properties.screen_space_transform_is_animating = animating_transform_to_screen; @@ -1886,9 +1817,8 @@ static void CalculateDrawPropertiesInternal( data_for_children.full_hierarchy_matrix.FlattenTo2d(); if (layer->mask_layer()) { - DrawProperties<LayerType>& mask_layer_draw_properties = + DrawProperties& mask_layer_draw_properties = layer->mask_layer()->draw_properties(); - mask_layer_draw_properties.render_target = layer; mask_layer_draw_properties.visible_layer_rect = gfx::Rect(layer->bounds()); // Temporarily copy the draw transform of the mask's owning layer into the @@ -1901,51 +1831,37 @@ static void CalculateDrawPropertiesInternal( } if (layer->replica_layer() && layer->replica_layer()->mask_layer()) { - DrawProperties<LayerType>& replica_mask_draw_properties = + DrawProperties& replica_mask_draw_properties = layer->replica_layer()->mask_layer()->draw_properties(); - replica_mask_draw_properties.render_target = layer; replica_mask_draw_properties.visible_layer_rect = gfx::Rect(layer->bounds()); replica_mask_draw_properties.target_space_transform = layer_draw_properties.target_space_transform; } - // Ignore occlusion from outside the surface when surface contents need to - // be fully drawn. Layers with copy-request need to be complete. - // We could be smarter about layers with replica and exclude regions - // where both layer and the replica are occluded, but this seems like an - // overkill. The same is true for layers with filters that move pixels. - // TODO(senorblanco): make this smarter for the SkImageFilter case (check - // for pixel-moving filters) - if (layer->HasCopyRequest() || - layer->has_replica() || - layer->filters().HasReferenceFilter() || - layer->filters().HasFilterThatMovesPixels()) { - nearest_occlusion_immune_ancestor_surface = render_surface; - } - render_surface->SetNearestOcclusionImmuneAncestor( - nearest_occlusion_immune_ancestor_surface); - layer_or_ancestor_clips_descendants = false; bool subtree_is_clipped_by_surface_bounds = false; - if (ancestor_clips_subtree) { - // It may be the layer or the surface doing the clipping of the subtree, - // but in either case, we'll be clipping to the projected clip rect of our - // ancestor. - gfx::Transform inverse_surface_draw_transform( - gfx::Transform::kSkipInitialization); - if (!render_surface->draw_transform().GetInverse( - &inverse_surface_draw_transform)) { - // TODO(shawnsingh): Either we need to handle uninvertible transforms - // here, or DCHECK that the transform is invertible. - } + // It may be the layer or the surface doing the clipping of the subtree, + // but in either case, we'll be clipping to the projected clip rect of our + // ancestor. + gfx::Transform inverse_surface_draw_transform( + gfx::Transform::kSkipInitialization); + if (!render_surface->draw_transform().GetInverse( + &inverse_surface_draw_transform)) { + // TODO(shawnsingh): Either we need to handle uninvertible transforms + // here, or DCHECK that the transform is invertible. + } - gfx::Rect surface_clip_rect_in_target_space = gfx::IntersectRects( - data_from_ancestor.clip_rect_of_target_surface_in_target_space, + gfx::Rect surface_clip_rect_in_target_space = + data_from_ancestor.clip_rect_of_target_surface_in_target_space; + if (ancestor_clips_subtree) + surface_clip_rect_in_target_space.Intersect( ancestor_clip_rect_in_target_space); - gfx::Rect projected_surface_rect = MathUtil::ProjectEnclosingClippedRect( - inverse_surface_draw_transform, surface_clip_rect_in_target_space); + gfx::Rect projected_surface_rect = MathUtil::ProjectEnclosingClippedRect( + inverse_surface_draw_transform, surface_clip_rect_in_target_space); + clip_rect_of_target_surface_in_target_space = projected_surface_rect; + if (ancestor_clips_subtree) { if (layer_draw_properties.num_unclipped_descendants > 0u) { // If we have unclipped descendants, we cannot count on the render // surface's bounds clipping our subtree: the unclipped descendants @@ -1964,7 +1880,6 @@ static void CalculateDrawPropertiesInternal( // expressed in the space where this surface draws, i.e. the same space // as clip_rect_from_ancestor_in_ancestor_target_space. render_surface->SetClipRect(ancestor_clip_rect_in_target_space); - clip_rect_of_target_surface_in_target_space = projected_surface_rect; subtree_is_clipped_by_surface_bounds = true; } } @@ -1973,14 +1888,11 @@ static void CalculateDrawPropertiesInternal( DCHECK(!layer->parent() || layer->parent()->render_target() == accumulated_surface_state->back().render_target); - accumulated_surface_state->push_back( - AccumulatedSurfaceState<LayerType>(layer)); + accumulated_surface_state->push_back(AccumulatedSurfaceState(layer)); render_surface->SetIsClipped(subtree_is_clipped_by_surface_bounds); if (!subtree_is_clipped_by_surface_bounds) { render_surface->SetClipRect(gfx::Rect()); - clip_rect_of_target_surface_in_target_space = - data_from_ancestor.clip_rect_of_target_surface_in_target_space; } // If the new render surface is drawn translucent or with a non-integral @@ -1988,21 +1900,15 @@ static void CalculateDrawPropertiesInternal( // cannot use LCD text. data_for_children.subtree_can_use_lcd_text = subtree_can_use_lcd_text; - render_surface_layer_list->push_back(layer); } else { DCHECK(layer->parent()); // Note: layer_draw_properties.target_space_transform is computed above, // before this if-else statement. - layer_draw_properties.target_space_transform_is_animating = - animating_transform_to_target; 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; + DCHECK_EQ(layer->draw_blend_mode(), layer->blend_mode()); data_for_children.parent_matrix = combined_transform; // Layers without render_surfaces directly inherit the ancestor's clip @@ -2017,10 +1923,6 @@ static void CalculateDrawPropertiesInternal( // clipping goes on between layers here. clip_rect_of_target_surface_in_target_space = data_from_ancestor.clip_rect_of_target_surface_in_target_space; - - // Layers that are not their own render_target will render into the target - // of their nearest ancestor. - layer_draw_properties.render_target = layer->parent()->render_target(); } layer_draw_properties.can_use_lcd_text = layer_can_use_lcd_text; @@ -2056,26 +1958,6 @@ static void CalculateDrawPropertiesInternal( layer_draw_properties.clip_rect = rect_in_target_space; } - typename LayerType::LayerListType& descendants = - (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. - size_t sorting_start_index = descendants.size(); - - if (!LayerShouldBeSkipped(layer, layer_is_drawn)) { - MarkLayerWithRenderSurfaceLayerListId(layer, - current_render_surface_layer_list_id); - descendants.push_back(layer); - } - - // Any layers that are appended after this point may need to be sorted if we - // visit the children out of order. - size_t render_surface_layer_list_child_sorting_start_index = - render_surface_layer_list->size(); - size_t layer_list_child_sorting_start_index = descendants.size(); - if (!layer->children().empty()) { if (layer == globals.elastic_overscroll_application_layer) { data_for_children.parent_matrix.Translate( @@ -2101,58 +1983,26 @@ static void CalculateDrawPropertiesInternal( clip_rect_of_target_surface_in_target_space; data_for_children.ancestor_clips_subtree = layer_or_ancestor_clips_descendants; - data_for_children.nearest_occlusion_immune_ancestor_surface = - nearest_occlusion_immune_ancestor_surface; data_for_children.subtree_is_visible_from_ancestor = layer_is_drawn; } - std::vector<LayerType*> sorted_children; - bool child_order_changed = false; + std::vector<LayerImpl*> sorted_children; if (layer_draw_properties.has_child_with_a_scroll_parent) - child_order_changed = SortChildrenForRecursion(&sorted_children, *layer); + SortChildrenForRecursion(&sorted_children, *layer); for (size_t i = 0; i < layer->children().size(); ++i) { // If one of layer's children has a scroll parent, then we may have to // visit the children out of order. The new order is stored in // sorted_children. Otherwise, we'll grab the child directly from the // layer's list of children. - LayerType* child = + + LayerImpl* child = layer_draw_properties.has_child_with_a_scroll_parent ? sorted_children[i] : LayerTreeHostCommon::get_layer_as_raw_ptr(layer->children(), i); - child->draw_properties().index_of_first_descendants_addition = - descendants.size(); - child->draw_properties().index_of_first_render_surface_layer_list_addition = - render_surface_layer_list->size(); - - CalculateDrawPropertiesInternal<LayerType>( - child, - globals, - data_for_children, - render_surface_layer_list, - &descendants, - accumulated_surface_state, - current_render_surface_layer_list_id); - // 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 - // we need to mark just the mask layer (and replica mask layer) - // with the id. - MarkMasksWithRenderSurfaceLayerListId( - child, current_render_surface_layer_list_id); - descendants.push_back(child); - } - - child->draw_properties().num_descendants_added = - descendants.size() - - child->draw_properties().index_of_first_descendants_addition; - child->draw_properties().num_render_surfaces_added = - render_surface_layer_list->size() - - child->draw_properties() - .index_of_first_render_surface_layer_list_addition; + CalculateDrawPropertiesInternal(child, globals, data_for_children, + accumulated_surface_state); if (child->layer_or_descendant_is_drawn()) { bool layer_or_descendant_is_drawn = true; @@ -2160,21 +2010,6 @@ static void CalculateDrawPropertiesInternal( } } - // Add the unsorted layer list contributions, if necessary. - if (child_order_changed) { - SortLayerListContributions( - *layer, - GetLayerListForSorting(render_surface_layer_list), - render_surface_layer_list_child_sorting_start_index, - &GetNewRenderSurfacesStartIndexAndCount<LayerType>); - - SortLayerListContributions( - *layer, - &descendants, - layer_list_child_sorting_start_index, - &GetNewDescendantsStartIndexAndCount<LayerType>); - } - // Compute the total drawable_content_rect for this subtree (the rect is in // target surface space). gfx::Rect local_drawable_content_rect_of_subtree = @@ -2184,12 +2019,6 @@ static void CalculateDrawPropertiesInternal( accumulated_surface_state->pop_back(); } - if (render_to_separate_surface && !IsRootLayer(layer) && - layer->render_surface()->layer_list().empty()) { - RemoveSurfaceForEarlyExit(layer, render_surface_layer_list); - return; - } - // Compute the layer's drawable content rect (the rect is in target surface // space). layer_draw_properties.drawable_content_rect = rect_in_target_space; @@ -2214,15 +2043,12 @@ static void CalculateDrawPropertiesInternal( layer->render_surface()->SetContentRect( ancestor_clip_rect_in_target_space); } else if (render_to_separate_surface) { - typename LayerType::RenderSurfaceType* render_surface = - layer->render_surface(); + RenderSurfaceImpl* render_surface = layer->render_surface(); gfx::Rect clipped_content_rect = local_drawable_content_rect_of_subtree; // Don't clip if the layer is reflected as the reflection shouldn't be - // clipped. If the layer is animating, then the surface's transform to - // its target is not known on the main thread, and we should not use it - // to clip. - if (!layer->replica_layer() && TransformToParentIsKnown(layer)) { + // clipped. + if (!layer->replica_layer()) { // Note, it is correct to use data_from_ancestor.ancestor_clips_subtree // here, because we are looking at this layer's render_surface, not the // layer itself. @@ -2242,11 +2068,6 @@ static void CalculateDrawPropertiesInternal( clipped_content_rect.set_height( std::min(clipped_content_rect.height(), globals.max_texture_size)); - if (clipped_content_rect.IsEmpty()) { - RemoveSurfaceForEarlyExit(layer, render_surface_layer_list); - return; - } - // Layers having a non-default blend mode will blend with the content // inside its parent's render target. This render target should be // either root_for_isolated_group, or the root of the layer tree. @@ -2259,6 +2080,10 @@ static void CalculateDrawPropertiesInternal( render_surface->SetContentRect(clipped_content_rect); + if (clipped_content_rect.IsEmpty()) { + return; + } + // The owning layer's screen_space_transform has a scale from content to // layer space which we need to undo and replace with a scale from the // surface's subtree into layer space. @@ -2304,28 +2129,14 @@ static void CalculateDrawPropertiesInternal( SavePaintPropertiesLayer(layer); - // If neither this layer nor any of its children were added, early out. - if (sorting_start_index == descendants.size()) { - DCHECK(!render_to_separate_surface || IsRootLayer(layer)); - return; - } - - UpdateAccumulatedSurfaceState<LayerType>( - layer, local_drawable_content_rect_of_subtree, accumulated_surface_state); - - if (layer->HasContributingDelegatedRenderPasses()) { - layer->render_target()->render_surface()-> - AddContributingDelegatedRenderPassLayer(layer); - } + UpdateAccumulatedSurfaceState(layer, local_drawable_content_rect_of_subtree, + accumulated_surface_state); } // NOLINT(readability/fn_size) -template <typename LayerType, typename RenderSurfaceLayerListType> static void ProcessCalcDrawPropsInputs( - const LayerTreeHostCommon::CalcDrawPropsInputs<LayerType, - RenderSurfaceLayerListType>& - inputs, - SubtreeGlobals<LayerType>* globals, - DataForRecursion<LayerType>* data_for_recursion) { + const LayerTreeHostCommon::CalcDrawPropsImplInputs& inputs, + SubtreeGlobals* globals, + DataForRecursion* data_for_recursion) { DCHECK(inputs.root_layer); DCHECK(IsRootLayer(inputs.root_layer)); DCHECK(inputs.render_surface_layer_list); @@ -2369,9 +2180,9 @@ static void ProcessCalcDrawPropsInputs( data_for_recursion->clip_rect_of_target_surface_in_target_space = device_viewport_rect; data_for_recursion->maximum_animation_contents_scale = 0.f; + data_for_recursion->starting_animation_contents_scale = 0.f; data_for_recursion->ancestor_is_animating_scale = false; data_for_recursion->ancestor_clips_subtree = true; - data_for_recursion->nearest_occlusion_immune_ancestor_surface = NULL; data_for_recursion->in_subtree_of_page_scale_layer = false; data_for_recursion->subtree_can_use_lcd_text = inputs.can_use_lcd_text; data_for_recursion->subtree_is_visible_from_ancestor = true; @@ -2391,15 +2202,10 @@ void LayerTreeHostCommon::UpdateRenderSurface( // 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( @@ -2422,13 +2228,7 @@ void LayerTreeHostCommon::UpdateRenderSurfaces( 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; + static const int tolerance = 1; return std::abs(r1.x() - r2.x()) <= tolerance && std::abs(r1.y() - r2.y()) <= tolerance && @@ -2458,44 +2258,108 @@ static bool ApproximatelyEqual(const gfx::Transform& a, return true; } +void VerifyPropertyTreeValuesForSurface(RenderSurfaceImpl* render_surface, + PropertyTrees* property_trees) { + RenderSurfaceDrawProperties draw_properties; + ComputeSurfaceDrawPropertiesUsingPropertyTrees(render_surface, property_trees, + &draw_properties); + + // content_rect has to be computed recursively, so is computed separately from + // other draw properties. + draw_properties.content_rect = + render_surface->content_rect_from_property_trees(); + + const bool render_surface_draw_transforms_match = ApproximatelyEqual( + render_surface->draw_transform(), draw_properties.draw_transform); + CHECK(render_surface_draw_transforms_match) + << "expected: " << render_surface->draw_transform().ToString() + << " actual: " << draw_properties.draw_transform.ToString(); + + const bool render_surface_screen_space_transform_match = + ApproximatelyEqual(render_surface->screen_space_transform(), + draw_properties.screen_space_transform); + CHECK(render_surface_screen_space_transform_match) + << "expected: " << render_surface->screen_space_transform().ToString() + << " actual: " << draw_properties.screen_space_transform.ToString(); + + const bool render_surface_replica_draw_transforms_match = + ApproximatelyEqual(render_surface->replica_draw_transform(), + draw_properties.replica_draw_transform); + CHECK(render_surface_replica_draw_transforms_match) + << "expected: " << render_surface->replica_draw_transform().ToString() + << " actual: " << draw_properties.replica_draw_transform.ToString(); + + const bool render_surface_replica_screen_space_transforms_match = + ApproximatelyEqual(render_surface->replica_screen_space_transform(), + draw_properties.replica_screen_space_transform); + CHECK(render_surface_replica_screen_space_transforms_match) + << "expected: " + << render_surface->replica_screen_space_transform().ToString() + << " actual: " + << draw_properties.replica_screen_space_transform.ToString(); + + CHECK_EQ(render_surface->is_clipped(), draw_properties.is_clipped); + + const bool render_surface_clip_rects_match = ApproximatelyEqual( + render_surface->clip_rect(), draw_properties.clip_rect); + CHECK(render_surface_clip_rects_match) + << "expected: " << render_surface->clip_rect().ToString() + << " actual: " << draw_properties.clip_rect.ToString(); + + CHECK_EQ(render_surface->draw_opacity(), draw_properties.draw_opacity); + + const bool render_surface_content_rects_match = ApproximatelyEqual( + render_surface->content_rect(), draw_properties.content_rect); + CHECK(render_surface_content_rects_match) + << "expected: " << render_surface->content_rect().ToString() + << " actual: " << draw_properties.content_rect.ToString(); +} + void VerifyPropertyTreeValuesForLayer(LayerImpl* current_layer, PropertyTrees* property_trees, bool layers_always_allowed_lcd_text, bool can_use_lcd_text) { - const bool visible_rects_match = - ApproximatelyEqual(current_layer->visible_layer_rect(), - current_layer->visible_rect_from_property_trees()); + DrawProperties draw_properties; + ComputeLayerDrawPropertiesUsingPropertyTrees( + current_layer, property_trees, layers_always_allowed_lcd_text, + can_use_lcd_text, &draw_properties); + + const bool visible_rects_match = ApproximatelyEqual( + current_layer->visible_layer_rect(), draw_properties.visible_layer_rect); CHECK(visible_rects_match) << "expected: " << current_layer->visible_layer_rect().ToString() - << " actual: " - << current_layer->visible_rect_from_property_trees().ToString(); + << " actual: " << draw_properties.visible_layer_rect.ToString(); - const bool draw_transforms_match = - ApproximatelyEqual(current_layer->draw_transform(), - DrawTransformFromPropertyTrees( - current_layer, property_trees->transform_tree)); + const bool draw_transforms_match = ApproximatelyEqual( + current_layer->draw_transform(), draw_properties.target_space_transform); CHECK(draw_transforms_match) << "expected: " << current_layer->draw_transform().ToString() - << " actual: " - << DrawTransformFromPropertyTrees( - current_layer, property_trees->transform_tree).ToString(); - - const bool draw_opacities_match = - current_layer->draw_opacity() == - DrawOpacityFromPropertyTrees(current_layer, property_trees->opacity_tree); - CHECK(draw_opacities_match) - << "expected: " << current_layer->draw_opacity() - << " actual: " << DrawOpacityFromPropertyTrees( - current_layer, property_trees->opacity_tree); - const bool can_use_lcd_text_match = - CanUseLcdTextFromPropertyTrees( - current_layer, layers_always_allowed_lcd_text, can_use_lcd_text, - property_trees) == current_layer->can_use_lcd_text(); - CHECK(can_use_lcd_text_match); -} - -void VerifyPropertyTreeValues( - LayerTreeHostCommon::CalcDrawPropsMainInputs* inputs) { + << " actual: " << draw_properties.target_space_transform.ToString(); + + CHECK_EQ(current_layer->draw_opacity(), draw_properties.opacity); + CHECK_EQ(current_layer->can_use_lcd_text(), draw_properties.can_use_lcd_text); + CHECK_EQ(current_layer->is_clipped(), draw_properties.is_clipped); + CHECK_EQ(current_layer->screen_space_transform_is_animating(), + draw_properties.screen_space_transform_is_animating); + + const bool drawable_content_rects_match = + ApproximatelyEqual(current_layer->drawable_content_rect(), + draw_properties.drawable_content_rect); + CHECK(drawable_content_rects_match) + << "expected: " << current_layer->drawable_content_rect().ToString() + << " actual: " << draw_properties.drawable_content_rect.ToString(); + + const bool clip_rects_match = + ApproximatelyEqual(current_layer->clip_rect(), draw_properties.clip_rect); + CHECK(clip_rects_match) << "expected: " + << current_layer->clip_rect().ToString() + << " actual: " + << draw_properties.clip_rect.ToString(); + + CHECK_EQ(current_layer->draw_properties().maximum_animation_contents_scale, + draw_properties.maximum_animation_contents_scale); + CHECK_EQ(current_layer->draw_properties().starting_animation_contents_scale, + draw_properties.starting_animation_contents_scale); } void VerifyPropertyTreeValues( @@ -2505,6 +2369,9 @@ void VerifyPropertyTreeValues( end = LayerIterator::End(inputs->render_surface_layer_list); it != end; ++it) { LayerImpl* current_layer = *it; + if (it.represents_target_render_surface()) + VerifyPropertyTreeValuesForSurface(current_layer->render_surface(), + inputs->property_trees); if (!it.represents_itself() || !current_layer->DrawsContent()) continue; VerifyPropertyTreeValuesForLayer(current_layer, inputs->property_trees, @@ -2518,14 +2385,286 @@ enum PropertyTreeOption { 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; +void CalculateRenderTargetInternal(LayerImpl* layer, + bool subtree_visible_from_ancestor, + bool can_render_to_separate_surface) { + const bool layer_is_visible = + subtree_visible_from_ancestor && !layer->hide_layer_and_subtree(); + const bool layer_is_drawn = layer_is_visible || layer->HasCopyRequest(); + + // The root layer cannot be skipped. + if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_drawn)) { + layer->draw_properties().render_target = nullptr; + return; + } + + bool render_to_separate_surface = + IsRootLayer(layer) || + (can_render_to_separate_surface && layer->render_surface()); + + if (render_to_separate_surface) { + DCHECK(layer->render_surface()); + layer->draw_properties().render_target = layer; + + if (layer->mask_layer()) + layer->mask_layer()->draw_properties().render_target = layer; + + if (layer->replica_layer() && layer->replica_layer()->mask_layer()) + layer->replica_layer()->mask_layer()->draw_properties().render_target = + layer; + + } else { + DCHECK(layer->parent()); + layer->draw_properties().render_target = layer->parent()->render_target(); + } + + for (size_t i = 0; i < layer->children().size(); ++i) { + CalculateRenderTargetInternal( + LayerTreeHostCommon::get_layer_as_raw_ptr(layer->children(), i), + layer_is_drawn, can_render_to_separate_surface); + } +} + +void CalculateRenderSurfaceLayerListInternal( + LayerImpl* layer, + PropertyTrees* property_trees, + LayerImplList* render_surface_layer_list, + LayerImplList* descendants, + RenderSurfaceImpl* nearest_occlusion_immune_ancestor, + bool subtree_visible_from_ancestor, + const bool can_render_to_separate_surface, + const int current_render_surface_layer_list_id, + const bool verify_property_trees) { + // This calculates top level Render Surface Layer List, and Layer List for all + // Render Surfaces. + + // |layer| is current layer. + + // |render_surface_layer_list| is the top level RenderSurfaceLayerList. + + // |descendants| is used to determine what's in current layer's render + // surface's layer list. + + // |subtree_visible_from_ancestor| is set during recursion to affect current + // layer's subtree. + + // |can_render_to_separate_surface| and |current_render_surface_layer_list_id| + // are settings that should stay the same during recursion. + + // Layers that are marked as hidden will hide themselves and their subtree. + // Exception: Layers with copy requests, whether hidden or not, must be drawn + // anyway. In this case, we will inform their subtree they are visible to get + // the right results. + const bool layer_is_visible = + subtree_visible_from_ancestor && !layer->hide_layer_and_subtree(); + const bool layer_is_drawn = layer_is_visible || layer->HasCopyRequest(); + + // The root layer cannot be skipped. + if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_drawn)) { + if (layer->render_surface()) + layer->ClearRenderSurfaceLayerList(); + layer->draw_properties().render_target = nullptr; + return; + } + + bool render_to_separate_surface = + IsRootLayer(layer) || + (can_render_to_separate_surface && layer->render_surface()); + + if (render_to_separate_surface) { + DCHECK(layer->render_surface()); + if (!layer->double_sided() && + IsSurfaceBackFaceVisible(layer, layer->draw_transform())) { + layer->ClearRenderSurfaceLayerList(); + layer->draw_properties().render_target = nullptr; + return; + } + if (IsRootLayer(layer)) { + // The root surface does not contribute to any other surface, it has no + // target. + layer->render_surface()->set_contributes_to_drawn_surface(false); + } else { + // Even if the |layer_is_drawn|, it only contributes to a drawn surface + // when the |layer_is_visible|. + layer->render_surface()->set_contributes_to_drawn_surface( + layer_is_visible); + } + + // Ignore occlusion from outside the surface when surface contents need to + // be fully drawn. Layers with copy-request need to be complete. + // We could be smarter about layers with replica and exclude regions + // where both layer and the replica are occluded, but this seems like an + // overkill. The same is true for layers with filters that move pixels. + // TODO(senorblanco): make this smarter for the SkImageFilter case (check + // for pixel-moving filters) + if (layer->HasCopyRequest() || layer->has_replica() || + layer->filters().HasReferenceFilter() || + layer->filters().HasFilterThatMovesPixels()) { + nearest_occlusion_immune_ancestor = layer->render_surface(); + } + layer->render_surface()->SetNearestOcclusionImmuneAncestor( + nearest_occlusion_immune_ancestor); + layer->ClearRenderSurfaceLayerList(); + + render_surface_layer_list->push_back(layer); + + descendants = &(layer->render_surface()->layer_list()); + } + + size_t descendants_size = descendants->size(); + + bool layer_should_be_skipped = LayerShouldBeSkipped(layer, layer_is_drawn); + if (!layer_should_be_skipped) { + MarkLayerWithRenderSurfaceLayerListId(layer, + current_render_surface_layer_list_id); + descendants->push_back(layer); + } + + // The render surface's content rect is the union of drawable content rects + // of the layers that draw into the surface. If the render surface is clipped, + // it is also intersected with the render's surface clip rect. + if (verify_property_trees) { + if (render_to_separate_surface) { + if (IsRootLayer(layer)) { + // The root layer's surface content rect is always the entire viewport. + gfx::Rect viewport = + gfx::ToEnclosingRect(property_trees->clip_tree.ViewportClip()); + layer->render_surface()->SetAccumulatedContentRect(viewport); + } else { + // If the owning layer of a render surface draws content, the content + // rect of the render surface is initialized to the drawable content + // rect of the layer. + gfx::Rect content_rect = layer->DrawsContent() + ? layer->drawable_content_rect() + : gfx::Rect(); + layer->render_surface()->SetAccumulatedContentRect(content_rect); + } + } else if (!layer_should_be_skipped && + !IsRootLayer(layer->render_target())) { + // In this case, the layer's drawable content rect can expand the + // content rect of the render surface it is drawing into. + gfx::Rect surface_content_rect = + layer->render_target()->render_surface()->accumulated_content_rect(); + surface_content_rect.Union(layer->drawable_content_rect()); + layer->render_target()->render_surface()->SetAccumulatedContentRect( + surface_content_rect); + } + } + + for (auto& child_layer : layer->children()) { + CalculateRenderSurfaceLayerListInternal( + child_layer, property_trees, render_surface_layer_list, descendants, + nearest_occlusion_immune_ancestor, layer_is_drawn, + can_render_to_separate_surface, current_render_surface_layer_list_id, + verify_property_trees); + + // If the child is its own render target, then it has a render surface. + if (child_layer->render_target() == child_layer && + !child_layer->render_surface()->layer_list().empty() && + !child_layer->render_surface()->content_rect().IsEmpty()) { + // This child will contribute its render surface, which means + // we need to mark just the mask layer (and replica mask layer) + // with the id. + MarkMasksWithRenderSurfaceLayerListId( + child_layer, current_render_surface_layer_list_id); + descendants->push_back(child_layer); + } + + if (child_layer->layer_or_descendant_is_drawn()) { + bool layer_or_descendant_is_drawn = true; + layer->set_layer_or_descendant_is_drawn(layer_or_descendant_is_drawn); + } + } + + if (render_to_separate_surface && !IsRootLayer(layer) && + layer->render_surface()->layer_list().empty()) { + RemoveSurfaceForEarlyExit(layer, render_surface_layer_list); + return; + } + + if (verify_property_trees && render_to_separate_surface && + !IsRootLayer(layer)) { + if (!layer->replica_layer() && layer->render_surface()->is_clipped()) { + // Here, we clip the render surface's content rect with its clip rect. + // As the clip rect of render surface is in the surface's target space, + // we first map the content rect into the target space, intersect it with + // clip rect and project back the result to the surface space. + gfx::Rect surface_content_rect = + layer->render_surface()->accumulated_content_rect(); + + if (!surface_content_rect.IsEmpty()) { + gfx::Rect surface_clip_rect = LayerTreeHostCommon::CalculateVisibleRect( + layer->render_surface()->clip_rect(), surface_content_rect, + layer->render_surface()->draw_transform()); + surface_content_rect.Intersect(surface_clip_rect); + layer->render_surface()->SetAccumulatedContentRect( + surface_content_rect); + } + } + layer->render_surface()->SetContentRectFromPropertyTrees( + layer->render_surface()->accumulated_content_rect()); + if (!IsRootLayer(layer->parent()->render_target())) { + // The surface's drawable content rect may expand the content rect + // of its target's surface(surface's target's surface). + gfx::Rect surface_target_rect = layer->parent() + ->render_target() + ->render_surface() + ->accumulated_content_rect(); + surface_target_rect.Union( + gfx::ToEnclosedRect(layer->render_surface()->DrawableContentRect())); + layer->parent() + ->render_target() + ->render_surface() + ->SetAccumulatedContentRect(surface_target_rect); + } + } + + if (verify_property_trees && IsRootLayer(layer)) + layer->render_surface()->SetContentRectFromPropertyTrees( + layer->render_surface()->accumulated_content_rect()); + + if (render_to_separate_surface && !IsRootLayer(layer) && + layer->render_surface()->content_rect().IsEmpty()) { + RemoveSurfaceForEarlyExit(layer, render_surface_layer_list); + return; + } + + // If neither this layer nor any of its children were added, early out. + if (descendants_size == descendants->size()) { + DCHECK(!render_to_separate_surface || IsRootLayer(layer)); + return; + } + + if (layer->HasContributingDelegatedRenderPasses()) { + layer->render_target() + ->render_surface() + ->AddContributingDelegatedRenderPassLayer(layer); + } +} + +void CalculateRenderTarget( + LayerTreeHostCommon::CalcDrawPropsImplInputs* inputs) { + CalculateRenderTargetInternal(inputs->root_layer, true, + inputs->can_render_to_separate_surface); +} + +void CalculateRenderSurfaceLayerList( + LayerTreeHostCommon::CalcDrawPropsImplInputs* inputs) { + const bool subtree_visible_from_ancestor = true; + CalculateRenderSurfaceLayerListInternal( + inputs->root_layer, inputs->property_trees, + inputs->render_surface_layer_list, nullptr, nullptr, + subtree_visible_from_ancestor, inputs->can_render_to_separate_surface, + inputs->current_render_surface_layer_list_id, + inputs->verify_property_trees); +} + +void CalculateDrawPropertiesAndVerify( + LayerTreeHostCommon::CalcDrawPropsImplInputs* inputs, + PropertyTreeOption property_tree_option) { + SubtreeGlobals globals; + DataForRecursion data_for_recursion; + inputs->render_surface_layer_list->clear(); ProcessCalcDrawPropsInputs(*inputs, &globals, &data_for_recursion); UpdateMetaInformationSequenceNumber(inputs->root_layer); @@ -2536,28 +2675,9 @@ void CalculateDrawPropertiesAndVerify(LayerTreeHostCommon::CalcDrawPropsInputs< 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"); - } - - 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; + LayerImplList 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 @@ -2594,12 +2714,28 @@ void CalculateDrawPropertiesAndVerify(LayerTreeHostCommon::CalcDrawPropsInputs< break; } } + } - VerifyPropertyTreeValues(inputs); + if (should_measure_property_tree_performance) { + TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), + "LayerTreeHostCommon::CalculateDrawProperties"); } - // The dummy layer list should not have been used. - DCHECK_EQ(0u, dummy_layer_list.size()); + std::vector<AccumulatedSurfaceState> accumulated_surface_state; + CalculateRenderTarget(inputs); + CalculateDrawPropertiesInternal(inputs->root_layer, globals, + data_for_recursion, + &accumulated_surface_state); + CalculateRenderSurfaceLayerList(inputs); + + if (should_measure_property_tree_performance) { + TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"), + "LayerTreeHostCommon::CalculateDrawProperties"); + } + + if (inputs->verify_property_trees) + VerifyPropertyTreeValues(inputs); + // A root layer render_surface should always exist after // CalculateDrawProperties. DCHECK(inputs->root_layer->render_surface()); @@ -2607,10 +2743,18 @@ void CalculateDrawPropertiesAndVerify(LayerTreeHostCommon::CalcDrawPropsInputs< 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); + LayerList update_layer_list; + bool can_render_to_separate_surface = true; + UpdateRenderSurfaces(inputs->root_layer, can_render_to_separate_surface, + gfx::Transform(), false); + PropertyTrees* property_trees = + inputs->root_layer->layer_tree_host()->property_trees(); + BuildPropertyTreesAndComputeVisibleRects( + inputs->root_layer, inputs->page_scale_layer, + inputs->inner_viewport_scroll_layer, inputs->outer_viewport_scroll_layer, + inputs->page_scale_factor, inputs->device_scale_factor, + gfx::Rect(inputs->device_viewport_size), inputs->device_transform, + property_trees, &update_layer_list); } void LayerTreeHostCommon::CalculateDrawProperties( diff --git a/chromium/cc/trees/layer_tree_host_common.h b/chromium/cc/trees/layer_tree_host_common.h index bf62111acbe..814833db812 100644 --- a/chromium/cc/trees/layer_tree_host_common.h +++ b/chromium/cc/trees/layer_tree_host_common.h @@ -31,89 +31,86 @@ class CC_EXPORT LayerTreeHostCommon { const gfx::Rect& layer_bound_rect, const gfx::Transform& transform); - template <typename LayerType, typename RenderSurfaceLayerListType> - struct CalcDrawPropsInputs { + struct CC_EXPORT CalcDrawPropsMainInputs { public: - CalcDrawPropsInputs(LayerType* root_layer, - const gfx::Size& device_viewport_size, - const gfx::Transform& device_transform, - float device_scale_factor, - float page_scale_factor, - const LayerType* page_scale_layer, - const LayerType* inner_viewport_scroll_layer, - const LayerType* outer_viewport_scroll_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, - 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_layer(page_scale_layer), - inner_viewport_scroll_layer(inner_viewport_scroll_layer), - outer_viewport_scroll_layer(outer_viewport_scroll_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), - property_trees(property_trees) {} - - LayerType* root_layer; + CalcDrawPropsMainInputs(Layer* root_layer, + const gfx::Size& device_viewport_size, + const gfx::Transform& device_transform, + float device_scale_factor, + float page_scale_factor, + const Layer* page_scale_layer, + const Layer* inner_viewport_scroll_layer, + const Layer* outer_viewport_scroll_layer); + CalcDrawPropsMainInputs(Layer* root_layer, + const gfx::Size& device_viewport_size, + const gfx::Transform& device_transform); + CalcDrawPropsMainInputs(Layer* root_layer, + const gfx::Size& device_viewport_size); + Layer* root_layer; gfx::Size device_viewport_size; gfx::Transform device_transform; float device_scale_factor; float page_scale_factor; - const LayerType* page_scale_layer; - const LayerType* inner_viewport_scroll_layer; - const LayerType* outer_viewport_scroll_layer; + const Layer* page_scale_layer; + const Layer* inner_viewport_scroll_layer; + const Layer* outer_viewport_scroll_layer; + }; + + struct CC_EXPORT CalcDrawPropsImplInputs { + public: + CalcDrawPropsImplInputs( + LayerImpl* root_layer, + const gfx::Size& device_viewport_size, + const gfx::Transform& device_transform, + float device_scale_factor, + float page_scale_factor, + const LayerImpl* page_scale_layer, + const LayerImpl* inner_viewport_scroll_layer, + const LayerImpl* outer_viewport_scroll_layer, + const gfx::Vector2dF& elastic_overscroll, + const LayerImpl* 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, + LayerImplList* render_surface_layer_list, + int current_render_surface_layer_list_id, + PropertyTrees* property_trees); + + LayerImpl* root_layer; + gfx::Size device_viewport_size; + gfx::Transform device_transform; + float device_scale_factor; + float page_scale_factor; + const LayerImpl* page_scale_layer; + const LayerImpl* inner_viewport_scroll_layer; + const LayerImpl* outer_viewport_scroll_layer; gfx::Vector2dF elastic_overscroll; - const LayerType* elastic_overscroll_application_layer; + const LayerImpl* 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; + LayerImplList* render_surface_layer_list; int current_render_surface_layer_list_id; PropertyTrees* property_trees; }; - template <typename LayerType, typename RenderSurfaceLayerListType> - struct CalcDrawPropsInputsForTesting - : public CalcDrawPropsInputs<LayerType, RenderSurfaceLayerListType> { - CalcDrawPropsInputsForTesting( - LayerType* root_layer, - const gfx::Size& device_viewport_size, - const gfx::Transform& device_transform, - RenderSurfaceLayerListType* render_surface_layer_list); - CalcDrawPropsInputsForTesting( - LayerType* root_layer, - const gfx::Size& device_viewport_size, - RenderSurfaceLayerListType* render_surface_layer_list); + struct CC_EXPORT CalcDrawPropsImplInputsForTesting + : public CalcDrawPropsImplInputs { + CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer, + const gfx::Size& device_viewport_size, + const gfx::Transform& device_transform, + LayerImplList* render_surface_layer_list); + CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer, + const gfx::Size& device_viewport_size, + LayerImplList* render_surface_layer_list); }; - 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, @@ -127,9 +124,6 @@ class CC_EXPORT LayerTreeHostCommon { static void PreCalculateMetaInformationForTesting(LayerImpl* root_layer); static void PreCalculateMetaInformationForTesting(Layer* root_layer); - typedef CalcDrawPropsInputs<LayerImpl, LayerImplList> CalcDrawPropsImplInputs; - typedef CalcDrawPropsInputsForTesting<LayerImpl, LayerImplList> - CalcDrawPropsImplInputsForTesting; static void CalculateDrawProperties(CalcDrawPropsImplInputs* inputs); static void CalculateDrawProperties( CalcDrawPropsImplInputsForTesting* inputs); @@ -243,69 +237,6 @@ void LayerTreeHostCommon::CallFunctionForSubtree(LayerType* layer, CC_EXPORT PropertyTrees* GetPropertyTrees(Layer* layer); CC_EXPORT PropertyTrees* GetPropertyTrees(LayerImpl* layer); -template <typename LayerType, typename RenderSurfaceLayerListType> -LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType, - RenderSurfaceLayerListType>:: - CalcDrawPropsInputsForTesting( - LayerType* root_layer, - const gfx::Size& device_viewport_size, - const gfx::Transform& device_transform, - RenderSurfaceLayerListType* render_surface_layer_list) - : CalcDrawPropsInputs<LayerType, RenderSurfaceLayerListType>( - root_layer, - device_viewport_size, - device_transform, - 1.f, - 1.f, - NULL, - NULL, - NULL, - gfx::Vector2dF(), - NULL, - std::numeric_limits<int>::max() / 2, - false, - false, - true, - false, - true, - render_surface_layer_list, - 0, - GetPropertyTrees(root_layer)) { - DCHECK(root_layer); - DCHECK(render_surface_layer_list); -} - -template <typename LayerType, typename RenderSurfaceLayerListType> -LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType, - RenderSurfaceLayerListType>:: - CalcDrawPropsInputsForTesting( - LayerType* root_layer, - const gfx::Size& device_viewport_size, - RenderSurfaceLayerListType* render_surface_layer_list) - : CalcDrawPropsInputs<LayerType, RenderSurfaceLayerListType>( - root_layer, - device_viewport_size, - gfx::Transform(), - 1.f, - 1.f, - NULL, - NULL, - NULL, - gfx::Vector2dF(), - NULL, - std::numeric_limits<int>::max() / 2, - false, - false, - true, - false, - true, - render_surface_layer_list, - 0, - GetPropertyTrees(root_layer)) { - DCHECK(root_layer); - DCHECK(render_surface_layer_list); -} - } // namespace cc #endif // CC_TREES_LAYER_TREE_HOST_COMMON_H_ diff --git a/chromium/cc/trees/layer_tree_host_common_perftest.cc b/chromium/cc/trees/layer_tree_host_common_perftest.cc index 49831328d1e..f326ec25dff 100644 --- a/chromium/cc/trees/layer_tree_host_common_perftest.cc +++ b/chromium/cc/trees/layer_tree_host_common_perftest.cc @@ -116,7 +116,7 @@ class CalcDrawPropsTest : public LayerTreeHostCommonPerfTest { active_tree->InnerViewportScrollLayer(), active_tree->OuterViewportScrollLayer(), active_tree->elastic_overscroll()->Current(active_tree->IsActiveTree()), - active_tree->overscroll_elasticity_layer(), max_texture_size, + active_tree->OverscrollElasticityLayer(), max_texture_size, host_impl->settings().can_use_lcd_text, host_impl->settings().layers_always_allowed_lcd_text, can_render_to_separate_surface, @@ -156,7 +156,7 @@ class BspTreePerfTest : public CalcDrawPropsTest { for (LayerImplList::iterator it = base_list.begin(); it != base_list.end(); ++it) { DrawPolygon* draw_polygon = - new DrawPolygon(NULL, gfx::RectF((*it)->bounds()), + new DrawPolygon(NULL, gfx::RectF(gfx::SizeF((*it)->bounds())), (*it)->draw_transform(), polygon_counter++); polygon_list.push_back(scoped_ptr<DrawPolygon>(draw_polygon)); } diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc index 43e2bb02123..8af5a0650a9 100644 --- a/chromium/cc/trees/layer_tree_host_common_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc @@ -7,6 +7,7 @@ #include <algorithm> #include <set> +#include "cc/animation/keyframed_animation_curve.h" #include "cc/animation/layer_animation_controller.h" #include "cc/animation/transform_operations.h" #include "cc/base/math_util.h" @@ -15,7 +16,6 @@ #include "cc/layers/layer_client.h" #include "cc/layers/layer_impl.h" #include "cc/layers/layer_iterator.h" -#include "cc/layers/render_surface.h" #include "cc/layers/render_surface_impl.h" #include "cc/output/copy_output_request.h" #include "cc/output/copy_output_result.h" @@ -24,11 +24,13 @@ #include "cc/test/fake_impl_proxy.h" #include "cc/test/fake_layer_tree_host.h" #include "cc/test/fake_layer_tree_host_impl.h" +#include "cc/test/fake_output_surface.h" #include "cc/test/fake_picture_layer.h" #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/draw_property_utils.h" #include "cc/trees/layer_tree_impl.h" #include "cc/trees/proxy.h" #include "cc/trees/single_thread_proxy.h" @@ -68,17 +70,9 @@ class MockContentLayerClient : public ContentLayerClient { return nullptr; } bool FillsBoundsCompletely() const override { return false; } + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } }; -scoped_refptr<FakePictureLayer> CreateDrawablePictureLayer( - const LayerSettings& settings, - ContentLayerClient* delegate) { - scoped_refptr<FakePictureLayer> to_return = - FakePictureLayer::Create(settings, delegate); - to_return->SetIsDrawable(true); - return to_return; -} - #define EXPECT_CONTENTS_SCALE_EQ(expected, layer) \ do { \ EXPECT_FLOAT_EQ(expected, layer->contents_scale_x()); \ @@ -152,43 +146,27 @@ TEST_F(LayerTreeHostCommonTest, TransformsForNoOpLayer) { } TEST_F(LayerTreeHostCommonTest, DoNotSkipLayersWithHandlers) { - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child = Layer::Create(layer_settings()); - parent->AddChild(child); - child->AddChild(grand_child); - - host()->SetRootLayer(parent); + LayerImpl* parent = root_layer(); + LayerImpl* child = AddChild<LayerImpl>(parent); + LayerImpl* grand_child = AddChild<LayerImpl>(child); gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(10, 10), - gfx::Size(100, 100), - true, - false); + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(10, 10), gfx::Size(100, 100), true, + false, false); // This would have previously caused us to skip our subtree, but this would be // wrong; we need up-to-date draw properties to do hit testing on the layers // with handlers. child->SetOpacity(0.f); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(10, 10), - gfx::Size(100, 100), - true, - false); + SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), + gfx::PointF(10, 10), gfx::Size(100, 100), true, + false, false); grand_child->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 100, 100)); - ExecuteCalculateDrawProperties(parent.get()); + ExecuteCalculateDrawProperties(parent); // Check that we've computed draw properties for the subtree rooted at // |child|. @@ -201,113 +179,96 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) { scoped_refptr<Layer> layer = Layer::Create(layer_settings()); scoped_refptr<Layer> root = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(1, 2), - true, - false); + SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(1, 2), true, false); root->AddChild(layer); host()->SetRootLayer(root); + TransformTree& tree = host()->property_trees()->transform_tree; + // Case 2: Setting the bounds of the layer should not affect either the draw // transform or the screenspace transform. gfx::Transform translation_to_center; translation_to_center.Translate(5.0, 6.0); - SetLayerPropertiesForTesting(layer.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 12), - true, - false); + SetLayerPropertiesForTesting(layer.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 12), true, false); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, layer->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, - layer->screen_space_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ( + identity_matrix, DrawTransformFromPropertyTrees(layer.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + identity_matrix, + ScreenSpaceTransformFromPropertyTrees(layer.get(), tree)); // Case 3: The anchor point by itself (without a layer transform) should have // no effect on the transforms. - SetLayerPropertiesForTesting(layer.get(), - identity_matrix, - gfx::Point3F(2.5f, 3.0f, 0.f), - gfx::PointF(), - gfx::Size(10, 12), - true, - false); + SetLayerPropertiesForTesting(layer.get(), identity_matrix, + gfx::Point3F(2.5f, 3.0f, 0.f), gfx::PointF(), + gfx::Size(10, 12), true, false); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, layer->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, - layer->screen_space_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ( + identity_matrix, DrawTransformFromPropertyTrees(layer.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + identity_matrix, + ScreenSpaceTransformFromPropertyTrees(layer.get(), tree)); // Case 4: A change in actual position affects both the draw transform and // screen space transform. gfx::Transform position_transform; position_transform.Translate(0.f, 1.2f); - SetLayerPropertiesForTesting(layer.get(), - identity_matrix, - gfx::Point3F(2.5f, 3.0f, 0.f), - gfx::PointF(0.f, 1.2f), - gfx::Size(10, 12), - true, - false); + SetLayerPropertiesForTesting( + layer.get(), identity_matrix, gfx::Point3F(2.5f, 3.0f, 0.f), + gfx::PointF(0.f, 1.2f), gfx::Size(10, 12), true, false); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRANSFORMATION_MATRIX_EQ(position_transform, layer->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(position_transform, - layer->screen_space_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ( + position_transform, DrawTransformFromPropertyTrees(layer.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + position_transform, + ScreenSpaceTransformFromPropertyTrees(layer.get(), tree)); // Case 5: In the correct sequence of transforms, the layer transform should // pre-multiply the translation_to_center. This is easily tested by using a // scale transform, because scale and translation are not commutative. gfx::Transform layer_transform; layer_transform.Scale3d(2.0, 2.0, 1.0); - SetLayerPropertiesForTesting(layer.get(), - layer_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 12), - true, - false); + SetLayerPropertiesForTesting(layer.get(), layer_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 12), true, false); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRANSFORMATION_MATRIX_EQ(layer_transform, layer->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(layer_transform, - layer->screen_space_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ( + layer_transform, DrawTransformFromPropertyTrees(layer.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + layer_transform, + ScreenSpaceTransformFromPropertyTrees(layer.get(), tree)); // Case 6: The layer transform should occur with respect to the anchor point. gfx::Transform translation_to_anchor; translation_to_anchor.Translate(5.0, 0.0); gfx::Transform expected_result = translation_to_anchor * layer_transform * Inverse(translation_to_anchor); - SetLayerPropertiesForTesting(layer.get(), - layer_transform, - gfx::Point3F(5.0f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 12), - true, - false); + SetLayerPropertiesForTesting(layer.get(), layer_transform, + gfx::Point3F(5.0f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 12), true, false); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, layer->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, - layer->screen_space_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ( + expected_result, DrawTransformFromPropertyTrees(layer.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + expected_result, + ScreenSpaceTransformFromPropertyTrees(layer.get(), tree)); // Case 7: Verify that position pre-multiplies the layer transform. The // current implementation of CalculateDrawProperties does this implicitly, but // it is still worth testing to detect accidental regressions. expected_result = position_transform * translation_to_anchor * layer_transform * Inverse(translation_to_anchor); - SetLayerPropertiesForTesting(layer.get(), - layer_transform, - gfx::Point3F(5.0f, 0.f, 0.f), - gfx::PointF(0.f, 1.2f), - gfx::Size(10, 12), - true, - false); + SetLayerPropertiesForTesting( + layer.get(), layer_transform, gfx::Point3F(5.0f, 0.f, 0.f), + gfx::PointF(0.f, 1.2f), gfx::Size(10, 12), true, false); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, layer->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, - layer->screen_space_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ( + expected_result, DrawTransformFromPropertyTrees(layer.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + expected_result, + ScreenSpaceTransformFromPropertyTrees(layer.get(), tree)); } TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) { @@ -413,78 +374,57 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSimpleHierarchy) { host()->SetRootLayer(root); // One-time setup of root layer - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(1, 2), - true, - false); + SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(1, 2), true, false); + + TransformTree& tree = host()->property_trees()->transform_tree; // Case 1: parent's anchor point should not affect child or grand_child. - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(2.5f, 3.0f, 0.f), - gfx::PointF(), - gfx::Size(10, 12), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(16, 18), - true, - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(76, 78), - true, - false); + SetLayerPropertiesForTesting(parent.get(), identity_matrix, + gfx::Point3F(2.5f, 3.0f, 0.f), gfx::PointF(), + gfx::Size(10, 12), true, false); + SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(16, 18), true, false); + SetLayerPropertiesForTesting(grand_child.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(76, 78), + true, false); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, - child->screen_space_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, - grand_child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, - grand_child->screen_space_transform()); + + EXPECT_TRANSFORMATION_MATRIX_EQ( + identity_matrix, DrawTransformFromPropertyTrees(child.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + identity_matrix, + ScreenSpaceTransformFromPropertyTrees(child.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + identity_matrix, DrawTransformFromPropertyTrees(grand_child.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + identity_matrix, + ScreenSpaceTransformFromPropertyTrees(grand_child.get(), tree)); // Case 2: parent's position affects child and grand_child. gfx::Transform parent_position_transform; parent_position_transform.Translate(0.f, 1.2f); - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(2.5f, 3.0f, 0.f), - gfx::PointF(0.f, 1.2f), - gfx::Size(10, 12), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(16, 18), - true, - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(76, 78), - true, - false); + SetLayerPropertiesForTesting( + parent.get(), identity_matrix, gfx::Point3F(2.5f, 3.0f, 0.f), + gfx::PointF(0.f, 1.2f), gfx::Size(10, 12), true, false); + SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(16, 18), true, false); + SetLayerPropertiesForTesting(grand_child.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(76, 78), + true, false); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRANSFORMATION_MATRIX_EQ(parent_position_transform, - child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(parent_position_transform, - child->screen_space_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(parent_position_transform, - grand_child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(parent_position_transform, - grand_child->screen_space_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ( + parent_position_transform, + DrawTransformFromPropertyTrees(child.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + parent_position_transform, + ScreenSpaceTransformFromPropertyTrees(child.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + parent_position_transform, + DrawTransformFromPropertyTrees(grand_child.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + parent_position_transform, + ScreenSpaceTransformFromPropertyTrees(grand_child.get(), tree)); // Case 3: parent's local transform affects child and grandchild gfx::Transform parent_layer_transform; @@ -494,63 +434,43 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSimpleHierarchy) { gfx::Transform parent_composite_transform = parent_translation_to_anchor * parent_layer_transform * Inverse(parent_translation_to_anchor); - SetLayerPropertiesForTesting(parent.get(), - parent_layer_transform, - gfx::Point3F(2.5f, 3.0f, 0.f), - gfx::PointF(), - gfx::Size(10, 12), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(16, 18), - true, - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(76, 78), - true, - false); + SetLayerPropertiesForTesting(parent.get(), parent_layer_transform, + gfx::Point3F(2.5f, 3.0f, 0.f), gfx::PointF(), + gfx::Size(10, 12), true, false); + SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(16, 18), true, false); + SetLayerPropertiesForTesting(grand_child.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(76, 78), + true, false); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, - child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, - child->screen_space_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, - grand_child->draw_transform()); - EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform, - grand_child->screen_space_transform()); + EXPECT_TRANSFORMATION_MATRIX_EQ( + parent_composite_transform, + DrawTransformFromPropertyTrees(child.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + parent_composite_transform, + ScreenSpaceTransformFromPropertyTrees(child.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + parent_composite_transform, + DrawTransformFromPropertyTrees(grand_child.get(), tree)); + EXPECT_TRANSFORMATION_MATRIX_EQ( + parent_composite_transform, + ScreenSpaceTransformFromPropertyTrees(grand_child.get(), tree)); } TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) { - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> grand_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(parent); - parent->AddChild(child); - child->AddChild(grand_child); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* parent = AddChildToRoot<LayerImpl>(); + LayerImpl* child = AddChild<LayerImpl>(parent); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + grand_child->SetDrawsContent(true); - // One-time setup of root layer gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(1, 2), - true, - false); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(1, 2), true, false, + true); // Child is set up so that a new render surface should be created. child->SetOpacity(0.5f); - child->SetForceRenderSurface(true); gfx::Transform parent_layer_transform; parent_layer_transform.Scale3d(1.f, 0.9f, 1.f); @@ -569,35 +489,20 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) { gfx::Transform surface_sublayer_composite_transform = parent_composite_transform * Inverse(surface_sublayer_transform); - // Child's render surface should not exist yet. - ASSERT_FALSE(child->render_surface()); - - SetLayerPropertiesForTesting(parent.get(), - parent_layer_transform, - gfx::Point3F(25.0f, 30.0f, 0.f), - gfx::PointF(), - gfx::Size(100, 120), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(16, 18), - true, - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(8, 10), - true, + SetLayerPropertiesForTesting(parent, parent_layer_transform, + gfx::Point3F(25.0f, 30.0f, 0.f), gfx::PointF(), + gfx::Size(100, 120), true, false, false); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(16, 18), true, false, + true); + SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(8, 10), true, false, false); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); // Render surface should have been created now. ASSERT_TRUE(child->render_surface()); - ASSERT_EQ(child.get(), child->render_target()); + ASSERT_EQ(child, child->render_target()); // The child layer's draw transform should refer to its new render surface. // The screen-space transform, however, should still refer to the root. @@ -621,28 +526,19 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) { } TEST_F(LayerTreeHostCommonTest, TransformsForReplica) { - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<Layer> child_replica = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> grand_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(parent); - parent->AddChild(child); - child->AddChild(grand_child); - child->SetReplicaLayer(child_replica.get()); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* parent = AddChildToRoot<LayerImpl>(); + LayerImpl* child = AddChild<LayerImpl>(parent); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + grand_child->SetDrawsContent(true); + scoped_ptr<LayerImpl> child_replica = + LayerImpl::Create(host_impl()->active_tree(), 100); // One-time setup of root layer gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(1, 2), - true, - false); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(1, 2), true, false, + true); // Child is set up so that a new render surface should be created. child->SetOpacity(0.5f); @@ -665,43 +561,29 @@ TEST_F(LayerTreeHostCommonTest, TransformsForReplica) { gfx::Transform replica_composite_transform = parent_composite_transform * replica_layer_transform * Inverse(surface_sublayer_transform); - child_replica->SetIsDrawable(true); + child_replica->SetDrawsContent(true); // Child's render surface should not exist yet. ASSERT_FALSE(child->render_surface()); - SetLayerPropertiesForTesting(parent.get(), - parent_layer_transform, - gfx::Point3F(2.5f, 3.0f, 0.f), - gfx::PointF(), - gfx::Size(10, 12), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(16, 18), - true, - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(-0.5f, -0.5f), - gfx::Size(1, 1), - true, - false); - SetLayerPropertiesForTesting(child_replica.get(), - replica_layer_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(), - true, - false); - ExecuteCalculateDrawProperties(root.get()); + SetLayerPropertiesForTesting(parent, parent_layer_transform, + gfx::Point3F(2.5f, 3.0f, 0.f), gfx::PointF(), + gfx::Size(10, 12), true, false, false); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(16, 18), true, false, + true); + SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), + gfx::PointF(-0.5f, -0.5f), gfx::Size(1, 1), true, + false, false); + SetLayerPropertiesForTesting(child_replica.get(), replica_layer_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(), true, + false, false); + child->SetReplicaLayer(child_replica.Pass()); + + ExecuteCalculateDrawProperties(root); // Render surface should have been created now. ASSERT_TRUE(child->render_surface()); - ASSERT_EQ(child.get(), child->render_target()); + ASSERT_EQ(child, child->render_target()); EXPECT_TRANSFORMATION_MATRIX_EQ( replica_composite_transform, @@ -726,33 +608,23 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) { // - verifying that each layer has a reference to the correct render surface // and render target values. - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface2 = Layer::Create(layer_settings()); - scoped_refptr<Layer> child_of_root = Layer::Create(layer_settings()); - scoped_refptr<Layer> child_of_rs1 = Layer::Create(layer_settings()); - scoped_refptr<Layer> child_of_rs2 = Layer::Create(layer_settings()); - scoped_refptr<Layer> replica_of_rs1 = Layer::Create(layer_settings()); - scoped_refptr<Layer> replica_of_rs2 = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child_of_root = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> grand_child_of_rs1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> grand_child_of_rs2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(parent); - parent->AddChild(render_surface1); - parent->AddChild(child_of_root); - render_surface1->AddChild(child_of_rs1); - render_surface1->AddChild(render_surface2); - render_surface2->AddChild(child_of_rs2); - child_of_root->AddChild(grand_child_of_root); - child_of_rs1->AddChild(grand_child_of_rs1); - child_of_rs2->AddChild(grand_child_of_rs2); - render_surface1->SetReplicaLayer(replica_of_rs1.get()); - render_surface2->SetReplicaLayer(replica_of_rs2.get()); + LayerImpl* root = root_layer(); + LayerImpl* parent = AddChildToRoot<LayerImpl>(); + LayerImpl* render_surface1 = AddChild<LayerImpl>(parent); + LayerImpl* render_surface2 = AddChild<LayerImpl>(render_surface1); + LayerImpl* child_of_root = AddChild<LayerImpl>(parent); + LayerImpl* child_of_rs1 = AddChild<LayerImpl>(render_surface1); + LayerImpl* child_of_rs2 = AddChild<LayerImpl>(render_surface2); + LayerImpl* grand_child_of_root = AddChild<LayerImpl>(child_of_root); + LayerImpl* grand_child_of_rs1 = AddChild<LayerImpl>(child_of_rs1); + grand_child_of_rs1->SetDrawsContent(true); + LayerImpl* grand_child_of_rs2 = AddChild<LayerImpl>(child_of_rs2); + grand_child_of_rs2->SetDrawsContent(true); - host()->SetRootLayer(root); + scoped_ptr<LayerImpl> replica_of_rs1 = + LayerImpl::Create(host_impl()->active_tree(), 101); + scoped_ptr<LayerImpl> replica_of_rs2 = + LayerImpl::Create(host_impl()->active_tree(), 102); // In combination with descendant draws content, opacity != 1 forces the layer // to have a new render surface. @@ -761,13 +633,9 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) { // One-time setup of root layer gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(1, 2), - true, - false); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(1, 2), true, false, + true); // All layers in the tree are initialized with an anchor at .25 and a size of // (10,10). matrix "A" is the composite layer transform used in all layers, @@ -808,85 +676,43 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) { // the owning layer gfx::Transform S2 = Inverse(surface2_sublayer_transform); - SetLayerPropertiesForTesting(parent.get(), - layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(render_surface2.get(), - layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(child_of_root.get(), - layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(child_of_rs1.get(), - layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(child_of_rs2.get(), - layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child_of_root.get(), - layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child_of_rs1.get(), - layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child_of_rs2.get(), - layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(replica_of_rs1.get(), - replica_layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(), - true, - false); - SetLayerPropertiesForTesting(replica_of_rs2.get(), - replica_layer_transform, - gfx::Point3F(2.5f, 0.f, 0.f), - gfx::PointF(), - gfx::Size(), - true, - false); - - ExecuteCalculateDrawProperties(root.get()); + SetLayerPropertiesForTesting(parent, layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 10), true, false, false); + SetLayerPropertiesForTesting(render_surface1, layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 10), true, false, true); + SetLayerPropertiesForTesting(render_surface2, layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 10), true, false, true); + SetLayerPropertiesForTesting(child_of_root, layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 10), true, false, false); + SetLayerPropertiesForTesting(child_of_rs1, layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 10), true, false, false); + SetLayerPropertiesForTesting(child_of_rs2, layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 10), true, false, false); + SetLayerPropertiesForTesting(grand_child_of_root, layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 10), true, false, false); + SetLayerPropertiesForTesting(grand_child_of_rs1, layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 10), true, false, false); + SetLayerPropertiesForTesting(grand_child_of_rs2, layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(10, 10), true, false, false); + SetLayerPropertiesForTesting(replica_of_rs1.get(), replica_layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(), true, false, false); + SetLayerPropertiesForTesting(replica_of_rs2.get(), replica_layer_transform, + gfx::Point3F(2.5f, 0.f, 0.f), gfx::PointF(), + gfx::Size(), true, false, false); + + render_surface1->SetReplicaLayer(replica_of_rs1.Pass()); + render_surface2->SetReplicaLayer(replica_of_rs2.Pass()); + ExecuteCalculateDrawProperties(root); // Only layers that are associated with render surfaces should have an actual // RenderSurface() value. @@ -903,17 +729,17 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) { ASSERT_FALSE(grand_child_of_rs2->render_surface()); // Verify all render target accessors - EXPECT_EQ(root.get(), parent->render_target()); - EXPECT_EQ(root.get(), child_of_root->render_target()); - EXPECT_EQ(root.get(), grand_child_of_root->render_target()); + EXPECT_EQ(root, parent->render_target()); + EXPECT_EQ(root, child_of_root->render_target()); + EXPECT_EQ(root, grand_child_of_root->render_target()); - EXPECT_EQ(render_surface1.get(), render_surface1->render_target()); - EXPECT_EQ(render_surface1.get(), child_of_rs1->render_target()); - EXPECT_EQ(render_surface1.get(), grand_child_of_rs1->render_target()); + EXPECT_EQ(render_surface1, render_surface1->render_target()); + EXPECT_EQ(render_surface1, child_of_rs1->render_target()); + EXPECT_EQ(render_surface1, grand_child_of_rs1->render_target()); - EXPECT_EQ(render_surface2.get(), render_surface2->render_target()); - EXPECT_EQ(render_surface2.get(), child_of_rs2->render_target()); - EXPECT_EQ(render_surface2.get(), grand_child_of_rs2->render_target()); + EXPECT_EQ(render_surface2, render_surface2->render_target()); + EXPECT_EQ(render_surface2, child_of_rs2->render_target()); + EXPECT_EQ(render_surface2, grand_child_of_rs2->render_target()); // Verify layer draw transforms note that draw transforms are described with // respect to the nearest ancestor render surface but screen space transforms @@ -1011,48 +837,29 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) { // Note that the way the code is currently implemented, it is not expected to // use a canonical orthographic projection. - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> grand_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> great_grand_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); + LayerImpl* root = root_layer(); + LayerImpl* child = AddChildToRoot<LayerImpl>(); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + grand_child->SetDrawsContent(true); + LayerImpl* great_grand_child = AddChild<LayerImpl>(grand_child); + great_grand_child->SetDrawsContent(true); gfx::Transform rotation_about_y_axis; rotation_about_y_axis.RotateAboutYAxis(30.0); const gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(child.get(), - rotation_about_y_axis, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child.get(), - rotation_about_y_axis, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(great_grand_child.get(), identity_matrix, + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(child, rotation_about_y_axis, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + true); + SetLayerPropertiesForTesting(grand_child, rotation_about_y_axis, 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); - - host()->SetRootLayer(root); + true, false, false); + SetLayerPropertiesForTesting(great_grand_child, identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), + true, false, false); // No layers in this test should preserve 3d. ASSERT_TRUE(root->should_flatten_transform()); @@ -1073,7 +880,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) { gfx::Transform expected_great_grand_child_screen_space_transform = flattened_rotation_about_y * flattened_rotation_about_y; - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); // The child's draw transform should have been taken by its surface. ASSERT_TRUE(child->render_surface()); @@ -1096,6 +903,43 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) { great_grand_child->screen_space_transform()); } +TEST_F(LayerTreeHostCommonTest, LayerFullyContainedWithinClipInTargetSpace) { + scoped_refptr<Layer> root = Layer::Create(layer_settings()); + scoped_refptr<Layer> child = Layer::Create(layer_settings()); + scoped_refptr<LayerWithForcedDrawsContent> grand_child = + make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); + + gfx::Transform child_transform; + child_transform.Translate(50.0, 50.0); + child_transform.RotateAboutZAxis(30.0); + + gfx::Transform grand_child_transform; + grand_child_transform.RotateAboutYAxis(90.0); + + const gfx::Transform identity_matrix; + SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(200, 200), true, false); + SetLayerPropertiesForTesting(child.get(), child_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false); + SetLayerPropertiesForTesting(grand_child.get(), grand_child_transform, + gfx::Point3F(), gfx::PointF(), + gfx::Size(100, 100), true, false); + + root->AddChild(child); + child->AddChild(grand_child); + grand_child->SetShouldFlattenTransform(false); + + host()->SetRootLayer(root); + + ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); + + // Mapping grand_child's bounds to target space produces a non-empty rect + // that is fully contained within the target's bounds, so grand_child should + // be considered fully visible. + EXPECT_EQ(gfx::Rect(grand_child->bounds()), + grand_child->visible_rect_from_property_trees()); +} + TEST_F(LayerTreeHostCommonTest, TransformsForDegenerateIntermediateLayer) { // A layer that is empty in one axis, but not the other, was accidentally // skipping a necessary translation. Without that translation, the coordinate @@ -1106,45 +950,27 @@ TEST_F(LayerTreeHostCommonTest, TransformsForDegenerateIntermediateLayer) { // implicitly inherited by the rest of the subtree, which then is positioned // incorrectly as a result. - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> grand_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); + LayerImpl* root = root_layer(); + LayerImpl* child = AddChild<LayerImpl>(root); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + grand_child->SetDrawsContent(true); // The child height is zero, but has non-zero width that should be accounted // for while computing draw transforms. const gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 0), - true, - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 0), true, false, + true); + SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, false); - root->AddChild(child); - child->AddChild(grand_child); - child->SetForceRenderSurface(true); - - host()->SetRootLayer(root); - - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); - ASSERT_TRUE(child->render_surface()); + ASSERT_TRUE(child->has_render_surface()); // This is the real test, the rest are sanity checks. EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->render_surface()->draw_transform()); @@ -1157,37 +983,26 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { // Transformations applied at the root of the tree should be forwarded // to child layers instead of applied to the root RenderSurface. const gfx::Transform identity_matrix; - scoped_refptr<LayerWithForcedDrawsContent> root = - new LayerWithForcedDrawsContent(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child = - new LayerWithForcedDrawsContent(layer_settings()); - child->SetScrollClipLayerId(root->id()); - root->AddChild(child); + LayerImpl* root = root_layer(); + root->SetDrawsContent(true); + LayerImpl* child = AddChild<LayerImpl>(root); + child->SetDrawsContent(true); - host()->SetRootLayer(root); + child->SetScrollClipLayer(root->id()); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(20, 20), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(20, 20), true, false, false); gfx::Transform translate; translate.Translate(50, 50); { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), translate, &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; + LayerImplList render_surface_layer_list_impl; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, root->bounds(), translate, &render_surface_layer_list_impl); inputs.property_trees->needs_rebuild = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); EXPECT_EQ(translate, root->draw_properties().target_space_transform); @@ -1198,10 +1013,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { gfx::Transform scale; scale.Scale(2, 2); { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), scale, &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; + LayerImplList render_surface_layer_list_impl; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, root->bounds(), scale, &render_surface_layer_list_impl); inputs.property_trees->needs_rebuild = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); EXPECT_EQ(scale, root->draw_properties().target_space_transform); @@ -1212,10 +1026,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { gfx::Transform rotate; rotate.Rotate(2); { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), rotate, &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; + LayerImplList render_surface_layer_list_impl; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, root->bounds(), rotate, &render_surface_layer_list_impl); inputs.property_trees->needs_rebuild = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); EXPECT_EQ(rotate, root->draw_properties().target_space_transform); @@ -1228,10 +1041,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { composite.ConcatTransform(scale); composite.ConcatTransform(rotate); { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), composite, &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; + LayerImplList render_surface_layer_list_impl; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, root->bounds(), composite, &render_surface_layer_list_impl); inputs.property_trees->needs_rebuild = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); EXPECT_EQ(composite, root->draw_properties().target_space_transform); @@ -1243,11 +1055,10 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { float device_scale_factor = 1.5f; { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), translate, &render_surface_layer_list); + LayerImplList render_surface_layer_list_impl; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, root->bounds(), translate, &render_surface_layer_list_impl); 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; @@ -1263,12 +1074,11 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { float page_scale_factor = 2.f; { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), translate, &render_surface_layer_list); + LayerImplList render_surface_layer_list_impl; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, root->bounds(), translate, &render_surface_layer_list_impl); inputs.page_scale_factor = page_scale_factor; - inputs.page_scale_layer = root.get(); - inputs.can_adjust_raster_scales = true; + inputs.page_scale_layer = root; inputs.property_trees->needs_rebuild = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); gfx::Transform page_scaled_translate = translate; @@ -1284,10 +1094,10 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { root->SetTransform(composite); { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), composite, &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; + LayerImplList render_surface_layer_list_impl; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, root->bounds(), composite, &render_surface_layer_list_impl); + inputs.property_trees->needs_rebuild = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); gfx::Transform compositeSquared = composite; compositeSquared.ConcatTransform(composite); @@ -1301,48 +1111,24 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) { TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForRenderSurfaceWithClippedLayer) { - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - - host()->SetRootLayer(parent); + LayerImpl* parent = root_layer(); + parent->SetMasksToBounds(true); + LayerImpl* render_surface1 = AddChildToRoot<LayerImpl>(); + LayerImpl* child = AddChild<LayerImpl>(render_surface1); + child->SetDrawsContent(true); const gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(30.f, 30.f), - gfx::Size(10, 10), - true, - false); - - parent->AddChild(render_surface1); - parent->SetMasksToBounds(true); - render_surface1->AddChild(child); - render_surface1->SetForceRenderSurface(true); + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + true); + SetLayerPropertiesForTesting(render_surface1, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(30.f, 30.f), gfx::Size(10, 10), true, + false, false); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), - parent->bounds(), - gfx::Transform(), - &render_surface_layer_list); - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawProperties(parent); // The child layer's content is entirely outside the parent's clip rect, so // the intermediate render surface should not be listed here, even if it was @@ -1350,7 +1136,7 @@ TEST_F(LayerTreeHostCommonTest, // are unexpected at draw time (e.g. we might try to create a content texture // of size 0). ASSERT_TRUE(parent->render_surface()); - EXPECT_EQ(1U, render_surface_layer_list.size()); + EXPECT_EQ(1U, render_surface_layer_list_impl()->size()); } TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) { @@ -1384,33 +1170,69 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) { EXPECT_EQ(gfx::Rect(), parent->drawable_content_rect()); } -TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) { - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); +TEST_F(LayerTreeHostCommonTest, + RenderSurfaceListForTransparentChildWithBackgroundFilter) { + LayerImpl* parent = root_layer(); + LayerImpl* render_surface1 = AddChild<LayerImpl>(parent); + LayerImpl* child = AddChild<LayerImpl>(render_surface1); + child->SetDrawsContent(true); - host()->SetRootLayer(parent); + const gfx::Transform identity_matrix; + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + true); + SetLayerPropertiesForTesting(render_surface1, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + false); + render_surface1->SetOpacity(0.f); + FilterOperations filters; + filters.Append(FilterOperation::CreateBlurFilter(1.5f)); + render_surface1->SetBackgroundFilters(filters); + + LayerImplList render_surface_layer_list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + parent, parent->bounds(), &render_surface_layer_list); + inputs.can_adjust_raster_scales = true; + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + + // The layer is fully transparent, but has a background filter, so it + // shouldn't be skipped. + ASSERT_TRUE(parent->render_surface()); + EXPECT_EQ(1U, parent->render_surface()->layer_list().size()); + EXPECT_EQ(2U, render_surface_layer_list.size()); + EXPECT_EQ(gfx::Rect(0, 0, 10, 10), parent->drawable_content_rect()); +} + +TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) { + LayerImpl* parent = root_layer(); + LayerImpl* child = AddChild<LayerImpl>(parent); + child->SetDrawsContent(true); 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); + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + true); - parent->AddChild(child); child->SetBlendMode(blend_mode); + child->SetOpacity(0.5f); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawProperties(parent); // 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); + EXPECT_EQ(1.0f, child->draw_opacity()); + EXPECT_EQ(0.5f, child->render_surface()->draw_opacity()); + EXPECT_EQ(SkXfermode::kSrcOver_Mode, child->draw_blend_mode()); } TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) { @@ -1449,32 +1271,26 @@ TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) { render_surface1->AddChild(child); // Sanity check before the actual test - EXPECT_FALSE(parent->render_surface()); - EXPECT_FALSE(render_surface1->render_surface()); + EXPECT_FALSE(parent->has_render_surface()); + EXPECT_FALSE(render_surface1->has_render_surface()); { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; + LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(parent.get(), + parent->bounds()); LayerTreeHostCommon::CalculateDrawProperties(&inputs); // The root layer always creates a render surface - EXPECT_TRUE(parent->render_surface()); - EXPECT_TRUE(render_surface1->render_surface()); - EXPECT_EQ(2U, render_surface_layer_list.size()); + EXPECT_TRUE(parent->has_render_surface()); + EXPECT_TRUE(render_surface1->has_render_surface()); } { - RenderSurfaceLayerList render_surface_layer_list; render_surface1->SetForceRenderSurface(false); - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; + LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(parent.get(), + parent->bounds()); LayerTreeHostCommon::CalculateDrawProperties(&inputs); - EXPECT_TRUE(parent->render_surface()); - EXPECT_FALSE(render_surface1->render_surface()); - EXPECT_EQ(1U, render_surface_layer_list.size()); + EXPECT_TRUE(parent->has_render_surface()); + EXPECT_FALSE(render_surface1->has_render_surface()); } } @@ -1482,12 +1298,13 @@ 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(layer_settings()); - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> grand_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); + LayerImpl* root = root_layer(); + LayerImpl* parent = AddChild<LayerImpl>(root); + LayerImpl* child = AddChild<LayerImpl>(parent); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + + child->SetDrawsContent(true); + grand_child->SetDrawsContent(true); gfx::Transform rotation_about_y_axis; rotation_about_y_axis.RotateAboutYAxis(30.0); @@ -1495,25 +1312,21 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfacesFlattenScreenSpaceTransform) { 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); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(parent, rotation_about_y_axis, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + false); + SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + false); grand_child->SetShouldFlattenTransform(false); - host()->SetRootLayer(root); - // Only grand_child should preserve 3d. EXPECT_TRUE(root->should_flatten_transform()); EXPECT_TRUE(parent->should_flatten_transform()); @@ -1526,7 +1339,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfacesFlattenScreenSpaceTransform) { gfx::Transform flattened_rotation_about_y = rotation_about_y_axis; flattened_rotation_about_y.FlattenTo2d(); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); EXPECT_TRUE(parent->render_surface()); EXPECT_FALSE(child->render_surface()); @@ -1560,94 +1373,56 @@ TEST_F(LayerTreeHostCommonTest, ClipRectCullsRenderSurfaces) { // In this configuration, grand_child and great_grand_child are completely // outside the clip rect, and they should never get scheduled on the list of // render surfaces. - // - - const gfx::Transform identity_matrix; - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child = Layer::Create(layer_settings()); - scoped_refptr<Layer> great_grand_child = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> leaf_node1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> leaf_node2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - parent->AddChild(child); - child->AddChild(grand_child); - grand_child->AddChild(great_grand_child); - host()->SetRootLayer(parent); + LayerImpl* parent = root_layer(); + LayerImpl* child = AddChildToRoot<LayerImpl>(); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + LayerImpl* great_grand_child = AddChild<LayerImpl>(grand_child); // leaf_node1 ensures that parent and child are kept on the // render_surface_layer_list, even though grand_child and great_grand_child // should be clipped. - child->AddChild(leaf_node1); - great_grand_child->AddChild(leaf_node2); + LayerImpl* leaf_node1 = AddChild<LayerImpl>(child); + leaf_node1->SetDrawsContent(true); + LayerImpl* leaf_node2 = AddChild<LayerImpl>(great_grand_child); + leaf_node2->SetDrawsContent(true); - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(500, 500), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(45.f, 45.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(great_grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(leaf_node1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(500, 500), - true, + const gfx::Transform identity_matrix; + + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(500, 500), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(20, 20), true, false, + true); + SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), + gfx::PointF(45.f, 45.f), gfx::Size(10, 10), true, + false, false); + SetLayerPropertiesForTesting(great_grand_child, identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), + true, false, false); + SetLayerPropertiesForTesting(leaf_node1, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(500, 500), true, false, false); - SetLayerPropertiesForTesting(leaf_node2.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, + SetLayerPropertiesForTesting(leaf_node2, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(20, 20), true, false, false); child->SetMasksToBounds(true); child->SetOpacity(0.4f); - child->SetForceRenderSurface(true); grand_child->SetOpacity(0.5f); great_grand_child->SetOpacity(0.4f); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawProperties(parent); - ASSERT_EQ(2U, render_surface_layer_list.size()); - EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); - EXPECT_EQ(child->id(), render_surface_layer_list.at(1)->id()); + ASSERT_EQ(2U, render_surface_layer_list_impl()->size()); + EXPECT_EQ(parent->id(), render_surface_layer_list_impl()->at(0)->id()); + EXPECT_EQ(child->id(), render_surface_layer_list_impl()->at(1)->id()); } TEST_F(LayerTreeHostCommonTest, ClipRectCullsSurfaceWithoutVisibleContent) { // When a render surface has a clip rect, it is used to clip the content rect - // of the surface. When the render surface is animating its transforms, then - // the content rect's position in the clip rect is not defined on the main - // thread, and its content rect should not be clipped. + // of the surface. // The test tree is set up as follows: // - parent is a container layer that masksToBounds=true to cause clipping. @@ -1658,92 +1433,43 @@ TEST_F(LayerTreeHostCommonTest, ClipRectCullsSurfaceWithoutVisibleContent) { // In this configuration, grand_child should be outside the clipped // content rect of the child, making grand_child not appear in the - // render_surface_layer_list. However, when we place an animation on the - // child, this clipping should be avoided and we should keep the grand_child - // in the render_surface_layer_list. + // render_surface_layer_list. - const gfx::Transform identity_matrix; - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> leaf_node = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - parent->AddChild(child); - child->AddChild(grand_child); - grand_child->AddChild(leaf_node); + LayerImpl* parent = root_layer(); + LayerImpl* child = AddChildToRoot<LayerImpl>(); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + LayerImpl* leaf_node = AddChild<LayerImpl>(grand_child); + leaf_node->SetDrawsContent(true); - host()->SetRootLayer(parent); + const gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, - false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(200.f, 200.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(leaf_node.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(20, 20), true, false, + true); + SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), + gfx::PointF(200.f, 200.f), gfx::Size(10, 10), + true, false, true); + SetLayerPropertiesForTesting(leaf_node, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, false); parent->SetMasksToBounds(true); child->SetOpacity(0.4f); - child->SetForceRenderSurface(true); grand_child->SetOpacity(0.4f); - grand_child->SetForceRenderSurface(true); - { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); - - // Without an animation, we should cull child and grand_child from the - // render_surface_layer_list. - ASSERT_EQ(1U, render_surface_layer_list.size()); - EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); - } - - // Now put an animating transform on child. - AddAnimatedTransformToController( - child->layer_animation_controller(), 10.0, 30, 0); - - { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawProperties(parent); - // With an animating transform, we should keep child and grand_child in the - // render_surface_layer_list. - ASSERT_EQ(3U, render_surface_layer_list.size()); - EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); - EXPECT_EQ(child->id(), render_surface_layer_list.at(1)->id()); - EXPECT_EQ(grand_child->id(), render_surface_layer_list.at(2)->id()); - } + // We should cull child and grand_child from the + // render_surface_layer_list. + ASSERT_EQ(1U, render_surface_layer_list_impl()->size()); + EXPECT_EQ(parent->id(), render_surface_layer_list_impl()->at(0)->id()); } -TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectly) { - // Layer's IsClipped() property is set to true when: +TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectlyLayerImpl) { + // Tests that LayerImpl's IsClipped() property is set to true when: // - the layer clips its subtree, e.g. masks to bounds, // - the layer is clipped by an ancestor that contributes to the same // render target, @@ -1757,83 +1483,41 @@ TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectly) { // and propagates the clip to the subtree. const gfx::Transform identity_matrix; - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> child1 = Layer::Create(layer_settings()); - scoped_refptr<Layer> child2 = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> leaf_node1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> leaf_node2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(parent); - parent->AddChild(child1); - parent->AddChild(child2); - child1->AddChild(grand_child); - child2->AddChild(leaf_node2); - grand_child->AddChild(leaf_node1); - - host()->SetRootLayer(root); - - child2->SetForceRenderSurface(true); + LayerImpl* root = root_layer(); + LayerImpl* parent = AddChild<LayerImpl>(root); + LayerImpl* child1 = AddChild<LayerImpl>(parent); + LayerImpl* child2 = AddChild<LayerImpl>(parent); + LayerImpl* grand_child = AddChild<LayerImpl>(child1); + LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child); + leaf_node1->SetDrawsContent(true); + LayerImpl* leaf_node2 = AddChild<LayerImpl>(child2); + leaf_node2->SetDrawsContent(true); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(child1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, false); - SetLayerPropertiesForTesting(child2.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, + SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, false); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, + SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(grand_child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, false); - SetLayerPropertiesForTesting(leaf_node1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, + SetLayerPropertiesForTesting(leaf_node1, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, false); - SetLayerPropertiesForTesting(leaf_node2.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, + SetLayerPropertiesForTesting(leaf_node2, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, false); // Case 1: nothing is clipped except the root render surface. { - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawProperties(root); ASSERT_TRUE(root->render_surface()); ASSERT_TRUE(child2->render_surface()); @@ -1854,12 +1538,10 @@ TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectly) { // not clipped explicitly because child2's surface already accounts for // that clip. { - RenderSurfaceLayerList render_surface_layer_list; parent->SetMasksToBounds(true); - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + host_impl()->active_tree()->property_trees()->needs_rebuild = true; + + ExecuteCalculateDrawProperties(root); ASSERT_TRUE(root->render_surface()); ASSERT_TRUE(child2->render_surface()); @@ -1873,18 +1555,17 @@ TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectly) { EXPECT_TRUE(grand_child->is_clipped()); EXPECT_TRUE(leaf_node1->is_clipped()); EXPECT_FALSE(leaf_node2->is_clipped()); + + parent->SetMasksToBounds(false); } // Case 3: child2 masksToBounds. The layer and subtree are clipped, and // child2's render surface is not clipped. { - RenderSurfaceLayerList render_surface_layer_list; - parent->SetMasksToBounds(false); child2->SetMasksToBounds(true); - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + host_impl()->active_tree()->property_trees()->needs_rebuild = true; + + ExecuteCalculateDrawProperties(root); ASSERT_TRUE(root->render_surface()); ASSERT_TRUE(child2->render_surface()); @@ -1914,82 +1595,41 @@ TEST_F(LayerTreeHostCommonTest, DrawableContentRectForLayers) { // the mask region. // grand_child4 - outside parent's clip rect; the DrawableContentRect should // be empty. - // const gfx::Transform identity_matrix; - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child1 = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child2 = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child3 = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child4 = Layer::Create(layer_settings()); - - parent->AddChild(child); - child->AddChild(grand_child1); - child->AddChild(grand_child2); - child->AddChild(grand_child3); - child->AddChild(grand_child4); - - host()->SetRootLayer(parent); + LayerImpl* parent = root_layer(); + LayerImpl* child = AddChild<LayerImpl>(parent); + LayerImpl* grand_child1 = AddChild<LayerImpl>(child); + LayerImpl* grand_child2 = AddChild<LayerImpl>(child); + LayerImpl* grand_child3 = AddChild<LayerImpl>(child); + LayerImpl* grand_child4 = AddChild<LayerImpl>(child); - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(500, 500), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, - false); - SetLayerPropertiesForTesting(grand_child1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(5.f, 5.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child2.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(15.f, 15.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child3.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(15.f, 15.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child4.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(45.f, 45.f), - gfx::Size(10, 10), - true, - false); + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(500, 500), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(20, 20), true, false, + true); + SetLayerPropertiesForTesting(grand_child1, identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(10, 10), true, + false, false); + SetLayerPropertiesForTesting(grand_child2, identity_matrix, gfx::Point3F(), + gfx::PointF(15.f, 15.f), gfx::Size(10, 10), true, + false, false); + SetLayerPropertiesForTesting(grand_child3, identity_matrix, gfx::Point3F(), + gfx::PointF(15.f, 15.f), gfx::Size(10, 10), true, + false, false); + SetLayerPropertiesForTesting(grand_child4, identity_matrix, gfx::Point3F(), + gfx::PointF(45.f, 45.f), gfx::Size(10, 10), true, + false, false); child->SetMasksToBounds(true); grand_child3->SetMasksToBounds(true); - // Force everyone to be a render surface. + // Force child to be a render surface. child->SetOpacity(0.4f); - grand_child1->SetOpacity(0.5f); - grand_child2->SetOpacity(0.5f); - grand_child3->SetOpacity(0.5f); - grand_child4->SetOpacity(0.5f); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawProperties(parent); 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()); @@ -2005,106 +1645,54 @@ TEST_F(LayerTreeHostCommonTest, ClipRectIsPropagatedCorrectlyToSurfaces) { // clipping; instead the surface will enforce the clip for the entire subtree. // They may still have a clip rect of their own layer bounds, however, if // masksToBounds was true. - const gfx::Transform identity_matrix; - scoped_refptr<Layer> parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child1 = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child2 = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child3 = Layer::Create(layer_settings()); - scoped_refptr<Layer> grand_child4 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> leaf_node1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> leaf_node2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> leaf_node3 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> leaf_node4 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - - parent->AddChild(child); - child->AddChild(grand_child1); - child->AddChild(grand_child2); - child->AddChild(grand_child3); - child->AddChild(grand_child4); - - host()->SetRootLayer(parent); - + LayerImpl* parent = root_layer(); + LayerImpl* child = AddChildToRoot<LayerImpl>(); + LayerImpl* grand_child1 = AddChild<LayerImpl>(child); + LayerImpl* grand_child2 = AddChild<LayerImpl>(child); + LayerImpl* grand_child3 = AddChild<LayerImpl>(child); + LayerImpl* grand_child4 = AddChild<LayerImpl>(child); // the leaf nodes ensure that these grand_children become render surfaces for // this test. - grand_child1->AddChild(leaf_node1); - grand_child2->AddChild(leaf_node2); - grand_child3->AddChild(leaf_node3); - grand_child4->AddChild(leaf_node4); + LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child1); + leaf_node1->SetDrawsContent(true); + LayerImpl* leaf_node2 = AddChild<LayerImpl>(grand_child2); + leaf_node2->SetDrawsContent(true); + LayerImpl* leaf_node3 = AddChild<LayerImpl>(grand_child3); + leaf_node3->SetDrawsContent(true); + LayerImpl* leaf_node4 = AddChild<LayerImpl>(grand_child4); + leaf_node4->SetDrawsContent(true); - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(500, 500), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, - false); - SetLayerPropertiesForTesting(grand_child1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(5.f, 5.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child2.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(15.f, 15.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child3.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(15.f, 15.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(grand_child4.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(45.f, 45.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(leaf_node1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, + const gfx::Transform identity_matrix; + + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(500, 500), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(20, 20), true, false, + true); + SetLayerPropertiesForTesting(grand_child1, identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(10, 10), true, + false, true); + SetLayerPropertiesForTesting(grand_child2, identity_matrix, gfx::Point3F(), + gfx::PointF(15.f, 15.f), gfx::Size(10, 10), true, + false, true); + SetLayerPropertiesForTesting(grand_child3, identity_matrix, gfx::Point3F(), + gfx::PointF(15.f, 15.f), gfx::Size(10, 10), true, + false, true); + SetLayerPropertiesForTesting(grand_child4, identity_matrix, gfx::Point3F(), + gfx::PointF(45.f, 45.f), gfx::Size(10, 10), true, + false, true); + SetLayerPropertiesForTesting(leaf_node1, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, false); - SetLayerPropertiesForTesting(leaf_node2.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, + SetLayerPropertiesForTesting(leaf_node2, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, false); - SetLayerPropertiesForTesting(leaf_node3.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, + SetLayerPropertiesForTesting(leaf_node3, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, false); - SetLayerPropertiesForTesting(leaf_node4.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, + SetLayerPropertiesForTesting(leaf_node4, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, false); child->SetMasksToBounds(true); @@ -2113,21 +1701,13 @@ TEST_F(LayerTreeHostCommonTest, ClipRectIsPropagatedCorrectlyToSurfaces) { // Force everyone to be a render surface. child->SetOpacity(0.4f); - child->SetForceRenderSurface(true); grand_child1->SetOpacity(0.5f); - grand_child1->SetForceRenderSurface(true); grand_child2->SetOpacity(0.5f); - grand_child2->SetForceRenderSurface(true); grand_child3->SetOpacity(0.5f); - grand_child3->SetForceRenderSurface(true); grand_child4->SetOpacity(0.5f); - grand_child4->SetForceRenderSurface(true); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawProperties(parent); + ASSERT_TRUE(grand_child1->render_surface()); ASSERT_TRUE(grand_child2->render_surface()); ASSERT_TRUE(grand_child3->render_surface()); @@ -2235,46 +1815,14 @@ TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) { EXPECT_EQ(render_surface2, child_of_rs2->render_target()); EXPECT_EQ(render_surface2, grand_child_of_rs2->render_target()); - // Verify draw_opacity_is_animating values - EXPECT_FALSE(parent->draw_opacity_is_animating()); - EXPECT_FALSE(child_of_root->draw_opacity_is_animating()); - EXPECT_TRUE(grand_child_of_root->draw_opacity_is_animating()); - EXPECT_FALSE(render_surface1->draw_opacity_is_animating()); - EXPECT_TRUE(render_surface1->render_surface()->draw_opacity_is_animating()); - EXPECT_FALSE(child_of_rs1->draw_opacity_is_animating()); - EXPECT_FALSE(grand_child_of_rs1->draw_opacity_is_animating()); - EXPECT_FALSE(render_surface2->draw_opacity_is_animating()); - EXPECT_FALSE(render_surface2->render_surface()->draw_opacity_is_animating()); - EXPECT_FALSE(child_of_rs2->draw_opacity_is_animating()); - EXPECT_FALSE(grand_child_of_rs2->draw_opacity_is_animating()); - - // Verify draw_transform_is_animating values - EXPECT_FALSE(parent->draw_transform_is_animating()); - EXPECT_FALSE(child_of_root->draw_transform_is_animating()); - EXPECT_TRUE(grand_child_of_root->draw_transform_is_animating()); - EXPECT_FALSE(render_surface1->draw_transform_is_animating()); - EXPECT_FALSE(render_surface1->render_surface() - ->target_surface_transforms_are_animating()); - EXPECT_FALSE(child_of_rs1->draw_transform_is_animating()); - EXPECT_FALSE(grand_child_of_rs1->draw_transform_is_animating()); - EXPECT_FALSE(render_surface2->draw_transform_is_animating()); - EXPECT_TRUE(render_surface2->render_surface() - ->target_surface_transforms_are_animating()); - EXPECT_FALSE(child_of_rs2->draw_transform_is_animating()); - EXPECT_TRUE(grand_child_of_rs2->draw_transform_is_animating()); - // Verify screen_space_transform_is_animating values EXPECT_FALSE(parent->screen_space_transform_is_animating()); EXPECT_FALSE(child_of_root->screen_space_transform_is_animating()); EXPECT_TRUE(grand_child_of_root->screen_space_transform_is_animating()); EXPECT_FALSE(render_surface1->screen_space_transform_is_animating()); - EXPECT_FALSE(render_surface1->render_surface() - ->screen_space_transforms_are_animating()); EXPECT_FALSE(child_of_rs1->screen_space_transform_is_animating()); EXPECT_FALSE(grand_child_of_rs1->screen_space_transform_is_animating()); EXPECT_TRUE(render_surface2->screen_space_transform_is_animating()); - EXPECT_TRUE(render_surface2->render_surface() - ->screen_space_transforms_are_animating()); EXPECT_TRUE(child_of_rs2->screen_space_transform_is_animating()); EXPECT_TRUE(grand_child_of_rs2->screen_space_transform_is_animating()); @@ -2302,6 +1850,75 @@ TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) { 5.0, grand_child_of_rs2->screen_space_transform().matrix().get(1, 3)); } +TEST_F(LayerTreeHostCommonTest, LargeTransforms) { + LayerImpl* parent = root_layer(); + LayerImpl* child = AddChildToRoot<LayerImpl>(); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + + grand_child->SetDrawsContent(true); + + gfx::Transform large_transform; + large_transform.Scale(SkDoubleToMScalar(1e37), SkDoubleToMScalar(1e37)); + + gfx::Transform identity; + + SetLayerPropertiesForTesting(parent, identity, gfx::Point3F(), gfx::PointF(), + gfx::Size(10, 10), true, false, true); + SetLayerPropertiesForTesting(child, large_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + false); + SetLayerPropertiesForTesting(grand_child, large_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + false); + ExecuteCalculateDrawProperties(parent); + + EXPECT_EQ(gfx::Rect(), grand_child->visible_layer_rect()); +} + +TEST_F(LayerTreeHostCommonTest, + ScreenSpaceTransformIsAnimatingWithDelayedAnimation) { + LayerImpl* parent = root_layer(); + LayerImpl* child = AddChild<LayerImpl>(parent); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + LayerImpl* great_grand_child = AddChild<LayerImpl>(grand_child); + + parent->SetDrawsContent(true); + child->SetDrawsContent(true); + grand_child->SetDrawsContent(true); + great_grand_child->SetDrawsContent(true); + + gfx::Transform identity; + + SetLayerPropertiesForTesting(parent, identity, gfx::Point3F(), gfx::PointF(), + gfx::Size(10, 10), true, false, true); + SetLayerPropertiesForTesting(child, identity, gfx::Point3F(), gfx::PointF(), + gfx::Size(10, 10), true, false, false); + SetLayerPropertiesForTesting(grand_child, identity, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + false); + SetLayerPropertiesForTesting(great_grand_child, identity, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, + false); + + // Add a transform animation with a start delay to |grand_child|. + scoped_ptr<Animation> animation = Animation::Create( + scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), 0, 1, + Animation::TRANSFORM); + animation->set_fill_mode(Animation::FILL_MODE_NONE); + animation->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); + grand_child->layer_animation_controller()->AddAnimation(animation.Pass()); + + ExecuteCalculateDrawProperties(parent); + + EXPECT_FALSE(parent->screen_space_transform_is_animating()); + EXPECT_FALSE(child->screen_space_transform_is_animating()); + + EXPECT_FALSE(grand_child->TransformIsAnimating()); + EXPECT_TRUE(grand_child->HasPotentiallyRunningTransformAnimation()); + EXPECT_TRUE(grand_child->screen_space_transform_is_animating()); + EXPECT_TRUE(great_grand_child->screen_space_transform_is_animating()); +} + TEST_F(LayerTreeHostCommonTest, VisibleRectForIdentityTransform) { // Test the calculateVisibleRect() function works correctly for identity // transforms. @@ -2574,8 +2191,8 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectForPerspectiveUnprojection) { // Sanity check that un-projection does indeed cause w < 0, otherwise this // code is not testing the intended scenario. bool clipped; - gfx::RectF clipped_rect = - MathUtil::MapClippedRect(layer_to_surface_transform, layer_content_rect); + gfx::RectF clipped_rect = MathUtil::MapClippedRect( + layer_to_surface_transform, gfx::RectF(layer_content_rect)); MathUtil::ProjectQuad( Inverse(layer_to_surface_transform), gfx::QuadF(clipped_rect), &clipped); ASSERT_TRUE(clipped); @@ -2591,153 +2208,103 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectForPerspectiveUnprojection) { TEST_F(LayerTreeHostCommonTest, VisibleRectsForPositionedRootLayerClippedByViewport) { - scoped_refptr<Layer> root = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + root->SetDrawsContent(true); gfx::Transform identity_matrix; // Root layer is positioned at (60, 70). The default device viewport size // is (0, 0, 100x100) in target space. So the root layer's visible rect // will be clipped by the viewport to be (0, 0, 40x30) in layer's space. - SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), gfx::PointF(60, 70), gfx::Size(100, 100), true, - false); - ExecuteCalculateDrawProperties(root.get()); + false, true); + ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + EXPECT_EQ(gfx::RectF(100.f, 100.f), root->render_surface()->DrawableContentRect()); // In target space, not clipped. EXPECT_EQ(gfx::Rect(60, 70, 100, 100), root->drawable_content_rect()); // In layer space, clipped. - EXPECT_EQ(gfx::Rect(0, 0, 40, 30), root->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(40, 30), root->visible_layer_rect()); } TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) { - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child3 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(child1); - root->AddChild(child2); - root->AddChild(child3); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* child1_layer = AddChildToRoot<LayerImpl>(); + child1_layer->SetDrawsContent(true); + LayerImpl* child2_layer = AddChildToRoot<LayerImpl>(); + child2_layer->SetDrawsContent(true); + LayerImpl* child3_layer = AddChildToRoot<LayerImpl>(); + child3_layer->SetDrawsContent(true); 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(), - 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, + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(child1_layer, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, false); + SetLayerPropertiesForTesting(child2_layer, identity_matrix, gfx::Point3F(), + gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(child3_layer, identity_matrix, gfx::Point3F(), + gfx::PointF(125.f, 125.f), gfx::Size(50, 50), + true, false, false); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + EXPECT_EQ(gfx::RectF(100.f, 100.f), root->render_surface()->DrawableContentRect()); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible_layer_rects. EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); // layer visible_layer_rects are clipped by their target surface. - EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2->visible_layer_rect()); - EXPECT_TRUE(child3->visible_layer_rect().IsEmpty()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1_layer->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 25, 25), child2_layer->visible_layer_rect()); + EXPECT_TRUE(child3_layer->visible_layer_rect().IsEmpty()); // layer drawable_content_rects are not clipped. - 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()); + EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1_layer->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(75, 75, 50, 50), child2_layer->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(125, 125, 50, 50), child3_layer->drawable_content_rect()); } TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForLayersClippedByLayer) { - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> grand_child1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> grand_child2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> grand_child3 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(child); - child->AddChild(grand_child1); - child->AddChild(grand_child2); - child->AddChild(grand_child3); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* child = AddChildToRoot<LayerImpl>(); + LayerImpl* grand_child1 = AddChild<LayerImpl>(child); + grand_child1->SetDrawsContent(true); + LayerImpl* grand_child2 = AddChild<LayerImpl>(child); + grand_child2->SetDrawsContent(true); + LayerImpl* grand_child3 = AddChild<LayerImpl>(child); + grand_child3->SetDrawsContent(true); gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(grand_child1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(5.f, 5.f), - gfx::Size(50, 50), - true, - false); - SetLayerPropertiesForTesting(grand_child2.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(75.f, 75.f), - gfx::Size(50, 50), - true, - false); - SetLayerPropertiesForTesting(grand_child3.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(125.f, 125.f), - gfx::Size(50, 50), - true, + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, false); + SetLayerPropertiesForTesting(grand_child1, identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(grand_child2, identity_matrix, gfx::Point3F(), + gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(grand_child3, identity_matrix, gfx::Point3F(), + gfx::PointF(125.f, 125.f), gfx::Size(50, 50), + true, false, false); child->SetMasksToBounds(true); - ExecuteCalculateDrawProperties(root.get()); - - ASSERT_FALSE(child->render_surface()); + ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + EXPECT_EQ(gfx::RectF(100.f, 100.f), root->render_surface()->DrawableContentRect()); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible content rects. EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); @@ -2788,75 +2355,48 @@ TEST_F(LayerTreeHostCommonTest, VisibleContentRectWithClippingAndScaling) { TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForLayersInUnclippedRenderSurface) { - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child3 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(render_surface1); - render_surface1->AddChild(child1); - render_surface1->AddChild(child2); - render_surface1->AddChild(child3); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* render_surface = AddChildToRoot<LayerImpl>(); + LayerImpl* child1 = AddChild<LayerImpl>(render_surface); + child1->SetDrawsContent(true); + LayerImpl* child2 = AddChild<LayerImpl>(render_surface); + child2->SetDrawsContent(true); + LayerImpl* child3 = AddChild<LayerImpl>(render_surface); + child3->SetDrawsContent(true); gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(3, 4), - 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); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(3, 4), true, false, + true); + SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), + gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(child3, identity_matrix, gfx::Point3F(), + gfx::PointF(125.f, 125.f), gfx::Size(50, 50), + true, false, false); - render_surface1->SetForceRenderSurface(true); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); - ASSERT_TRUE(render_surface1->render_surface()); + ASSERT_TRUE(render_surface->render_surface()); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + EXPECT_EQ(gfx::RectF(100.f, 100.f), root->render_surface()->DrawableContentRect()); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible content rects. EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface->visible_layer_rect()); // An unclipped surface grows its DrawableContentRect to include all drawable // regions of the subtree. - EXPECT_EQ(gfx::Rect(5, 5, 170, 170), - render_surface1->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::RectF(5.f, 5.f, 170.f, 170.f), + render_surface->render_surface()->DrawableContentRect()); // All layers that draw content into the unclipped surface are also unclipped. EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_layer_rect()); @@ -2870,36 +2410,32 @@ TEST_F(LayerTreeHostCommonTest, TEST_F(LayerTreeHostCommonTest, VisibleContentRectsForClippedSurfaceWithEmptyClip) { - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child3 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(child1); - root->AddChild(child2); - root->AddChild(child3); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* child1 = AddChild<LayerImpl>(root); + LayerImpl* child2 = AddChild<LayerImpl>(root); + LayerImpl* child3 = AddChild<LayerImpl>(root); + child1->SetDrawsContent(true); + child2->SetDrawsContent(true); + child3->SetDrawsContent(true); 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(), + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, - false); - SetLayerPropertiesForTesting(child2.get(), identity_matrix, gfx::Point3F(), + false, false); + SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true, - false); - SetLayerPropertiesForTesting(child3.get(), identity_matrix, gfx::Point3F(), + false, false); + SetLayerPropertiesForTesting(child3, identity_matrix, gfx::Point3F(), gfx::PointF(125.f, 125.f), gfx::Size(50, 50), - true, false); + true, false, false); - RenderSurfaceLayerList render_surface_layer_list; + LayerImplList render_surface_layer_list_impl; // Now set the root render surface an empty clip. - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), gfx::Size(), &render_surface_layer_list); + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( + root, gfx::Size(), &render_surface_layer_list_impl); LayerTreeHostCommon::CalculateDrawProperties(&inputs); ASSERT_TRUE(root->render_surface()); @@ -2919,34 +2455,23 @@ TEST_F(LayerTreeHostCommonTest, TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForLayersWithUninvertibleTransform) { - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(child); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* child = AddChildToRoot<LayerImpl>(); + child->SetDrawsContent(true); // Case 1: a truly degenerate matrix gfx::Transform identity_matrix; gfx::Transform uninvertible_matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); ASSERT_FALSE(uninvertible_matrix.IsInvertible()); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(child.get(), - uninvertible_matrix, - gfx::Point3F(), - gfx::PointF(5.f, 5.f), - gfx::Size(50, 50), - true, - false); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(child, uninvertible_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, + false, false); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); EXPECT_TRUE(child->visible_layer_rect().IsEmpty()); EXPECT_TRUE(child->drawable_content_rect().IsEmpty()); @@ -2957,15 +2482,11 @@ TEST_F(LayerTreeHostCommonTest, uninvertible_matrix.matrix().set(2, 2, 0.0); ASSERT_FALSE(uninvertible_matrix.IsInvertible()); - SetLayerPropertiesForTesting(child.get(), - uninvertible_matrix, - gfx::Point3F(), - gfx::PointF(5.f, 5.f), - gfx::Size(50, 50), - true, - false); + SetLayerPropertiesForTesting(child, uninvertible_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, + false, false); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); EXPECT_TRUE(child->visible_layer_rect().IsEmpty()); EXPECT_TRUE(child->drawable_content_rect().IsEmpty()); @@ -2976,21 +2497,125 @@ TEST_F(LayerTreeHostCommonTest, uninvertible_matrix.matrix().set(2, 2, 0.0); ASSERT_FALSE(uninvertible_matrix.IsInvertible()); - SetLayerPropertiesForTesting(child.get(), - uninvertible_matrix, - gfx::Point3F(), - gfx::PointF(5.f, 5.f), - gfx::Size(50, 50), - true, - false); + SetLayerPropertiesForTesting(child, uninvertible_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, + false, false); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); EXPECT_TRUE(child->visible_layer_rect().IsEmpty()); EXPECT_TRUE(child->drawable_content_rect().IsEmpty()); } TEST_F(LayerTreeHostCommonTest, + VisibleContentRectForLayerWithUninvertibleDrawTransform) { + LayerImpl* root = root_layer(); + LayerImpl* child = AddChildToRoot<LayerImpl>(); + LayerImpl* grand_child = AddChild<LayerImpl>(child); + child->SetDrawsContent(true); + grand_child->SetDrawsContent(true); + + gfx::Transform identity_matrix; + + gfx::Transform perspective; + perspective.ApplyPerspectiveDepth(SkDoubleToMScalar(1e-12)); + + gfx::Transform rotation; + rotation.RotateAboutYAxis(45.0); + + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(child, perspective, gfx::Point3F(), + gfx::PointF(10.f, 10.f), gfx::Size(100, 100), + false, true, false); + SetLayerPropertiesForTesting(grand_child, rotation, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), false, true, + false); + + ExecuteCalculateDrawProperties(root); + + // Though all layers have invertible transforms, matrix multiplication using + // floating-point math makes the draw transform uninvertible. + EXPECT_FALSE(grand_child->draw_transform().IsInvertible()); + + // CalcDrawProps only skips a subtree when a layer's own transform is + // uninvertible, not when its draw transform is invertible, since CDP makes + // skipping decisions before computing a layer's draw transform. Property + // trees make skipping decisions after computing draw transforms, so could be + // made to skip layers with an uninvertible draw transform (once CDP is + // deleted). + EXPECT_EQ(gfx::Rect(grand_child->bounds()), + grand_child->visible_layer_rect()); +} + +TEST_F(LayerTreeHostCommonTest, + OcclusionForLayerWithUninvertibleDrawTransform) { + FakeImplProxy proxy; + TestSharedBitmapManager shared_bitmap_manager; + TestTaskGraphRunner task_graph_runner; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); + FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, + &task_graph_runner); + 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> grand_child = + LayerImpl::Create(host_impl.active_tree(), 3); + scoped_ptr<LayerImpl> occluding_child = + LayerImpl::Create(host_impl.active_tree(), 4); + child->SetDrawsContent(true); + grand_child->SetDrawsContent(true); + occluding_child->SetDrawsContent(true); + occluding_child->SetContentsOpaque(true); + + gfx::Transform identity_matrix; + gfx::Transform perspective; + perspective.ApplyPerspectiveDepth(SkDoubleToMScalar(1e-12)); + + gfx::Transform rotation; + rotation.RotateAboutYAxis(45.0); + + SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(1000, 1000), true, + false, true); + SetLayerPropertiesForTesting(child.get(), perspective, gfx::Point3F(), + gfx::PointF(10.f, 10.f), gfx::Size(300, 300), + false, true, false); + SetLayerPropertiesForTesting(grand_child.get(), rotation, gfx::Point3F(), + gfx::PointF(), gfx::Size(200, 200), false, true, + false); + SetLayerPropertiesForTesting(occluding_child.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), + gfx::Size(200, 200), false, false, false); + + host_impl.SetViewportSize(root->bounds()); + + child->AddChild(grand_child.Pass()); + root->AddChild(child.Pass()); + root->AddChild(occluding_child.Pass()); + host_impl.active_tree()->SetRootLayer(root.Pass()); + host_impl.InitializeRenderer(output_surface.get()); + bool update_lcd_text = false; + host_impl.active_tree()->UpdateDrawProperties(update_lcd_text); + + LayerImpl* grand_child_ptr = + host_impl.active_tree()->root_layer()->children()[0]->children()[0]; + + // Though all layers have invertible transforms, matrix multiplication using + // floating-point math makes the draw transform uninvertible. + EXPECT_FALSE(grand_child_ptr->draw_transform().IsInvertible()); + + // Since |grand_child| has an uninvertible draw transform, it is treated as + // unoccluded (even though |occluding_child| comes later in draw order, and + // hence potentially occludes it). + gfx::Rect layer_bounds = gfx::Rect(grand_child_ptr->bounds()); + EXPECT_EQ( + layer_bounds, + grand_child_ptr->draw_properties() + .occlusion_in_content_space.GetUnoccludedContentRect(layer_bounds)); +} + +TEST_F(LayerTreeHostCommonTest, SingularTransformDoesNotPreventClearingDrawProperties) { scoped_refptr<Layer> root = Layer::Create(layer_settings()); scoped_refptr<LayerWithForcedDrawsContent> child = @@ -3065,76 +2690,50 @@ TEST_F(LayerTreeHostCommonTest, TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForLayersInClippedRenderSurface) { - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child3 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(render_surface1); - render_surface1->AddChild(child1); - render_surface1->AddChild(child2); - render_surface1->AddChild(child3); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* render_surface = AddChildToRoot<LayerImpl>(); + LayerImpl* child1 = AddChild<LayerImpl>(render_surface); + child1->SetDrawsContent(true); + LayerImpl* child2 = AddChild<LayerImpl>(render_surface); + child2->SetDrawsContent(true); + LayerImpl* child3 = AddChild<LayerImpl>(render_surface); + child3->SetDrawsContent(true); gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(3, 4), - 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); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(3, 4), true, false, + true); + SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), + gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(child3, identity_matrix, gfx::Point3F(), + gfx::PointF(125.f, 125.f), gfx::Size(50, 50), + true, false, false); root->SetMasksToBounds(true); - render_surface1->SetForceRenderSurface(true); - ExecuteCalculateDrawProperties(root.get()); - ASSERT_TRUE(render_surface1->render_surface()); + ExecuteCalculateDrawProperties(root); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + ASSERT_TRUE(render_surface->render_surface()); + + EXPECT_EQ(gfx::RectF(100.f, 100.f), root->render_surface()->DrawableContentRect()); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible content rects. EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface->visible_layer_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_EQ(gfx::Rect(5, 5, 95, 95), - render_surface1->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::RectF(5.f, 5.f, 95.f, 95.f), + render_surface->render_surface()->DrawableContentRect()); // All layers that draw content into the surface have their visible content // rect clipped by the surface clip rect. @@ -3151,78 +2750,46 @@ TEST_F(LayerTreeHostCommonTest, TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSurfaceHierarchy) { // Check that clipping does not propagate down surfaces. - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface2 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child2 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child3 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(render_surface1); - render_surface1->AddChild(render_surface2); - render_surface2->AddChild(child1); - render_surface2->AddChild(child2); - render_surface2->AddChild(child3); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* render_surface1 = AddChildToRoot<LayerImpl>(); + LayerImpl* render_surface2 = AddChild<LayerImpl>(render_surface1); + LayerImpl* child1 = AddChild<LayerImpl>(render_surface2); + child1->SetDrawsContent(true); + LayerImpl* child2 = AddChild<LayerImpl>(render_surface2); + child2->SetDrawsContent(true); + LayerImpl* child3 = AddChild<LayerImpl>(render_surface2); + child3->SetDrawsContent(true); gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(3, 4), - true, - false); - SetLayerPropertiesForTesting(render_surface2.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(7, 13), - 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); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(render_surface1, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(3, 4), true, false, + true); + SetLayerPropertiesForTesting(render_surface2, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(7, 13), true, false, + true); + SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), + gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(child3, identity_matrix, gfx::Point3F(), + gfx::PointF(125.f, 125.f), gfx::Size(50, 50), + true, false, false); root->SetMasksToBounds(true); - render_surface1->SetForceRenderSurface(true); - render_surface2->SetForceRenderSurface(true); - ExecuteCalculateDrawProperties(root.get()); + + ExecuteCalculateDrawProperties(root); ASSERT_TRUE(render_surface1->render_surface()); ASSERT_TRUE(render_surface2->render_surface()); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + EXPECT_EQ(gfx::RectF(100.f, 100.f), root->render_surface()->DrawableContentRect()); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), root->drawable_content_rect()); + EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect()); // Layers that do not draw content should have empty visible content rects. EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); @@ -3231,13 +2798,13 @@ TEST_F(LayerTreeHostCommonTest, // A clipped surface grows its DrawableContentRect to include all drawable // regions of the subtree, but also gets clamped by the ancestor's clip. - EXPECT_EQ(gfx::Rect(5, 5, 95, 95), + EXPECT_EQ(gfx::RectF(5.f, 5.f, 95.f, 95.f), 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_EQ(gfx::Rect(5, 5, 170, 170), + EXPECT_EQ(gfx::RectF(5.f, 5.f, 170.f, 170.f), render_surface2->render_surface()->DrawableContentRect()); // All layers that draw content into render_surface2 think they are unclipped. @@ -3255,53 +2822,35 @@ TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsWithTransformOnUnclippedSurface) { // Layers that have non-axis aligned bounds (due to transforms) have an // expanded, axis-aligned DrawableContentRect and visible content rect. - - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(render_surface1); - render_surface1->AddChild(child1); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* render_surface = AddChildToRoot<LayerImpl>(); + LayerImpl* child1 = AddChild<LayerImpl>(render_surface); + child1->SetDrawsContent(true); gfx::Transform identity_matrix; gfx::Transform child_rotation; child_rotation.Rotate(45.0); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(3, 4), - true, - false); - SetLayerPropertiesForTesting(child1.get(), - child_rotation, - gfx::Point3F(25, 25, 0.f), - gfx::PointF(25.f, 25.f), - gfx::Size(50, 50), - true, - false); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(3, 4), true, false, + true); + SetLayerPropertiesForTesting( + child1, child_rotation, gfx::Point3F(25, 25, 0.f), + gfx::PointF(25.f, 25.f), gfx::Size(50, 50), true, false, false); - render_surface1->SetForceRenderSurface(true); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); - ASSERT_TRUE(render_surface1->render_surface()); + ASSERT_TRUE(render_surface->render_surface()); - EXPECT_EQ(gfx::Rect(0, 0, 100, 100), + EXPECT_EQ(gfx::RectF(100.f, 100.f), 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_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect()); - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface1->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), render_surface->visible_layer_rect()); // The unclipped surface grows its DrawableContentRect to include all drawable // regions of the subtree. @@ -3311,8 +2860,8 @@ TEST_F(LayerTreeHostCommonTest, 50 - diagonal_radius, diagonal_radius * 2, diagonal_radius * 2); - EXPECT_EQ(expected_surface_drawable_content, - render_surface1->render_surface()->DrawableContentRect()); + EXPECT_EQ(gfx::RectF(expected_surface_drawable_content), + render_surface->render_surface()->DrawableContentRect()); // All layers that draw content into the unclipped surface are also unclipped. EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_layer_rect()); @@ -3323,47 +2872,30 @@ TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsWithTransformOnClippedSurface) { // Layers that have non-axis aligned bounds (due to transforms) have an // expanded, axis-aligned DrawableContentRect and visible content rect. - - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child1 = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - root->AddChild(render_surface1); - render_surface1->AddChild(child1); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + LayerImpl* render_surface = AddChildToRoot<LayerImpl>(); + LayerImpl* child1 = AddChild<LayerImpl>(render_surface); + child1->SetDrawsContent(true); gfx::Transform identity_matrix; gfx::Transform child_rotation; child_rotation.Rotate(45.0); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(3, 4), - true, - false); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(3, 4), true, false, + true); - SetLayerPropertiesForTesting(child1.get(), - child_rotation, - gfx::Point3F(25, 25, 0.f), - gfx::PointF(25.f, 25.f), - gfx::Size(50, 50), - true, - false); + SetLayerPropertiesForTesting( + child1, child_rotation, gfx::Point3F(25, 25, 0.f), + gfx::PointF(25.f, 25.f), gfx::Size(50, 50), true, false, false); root->SetMasksToBounds(true); - render_surface1->SetForceRenderSurface(true); - ExecuteCalculateDrawProperties(root.get()); - ASSERT_TRUE(render_surface1->render_surface()); + ExecuteCalculateDrawProperties(root); + + ASSERT_TRUE(render_surface->render_surface()); // The clipped surface clamps the DrawableContentRect that encloses the // rotated layer. @@ -3372,10 +2904,10 @@ TEST_F(LayerTreeHostCommonTest, 50 - diagonal_radius, diagonal_radius * 2, diagonal_radius * 2); - gfx::Rect expected_surface_drawable_content = - gfx::IntersectRects(unclipped_surface_content, gfx::Rect(0, 0, 50, 50)); + gfx::RectF expected_surface_drawable_content( + gfx::IntersectRects(unclipped_surface_content, gfx::Rect(50, 50))); EXPECT_EQ(expected_surface_drawable_content, - render_surface1->render_surface()->DrawableContentRect()); + render_surface->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 @@ -3389,92 +2921,63 @@ TEST_F(LayerTreeHostCommonTest, } TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsInHighDPI) { - MockContentLayerClient client; - - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<FakePictureLayer> render_surface1 = - CreateDrawablePictureLayer(layer_settings(), &client); - scoped_refptr<FakePictureLayer> render_surface2 = - CreateDrawablePictureLayer(layer_settings(), &client); - scoped_refptr<FakePictureLayer> child1 = - CreateDrawablePictureLayer(layer_settings(), &client); - scoped_refptr<FakePictureLayer> child2 = - CreateDrawablePictureLayer(layer_settings(), &client); - scoped_refptr<FakePictureLayer> child3 = - CreateDrawablePictureLayer(layer_settings(), &client); - root->AddChild(render_surface1); - render_surface1->AddChild(render_surface2); - render_surface2->AddChild(child1); - render_surface2->AddChild(child2); - render_surface2->AddChild(child3); - - host()->SetRootLayer(root); + LayerImpl* root = root_layer(); + FakePictureLayerImpl* render_surface1 = + AddChildToRoot<FakePictureLayerImpl>(); + render_surface1->SetDrawsContent(true); + FakePictureLayerImpl* render_surface2 = + AddChild<FakePictureLayerImpl>(render_surface1); + render_surface2->SetDrawsContent(true); + FakePictureLayerImpl* child1 = + AddChild<FakePictureLayerImpl>(render_surface2); + child1->SetDrawsContent(true); + FakePictureLayerImpl* child2 = + AddChild<FakePictureLayerImpl>(render_surface2); + child2->SetDrawsContent(true); + FakePictureLayerImpl* child3 = + AddChild<FakePictureLayerImpl>(render_surface2); + child3->SetDrawsContent(true); gfx::Transform identity_matrix; - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(100, 100), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(5.f, 5.f), - gfx::Size(3, 4), - true, - false); - SetLayerPropertiesForTesting(render_surface2.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(5.f, 5.f), - gfx::Size(7, 13), - 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); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + true); + SetLayerPropertiesForTesting(render_surface1, identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(3, 4), true, + false, true); + SetLayerPropertiesForTesting(render_surface2, identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(7, 13), true, + false, true); + SetLayerPropertiesForTesting(child1, identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(child2, identity_matrix, gfx::Point3F(), + gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true, + false, false); + SetLayerPropertiesForTesting(child3, identity_matrix, gfx::Point3F(), + gfx::PointF(125.f, 125.f), gfx::Size(50, 50), + true, false, false); float device_scale_factor = 2.f; root->SetMasksToBounds(true); - render_surface1->SetForceRenderSurface(true); - render_surface2->SetForceRenderSurface(true); - ExecuteCalculateDrawProperties(root.get(), device_scale_factor); + + ExecuteCalculateDrawProperties(root, device_scale_factor); ASSERT_TRUE(render_surface1->render_surface()); ASSERT_TRUE(render_surface2->render_surface()); // drawable_content_rects for all layers and surfaces are scaled by // device_scale_factor. - EXPECT_EQ(gfx::Rect(0, 0, 200, 200), + EXPECT_EQ(gfx::RectF(200.f, 200.f), root->render_surface()->DrawableContentRect()); EXPECT_EQ(gfx::Rect(0, 0, 200, 200), root->drawable_content_rect()); - EXPECT_EQ(gfx::Rect(10, 10, 190, 190), + EXPECT_EQ(gfx::RectF(10.f, 10.f, 190.f, 190.f), render_surface1->render_surface()->DrawableContentRect()); // render_surface2 lives in the "unclipped universe" of render_surface1, and // is only implicitly clipped by render_surface1. - EXPECT_EQ(gfx::Rect(10, 10, 350, 350), + EXPECT_EQ(gfx::RectF(10.f, 10.f, 350.f, 350.f), render_surface2->render_surface()->DrawableContentRect()); EXPECT_EQ(gfx::Rect(10, 10, 100, 100), child1->drawable_content_rect()); @@ -3618,81 +3121,26 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithoutPreserves3d) { true, false); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawPropertiesWithPropertyTrees(parent.get()); // Verify which render surfaces were created. - EXPECT_FALSE(front_facing_child->render_surface()); - EXPECT_FALSE(back_facing_child->render_surface()); - EXPECT_TRUE(front_facing_surface->render_surface()); - 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()); - EXPECT_FALSE(back_facing_child_of_back_facing_surface->render_surface()); - - // Verify the render_surface_layer_list. - ASSERT_EQ(3u, render_surface_layer_list.size()); - EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); - EXPECT_EQ(front_facing_surface->id(), render_surface_layer_list.at(1)->id()); - // Even though the back facing surface LAYER gets culled, the other - // descendants should still be added, so the SURFACE should not be culled. - EXPECT_EQ(back_facing_surface->id(), render_surface_layer_list.at(2)->id()); - - // Verify root surface's layer list. - ASSERT_EQ( - 3u, - render_surface_layer_list.at(0)->render_surface()->layer_list().size()); - EXPECT_EQ(front_facing_child->id(), - render_surface_layer_list.at(0) - ->render_surface() - ->layer_list() - .at(0) - ->id()); - EXPECT_EQ(front_facing_surface->id(), - render_surface_layer_list.at(0) - ->render_surface() - ->layer_list() - .at(1) - ->id()); - EXPECT_EQ(back_facing_surface->id(), - render_surface_layer_list.at(0) - ->render_surface() - ->layer_list() - .at(2) - ->id()); - - // Verify front_facing_surface's layer list. - ASSERT_EQ( - 2u, - render_surface_layer_list.at(1)->render_surface()->layer_list().size()); - EXPECT_EQ(front_facing_surface->id(), - render_surface_layer_list.at(1) - ->render_surface() - ->layer_list() - .at(0) - ->id()); - EXPECT_EQ(front_facing_child_of_front_facing_surface->id(), - render_surface_layer_list.at(1) - ->render_surface() - ->layer_list() - .at(1) - ->id()); - - // Verify back_facing_surface's layer list; its own layer should be culled - // from the surface list. - ASSERT_EQ( - 1u, - render_surface_layer_list.at(2)->render_surface()->layer_list().size()); - EXPECT_EQ(front_facing_child_of_back_facing_surface->id(), - render_surface_layer_list.at(2) - ->render_surface() - ->layer_list() - .at(0) - ->id()); + EXPECT_FALSE(front_facing_child->has_render_surface()); + EXPECT_FALSE(back_facing_child->has_render_surface()); + EXPECT_TRUE(front_facing_surface->has_render_surface()); + EXPECT_TRUE(back_facing_surface->has_render_surface()); + EXPECT_FALSE( + front_facing_child_of_front_facing_surface->has_render_surface()); + EXPECT_FALSE(back_facing_child_of_front_facing_surface->has_render_surface()); + EXPECT_FALSE(front_facing_child_of_back_facing_surface->has_render_surface()); + EXPECT_FALSE(back_facing_child_of_back_facing_surface->has_render_surface()); + + EXPECT_EQ(4u, update_layer_list().size()); + EXPECT_TRUE(UpdateLayerListContains(front_facing_child->id())); + EXPECT_TRUE(UpdateLayerListContains(front_facing_surface->id())); + EXPECT_TRUE(UpdateLayerListContains( + front_facing_child_of_front_facing_surface->id())); + EXPECT_TRUE( + UpdateLayerListContains(front_facing_child_of_back_facing_surface->id())); } TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithPreserves3d) { @@ -3829,51 +3277,26 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithPreserves3d) { true, true); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawPropertiesWithPropertyTrees(parent.get()); // 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_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()); - EXPECT_FALSE(back_facing_child_of_back_facing_surface->render_surface()); - - // Verify the render_surface_layer_list. The back-facing surface should be - // culled. - ASSERT_EQ(2u, render_surface_layer_list.size()); - EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); - EXPECT_EQ(front_facing_surface->id(), render_surface_layer_list.at(1)->id()); - - // Verify root surface's layer list. - ASSERT_EQ( - 2u, - render_surface_layer_list.at(0)->render_surface()->layer_list().size()); - EXPECT_EQ(front_facing_child->id(), - render_surface_layer_list.at(0) - ->render_surface()->layer_list().at(0)->id()); - EXPECT_EQ(front_facing_surface->id(), - render_surface_layer_list.at(0) - ->render_surface()->layer_list().at(1)->id()); - - // Verify front_facing_surface's layer list. - ASSERT_EQ( - 2u, - render_surface_layer_list.at(1)->render_surface()->layer_list().size()); - EXPECT_EQ(front_facing_surface->id(), - render_surface_layer_list.at(1) - ->render_surface()->layer_list().at(0)->id()); - EXPECT_EQ(front_facing_child_of_front_facing_surface->id(), - render_surface_layer_list.at(1) - ->render_surface()->layer_list().at(1)->id()); + EXPECT_FALSE(front_facing_child->has_render_surface()); + EXPECT_FALSE(back_facing_child->has_render_surface()); + EXPECT_TRUE(front_facing_surface->has_render_surface()); + // We expect that a has_render_surface was created but not used. + EXPECT_TRUE(back_facing_surface->has_render_surface()); + EXPECT_FALSE( + front_facing_child_of_front_facing_surface->has_render_surface()); + EXPECT_FALSE(back_facing_child_of_front_facing_surface->has_render_surface()); + EXPECT_FALSE(front_facing_child_of_back_facing_surface->has_render_surface()); + EXPECT_FALSE(back_facing_child_of_back_facing_surface->has_render_surface()); + + EXPECT_EQ(3u, update_layer_list().size()); + + EXPECT_TRUE(UpdateLayerListContains(front_facing_child->id())); + EXPECT_TRUE(UpdateLayerListContains(front_facing_surface->id())); + EXPECT_TRUE(UpdateLayerListContains( + front_facing_child_of_front_facing_surface->id())); } TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithAnimatingTransforms) { @@ -3969,60 +3392,38 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithAnimatingTransforms) { true, false); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; + LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(parent.get(), + parent->bounds()); LayerTreeHostCommon::CalculateDrawProperties(&inputs); - EXPECT_FALSE(child->render_surface()); - EXPECT_TRUE(animating_surface->render_surface()); - EXPECT_FALSE(child_of_animating_surface->render_surface()); - EXPECT_FALSE(animating_child->render_surface()); - EXPECT_FALSE(child2->render_surface()); - - // Verify that the animating_child and child_of_animating_surface were not - // culled, but that child was. - ASSERT_EQ(2u, render_surface_layer_list.size()); - EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); - EXPECT_EQ(animating_surface->id(), render_surface_layer_list.at(1)->id()); + EXPECT_FALSE(child->has_render_surface()); + EXPECT_TRUE(animating_surface->has_render_surface()); + EXPECT_FALSE(child_of_animating_surface->has_render_surface()); + EXPECT_FALSE(animating_child->has_render_surface()); + EXPECT_FALSE(child2->has_render_surface()); + + ExecuteCalculateDrawPropertiesWithPropertyTrees(parent.get()); + + EXPECT_EQ(4u, update_layer_list().size()); // The non-animating child be culled from the layer list for the parent render // surface. - ASSERT_EQ( - 3u, - render_surface_layer_list.at(0)->render_surface()->layer_list().size()); - EXPECT_EQ(animating_surface->id(), - render_surface_layer_list.at(0) - ->render_surface()->layer_list().at(0)->id()); - EXPECT_EQ(animating_child->id(), - render_surface_layer_list.at(0) - ->render_surface()->layer_list().at(1)->id()); - EXPECT_EQ(child2->id(), - render_surface_layer_list.at(0) - ->render_surface()->layer_list().at(2)->id()); - - ASSERT_EQ( - 2u, - render_surface_layer_list.at(1)->render_surface()->layer_list().size()); - EXPECT_EQ(animating_surface->id(), - render_surface_layer_list.at(1) - ->render_surface()->layer_list().at(0)->id()); - EXPECT_EQ(child_of_animating_surface->id(), - render_surface_layer_list.at(1) - ->render_surface()->layer_list().at(1)->id()); - - EXPECT_FALSE(child2->visible_layer_rect().IsEmpty()); + EXPECT_TRUE(UpdateLayerListContains(animating_surface->id())); + EXPECT_TRUE(UpdateLayerListContains(animating_child->id())); + EXPECT_TRUE(UpdateLayerListContains(child2->id())); + EXPECT_TRUE(UpdateLayerListContains(child_of_animating_surface->id())); + + EXPECT_FALSE(child2->visible_rect_from_property_trees().IsEmpty()); // The animating layers should have a visible content rect that represents the // area of the front face that is within the viewport. - EXPECT_EQ(animating_child->visible_layer_rect(), + EXPECT_EQ(animating_child->visible_rect_from_property_trees(), gfx::Rect(animating_child->bounds())); - EXPECT_EQ(animating_surface->visible_layer_rect(), + EXPECT_EQ(animating_surface->visible_rect_from_property_trees(), gfx::Rect(animating_surface->bounds())); // And layers in the subtree of the animating layer should have valid visible // content rects also. - EXPECT_EQ(child_of_animating_surface->visible_layer_rect(), + EXPECT_EQ(child_of_animating_surface->visible_rect_from_property_trees(), gfx::Rect(child_of_animating_surface->bounds())); } @@ -4097,46 +3498,19 @@ TEST_F(LayerTreeHostCommonTest, front_facing_surface->Set3dSortingContextId(1); back_facing_surface->Set3dSortingContextId(1); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawPropertiesWithPropertyTrees(parent.get()); // Verify which render surfaces were created and used. - EXPECT_TRUE(front_facing_surface->render_surface()); + EXPECT_TRUE(front_facing_surface->has_render_surface()); // 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()); - - // Verify the render_surface_layer_list. The back-facing surface should be - // culled. - ASSERT_EQ(2u, render_surface_layer_list.size()); - EXPECT_EQ(parent->id(), render_surface_layer_list.at(0)->id()); - EXPECT_EQ(front_facing_surface->id(), render_surface_layer_list.at(1)->id()); - - // Verify root surface's layer list. - ASSERT_EQ( - 1u, - render_surface_layer_list.at(0)->render_surface()->layer_list().size()); - EXPECT_EQ(front_facing_surface->id(), - render_surface_layer_list.at(0) - ->render_surface()->layer_list().at(0)->id()); - - // Verify front_facing_surface's layer list. - ASSERT_EQ( - 2u, - render_surface_layer_list.at(1)->render_surface()->layer_list().size()); - EXPECT_EQ(front_facing_surface->id(), - render_surface_layer_list.at(1) - ->render_surface()->layer_list().at(0)->id()); - EXPECT_EQ(child1->id(), - render_surface_layer_list.at(1) - ->render_surface()->layer_list().at(1)->id()); + EXPECT_TRUE(back_facing_surface->has_render_surface()); + EXPECT_FALSE(child1->has_render_surface()); + EXPECT_FALSE(child2->has_render_surface()); + + EXPECT_EQ(2u, update_layer_list().size()); + EXPECT_TRUE(UpdateLayerListContains(front_facing_surface->id())); + EXPECT_TRUE(UpdateLayerListContains(child1->id())); } TEST_F(LayerTreeHostCommonScalingTest, LayerTransformsInHighDPI) { @@ -4177,14 +3551,14 @@ TEST_F(LayerTreeHostCommonScalingTest, LayerTransformsInHighDPI) { parent->draw_transform()); // Verify results of transformed parent rects - gfx::RectF parent_bounds(parent->bounds()); + gfx::RectF parent_bounds(gfx::SizeF(parent->bounds())); gfx::RectF parent_draw_rect = MathUtil::MapClippedRect(parent->draw_transform(), parent_bounds); gfx::RectF parent_screen_space_rect = MathUtil::MapClippedRect(parent->screen_space_transform(), parent_bounds); - gfx::RectF expected_parent_draw_rect(parent->bounds()); + gfx::RectF expected_parent_draw_rect(gfx::SizeF(parent->bounds())); expected_parent_draw_rect.Scale(device_scale_factor); EXPECT_FLOAT_RECT_EQ(expected_parent_draw_rect, parent_draw_rect); EXPECT_FLOAT_RECT_EQ(expected_parent_draw_rect, parent_screen_space_rect); @@ -4205,7 +3579,7 @@ TEST_F(LayerTreeHostCommonScalingTest, LayerTransformsInHighDPI) { // Verify results of transformed child and child_empty rects. They should // match. - gfx::RectF child_bounds(child->bounds()); + gfx::RectF child_bounds(gfx::SizeF(child->bounds())); gfx::RectF child_draw_rect = MathUtil::MapClippedRect(child->draw_transform(), child_bounds); @@ -4217,7 +3591,8 @@ TEST_F(LayerTreeHostCommonScalingTest, LayerTransformsInHighDPI) { gfx::RectF child_empty_screen_space_rect = MathUtil::MapClippedRect( child_empty->screen_space_transform(), child_bounds); - gfx::RectF expected_child_draw_rect(child->position(), child->bounds()); + gfx::RectF expected_child_draw_rect(child->position(), + gfx::SizeF(child->bounds())); expected_child_draw_rect.Scale(device_scale_factor); EXPECT_FLOAT_RECT_EQ(expected_child_draw_rect, child_draw_rect); EXPECT_FLOAT_RECT_EQ(expected_child_draw_rect, child_screen_space_rect); @@ -4392,71 +3767,44 @@ TEST_F(LayerTreeHostCommonScalingTest, IdealScaleForAnimatingLayer) { } TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) { - MockContentLayerClient delegate; gfx::Transform identity_matrix; - scoped_refptr<FakePictureLayer> parent = - CreateDrawablePictureLayer(layer_settings(), &delegate); - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(30, 30), - false, + LayerImpl* parent = root_layer(); + parent->SetDrawsContent(true); + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), false, true, true); - scoped_refptr<FakePictureLayer> child = - CreateDrawablePictureLayer(layer_settings(), &delegate); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(2.f, 2.f), - gfx::Size(10, 10), - false, - true); + LayerImpl* child = AddChildToRoot<LayerImpl>(); + child->SetDrawsContent(true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(2.f, 2.f), gfx::Size(10, 10), false, + true, true); gfx::Transform replica_transform; replica_transform.Scale(1.0, -1.0); - scoped_refptr<FakePictureLayer> replica = - CreateDrawablePictureLayer(layer_settings(), &delegate); - SetLayerPropertiesForTesting(replica.get(), - replica_transform, - gfx::Point3F(), - gfx::PointF(2.f, 2.f), - gfx::Size(10, 10), - false, - true); + + scoped_ptr<LayerImpl> replica = + LayerImpl::Create(host_impl()->active_tree(), 7); + SetLayerPropertiesForTesting(replica.get(), replica_transform, gfx::Point3F(), + gfx::PointF(2.f, 2.f), gfx::Size(10, 10), false, + true, false); + child->SetReplicaLayer(replica.Pass()); // This layer should end up in the same surface as child, with the same draw // and screen space transforms. - scoped_refptr<FakePictureLayer> duplicate_child_non_owner = - CreateDrawablePictureLayer(layer_settings(), &delegate); - SetLayerPropertiesForTesting(duplicate_child_non_owner.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - false, - true); - - parent->AddChild(child); - child->AddChild(duplicate_child_non_owner); - child->SetReplicaLayer(replica.get()); - - host()->SetRootLayer(parent); - - RenderSurfaceLayerList render_surface_layer_list; + LayerImpl* duplicate_child_non_owner = AddChild<LayerImpl>(child); + duplicate_child_non_owner->SetDrawsContent(true); + SetLayerPropertiesForTesting(duplicate_child_non_owner, identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), + false, true, false); float device_scale_factor = 1.5f; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.device_scale_factor = device_scale_factor; - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawProperties(parent, device_scale_factor); // We should have two render surfaces. The root's render surface and child's // render surface (it needs one because it has a replica layer). - EXPECT_EQ(2u, render_surface_layer_list.size()); + EXPECT_EQ(2u, render_surface_layer_list_impl()->size()); gfx::Transform expected_parent_transform; expected_parent_transform.Scale(device_scale_factor, device_scale_factor); @@ -4531,58 +3879,35 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) { TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPIAccurateScaleZeroPosition) { - MockContentLayerClient delegate; gfx::Transform identity_matrix; - scoped_refptr<FakePictureLayer> parent = - CreateDrawablePictureLayer(layer_settings(), &delegate); - SetLayerPropertiesForTesting(parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(33, 31), - false, + LayerImpl* parent = root_layer(); + parent->SetDrawsContent(true); + SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(33, 31), false, true, true); - scoped_refptr<FakePictureLayer> child = - CreateDrawablePictureLayer(layer_settings(), &delegate); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(13, 11), - false, + LayerImpl* child = AddChildToRoot<LayerImpl>(); + child->SetDrawsContent(true); + SetLayerPropertiesForTesting(child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(13, 11), false, true, true); gfx::Transform replica_transform; replica_transform.Scale(1.0, -1.0); - scoped_refptr<FakePictureLayer> replica = - CreateDrawablePictureLayer(layer_settings(), &delegate); - SetLayerPropertiesForTesting(replica.get(), - replica_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(13, 11), - false, - true); - - parent->AddChild(child); - child->SetReplicaLayer(replica.get()); - - host()->SetRootLayer(parent); + scoped_ptr<LayerImpl> replica = + LayerImpl::Create(host_impl()->active_tree(), 7); + SetLayerPropertiesForTesting(replica.get(), replica_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(13, 11), false, true, + false); + child->SetReplicaLayer(replica.Pass()); float device_scale_factor = 1.7f; - - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - parent.get(), parent->bounds(), &render_surface_layer_list); - inputs.device_scale_factor = device_scale_factor; - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ExecuteCalculateDrawProperties(parent, device_scale_factor); // We should have two render surfaces. The root's render surface and child's // render surface (it needs one because it has a replica layer). - EXPECT_EQ(2u, render_surface_layer_list.size()); + EXPECT_EQ(2u, render_surface_layer_list_impl()->size()); gfx::Transform identity_transform; EXPECT_TRANSFORMATION_MATRIX_EQ(identity_transform, @@ -4674,7 +3999,7 @@ TEST_F(LayerTreeHostCommonTest, TransparentChildRenderSurfaceCreation) { ExecuteCalculateDrawProperties(root.get()); - EXPECT_FALSE(child->render_surface()); + EXPECT_FALSE(child->has_render_surface()); } TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) { @@ -4841,7 +4166,7 @@ TEST_P(LCDTextTest, CanUseLCDText) { // Case 6: Skew. gfx::Transform skew; - skew.SkewX(10.0); + skew.Skew(10.0, 0.0); child_->SetTransform(skew); child_->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_, @@ -4942,65 +4267,6 @@ INSTANTIATE_TEST_CASE_P(LayerTreeHostCommonTest, testing::Bool(), testing::Bool())); -TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayer) { - FakeImplProxy proxy; - TestSharedBitmapManager shared_bitmap_manager; - TestTaskGraphRunner task_graph_runner; - FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, - &task_graph_runner); - host_impl.CreatePendingTree(); - const gfx::Transform identity_matrix; - - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - root->SetIsDrawable(true); - - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(40, 40), - true, - false); - child->SetIsDrawable(true); - - scoped_refptr<Layer> grand_child = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(30, 30), - true, - false); - grand_child->SetIsDrawable(true); - grand_child->SetHideLayerAndSubtree(true); - - child->AddChild(grand_child); - root->AddChild(child); - - host()->SetRootLayer(root); - - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); - - // We should have one render surface and two layers. The grand child has - // hidden itself. - ASSERT_EQ(1u, render_surface_layer_list.size()); - ASSERT_EQ(2u, root->render_surface()->layer_list().size()); - EXPECT_EQ(root->id(), root->render_surface()->layer_list().at(0)->id()); - EXPECT_EQ(child->id(), root->render_surface()->layer_list().at(1)->id()); -} - TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; @@ -5048,64 +4314,6 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) { EXPECT_EQ(2, root->render_surface()->layer_list().at(1)->id()); } -TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayers) { - FakeImplProxy proxy; - TestSharedBitmapManager shared_bitmap_manager; - TestTaskGraphRunner task_graph_runner; - FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, - &task_graph_runner); - host_impl.CreatePendingTree(); - const gfx::Transform identity_matrix; - - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - root->SetIsDrawable(true); - - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(40, 40), - true, - false); - child->SetIsDrawable(true); - child->SetHideLayerAndSubtree(true); - - scoped_refptr<Layer> grand_child = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(grand_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(30, 30), - true, - false); - grand_child->SetIsDrawable(true); - - child->AddChild(grand_child); - root->AddChild(child); - - host()->SetRootLayer(root); - - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; - LayerTreeHostCommon::CalculateDrawProperties(&inputs); - - // We should have one render surface and one layers. The child has - // hidden itself and the grand child. - ASSERT_EQ(1u, render_surface_layer_list.size()); - ASSERT_EQ(1u, root->render_surface()->layer_list().size()); - EXPECT_EQ(root->id(), root->render_surface()->layer_list().at(0)->id()); -} - TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayersImpl) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; @@ -5162,122 +4370,105 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) { host_impl.CreatePendingTree(); const gfx::Transform identity_matrix; - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - root->SetIsDrawable(true); + 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, + true); + root->SetDrawsContent(true); - scoped_refptr<Layer> copy_grand_parent = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(copy_grand_parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(40, 40), - true, - false); - copy_grand_parent->SetIsDrawable(true); + scoped_ptr<LayerImpl> copy_grand_parent = + LayerImpl::Create(host_impl.pending_tree(), 2); + SetLayerPropertiesForTesting(copy_grand_parent.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(40, 40), + true, false, false); + copy_grand_parent->SetDrawsContent(true); + LayerImpl* copy_grand_parent_layer = copy_grand_parent.get(); - scoped_refptr<Layer> copy_parent = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(copy_parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(30, 30), - true, - false); - copy_parent->SetIsDrawable(true); - copy_parent->SetForceRenderSurface(true); + scoped_ptr<LayerImpl> copy_parent = + LayerImpl::Create(host_impl.pending_tree(), 3); + SetLayerPropertiesForTesting(copy_parent.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30), + true, false, true); + copy_parent->SetDrawsContent(true); + LayerImpl* copy_parent_layer = copy_parent.get(); - scoped_refptr<Layer> copy_layer = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(copy_layer.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, - false); - copy_layer->SetIsDrawable(true); + scoped_ptr<LayerImpl> copy_request = + LayerImpl::Create(host_impl.pending_tree(), 4); + SetLayerPropertiesForTesting(copy_request.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(20, 20), + true, false, true); + copy_request->SetDrawsContent(true); + LayerImpl* copy_layer = copy_request.get(); - scoped_refptr<Layer> copy_child = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(copy_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, - false); - copy_child->SetIsDrawable(true); + scoped_ptr<LayerImpl> copy_child = + LayerImpl::Create(host_impl.pending_tree(), 5); + SetLayerPropertiesForTesting(copy_child.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(20, 20), + true, false, false); + copy_child->SetDrawsContent(true); + LayerImpl* copy_child_layer = copy_child.get(); - scoped_refptr<Layer> copy_grand_parent_sibling_before = - Layer::Create(layer_settings()); + scoped_ptr<LayerImpl> copy_grand_parent_sibling_before = + LayerImpl::Create(host_impl.pending_tree(), 6); SetLayerPropertiesForTesting(copy_grand_parent_sibling_before.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(40, 40), - true, - false); - copy_grand_parent_sibling_before->SetIsDrawable(true); - - scoped_refptr<Layer> copy_grand_parent_sibling_after = - Layer::Create(layer_settings()); + identity_matrix, gfx::Point3F(), gfx::PointF(), + gfx::Size(40, 40), true, false, false); + copy_grand_parent_sibling_before->SetDrawsContent(true); + LayerImpl* copy_grand_parent_sibling_before_layer = + copy_grand_parent_sibling_before.get(); + + scoped_ptr<LayerImpl> copy_grand_parent_sibling_after = + LayerImpl::Create(host_impl.pending_tree(), 7); SetLayerPropertiesForTesting(copy_grand_parent_sibling_after.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(40, 40), - true, - false); - copy_grand_parent_sibling_after->SetIsDrawable(true); - - copy_layer->AddChild(copy_child); - copy_parent->AddChild(copy_layer); - copy_grand_parent->AddChild(copy_parent); - root->AddChild(copy_grand_parent_sibling_before); - root->AddChild(copy_grand_parent); - root->AddChild(copy_grand_parent_sibling_after); - - host()->SetRootLayer(root); + identity_matrix, gfx::Point3F(), gfx::PointF(), + gfx::Size(40, 40), true, false, false); + copy_grand_parent_sibling_after->SetDrawsContent(true); + LayerImpl* copy_grand_parent_sibling_after_layer = + copy_grand_parent_sibling_after.get(); + + copy_request->AddChild(copy_child.Pass()); + copy_parent->AddChild(copy_request.Pass()); + copy_grand_parent->AddChild(copy_parent.Pass()); + root->AddChild(copy_grand_parent_sibling_before.Pass()); + root->AddChild(copy_grand_parent.Pass()); + root->AddChild(copy_grand_parent_sibling_after.Pass()); // Hide the copy_grand_parent and its subtree. But make a copy request in that // hidden subtree on copy_layer. - copy_grand_parent->SetHideLayerAndSubtree(true); - copy_grand_parent_sibling_before->SetHideLayerAndSubtree(true); - copy_grand_parent_sibling_after->SetHideLayerAndSubtree(true); - copy_layer->RequestCopyOfOutput(CopyOutputRequest::CreateRequest( - base::Bind(&EmptyCopyOutputCallback))); + copy_grand_parent_layer->SetHideLayerAndSubtree(true); + copy_grand_parent_sibling_before_layer->SetHideLayerAndSubtree(true); + copy_grand_parent_sibling_after_layer->SetHideLayerAndSubtree(true); + + ScopedPtrVector<CopyOutputRequest> copy_requests; + copy_requests.push_back( + CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback))); + copy_layer->PassCopyRequests(©_requests); EXPECT_TRUE(copy_layer->HasCopyRequest()); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( + LayerImplList render_surface_layer_list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( root.get(), root->bounds(), &render_surface_layer_list); inputs.can_adjust_raster_scales = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); - EXPECT_TRUE(root->draw_properties().layer_or_descendant_has_copy_request); - EXPECT_TRUE(copy_grand_parent->draw_properties(). - layer_or_descendant_has_copy_request); - EXPECT_TRUE(copy_parent->draw_properties(). - layer_or_descendant_has_copy_request); - EXPECT_TRUE(copy_layer->draw_properties(). - layer_or_descendant_has_copy_request); - EXPECT_FALSE(copy_child->draw_properties(). - layer_or_descendant_has_copy_request); - EXPECT_FALSE(copy_grand_parent_sibling_before->draw_properties(). - layer_or_descendant_has_copy_request); - EXPECT_FALSE(copy_grand_parent_sibling_after->draw_properties(). - layer_or_descendant_has_copy_request); + EXPECT_GT(root->num_layer_or_descendants_with_copy_request(), 0); + EXPECT_GT( + copy_grand_parent_layer->num_layer_or_descendants_with_copy_request(), 0); + EXPECT_GT(copy_parent_layer->num_layer_or_descendants_with_copy_request(), 0); + EXPECT_GT(copy_layer->num_layer_or_descendants_with_copy_request(), 0); + EXPECT_EQ(copy_child_layer->num_layer_or_descendants_with_copy_request(), 0); + EXPECT_EQ(copy_grand_parent_sibling_before_layer + ->num_layer_or_descendants_with_copy_request(), + 0); + EXPECT_EQ(copy_grand_parent_sibling_after_layer + ->num_layer_or_descendants_with_copy_request(), + 0); // We should have three render surfaces, one for the root, one for the parent // since it owns a surface, and one for the copy_layer. ASSERT_EQ(3u, render_surface_layer_list.size()); EXPECT_EQ(root->id(), render_surface_layer_list.at(0)->id()); - EXPECT_EQ(copy_parent->id(), render_surface_layer_list.at(1)->id()); + EXPECT_EQ(copy_parent_layer->id(), render_surface_layer_list.at(1)->id()); EXPECT_EQ(copy_layer->id(), render_surface_layer_list.at(2)->id()); // The root render surface should have 2 contributing layers. The @@ -5286,20 +4477,20 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) { // request. ASSERT_EQ(2u, root->render_surface()->layer_list().size()); EXPECT_EQ(root->id(), root->render_surface()->layer_list().at(0)->id()); - EXPECT_EQ(copy_parent->id(), + EXPECT_EQ(copy_parent_layer->id(), root->render_surface()->layer_list().at(1)->id()); // Nothing actually draws into the copy parent, so only the copy_layer will // appear in its list, since it needs to be drawn for the copy request. - ASSERT_EQ(1u, copy_parent->render_surface()->layer_list().size()); + ASSERT_EQ(1u, copy_parent_layer->render_surface()->layer_list().size()); EXPECT_EQ(copy_layer->id(), - copy_parent->render_surface()->layer_list().at(0)->id()); + copy_parent_layer->render_surface()->layer_list().at(0)->id()); // The copy_layer's render surface should have two contributing layers. ASSERT_EQ(2u, copy_layer->render_surface()->layer_list().size()); EXPECT_EQ(copy_layer->id(), copy_layer->render_surface()->layer_list().at(0)->id()); - EXPECT_EQ(copy_child->id(), + EXPECT_EQ(copy_child_layer->id(), copy_layer->render_surface()->layer_list().at(1)->id()); } @@ -5312,59 +4503,46 @@ TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) { host_impl.CreatePendingTree(); const gfx::Transform identity_matrix; - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(root.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - root->SetIsDrawable(true); + 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, + true); + root->SetDrawsContent(true); - scoped_refptr<Layer> copy_parent = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(copy_parent.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(), - true, - false); - copy_parent->SetIsDrawable(true); + scoped_ptr<LayerImpl> copy_parent = + LayerImpl::Create(host_impl.pending_tree(), 2); + SetLayerPropertiesForTesting(copy_parent.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(), true, + false, false); + copy_parent->SetDrawsContent(true); copy_parent->SetMasksToBounds(true); - scoped_refptr<Layer> copy_layer = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(copy_layer.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(30, 30), - true, - false); - copy_layer->SetIsDrawable(true); - - scoped_refptr<Layer> copy_child = Layer::Create(layer_settings()); - SetLayerPropertiesForTesting(copy_child.get(), - identity_matrix, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, - false); - copy_child->SetIsDrawable(true); - - copy_layer->AddChild(copy_child); - copy_parent->AddChild(copy_layer); - root->AddChild(copy_parent); + scoped_ptr<LayerImpl> copy_layer = + LayerImpl::Create(host_impl.pending_tree(), 3); + SetLayerPropertiesForTesting(copy_layer.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30), + true, false, true); + copy_layer->SetDrawsContent(true); - host()->SetRootLayer(root); + scoped_ptr<LayerImpl> copy_child = + LayerImpl::Create(host_impl.pending_tree(), 4); + SetLayerPropertiesForTesting(copy_child.get(), identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(20, 20), + true, false, false); + copy_child->SetDrawsContent(true); - copy_layer->RequestCopyOfOutput(CopyOutputRequest::CreateRequest( - base::Bind(&EmptyCopyOutputCallback))); + ScopedPtrVector<CopyOutputRequest> copy_requests; + copy_requests.push_back( + CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback))); + copy_layer->PassCopyRequests(©_requests); EXPECT_TRUE(copy_layer->HasCopyRequest()); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( + copy_layer->AddChild(copy_child.Pass()); + copy_parent->AddChild(copy_layer.Pass()); + root->AddChild(copy_parent.Pass()); + + LayerImplList render_surface_layer_list; + LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs( root.get(), root->bounds(), &render_surface_layer_list); inputs.can_adjust_raster_scales = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); @@ -5424,16 +4602,14 @@ TEST_F(LayerTreeHostCommonTest, VisibleContentRectInsideSurface) { host()->SetRootLayer(root); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - root.get(), root->bounds(), &render_surface_layer_list); - inputs.can_adjust_raster_scales = true; + LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(root.get(), + root->bounds()); LayerTreeHostCommon::CalculateDrawProperties(&inputs); // The visible_layer_rect for the |surface_child| should not be clipped by // the viewport. EXPECT_EQ(gfx::Rect(50, 50).ToString(), - surface_child->visible_layer_rect().ToString()); + surface_child->visible_rect_from_property_trees().ToString()); } TEST_F(LayerTreeHostCommonTest, TransformedClipParent) { @@ -5448,69 +4624,42 @@ TEST_F(LayerTreeHostCommonTest, TransformedClipParent) { // // The render surface should be resized correctly and the clip child should // inherit the right clip rect. - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface = Layer::Create(layer_settings()); - scoped_refptr<Layer> clip_parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> intervening = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> clip_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - - root->AddChild(render_surface); - render_surface->AddChild(clip_parent); - clip_parent->AddChild(intervening); - intervening->AddChild(clip_child); - - clip_child->SetClipParent(clip_parent.get()); + LayerImpl* root = root_layer(); + LayerImpl* render_surface = AddChildToRoot<LayerImpl>(); + LayerImpl* clip_parent = AddChild<LayerImpl>(render_surface); + LayerImpl* intervening = AddChild<LayerImpl>(clip_parent); + LayerImpl* clip_child = AddChild<LayerImpl>(intervening); + clip_child->SetDrawsContent(true); + clip_child->SetClipParent(clip_parent); + scoped_ptr<std::set<LayerImpl*>> clip_children(new std::set<LayerImpl*>); + clip_children->insert(clip_child); + clip_parent->SetClipChildren(clip_children.release()); intervening->SetMasksToBounds(true); clip_parent->SetMasksToBounds(true); - render_surface->SetForceRenderSurface(true); - gfx::Transform scale_transform; scale_transform.Scale(2, 2); gfx::Transform identity_transform; - SetLayerPropertiesForTesting(root.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - SetLayerPropertiesForTesting(render_surface.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(clip_parent.get(), - scale_transform, - gfx::Point3F(), - gfx::PointF(1.f, 1.f), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(intervening.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(1.f, 1.f), - gfx::Size(5, 5), - true, - false); - SetLayerPropertiesForTesting(clip_child.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(1.f, 1.f), - gfx::Size(10, 10), - true, - false); - - host()->SetRootLayer(root); + SetLayerPropertiesForTesting(root, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(render_surface, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), + true, false, true); + SetLayerPropertiesForTesting(clip_parent, scale_transform, gfx::Point3F(), + gfx::PointF(1.f, 1.f), gfx::Size(10, 10), true, + false, false); + SetLayerPropertiesForTesting(intervening, identity_transform, gfx::Point3F(), + gfx::PointF(1.f, 1.f), gfx::Size(5, 5), true, + false, false); + SetLayerPropertiesForTesting(clip_child, identity_transform, gfx::Point3F(), + gfx::PointF(1.f, 1.f), gfx::Size(10, 10), true, + false, false); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); ASSERT_TRUE(root->render_surface()); ASSERT_TRUE(render_surface->render_surface()); @@ -5549,78 +4698,43 @@ TEST_F(LayerTreeHostCommonTest, ClipParentWithInterveningRenderSurface) { // + render_surface2 (also sets opacity) // + clip_child // - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> clip_parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<Layer> intervening = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface2 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> clip_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - - root->AddChild(clip_parent); - clip_parent->AddChild(render_surface1); - render_surface1->AddChild(intervening); - intervening->AddChild(render_surface2); - render_surface2->AddChild(clip_child); + LayerImpl* root = root_layer(); + LayerImpl* clip_parent = AddChildToRoot<LayerImpl>(); + LayerImpl* render_surface1 = AddChild<LayerImpl>(clip_parent); + LayerImpl* intervening = AddChild<LayerImpl>(render_surface1); + LayerImpl* render_surface2 = AddChild<LayerImpl>(intervening); + LayerImpl* clip_child = AddChild<LayerImpl>(render_surface2); + clip_child->SetDrawsContent(true); - clip_child->SetClipParent(clip_parent.get()); + clip_child->SetClipParent(clip_parent); intervening->SetMasksToBounds(true); clip_parent->SetMasksToBounds(true); - render_surface1->SetForceRenderSurface(true); - render_surface2->SetForceRenderSurface(true); - gfx::Transform translation_transform; translation_transform.Translate(2, 2); gfx::Transform identity_transform; - SetLayerPropertiesForTesting(root.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - SetLayerPropertiesForTesting(clip_parent.get(), - translation_transform, - gfx::Point3F(), - gfx::PointF(1.f, 1.f), - gfx::Size(40, 40), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(intervening.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(1.f, 1.f), - gfx::Size(5, 5), - true, - false); - SetLayerPropertiesForTesting(render_surface2.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(clip_child.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(-10.f, -10.f), - gfx::Size(60, 60), - true, - false); - - host()->SetRootLayer(root); + SetLayerPropertiesForTesting(root, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(clip_parent, translation_transform, + gfx::Point3F(), gfx::PointF(1.f, 1.f), + gfx::Size(40, 40), true, false, false); + SetLayerPropertiesForTesting(render_surface1, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), + true, false, true); + SetLayerPropertiesForTesting(intervening, identity_transform, gfx::Point3F(), + gfx::PointF(1.f, 1.f), gfx::Size(5, 5), true, + false, false); + SetLayerPropertiesForTesting(render_surface2, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), + true, false, true); + SetLayerPropertiesForTesting(clip_child, identity_transform, gfx::Point3F(), + gfx::PointF(-10.f, -10.f), gfx::Size(60, 60), + true, false, false); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); EXPECT_TRUE(root->render_surface()); EXPECT_TRUE(render_surface1->render_surface()); @@ -5675,80 +4789,45 @@ TEST_F(LayerTreeHostCommonTest, ClipParentScrolledInterveningLayer) { // + render_surface2 (also sets opacity) // + clip_child // - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> clip_parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<Layer> intervening = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface2 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> clip_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - - root->AddChild(clip_parent); - clip_parent->AddChild(render_surface1); - render_surface1->AddChild(intervening); - intervening->AddChild(render_surface2); - render_surface2->AddChild(clip_child); + LayerImpl* root = root_layer(); + LayerImpl* clip_parent = AddChildToRoot<LayerImpl>(); + LayerImpl* render_surface1 = AddChild<LayerImpl>(clip_parent); + LayerImpl* intervening = AddChild<LayerImpl>(render_surface1); + LayerImpl* render_surface2 = AddChild<LayerImpl>(intervening); + LayerImpl* clip_child = AddChild<LayerImpl>(render_surface2); + clip_child->SetDrawsContent(true); - clip_child->SetClipParent(clip_parent.get()); + clip_child->SetClipParent(clip_parent); intervening->SetMasksToBounds(true); clip_parent->SetMasksToBounds(true); - intervening->SetScrollClipLayerId(clip_parent->id()); - intervening->SetScrollOffset(gfx::ScrollOffset(3, 3)); - - render_surface1->SetForceRenderSurface(true); - render_surface2->SetForceRenderSurface(true); + intervening->SetScrollClipLayer(clip_parent->id()); + intervening->SetCurrentScrollOffset(gfx::ScrollOffset(3, 3)); gfx::Transform translation_transform; translation_transform.Translate(2, 2); gfx::Transform identity_transform; - SetLayerPropertiesForTesting(root.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - SetLayerPropertiesForTesting(clip_parent.get(), - translation_transform, - gfx::Point3F(), - gfx::PointF(1.f, 1.f), - gfx::Size(40, 40), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(intervening.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(1.f, 1.f), - gfx::Size(5, 5), - true, - false); - SetLayerPropertiesForTesting(render_surface2.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(clip_child.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(-10.f, -10.f), - gfx::Size(60, 60), - true, - false); - - host()->SetRootLayer(root); + SetLayerPropertiesForTesting(root, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(clip_parent, translation_transform, + gfx::Point3F(), gfx::PointF(1.f, 1.f), + gfx::Size(40, 40), true, false, false); + SetLayerPropertiesForTesting(render_surface1, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), + true, false, true); + SetLayerPropertiesForTesting(intervening, identity_transform, gfx::Point3F(), + gfx::PointF(1.f, 1.f), gfx::Size(5, 5), true, + false, false); + SetLayerPropertiesForTesting(render_surface2, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(10, 10), + true, false, true); + SetLayerPropertiesForTesting(clip_child, identity_transform, gfx::Point3F(), + gfx::PointF(-10.f, -10.f), gfx::Size(60, 60), + true, false, false); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); EXPECT_TRUE(root->render_surface()); EXPECT_TRUE(render_surface1->render_surface()); @@ -5800,63 +4879,39 @@ TEST_F(LayerTreeHostCommonTest, DescendantsOfClipChildren) { // + clip_child // + child // - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> clip_parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> intervening = Layer::Create(layer_settings()); - scoped_refptr<Layer> clip_child = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - - root->AddChild(clip_parent); - clip_parent->AddChild(intervening); - intervening->AddChild(clip_child); - clip_child->AddChild(child); + LayerImpl* root = root_layer(); + LayerImpl* clip_parent = AddChild<LayerImpl>(root); + LayerImpl* intervening = AddChild<LayerImpl>(clip_parent); + LayerImpl* clip_child = AddChild<LayerImpl>(intervening); + LayerImpl* child = AddChild<LayerImpl>(clip_child); + child->SetDrawsContent(true); - clip_child->SetClipParent(clip_parent.get()); + clip_child->SetClipParent(clip_parent); + scoped_ptr<std::set<LayerImpl*>> clip_children(new std::set<LayerImpl*>); + clip_children->insert(clip_child); + clip_parent->SetClipChildren(clip_children.release()); intervening->SetMasksToBounds(true); clip_parent->SetMasksToBounds(true); gfx::Transform identity_transform; - SetLayerPropertiesForTesting(root.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - SetLayerPropertiesForTesting(clip_parent.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(40, 40), - true, + SetLayerPropertiesForTesting(root, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(clip_parent, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(40, 40), true, false, false); - SetLayerPropertiesForTesting(intervening.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(5, 5), - true, + SetLayerPropertiesForTesting(intervening, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(5, 5), true, false, false); - SetLayerPropertiesForTesting(clip_child.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(60, 60), - true, + SetLayerPropertiesForTesting(clip_child, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(60, 60), true, false, false); - SetLayerPropertiesForTesting(child.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(60, 60), - true, + SetLayerPropertiesForTesting(child, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(60, 60), true, false, false); - host()->SetRootLayer(root); - - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); EXPECT_TRUE(root->render_surface()); @@ -5883,76 +4938,44 @@ TEST_F(LayerTreeHostCommonTest, // + non_clip_child // // In this example render_surface2 should be unaffected by clip_child. - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> clip_parent = Layer::Create(layer_settings()); - scoped_refptr<Layer> render_surface1 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> clip_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<Layer> render_surface2 = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> non_clip_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - - root->AddChild(clip_parent); - clip_parent->AddChild(render_surface1); - render_surface1->AddChild(clip_child); - clip_parent->AddChild(render_surface2); - render_surface2->AddChild(non_clip_child); - - clip_child->SetClipParent(clip_parent.get()); + LayerImpl* root = root_layer(); + LayerImpl* clip_parent = AddChildToRoot<LayerImpl>(); + LayerImpl* render_surface1 = AddChild<LayerImpl>(clip_parent); + LayerImpl* clip_child = AddChild<LayerImpl>(render_surface1); + clip_child->SetDrawsContent(true); + LayerImpl* render_surface2 = AddChild<LayerImpl>(clip_parent); + LayerImpl* non_clip_child = AddChild<LayerImpl>(render_surface2); + non_clip_child->SetDrawsContent(true); + + clip_child->SetClipParent(clip_parent); + scoped_ptr<std::set<LayerImpl*>> clip_children(new std::set<LayerImpl*>); + clip_children->insert(clip_child); + clip_parent->SetClipChildren(clip_children.release()); clip_parent->SetMasksToBounds(true); render_surface1->SetMasksToBounds(true); gfx::Transform identity_transform; - SetLayerPropertiesForTesting(root.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(15, 15), - true, - false); - SetLayerPropertiesForTesting(clip_parent.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(render_surface1.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(5, 5), - gfx::Size(5, 5), - true, - false); - SetLayerPropertiesForTesting(render_surface2.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(5, 5), - true, - false); - SetLayerPropertiesForTesting(clip_child.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(-1, 1), - gfx::Size(10, 10), - true, - false); - SetLayerPropertiesForTesting(non_clip_child.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(5, 5), - true, + SetLayerPropertiesForTesting(root, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(15, 15), true, false, + true); + SetLayerPropertiesForTesting(clip_parent, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(10, 10), true, false, false); + SetLayerPropertiesForTesting(render_surface1, identity_transform, + gfx::Point3F(), gfx::PointF(5, 5), + gfx::Size(5, 5), true, false, true); + SetLayerPropertiesForTesting(render_surface2, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(5, 5), + true, false, true); + SetLayerPropertiesForTesting(clip_child, identity_transform, gfx::Point3F(), + gfx::PointF(-1, 1), gfx::Size(10, 10), true, + false, false); + SetLayerPropertiesForTesting(non_clip_child, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(5, 5), + true, false, false); - render_surface1->SetForceRenderSurface(true); - render_surface2->SetForceRenderSurface(true); - - host()->SetRootLayer(root); - - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); EXPECT_TRUE(root->render_surface()); EXPECT_TRUE(render_surface1->render_surface()); @@ -6152,64 +5175,39 @@ TEST_F(LayerTreeHostCommonTest, ClippedByScrollParent) { // | + scroll_parent // + scroll_child // - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> scroll_parent_border = Layer::Create(layer_settings()); - scoped_refptr<Layer> scroll_parent_clip = Layer::Create(layer_settings()); - scoped_refptr<LayerWithForcedDrawsContent> scroll_parent = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> scroll_child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - - root->AddChild(scroll_child); - - root->AddChild(scroll_parent_border); - scroll_parent_border->AddChild(scroll_parent_clip); - scroll_parent_clip->AddChild(scroll_parent); + LayerImpl* root = root_layer(); + LayerImpl* scroll_parent_border = AddChildToRoot<LayerImpl>(); + LayerImpl* scroll_parent_clip = AddChild<LayerImpl>(scroll_parent_border); + LayerImpl* scroll_parent = AddChild<LayerImpl>(scroll_parent_clip); + LayerImpl* scroll_child = AddChild<LayerImpl>(root); + scroll_parent->SetDrawsContent(true); + scroll_child->SetDrawsContent(true); scroll_parent_clip->SetMasksToBounds(true); - scroll_child->SetScrollParent(scroll_parent.get()); + scroll_child->SetScrollParent(scroll_parent); + scoped_ptr<std::set<LayerImpl*>> scroll_children(new std::set<LayerImpl*>); + scroll_children->insert(scroll_child); + scroll_parent->SetScrollChildren(scroll_children.release()); gfx::Transform identity_transform; - 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, - false); - SetLayerPropertiesForTesting(scroll_parent.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, - false); - SetLayerPropertiesForTesting(scroll_child.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, + SetLayerPropertiesForTesting(root, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(scroll_parent_border, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(40, 40), + true, false, false); + SetLayerPropertiesForTesting(scroll_parent_clip, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30), + true, false, false); + SetLayerPropertiesForTesting(scroll_parent, identity_transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(50, 50), + true, false, false); + SetLayerPropertiesForTesting(scroll_child, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, false); - host()->SetRootLayer(root); - - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); EXPECT_TRUE(root->render_surface()); @@ -6219,47 +5217,27 @@ TEST_F(LayerTreeHostCommonTest, ClippedByScrollParent) { } TEST_F(LayerTreeHostCommonTest, SingularTransformSubtreesDoNotDraw) { - scoped_refptr<LayerWithForcedDrawsContent> root = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> parent = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - scoped_refptr<LayerWithForcedDrawsContent> child = - make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings())); - - root->AddChild(parent); - parent->AddChild(child); + LayerImpl* root = root_layer(); + root->SetDrawsContent(true); + LayerImpl* parent = AddChildToRoot<LayerImpl>(); + parent->SetDrawsContent(true); + LayerImpl* child = AddChild<LayerImpl>(parent); + child->SetDrawsContent(true); gfx::Transform identity_transform; - SetLayerPropertiesForTesting(root.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(50, 50), - true, + SetLayerPropertiesForTesting(root, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, true, true); - root->SetForceRenderSurface(true); - SetLayerPropertiesForTesting(parent.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(30, 30), - true, + SetLayerPropertiesForTesting(parent, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, true, true); - parent->SetForceRenderSurface(true); - SetLayerPropertiesForTesting(child.get(), - identity_transform, - gfx::Point3F(), - gfx::PointF(), - gfx::Size(20, 20), - true, + SetLayerPropertiesForTesting(child, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(20, 20), true, true, true); - child->SetForceRenderSurface(true); - host()->SetRootLayer(root); - - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); - EXPECT_EQ(3u, render_surface_layer_list()->size()); + EXPECT_EQ(3u, render_surface_layer_list_impl()->size()); gfx::Transform singular_transform; singular_transform.Scale3d( @@ -6267,18 +5245,18 @@ TEST_F(LayerTreeHostCommonTest, SingularTransformSubtreesDoNotDraw) { child->SetTransform(singular_transform); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); - EXPECT_EQ(2u, render_surface_layer_list()->size()); + EXPECT_EQ(2u, render_surface_layer_list_impl()->size()); // Ensure that the entire subtree under a layer with singular transform does // not get rendered. parent->SetTransform(singular_transform); child->SetTransform(identity_transform); - ExecuteCalculateDrawProperties(root.get()); + ExecuteCalculateDrawProperties(root); - EXPECT_EQ(1u, render_surface_layer_list()->size()); + EXPECT_EQ(1u, render_surface_layer_list_impl()->size()); } TEST_F(LayerTreeHostCommonTest, ClippedByOutOfOrderScrollParent) { @@ -6560,23 +5538,27 @@ TEST_F(LayerTreeHostCommonTest, FixedPositionWithInterveningRenderSurface) { ExecuteCalculateDrawProperties(root.get()); + TransformTree& tree = host()->property_trees()->transform_tree; + gfx::Transform expected_fixed_draw_transform; expected_fixed_draw_transform.Translate(10.f, 15.f); - EXPECT_EQ(expected_fixed_draw_transform, fixed->draw_transform()); + EXPECT_EQ(expected_fixed_draw_transform, + DrawTransformFromPropertyTrees(fixed.get(), tree)); 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()); + ScreenSpaceTransformFromPropertyTrees(fixed.get(), tree)); gfx::Transform expected_child_draw_transform; expected_child_draw_transform.Translate(11.f, 17.f); - EXPECT_EQ(expected_child_draw_transform, child->draw_transform()); + EXPECT_EQ(expected_child_draw_transform, + DrawTransformFromPropertyTrees(child.get(), tree)); 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()); + ScreenSpaceTransformFromPropertyTrees(child.get(), tree)); } TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) { @@ -6810,6 +5792,63 @@ TEST_F(LayerTreeHostCommonTest, container_offset - rounded_effective_scroll_offset); } +TEST_F(LayerTreeHostCommonTest, + ScrollSnappingWithAnimatedScreenSpaceTransform) { + // This test verifies that a scrolling layer whose screen space transform is + // animating doesn't get snapped to integer coordinates. + // + // + root + // + animated layer + // + surface + // + container + // + scroller + // + LayerImpl* root = root_layer(); + LayerImpl* animated_layer = AddChildToRoot<FakePictureLayerImpl>(); + LayerImpl* surface = AddChild<LayerImpl>(animated_layer); + LayerImpl* container = AddChild<LayerImpl>(surface); + LayerImpl* scroller = AddChild<LayerImpl>(container); + scroller->SetScrollClipLayer(container->id()); + scroller->SetDrawsContent(true); + + gfx::Transform identity_transform; + gfx::Transform start_scale; + start_scale.Scale(1.5f, 1.5f); + SetLayerPropertiesForTesting(root, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(animated_layer, start_scale, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + false); + SetLayerPropertiesForTesting(surface, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(container, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + false); + SetLayerPropertiesForTesting(scroller, identity_transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false, + false); + + gfx::Transform end_scale; + end_scale.Scale(2.f, 2.f); + TransformOperations start_operations; + start_operations.AppendMatrix(start_scale); + TransformOperations end_operations; + end_operations.AppendMatrix(end_scale); + AddAnimatedTransformToLayer(animated_layer, 1.0, start_operations, + end_operations); + + gfx::Vector2dF scroll_delta(5.f, 9.f); + scroller->SetScrollDelta(scroll_delta); + + ExecuteCalculateDrawProperties(root); + + gfx::Vector2dF expected_draw_transform_translation(-7.5f, -13.5f); + EXPECT_VECTOR2DF_EQ(expected_draw_transform_translation, + scroller->draw_transform().To2dTranslation()); +} + class AnimationScaleFactorTrackingLayerImpl : public LayerImpl { public: static scoped_ptr<AnimationScaleFactorTrackingLayerImpl> Create( @@ -6833,7 +5872,9 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { FakeImplProxy proxy; TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; - FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, + LayerTreeSettings settings; + settings.layer_transforms_should_scale_layer_contents = true; + FakeLayerTreeHostImpl host_impl(settings, &proxy, &shared_bitmap_manager, &task_graph_runner); gfx::Transform identity_matrix; scoped_ptr<AnimationScaleFactorTrackingLayerImpl> grand_parent = @@ -6878,6 +5919,16 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { EXPECT_EQ( 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + EXPECT_EQ(0.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 0.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); + TransformOperations translation; translation.AppendTranslate(1.f, 2.f, 3.f); @@ -6893,10 +5944,21 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { EXPECT_EQ( 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + EXPECT_EQ(0.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 0.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); + TransformOperations scale; scale.AppendScale(5.f, 4.f, 3.f); AddAnimatedTransformToLayer(child_raw, 1.0, TransformOperations(), scale); + child_raw->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(grand_parent.get()); // Only |child| has a scale-affecting animation. @@ -6908,8 +5970,19 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { EXPECT_EQ( 5.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + EXPECT_EQ(0.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(1.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 1.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); + AddAnimatedTransformToLayer( grand_parent.get(), 1.0, TransformOperations(), scale); + grand_parent->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(grand_parent.get()); // |grand_parent| and |child| have scale-affecting animations. @@ -6923,7 +5996,18 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { EXPECT_EQ( 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + EXPECT_EQ(1.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(1.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 0.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); + AddAnimatedTransformToLayer(parent_raw, 1.0, TransformOperations(), scale); + parent_raw->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(grand_parent.get()); // |grand_parent|, |parent|, and |child| have scale-affecting animations. @@ -6935,6 +6019,16 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { EXPECT_EQ( 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + EXPECT_EQ(1.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 0.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); + grand_parent->layer_animation_controller()->AbortAnimations( Animation::TRANSFORM); parent_raw->layer_animation_controller()->AbortAnimations( @@ -6947,6 +6041,7 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { AddAnimatedTransformToLayer( child_raw, 1.0, TransformOperations(), perspective); + child_raw->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(grand_parent.get()); // |child| has a scale-affecting animation but computing the maximum of this @@ -6959,6 +6054,16 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { EXPECT_EQ( 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + EXPECT_EQ(0.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 0.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); + child_raw->layer_animation_controller()->AbortAnimations( Animation::TRANSFORM); @@ -6982,6 +6087,16 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { 10.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + EXPECT_EQ(0.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(2.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(2.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 2.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); + gfx::Transform perspective_matrix; perspective_matrix.ApplyPerspectiveDepth(2.f); child_raw->SetTransform(perspective_matrix); @@ -6997,6 +6112,16 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { EXPECT_EQ( 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + EXPECT_EQ(0.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(2.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 0.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); + parent_raw->SetTransform(perspective_matrix); grand_parent->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(grand_parent.get()); @@ -7011,6 +6136,16 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { EXPECT_EQ( 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + EXPECT_EQ(0.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 0.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); + parent_raw->SetTransform(identity_matrix); child_raw->SetTransform(identity_matrix); grand_parent->SetTransform(perspective_matrix); @@ -7026,6 +6161,16 @@ TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) { EXPECT_EQ(0.f, child_raw->draw_properties().maximum_animation_contents_scale); EXPECT_EQ( 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale); + + EXPECT_EQ(0.f, + grand_parent->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + parent_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ(0.f, + child_raw->draw_properties().starting_animation_contents_scale); + EXPECT_EQ( + 0.f, + grand_child_raw->draw_properties().starting_animation_contents_scale); } static int membership_id(LayerImpl* layer) { @@ -7116,6 +6261,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->SetHasRenderSurface(true); + grand_child1_raw->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(grand_parent_raw); member_id = render_surface_layer_list_count(); @@ -7155,6 +6301,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) { // content. grand_child1_raw->SetDrawsContent(false); grand_child1_raw->SetHasRenderSurface(false); + grand_child1_raw->layer_tree_impl()->property_trees()->needs_rebuild = true; child_raw->SetHasRenderSurface(true); grand_child2_raw->SetDrawsContent(true); @@ -7176,6 +6323,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) { // Add a mask layer to child. child_raw->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 6).Pass()); + child_raw->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(grand_parent_raw); member_id = render_surface_layer_list_count(); @@ -7204,6 +6352,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) { LayerImpl::Create(host_impl.active_tree(), 20); replica_layer->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 21)); child_raw->SetReplicaLayer(replica_layer.Pass()); + child_raw->layer_tree_impl()->property_trees()->needs_rebuild = true; ExecuteCalculateDrawProperties(grand_parent_raw); member_id = render_surface_layer_list_count(); @@ -7267,6 +6416,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) { EXPECT_EQ(expected, actual); child_raw->TakeMaskLayer(); + child_raw->layer_tree_impl()->property_trees()->needs_rebuild = true; // Now everyone's a member! grand_parent_raw->SetDrawsContent(true); @@ -7483,9 +6633,8 @@ TEST_F(LayerTreeHostCommonTest, VisibleContentRectInChildRenderSurface) { host()->SetRootLayer(root); gfx::Size device_viewport_size(768, 582); - RenderSurfaceLayerList render_surface_layer_list; - LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( - host()->root_layer(), device_viewport_size, &render_surface_layer_list); + LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(host()->root_layer(), + device_viewport_size); inputs.device_scale_factor = 2.f; inputs.page_scale_factor = 1.f; inputs.page_scale_layer = NULL; @@ -7493,11 +6642,13 @@ TEST_F(LayerTreeHostCommonTest, VisibleContentRectInChildRenderSurface) { // Layers in the root render surface have their visible content rect clipped // by the viewport. - EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), root->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), + root->visible_rect_from_property_trees()); // Layers drawing to a child render surface should still have their visible // content rect clipped by the viewport. - EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), content->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), + content->visible_rect_from_property_trees()); } TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) { @@ -7552,11 +6703,9 @@ TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) { root, device_viewport_size, &layer_impl_list); LayerTreeHostCommon::CalculateDrawProperties(&inputs); - EXPECT_EQ(gfx::Rect(root_size), sublayer->visible_layer_rect()); root->SetBoundsDelta(gfx::Vector2dF(0.0, 50.0)); - LayerTreeHostCommon::CalculateDrawProperties(&inputs); gfx::Rect affected_by_delta(0, 0, root_size.width(), @@ -7723,9 +6872,9 @@ TEST_F(LayerTreeHostCommonTest, // 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), + // |surface| and layers that draw into it as having empty visible rect. + EXPECT_EQ(gfx::Rect(), surface->visible_rect_from_property_trees()); + EXPECT_EQ(gfx::Rect(), descendant_of_animation->visible_rect_from_property_trees()); } @@ -7752,9 +6901,9 @@ TEST_F(LayerTreeHostCommonTest, AnimatedFilterCreatesRenderSurface) { ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRUE(root->render_surface()); - EXPECT_TRUE(child->render_surface()); - EXPECT_FALSE(grandchild->render_surface()); + EXPECT_TRUE(root->has_render_surface()); + EXPECT_TRUE(child->has_render_surface()); + EXPECT_FALSE(grandchild->has_render_surface()); EXPECT_TRUE(root->filters().IsEmpty()); EXPECT_TRUE(child->filters().IsEmpty()); @@ -7765,6 +6914,59 @@ TEST_F(LayerTreeHostCommonTest, AnimatedFilterCreatesRenderSurface) { EXPECT_FALSE(grandchild->FilterIsAnimating()); } +// Verify that having a filter animation with a delayed start time creates a +// render surface. +TEST_F(LayerTreeHostCommonTest, DelayedFilterAnimationCreatesRenderSurface) { + scoped_refptr<Layer> root = Layer::Create(layer_settings()); + scoped_refptr<Layer> child = Layer::Create(layer_settings()); + scoped_refptr<Layer> grandchild = Layer::Create(layer_settings()); + 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); + host()->SetRootLayer(root); + + scoped_ptr<KeyframedFilterAnimationCurve> curve( + KeyframedFilterAnimationCurve::Create()); + FilterOperations start_filters; + start_filters.Append(FilterOperation::CreateBrightnessFilter(0.1f)); + FilterOperations end_filters; + end_filters.Append(FilterOperation::CreateBrightnessFilter(0.3f)); + curve->AddKeyframe( + FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr)); + curve->AddKeyframe(FilterKeyframe::Create( + base::TimeDelta::FromMilliseconds(100), end_filters, nullptr)); + scoped_ptr<Animation> animation = + Animation::Create(curve.Pass(), 0, 1, Animation::FILTER); + animation->set_fill_mode(Animation::FILL_MODE_NONE); + animation->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); + child->layer_animation_controller()->AddAnimation(animation.Pass()); + + ExecuteCalculateDrawProperties(root.get()); + + EXPECT_TRUE(root->has_render_surface()); + EXPECT_TRUE(child->has_render_surface()); + EXPECT_FALSE(grandchild->has_render_surface()); + + EXPECT_TRUE(root->filters().IsEmpty()); + EXPECT_TRUE(child->filters().IsEmpty()); + EXPECT_TRUE(grandchild->filters().IsEmpty()); + + EXPECT_FALSE(root->FilterIsAnimating()); + EXPECT_FALSE(root->HasPotentiallyRunningFilterAnimation()); + EXPECT_FALSE(child->FilterIsAnimating()); + EXPECT_TRUE(child->HasPotentiallyRunningFilterAnimation()); + EXPECT_FALSE(grandchild->FilterIsAnimating()); + EXPECT_FALSE(grandchild->HasPotentiallyRunningFilterAnimation()); +} + // Ensures that the property tree code accounts for offsets between fixed // position layers and their respective containers. TEST_F(LayerTreeHostCommonTest, PropertyTreesAccountForFixedParentOffset) { @@ -8174,6 +7376,25 @@ TEST_F(LayerTreeHostCommonTest, SkippingSubtreeMain) { EXPECT_EQ(gfx::Rect(0, 0), grandchild->visible_rect_from_property_trees()); child->SetHideLayerAndSubtree(false); + gfx::Transform zero_z_scale; + zero_z_scale.Scale3d(1, 1, 0); + child->SetTransform(zero_z_scale); + + // Add a transform animation with a start delay. Now, even though |child| has + // a singular transform, the subtree should still get processed. + int animation_id = 0; + scoped_ptr<Animation> animation = Animation::Create( + scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), + animation_id, 1, Animation::TRANSFORM); + animation->set_fill_mode(Animation::FILL_MODE_NONE); + animation->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); + child->AddAnimation(animation.Pass()); + ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); + EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_rect_from_property_trees()); + grandchild->set_visible_rect_from_property_trees(gfx::Rect()); + + child->RemoveAnimation(animation_id); + child->SetTransform(identity); child->SetOpacity(0.f); ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); EXPECT_EQ(gfx::Rect(0, 0), grandchild->visible_rect_from_property_trees()); @@ -8181,17 +7402,20 @@ TEST_F(LayerTreeHostCommonTest, SkippingSubtreeMain) { // 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))); + greatgrandchild->RequestCopyOfOutput( + CopyOutputRequest::CreateBitmapRequest(base::Bind(&CopyOutputCallback))); ExecuteCalculateDrawPropertiesWithPropertyTrees(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()); - ExecuteCalculateDrawPropertiesWithPropertyTrees(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))); + // Add an opacity animation with a start delay. + animation_id = 1; + animation = Animation::Create( + scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + animation_id, 1, Animation::OPACITY); + animation->set_fill_mode(Animation::FILL_MODE_NONE); + animation->set_time_offset(base::TimeDelta::FromMilliseconds(-1000)); + child->AddAnimation(animation.Pass()); ExecuteCalculateDrawPropertiesWithPropertyTrees(root.get()); EXPECT_EQ(gfx::Rect(10, 10), grandchild->visible_rect_from_property_trees()); } @@ -8270,17 +7494,6 @@ TEST_F(LayerTreeHostCommonTest, SkippingSubtreeImpl) { // 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))); - ExecuteCalculateDrawPropertiesWithPropertyTrees(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()); - ExecuteCalculateDrawPropertiesWithPropertyTrees(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()); @@ -8356,50 +7569,37 @@ TEST_F(LayerTreeHostCommonTest, LayerTreeRebuildTest) { host()->SetRootLayer(root); ExecuteCalculateDrawProperties(root.get()); - EXPECT_EQ(parent->draw_properties().num_unclipped_descendants, 1u); - - // 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); + EXPECT_EQ(parent->num_unclipped_descendants(), 1u); child->RequestCopyOfOutput( CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback))); - EXPECT_TRUE(root->draw_properties().layer_or_descendant_has_copy_request); + EXPECT_GT(root->num_layer_or_descendants_with_copy_request(), 0); ExecuteCalculateDrawProperties(root.get()); - EXPECT_TRUE(root->draw_properties().layer_or_descendant_has_copy_request); + EXPECT_GT(root->num_layer_or_descendants_with_copy_request(), 0); } TEST_F(LayerTreeHostCommonTest, InputHandlersRecursiveUpdateTest) { // Ensure that the treewalk in LayertreeHostCommon:: // PreCalculateMetaInformation updates input handlers correctly. - scoped_refptr<Layer> root = Layer::Create(layer_settings()); - scoped_refptr<Layer> child = Layer::Create(layer_settings()); - - root->AddChild(child); - - child->SetHaveWheelEventHandlers(true); + LayerImpl* root = root_layer(); + LayerImpl* child = AddChild<LayerImpl>(root); 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); + SetLayerPropertiesForTesting(root, identity, gfx::Point3F(), gfx::PointF(), + gfx::Size(100, 100), true, false, true); + SetLayerPropertiesForTesting(child, identity, gfx::Point3F(), gfx::PointF(), + gfx::Size(100, 100), true, false, false); - host()->SetRootLayer(root); + EXPECT_EQ(root->layer_or_descendant_has_input_handler(), false); + + child->SetHaveWheelEventHandlers(true); + ExecuteCalculateDrawProperties(root); + EXPECT_EQ(root->layer_or_descendant_has_input_handler(), true); - 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); + ExecuteCalculateDrawProperties(root); + EXPECT_EQ(root->layer_or_descendant_has_input_handler(), false); } TEST_F(LayerTreeHostCommonTest, ResetPropertyTreeIndices) { @@ -8466,5 +7666,302 @@ TEST_F(LayerTreeHostCommonTest, ResetLayerDrawPropertiestest) { EXPECT_FALSE(child->sorted_for_recursion()); } +TEST_F(LayerTreeHostCommonTest, RenderSurfaceClipsSubtree) { + // Ensure that a Clip Node is added when a render surface applies clip. + LayerImpl* root = root_layer(); + LayerImpl* significant_transform = AddChildToRoot<LayerImpl>(); + LayerImpl* layer_clips_subtree = AddChild<LayerImpl>(significant_transform); + LayerImpl* render_surface = AddChild<LayerImpl>(layer_clips_subtree); + LayerImpl* test_layer = AddChild<LayerImpl>(render_surface); + + const gfx::Transform identity_matrix; + // This transform should be a significant one so that a transform node is + // formed for it. + gfx::Transform transform1; + transform1.RotateAboutYAxis(45); + transform1.RotateAboutXAxis(30); + // This transform should be a 3d transform as we want the render surface + // to flatten the transform + gfx::Transform transform2; + transform2.Translate3d(10, 10, 10); + + layer_clips_subtree->SetMasksToBounds(true); + test_layer->SetDrawsContent(true); + + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(significant_transform, transform1, + gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30), + true, false, false); + SetLayerPropertiesForTesting(layer_clips_subtree, identity_matrix, + gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30), + true, false, false); + SetLayerPropertiesForTesting(render_surface, transform2, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(test_layer, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + false); + + ExecuteCalculateDrawProperties(root); + + TransformTree transform_tree = + root->layer_tree_impl()->property_trees()->transform_tree; + TransformNode* transform_node = + transform_tree.Node(significant_transform->transform_tree_index()); + EXPECT_EQ(transform_node->owner_id, significant_transform->id()); + + ClipTree clip_tree = root->layer_tree_impl()->property_trees()->clip_tree; + ClipNode* clip_node = clip_tree.Node(render_surface->clip_tree_index()); + EXPECT_TRUE(clip_node->data.use_only_parent_clip); + EXPECT_EQ(gfx::Rect(30, 21), test_layer->visible_rect_from_property_trees()); +} + +TEST_F(LayerTreeHostCommonTest, TransformOfParentClipNodeAncestorOfTarget) { + // Ensure that when parent clip node's transform is an ancestor of current + // clip node's target, clip is 'projected' from parent space to current + // target space and visible rects are calculated correctly. + LayerImpl* root = root_layer(); + LayerImpl* clip_layer = AddChild<LayerImpl>(root); + LayerImpl* target_layer = AddChild<LayerImpl>(clip_layer); + LayerImpl* test_layer = AddChild<LayerImpl>(target_layer); + + const gfx::Transform identity_matrix; + gfx::Transform transform; + transform.RotateAboutYAxis(45); + clip_layer->SetMasksToBounds(true); + target_layer->SetMasksToBounds(true); + test_layer->SetDrawsContent(true); + + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(clip_layer, transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + false); + SetLayerPropertiesForTesting(target_layer, transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(test_layer, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + false); + ExecuteCalculateDrawProperties(root); + + EXPECT_EQ(gfx::Rect(30, 30), test_layer->visible_rect_from_property_trees()); +} + +TEST_F(LayerTreeHostCommonTest, + RenderSurfaceWithUnclippedDescendantsClipsSubtree) { + // Ensure clip rect is calculated correctly when render surface has unclipped + // descendants. + LayerImpl* root = root_layer(); + LayerImpl* clip_parent = AddChildToRoot<LayerImpl>(); + LayerImpl* between_clip_parent_and_child = AddChild<LayerImpl>(clip_parent); + LayerImpl* render_surface = + AddChild<LayerImpl>(between_clip_parent_and_child); + LayerImpl* test_layer = AddChild<LayerImpl>(render_surface); + + const gfx::Transform identity_matrix; + gfx::Transform transform; + transform.Translate(2.0, 2.0); + + test_layer->SetDrawsContent(true); + render_surface->SetClipParent(clip_parent); + scoped_ptr<std::set<LayerImpl*>> clip_children(new std::set<LayerImpl*>); + clip_children->insert(render_surface); + clip_parent->SetClipChildren(clip_children.release()); + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(clip_parent, transform, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + false); + SetLayerPropertiesForTesting(between_clip_parent_and_child, transform, + gfx::Point3F(), gfx::PointF(), gfx::Size(30, 30), + true, false, false); + SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(test_layer, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + false); + + ExecuteCalculateDrawProperties(root); + + EXPECT_EQ(gfx::Rect(30, 30), test_layer->clip_rect()); +} + +TEST_F(LayerTreeHostCommonTest, + RenderSurfaceClipsSubtreeAndHasUnclippedDescendants) { + LayerImpl* root = root_layer(); + LayerImpl* clip_parent = AddChildToRoot<LayerImpl>(); + LayerImpl* render_surface = AddChild<LayerImpl>(clip_parent); + LayerImpl* test_layer1 = AddChild<LayerImpl>(render_surface); + LayerImpl* clip_child = AddChild<LayerImpl>(test_layer1); + LayerImpl* test_layer2 = AddChild<LayerImpl>(clip_child); + + const gfx::Transform identity_matrix; + root->SetMasksToBounds(true); + render_surface->SetMasksToBounds(true); + render_surface->SetDrawsContent(true); + clip_child->SetDrawsContent(true); + test_layer1->SetDrawsContent(true); + test_layer2->SetDrawsContent(true); + clip_child->SetClipParent(clip_parent); + scoped_ptr<std::set<LayerImpl*>> clip_children(new std::set<LayerImpl*>); + clip_children->insert(clip_child); + clip_parent->SetClipChildren(clip_children.release()); + + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(clip_parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + false); + SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(test_layer1, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + false); + SetLayerPropertiesForTesting(clip_child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + false); + SetLayerPropertiesForTesting(test_layer2, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + false); + + ExecuteCalculateDrawProperties(root); + EXPECT_EQ(gfx::Rect(50, 50), render_surface->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(50, 50), test_layer1->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(30, 30), clip_child->visible_layer_rect()); + EXPECT_EQ(gfx::Rect(30, 30), test_layer2->visible_layer_rect()); +} + +TEST_F(LayerTreeHostCommonTest, UnclippedClipParent) { + LayerImpl* root = root_layer(); + LayerImpl* clip_parent = AddChildToRoot<LayerImpl>(); + LayerImpl* render_surface = AddChild<LayerImpl>(clip_parent); + LayerImpl* clip_child = AddChild<LayerImpl>(render_surface); + + const gfx::Transform identity_matrix; + clip_parent->SetDrawsContent(true); + render_surface->SetMasksToBounds(true); + render_surface->SetDrawsContent(true); + clip_child->SetDrawsContent(true); + + clip_child->SetClipParent(clip_parent); + scoped_ptr<std::set<LayerImpl*>> clip_children(new std::set<LayerImpl*>); + clip_children->insert(clip_child); + clip_parent->SetClipChildren(clip_children.release()); + + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(clip_parent, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + false); + SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(clip_child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + false); + + ExecuteCalculateDrawProperties(root); + + // The clip child should inherit its clip parent's clipping state, not its + // tree parent's clipping state. + EXPECT_FALSE(clip_parent->is_clipped()); + EXPECT_TRUE(render_surface->is_clipped()); + EXPECT_FALSE(clip_child->is_clipped()); +} + +TEST_F(LayerTreeHostCommonTest, LayerWithInputHandlerAndZeroOpacity) { + LayerImpl* root = root_layer(); + LayerImpl* render_surface = AddChild<LayerImpl>(root); + LayerImpl* test_layer = AddChild<LayerImpl>(render_surface); + + const gfx::Transform identity_matrix; + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(test_layer, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(20, 20), true, false, + false); + + render_surface->SetMasksToBounds(true); + test_layer->SetDrawsContent(true); + test_layer->SetOpacity(0); + test_layer->SetHaveWheelEventHandlers(true); + + ExecuteCalculateDrawProperties(root); + EXPECT_EQ(gfx::Rect(20, 20), test_layer->drawable_content_rect()); + EXPECT_EQ(gfx::RectF(20, 20), + render_surface->render_surface()->DrawableContentRect()); +} + +TEST_F(LayerTreeHostCommonTest, + LayerClipRectLargerThanClippingRenderSurfaceRect) { + LayerImpl* root = root_layer(); + LayerImpl* render_surface = AddChild<LayerImpl>(root); + LayerImpl* test_layer = AddChild<LayerImpl>(render_surface); + const gfx::Transform identity_matrix; + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(render_surface, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + true); + SetLayerPropertiesForTesting(test_layer, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(50, 50), true, false, + false); + root->SetMasksToBounds(true); + render_surface->SetMasksToBounds(true); + test_layer->SetMasksToBounds(true); + test_layer->SetDrawsContent(true); + ExecuteCalculateDrawProperties(root); + + EXPECT_EQ(gfx::Rect(30, 30), root->clip_rect()); + EXPECT_EQ(gfx::Rect(50, 50), render_surface->clip_rect()); + EXPECT_EQ(gfx::Rect(50, 50), test_layer->clip_rect()); +} + +TEST_F(LayerTreeHostCommonTest, TwoUnclippedRenderSurfaces) { + LayerImpl* root = root_layer(); + LayerImpl* render_surface1 = AddChild<LayerImpl>(root); + LayerImpl* render_surface2 = AddChild<LayerImpl>(render_surface1); + LayerImpl* clip_child = AddChild<LayerImpl>(render_surface2); + + const gfx::Transform identity_matrix; + clip_child->SetClipParent(root); + scoped_ptr<std::set<LayerImpl*>> clip_children(new std::set<LayerImpl*>); + clip_children->insert(clip_child); + root->SetClipChildren(clip_children.release()); + root->SetMasksToBounds(true); + render_surface1->SetDrawsContent(true); + render_surface2->SetDrawsContent(true); + + SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(render_surface1, identity_matrix, gfx::Point3F(), + gfx::PointF(10, 10), gfx::Size(30, 30), true, + false, true); + SetLayerPropertiesForTesting(render_surface2, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + true); + SetLayerPropertiesForTesting(clip_child, identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(30, 30), true, false, + false); + ExecuteCalculateDrawProperties(root); + + EXPECT_EQ(gfx::Rect(-10, -10, 30, 30), render_surface2->clip_rect()); +} + } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc index f122aeb58b9..ab75b9c0c11 100644 --- a/chromium/cc/trees/layer_tree_host_impl.cc +++ b/chromium/cc/trees/layer_tree_host_impl.cc @@ -23,17 +23,18 @@ #include "cc/animation/scroll_offset_animation_curve.h" #include "cc/animation/scrollbar_animation_controller.h" #include "cc/animation/timing_function.h" +#include "cc/base/histograms.h" #include "cc/base/math_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/scroll_state.h" #include "cc/input/top_controls_manager.h" #include "cc/layers/append_quads_data.h" #include "cc/layers/heads_up_display_layer_impl.h" @@ -57,7 +58,6 @@ #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" @@ -129,34 +129,6 @@ void DidVisibilityChange(LayerTreeHostImpl* id, bool visible) { TRACE_EVENT_ASYNC_END0("cc", "LayerTreeHostImpl::SetVisible", id); } -size_t GetMaxTransferBufferUsageBytes( - const ContextProvider::Capabilities& context_capabilities, - double refresh_rate) { - // We want to make sure the default transfer buffer size is equal to the - // amount of data that can be uploaded by the compositor to avoid stalling - // the pipeline. - // For reference Chromebook Pixel can upload 1MB in about 0.5ms. - const size_t kMaxBytesUploadedPerMs = 1024 * 1024 * 2; - - // We need to upload at least enough work to keep the GPU process busy until - // the next time it can handle a request to start more uploads from the - // compositor. We assume that it will pick up any sent upload requests within - // the time of a vsync, since the browser will want to swap a frame within - // that time interval, and then uploads should have a chance to be processed. - size_t ms_per_frame = std::floor(1000.0 / refresh_rate); - size_t max_transfer_buffer_usage_bytes = - ms_per_frame * kMaxBytesUploadedPerMs; - - // The context may request a lower limit based on the device capabilities. - return std::min(context_capabilities.max_transfer_buffer_usage_bytes, - max_transfer_buffer_usage_bytes); -} - -size_t GetMaxStagingResourceCount() { - // Upper bound for number of staging resource to allow. - return 32; -} - size_t GetDefaultMemoryAllocationLimit() { // TODO(ccameron): (http://crbug.com/137094) This 64MB default is a straggler // from the old texture manager and is just to give us a default memory @@ -169,8 +141,8 @@ size_t GetDefaultMemoryAllocationLimit() { } // namespace -LayerTreeHostImpl::FrameData::FrameData() : has_no_damage(false) { -} +LayerTreeHostImpl::FrameData::FrameData() + : render_surface_layer_list(nullptr), has_no_damage(false) {} LayerTreeHostImpl::FrameData::~FrameData() {} @@ -200,6 +172,7 @@ LayerTreeHostImpl::LayerTreeHostImpl( : client_(client), proxy_(proxy), current_begin_frame_tracker_(BEGINFRAMETRACKER_FROM_HERE), + output_surface_(nullptr), content_is_suitable_for_gpu_rasterization_(true), has_gpu_rasterization_trigger_(false), use_gpu_rasterization_(false), @@ -208,34 +181,32 @@ LayerTreeHostImpl::LayerTreeHostImpl( tree_resources_for_gpu_rasterization_dirty_(false), input_handler_client_(NULL), did_lock_scrolling_layer_(false), - should_bubble_scrolls_(false), wheel_scrolling_(false), scroll_affects_scroll_handler_(false), scroll_layer_id_when_mouse_over_scrollbar_(0), tile_priorities_dirty_(false), - root_layer_scroll_offset_delegate_(NULL), settings_(settings), visible_(true), cached_managed_memory_policy_( GetDefaultMemoryAllocationLimit(), gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING, ManagedMemoryPolicy::kDefaultNumResourcesLimit), - // Must be initialized after settings_ and proxy_. + is_synchronous_single_threaded_(!proxy->HasImplThread() && + !settings.single_thread_proxy_scheduler), + // Must be initialized after is_synchronous_single_threaded_ and proxy_. tile_manager_( TileManager::Create(this, GetTaskRunner(), - IsSynchronousSingleThreaded() + is_synchronous_single_threaded_ ? std::numeric_limits<size_t>::max() : settings.scheduled_raster_task_limit)), pinch_gesture_active_(false), pinch_gesture_end_should_clear_scrolling_layer_(false), fps_counter_(FrameRateCounter::Create(proxy_->HasImplThread())), - paint_time_counter_(PaintTimeCounter::Create()), memory_history_(MemoryHistory::Create()), debug_rect_history_(DebugRectHistory::Create()), texture_mailbox_deleter_(new TextureMailboxDeleter(GetTaskRunner())), max_memory_needed_bytes_(0), - device_scale_factor_(1.f), resourceless_software_draw_(false), animation_registrar_(), rendering_stats_instrumentation_(rendering_stats_instrumentation), @@ -261,8 +232,6 @@ LayerTreeHostImpl::LayerTreeHostImpl( } DCHECK(proxy_->IsImplThread()); - DCHECK_IMPLIES(settings.use_one_copy, !settings.use_zero_copy); - DCHECK_IMPLIES(settings.use_zero_copy, !settings.use_one_copy); DidVisibilityChange(this, visible_); SetDebugState(settings.initial_debug_state); @@ -314,6 +283,13 @@ LayerTreeHostImpl::~LayerTreeHostImpl() { } CleanUpTileManager(); + renderer_ = nullptr; + resource_provider_ = nullptr; + + if (output_surface_) { + output_surface_->DetachFromClient(); + output_surface_ = nullptr; + } } void LayerTreeHostImpl::BeginMainFrameAborted(CommitEarlyOutReason reason) { @@ -343,6 +319,19 @@ void LayerTreeHostImpl::BeginCommit() { void LayerTreeHostImpl::CommitComplete() { TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete"); + if (proxy_->CommitToActiveTree()) { + // We have to activate animations here or "IsActive()" is true on the layers + // but the animations aren't activated yet so they get ignored by + // UpdateDrawProperties. + ActivateAnimations(); + } + + // Start animations before UpdateDrawProperties and PrepareTiles, as they can + // change the results. When doing commit to the active tree, this must happen + // after ActivateAnimations() in order for this ticking to be propogated to + // layers on the active tree. + Animate(); + // LayerTreeHost may have changed the GPU rasterization flags state, which // may require an update of the tree resources. UpdateTreeResourcesForGpuRasterizationIfNeeded(); @@ -418,20 +407,32 @@ bool LayerTreeHostImpl::CanDraw() const { return true; } -void LayerTreeHostImpl::Animate(base::TimeTicks monotonic_time) { +void LayerTreeHostImpl::Animate() { + DCHECK(proxy_->IsImplThread()); + base::TimeTicks monotonic_time = CurrentBeginFrameArgs().frame_time; + // mithro(TODO): Enable these checks. // DCHECK(!current_begin_frame_tracker_.HasFinished()); // DCHECK(monotonic_time == current_begin_frame_tracker_.Current().frame_time) // << "Called animate with unknown frame time!?"; - if (!root_layer_scroll_offset_delegate_ || - (CurrentlyScrollingLayer() != InnerViewportScrollLayer() && - CurrentlyScrollingLayer() != OuterViewportScrollLayer())) { - AnimateInput(monotonic_time); + + if (input_handler_client_) { + // This animates fling scrolls. But on Android WebView root flings are + // controlled by the application, so the compositor does not animate them. + bool ignore_fling = + settings_.ignore_root_layer_flings && IsCurrentlyScrollingRoot(); + if (!ignore_fling) + input_handler_client_->Animate(monotonic_time); } + AnimatePageScale(monotonic_time); AnimateLayers(monotonic_time); AnimateScrollbars(monotonic_time); AnimateTopControls(monotonic_time); + + // Animating stuff can change the root scroll offset, so inform the + // synchronous input handler. + UpdateRootLayerStateForSynchronousInputHandler(); } bool LayerTreeHostImpl::PrepareTiles() { @@ -457,7 +458,7 @@ void LayerTreeHostImpl::StartPageScaleAnimation( gfx::ScrollOffset scroll_total = active_tree_->TotalScrollOffset(); gfx::SizeF scaled_scrollable_size = active_tree_->ScrollableSize(); gfx::SizeF viewport_size = - active_tree_->InnerViewportContainerLayer()->bounds(); + gfx::SizeF(active_tree_->InnerViewportContainerLayer()->bounds()); // Easing constants experimentally determined. scoped_ptr<TimingFunction> timing_function = @@ -487,48 +488,46 @@ void LayerTreeHostImpl::StartPageScaleAnimation( } void LayerTreeHostImpl::SetNeedsAnimateInput() { - if (root_layer_scroll_offset_delegate_ && - (CurrentlyScrollingLayer() == InnerViewportScrollLayer() || - CurrentlyScrollingLayer() == OuterViewportScrollLayer())) { - if (root_layer_animation_callback_.is_null()) { - root_layer_animation_callback_ = - base::Bind(&LayerTreeHostImpl::AnimateInput, AsWeakPtr()); - } - root_layer_scroll_offset_delegate_->SetNeedsAnimate( - root_layer_animation_callback_); - return; - } - + DCHECK_IMPLIES(IsCurrentlyScrollingRoot(), + !settings_.ignore_root_layer_flings); SetNeedsAnimate(); } +bool LayerTreeHostImpl::IsCurrentlyScrollingRoot() const { + LayerImpl* scrolling_layer = CurrentlyScrollingLayer(); + if (!scrolling_layer) + return false; + return scrolling_layer == InnerViewportScrollLayer(); +} + bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt( const gfx::Point& viewport_point, - InputHandler::ScrollInputType type) { - if (!CurrentlyScrollingLayer()) + InputHandler::ScrollInputType type) const { + LayerImpl* scrolling_layer_impl = CurrentlyScrollingLayer(); + if (!scrolling_layer_impl) return false; gfx::PointF device_viewport_point = - gfx::ScalePoint(viewport_point, device_scale_factor_); + gfx::ScalePoint(viewport_point, active_tree_->device_scale_factor()); LayerImpl* layer_impl = active_tree_->FindLayerThatIsHitByPoint(device_viewport_point); bool scroll_on_main_thread = false; - LayerImpl* scrolling_layer_impl = FindScrollLayerForDeviceViewportPoint( + LayerImpl* test_layer_impl = FindScrollLayerForDeviceViewportPoint( device_viewport_point, type, layer_impl, &scroll_on_main_thread, NULL); - if (!scrolling_layer_impl) + if (!test_layer_impl) return false; - if (CurrentlyScrollingLayer() == scrolling_layer_impl) + if (scrolling_layer_impl == test_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())) { + if ((scrolling_layer_impl == InnerViewportScrollLayer() && + test_layer_impl == OuterViewportScrollLayer()) || + (scrolling_layer_impl == OuterViewportScrollLayer() && + test_layer_impl == InnerViewportScrollLayer())) { return true; } @@ -538,7 +537,7 @@ bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt( bool LayerTreeHostImpl::HaveWheelEventHandlersAt( const gfx::Point& viewport_point) { gfx::PointF device_viewport_point = - gfx::ScalePoint(viewport_point, device_scale_factor_); + gfx::ScalePoint(viewport_point, active_tree_->device_scale_factor()); LayerImpl* layer_impl = active_tree_->FindLayerWithWheelHandlerThatIsHitByPoint( @@ -547,15 +546,16 @@ bool LayerTreeHostImpl::HaveWheelEventHandlersAt( return layer_impl != NULL; } -static LayerImpl* NextScrollLayer(LayerImpl* layer) { - if (LayerImpl* scroll_parent = layer->scroll_parent()) - return scroll_parent; +static LayerImpl* NextLayerInScrollOrder(LayerImpl* layer) { + if (layer->scroll_parent()) + return layer->scroll_parent(); + return layer->parent(); } static ScrollBlocksOn EffectiveScrollBlocksOn(LayerImpl* layer) { ScrollBlocksOn blocks = SCROLL_BLOCKS_ON_NONE; - for (; layer; layer = NextScrollLayer(layer)) { + for (; layer; layer = NextLayerInScrollOrder(layer)) { blocks |= layer->scroll_blocks_on(); } return blocks; @@ -564,7 +564,7 @@ static ScrollBlocksOn EffectiveScrollBlocksOn(LayerImpl* layer) { bool LayerTreeHostImpl::DoTouchEventsBlockScrollAt( const gfx::Point& viewport_point) { gfx::PointF device_viewport_point = - gfx::ScalePoint(viewport_point, device_scale_factor_); + gfx::ScalePoint(viewport_point, active_tree_->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 @@ -816,6 +816,16 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses( root_pass->damage_rect = root_pass->output_rect; } + // Because the active tree could be drawn again if this fails for some reason, + // clear all of the copy request flags so that sanity checks for the counts + // succeed. + if (!active_tree_->LayersWithCopyOutputRequest().empty()) { + LayerTreeHostCommon::CallFunctionForSubtree( + active_tree_->root_layer(), [](LayerImpl* layer) { + layer->set_num_layer_or_descendant_with_copy_request(0); + }); + } + // 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 @@ -919,8 +929,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses( if (append_quads_data.num_missing_tiles) { bool layer_has_animating_transform = - it->screen_space_transform_is_animating() || - it->draw_transform_is_animating(); + it->screen_space_transform_is_animating(); if (layer_has_animating_transform) have_missing_animated_tiles = true; } @@ -1036,13 +1045,18 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) { "Compositing.NumActiveLayers", base::saturated_cast<int>(active_tree_->NumLayers()), 1, 400, 20); - 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", - base::saturated_cast<int>(total_picture_memory / 1024)); + if (const char* client_name = GetClientNameForMetrics()) { + 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) { + // GetClientNameForMetrics only returns one non-null value over the + // lifetime of the process, so this histogram name is runtime constant. + UMA_HISTOGRAM_COUNTS( + base::StringPrintf("Compositing.%s.PictureMemoryUsageKb", + client_name), + base::saturated_cast<int>(total_picture_memory / 1024)); + } } bool update_lcd_text = false; @@ -1096,28 +1110,20 @@ void LayerTreeHostImpl::RemoveRenderPasses(FrameData* frame) { 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; + for (auto it = pass->quad_list.begin(); it != pass->quad_list.end();) { + if (it->material != DrawQuad::RENDER_PASS) { + ++it; + 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]++; + ++it; + } else { + it = pass->quad_list.EraseAndInvalidateAllPointers(it); } } @@ -1223,33 +1229,14 @@ void LayerTreeHostImpl::UpdateTileManagerMemoryPolicy( false /* aggressively_free_resources */); } - // TODO(reveman): We should avoid keeping around unused resources if - // possible. crbug.com/224475 - // Unused limit is calculated from soft-limit, as hard-limit may - // be very high and shouldn't typically be exceeded. - size_t unused_memory_limit_in_bytes = static_cast<size_t>( - (static_cast<int64>(global_tile_state_.soft_memory_limit_in_bytes) * - settings_.max_unused_resource_memory_percentage) / - 100); - DCHECK(resource_pool_); - resource_pool_->CheckBusyResources(false); + resource_pool_->CheckBusyResources(); // Soft limit is used for resource pool such that memory returns to soft // limit after going over. resource_pool_->SetResourceUsageLimits( global_tile_state_.soft_memory_limit_in_bytes, - unused_memory_limit_in_bytes, global_tile_state_.num_resources_limit); - // Release all staging resources when invisible. - if (staging_resource_pool_) { - staging_resource_pool_->CheckBusyResources(false); - staging_resource_pool_->SetResourceUsageLimits( - std::numeric_limits<size_t>::max(), - std::numeric_limits<size_t>::max(), - visible_ ? GetMaxStagingResourceCount() : 0); - } - DidModifyTilePriorities(); } @@ -1419,8 +1406,8 @@ void LayerTreeHostImpl::SetExternalDrawConstraints( if (transform_for_tile_priority.GetInverse(&screen_to_view)) { // Convert from screen space to view space. viewport_rect_for_tile_priority_in_view_space = - gfx::ToEnclosingRect(MathUtil::ProjectClippedRect( - screen_to_view, viewport_rect_for_tile_priority)); + MathUtil::ProjectEnclosingClippedRect( + screen_to_view, viewport_rect_for_tile_priority); } } @@ -1463,7 +1450,7 @@ void LayerTreeHostImpl::ReclaimResources(const CompositorFrameAck* ack) { // In OOM, we now might be able to release more resources that were held // because they were exported. if (resource_pool_) { - resource_pool_->CheckBusyResources(false); + resource_pool_->CheckBusyResources(); resource_pool_->ReduceResourceUsage(); } // If we're not visible, we likely released resources, so we want to @@ -1484,7 +1471,7 @@ void LayerTreeHostImpl::OnCanDrawStateChangedForTree() { CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const { CompositorFrameMetadata metadata; - metadata.device_scale_factor = device_scale_factor_; + metadata.device_scale_factor = active_tree_->device_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(); @@ -1494,22 +1481,25 @@ CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const { gfx::Vector2dF(0.f, top_controls_manager_->ControlsTopOffset()); metadata.location_bar_content_translation = gfx::Vector2dF(0.f, top_controls_manager_->ContentTopOffset()); + metadata.root_background_color = active_tree_->background_color(); active_tree_->GetViewportSelection(&metadata.selection); - LayerImpl* root_layer_for_overflow = OuterViewportScrollLayer() - ? OuterViewportScrollLayer() - : InnerViewportScrollLayer(); - if (root_layer_for_overflow) { + if (OuterViewportScrollLayer()) { metadata.root_overflow_x_hidden = - !root_layer_for_overflow->user_scrollable_horizontal(); + !OuterViewportScrollLayer()->user_scrollable_horizontal(); metadata.root_overflow_y_hidden = - !root_layer_for_overflow->user_scrollable_vertical(); + !OuterViewportScrollLayer()->user_scrollable_vertical(); } if (!InnerViewportScrollLayer()) return metadata; + metadata.root_overflow_x_hidden |= + !InnerViewportScrollLayer()->user_scrollable_horizontal(); + metadata.root_overflow_y_hidden |= + !InnerViewportScrollLayer()->user_scrollable_vertical(); + // TODO(miletus) : Change the metadata to hold ScrollOffset. metadata.root_scroll_offset = gfx::ScrollOffsetToVector2dF( active_tree_->TotalScrollOffset()); @@ -1590,18 +1580,14 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame) { scoped_ptr<SoftwareRenderer> temp_software_renderer = SoftwareRenderer::Create(this, &settings_.renderer_settings, - output_surface_.get(), NULL); - temp_software_renderer->DrawFrame(&frame->render_passes, - device_scale_factor_, - DeviceViewport(), - DeviceClip(), - disable_picture_quad_image_filtering); + output_surface_, NULL); + temp_software_renderer->DrawFrame( + &frame->render_passes, active_tree_->device_scale_factor(), + DeviceViewport(), DeviceClip(), disable_picture_quad_image_filtering); } else { renderer_->DrawFrame(&frame->render_passes, - device_scale_factor_, - DeviceViewport(), - DeviceClip(), - false); + active_tree_->device_scale_factor(), DeviceViewport(), + DeviceClip(), false); } // The render passes should be consumed by the renderer. DCHECK(frame->render_passes.empty()); @@ -1637,6 +1623,18 @@ void LayerTreeHostImpl::FinishAllRendering() { renderer_->Finish(); } +int LayerTreeHostImpl::RequestedMSAASampleCount() const { + if (settings_.gpu_rasterization_msaa_sample_count == -1) { + // Use the most up-to-date version of device_scale_factor that we have. + float device_scale_factor = pending_tree_ + ? pending_tree_->device_scale_factor() + : active_tree_->device_scale_factor(); + return device_scale_factor >= 2.0f ? 4 : 8; + } + + return settings_.gpu_rasterization_msaa_sample_count; +} + bool LayerTreeHostImpl::CanUseGpuRasterization() { if (!(output_surface_ && output_surface_->context_provider() && output_surface_->worker_context_provider())) @@ -1644,7 +1642,7 @@ bool LayerTreeHostImpl::CanUseGpuRasterization() { ContextProvider* context_provider = output_surface_->worker_context_provider(); - base::AutoLock context_lock(*context_provider->GetLock()); + ContextProvider::ScopedContextLock scoped_context(context_provider); if (!context_provider->GrContext()) return false; @@ -1655,9 +1653,8 @@ 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; + renderer() && RequestedMSAASampleCount() > 0 && + GetRendererCapabilities().max_msaa_samples >= RequestedMSAASampleCount(); if (settings_.gpu_rasterization_forced) { use_gpu = true; gpu_rasterization_status_ = GpuRasterizationStatus::ON_FORCED; @@ -1740,11 +1737,11 @@ bool LayerTreeHostImpl::SwapBuffers(const LayerTreeHostImpl::FrameData& frame) { CompositorFrameMetadata metadata = MakeCompositorFrameMetadata(); active_tree()->FinishSwapPromises(&metadata); for (auto& latency : metadata.latency_info) { - TRACE_EVENT_FLOW_STEP0( - "input,benchmark", - "LatencyInfo.Flow", - TRACE_ID_DONT_MANGLE(latency.trace_id), - "SwapBuffers"); + TRACE_EVENT_WITH_FLOW1("input,benchmark", + "LatencyInfo.Flow", + TRACE_ID_DONT_MANGLE(latency.trace_id()), + TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, + "step", "SwapBuffers"); // Only add the latency component once for renderer swap, not the browser // swap. if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, @@ -1782,54 +1779,36 @@ void LayerTreeHostImpl::UpdateViewportContainerSizes() { if (!inner_container) return; - // TODO(bokan): This code is currently specific to top controls. It should be - // made general. crbug.com/464814. - if (!TopControlsHeight()) { - inner_container->SetBoundsDelta(gfx::Vector2dF()); - active_tree_->InnerViewportScrollLayer()->SetBoundsDelta(gfx::Vector2dF()); - - if (outer_container) { - outer_container->SetBoundsDelta(gfx::Vector2dF()); - ViewportAnchor anchor(InnerViewportScrollLayer(), - OuterViewportScrollLayer()); - anchor.ResetViewportToAnchoredPosition(); - } - - 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. 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; + float delta_from_top_controls = + top_controls_layout_height - top_controls_manager_->ContentTopOffset(); - // Adjust the outer viewport container as well, since adjusting only the - // inner may cause its bounds to exceed those of the outer, causing scroll - // clamping. We adjust it so it maintains the same aspect ratio as the - // inner viewport. - float aspect_ratio = inner_container->BoundsForScrolling().width() / - inner_container->BoundsForScrolling().height(); - float target_height = outer_container->BoundsForScrolling().width() / - aspect_ratio; - float current_outer_height = outer_container->BoundsForScrolling().height() - - outer_container->bounds_delta().y(); - gfx::Vector2dF delta(0, target_height - current_outer_height); + // Adjust the viewport layers by shrinking/expanding the container to account + // for changes in the size (e.g. top controls) since the last resize from + // Blink. + gfx::Vector2dF amount_to_expand( + 0.f, + delta_from_top_controls); + inner_container->SetBoundsDelta(amount_to_expand); - outer_container->SetBoundsDelta(delta); - active_tree_->InnerViewportScrollLayer()->SetBoundsDelta(delta); + if (outer_container && !outer_container->BoundsForScrolling().IsEmpty()) { + // Adjust the outer viewport container as well, since adjusting only the + // inner may cause its bounds to exceed those of the outer, causing scroll + // clamping. + gfx::Vector2dF amount_to_expand_scaled = gfx::ScaleVector2d( + amount_to_expand, 1.f / active_tree_->min_page_scale_factor()); + outer_container->SetBoundsDelta(amount_to_expand_scaled); + active_tree_->InnerViewportScrollLayer()->SetBoundsDelta( + amount_to_expand_scaled); - anchor.ResetViewportToAnchoredPosition(); + anchor.ResetViewportToAnchoredPosition(); + } } void LayerTreeHostImpl::SynchronouslyInitializeAllTiles() { @@ -1867,12 +1846,11 @@ LayerImpl* LayerTreeHostImpl::CurrentlyScrollingLayer() const { bool LayerTreeHostImpl::IsActivelyScrolling() const { if (!CurrentlyScrollingLayer()) return false; - if (root_layer_scroll_offset_delegate_ && - (CurrentlyScrollingLayer() == InnerViewportScrollLayer() || - CurrentlyScrollingLayer() == OuterViewportScrollLayer())) { - // ScrollDelegate cannot determine current scroll, so assume no. + // On Android WebView root flings are controlled by the application, + // so the compositor does not animate them and can't tell if they + // are actually animating. So assume there are none. + if (settings_.ignore_root_layer_flings && IsCurrentlyScrollingRoot()) return false; - } return did_lock_scrolling_layer_; } @@ -1912,8 +1890,6 @@ void LayerTreeHostImpl::ActivateSyncTree() { if (pending_tree_) { TRACE_EVENT_ASYNC_END0("cc", "PendingTree:waiting", pending_tree_.get()); - active_tree_->SetRootLayerScrollOffsetDelegate(NULL); - active_tree_->PushPersistedState(pending_tree_.get()); // Process any requests in the UI resource queue. The request queue is // given in LayerTreeHost::FinishCommitOnImplThread. This must take place // before the swap. @@ -1937,8 +1913,9 @@ void LayerTreeHostImpl::ActivateSyncTree() { UpdateViewportContainerSizes(); - active_tree_->SetRootLayerScrollOffsetDelegate( - root_layer_scroll_offset_delegate_); + // If we commit to the active tree directly, this is already done during + // commit. + ActivateAnimations(); } else { active_tree_->ProcessUIResourceRequestQueue(); } @@ -1947,7 +1924,6 @@ void LayerTreeHostImpl::ActivateSyncTree() { // won't already account for current bounds_delta values. active_tree_->UpdatePropertyTreesForBoundsDelta(); active_tree_->DidBecomeActive(); - ActivateAnimations(); client_->RenewTreePriority(); // If we have any picture layers, then by activating we also modified tile // priorities. @@ -1959,16 +1935,6 @@ void LayerTreeHostImpl::ActivateSyncTree() { if (!tree_activation_callback_.is_null()) tree_activation_callback_.Run(); - if (debug_state_.continuous_painting) { - const RenderingStats& stats = - rendering_stats_instrumentation_->GetRenderingStats(); - // TODO(hendrikw): This requires a different metric when we commit directly - // to the active tree. See crbug.com/429311. - paint_time_counter_->SavePaintTime( - stats.commit_to_activate_duration.GetLastTimeDelta() + - stats.draw_duration.GetLastTimeDelta()); - } - scoped_ptr<PendingPageScaleAnimation> pending_page_scale_animation = active_tree_->TakePendingPageScaleAnimation(); if (pending_page_scale_animation) { @@ -1978,6 +1944,9 @@ void LayerTreeHostImpl::ActivateSyncTree() { pending_page_scale_animation->scale, pending_page_scale_animation->duration); } + // Activation can change the root scroll offset, so inform the synchronous + // input handler. + UpdateRootLayerStateForSynchronousInputHandler(); } void LayerTreeHostImpl::SetVisible(bool visible) { @@ -1996,11 +1965,9 @@ void LayerTreeHostImpl::SetVisible(bool visible) { else EvictAllUIResources(); - // Call PrepareTiles unconditionally on visibility change since this tab may - // never get another draw or timer tick. When becoming visible we care about - // unblocking the scheduler which might be waiting for activation / ready to - // draw. When becoming invisible we care about evicting tiles immediately. - PrepareTiles(); + // Call PrepareTiles to evict tiles when we become invisible. + if (!visible) + PrepareTiles(); if (!renderer_) return; @@ -2058,18 +2025,18 @@ void LayerTreeHostImpl::CreateAndSetRenderer() { DCHECK(resource_provider_); if (output_surface_->capabilities().delegated_rendering) { - renderer_ = DelegatingRenderer::Create(this, &settings_.renderer_settings, - output_surface_.get(), - resource_provider_.get()); + renderer_ = + DelegatingRenderer::Create(this, &settings_.renderer_settings, + output_surface_, resource_provider_.get()); } else if (output_surface_->context_provider()) { renderer_ = GLRenderer::Create( - this, &settings_.renderer_settings, output_surface_.get(), + this, &settings_.renderer_settings, output_surface_, resource_provider_.get(), texture_mailbox_deleter_.get(), settings_.renderer_settings.highp_threshold_min); } else if (output_surface_->software_device()) { - renderer_ = SoftwareRenderer::Create(this, &settings_.renderer_settings, - output_surface_.get(), - resource_provider_.get()); + renderer_ = + SoftwareRenderer::Create(this, &settings_.renderer_settings, + output_surface_, resource_provider_.get()); } DCHECK(renderer_); @@ -2086,25 +2053,27 @@ void LayerTreeHostImpl::CreateAndSetRenderer() { } void LayerTreeHostImpl::CreateTileManagerResources() { - CreateResourceAndTileTaskWorkerPool(&tile_task_worker_pool_, &resource_pool_, - &staging_resource_pool_); + CreateResourceAndTileTaskWorkerPool(&tile_task_worker_pool_, &resource_pool_); + // TODO(vmpstr): Initialize tile task limit at ctor time. tile_manager_->SetResources( resource_pool_.get(), tile_task_worker_pool_->AsTileTaskRunner(), - IsSynchronousSingleThreaded() ? std::numeric_limits<size_t>::max() - : settings_.scheduled_raster_task_limit); + is_synchronous_single_threaded_ ? std::numeric_limits<size_t>::max() + : settings_.scheduled_raster_task_limit); UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy()); } void LayerTreeHostImpl::CreateResourceAndTileTaskWorkerPool( scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool, - scoped_ptr<ResourcePool>* resource_pool, - scoped_ptr<ResourcePool>* staging_resource_pool) { + scoped_ptr<ResourcePool>* resource_pool) { DCHECK(GetTaskRunner()); + // TODO(vmpstr): Make this a DCHECK (or remove) when crbug.com/419086 is + // resolved. + CHECK(resource_provider_); // 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()) { + if (is_synchronous_single_threaded_) { 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(); @@ -2112,8 +2081,8 @@ void LayerTreeHostImpl::CreateResourceAndTileTaskWorkerPool( ContextProvider* context_provider = output_surface_->context_provider(); if (!context_provider) { - *resource_pool = - ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D); + *resource_pool = ResourcePool::Create(resource_provider_.get(), + GetTaskRunner(), GL_TEXTURE_2D); *tile_task_worker_pool = BitmapTileTaskWorkerPool::Create( GetTaskRunner(), task_graph_runner, resource_provider_.get()); @@ -2121,11 +2090,12 @@ void LayerTreeHostImpl::CreateResourceAndTileTaskWorkerPool( } if (use_gpu_rasterization_) { - *resource_pool = - ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D); + DCHECK(resource_provider_->output_surface()->worker_context_provider()); + + *resource_pool = ResourcePool::Create(resource_provider_.get(), + GetTaskRunner(), GL_TEXTURE_2D); - int msaa_sample_count = - use_msaa_ ? settings_.gpu_rasterization_msaa_sample_count : 0; + int msaa_sample_count = use_msaa_ ? RequestedMSAASampleCount() : 0; *tile_task_worker_pool = GpuTileTaskWorkerPool::Create( GetTaskRunner(), task_graph_runner, context_provider, @@ -2135,59 +2105,38 @@ void LayerTreeHostImpl::CreateResourceAndTileTaskWorkerPool( } DCHECK(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) { - *resource_pool = - ResourcePool::Create(resource_provider_.get(), image_target); - *tile_task_worker_pool = ZeroCopyTileTaskWorkerPool::Create( - GetTaskRunner(), task_graph_runner, resource_provider_.get()); - return; + bool use_zero_copy = settings_.use_zero_copy; + // TODO(reveman): Remove this when mojo supports worker contexts. + // crbug.com/522440 + if (!resource_provider_->output_surface()->worker_context_provider()) { + LOG(ERROR) + << "Forcing zero-copy tile initialization as worker context is missing"; + use_zero_copy = true; } - if (settings_.use_one_copy) { - // 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. - DCHECK(!IsSynchronousSingleThreaded()); - - // We need to create a staging resource pool when using copy rasterizer. - *staging_resource_pool = - ResourcePool::Create(resource_provider_.get(), image_target); + if (use_zero_copy) { *resource_pool = - ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D); - - int max_copy_texture_chromium_size = - context_provider->ContextCapabilities() - .gpu.max_copy_texture_chromium_size; + ResourcePool::Create(resource_provider_.get(), GetTaskRunner()); - *tile_task_worker_pool = OneCopyTileTaskWorkerPool::Create( - GetTaskRunner(), task_graph_runner, context_provider, - resource_provider_.get(), staging_resource_pool_.get(), - max_copy_texture_chromium_size, - settings_.use_persistent_map_for_gpu_memory_buffers); + *tile_task_worker_pool = ZeroCopyTileTaskWorkerPool::Create( + GetTaskRunner(), task_graph_runner, resource_provider_.get(), + settings_.renderer_settings.use_rgba_4444_textures); 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(), + GetTaskRunner(), GL_TEXTURE_2D); - *resource_pool = ResourcePool::Create( - resource_provider_.get(), GL_TEXTURE_2D); + int max_copy_texture_chromium_size = context_provider->ContextCapabilities() + .gpu.max_copy_texture_chromium_size; - *tile_task_worker_pool = PixelBufferTileTaskWorkerPool::Create( - GetTaskRunner(), task_graph_runner_, context_provider, - resource_provider_.get(), - GetMaxTransferBufferUsageBytes(context_provider->ContextCapabilities(), - settings_.renderer_settings.refresh_rate)); + *tile_task_worker_pool = OneCopyTileTaskWorkerPool::Create( + GetTaskRunner(), task_graph_runner, context_provider, + resource_provider_.get(), max_copy_texture_chromium_size, + settings_.use_persistent_map_for_gpu_memory_buffers, + settings_.max_staging_buffer_usage_in_bytes, + settings_.renderer_settings.use_rgba_4444_textures); } void LayerTreeHostImpl::RecordMainFrameTiming( @@ -2214,18 +2163,12 @@ void LayerTreeHostImpl::PostFrameTimingEvents( void LayerTreeHostImpl::CleanUpTileManager() { tile_manager_->FinishTasksAndCleanUp(); resource_pool_ = nullptr; - staging_resource_pool_ = nullptr; tile_task_worker_pool_ = nullptr; single_thread_synchronous_task_graph_runner_ = nullptr; } -bool LayerTreeHostImpl::IsSynchronousSingleThreaded() const { - return !proxy_->HasImplThread() && !settings_.single_thread_proxy_scheduler; -} - -bool LayerTreeHostImpl::InitializeRenderer( - scoped_ptr<OutputSurface> output_surface) { - TRACE_EVENT0("cc", "LayerTreeHostImpl::InitializeRenderer"); +void LayerTreeHostImpl::ReleaseOutputSurface() { + TRACE_EVENT0("cc", "LayerTreeHostImpl::ReleaseOutputSurface"); // Since we will create a new resource provider, we cannot continue to use // the old resources (i.e. render_surfaces and texture IDs). Clear them @@ -2236,8 +2179,20 @@ bool LayerTreeHostImpl::InitializeRenderer( renderer_ = nullptr; CleanUpTileManager(); resource_provider_ = nullptr; - output_surface_ = nullptr; + // Detach from the old output surface and reset |output_surface_| pointer + // as this surface is going to be destroyed independent of if binding the + // new output surface succeeds or not. + if (output_surface_) { + output_surface_->DetachFromClient(); + output_surface_ = nullptr; + } +} + +bool LayerTreeHostImpl::InitializeRenderer(OutputSurface* output_surface) { + TRACE_EVENT0("cc", "LayerTreeHostImpl::InitializeRenderer"); + + ReleaseOutputSurface(); 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 @@ -2245,14 +2200,13 @@ bool LayerTreeHostImpl::InitializeRenderer( return false; } - output_surface_ = output_surface.Pass(); + output_surface_ = output_surface; resource_provider_ = ResourceProvider::Create( - output_surface_.get(), shared_bitmap_manager_, gpu_memory_buffer_manager_, + output_surface_, 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, - settings_.use_persistent_map_for_gpu_memory_buffers); + settings_.use_image_texture_targets); CreateAndSetRenderer(); @@ -2313,18 +2267,8 @@ void LayerTreeHostImpl::SetViewportSize(const gfx::Size& device_viewport_size) { client_->OnCanDrawStateChanged(CanDraw()); SetFullRootLayerDamage(); active_tree_->set_needs_update_draw_properties(); -} - -void LayerTreeHostImpl::SetDeviceScaleFactor(float device_scale_factor) { - if (device_scale_factor == device_scale_factor_) - return; - device_scale_factor_ = device_scale_factor; - - SetFullRootLayerDamage(); -} - -void LayerTreeHostImpl::SetPageScaleOnActiveTree(float page_scale_factor) { - active_tree_->SetPageScaleOnActiveTree(page_scale_factor); + active_tree_->property_trees()->clip_tree.SetViewportClip( + gfx::RectF(gfx::SizeF(device_viewport_size))); } const gfx::Rect LayerTreeHostImpl::ViewportRectForTilePriority() const { @@ -2394,7 +2338,7 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint( // Walk up the hierarchy and look for a scrollable layer. LayerImpl* potentially_scrolling_layer_impl = NULL; - for (; layer_impl; layer_impl = NextScrollLayer(layer_impl)) { + for (; layer_impl; layer_impl = NextLayerInScrollOrder(layer_impl)) { // The content layer can also block attempts to scroll outside the main // thread. ScrollStatus status = @@ -2426,11 +2370,14 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint( // Falling back to the root scroll layer ensures generation of root overscroll // notifications while preventing scroll updates from being unintentionally - // forwarded to the main thread. + // forwarded to the main thread. The inner viewport layer represents the + // viewport during scrolling. if (!potentially_scrolling_layer_impl) - potentially_scrolling_layer_impl = OuterViewportScrollLayer() - ? OuterViewportScrollLayer() - : InnerViewportScrollLayer(); + potentially_scrolling_layer_impl = InnerViewportScrollLayer(); + + // The inner viewport layer represents the viewport. + if (potentially_scrolling_layer_impl == OuterViewportScrollLayer()) + potentially_scrolling_layer_impl = InnerViewportScrollLayer(); return potentially_scrolling_layer_impl; } @@ -2439,7 +2386,7 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint( static bool HasScrollAncestor(LayerImpl* child, LayerImpl* scroll_ancestor) { DCHECK(scroll_ancestor); for (LayerImpl* ancestor = child; ancestor; - ancestor = NextScrollLayer(ancestor)) { + ancestor = NextLayerInScrollOrder(ancestor)) { if (ancestor->scrollable()) return ancestor == scroll_ancestor; } @@ -2455,7 +2402,6 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBeginImpl( top_controls_manager_->ScrollBegin(); active_tree_->SetCurrentlyScrollingLayer(scrolling_layer_impl); - should_bubble_scrolls_ = (type != NON_BUBBLING_GESTURE); wheel_scrolling_ = (type == WHEEL); client_->RenewTreePriority(); UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", false); @@ -2481,7 +2427,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin( ClearCurrentlyScrollingLayer(); gfx::PointF device_viewport_point = - gfx::ScalePoint(viewport_point, device_scale_factor_); + gfx::ScalePoint(viewport_point, active_tree_->device_scale_factor()); LayerImpl* layer_impl = active_tree_->FindLayerThatIsHitByPoint(device_viewport_point); @@ -2521,8 +2467,9 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated( 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()) + layer_impl = NextLayerInScrollOrder(layer_impl)) { + // The inner viewport layer represents the viewport. + if (!layer_impl->scrollable() || layer_impl == OuterViewportScrollLayer()) continue; gfx::ScrollOffset current_offset = layer_impl->CurrentScrollOffset(); @@ -2565,11 +2512,12 @@ gfx::Vector2dF LayerTreeHostImpl::ScrollLayerWithViewportSpaceDelta( gfx::Transform::kSkipInitialization); bool did_invert = layer_impl->screen_space_transform().GetInverse( &inverse_screen_space_transform); - // TODO(shawnsingh): With the advent of impl-side crolling for non-root + // TODO(shawnsingh): With the advent of impl-side scrolling for non-root // layers, we may need to explicitly handle uninvertible transforms here. DCHECK(did_invert); - float scale_from_viewport_to_screen_space = device_scale_factor_; + float scale_from_viewport_to_screen_space = + active_tree_->device_scale_factor(); gfx::PointF screen_space_point = gfx::ScalePoint(viewport_point, scale_from_viewport_to_screen_space); @@ -2638,29 +2586,72 @@ static gfx::Vector2dF ScrollLayerWithLocalDelta( 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); + bool is_direct_manipulation) { + // Events representing direct manipulation of the screen (such as 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, events not representing direct manipulation of the + // screen (such as 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_direct_manipulation) + return ScrollLayerWithViewportSpaceDelta(layer_impl, viewport_point, delta); + float scale_factor = active_tree()->current_page_scale_factor(); + return ScrollLayerWithLocalDelta(layer_impl, delta, scale_factor); +} + +void LayerTreeHostImpl::ApplyScroll(LayerImpl* layer, + ScrollState* scroll_state) { + DCHECK(scroll_state); + gfx::Point viewport_point(scroll_state->start_position_x(), + scroll_state->start_position_y()); + const gfx::Vector2dF delta(scroll_state->delta_x(), scroll_state->delta_y()); + gfx::Vector2dF applied_delta; + // TODO(tdresser): Use a more rational epsilon. See crbug.com/510550 for + // details. + const float kEpsilon = 0.1f; + + if (layer == InnerViewportScrollLayer()) { + bool affect_top_controls = !wheel_scrolling_; + Viewport::ScrollResult result = viewport()->ScrollBy( + delta, viewport_point, scroll_state->is_direct_manipulation(), + affect_top_controls); + applied_delta = result.consumed_delta; + scroll_state->set_caused_scroll( + std::abs(result.content_scrolled_delta.x()) > kEpsilon, + std::abs(result.content_scrolled_delta.y()) > kEpsilon); + scroll_state->ConsumeDelta(applied_delta.x(), applied_delta.y()); + } else { + applied_delta = ScrollLayer(layer, delta, viewport_point, + scroll_state->is_direct_manipulation()); + } + + // If the layer wasn't able to move, try the next one in the hierarchy. + bool scrolled = std::abs(applied_delta.x()) > kEpsilon; + scrolled = scrolled || std::abs(applied_delta.y()) > kEpsilon; + + if (scrolled && layer != InnerViewportScrollLayer()) { + // 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, delta) < + angle_threshold) { + applied_delta = delta; + } else { + // Allow further movement only on an axis perpendicular to the direction + // in which the layer moved. + applied_delta = MathUtil::ProjectVector(delta, applied_delta); + } + scroll_state->set_caused_scroll(std::abs(applied_delta.x()) > kEpsilon, + std::abs(applied_delta.y()) > kEpsilon); + scroll_state->ConsumeDelta(applied_delta.x(), applied_delta.y()); } - return ScrollLayerWithViewportSpaceDelta(layer_impl, - viewport_point, - delta); -} - -static LayerImpl* nextLayerInScrollOrder(LayerImpl* layer) { - if (layer->scroll_parent()) - return layer->scroll_parent(); + if (!scrolled) + return; - return layer->parent(); + scroll_state->set_current_native_scrolling_layer(layer); } InputHandlerScrollResult LayerTreeHostImpl::ScrollBy( @@ -2670,86 +2661,34 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy( if (!CurrentlyScrollingLayer()) return InputHandlerScrollResult(); - gfx::Vector2dF pending_delta = scroll_delta; - gfx::Vector2dF unused_root_delta; - bool did_scroll_x = false; - bool did_scroll_y = false; - bool did_scroll_top_controls = false; - - if (pinch_gesture_active_ && settings().invert_viewport_scroll_order) { - // Scrolls during a pinch gesture should pan the visual viewport, rather - // than a typical bubbling scroll. - viewport()->Pan(pending_delta); - return InputHandlerScrollResult(); - } - - for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); - layer_impl; - layer_impl = nextLayerInScrollOrder(layer_impl)) { + float initial_top_controls_offset = + top_controls_manager_->ControlsTopOffset(); + ScrollState scroll_state( + scroll_delta.x(), scroll_delta.y(), viewport_point.x(), + viewport_point.y(), false /* should_propagate */, + did_lock_scrolling_layer_ /* delta_consumed_for_scroll_sequence */, + !wheel_scrolling_ /* is_direct_manipulation */); + scroll_state.set_current_native_scrolling_layer(CurrentlyScrollingLayer()); + + std::list<LayerImpl*> current_scroll_chain; + for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); layer_impl; + layer_impl = NextLayerInScrollOrder(layer_impl)) { // 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; - - gfx::Vector2dF applied_delta; - if (layer_impl == InnerViewportScrollLayer()) { - bool affect_top_controls = true; - Viewport::ScrollResult result = viewport()->ScrollBy(pending_delta, - viewport_point, - wheel_scrolling_, - affect_top_controls); - 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_); - } - - // 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) { - 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 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) - 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 (!should_bubble_scrolls_ && did_lock_scrolling_layer_) - break; + current_scroll_chain.push_front(layer_impl); } + scroll_state.set_scroll_chain(current_scroll_chain); + scroll_state.DistributeToScrollChainDescendant(); + active_tree_->SetCurrentlyScrollingLayer( + scroll_state.current_native_scrolling_layer()); + did_lock_scrolling_layer_ = scroll_state.delta_consumed_for_scroll_sequence(); + + bool did_scroll_x = scroll_state.caused_scroll_x(); + bool did_scroll_y = scroll_state.caused_scroll_y(); bool did_scroll_content = did_scroll_x || did_scroll_y; if (did_scroll_content) { // If we are scrolling with an active scroll handler, forward latency @@ -2767,13 +2706,32 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy( accumulated_root_overscroll_.set_x(0); if (did_scroll_y) accumulated_root_overscroll_.set_y(0); + gfx::Vector2dF unused_root_delta(scroll_state.delta_x(), + scroll_state.delta_y()); + + // When inner viewport is unscrollable, disable overscrolls. + if (InnerViewportScrollLayer()) { + if (!InnerViewportScrollLayer()->user_scrollable_horizontal()) + unused_root_delta.set_x(0); + if (!InnerViewportScrollLayer()->user_scrollable_vertical()) + unused_root_delta.set_y(0); + } + accumulated_root_overscroll_ += unused_root_delta; + bool did_scroll_top_controls = + initial_top_controls_offset != top_controls_manager_->ControlsTopOffset(); + InputHandlerScrollResult scroll_result; scroll_result.did_scroll = did_scroll_content || did_scroll_top_controls; scroll_result.did_overscroll_root = !unused_root_delta.IsZero(); scroll_result.accumulated_root_overscroll = accumulated_root_overscroll_; scroll_result.unused_scroll_delta = unused_root_delta; + + // Scrolling can change the root scroll offset, so inform the synchronous + // input handler. + UpdateRootLayerStateForSynchronousInputHandler(); + return scroll_result; } @@ -2784,10 +2742,10 @@ bool LayerTreeHostImpl::ScrollVerticallyByPage(const gfx::Point& viewport_point, ScrollDirection direction) { DCHECK(wheel_scrolling_); - for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); - layer_impl; - layer_impl = layer_impl->parent()) { - if (!layer_impl->scrollable()) + for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); layer_impl; + layer_impl = NextLayerInScrollOrder(layer_impl)) { + // The inner viewport layer represents the viewport. + if (!layer_impl->scrollable() || layer_impl == OuterViewportScrollLayer()) continue; if (!layer_impl->HasScrollbar(VERTICAL)) @@ -2819,19 +2777,19 @@ bool LayerTreeHostImpl::ScrollVerticallyByPage(const gfx::Point& viewport_point, return false; } -void LayerTreeHostImpl::SetRootLayerScrollOffsetDelegate( - LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate) { - root_layer_scroll_offset_delegate_ = root_layer_scroll_offset_delegate; - active_tree_->SetRootLayerScrollOffsetDelegate( - root_layer_scroll_offset_delegate_); +void LayerTreeHostImpl::RequestUpdateForSynchronousInputHandler() { + UpdateRootLayerStateForSynchronousInputHandler(); } -void LayerTreeHostImpl::OnRootLayerDelegatedScrollOffsetChanged() { - DCHECK(root_layer_scroll_offset_delegate_); - active_tree_->DistributeRootScrollOffset(); +void LayerTreeHostImpl::SetSynchronousInputHandlerRootScrollOffset( + const gfx::ScrollOffset& root_offset) { + active_tree_->DistributeRootScrollOffset(root_offset); client_->SetNeedsCommitOnImplThread(); - SetNeedsRedraw(); - active_tree_->set_needs_update_draw_properties(); + // After applying the synchronous input handler's scroll offset, tell it what + // we ended up with. + UpdateRootLayerStateForSynchronousInputHandler(); + // No need to SetNeedsRedraw, this is for WebView and every frame has redraw + // requested by the WebView embedder already. } void LayerTreeHostImpl::ClearCurrentlyScrollingLayer() { @@ -2849,17 +2807,6 @@ void LayerTreeHostImpl::ScrollEnd() { InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() { if (!CurrentlyScrollingLayer()) return SCROLL_IGNORED; - - bool currently_scrolling_viewport = - CurrentlyScrollingLayer() == OuterViewportScrollLayer() || - CurrentlyScrollingLayer() == InnerViewportScrollLayer(); - if (!wheel_scrolling_ && !currently_scrolling_viewport) { - // Allow the fling to lock to the first layer that moves after the initial - // fling |ScrollBy()| event, unless we're already scrolling the viewport. - did_lock_scrolling_layer_ = false; - should_bubble_scrolls_ = false; - } - return SCROLL_STARTED; } @@ -2872,16 +2819,15 @@ float LayerTreeHostImpl::DeviceSpaceDistanceToLayer( gfx::Rect layer_impl_bounds(layer_impl->bounds()); gfx::RectF device_viewport_layer_impl_bounds = MathUtil::MapClippedRect( - layer_impl->screen_space_transform(), - layer_impl_bounds); + layer_impl->screen_space_transform(), gfx::RectF(layer_impl_bounds)); return device_viewport_layer_impl_bounds.ManhattanDistanceToPoint( device_viewport_point); } void LayerTreeHostImpl::MouseMoveAt(const gfx::Point& viewport_point) { - gfx::PointF device_viewport_point = gfx::ScalePoint(viewport_point, - device_scale_factor_); + gfx::PointF device_viewport_point = + gfx::ScalePoint(viewport_point, active_tree_->device_scale_factor()); LayerImpl* layer_impl = active_tree_->FindLayerThatIsHitByPoint(device_viewport_point); if (HandleMouseOverScrollbar(layer_impl, device_viewport_point)) @@ -2925,7 +2871,7 @@ void LayerTreeHostImpl::MouseMoveAt(const gfx::Point& viewport_point) { DeviceSpaceDistanceToLayer(device_viewport_point, *it)); animation_controller->DidMouseMoveNear(distance_to_scrollbar / - device_scale_factor_); + active_tree_->device_scale_factor()); } bool LayerTreeHostImpl::HandleMouseOverScrollbar(LayerImpl* layer_impl, @@ -2950,36 +2896,23 @@ void LayerTreeHostImpl::PinchGestureBegin() { pinch_gesture_active_ = true; client_->RenewTreePriority(); pinch_gesture_end_should_clear_scrolling_layer_ = !CurrentlyScrollingLayer(); - if (active_tree_->OuterViewportScrollLayer()) { - active_tree_->SetCurrentlyScrollingLayer( - active_tree_->OuterViewportScrollLayer()); - } else { - active_tree_->SetCurrentlyScrollingLayer( - active_tree_->InnerViewportScrollLayer()); - } + active_tree_->SetCurrentlyScrollingLayer( + active_tree_->InnerViewportScrollLayer()); top_controls_manager_->PinchBegin(); } void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta, const gfx::Point& anchor) { + TRACE_EVENT0("cc", "LayerTreeHostImpl::PinchGestureUpdate"); if (!InnerViewportScrollLayer()) return; - - TRACE_EVENT0("cc", "LayerTreeHostImpl::PinchGestureUpdate"); - - // For a moment the scroll offset ends up being outside of the max range. This - // confuses the delegate so we switch it off till after we're done processing - // the pinch update. - active_tree_->SetRootLayerScrollOffsetDelegate(NULL); - viewport()->PinchUpdate(magnify_delta, anchor); - - active_tree_->SetRootLayerScrollOffsetDelegate( - root_layer_scroll_offset_delegate_); - client_->SetNeedsCommitOnImplThread(); SetNeedsRedraw(); client_->RenewTreePriority(); + // Pinching can change the root scroll offset, so inform the synchronous input + // handler. + UpdateRootLayerStateForSynchronousInputHandler(); } void LayerTreeHostImpl::PinchGestureEnd() { @@ -3056,12 +2989,6 @@ void LayerTreeHostImpl::ScrollViewportBy(gfx::Vector2dF scroll_delta) { InnerViewportScrollLayer()->ScrollBy(unused_delta); } -void LayerTreeHostImpl::AnimateInput(base::TimeTicks monotonic_time) { - DCHECK(proxy_->IsImplThread()); - if (input_handler_client_) - input_handler_client_->Animate(monotonic_time); -} - void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) { if (!page_scale_animation_) return; @@ -3125,20 +3052,26 @@ void LayerTreeHostImpl::AnimateScrollbars(base::TimeTicks monotonic_time) { } void LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time) { - if (!settings_.accelerated_animation_enabled || !active_tree_->root_layer()) + if (!settings_.accelerated_animation_enabled) return; + bool animated = false; if (animation_host_) { if (animation_host_->AnimateLayers(monotonic_time)) - SetNeedsAnimate(); + animated = true; } else { if (animation_registrar_->AnimateLayers(monotonic_time)) - SetNeedsAnimate(); + animated = true; } + + // TODO(ajuma): Only do this if the animations are on the active tree, or if + // they are on the pending tree waiting for some future time to start. + if (animated) + SetNeedsAnimate(); } void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) { - if (!settings_.accelerated_animation_enabled || !active_tree_->root_layer()) + if (!settings_.accelerated_animation_enabled) return; bool has_active_animations = false; @@ -3162,15 +3095,25 @@ void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) { } void LayerTreeHostImpl::ActivateAnimations() { - if (!settings_.accelerated_animation_enabled || !active_tree_->root_layer()) + if (!settings_.accelerated_animation_enabled) return; + bool activated = false; if (animation_host_) { if (animation_host_->ActivateAnimations()) - SetNeedsAnimate(); + activated = true; } else { if (animation_registrar_->ActivateAnimations()) - SetNeedsAnimate(); + activated = true; + } + + if (activated) { + SetNeedsAnimate(); + // Activating an animation changes layer draw properties, such as + // screen_space_transform_is_animating, or changes transforms etc. So when + // we see a new animation get activated, we need to update the draw + // properties on the active tree. + active_tree()->set_needs_update_draw_properties(); } } @@ -3313,8 +3256,6 @@ void LayerTreeHostImpl::SetDebugState( const LayerTreeDebugState& new_debug_state) { if (LayerTreeDebugState::Equal(debug_state_, new_debug_state)) return; - if (debug_state_.continuous_painting != new_debug_state.continuous_painting) - paint_time_counter_->ClearHistory(); debug_state_ = new_debug_state; UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy()); @@ -3447,6 +3388,16 @@ void LayerTreeHostImpl::NotifySwapPromiseMonitorsOfForwardingToMainThread() { (*it)->OnForwardScrollUpdateToMainThreadOnImpl(); } +void LayerTreeHostImpl::UpdateRootLayerStateForSynchronousInputHandler() { + if (!input_handler_client_) + return; + input_handler_client_->UpdateRootLayerStateForSynchronousInputHandler( + active_tree_->TotalScrollOffset(), active_tree_->TotalMaxScrollOffset(), + active_tree_->ScrollableSize(), active_tree_->current_page_scale_factor(), + active_tree_->min_page_scale_factor(), + active_tree_->max_page_scale_factor()); +} + void LayerTreeHostImpl::ScrollAnimationCreate( LayerImpl* layer_impl, const gfx::ScrollOffset& target_offset, @@ -3566,6 +3517,18 @@ void LayerTreeHostImpl::SetTreeLayerScrollOffsetMutated( layer->OnScrollOffsetAnimated(scroll_offset); } +void LayerTreeHostImpl::TreeLayerTransformIsPotentiallyAnimatingChanged( + int layer_id, + LayerTreeImpl* tree, + bool is_animating) { + if (!tree) + return; + + LayerAnimationValueObserver* layer = tree->LayerById(layer_id); + if (layer) + layer->OnTransformIsPotentiallyAnimatingChanged(is_animating); +} + void LayerTreeHostImpl::SetLayerFilterMutated(int layer_id, LayerTreeType tree_type, const FilterOperations& filters) { @@ -3612,6 +3575,19 @@ void LayerTreeHostImpl::SetLayerScrollOffsetMutated( } } +void LayerTreeHostImpl::LayerTransformIsPotentiallyAnimatingChanged( + int layer_id, + LayerTreeType tree_type, + bool is_animating) { + if (tree_type == LayerTreeType::ACTIVE) { + TreeLayerTransformIsPotentiallyAnimatingChanged(layer_id, active_tree(), + is_animating); + } else { + TreeLayerTransformIsPotentiallyAnimatingChanged(layer_id, pending_tree(), + is_animating); + } +} + void LayerTreeHostImpl::ScrollOffsetAnimationFinished() { ScrollEnd(); } diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h index f66f5b1de83..f2d5dfaa305 100644 --- a/chromium/cc/trees/layer_tree_host_impl.h +++ b/chromium/cc/trees/layer_tree_host_impl.h @@ -21,7 +21,6 @@ #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" #include "cc/input/top_controls_manager_client.h" #include "cc/layers/layer_lists.h" #include "cc/layers/render_pass_sink.h" @@ -60,7 +59,6 @@ class LayerImpl; class LayerTreeImpl; class MemoryHistory; class PageScaleAnimation; -class PaintTimeCounter; class PictureLayerImpl; class RasterTilePriorityQueue; class TileTaskWorkerPool; @@ -168,14 +166,15 @@ class CC_EXPORT LayerTreeHostImpl InputHandler::ScrollStatus ScrollAnimated( const gfx::Point& viewport_point, const gfx::Vector2dF& scroll_delta) override; + void ApplyScroll(LayerImpl* layer, ScrollState* scroll_state); InputHandlerScrollResult ScrollBy( const gfx::Point& viewport_point, const gfx::Vector2dF& scroll_delta) override; bool ScrollVerticallyByPage(const gfx::Point& viewport_point, ScrollDirection direction) override; - void SetRootLayerScrollOffsetDelegate( - LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate) override; - void OnRootLayerDelegatedScrollOffsetChanged() override; + void RequestUpdateForSynchronousInputHandler() override; + void SetSynchronousInputHandlerRootScrollOffset( + const gfx::ScrollOffset& root_offset) override; void ScrollEnd() override; InputHandler::ScrollStatus FlingScrollBegin() override; void MouseMoveAt(const gfx::Point& viewport_point) override; @@ -188,8 +187,10 @@ class CC_EXPORT LayerTreeHostImpl float page_scale, base::TimeDelta duration); void SetNeedsAnimateInput() override; - bool IsCurrentlyScrollingLayerAt(const gfx::Point& viewport_point, - InputHandler::ScrollInputType type) override; + bool IsCurrentlyScrollingRoot() const override; + bool IsCurrentlyScrollingLayerAt( + const gfx::Point& viewport_point, + InputHandler::ScrollInputType type) const override; bool HaveWheelEventHandlersAt(const gfx::Point& viewport_point) override; bool DoTouchEventsBlockScrollAt(const gfx::Point& viewport_port) override; scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor( @@ -226,7 +227,7 @@ class CC_EXPORT LayerTreeHostImpl virtual void BeginMainFrameAborted(CommitEarlyOutReason reason); virtual void BeginCommit(); virtual void CommitComplete(); - virtual void Animate(base::TimeTicks monotonic_time); + virtual void Animate(); virtual void UpdateAnimationState(bool start_ready_animations); void ActivateAnimations(); void MainThreadHasStoppedFlinging(); @@ -245,6 +246,9 @@ class CC_EXPORT LayerTreeHostImpl void SetTreeLayerScrollOffsetMutated(int layer_id, LayerTreeImpl* tree, const gfx::ScrollOffset& scroll_offset); + void TreeLayerTransformIsPotentiallyAnimatingChanged(int layer_id, + LayerTreeImpl* tree, + bool is_animating); // LayerTreeMutatorsClient implementation. bool IsLayerInTree(int layer_id, LayerTreeType tree_type) const override; @@ -262,6 +266,9 @@ class CC_EXPORT LayerTreeHostImpl int layer_id, LayerTreeType tree_type, const gfx::ScrollOffset& scroll_offset) override; + void LayerTransformIsPotentiallyAnimatingChanged(int layer_id, + LayerTreeType tree_type, + bool is_animating) override; void ScrollOffsetAnimationFinished() override; gfx::ScrollOffset GetScrollOffsetForAnimation(int layer_id) const override; @@ -353,13 +360,15 @@ class CC_EXPORT LayerTreeHostImpl // Implementation. int id() const { return id_; } bool CanDraw() const; - OutputSurface* output_surface() const { return output_surface_.get(); } + OutputSurface* output_surface() const { return output_surface_; } + void ReleaseOutputSurface(); std::string LayerTreeAsJson() const; void FinishAllRendering(); + int RequestedMSAASampleCount() const; - virtual bool InitializeRenderer(scoped_ptr<OutputSurface> output_surface); + virtual bool InitializeRenderer(OutputSurface* output_surface); TileManager* tile_manager() { return tile_manager_.get(); } void SetHasGpuRasterizationTrigger(bool flag) { @@ -426,8 +435,6 @@ class CC_EXPORT LayerTreeHostImpl virtual void SetVisible(bool visible); bool visible() const { return visible_; } - bool AnimationsAreVisible() { return visible() && CanDraw(); } - void SetNeedsCommit() { client_->SetNeedsCommitOnImplThread(); } void SetNeedsAnimate(); void SetNeedsRedraw(); @@ -439,11 +446,6 @@ class CC_EXPORT LayerTreeHostImpl void SetViewportSize(const gfx::Size& device_viewport_size); gfx::Size device_viewport_size() const { return device_viewport_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(); @@ -455,9 +457,6 @@ class CC_EXPORT LayerTreeHostImpl FrameRateCounter* fps_counter() { return fps_counter_.get(); } - PaintTimeCounter* paint_time_counter() { - return paint_time_counter_.get(); - } MemoryHistory* memory_history() { return memory_history_.get(); } @@ -552,8 +551,7 @@ class CC_EXPORT LayerTreeHostImpl virtual void CreateResourceAndTileTaskWorkerPool( scoped_ptr<TileTaskWorkerPool>* tile_task_worker_pool, - scoped_ptr<ResourcePool>* resource_pool, - scoped_ptr<ResourcePool>* staging_resource_pool); + scoped_ptr<ResourcePool>* resource_pool); bool prepare_tiles_needed() const { return tile_priorities_dirty_; } @@ -564,7 +562,7 @@ class CC_EXPORT LayerTreeHostImpl gfx::Vector2dF ScrollLayer(LayerImpl* layer_impl, const gfx::Vector2dF& delta, const gfx::Point& viewport_point, - bool is_wheel_scroll); + bool is_direct_manipulation); // Record main frame timing information. // |start_of_main_frame_args| is the BeginFrameArgs of the beginning of the @@ -624,8 +622,6 @@ class CC_EXPORT LayerTreeHostImpl void UpdateGpuRasterizationStatus(); - bool IsSynchronousSingleThreaded() const; - Viewport* viewport() { return viewport_.get(); } // Scroll by preferring to move the outer viewport first, only moving the @@ -639,7 +635,6 @@ class CC_EXPORT LayerTreeHostImpl LayerImpl* scrolling_layer_impl, InputHandler::ScrollInputType type); - void AnimateInput(base::TimeTicks monotonic_time); void AnimatePageScale(base::TimeTicks monotonic_time); void AnimateScrollbars(base::TimeTicks monotonic_time); void AnimateTopControls(base::TimeTicks monotonic_time); @@ -676,6 +671,8 @@ class CC_EXPORT LayerTreeHostImpl void NotifySwapPromiseMonitorsOfSetNeedsRedraw(); void NotifySwapPromiseMonitorsOfForwardingToMainThread(); + void UpdateRootLayerStateForSynchronousInputHandler(); + void ScrollAnimationCreate(LayerImpl* layer_impl, const gfx::ScrollOffset& target_offset, const gfx::ScrollOffset& current_offset); @@ -697,7 +694,7 @@ class CC_EXPORT LayerTreeHostImpl // request queue. std::set<UIResourceId> evicted_ui_resources_; - scoped_ptr<OutputSurface> output_surface_; + OutputSurface* output_surface_; scoped_ptr<ResourceProvider> resource_provider_; bool content_is_suitable_for_gpu_rasterization_; @@ -708,7 +705,6 @@ class CC_EXPORT LayerTreeHostImpl 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_; GlobalStateThatImpactsTilePriority global_tile_state_; @@ -726,7 +722,6 @@ class CC_EXPORT LayerTreeHostImpl InputHandlerClient* input_handler_client_; bool did_lock_scrolling_layer_; - bool should_bubble_scrolls_; bool wheel_scrolling_; bool scroll_affects_scroll_handler_; int scroll_layer_id_when_mouse_over_scrollbar_; @@ -738,15 +733,12 @@ class CC_EXPORT LayerTreeHostImpl bool tile_priorities_dirty_; - // The optional delegate for the root layer scroll offset. - LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate_; - LayerScrollOffsetDelegate::AnimationCallback root_layer_animation_callback_; - const LayerTreeSettings settings_; LayerTreeDebugState debug_state_; bool visible_; ManagedMemoryPolicy cached_managed_memory_policy_; + const bool is_synchronous_single_threaded_; scoped_ptr<TileManager> tile_manager_; gfx::Vector2dF accumulated_root_overscroll_; @@ -759,7 +751,6 @@ class CC_EXPORT LayerTreeHostImpl scoped_ptr<PageScaleAnimation> page_scale_animation_; scoped_ptr<FrameRateCounter> fps_counter_; - scoped_ptr<PaintTimeCounter> paint_time_counter_; scoped_ptr<MemoryHistory> memory_history_; scoped_ptr<DebugRectHistory> debug_rect_history_; @@ -775,10 +766,6 @@ class CC_EXPORT LayerTreeHostImpl // overridden. gfx::Size device_viewport_size_; - // Conversion factor from CSS pixels to physical pixels when - // pageScaleFactor=1. - float device_scale_factor_; - // 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 diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc index d20e603fd0c..3d47528b9bc 100644 --- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc @@ -14,6 +14,7 @@ #include "base/location.h" #include "base/thread_task_runner_handle.h" #include "cc/animation/scrollbar_animation_controller_thinning.h" +#include "cc/animation/transform_operations.h" #include "cc/base/math_util.h" #include "cc/input/page_scale_animation.h" #include "cc/input/top_controls_manager.h" @@ -42,18 +43,17 @@ #include "cc/quads/tile_draw_quad.h" #include "cc/test/animation_test_common.h" #include "cc/test/begin_frame_args_test.h" +#include "cc/test/fake_display_list_raster_source.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_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" @@ -101,8 +101,8 @@ class LayerTreeHostImplTest : public testing::Test, LayerTreeSettings settings; settings.minimum_occlusion_tracking_size = gfx::Size(); settings.renderer_settings.texture_id_allocation_chunk_size = 1; - settings.report_overscroll_only_for_scrollable_axes = true; settings.gpu_rasterization_enabled = true; + settings.verify_property_trees = true; return settings; } @@ -169,11 +169,15 @@ class LayerTreeHostImplTest : public testing::Test, settings, this, &proxy_, &stats_instrumentation_, &shared_bitmap_manager_, &gpu_memory_buffer_manager_, &task_graph_runner_, 0); - bool init = host_impl_->InitializeRenderer(output_surface.Pass()); + output_surface_ = output_surface.Pass(); + bool init = host_impl_->InitializeRenderer(output_surface_.get()); host_impl_->SetViewportSize(gfx::Size(10, 10)); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); // Set the BeginFrameArgs so that methods which use it are able to. - host_impl_->WillBeginImplFrame( - CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); + host_impl_->WillBeginImplFrame(CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, + base::TimeTicks() + base::TimeDelta::FromMilliseconds(1))); + host_impl_->DidFinishImplFrame(); return init; } @@ -299,6 +303,7 @@ class LayerTreeHostImplTest : public testing::Test, LayerImpl* SetupScrollAndContentsLayers(const gfx::Size& content_size) { LayerImpl* scroll_layer = CreateScrollAndContentsLayers( host_impl_->active_tree(), content_size); + host_impl_->active_tree()->BuildPropertyTreesForTesting(); host_impl_->active_tree()->DidBecomeActive(); return scroll_layer; } @@ -331,7 +336,6 @@ class LayerTreeHostImplTest : public testing::Test, return content_layer; } - // TODO(wjmaclean) Add clip-layer pointer to parameters. scoped_ptr<LayerImpl> CreateScrollableLayer(int id, const gfx::Size& size, LayerImpl* clip_layer) { @@ -348,11 +352,23 @@ class LayerTreeHostImplTest : public testing::Test, void DrawFrame() { LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); } + void RebuildPropertyTrees() { + host_impl_->active_tree()->property_trees()->needs_rebuild = true; + host_impl_->active_tree()->BuildPropertyTreesForTesting(); + } + + DrawResult PrepareToDrawFrame(LayerTreeHostImpl::FrameData* frame) { + // We need to build property trees here before drawing the frame as they are + // not built on the impl thread. + RebuildPropertyTrees(); + return host_impl_->PrepareToDraw(frame); + } + void pinch_zoom_pan_viewport_forces_commit_redraw(float device_scale_factor); void pinch_zoom_pan_viewport_test(float device_scale_factor); void pinch_zoom_pan_viewport_and_scroll_test(float device_scale_factor); @@ -408,7 +424,7 @@ class LayerTreeHostImplTest : public testing::Test, void DrawOneFrame() { LayerTreeHostImpl::FrameData frame_data; - host_impl_->PrepareToDraw(&frame_data); + PrepareToDrawFrame(&frame_data); host_impl_->DidDrawAllLayers(frame_data); } @@ -419,6 +435,7 @@ class LayerTreeHostImplTest : public testing::Test, TestSharedBitmapManager shared_bitmap_manager_; TestGpuMemoryBufferManager gpu_memory_buffer_manager_; TestTaskGraphRunner task_graph_runner_; + scoped_ptr<OutputSurface> output_surface_; scoped_ptr<LayerTreeHostImpl> host_impl_; FakeRenderingStatsInstrumentation stats_instrumentation_; bool on_can_draw_state_changed_called_; @@ -655,6 +672,7 @@ TEST_F(LayerTreeHostImplTest, ScrollBlocksOnTouchEventHandlers) { child_layer->SetPosition(gfx::PointF(0, 20)); child_layer->SetBounds(gfx::Size(50, 50)); scroll->AddChild(child_layer.Pass()); + RebuildPropertyTrees(); } // Touch handler regions determine whether touch events block scroll. @@ -737,6 +755,7 @@ TEST_F(LayerTreeHostImplTest, ScrollBlocksOnLayerTopology) { scrollable_child_1->SetHaveScrollEventHandlers(true); scrollable_child_clip_1->AddChild(scrollable_child_1.Pass()); root_child->AddChild(scrollable_child_clip_1.Pass()); + RebuildPropertyTrees(); } LayerImpl* child2 = 0; @@ -751,6 +770,7 @@ TEST_F(LayerTreeHostImplTest, ScrollBlocksOnLayerTopology) { scrollable_child_2->SetHaveScrollEventHandlers(true); scrollable_child_clip_2->AddChild(scrollable_child_2.Pass()); root_child->AddChild(scrollable_child_clip_2.Pass()); + RebuildPropertyTrees(); } // Scroll-blocks-on on a layer affects scrolls that hit that layer. @@ -1052,22 +1072,118 @@ TEST_F(LayerTreeHostImplTest, ScrollWithUserUnscrollableLayers) { host_impl_->ScrollBy(scroll_position, scroll_delta); host_impl_->ScrollEnd(); - EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 0), scroll_layer->CurrentScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset()); overflow->set_user_scrollable_vertical(false); 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(0, 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->CurrentScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset()); } +TEST_F(LayerTreeHostImplTest, AnimationSchedulingPendingTree) { + host_impl_->SetViewportSize(gfx::Size(50, 50)); + + host_impl_->CreatePendingTree(); + host_impl_->pending_tree()->SetRootLayer( + LayerImpl::Create(host_impl_->pending_tree(), 1)); + LayerImpl* root = host_impl_->pending_tree()->root_layer(); + root->SetBounds(gfx::Size(50, 50)); + root->SetHasRenderSurface(true); + + root->AddChild(LayerImpl::Create(host_impl_->pending_tree(), 2)); + LayerImpl* child = root->children()[0]; + child->SetBounds(gfx::Size(10, 10)); + child->draw_properties().visible_layer_rect = gfx::Rect(10, 10); + child->SetDrawsContent(true); + AddAnimatedTransformToLayer(child, 10.0, 3, 0); + + EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_redraw_); + EXPECT_FALSE(did_request_commit_); + + host_impl_->Animate(); + + // An animation exists on the pending layer. Doing Animate() requests another + // frame. + // In reality, animations without has_set_start_time() == true do not need to + // be continuously ticked on the pending tree, so it should not request + // another animation frame here. But we currently do so blindly if any + // animation exists. + EXPECT_TRUE(did_request_animate_); + // The pending tree with an animation does not need to draw after animating. + EXPECT_FALSE(did_request_redraw_); + EXPECT_FALSE(did_request_commit_); + + did_request_animate_ = false; + did_request_redraw_ = false; + did_request_commit_ = false; + + host_impl_->ActivateSyncTree(); + + // When the animation activates, we should request another animation frame + // to keep the animation moving. + EXPECT_TRUE(did_request_animate_); + // On activation we don't need to request a redraw for the animation, + // activating will draw on its own when it's ready. + EXPECT_FALSE(did_request_redraw_); + EXPECT_FALSE(did_request_commit_); +} + +TEST_F(LayerTreeHostImplTest, AnimationSchedulingActiveTree) { + host_impl_->SetViewportSize(gfx::Size(50, 50)); + + host_impl_->active_tree()->SetRootLayer( + LayerImpl::Create(host_impl_->active_tree(), 1)); + LayerImpl* root = host_impl_->active_tree()->root_layer(); + root->SetBounds(gfx::Size(50, 50)); + root->SetHasRenderSurface(true); + + root->AddChild(LayerImpl::Create(host_impl_->active_tree(), 2)); + LayerImpl* child = root->children()[0]; + child->SetBounds(gfx::Size(10, 10)); + child->draw_properties().visible_layer_rect = gfx::Rect(10, 10); + child->SetDrawsContent(true); + + // Add a translate from 6,7 to 8,9. + TransformOperations start; + start.AppendTranslate(6.f, 7.f, 0.f); + TransformOperations end; + end.AppendTranslate(8.f, 9.f, 0.f); + AddAnimatedTransformToLayer(child, 4.0, start, end); + + base::TimeTicks now = base::TimeTicks::Now(); + host_impl_->WillBeginImplFrame( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now)); + + EXPECT_FALSE(did_request_animate_); + EXPECT_FALSE(did_request_redraw_); + EXPECT_FALSE(did_request_commit_); + + host_impl_->ActivateAnimations(); + did_request_animate_ = false; + did_request_redraw_ = false; + did_request_commit_ = false; + + host_impl_->Animate(); + + // An animation exists on the active layer. Doing Animate() requests another + // frame after the current one. + EXPECT_TRUE(did_request_animate_); + // TODO(danakj): We also need to draw in the current frame if something + // animated, but this is currently handled by + // SchedulerStateMachine::WillAnimate. + EXPECT_FALSE(did_request_redraw_); + EXPECT_FALSE(did_request_commit_); +} + TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); @@ -1084,7 +1200,7 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { { host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); - host_impl_->SetPageScaleOnActiveTree(page_scale_factor); + host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); scroll_layer->SetScrollDelta(gfx::Vector2d()); float page_scale_delta = 2.f; @@ -1112,7 +1228,7 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { { host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); - host_impl_->SetPageScaleOnActiveTree(page_scale_factor); + host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); scroll_layer->SetScrollDelta(gfx::Vector2d()); float page_scale_delta = 2.f; @@ -1136,11 +1252,11 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { } } -TEST_F(LayerTreeHostImplTest, ScrollDuringPinchScrollsInnerViewport) { +TEST_F(LayerTreeHostImplTest, ViewportScrollOrder) { LayerTreeSettings settings = DefaultSettings(); - settings.invert_viewport_scroll_order = true; CreateHostImpl(settings, CreateOutputSurface()); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.25f, 4.f); const gfx::Size content_size(1000, 1000); const gfx::Size viewport_size(500, 500); @@ -1153,19 +1269,102 @@ TEST_F(LayerTreeHostImplTest, ScrollDuringPinchScrollsInnerViewport) { gfx::Vector2dF(500, 500), outer_scroll_layer->MaxScrollOffset()); + RebuildPropertyTrees(); host_impl_->ScrollBegin(gfx::Point(250, 250), InputHandler::GESTURE); host_impl_->PinchGestureBegin(); - host_impl_->PinchGestureUpdate(2, gfx::Point(250, 250)); - host_impl_->ScrollBy(gfx::Point(250, 250), gfx::Vector2dF(10.f, 10.f)); + host_impl_->PinchGestureUpdate(2.f, gfx::Point(0, 0)); host_impl_->PinchGestureEnd(); host_impl_->ScrollEnd(); + // Sanity check - we're zoomed in, starting from the origin. + EXPECT_VECTOR_EQ( + gfx::Vector2dF(0, 0), + outer_scroll_layer->CurrentScrollOffset()); + EXPECT_VECTOR_EQ( + gfx::Vector2dF(0, 0), + inner_scroll_layer->CurrentScrollOffset()); + + // Scroll down - only the inner viewport should scroll. + host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::GESTURE); + host_impl_->ScrollBy(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)); + host_impl_->ScrollEnd(); + + EXPECT_VECTOR_EQ( + gfx::Vector2dF(50, 50), + inner_scroll_layer->CurrentScrollOffset()); + EXPECT_VECTOR_EQ( + gfx::Vector2dF(0, 0), + outer_scroll_layer->CurrentScrollOffset()); + + // Scroll down - outer viewport should start scrolling after the inner is at + // its maximum. + host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::GESTURE); + host_impl_->ScrollBy(gfx::Point(0, 0), gfx::Vector2dF(1000.f, 1000.f)); + host_impl_->ScrollEnd(); + + EXPECT_VECTOR_EQ( + gfx::Vector2dF(250, 250), + inner_scroll_layer->CurrentScrollOffset()); + EXPECT_VECTOR_EQ( + gfx::Vector2dF(300, 300), + outer_scroll_layer->CurrentScrollOffset()); +} + +// Tests that scrolls during a pinch gesture (i.e. "two-finger" scrolls) work +// as expected. That is, scrolling during a pinch should bubble from the inner +// to the outer viewport. +TEST_F(LayerTreeHostImplTest, ScrollDuringPinchGesture) { + LayerTreeSettings settings = DefaultSettings(); + CreateHostImpl(settings, + CreateOutputSurface()); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); + + const gfx::Size content_size(1000, 1000); + const gfx::Size viewport_size(500, 500); + CreateBasicVirtualViewportLayers(viewport_size, content_size); + + LayerImpl* outer_scroll_layer = host_impl_->OuterViewportScrollLayer(); + LayerImpl* inner_scroll_layer = host_impl_->InnerViewportScrollLayer(); + + EXPECT_VECTOR_EQ( + gfx::Vector2dF(500, 500), + outer_scroll_layer->MaxScrollOffset()); + + RebuildPropertyTrees(); + host_impl_->ScrollBegin(gfx::Point(250, 250), InputHandler::GESTURE); + host_impl_->PinchGestureBegin(); + + host_impl_->PinchGestureUpdate(2, gfx::Point(250, 250)); + EXPECT_VECTOR_EQ( + gfx::Vector2dF(0, 0), + outer_scroll_layer->CurrentScrollOffset()); + EXPECT_VECTOR_EQ( + gfx::Vector2dF(125, 125), + inner_scroll_layer->CurrentScrollOffset()); + + // Needed so that the pinch is accounted for in draw properties. + DrawFrame(); + + host_impl_->ScrollBy(gfx::Point(250, 250), gfx::Vector2dF(10.f, 10.f)); EXPECT_VECTOR_EQ( gfx::Vector2dF(0, 0), outer_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ( gfx::Vector2dF(130, 130), inner_scroll_layer->CurrentScrollOffset()); + + DrawFrame(); + + host_impl_->ScrollBy(gfx::Point(250, 250), gfx::Vector2dF(400.f, 400.f)); + EXPECT_VECTOR_EQ( + gfx::Vector2dF(80, 80), + outer_scroll_layer->CurrentScrollOffset()); + EXPECT_VECTOR_EQ( + gfx::Vector2dF(250, 250), + inner_scroll_layer->CurrentScrollOffset()); + + host_impl_->PinchGestureEnd(); + host_impl_->ScrollEnd(); } // Tests the "snapping" of pinch-zoom gestures to the screen edge. That is, when @@ -1173,9 +1372,9 @@ TEST_F(LayerTreeHostImplTest, ScrollDuringPinchScrollsInnerViewport) { // should assume the user means to scroll into the edge of the screen. TEST_F(LayerTreeHostImplTest, PinchZoomSnapsToScreenEdge) { LayerTreeSettings settings = DefaultSettings(); - settings.invert_viewport_scroll_order = true; CreateHostImpl(settings, CreateOutputSurface()); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); const gfx::Size content_size(1000, 1000); const gfx::Size viewport_size(500, 500); @@ -1187,6 +1386,7 @@ TEST_F(LayerTreeHostImplTest, PinchZoomSnapsToScreenEdge) { // Pinch in within the margins. The scroll should stay exactly locked to the // bottom and right. + RebuildPropertyTrees(); host_impl_->ScrollBegin(anchor, InputHandler::GESTURE); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, anchor); @@ -1264,11 +1464,12 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoomWheelBubbleBetweenViewports) { // Zoom into the page by a 2X factor float min_page_scale = 1.f, max_page_scale = 4.f; float page_scale_factor = 2.f; + RebuildPropertyTrees(); host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); - host_impl_->SetPageScaleOnActiveTree(page_scale_factor); + host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); - // Scroll by a small amount, there should be no bubbling up to the inner + // Scroll by a small amount, there should be no bubbling to the outer // viewport. host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL); host_impl_->ScrollBy(gfx::Point(0, 0), gfx::Vector2dF(10.f, 20.f)); @@ -1276,28 +1477,28 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoomWheelBubbleBetweenViewports) { EXPECT_VECTOR_EQ( gfx::Vector2dF(5, 10), - outer_scroll_layer->CurrentScrollOffset()); + inner_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ( gfx::Vector2dF(), - inner_scroll_layer->CurrentScrollOffset()); + outer_scroll_layer->CurrentScrollOffset()); - // Scroll by the outer viewport's max scroll extent, there the remainder - // should bubble up to the inner viewport. + // Scroll by the inner viewport's max scroll extent, the remainder + // should bubble up to the outer viewport. host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL); - host_impl_->ScrollBy(gfx::Point(0, 0), gfx::Vector2dF(200.f, 200.f)); + host_impl_->ScrollBy(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)); host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ( - gfx::Vector2dF(100, 100), - outer_scroll_layer->CurrentScrollOffset()); + gfx::Vector2dF(50, 50), + inner_scroll_layer->CurrentScrollOffset()); EXPECT_VECTOR_EQ( gfx::Vector2dF(5, 10), - inner_scroll_layer->CurrentScrollOffset()); + outer_scroll_layer->CurrentScrollOffset()); - // Scroll by the inner viewport's max scroll extent, it should all go to the - // inner viewport. + // Scroll by the outer viewport's max scroll extent, it should all go to the + // outer viewport. host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL); - host_impl_->ScrollBy(gfx::Point(0, 0), gfx::Vector2dF(90.f, 80.f)); + host_impl_->ScrollBy(gfx::Point(0, 0), gfx::Vector2dF(190.f, 180.f)); host_impl_->ScrollEnd(); EXPECT_VECTOR_EQ( @@ -1310,7 +1511,8 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoomWheelBubbleBetweenViewports) { TEST_F(LayerTreeHostImplTest, ScrollWithSwapPromises) { ui::LatencyInfo latency_info; - latency_info.trace_id = 1234; + latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, + 1234); scoped_ptr<SwapPromise> swap_promise( new LatencyInfoSwapPromise(latency_info)); @@ -1323,19 +1525,18 @@ TEST_F(LayerTreeHostImplTest, ScrollWithSwapPromises) { scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); EXPECT_EQ(1u, scroll_info->swap_promises.size()); - EXPECT_EQ(latency_info.trace_id, scroll_info->swap_promises[0]->TraceId()); + EXPECT_EQ(latency_info.trace_id(), scroll_info->swap_promises[0]->TraceId()); } -// Test that scrolls targeting a layer with a non-null scroll_parent() bubble -// up to the scroll_parent, rather than the stacking parent. -TEST_F(LayerTreeHostImplTest, ScrollBubblesToScrollParent) { +// Test that scrolls targeting a layer with a non-null scroll_parent() don't +// bubble up. +TEST_F(LayerTreeHostImplTest, ScrollDoesntBubble) { LayerImpl* viewport_scroll = SetupScrollAndContentsLayers(gfx::Size(100, 100)); host_impl_->SetViewportSize(gfx::Size(50, 50)); // Set up two scrolling children of the root, one of which is a scroll parent - // to the other. Scrolls bubbling from the child should bubble to the parent, - // not the viewport. + // to the other. Scrolls shouldn't bubbling from the child. LayerImpl *parent; LayerImpl *child; LayerImpl *child_clip; @@ -1361,20 +1562,23 @@ TEST_F(LayerTreeHostImplTest, ScrollBubblesToScrollParent) { viewport_scroll->AddChild(scroll_child_clip.Pass()); child_clip->SetScrollParent(parent); + scoped_ptr<std::set<LayerImpl*>> scroll_children(new std::set<LayerImpl*>); + scroll_children->insert(child_clip); + parent->SetScrollChildren(scroll_children.release()); DrawFrame(); { host_impl_->ScrollBegin(gfx::Point(21, 21), InputHandler::GESTURE); host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(5, 5)); - host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(2, 1)); + host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(100, 100)); host_impl_->ScrollEnd(); // The child should be fully scrolled by the first ScrollBy. EXPECT_VECTOR_EQ(gfx::Vector2dF(5, 5), child->CurrentScrollOffset()); - // The scroll_parent should receive the bubbled up second ScrollBy. - EXPECT_VECTOR_EQ(gfx::Vector2dF(2, 1), parent->CurrentScrollOffset()); + // The scroll_parent shouldn't receive the second ScrollBy. + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 0), parent->CurrentScrollOffset()); // The viewport shouldn't have been scrolled at all. EXPECT_VECTOR_EQ( @@ -1389,14 +1593,16 @@ TEST_F(LayerTreeHostImplTest, ScrollBubblesToScrollParent) { host_impl_->ScrollBegin(gfx::Point(21, 21), InputHandler::GESTURE); host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(3, 4)); host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(2, 1)); + host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(2, 1)); + host_impl_->ScrollBy(gfx::Point(21, 21), gfx::Vector2d(2, 1)); host_impl_->ScrollEnd(); - // The first ScrollBy should scroll the parent to its extent. + // The ScrollBy's should scroll the parent to its extent. EXPECT_VECTOR_EQ(gfx::Vector2dF(5, 5), parent->CurrentScrollOffset()); - // The viewport should now be next in bubbling order. + // The viewport shouldn't receive any scroll delta. EXPECT_VECTOR_EQ( - gfx::Vector2dF(2, 1), + gfx::Vector2dF(0, 0), host_impl_->InnerViewportScrollLayer()->CurrentScrollOffset()); EXPECT_VECTOR_EQ( gfx::Vector2dF(0, 0), @@ -1534,6 +1740,10 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2.f, gfx::Point(0, 0)); host_impl_->PinchGestureUpdate(1.f, gfx::Point(0, 0)); + + // Needed so layer transform includes page scale. + DrawFrame(); + host_impl_->ScrollBy(gfx::Point(0, 0), gfx::Vector2d(10, 10)); host_impl_->PinchGestureUpdate(1.f, gfx::Point(10, 10)); host_impl_->PinchGestureEnd(); @@ -1543,7 +1753,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) { host_impl_->ProcessScrollDeltas(); EXPECT_EQ(scroll_info->page_scale_delta, 2.f); EXPECT_TRUE(ScrollInfoContains(*scroll_info, scroll_layer->id(), - gfx::Vector2d(20, 20))); + gfx::Vector2d(10, 10))); } } @@ -1563,6 +1773,9 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { base::TimeTicks halfway_through_animation = start_time + duration / 2; base::TimeTicks end_time = start_time + duration; + BeginFrameArgs begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); + // Non-anchor zoom-in { host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, @@ -1583,22 +1796,31 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { did_request_redraw_ = false; did_request_animate_ = false; - host_impl_->Animate(start_time); + begin_frame_args.frame_time = start_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); + host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; did_request_animate_ = false; - host_impl_->Animate(halfway_through_animation); + begin_frame_args.frame_time = halfway_through_animation; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); + host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; did_request_animate_ = false; did_request_commit_ = false; - host_impl_->Animate(end_time); + begin_frame_args.frame_time = end_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_commit_); EXPECT_FALSE(did_request_animate_); + host_impl_->DidFinishImplFrame(); scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -1607,6 +1829,10 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { gfx::Vector2d(-50, -50))); } + start_time += base::TimeDelta::FromSeconds(10); + halfway_through_animation += base::TimeDelta::FromSeconds(10); + end_time += base::TimeDelta::FromSeconds(10); + // Anchor zoom-out { host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, @@ -1627,17 +1853,23 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { did_request_redraw_ = false; did_request_animate_ = false; - host_impl_->Animate(start_time); + begin_frame_args.frame_time = start_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); + host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; did_request_commit_ = false; did_request_animate_ = false; - host_impl_->Animate(end_time); + begin_frame_args.frame_time = end_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); EXPECT_FALSE(did_request_animate_); EXPECT_TRUE(did_request_commit_); + host_impl_->DidFinishImplFrame(); scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -1664,6 +1896,9 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { base::TimeTicks halfway_through_animation = start_time + duration / 2; base::TimeTicks end_time = start_time + duration; + BeginFrameArgs begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); + // Anchor zoom with unchanged page scale should not change scroll or scale. { host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, min_page_scale, @@ -1677,11 +1912,22 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { 1.f, duration))); host_impl_->ActivateSyncTree(); - host_impl_->Animate(start_time); - host_impl_->Animate(halfway_through_animation); + begin_frame_args.frame_time = start_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); + host_impl_->DidFinishImplFrame(); + + begin_frame_args.frame_time = halfway_through_animation; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); - host_impl_->Animate(end_time); + host_impl_->DidFinishImplFrame(); + + begin_frame_args.frame_time = end_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_commit_); + host_impl_->DidFinishImplFrame(); scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -1692,6 +1938,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) { host_impl_->CreatePendingTree(); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); CreateScrollAndContentsLayers( host_impl_->pending_tree(), gfx::Size(100, 100)); @@ -1715,6 +1962,9 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) { base::TimeTicks end_time = start_time + duration; float target_scale = 2.f; + BeginFrameArgs begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); + scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50)); // Make sure TakePageScaleAnimation works properly. @@ -1741,9 +1991,12 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) { false, target_scale, duration))); - host_impl_->Animate(halfway_through_animation); + begin_frame_args.frame_time = halfway_through_animation; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_FALSE(did_request_animate_); EXPECT_FALSE(did_request_redraw_); + host_impl_->DidFinishImplFrame(); // Activate the sync tree. This should cause the animation to become enabled. // It should also clear the pointer on the sync tree. @@ -1753,34 +2006,51 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationTransferedOnSyncTreeActivate) { EXPECT_FALSE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); + start_time += base::TimeDelta::FromSeconds(10); + third_through_animation += base::TimeDelta::FromSeconds(10); + halfway_through_animation += base::TimeDelta::FromSeconds(10); + end_time += base::TimeDelta::FromSeconds(10); + // From here on, make sure the animation runs as normal. did_request_redraw_ = false; did_request_animate_ = false; - host_impl_->Animate(start_time); + begin_frame_args.frame_time = start_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); + host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; did_request_animate_ = false; - host_impl_->Animate(third_through_animation); + begin_frame_args.frame_time = third_through_animation; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); + host_impl_->DidFinishImplFrame(); // Another activation shouldn't have any effect on the animation. host_impl_->ActivateSyncTree(); did_request_redraw_ = false; did_request_animate_ = false; - host_impl_->Animate(halfway_through_animation); + begin_frame_args.frame_time = halfway_through_animation; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_animate_); + host_impl_->DidFinishImplFrame(); did_request_redraw_ = false; did_request_animate_ = false; did_request_commit_ = false; - host_impl_->Animate(end_time); + begin_frame_args.frame_time = end_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_request_commit_); EXPECT_FALSE(did_request_animate_); + host_impl_->DidFinishImplFrame(); scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); @@ -1803,6 +2073,9 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationCompletedNotification) { base::TimeTicks halfway_through_animation = start_time + duration / 2; base::TimeTicks end_time = start_time + duration; + BeginFrameArgs begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f); scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50)); @@ -1811,14 +2084,23 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationCompletedNotification) { scoped_ptr<PendingPageScaleAnimation>(new PendingPageScaleAnimation( gfx::Vector2d(), false, 2.f, duration))); host_impl_->ActivateSyncTree(); - host_impl_->Animate(start_time); + begin_frame_args.frame_time = start_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_FALSE(did_complete_page_scale_animation_); + host_impl_->DidFinishImplFrame(); - host_impl_->Animate(halfway_through_animation); + begin_frame_args.frame_time = halfway_through_animation; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_FALSE(did_complete_page_scale_animation_); + host_impl_->DidFinishImplFrame(); - host_impl_->Animate(end_time); + begin_frame_args.frame_time = end_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_TRUE(did_complete_page_scale_animation_); + host_impl_->DidFinishImplFrame(); } class LayerTreeHostImplOverridePhysicalTime : public LayerTreeHostImpl { @@ -1855,7 +2137,6 @@ class LayerTreeHostImplOverridePhysicalTime : public LayerTreeHostImpl { 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 = @@ -1863,40 +2144,24 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { settings, this, &proxy_, &shared_bitmap_manager_, &task_graph_runner_, &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); + output_surface_ = CreateOutputSurface(); + host_impl_->InitializeRenderer(output_surface_.get()); - 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->SetIsContainerForFixedPositionLayers(true); - - scoped_ptr<LayerImpl> contents = - LayerImpl::Create(host_impl_->active_tree(), 3); - contents->SetDrawsContent(true); - contents->SetBounds(content_size); + SetupScrollAndContentsLayers(content_size); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f); + host_impl_->SetViewportSize( + gfx::Size(content_size.width() / 2, content_size.height() / 2)); scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar = - SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), 4, + SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), 400, VERTICAL, 10, 0, false, true); EXPECT_FLOAT_EQ(0.f, scrollbar->opacity()); - scroll->AddChild(contents.Pass()); - root->AddChild(scroll.Pass()); - root->SetHasRenderSurface(true); - scrollbar->SetScrollLayerAndClipLayerByIds(2, 1); + LayerImpl* scroll = host_impl_->InnerViewportScrollLayer(); + LayerImpl* root = scroll->parent()->parent(); + scrollbar->SetScrollLayerAndClipLayerByIds(scroll->id(), root->id()); root->AddChild(scrollbar.Pass()); - 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(); } @@ -1950,13 +2215,17 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { EXPECT_FALSE(did_request_redraw_); // After the scrollbar animation begins, we should start getting redraws. - host_impl_->Animate(fake_now); + BeginFrameArgs begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, fake_now); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); 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())); + host_impl_->DidFinishImplFrame(); // Setting the scroll offset outside a scroll should also cause the // scrollbar to appear and to schedule a scrollbar animation. @@ -1987,7 +2256,7 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest { // Changing page scale triggers scrollbar animation. host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f); - host_impl_->SetPageScaleOnActiveTree(1.1f); + host_impl_->active_tree()->SetPageScaleOnActiveTree(1.1f); EXPECT_FALSE(did_request_animate_); EXPECT_FALSE(did_request_redraw_); EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), @@ -2006,6 +2275,64 @@ TEST_F(LayerTreeHostImplTestScrollbarAnimation, Thinning) { RunTest(LayerTreeSettings::THINNING); } +class LayerTreeHostImplTestScrollbarOpacity : public LayerTreeHostImplTest { + protected: + void RunTest(LayerTreeSettings::ScrollbarAnimator animator) { + LayerTreeSettings settings; + settings.scrollbar_animator = animator; + settings.scrollbar_fade_delay_ms = 20; + settings.scrollbar_fade_duration_ms = 20; + settings.verify_property_trees = true; + gfx::Size content_size(100, 100); + + CreateHostImpl(settings, CreateOutputSurface()); + host_impl_->CreatePendingTree(); + CreateScrollAndContentsLayers(host_impl_->pending_tree(), content_size); + scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar = + SolidColorScrollbarLayerImpl::Create(host_impl_->pending_tree(), 400, + VERTICAL, 10, 0, false, true); + LayerImpl* scroll = host_impl_->pending_tree()->InnerViewportScrollLayer(); + LayerImpl* root = scroll->parent()->parent(); + scrollbar->SetScrollLayerAndClipLayerByIds(scroll->id(), root->id()); + root->AddChild(scrollbar.Pass()); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); + host_impl_->pending_tree()->BuildPropertyTreesForTesting(); + host_impl_->ActivateSyncTree(); + + LayerImpl* scrollbar_layer = host_impl_->active_tree()->LayerById(400); + + EffectNode* active_tree_node = + host_impl_->active_tree()->property_trees()->effect_tree.Node( + scrollbar_layer->effect_tree_index()); + EXPECT_FLOAT_EQ(scrollbar_layer->opacity(), active_tree_node->data.opacity); + + host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL); + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 5)); + host_impl_->ScrollEnd(); + host_impl_->CreatePendingTree(); + EffectNode* pending_tree_node = + host_impl_->pending_tree()->property_trees()->effect_tree.Node( + scrollbar_layer->effect_tree_index()); + EXPECT_FLOAT_EQ(1.f, active_tree_node->data.opacity); + EXPECT_FLOAT_EQ(1.f, scrollbar_layer->opacity()); + EXPECT_FLOAT_EQ(0.f, pending_tree_node->data.opacity); + host_impl_->ActivateSyncTree(); + active_tree_node = + host_impl_->active_tree()->property_trees()->effect_tree.Node( + scrollbar_layer->effect_tree_index()); + EXPECT_FLOAT_EQ(1.f, active_tree_node->data.opacity); + EXPECT_FLOAT_EQ(1.f, scrollbar_layer->opacity()); + } +}; + +TEST_F(LayerTreeHostImplTestScrollbarOpacity, LinearFade) { + RunTest(LayerTreeSettings::LINEAR_FADE); +} + +TEST_F(LayerTreeHostImplTestScrollbarOpacity, Thinning) { + RunTest(LayerTreeSettings::THINNING); +} + void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale( float device_scale_factor) { LayerTreeSettings settings; @@ -2014,12 +2341,12 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale( settings.scrollbar_animator = LayerTreeSettings::THINNING; gfx::Size viewport_size(300, 200); - gfx::Size device_viewport_size = gfx::ToFlooredSize( - gfx::ScaleSize(viewport_size, device_scale_factor)); + gfx::Size device_viewport_size = + gfx::ScaleToFlooredSize(viewport_size, device_scale_factor); gfx::Size content_size(1000, 1000); CreateHostImpl(settings, CreateOutputSurface()); - host_impl_->SetDeviceScaleFactor(device_scale_factor); + host_impl_->active_tree()->SetDeviceScaleFactor(device_scale_factor); host_impl_->SetViewportSize(device_viewport_size); scoped_ptr<LayerImpl> root = @@ -2149,6 +2476,39 @@ TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) { EXPECT_TRUE(metadata.root_overflow_y_hidden); } + // Re-enable scrollability and verify that overflows are no longer hidden. + { + host_impl_->active_tree() + ->OuterViewportScrollLayer() + ->set_user_scrollable_horizontal(true); + host_impl_->active_tree() + ->OuterViewportScrollLayer() + ->set_user_scrollable_vertical(true); + CompositorFrameMetadata metadata = + host_impl_->MakeCompositorFrameMetadata(); + EXPECT_FALSE(metadata.root_overflow_x_hidden); + EXPECT_FALSE(metadata.root_overflow_y_hidden); + } + + // Root "overflow: hidden" properties should also be reflected on the + // inner viewport scroll layer. + { + host_impl_->active_tree() + ->InnerViewportScrollLayer() + ->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() + ->InnerViewportScrollLayer() + ->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_->PinchGestureBegin(); @@ -2169,7 +2529,7 @@ TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) { // Likewise if set from the main thread. host_impl_->ProcessScrollDeltas(); host_impl_->active_tree()->PushPageScaleFromMainThread(4.f, 0.5f, 4.f); - host_impl_->SetPageScaleOnActiveTree(4.f); + host_impl_->active_tree()->SetPageScaleOnActiveTree(4.f); { CompositorFrameMetadata metadata = host_impl_->MakeCompositorFrameMetadata(); @@ -2262,7 +2622,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) { { LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -2279,7 +2639,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) { layer->set_will_draw_returns_false(); layer->ClearDidDrawCheck(); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -2310,7 +2670,8 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) { EXPECT_FALSE(layer->will_draw_called()); EXPECT_FALSE(layer->did_draw_called()); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + host_impl_->active_tree()->BuildPropertyTreesForTesting(); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -2325,7 +2686,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) { EXPECT_FALSE(layer->will_draw_called()); EXPECT_FALSE(layer->did_draw_called()); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -2364,7 +2725,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawNotCalledOnOccludedLayer) { EXPECT_FALSE(top_layer->will_draw_called()); EXPECT_FALSE(top_layer->did_draw_called()); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -2399,7 +2760,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) { LayerTreeHostImpl::FrameData frame; FakeLayerTreeHostImpl::RecursiveUpdateNumChildren( host_impl_->active_tree()->root_layer()); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -2549,7 +2910,7 @@ TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsAndFails) { root->SetHasRenderSurface(true); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); host_impl_->SwapBuffers(frame); @@ -2597,7 +2958,7 @@ TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsAndFails) { host_impl_->SetRequiresHighResToDraw(); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(testcase.expected_result, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(testcase.expected_result, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); host_impl_->SwapBuffers(frame); @@ -2636,7 +2997,7 @@ TEST_F(LayerTreeHostImplTest, root->SetHasRenderSurface(true); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); host_impl_->SwapBuffers(frame); @@ -2684,7 +3045,7 @@ TEST_F(LayerTreeHostImplTest, host_impl_->SetRequiresHighResToDraw(); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(testcase.expected_result, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(testcase.expected_result, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); host_impl_->SwapBuffers(frame); @@ -2707,6 +3068,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) { TEST_F(LayerTreeHostImplTest, ClampingAfterActivation) { host_impl_->CreatePendingTree(); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); CreateScrollAndContentsLayers(host_impl_->pending_tree(), gfx::Size(100, 100)); host_impl_->ActivateSyncTree(); @@ -2724,7 +3086,6 @@ TEST_F(LayerTreeHostImplTest, ClampingAfterActivation) { EXPECT_EQ(active_outer_layer->CurrentScrollOffset(), gfx::ScrollOffset(0, 0)); } -// TODO(bokan): Convert these tests to create inner and outer viewports. class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest { public: LayerTreeHostImplTopControlsTest() @@ -2744,63 +3105,11 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest { if (init) { host_impl_->active_tree()->set_top_controls_height(top_controls_height_); host_impl_->active_tree()->SetCurrentTopControlsShownRatio(1.f); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); } return init; } - void SetupTopControlsAndScrollLayer() { - scoped_ptr<LayerImpl> root = - LayerImpl::Create(host_impl_->active_tree(), 1); - scoped_ptr<LayerImpl> root_clip = - LayerImpl::Create(host_impl_->active_tree(), 2); - root_clip->SetBounds(clip_size_); - root->SetScrollClipLayer(root_clip->id()); - root->SetBounds(layer_size_); - root->SetPosition(gfx::PointF()); - root->SetDrawsContent(false); - 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( - 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_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 = - LayerImpl::Create(host_impl_->sync_tree(), 2); - root_clip->SetBounds(clip_size_); - root->SetScrollClipLayer(root_clip->id()); - root->SetBounds(layer_size_); - root->SetPosition(gfx::PointF()); - root->SetDrawsContent(false); - root->SetIsContainerForFixedPositionLayers(true); - inner_viewport_scroll_layer_id = root->id(); - page_scale_layer_id = root_clip->id(); - root_clip->AddChild(root.Pass()); - host_impl_->sync_tree()->SetRootLayer(root_clip.Pass()); - host_impl_->sync_tree()->SetViewportLayersFromIds( - 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_shrink_blink_size(true); - host_impl_->DidChangeTopControlsPosition(); - } - void SetupTopControlsAndScrollLayerWithVirtualViewport( const gfx::Size& inner_viewport_size, const gfx::Size& outer_viewport_size, @@ -2864,6 +3173,73 @@ class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest { LayerTreeSettings settings_; }; // class LayerTreeHostImplTopControlsTest +// Tests that, on a page with content the same size as the viewport, hiding +// the top controls also increases the ScrollableSize (i.e. the content size). +// Since the viewport got larger, the effective scrollable "content" also did. +// This ensures, for one thing, that the overscroll glow is shown in the right +// place. +TEST_F(LayerTreeHostImplTopControlsTest, + HidingTopControlsExpandsScrollableSize) { + SetupTopControlsAndScrollLayerWithVirtualViewport( + gfx::Size(50, 50), gfx::Size(50, 50), gfx::Size(50, 50)); + + LayerTreeImpl* active_tree = host_impl_->active_tree(); + + // Create a content layer beneath the outer viewport scroll layer. + int id = host_impl_->OuterViewportScrollLayer()->id(); + host_impl_->OuterViewportScrollLayer()->AddChild( + LayerImpl::Create(host_impl_->active_tree(), id + 2)); + LayerImpl* content = active_tree->OuterViewportScrollLayer()->children()[0]; + content->SetBounds(gfx::Size(50, 50)); + + DrawFrame(); + + LayerImpl* inner_container = active_tree->InnerViewportContainerLayer(); + LayerImpl* outer_container = active_tree->OuterViewportContainerLayer(); + + // The top controls should start off showing so the viewport should be shrunk. + ASSERT_EQ(gfx::Size(50, 50), inner_container->bounds()); + ASSERT_EQ(gfx::Size(50, 50), outer_container->bounds()); + + EXPECT_EQ(gfx::SizeF(50, 50), active_tree->ScrollableSize()); + + EXPECT_EQ(InputHandler::SCROLL_STARTED, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE)); + + host_impl_->top_controls_manager()->ScrollBegin(); + + // Hide the top controls by a bit, the scrollable size should increase but the + // actual content bounds shouldn't. + { + host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + ASSERT_EQ(gfx::Size(50, 75), inner_container->bounds()); + ASSERT_EQ(gfx::Size(50, 75), outer_container->bounds()); + EXPECT_EQ(gfx::SizeF(50, 75), active_tree->ScrollableSize()); + EXPECT_EQ(gfx::SizeF(50, 50), content->BoundsForScrolling()); + } + + // Fully hide the top controls. + { + host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + ASSERT_EQ(gfx::Size(50, 100), inner_container->bounds()); + ASSERT_EQ(gfx::Size(50, 100), outer_container->bounds()); + EXPECT_EQ(gfx::SizeF(50, 100), active_tree->ScrollableSize()); + EXPECT_EQ(gfx::SizeF(50, 50), content->BoundsForScrolling()); + } + + // Scrolling additionally shouldn't have any effect. + { + host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + ASSERT_EQ(gfx::Size(50, 100), inner_container->bounds()); + ASSERT_EQ(gfx::Size(50, 100), outer_container->bounds()); + EXPECT_EQ(gfx::SizeF(50, 100), active_tree->ScrollableSize()); + EXPECT_EQ(gfx::SizeF(50, 50), content->BoundsForScrolling()); + } + + host_impl_->top_controls_manager()->ScrollEnd(); + host_impl_->ScrollEnd(); +} + TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsByFractionalAmount) { SetupTopControlsAndScrollLayerWithVirtualViewport( gfx::Size(10, 10), gfx::Size(10, 10), gfx::Size(10, 10)); @@ -2947,12 +3323,12 @@ TEST_F(LayerTreeHostImplTopControlsTest, // 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->CurrentScrollOffset().y()); - EXPECT_EQ(25.f, inner_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(25.f, outer_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(15.f, inner_scroll->CurrentScrollOffset().y()); host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -30.f)); - EXPECT_EQ(0.f, outer_scroll->CurrentScrollOffset().y()); - EXPECT_EQ(25.f, inner_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(25.f, outer_scroll->CurrentScrollOffset().y()); + EXPECT_EQ(0.f, inner_scroll->CurrentScrollOffset().y()); host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -50.f)); host_impl_->ScrollEnd(); @@ -2967,6 +3343,7 @@ TEST_F(LayerTreeHostImplTopControlsTest, FixedContainerDelta) { SetupTopControlsAndScrollLayerWithVirtualViewport( gfx::Size(100, 100), gfx::Size(100, 100), gfx::Size(100, 100)); DrawFrame(); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); float page_scale = 1.5f; LayerImpl* outer_viewport_scroll_layer = @@ -2986,8 +3363,8 @@ TEST_F(LayerTreeHostImplTopControlsTest, FixedContainerDelta) { host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta); 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()); + EXPECT_FLOAT_EQ(top_controls_scroll_delta.y(), + outer_viewport_scroll_layer->FixedContainerSizeDelta().y()); host_impl_->ScrollEnd(); // Scroll past the maximum extent. The delta shouldn't be greater than the @@ -3012,6 +3389,24 @@ TEST_F(LayerTreeHostImplTopControlsTest, FixedContainerDelta) { host_impl_->top_controls_manager()->ScrollEnd(); } +// Test that if only the top controls are scrolled, we shouldn't request a +// commit. +TEST_F(LayerTreeHostImplTopControlsTest, TopControlsDontTriggerCommit) { + 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()); + + // 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); + EXPECT_FALSE(did_request_commit_); +} + // Test that if a scrollable sublayer doesn't consume the scroll, // top controls should hide when scrolling down. TEST_F(LayerTreeHostImplTopControlsTest, TopControlsScrollableSublayer) { @@ -3062,7 +3457,8 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsScrollableSublayer) { // TreeImpl correctly affects the top controls manager and viewport bounds. TEST_F(LayerTreeHostImplTopControlsTest, PositionTopControlsExplicitly) { CreateHostImpl(settings_, CreateOutputSurface()); - SetupTopControlsAndScrollLayer(); + SetupTopControlsAndScrollLayerWithVirtualViewport( + layer_size_, layer_size_, layer_size_); DrawFrame(); host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f); @@ -3081,8 +3477,9 @@ TEST_F(LayerTreeHostImplTopControlsTest, PositionTopControlsExplicitly) { host_impl_->DidChangeTopControlsPosition(); // Now that top controls have moved, expect the clip to resize. - LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer(); - EXPECT_EQ(viewport_size_, root_clip_ptr->bounds()); + LayerImpl* inner_clip_ptr = + host_impl_->InnerViewportScrollLayer()->parent()->parent(); + EXPECT_EQ(viewport_size_, inner_clip_ptr->bounds()); } // Test that the top_controls delta and sent delta are appropriately @@ -3090,7 +3487,8 @@ TEST_F(LayerTreeHostImplTopControlsTest, PositionTopControlsExplicitly) { // change after the activation. TEST_F(LayerTreeHostImplTopControlsTest, ApplyDeltaOnTreeActivation) { CreateHostImpl(settings_, CreateOutputSurface()); - SetupTopControlsAndScrollLayer(); + SetupTopControlsAndScrollLayerWithVirtualViewport( + layer_size_, layer_size_, layer_size_); DrawFrame(); host_impl_->active_tree()->top_controls_shown_ratio()->PushFromMainThread( @@ -3106,15 +3504,16 @@ TEST_F(LayerTreeHostImplTopControlsTest, ApplyDeltaOnTreeActivation) { top_controls_height_); host_impl_->DidChangeTopControlsPosition(); - LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer(); - EXPECT_EQ(viewport_size_, root_clip_ptr->bounds()); + LayerImpl* inner_clip_ptr = + host_impl_->InnerViewportScrollLayer()->parent()->parent(); + EXPECT_EQ(viewport_size_, inner_clip_ptr->bounds()); EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset()); host_impl_->ActivateSyncTree(); - root_clip_ptr = host_impl_->active_tree()->root_layer(); + inner_clip_ptr = host_impl_->InnerViewportScrollLayer()->parent()->parent(); EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset()); - EXPECT_EQ(viewport_size_, root_clip_ptr->bounds()); + EXPECT_EQ(viewport_size_, inner_clip_ptr->bounds()); EXPECT_FLOAT_EQ( -15.f, host_impl_->active_tree()->top_controls_shown_ratio()->Delta() * @@ -3131,7 +3530,8 @@ TEST_F(LayerTreeHostImplTopControlsTest, ApplyDeltaOnTreeActivation) { // the compositor to accommodate the top controls. TEST_F(LayerTreeHostImplTopControlsTest, TopControlsLayoutHeightChanged) { CreateHostImpl(settings_, CreateOutputSurface()); - SetupTopControlsAndScrollLayer(); + SetupTopControlsAndScrollLayerWithVirtualViewport( + layer_size_, layer_size_, layer_size_); DrawFrame(); host_impl_->sync_tree()->PushTopControlsFromMainThread(1.f); @@ -3143,24 +3543,26 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsLayoutHeightChanged) { host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f); host_impl_->DidChangeTopControlsPosition(); - LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer(); - EXPECT_EQ(viewport_size_, root_clip_ptr->bounds()); + LayerImpl* inner_clip_ptr = + host_impl_->InnerViewportScrollLayer()->parent()->parent(); + EXPECT_EQ(viewport_size_, inner_clip_ptr->bounds()); EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset()); host_impl_->sync_tree()->root_layer()->SetBounds( - gfx::Size(root_clip_ptr->bounds().width(), - root_clip_ptr->bounds().height() - 50.f)); + gfx::Size(inner_clip_ptr->bounds().width(), + inner_clip_ptr->bounds().height() - 50.f)); host_impl_->ActivateSyncTree(); - root_clip_ptr = host_impl_->active_tree()->root_layer(); + inner_clip_ptr = + host_impl_->InnerViewportScrollLayer()->parent()->parent(); EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset()); // The total bounds should remain unchanged since the bounds delta should // 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, 50.f), root_clip_ptr->bounds_delta()); + EXPECT_EQ(viewport_size_, inner_clip_ptr->bounds()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 50.f), inner_clip_ptr->bounds_delta()); host_impl_->active_tree()->SetCurrentTopControlsShownRatio(1.f); host_impl_->DidChangeTopControlsPosition(); @@ -3168,9 +3570,9 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsLayoutHeightChanged) { 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_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f), inner_clip_ptr->bounds_delta()); EXPECT_EQ(gfx::Size(viewport_size_.width(), viewport_size_.height() - 50.f), - root_clip_ptr->bounds()); + inner_clip_ptr->bounds()); } // Test that showing/hiding the top controls when the viewport is fully scrolled @@ -3243,6 +3645,7 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsViewportOffsetClamping) { TEST_F(LayerTreeHostImplTopControlsTest, TopControlsAspectRatio) { SetupTopControlsAndScrollLayerWithVirtualViewport( gfx::Size(100, 100), gfx::Size(200, 200), gfx::Size(200, 400)); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 2.f); DrawFrame(); EXPECT_FLOAT_EQ(top_controls_height_, @@ -3264,12 +3667,14 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsAspectRatio) { host_impl_->active_tree()->OuterViewportContainerLayer(); LayerImpl* inner_container = host_impl_->active_tree()->InnerViewportContainerLayer(); - EXPECT_EQ(gfx::Size(100, 100+25), inner_container->BoundsForScrolling()); + EXPECT_EQ(gfx::SizeF(100.f, 100.f + 25.f), + inner_container->BoundsForScrolling()); // Outer viewport should match inner's aspect ratio. The bounds are ceiled. float aspect_ratio = inner_container->BoundsForScrolling().width() / inner_container->BoundsForScrolling().height(); - gfx::Size expected = gfx::ToCeiledSize(gfx::SizeF(200, 200 / aspect_ratio)); + gfx::SizeF expected = + gfx::SizeF(gfx::ToCeiledSize(gfx::SizeF(200, 200 / aspect_ratio))); EXPECT_EQ(expected, outer_container->BoundsForScrolling()); EXPECT_EQ(expected, host_impl_->InnerViewportScrollLayer()->BoundsForScrolling()); @@ -3290,7 +3695,8 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsScrollOuterViewport) { EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE)); host_impl_->ScrollBy(gfx::Point(), scroll_delta); - EXPECT_EQ(host_impl_->OuterViewportScrollLayer(), + + EXPECT_EQ(host_impl_->InnerViewportScrollLayer(), host_impl_->CurrentlyScrollingLayer()); host_impl_->ScrollEnd(); @@ -3304,7 +3710,7 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsScrollOuterViewport) { host_impl_->ScrollBy(gfx::Point(), scroll_delta); EXPECT_EQ(0, host_impl_->top_controls_manager()->ContentTopOffset()); - EXPECT_EQ(host_impl_->OuterViewportScrollLayer(), + EXPECT_EQ(host_impl_->InnerViewportScrollLayer(), host_impl_->CurrentlyScrollingLayer()); host_impl_->ScrollEnd(); @@ -3331,7 +3737,8 @@ TEST_F(LayerTreeHostImplTopControlsTest, TopControlsScrollOuterViewport) { TEST_F(LayerTreeHostImplTopControlsTest, ScrollNonScrollableRootWithTopControls) { CreateHostImpl(settings_, CreateOutputSurface()); - SetupTopControlsAndScrollLayer(); + SetupTopControlsAndScrollLayerWithVirtualViewport( + layer_size_, layer_size_, layer_size_); DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_STARTED, @@ -3342,8 +3749,9 @@ TEST_F(LayerTreeHostImplTopControlsTest, host_impl_->top_controls_manager()->ScrollEnd(); EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset()); // Now that top controls have moved, expect the clip to resize. - LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer(); - EXPECT_EQ(viewport_size_, root_clip_ptr->bounds()); + LayerImpl* inner_clip_ptr = + host_impl_->InnerViewportScrollLayer()->parent()->parent(); + EXPECT_EQ(viewport_size_, inner_clip_ptr->bounds()); host_impl_->ScrollEnd(); @@ -3359,7 +3767,7 @@ TEST_F(LayerTreeHostImplTopControlsTest, // Now that top controls have moved, expect the clip to resize. EXPECT_EQ(gfx::Size(viewport_size_.width(), viewport_size_.height() + scroll_increment_y), - root_clip_ptr->bounds()); + inner_clip_ptr->bounds()); host_impl_->top_controls_manager()->ScrollBy( gfx::Vector2dF(0.f, scroll_increment_y)); @@ -3367,7 +3775,7 @@ TEST_F(LayerTreeHostImplTopControlsTest, 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()); + EXPECT_EQ(clip_size_, inner_clip_ptr->bounds()); host_impl_->ScrollEnd(); @@ -3506,29 +3914,22 @@ TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) { } TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { - gfx::Size surface_size(20, 20); - gfx::Size viewport_size(10, 10); + gfx::Size viewport_size(20, 20); float page_scale = 2.f; - scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - scoped_ptr<LayerImpl> root_clip = - LayerImpl::Create(host_impl_->active_tree(), 2); - scoped_ptr<LayerImpl> root_scrolling = - CreateScrollableLayer(3, surface_size, root_clip.get()); - EXPECT_EQ(viewport_size, root_clip->bounds()); - 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(Layer::INVALID_ID, 1, 3, - Layer::INVALID_ID); - host_impl_->active_tree()->DidBecomeActive(); - host_impl_->SetViewportSize(viewport_size); + + SetupScrollAndContentsLayers(viewport_size); + + // Setup the layers so that the outer viewport is scrollable. + host_impl_->active_tree()->InnerViewportScrollLayer()->parent()->SetBounds( + viewport_size); + host_impl_->active_tree()->OuterViewportScrollLayer()->SetBounds( + gfx::Size(40, 40)); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); DrawFrame(); LayerImpl* root_scroll = + host_impl_->active_tree()->OuterViewportScrollLayer(); + LayerImpl* inner_scroll = host_impl_->active_tree()->InnerViewportScrollLayer(); EXPECT_EQ(viewport_size, root_scroll->scroll_clip_layer()->bounds()); @@ -3541,11 +3942,10 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { host_impl_->ScrollEnd(); // Set new page scale from main thread. - host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, page_scale, - page_scale); + host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, 2.f); scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), root_scroll->id(), + EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), inner_scroll->id(), expected_scroll_delta)); // The scroll range should also have been updated. @@ -3557,30 +3957,22 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { } TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { - gfx::Size surface_size(20, 20); - gfx::Size viewport_size(10, 10); + gfx::Size viewport_size(20, 20); float page_scale = 2.f; - scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); - scoped_ptr<LayerImpl> root_clip = - LayerImpl::Create(host_impl_->active_tree(), 2); - scoped_ptr<LayerImpl> root_scrolling = - CreateScrollableLayer(3, surface_size, root_clip.get()); - EXPECT_EQ(viewport_size, root_clip->bounds()); - 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(Layer::INVALID_ID, 1, 3, - Layer::INVALID_ID); - host_impl_->active_tree()->DidBecomeActive(); - host_impl_->SetViewportSize(viewport_size); - host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, page_scale); + + SetupScrollAndContentsLayers(viewport_size); + + // Setup the layers so that the outer viewport is scrollable. + host_impl_->active_tree()->InnerViewportScrollLayer()->parent()->SetBounds( + viewport_size); + host_impl_->active_tree()->OuterViewportScrollLayer()->SetBounds( + gfx::Size(40, 40)); + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); DrawFrame(); LayerImpl* root_scroll = + host_impl_->active_tree()->OuterViewportScrollLayer(); + LayerImpl* inner_scroll = host_impl_->active_tree()->InnerViewportScrollLayer(); EXPECT_EQ(viewport_size, root_scroll->scroll_clip_layer()->bounds()); @@ -3602,7 +3994,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { // The scroll delta is not scaled because the main thread did not scale. scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), root_scroll->id(), + EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), inner_scroll->id(), expected_scroll_delta)); // The scroll range should also have been updated. @@ -3613,6 +4005,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { } TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { + host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f); gfx::Size surface_size(10, 10); float default_page_scale = 1.f; gfx::Transform default_page_scale_matrix; @@ -3636,6 +4029,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { LayerImpl* grand_child = child->children()[0]; // Set new page scale on impl thread by pinching. + RebuildPropertyTrees(); host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(new_page_scale, gfx::Point()); @@ -3646,7 +4040,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { // Make sure all the layers are drawn with the page scale delta applied, i.e., // the page scale delta on the root layer is applied hierarchically. LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -3663,32 +4057,19 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { } 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); - root_scrolling->SetScrollClipLayer(root->id()); - root_scrolling->SetIsContainerForFixedPositionLayers(true); - LayerImpl* root_scrolling_ptr = root_scrolling.get(); - root->AddChild(root_scrolling.Pass()); - int child_scroll_layer_id = 3; - scoped_ptr<LayerImpl> child_scrolling = CreateScrollableLayer( - child_scroll_layer_id, surface_size, root_scrolling_ptr); - LayerImpl* child = child_scrolling.get(); - root_scrolling_ptr->AddChild(child_scrolling.Pass()); - 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(); - host_impl_->SetViewportSize(surface_size); + SetupScrollAndContentsLayers(gfx::Size(30, 30)); + + LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer(); + LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer(); + + // Make the outer scroll layer scrollable. + outer_scroll->SetBounds(gfx::Size(50, 50)); + DrawFrame(); gfx::Vector2d scroll_delta(0, 10); gfx::Vector2d expected_scroll_delta(scroll_delta); - gfx::ScrollOffset expected_max_scroll(child->MaxScrollOffset()); + gfx::ScrollOffset expected_max_scroll(outer_scroll->MaxScrollOffset()); EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL)); host_impl_->ScrollBy(gfx::Point(), scroll_delta); @@ -3701,11 +4082,11 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) { DrawOneFrame(); scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), child_scroll_layer_id, + EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), inner_scroll->id(), expected_scroll_delta)); // The scroll range should not have changed. - EXPECT_EQ(child->MaxScrollOffset(), expected_max_scroll); + EXPECT_EQ(outer_scroll->MaxScrollOffset(), expected_max_scroll); // The page scale delta remains constant because the impl thread did not // scale. @@ -3714,8 +4095,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) { TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) { // Scroll a child layer beyond its maximum scroll range and make sure the - // parent layer is scrolled on the axis on which the child was unable to - // scroll. + // parent layer isn't scrolled. gfx::Size surface_size(10, 10); gfx::Size content_size(20, 20); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); @@ -3754,9 +4134,8 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) { EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -5))); - // The child should have only scrolled on the other axis. - EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), child->id(), - gfx::Vector2d(-3, 0))); + // The child should not have scrolled. + ExpectNone(*scroll_info.get(), child->id()); } } @@ -3857,7 +4236,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { // Scrolling should be adjusted from viewport space. host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 2.f, 2.f); - host_impl_->SetPageScaleOnActiveTree(2.f); + host_impl_->active_tree()->SetPageScaleOnActiveTree(2.f); scroll_delta = gfx::Vector2d(0, -2); EXPECT_EQ(InputHandler::SCROLL_STARTED, @@ -3950,6 +4329,7 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) { host_impl_->active_tree()->DidBecomeActive(); // Scrolling should still work even though we did not draw yet. + RebuildPropertyTrees(); EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL)); } @@ -4055,8 +4435,7 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { 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. + // The child layer shouldn't have scrolled. gfx::Vector2d expected_scroll_delta( 0, -gesture_scroll_delta.x() * std::sin(MathUtil::Deg2Rad(child_layer_angle))); @@ -4065,14 +4444,8 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), child_layer_id, expected_scroll_delta)); - // The root scroll layer should have scrolled more, since the input scroll - // delta was mostly orthogonal to the child layer's vertical scroll axis. - gfx::Vector2d expected_root_scroll_delta( - gesture_scroll_delta.x() * - std::pow(std::cos(MathUtil::Deg2Rad(child_layer_angle)), 2), - 0); - EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), scroll_layer->id(), - expected_root_scroll_delta)); + // The root scroll layer shouldn't have scrolled. + ExpectNone(*scroll_info.get(), scroll_layer->id()); } } @@ -4159,7 +4532,7 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) { int scale = 2; gfx::Transform scale_transform; scale_transform.Scale(scale, scale); - scroll_layer->SetTransform(scale_transform); + scroll_layer->parent()->SetTransform(scale_transform); gfx::Size surface_size(50, 50); host_impl_->SetViewportSize(surface_size); @@ -4199,7 +4572,7 @@ TEST_F(LayerTreeHostImplTest, ScrollViewportRounding) { SetupScrollAndContentsLayers(gfx::Size(width, height)); host_impl_->active_tree()->InnerViewportContainerLayer()->SetBounds( gfx::Size(width * scale - 1, height * scale)); - host_impl_->SetDeviceScaleFactor(scale); + host_impl_->active_tree()->SetDeviceScaleFactor(scale); host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f); LayerImpl* inner_viewport_scroll_layer = @@ -4208,32 +4581,26 @@ TEST_F(LayerTreeHostImplTest, ScrollViewportRounding) { inner_viewport_scroll_layer->MaxScrollOffset()); } -class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate { +class TestInputHandlerClient : public InputHandlerClient { public: - TestScrollOffsetDelegate() + TestInputHandlerClient() : page_scale_factor_(0.f), min_page_scale_factor_(-1.f), - max_page_scale_factor_(-1.f), - needs_animate_(false) {} - - ~TestScrollOffsetDelegate() override {} - - gfx::ScrollOffset GetTotalScrollOffset() override { - return getter_return_value_; - } - - bool IsExternalScrollActive() const override { return false; } - - void SetNeedsAnimate(const AnimationCallback&) override { - needs_animate_ = true; - } - - void UpdateRootLayerState(const gfx::ScrollOffset& total_scroll_offset, - const gfx::ScrollOffset& max_scroll_offset, - const gfx::SizeF& scrollable_size, - float page_scale_factor, - float min_page_scale_factor, - float max_page_scale_factor) override { + max_page_scale_factor_(-1.f) {} + ~TestInputHandlerClient() override {} + + // InputHandlerClient implementation. + void WillShutdown() override {} + void Animate(base::TimeTicks time) override {} + void MainThreadHasStoppedFlinging() override {} + void ReconcileElasticOverscrollAndRootScroll() override {} + void UpdateRootLayerStateForSynchronousInputHandler( + const gfx::ScrollOffset& total_scroll_offset, + const gfx::ScrollOffset& max_scroll_offset, + const gfx::SizeF& scrollable_size, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) override { DCHECK(total_scroll_offset.x() <= max_scroll_offset.x()); DCHECK(total_scroll_offset.y() <= max_scroll_offset.y()); last_set_scroll_offset_ = total_scroll_offset; @@ -4242,24 +4609,12 @@ 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_); - } - - bool GetAndResetNeedsAnimate() { - bool needs_animate = needs_animate_; - needs_animate_ = false; - return needs_animate; } gfx::ScrollOffset last_set_scroll_offset() { return last_set_scroll_offset_; } - void set_getter_return_value(const gfx::ScrollOffset& value) { - getter_return_value_ = value; - } - gfx::ScrollOffset max_scroll_offset() const { return max_scroll_offset_; } @@ -4282,53 +4637,64 @@ class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate { private: gfx::ScrollOffset last_set_scroll_offset_; - gfx::ScrollOffset getter_return_value_; gfx::ScrollOffset max_scroll_offset_; gfx::SizeF scrollable_size_; float page_scale_factor_; float min_page_scale_factor_; float max_page_scale_factor_; - bool needs_animate_; }; -// TODO(jdduke): Test root fling animation. TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { - TestScrollOffsetDelegate scroll_delegate; + TestInputHandlerClient scroll_watcher; host_impl_->SetViewportSize(gfx::Size(10, 20)); LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); LayerImpl* clip_layer = scroll_layer->parent()->parent(); clip_layer->SetBounds(gfx::Size(10, 20)); - // Setting the delegate results in the current scroll offset being set. + host_impl_->BindToClient(&scroll_watcher); + gfx::Vector2dF initial_scroll_delta(10.f, 10.f); scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset()); scroll_layer->SetScrollDelta(initial_scroll_delta); - host_impl_->SetRootLayerScrollOffsetDelegate(&scroll_delegate); - EXPECT_EQ(initial_scroll_delta.ToString(), - scroll_delegate.last_set_scroll_offset().ToString()); + + EXPECT_EQ(gfx::ScrollOffset(), scroll_watcher.last_set_scroll_offset()); + + // Requesting an update results in the current scroll offset being set. + host_impl_->RequestUpdateForSynchronousInputHandler(); + EXPECT_EQ(gfx::ScrollOffset(initial_scroll_delta), + scroll_watcher.last_set_scroll_offset()); // Setting the delegate results in the scrollable_size, max_scroll_offset, // page_scale_factor and {min|max}_page_scale_factor being set. - EXPECT_EQ(gfx::SizeF(100, 100), scroll_delegate.scrollable_size()); - EXPECT_EQ(gfx::ScrollOffset(90, 80), scroll_delegate.max_scroll_offset()); - EXPECT_EQ(1.f, scroll_delegate.page_scale_factor()); - EXPECT_EQ(0.f, scroll_delegate.min_page_scale_factor()); - EXPECT_EQ(0.f, scroll_delegate.max_page_scale_factor()); + EXPECT_EQ(gfx::SizeF(100, 100), scroll_watcher.scrollable_size()); + EXPECT_EQ(gfx::ScrollOffset(90, 80), scroll_watcher.max_scroll_offset()); + EXPECT_EQ(1.f, scroll_watcher.page_scale_factor()); + EXPECT_EQ(1.f, scroll_watcher.min_page_scale_factor()); + EXPECT_EQ(1.f, scroll_watcher.max_page_scale_factor()); - // Updating page scale immediately updates the delegate. + // Put a page scale on the tree. 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_->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_->SetPageScaleOnActiveTree(2.f); + EXPECT_EQ(1.f, scroll_watcher.page_scale_factor()); + EXPECT_EQ(1.f, scroll_watcher.min_page_scale_factor()); + EXPECT_EQ(1.f, scroll_watcher.max_page_scale_factor()); + // Activation will update the delegate. + host_impl_->ActivateSyncTree(); + EXPECT_EQ(2.f, scroll_watcher.page_scale_factor()); + EXPECT_EQ(.5f, scroll_watcher.min_page_scale_factor()); + EXPECT_EQ(4.f, scroll_watcher.max_page_scale_factor()); + + // Reset the page scale for the rest of the test. 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()); + EXPECT_EQ(2.f, scroll_watcher.page_scale_factor()); + EXPECT_EQ(.5f, scroll_watcher.min_page_scale_factor()); + EXPECT_EQ(4.f, scroll_watcher.max_page_scale_factor()); + + // Animating page scale can change the root offset, so it should update the + // delegate. + host_impl_->Animate(); + EXPECT_EQ(1.f, scroll_watcher.page_scale_factor()); + EXPECT_EQ(.5f, scroll_watcher.min_page_scale_factor()); + EXPECT_EQ(4.f, scroll_watcher.max_page_scale_factor()); // 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 @@ -4340,46 +4706,37 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { host_impl_->PinchGestureEnd(); host_impl_->ScrollEnd(); - // Scrolling should be relative to the offset as returned by the delegate. + // Scrolling should be relative to the offset as given by the delegate. gfx::Vector2dF scroll_delta(0.f, 10.f); gfx::ScrollOffset current_offset(7.f, 8.f); - scroll_delegate.set_getter_return_value(current_offset); EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE)); - host_impl_->OnRootLayerDelegatedScrollOffsetChanged(); + host_impl_->SetSynchronousInputHandlerRootScrollOffset(current_offset); host_impl_->ScrollBy(gfx::Point(), scroll_delta); EXPECT_EQ(ScrollOffsetWithDelta(current_offset, scroll_delta), - scroll_delegate.last_set_scroll_offset()); + scroll_watcher.last_set_scroll_offset()); current_offset = gfx::ScrollOffset(42.f, 41.f); - scroll_delegate.set_getter_return_value(current_offset); - host_impl_->OnRootLayerDelegatedScrollOffsetChanged(); + host_impl_->SetSynchronousInputHandlerRootScrollOffset(current_offset); host_impl_->ScrollBy(gfx::Point(), scroll_delta); EXPECT_EQ(current_offset + gfx::ScrollOffset(scroll_delta), - scroll_delegate.last_set_scroll_offset()); + scroll_watcher.last_set_scroll_offset()); host_impl_->ScrollEnd(); - scroll_delegate.set_getter_return_value(gfx::ScrollOffset()); - host_impl_->OnRootLayerDelegatedScrollOffsetChanged(); + host_impl_->SetSynchronousInputHandlerRootScrollOffset(gfx::ScrollOffset()); // Forces a full tree synchronization and ensures that the scroll delegate // sees the correct size of the new tree. gfx::Size new_size(42, 24); host_impl_->CreatePendingTree(); + host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f); CreateScrollAndContentsLayers(host_impl_->pending_tree(), new_size); host_impl_->ActivateSyncTree(); - EXPECT_EQ(new_size, scroll_delegate.scrollable_size()); + EXPECT_EQ(gfx::SizeF(new_size), scroll_watcher.scrollable_size()); - // Un-setting the delegate should propagate the delegate's current offset to - // 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->CurrentScrollOffset().ToString()); + // Tear down the LayerTreeHostImpl before the InputHandlerClient. + host_impl_.reset(); } void CheckLayerScrollDelta(LayerImpl* layer, gfx::Vector2dF scroll_delta) { @@ -4394,12 +4751,10 @@ void CheckLayerScrollDelta(LayerImpl* layer, gfx::Vector2dF scroll_delta) { TEST_F(LayerTreeHostImplTest, ExternalRootLayerScrollOffsetDelegationReflectedInNextDraw) { - TestScrollOffsetDelegate scroll_delegate; host_impl_->SetViewportSize(gfx::Size(10, 20)); LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); LayerImpl* clip_layer = scroll_layer->parent()->parent(); clip_layer->SetBounds(gfx::Size(10, 20)); - host_impl_->SetRootLayerScrollOffsetDelegate(&scroll_delegate); // Draw first frame to clear any pending draws and check scroll. DrawFrame(); @@ -4408,18 +4763,15 @@ TEST_F(LayerTreeHostImplTest, // Set external scroll delta on delegate and notify LayerTreeHost. gfx::ScrollOffset scroll_offset(10.f, 10.f); - scroll_delegate.set_getter_return_value(scroll_offset); - host_impl_->OnRootLayerDelegatedScrollOffsetChanged(); + host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset); // Check scroll delta reflected in layer. LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); EXPECT_FALSE(frame.has_no_damage); CheckLayerScrollDelta(scroll_layer, ScrollOffsetToVector2dF(scroll_offset)); - - host_impl_->SetRootLayerScrollOffsetDelegate(NULL); } TEST_F(LayerTreeHostImplTest, OverscrollRoot) { @@ -4612,27 +4964,7 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) { // should be applied to one of its ancestors if possible. Overscroll should // be reflected only when it has bubbled up to the root scrolling layer. InputHandlerScrollResult scroll_result; - gfx::Size surface_size(10, 10); - 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); - scoped_ptr<LayerImpl> child = - CreateScrollableLayer(2, content_size, root_clip.get()); - - child->SetScrollClipLayer(Layer::INVALID_ID); - root->AddChild(child.Pass()); - root_clip->AddChild(root.Pass()); - - host_impl_->SetViewportSize(surface_size); - host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); - host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 3, 1, - Layer::INVALID_ID); - host_impl_->active_tree()->DidBecomeActive(); + SetupScrollAndContentsLayers(gfx::Size(20, 20)); DrawFrame(); { gfx::Vector2d scroll_delta(0, 8); @@ -4676,74 +5008,10 @@ TEST_F(LayerTreeHostImplTest, OverscrollAlways) { EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll()); } -TEST_F(LayerTreeHostImplTest, NoOverscrollOnFractionalDeviceScale) { - InputHandlerScrollResult scroll_result; - gfx::Size surface_size(980, 1439); - gfx::Size content_size(980, 1438); - 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()->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()); - - host_impl_->SetViewportSize(surface_size); - host_impl_->SetDeviceScaleFactor(device_scale_factor); - host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); - 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::SCROLL_STARTED, - host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL)); - scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, -1)); - EXPECT_FALSE(scroll_result.did_scroll); - EXPECT_FALSE(scroll_result.did_overscroll_root); - EXPECT_EQ(gfx::Vector2dF().ToString(), - host_impl_->accumulated_root_overscroll().ToString()); - - host_impl_->ScrollEnd(); - } -} - TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) { InputHandlerScrollResult scroll_result; - gfx::Size surface_size(100, 100); - 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); - scoped_ptr<LayerImpl> child = - CreateScrollableLayer(2, content_size, root_clip.get()); - - child->SetScrollClipLayer(Layer::INVALID_ID); - root->AddChild(child.Pass()); - root_clip->AddChild(root.Pass()); + SetupScrollAndContentsLayers(gfx::Size(200, 200)); - host_impl_->SetViewportSize(surface_size); - host_impl_->active_tree()->SetRootLayer(root_clip.Pass()); - 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 @@ -4904,7 +5172,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetContentsOpaque(true); layer1->SetExpectation(false, false); layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -4913,7 +5181,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetContentsOpaque(false); layer1->SetExpectation(true, false); layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -4923,7 +5191,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetOpacity(0.5f); layer1->SetExpectation(true, false); layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -4933,7 +5201,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetOpacity(0.5f); layer1->SetExpectation(true, false); layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -4955,7 +5223,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetOpacity(1.f); layer2->SetExpectation(false, false); layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -4968,7 +5236,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); layer2->SetExpectation(false, false); layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -4982,7 +5250,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); layer2->SetExpectation(false, false); layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -5002,7 +5270,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); FakeLayerTreeHostImpl::RecursiveUpdateNumChildren( host_impl_->active_tree()->root_layer()); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -5019,7 +5287,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetOpacity(0.5f); layer2->SetExpectation(true, false); layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -5034,7 +5302,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetOpacity(1.f); layer2->SetExpectation(true, false); layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -5050,7 +5318,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer2->SetOpacity(1.f); layer2->SetExpectation(false, false); layer2->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); EXPECT_TRUE(layer2->quads_appended()); @@ -5063,7 +5331,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); layer1->SetExpectation(true, false); layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -5075,7 +5343,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); layer1->SetExpectation(true, false); layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -5087,7 +5355,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); layer1->SetExpectation(true, false); layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -5100,7 +5368,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); layer1->SetExpectation(false, false); layer1->SetUpdateRect(gfx::Rect(layer1->bounds())); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(layer1->quads_appended()); host_impl_->DidDrawAllLayers(frame); @@ -5144,7 +5412,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size())); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); ASSERT_EQ(1u, frame.render_passes.size()); EXPECT_EQ(0u, CountGutterQuads(frame.render_passes[0]->quad_list)); @@ -5164,7 +5432,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size())); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); ASSERT_EQ(1u, frame.render_passes.size()); EXPECT_EQ(1u, CountGutterQuads(frame.render_passes[0]->quad_list)); @@ -5184,7 +5452,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size())); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); ASSERT_EQ(1u, frame.render_passes.size()); EXPECT_EQ(4u, CountGutterQuads(frame.render_passes[0]->quad_list)); @@ -5205,7 +5473,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size())); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); ASSERT_EQ(1u, frame.render_passes.size()); EXPECT_EQ(0u, CountGutterQuads(frame.render_passes[0]->quad_list)); @@ -5244,8 +5512,9 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { if (quad->material != DrawQuad::TEXTURE_CONTENT) continue; const TextureDrawQuad* texture_quad = TextureDrawQuad::MaterialCast(quad); - gfx::SizeF gutter_texture_size_pixels = gfx::ScaleSize( - gutter_texture_size_, host_impl_->device_scale_factor()); + gfx::SizeF gutter_texture_size_pixels = + gfx::ScaleSize(gfx::SizeF(gutter_texture_size_), + host_impl_->active_tree()->device_scale_factor()); EXPECT_EQ(texture_quad->uv_top_left.x(), texture_quad->rect.x() / gutter_texture_size_pixels.width()); EXPECT_EQ(texture_quad->uv_top_left.y(), @@ -5260,8 +5529,8 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { } gfx::Size DipSizeToPixelSize(const gfx::Size& size) { - return gfx::ToRoundedSize( - gfx::ScaleSize(size, host_impl_->device_scale_factor())); + return gfx::ScaleToRoundedSize( + size, host_impl_->active_tree()->device_scale_factor()); } DrawQuad::Material gutter_quad_material_; @@ -5291,7 +5560,7 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredScaled) { bool always_draw = false; CreateHostImpl(DefaultSettings(), CreateFakeOutputSurface(always_draw)); - host_impl_->SetDeviceScaleFactor(2.f); + host_impl_->active_tree()->SetDeviceScaleFactor(2.f); host_impl_->SetViewportSize(DipSizeToPixelSize(viewport_size_)); SetupActiveTreeLayers(); TestLayerCoversFullViewport(); @@ -5374,8 +5643,8 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) { LayerTreeHostImpl::FrameData frame; host_impl_->SetViewportSize(gfx::Size(10, 10)); - host_impl_->SetDeviceScaleFactor(1.f); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + host_impl_->active_tree()->SetDeviceScaleFactor(1.f); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(provider->TestContext3d()->reshape_called()); EXPECT_EQ(provider->TestContext3d()->width(), 10); @@ -5385,7 +5654,7 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) { provider->TestContext3d()->clear_reshape_called(); host_impl_->SetViewportSize(gfx::Size(20, 30)); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(provider->TestContext3d()->reshape_called()); EXPECT_EQ(provider->TestContext3d()->width(), 20); @@ -5394,8 +5663,8 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) { host_impl_->DidDrawAllLayers(frame); provider->TestContext3d()->clear_reshape_called(); - host_impl_->SetDeviceScaleFactor(2.f); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + host_impl_->active_tree()->SetDeviceScaleFactor(2.f); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); EXPECT_TRUE(provider->TestContext3d()->reshape_called()); EXPECT_EQ(provider->TestContext3d()->width(), 20); @@ -5425,7 +5694,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { LayerTreeHostImpl::Create( settings, this, &proxy_, &stats_instrumentation_, &shared_bitmap_manager_, NULL, &task_graph_runner_, 0); - layer_tree_host_impl->InitializeRenderer(output_surface.Pass()); + layer_tree_host_impl->InitializeRenderer(output_surface.get()); layer_tree_host_impl->WillBeginImplFrame( CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500)); @@ -5502,7 +5771,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerDoesntCreateExtraSurface) { LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); EXPECT_EQ(1u, frame.render_surface_layer_list->size()); EXPECT_EQ(1u, frame.render_passes.size()); host_impl_->DidDrawAllLayers(frame); @@ -5638,7 +5907,7 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) { harness.MustSetNoScissor(); { LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); } @@ -5651,7 +5920,7 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) { harness.MustSetScissor(0, 0, 10, 10); { LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); } @@ -5673,7 +5942,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwap) { harness.MustDrawSolidQuad(); { LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); } @@ -5688,7 +5957,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwap) { harness.MustDrawSolidQuad(); { LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); } @@ -5701,19 +5970,14 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity( Proxy* proxy, SharedBitmapManager* manager, TaskGraphRunner* task_graph_runner, - RenderingStatsInstrumentation* stats_instrumentation) { - scoped_refptr<TestContextProvider> provider(TestContextProvider::Create()); - scoped_ptr<OutputSurface> output_surface( - FakeOutputSurface::Create3d(provider)); - provider->BindToCurrentThread(); - provider->TestContext3d()->set_have_post_sub_buffer(true); - + RenderingStatsInstrumentation* stats_instrumentation, + OutputSurface* output_surface) { LayerTreeSettings settings; settings.renderer_settings.partial_swap_enabled = partial_swap; scoped_ptr<LayerTreeHostImpl> my_host_impl = LayerTreeHostImpl::Create(settings, client, proxy, stats_instrumentation, manager, nullptr, task_graph_runner, 0); - my_host_impl->InitializeRenderer(output_surface.Pass()); + my_host_impl->InitializeRenderer(output_surface); my_host_impl->WillBeginImplFrame( CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); my_host_impl->SetViewportSize(gfx::Size(100, 100)); @@ -5776,9 +6040,14 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity( TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorPartialSwap) { TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - SetupLayersForOpacity(true, this, &proxy_, &shared_bitmap_manager, - &task_graph_runner, &stats_instrumentation_); + scoped_refptr<TestContextProvider> provider(TestContextProvider::Create()); + provider->BindToCurrentThread(); + provider->TestContext3d()->set_have_post_sub_buffer(true); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(provider)); + scoped_ptr<LayerTreeHostImpl> my_host_impl = SetupLayersForOpacity( + true, this, &proxy_, &shared_bitmap_manager, &task_graph_runner, + &stats_instrumentation_, output_surface.get()); { LayerTreeHostImpl::FrameData frame; EXPECT_EQ(DRAW_SUCCESS, my_host_impl->PrepareToDraw(&frame)); @@ -5800,9 +6069,14 @@ TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorPartialSwap) { TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorNoPartialSwap) { TestSharedBitmapManager shared_bitmap_manager; TestTaskGraphRunner task_graph_runner; - scoped_ptr<LayerTreeHostImpl> my_host_impl = - SetupLayersForOpacity(false, this, &proxy_, &shared_bitmap_manager, - &task_graph_runner, &stats_instrumentation_); + scoped_refptr<TestContextProvider> provider(TestContextProvider::Create()); + provider->BindToCurrentThread(); + provider->TestContext3d()->set_have_post_sub_buffer(true); + scoped_ptr<OutputSurface> output_surface( + FakeOutputSurface::Create3d(provider)); + scoped_ptr<LayerTreeHostImpl> my_host_impl = SetupLayersForOpacity( + false, this, &proxy_, &shared_bitmap_manager, &task_graph_runner, + &stats_instrumentation_, output_surface.get()); { LayerTreeHostImpl::FrameData frame; EXPECT_EQ(DRAW_SUCCESS, my_host_impl->PrepareToDraw(&frame)); @@ -5857,7 +6131,7 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) { EXPECT_EQ(0u, context3d->NumTextures()); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); host_impl_->SwapBuffers(frame); @@ -5900,7 +6174,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { EXPECT_CALL(*mock_context, drawElements(_, _, _, _)) .Times(1); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); Mock::VerifyAndClearExpectations(&mock_context); @@ -5908,7 +6182,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { // Verify no quads are drawn when transparent background is set. host_impl_->active_tree()->set_has_transparent_background(true); host_impl_->SetFullRootLayerDamage(); - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); Mock::VerifyAndClearExpectations(&mock_context); @@ -5921,11 +6195,11 @@ class LayerTreeHostImplTestWithDelegatingRenderer return FakeOutputSurface::CreateDelegating3d(); } - void DrawFrameAndTestDamage(const gfx::RectF& expected_damage) { + void DrawFrameAndTestDamage(const gfx::Rect& expected_damage) { bool expect_to_draw = !expected_damage.IsEmpty(); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); if (!expect_to_draw) { // With no damage, we don't draw, and no quads are created. @@ -5942,12 +6216,12 @@ class LayerTreeHostImplTestWithDelegatingRenderer ASSERT_EQ(2u, root_render_pass->quad_list.size()); LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0]; - gfx::RectF expected_child_visible_rect(child->bounds()); + gfx::Rect expected_child_visible_rect(child->bounds()); 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->bounds()); + gfx::Rect expected_root_visible_rect(root->bounds()); EXPECT_EQ(expected_root_visible_rect, root_render_pass->quad_list.ElementAt(1)->visible_rect); } @@ -6025,13 +6299,13 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { // Due to precision issues (especially on Android), sometimes far // away quads can end up thinking they need AA. float device_scale_factor = 4.f / 3.f; - host_impl_->SetDeviceScaleFactor(device_scale_factor); gfx::Size root_size(2000, 1000); gfx::Size device_viewport_size = - gfx::ToCeiledSize(gfx::ScaleSize(root_size, device_scale_factor)); + gfx::ScaleToCeiledSize(root_size, device_scale_factor); host_impl_->SetViewportSize(device_viewport_size); host_impl_->CreatePendingTree(); + host_impl_->pending_tree()->SetDeviceScaleFactor(device_scale_factor); host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f / 16.f, 16.f); @@ -6048,13 +6322,12 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { root->AddChild(scoped_scrolling_layer.Pass()); gfx::Size content_layer_bounds(100000, 100); - gfx::Size pile_tile_size(3000, 3000); - scoped_refptr<FakePicturePileImpl> pile(FakePicturePileImpl::CreateFilledPile( - pile_tile_size, content_layer_bounds)); + scoped_refptr<FakeDisplayListRasterSource> raster_source( + FakeDisplayListRasterSource::CreateFilled(content_layer_bounds)); scoped_ptr<FakePictureLayerImpl> scoped_content_layer = FakePictureLayerImpl::CreateWithRasterSource(host_impl_->pending_tree(), - 3, pile); + 3, raster_source); LayerImpl* content_layer = scoped_content_layer.get(); scrolling_layer->AddChild(scoped_content_layer.Pass()); content_layer->SetBounds(content_layer_bounds); @@ -6066,6 +6339,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { scrolling_layer->SetScrollClipLayer(root->id()); scrolling_layer->PushScrollOffsetFromMainThread(scroll_offset); + host_impl_->pending_tree()->BuildPropertyTreesForTesting(); host_impl_->ActivateSyncTree(); bool update_lcd_text = false; @@ -6073,7 +6347,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { ASSERT_EQ(1u, host_impl_->active_tree()->RenderSurfaceLayerList().size()); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); ASSERT_EQ(1u, frame.render_passes.size()); ASSERT_LE(1u, frame.render_passes[0]->quad_list.size()); @@ -6082,7 +6356,8 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) { bool clipped = false, force_aa = false; gfx::QuadF device_layer_quad = MathUtil::MapQuad( quad->shared_quad_state->quad_to_target_transform, - gfx::QuadF(quad->shared_quad_state->visible_quad_layer_rect), &clipped); + gfx::QuadF(gfx::RectF(quad->shared_quad_state->visible_quad_layer_rect)), + &clipped); EXPECT_FALSE(clipped); bool antialiased = GLRendererWithSetupQuadForAntialiasing::ShouldAntialiasQuad( @@ -6110,7 +6385,7 @@ TEST_F(CompositorFrameMetadataTest, CompositorFrameAckCountsAsSwapComplete) { SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1)); { LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); } @@ -6128,9 +6403,9 @@ class CountingSoftwareDevice : public SoftwareOutputDevice { ++frames_began_; return SoftwareOutputDevice::BeginPaint(damage_rect); } - void EndPaint(SoftwareFrameData* frame_data) override { + void EndPaint() override { + SoftwareOutputDevice::EndPaint(); ++frames_ended_; - SoftwareOutputDevice::EndPaint(frame_data); } int frames_began_, frames_ended_; @@ -6204,7 +6479,7 @@ TEST_F(LayerTreeHostImplTest, SetupRootLayerImpl(root_layer.Pass()); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -6220,9 +6495,9 @@ TEST_F(LayerTreeHostImplTest, DefaultMemoryAllocation) { settings, this, &proxy_, &stats_instrumentation_, &shared_bitmap_manager_, &gpu_memory_buffer_manager_, &task_graph_runner_, 0); - scoped_ptr<OutputSurface> output_surface( - FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create())); - host_impl_->InitializeRenderer(output_surface.Pass()); + output_surface_ = + FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create()); + host_impl_->InitializeRenderer(output_surface_.get()); EXPECT_LT(0ul, host_impl_->memory_allocation_limit_bytes()); } @@ -6283,7 +6558,8 @@ class LayerTreeHostImplTestPrepareTiles : public LayerTreeHostImplTest { new FakeLayerTreeHostImpl(LayerTreeSettings(), &proxy_, &shared_bitmap_manager_, &task_graph_runner_); host_impl_.reset(fake_host_impl_); - host_impl_->InitializeRenderer(CreateOutputSurface()); + output_surface_ = CreateOutputSurface(); + host_impl_->InitializeRenderer(output_surface_.get()); host_impl_->SetViewportSize(gfx::Size(10, 10)); } @@ -6381,10 +6657,12 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) { requests.push_back(CopyOutputRequest::CreateRequest( base::Bind(&ShutdownReleasesContext_Callback))); - host_impl_->active_tree()->root_layer()->PassCopyRequests(&requests); + LayerImpl* root = host_impl_->active_tree()->root_layer(); + root->PassCopyRequests(&requests); + root->set_num_layer_or_descendant_with_copy_request(1); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); @@ -6447,7 +6725,7 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) { } } -TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) { +TEST_F(LayerTreeHostImplTest, TouchFlingShouldContinueScrollingCurrentLayer) { // Scroll a child layer beyond its maximum scroll range and make sure the // the scroll doesn't bubble up to the parent layer. gfx::Size surface_size(10, 10); @@ -6489,40 +6767,35 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) { ScrollInfoContains(*scroll_info, grand_child->id(), scroll_delta)); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); - // The child should have received the bubbled delta, but the locked - // scrolling layer should remain set as the grand child. - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); + // The locked scrolling layer should remain set as the grand child. + EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); scroll_info = host_impl_->ProcessScrollDeltas(); - ASSERT_EQ(2u, scroll_info->scrolls.size()); + ASSERT_EQ(1u, scroll_info->scrolls.size()); EXPECT_TRUE( ScrollInfoContains(*scroll_info, grand_child->id(), scroll_delta)); - EXPECT_TRUE(ScrollInfoContains(*scroll_info, child->id(), scroll_delta)); + ExpectNone(*scroll_info, child->id()); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); - // 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::SCROLL_STARTED, host_impl_->FlingScrollBegin()); - EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); - EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child); + EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); - // The child should have scrolled up to its limit. + // The child should not have scrolled. scroll_info = host_impl_->ProcessScrollDeltas(); - ASSERT_EQ(2u, scroll_info->scrolls.size()); + ASSERT_EQ(1u, scroll_info->scrolls.size()); EXPECT_TRUE( ScrollInfoContains(*scroll_info, grand_child->id(), scroll_delta)); - EXPECT_TRUE(ScrollInfoContains(*scroll_info, child->id(), - scroll_delta + scroll_delta)); + ExpectNone(*scroll_info, child->id()); // As the locked layer is at it's limit, no further scrolling can occur. EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); - EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); host_impl_->ScrollEnd(); } } -TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) { - // When flinging via wheel, the root should eventually scroll (we should - // bubble). +TEST_F(LayerTreeHostImplTest, WheelFlingShouldntBubble) { + // When flinging via wheel, we shouldn't bubble. gfx::Size surface_size(10, 10); gfx::Size content_size(20, 20); scoped_ptr<LayerImpl> root_clip = @@ -6556,10 +6829,9 @@ TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) { scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - // The root should have scrolled. - ASSERT_EQ(2u, scroll_info->scrolls.size()); - EXPECT_TRUE(ScrollInfoContains(*scroll_info.get(), root_scroll_id, - gfx::Vector2d(0, 10))); + // The root shouldn't have scrolled. + ASSERT_EQ(1u, scroll_info->scrolls.size()); + ExpectNone(*scroll_info.get(), root_scroll_id); } } @@ -6776,12 +7048,12 @@ TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) { ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, 0); scoped_ptr<SwapPromise> swap_promise( new LatencyInfoSwapPromise(latency_info)); - host_impl_->active_tree()->QueueSwapPromise(swap_promise.Pass()); + host_impl_->active_tree()->QueuePinnedSwapPromise(swap_promise.Pass()); host_impl_->SetNeedsRedraw(); gfx::Rect full_frame_damage(host_impl_->DrawViewportSize()); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); EXPECT_TRUE(host_impl_->SwapBuffers(frame)); @@ -6828,7 +7100,7 @@ TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToCompositorFrameMetadata) { gfx::Rect full_frame_damage(host_impl_->DrawViewportSize()); LayerTreeHostImpl::FrameData frame; - EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame)); + EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame)); host_impl_->DrawLayers(&frame); host_impl_->DidDrawAllLayers(frame); EXPECT_TRUE(host_impl_->SwapBuffers(frame)); @@ -6981,8 +7253,12 @@ const int LayerTreeHostImplWithTopControlsTest::top_controls_height_ = 50; TEST_F(LayerTreeHostImplWithTopControlsTest, NoIdleAnimations) { SetupScrollAndContentsLayers(gfx::Size(100, 100)) ->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 10)); - host_impl_->Animate(base::TimeTicks()); + BeginFrameArgs begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_FALSE(did_request_redraw_); + host_impl_->DidFinishImplFrame(); } TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsHeightIsCommitted) { @@ -7019,6 +7295,7 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationScheduling) { } TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { + InputHandlerScrollResult result; LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 200)); host_impl_->SetViewportSize(gfx::Size(100, 100)); host_impl_->top_controls_manager()->UpdateTopControlsState( @@ -7034,8 +7311,9 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { // 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); + result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)); + EXPECT_EQ(result.unused_scroll_delta, gfx::Vector2d(0, 0)); + EXPECT_TRUE(result.did_scroll); EXPECT_FLOAT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), @@ -7044,8 +7322,9 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { // Scroll across the boundary const float content_scroll = 20; offset = residue + content_scroll; - EXPECT_TRUE( - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); + result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)); + EXPECT_TRUE(result.did_scroll); + EXPECT_EQ(result.unused_scroll_delta, gfx::Vector2d(0, 0)); EXPECT_EQ(-top_controls_height_, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF(0, content_scroll).ToString(), @@ -7053,8 +7332,9 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { // Now scroll back to the top of the content offset = -content_scroll; - EXPECT_TRUE( - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); + result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)); + EXPECT_TRUE(result.did_scroll); + EXPECT_EQ(result.unused_scroll_delta, gfx::Vector2d(0, 0)); EXPECT_EQ(-top_controls_height_, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), @@ -7062,15 +7342,17 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { // And scroll the top controls completely into view offset = -top_controls_height_; - EXPECT_TRUE( - host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll); + result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)); + EXPECT_TRUE(result.did_scroll); + EXPECT_EQ(result.unused_scroll_delta, gfx::Vector2d(0, 0)); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().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); + result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)); + EXPECT_FALSE(result.did_scroll); + EXPECT_EQ(result.unused_scroll_delta, gfx::Vector2d(0, -50)); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->CurrentScrollOffset().ToString()); @@ -7078,6 +7360,37 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) { host_impl_->ScrollEnd(); } +TEST_F(LayerTreeHostImplWithTopControlsTest, WheelUnhandledByTopControls) { + SetupScrollAndContentsLayers(gfx::Size(100, 200)); + host_impl_->SetViewportSize(gfx::Size(50, 100)); + host_impl_->active_tree()->set_top_controls_shrink_blink_size(true); + host_impl_->top_controls_manager()->UpdateTopControlsState(BOTH, SHOWN, + false); + DrawFrame(); + + LayerImpl* viewport_layer = host_impl_->InnerViewportScrollLayer(); + + EXPECT_EQ(InputHandler::SCROLL_STARTED, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL)); + EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(), viewport_layer->CurrentScrollOffset()); + + // Wheel scrolls should not affect the top controls, and should pass + // directly through to the viewport. + const float delta = top_controls_height_; + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, delta)).did_scroll); + EXPECT_FLOAT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, delta), + viewport_layer->CurrentScrollOffset()); + + EXPECT_TRUE( + host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, delta)).did_scroll); + EXPECT_FLOAT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, delta * 2), + viewport_layer->CurrentScrollOffset()); +} + TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAtOrigin) { LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 200)); host_impl_->SetViewportSize(gfx::Size(100, 200)); @@ -7114,7 +7427,8 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAtOrigin) { // The top controls should properly animate until finished, despite the scroll // offset being at the origin. - base::TimeTicks animation_time = base::TimeTicks::Now(); + BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, base::TimeTicks::Now()); while (did_request_animate_) { did_request_redraw_ = false; did_request_animate_ = false; @@ -7123,8 +7437,9 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAtOrigin) { float old_offset = host_impl_->top_controls_manager()->ControlsTopOffset(); - animation_time += base::TimeDelta::FromMilliseconds(5); - host_impl_->Animate(animation_time); + begin_frame_args.frame_time += base::TimeDelta::FromMilliseconds(5); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); EXPECT_EQ(gfx::Vector2dF().ToString(), scroll_layer->CurrentScrollOffset().ToString()); @@ -7142,6 +7457,7 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAtOrigin) { EXPECT_TRUE(host_impl_->top_controls_manager()->animation()); EXPECT_TRUE(did_request_animate_); } + host_impl_->DidFinishImplFrame(); } EXPECT_FALSE(host_impl_->top_controls_manager()->animation()); } @@ -7184,7 +7500,8 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAfterScroll) { EXPECT_FALSE(did_request_commit_); // Animate the top controls to the limit. - base::TimeTicks animation_time = base::TimeTicks::Now(); + BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, base::TimeTicks::Now()); while (did_request_animate_) { did_request_redraw_ = false; did_request_animate_ = false; @@ -7193,8 +7510,9 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAfterScroll) { float old_offset = host_impl_->top_controls_manager()->ControlsTopOffset(); - animation_time += base::TimeDelta::FromMilliseconds(5); - host_impl_->Animate(animation_time); + begin_frame_args.frame_time += base::TimeDelta::FromMilliseconds(5); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); float new_offset = host_impl_->top_controls_manager()->ControlsTopOffset(); @@ -7203,6 +7521,7 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationAfterScroll) { EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); } + host_impl_->DidFinishImplFrame(); } EXPECT_FALSE(host_impl_->top_controls_manager()->animation()); EXPECT_EQ(-top_controls_height_, @@ -7248,7 +7567,8 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, EXPECT_FALSE(did_request_commit_); // Animate the top controls to the limit. - base::TimeTicks animation_time = base::TimeTicks::Now(); + BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, base::TimeTicks::Now()); while (did_request_animate_) { did_request_redraw_ = false; did_request_animate_ = false; @@ -7256,8 +7576,9 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, float old_offset = host_impl_->top_controls_manager()->ControlsTopOffset(); - animation_time += base::TimeDelta::FromMilliseconds(5); - host_impl_->Animate(animation_time); + begin_frame_args.frame_time += base::TimeDelta::FromMilliseconds(5); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); float new_offset = host_impl_->top_controls_manager()->ControlsTopOffset(); @@ -7265,6 +7586,7 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, EXPECT_TRUE(did_request_redraw_); EXPECT_TRUE(did_request_commit_); } + host_impl_->DidFinishImplFrame(); } EXPECT_FALSE(host_impl_->top_controls_manager()->animation()); EXPECT_EQ(-top_controls_height_, @@ -7273,7 +7595,7 @@ TEST_F(LayerTreeHostImplWithTopControlsTest, TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsScrollDeltaInOverScroll) { - // test varifies that the overscroll delta should not have accumulated in + // Verifies 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)); @@ -7402,9 +7724,6 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, ScrollBothInnerAndOuterLayer) { 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(); @@ -7416,8 +7735,7 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, ScrollBothInnerAndOuterLayer) { gfx::ScrollOffset current_offset(70.f, 100.f); - scroll_delegate.set_getter_return_value(current_offset); - host_impl_->OnRootLayerDelegatedScrollOffsetChanged(); + host_impl_->SetSynchronousInputHandlerRootScrollOffset(current_offset); EXPECT_EQ(gfx::ScrollOffset(25.f, 40.f), inner_scroll->MaxScrollOffset()); EXPECT_EQ(gfx::ScrollOffset(50.f, 80.f), outer_scroll->MaxScrollOffset()); @@ -7431,9 +7749,9 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, ScrollBothInnerAndOuterLayer) { } TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) { - gfx::Size content_size = gfx::Size(100, 160); - gfx::Size outer_viewport = gfx::Size(50, 80); - gfx::Size inner_viewport = gfx::Size(25, 40); + gfx::Size content_size = gfx::Size(200, 320); + gfx::Size outer_viewport = gfx::Size(100, 160); + gfx::Size inner_viewport = gfx::Size(50, 80); SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport); @@ -7446,17 +7764,19 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) { 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 + // Scrolling the viewport always sets the outer scroll layer as the + // currently scrolling layer. EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE)); - EXPECT_EQ(outer_scroll, host_impl_->CurrentlyScrollingLayer()); + EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); - EXPECT_EQ(outer_scroll, host_impl_->CurrentlyScrollingLayer()); + EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); - gfx::Vector2d scroll_delta(inner_viewport.width(), inner_viewport.height()); + gfx::Vector2d scroll_delta(inner_viewport.width() / 2.f, + inner_viewport.height() / 2.f); host_impl_->ScrollBy(gfx::Point(), scroll_delta); - outer_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y()); - EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), outer_scroll); + inner_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y()); + EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); host_impl_->ScrollEnd(); EXPECT_EQ(nullptr, host_impl_->CurrentlyScrollingLayer()); @@ -7464,20 +7784,20 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) { 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. + // Fling past the inner viewport boundry, make sure outer viewport scrolls. EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE)); - EXPECT_EQ(outer_scroll, host_impl_->CurrentlyScrollingLayer()); + EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); - EXPECT_EQ(outer_scroll, host_impl_->CurrentlyScrollingLayer()); + EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); host_impl_->ScrollBy(gfx::Point(), scroll_delta); - outer_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y()); - EXPECT_EQ(outer_scroll, host_impl_->CurrentlyScrollingLayer()); + inner_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y()); + EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); host_impl_->ScrollBy(gfx::Point(), scroll_delta); - inner_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y()); - EXPECT_EQ(outer_scroll, host_impl_->CurrentlyScrollingLayer()); + outer_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y()); + EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); host_impl_->ScrollEnd(); EXPECT_EQ(nullptr, host_impl_->CurrentlyScrollingLayer()); @@ -7489,9 +7809,9 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) { TEST_F(LayerTreeHostImplVirtualViewportTest, DiagonalScrollBubblesPerfectlyToInner) { - gfx::Size content_size = gfx::Size(100, 160); - gfx::Size outer_viewport = gfx::Size(50, 80); - gfx::Size inner_viewport = gfx::Size(25, 40); + gfx::Size content_size = gfx::Size(200, 320); + gfx::Size outer_viewport = gfx::Size(100, 160); + gfx::Size inner_viewport = gfx::Size(50, 80); SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport); @@ -7504,7 +7824,7 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, 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. + // Make sure the scroll goes to the inner viewport first. EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE)); EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin()); @@ -7512,9 +7832,10 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, InputHandler::GESTURE)); // Scroll near the edge of the outer viewport. - gfx::Vector2d scroll_delta(inner_viewport.width(), inner_viewport.height()); + gfx::Vector2d scroll_delta(inner_viewport.width() / 2.f, + inner_viewport.height() / 2.f); host_impl_->ScrollBy(gfx::Point(), scroll_delta); - outer_expected += scroll_delta; + inner_expected += scroll_delta; EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(), InputHandler::GESTURE)); @@ -7539,7 +7860,7 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, } TEST_F(LayerTreeHostImplVirtualViewportTest, - TouchFlingCanLockToViewportLayerAfterBubbling) { + TouchFlingDoesntSwitchScrollingLayer) { gfx::Size content_size = gfx::Size(100, 160); gfx::Size outer_viewport = gfx::Size(50, 80); gfx::Size inner_viewport = gfx::Size(25, 40); @@ -7572,25 +7893,23 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, ScrollInfoContains(*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. + // The fling have no effect on the currently scrolling 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_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll); EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(), InputHandler::GESTURE)); - // The inner viewport should have scrolled up to its limit. + // The inner viewport shouldn't have scrolled. scroll_info = host_impl_->ProcessScrollDeltas(); - ASSERT_EQ(2u, scroll_info->scrolls.size()); + ASSERT_EQ(1u, scroll_info->scrolls.size()); EXPECT_TRUE( ScrollInfoContains(*scroll_info, child_scroll->id(), scroll_delta)); - EXPECT_TRUE( - ScrollInfoContains(*scroll_info, inner_scroll->id(), scroll_delta)); + ExpectNone(*scroll_info, inner_scroll->id()); // 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); + EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll); host_impl_->ScrollEnd(); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt( gfx::Point(), InputHandler::GESTURE)); @@ -7625,6 +7944,32 @@ TEST_F(LayerTreeHostImplVirtualViewportTest, host_impl_->ScrollEnd(); } +TEST_F(LayerTreeHostImplVirtualViewportTest, + NoOverscrollWhenInnerViewportCantScroll) { + InputHandlerScrollResult scroll_result; + 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); + DrawFrame(); + + // Make inner viewport unscrollable. + LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer(); + inner_scroll->set_user_scrollable_horizontal(false); + inner_scroll->set_user_scrollable_vertical(false); + + // Ensure inner viewport doesn't react to scrolls (test it's unscrollable). + EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll->CurrentScrollOffset()); + EXPECT_EQ(InputHandler::SCROLL_STARTED, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE)); + scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 100)); + EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll->CurrentScrollOffset()); + + // When inner viewport is unscrollable, a fling gives zero overscroll. + EXPECT_FALSE(scroll_result.did_overscroll_root); + EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll()); +} + class LayerTreeHostImplWithImplicitLimitsTest : public LayerTreeHostImplTest { public: void SetUp() override { @@ -7684,17 +8029,26 @@ TEST_F(LayerTreeHostImplTest, ScrollAnimated) { base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromMilliseconds(100); + BeginFrameArgs begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); + EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50))); LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer(); - host_impl_->Animate(start_time); + begin_frame_args.frame_time = start_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); host_impl_->UpdateAnimationState(true); EXPECT_EQ(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset()); + host_impl_->DidFinishImplFrame(); - host_impl_->Animate(start_time + base::TimeDelta::FromMilliseconds(50)); + begin_frame_args.frame_time = + start_time + base::TimeDelta::FromMilliseconds(50); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); host_impl_->UpdateAnimationState(true); float y = scrolling_layer->CurrentScrollOffset().y(); @@ -7703,20 +8057,29 @@ TEST_F(LayerTreeHostImplTest, ScrollAnimated) { // Update target. EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50))); + host_impl_->DidFinishImplFrame(); - host_impl_->Animate(start_time + base::TimeDelta::FromMilliseconds(200)); + begin_frame_args.frame_time = + start_time + base::TimeDelta::FromMilliseconds(200); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); host_impl_->UpdateAnimationState(true); y = scrolling_layer->CurrentScrollOffset().y(); EXPECT_TRUE(y > 50 && y < 100); EXPECT_EQ(scrolling_layer, host_impl_->CurrentlyScrollingLayer()); + host_impl_->DidFinishImplFrame(); - host_impl_->Animate(start_time + base::TimeDelta::FromMilliseconds(250)); + begin_frame_args.frame_time = + start_time + base::TimeDelta::FromMilliseconds(250); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); host_impl_->UpdateAnimationState(true); EXPECT_VECTOR_EQ(gfx::ScrollOffset(0, 100), scrolling_layer->CurrentScrollOffset()); EXPECT_EQ(NULL, host_impl_->CurrentlyScrollingLayer()); + host_impl_->DidFinishImplFrame(); } // Evolved from LayerTreeHostImplTest.ScrollAnimated. @@ -7727,17 +8090,26 @@ TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimated) { base::TimeTicks start_time = base::TimeTicks() + base::TimeDelta::FromMilliseconds(100); + BeginFrameArgs begin_frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); + EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50))); LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer(); - host_impl_->Animate(start_time); + begin_frame_args.frame_time = start_time; + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); host_impl_->UpdateAnimationState(true); EXPECT_EQ(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset()); + host_impl_->DidFinishImplFrame(); - host_impl_->Animate(start_time + base::TimeDelta::FromMilliseconds(50)); + begin_frame_args.frame_time = + start_time + base::TimeDelta::FromMilliseconds(50); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); host_impl_->UpdateAnimationState(true); float y = scrolling_layer->CurrentScrollOffset().y(); @@ -7746,37 +8118,46 @@ TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimated) { // Update target. EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50))); + host_impl_->DidFinishImplFrame(); - host_impl_->Animate(start_time + base::TimeDelta::FromMilliseconds(200)); + begin_frame_args.frame_time = + start_time + base::TimeDelta::FromMilliseconds(200); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); host_impl_->UpdateAnimationState(true); y = scrolling_layer->CurrentScrollOffset().y(); EXPECT_TRUE(y > 50 && y < 100); EXPECT_EQ(scrolling_layer, host_impl_->CurrentlyScrollingLayer()); + host_impl_->DidFinishImplFrame(); - host_impl_->Animate(start_time + base::TimeDelta::FromMilliseconds(250)); + begin_frame_args.frame_time = + start_time + base::TimeDelta::FromMilliseconds(250); + host_impl_->WillBeginImplFrame(begin_frame_args); + host_impl_->Animate(); host_impl_->UpdateAnimationState(true); EXPECT_VECTOR_EQ(gfx::ScrollOffset(0, 100), scrolling_layer->CurrentScrollOffset()); EXPECT_EQ(NULL, host_impl_->CurrentlyScrollingLayer()); + host_impl_->DidFinishImplFrame(); } TEST_F(LayerTreeHostImplTest, InvalidLayerNotAddedToRasterQueue) { host_impl_->CreatePendingTree(); Region empty_invalidation; - scoped_refptr<RasterSource> pile_with_tiles( - FakePicturePileImpl::CreateFilledPileWithDefaultTileSize( - gfx::Size(10, 10))); + scoped_refptr<RasterSource> raster_source_with_tiles( + FakeDisplayListRasterSource::CreateFilled(gfx::Size(10, 10))); 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()->AddTiling(1.0f, raster_source_with_tiles); + layer->UpdateRasterSource(raster_source_with_tiles, &empty_invalidation, + nullptr); layer->tilings()->tiling_at(0)->set_resolution( TileResolution::HIGH_RESOLUTION); layer->tilings()->tiling_at(0)->CreateAllTilesForTesting(); @@ -7862,7 +8243,7 @@ TEST_F(LayerTreeHostImplTest, WheelScrollWithPageScaleFactorOnInnerLayer) { { host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, min_page_scale, max_page_scale); - host_impl_->SetPageScaleOnActiveTree(page_scale_factor); + host_impl_->active_tree()->SetPageScaleOnActiveTree(page_scale_factor); scroll_layer->SetScrollDelta(gfx::Vector2d()); float page_scale_delta = 2.f; @@ -8054,8 +8435,6 @@ class FakeVideoFrameController : public VideoFrameController { }; TEST_F(LayerTreeHostImplTest, AddVideoFrameControllerInsideFrame) { - host_impl_->DidFinishImplFrame(); - BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); FakeVideoFrameController controller; @@ -8079,8 +8458,6 @@ TEST_F(LayerTreeHostImplTest, AddVideoFrameControllerInsideFrame) { } TEST_F(LayerTreeHostImplTest, AddVideoFrameControllerOutsideFrame) { - host_impl_->DidFinishImplFrame(); - BeginFrameArgs begin_frame_args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); FakeVideoFrameController controller; @@ -8169,7 +8546,8 @@ class MockReclaimResourcesOutputSurface : public FakeOutputSurface { public: static scoped_ptr<MockReclaimResourcesOutputSurface> Create3d() { return make_scoped_ptr(new MockReclaimResourcesOutputSurface( - TestContextProvider::Create(), TestContextProvider::Create(), false)); + TestContextProvider::Create(), TestContextProvider::CreateWorker(), + false)); } MOCK_METHOD0(ForceReclaimResources, void()); diff --git a/chromium/cc/trees/layer_tree_host_perftest.cc b/chromium/cc/trees/layer_tree_host_perftest.cc index eb8183fadf2..845b1305e59 100644 --- a/chromium/cc/trees/layer_tree_host_perftest.cc +++ b/chromium/cc/trees/layer_tree_host_perftest.cc @@ -44,7 +44,8 @@ class LayerTreeHostPerfTest : public LayerTreeTest { } void InitializeSettings(LayerTreeSettings* settings) override { - settings->renderer_settings.disable_gpu_vsync = true; + settings->wait_for_beginframe_interval = false; + settings->renderer_settings.disable_display_vsync = true; } void BeginTest() override { diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc index e2715e3907c..688c9fbc1ca 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc @@ -6,6 +6,8 @@ #include "cc/layers/solid_color_layer.h" #include "cc/test/layer_tree_pixel_resource_test.h" #include "cc/test/pixel_comparator.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkSurface.h" #if !defined(OS_ANDROID) @@ -127,21 +129,23 @@ class LayerTreeHostBlendingPixelTest : public LayerTreeHostPixelResourceTest { // Draw the backdrop with horizontal lanes. const int kLaneWidth = width; const int kLaneHeight = height / kCSSTestColorsCount; - SkBitmap backing_store; - backing_store.allocN32Pixels(width, height); - SkCanvas canvas(backing_store); - canvas.clear(SK_ColorTRANSPARENT); + skia::RefPtr<SkSurface> backing_store = + skia::AdoptRef(SkSurface::NewRasterN32Premul(width, height)); + SkCanvas* canvas = backing_store->getCanvas(); + canvas->clear(SK_ColorTRANSPARENT); for (int i = 0; i < kCSSTestColorsCount; ++i) { SkPaint paint; paint.setColor(kCSSTestColors[i]); - canvas.drawRect( + canvas->drawRect( SkRect::MakeXYWH(0, i * kLaneHeight, kLaneWidth, kLaneHeight), paint); } scoped_refptr<PictureImageLayer> layer = PictureImageLayer::Create(layer_settings()); layer->SetIsDrawable(true); layer->SetBounds(gfx::Size(width, height)); - layer->SetBitmap(backing_store); + skia::RefPtr<const SkImage> image = + skia::AdoptRef(backing_store->newImageSnapshot()); + layer->SetImage(image.Pass()); return layer; } @@ -154,18 +158,19 @@ class LayerTreeHostBlendingPixelTest : public LayerTreeHostPixelResourceTest { mask->SetIsMask(true); mask->SetBounds(bounds); - SkBitmap bitmap; - bitmap.allocN32Pixels(bounds.width(), bounds.height()); - SkCanvas canvas(bitmap); + skia::RefPtr<SkSurface> surface = skia::AdoptRef( + SkSurface::NewRasterN32Premul(bounds.width(), bounds.height())); + SkCanvas* canvas = surface->getCanvas(); SkPaint paint; paint.setColor(SK_ColorWHITE); - canvas.clear(SK_ColorTRANSPARENT); - canvas.drawRect(SkRect::MakeXYWH(kMaskOffset, - kMaskOffset, - bounds.width() - kMaskOffset * 2, - bounds.height() - kMaskOffset * 2), - paint); - mask->SetBitmap(bitmap); + canvas->clear(SK_ColorTRANSPARENT); + canvas->drawRect(SkRect::MakeXYWH(kMaskOffset, kMaskOffset, + bounds.width() - kMaskOffset * 2, + bounds.height() - kMaskOffset * 2), + paint); + skia::RefPtr<const SkImage> image = + skia::AdoptRef(surface->newImageSnapshot()); + mask->SetImage(image.Pass()); layer->SetMaskLayer(mask.get()); } @@ -272,7 +277,7 @@ class LayerTreeHostBlendingPixelTest : public LayerTreeHostPixelResourceTest { }; TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) { - RunBlendingWithRootPixelTestType(GL_ASYNC_UPLOAD_2D_DRAW); + RunBlendingWithRootPixelTestType(GL_ZERO_COPY_RECT_DRAW); } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_Software) { @@ -284,7 +289,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) { const int kLaneHeight = kLaneWidth; const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth; const int kRootHeight = 2 * kLaneWidth + kLaneHeight; - InitializeFromTestCase(GL_ASYNC_UPLOAD_2D_DRAW); + InitializeFromTestCase(GL_ZERO_COPY_RECT_DRAW); scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSOrange); @@ -309,7 +314,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) { } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_GL) { - RunBlendingWithTransparentPixelTestType(GL_ASYNC_UPLOAD_2D_DRAW); + RunBlendingWithTransparentPixelTestType(GL_ZERO_COPY_RECT_DRAW); } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_Software) { @@ -318,7 +323,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_Software) { // Tests for render passes TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass.png"), 0); } @@ -328,7 +333,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_Software) { } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass.png"), kUseAntialiasing); } @@ -340,7 +345,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_Software) { } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMask_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks); } @@ -352,7 +357,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMaskAA_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks | kUseAntialiasing); } @@ -365,7 +370,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrix_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass.png"), kUseColorMatrix); } @@ -377,7 +382,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrixAA_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass.png"), kUseAntialiasing | kUseColorMatrix); } @@ -391,7 +396,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMaskColorMatrix_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks | kUseColorMatrix); } @@ -405,7 +410,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMaskColorMatrixAA_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks | kUseAntialiasing | kUseColorMatrix); } @@ -419,20 +424,20 @@ TEST_F(LayerTreeHostBlendingPixelTest, // Tests for render passes forcing shaders for all the blend modes. TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShaders_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass.png"), kForceShaders); } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersAA_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass.png"), kUseAntialiasing | kForceShaders); } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersWithMask_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks | kForceShaders); } @@ -446,7 +451,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersWithMaskAA_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks | kUseAntialiasing | kForceShaders); } @@ -460,21 +465,21 @@ TEST_F(LayerTreeHostBlendingPixelTest, TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersColorMatrix_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass.png"), kUseColorMatrix | kForceShaders); } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersColorMatrixAA_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass.png"), kUseAntialiasing | kUseColorMatrix | kForceShaders); } TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersWithMaskColorMatrix_GL) { - RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW, + RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks | kUseColorMatrix | kForceShaders); } @@ -489,7 +494,7 @@ TEST_F(LayerTreeHostBlendingPixelTest, TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersWithMaskColorMatrixAA_GL) { RunBlendingWithRenderPass( - GL_ASYNC_UPLOAD_2D_DRAW, + GL_ZERO_COPY_RECT_DRAW, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks | kUseAntialiasing | kUseColorMatrix | kForceShaders); } diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc index dd3cf733144..a98b08bbdf7 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc @@ -277,16 +277,87 @@ 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); +class ImageScaledBackgroundFilter : public LayerTreeHostFiltersPixelTest { + protected: + void RunPixelTestType(PixelTestType test_type, base::FilePath image_name) { + 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); - gfx::Rect rect(50, 50, 100, 100); + 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 + + RunPixelTest(test_type, background, image_name); + } +}; + +TEST_F(ImageScaledBackgroundFilter, ImageFilterScaled_GL) { + RunPixelTestType(PIXEL_TEST_GL, + base::FilePath(FILE_PATH_LITERAL( + "background_filter_on_scaled_layer_gl.png"))); +} + +TEST_F(ImageScaledBackgroundFilter, ImageFilterScaled_Software) { + RunPixelTestType(PIXEL_TEST_SOFTWARE, + base::FilePath(FILE_PATH_LITERAL( + "background_filter_on_scaled_layer_sw.png"))); +} + +class ImageBackgroundFilter : public LayerTreeHostFiltersPixelTest { + protected: + void RunPixelTestType(PixelTestType test_type, base::FilePath image_name) { + // Add a white background with a rotated red rect in the center. + 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); + CreateSolidColorLayer(rect, SK_ColorRED); gfx::Transform transform; transform.Translate(rect.width() / 2.0, rect.height() / 2.0); @@ -296,42 +367,50 @@ TEST_F(LayerTreeHostFiltersPixelTest, ImageFilterScaled_GL) { background->AddChild(layer); - rect.Inset(kInset, kInset); - } + // Add a slightly transparent blue layer. + scoped_refptr<SolidColorLayer> filter = + CreateSolidColorLayer(gfx::Rect(100, 0, 100, 200), 0x220000FF); - scoped_refptr<SolidColorLayer> filter = - CreateSolidColorLayer(gfx::Rect(100, 0, 100, 200), SK_ColorTRANSPARENT); + // Add some rotation so that we can see that it blurs only under the layer. + gfx::Transform transform_filter; + transform_filter.RotateAboutZAxis(10.0); + filter->SetTransform(transform_filter); - background->AddChild(filter); + 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); + // Add a blur filter to the blue layer. + FilterOperations filters; + filters.Append(FilterOperation::CreateBlurFilter(5.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)); + // Windows has 994 pixels off by at most 2: crbug.com/225027 + float percentage_pixels_large_error = 2.4825f; // 994px / (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"))); + RunPixelTest(test_type, background, image_name); + } +}; + +TEST_F(ImageBackgroundFilter, BackgroundFilterRotated_GL) { + RunPixelTestType( + PIXEL_TEST_GL, + base::FilePath(FILE_PATH_LITERAL("background_filter_rotated_gl.png"))); +} + +TEST_F(ImageBackgroundFilter, BackgroundFilterRotated_Software) { + RunPixelTestType( + PIXEL_TEST_SOFTWARE, + base::FilePath(FILE_PATH_LITERAL("background_filter_rotated_sw.png"))); } class ImageScaledRenderSurface : public LayerTreeHostFiltersPixelTest { diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc index 6a4bebd4f35..ce9dde54c4d 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc @@ -7,8 +7,13 @@ #include "cc/layers/picture_image_layer.h" #include "cc/layers/picture_layer.h" #include "cc/layers/solid_color_layer.h" +#include "cc/playback/display_item_list_settings.h" +#include "cc/playback/drawing_display_item.h" #include "cc/test/layer_tree_pixel_resource_test.h" #include "cc/test/pixel_comparator.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" +#include "third_party/skia/include/core/SkSurface.h" #if !defined(OS_ANDROID) @@ -25,10 +30,25 @@ class MaskContentLayerClient : public ContentLayerClient { ~MaskContentLayerClient() override {} bool FillsBoundsCompletely() const override { return false; } + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } + // TODO(pdr): Remove PaintContents as all calls should go through + // PaintContentsToDisplayList. void PaintContents(SkCanvas* canvas, const gfx::Rect& rect, PaintingControlSetting picture_control) override { + scoped_refptr<DisplayItemList> contents = + PaintContentsToDisplayList(rect, picture_control); + contents->Raster(canvas, nullptr, rect, 1.0f); + } + + scoped_refptr<DisplayItemList> PaintContentsToDisplayList( + const gfx::Rect& clip, + PaintingControlSetting picture_control) override { + SkPictureRecorder recorder; + skia::RefPtr<SkCanvas> canvas = skia::SharePtr( + recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_)))); + SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(2)); @@ -44,13 +64,17 @@ class MaskContentLayerClient : public ContentLayerClient { paint); inset_rect.Inset(3, 3, 2, 2); } - } - scoped_refptr<DisplayItemList> PaintContentsToDisplayList( - const gfx::Rect& clip, - PaintingControlSetting picture_control) override { - NOTIMPLEMENTED(); - return nullptr; + scoped_refptr<DisplayItemList> display_list = + DisplayItemList::Create(clip, DisplayItemListSettings()); + auto* item = display_list->CreateAndAppendItem<DrawingDisplayItem>(); + + skia::RefPtr<SkPicture> picture = + skia::AdoptRef(recorder.endRecordingAsPicture()); + item->SetNew(picture.Pass()); + + display_list->Finalize(); + return display_list; } private: @@ -90,14 +114,16 @@ TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) { mask->SetIsMask(true); mask->SetBounds(mask_bounds); - SkBitmap bitmap; - bitmap.allocN32Pixels(200, 200); - SkCanvas canvas(bitmap); - canvas.scale(SkIntToScalar(4), SkIntToScalar(4)); + skia::RefPtr<SkSurface> surface = + skia::AdoptRef(SkSurface::NewRasterN32Premul(200, 200)); + SkCanvas* canvas = surface->getCanvas(); + canvas->scale(SkIntToScalar(4), SkIntToScalar(4)); MaskContentLayerClient client(mask_bounds); - client.PaintContents(&canvas, gfx::Rect(mask_bounds), + client.PaintContents(canvas, gfx::Rect(mask_bounds), ContentLayerClient::PAINTING_BEHAVIOR_NORMAL); - mask->SetBitmap(bitmap); + skia::RefPtr<const SkImage> image = + skia::AdoptRef(surface->newImageSnapshot()); + mask->SetImage(image.Pass()); scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder( gfx::Rect(25, 25, 50, 50), kCSSGreen, 1, SK_ColorBLACK); @@ -292,9 +318,23 @@ class CheckerContentLayerClient : public ContentLayerClient { : bounds_(bounds), color_(color), vertical_(vertical) {} ~CheckerContentLayerClient() override {} bool FillsBoundsCompletely() const override { return false; } + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } + // TODO(pdr): Remove PaintContents as all calls should go through + // PaintContentsToDisplayList. void PaintContents(SkCanvas* canvas, const gfx::Rect& rect, PaintingControlSetting picture_control) override { + scoped_refptr<DisplayItemList> contents = + PaintContentsToDisplayList(rect, picture_control); + contents->Raster(canvas, nullptr, rect, 1.0f); + } + scoped_refptr<DisplayItemList> PaintContentsToDisplayList( + const gfx::Rect& clip, + PaintingControlSetting picture_control) override { + SkPictureRecorder recorder; + skia::RefPtr<SkCanvas> canvas = skia::SharePtr( + recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_)))); + SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(4)); @@ -309,12 +349,17 @@ class CheckerContentLayerClient : public ContentLayerClient { canvas->drawLine(0, i, bounds_.width(), i, paint); } } - } - scoped_refptr<DisplayItemList> PaintContentsToDisplayList( - const gfx::Rect& clip, - PaintingControlSetting picture_control) override { - NOTIMPLEMENTED(); - return nullptr; + + scoped_refptr<DisplayItemList> display_list = + DisplayItemList::Create(clip, DisplayItemListSettings()); + auto* item = display_list->CreateAndAppendItem<DrawingDisplayItem>(); + + skia::RefPtr<SkPicture> picture = + skia::AdoptRef(recorder.endRecordingAsPicture()); + item->SetNew(picture.Pass()); + + display_list->Finalize(); + return display_list; } private: @@ -329,9 +374,23 @@ class CircleContentLayerClient : public ContentLayerClient { : bounds_(bounds) {} ~CircleContentLayerClient() override {} bool FillsBoundsCompletely() const override { return false; } + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } + // TODO(pdr): Remove PaintContents as all calls should go through + // PaintContentsToDisplayList. void PaintContents(SkCanvas* canvas, const gfx::Rect& rect, PaintingControlSetting picture_control) override { + scoped_refptr<DisplayItemList> contents = + PaintContentsToDisplayList(rect, picture_control); + contents->Raster(canvas, nullptr, rect, 1.0f); + } + scoped_refptr<DisplayItemList> PaintContentsToDisplayList( + const gfx::Rect& clip, + PaintingControlSetting picture_control) override { + SkPictureRecorder recorder; + skia::RefPtr<SkCanvas> canvas = skia::SharePtr( + recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_)))); + SkPaint paint; paint.setStyle(SkPaint::kFill_Style); paint.setColor(SK_ColorWHITE); @@ -340,12 +399,16 @@ class CircleContentLayerClient : public ContentLayerClient { bounds_.height() / 2, bounds_.width() / 4, paint); - } - scoped_refptr<DisplayItemList> PaintContentsToDisplayList( - const gfx::Rect& clip, - PaintingControlSetting picture_control) override { - NOTIMPLEMENTED(); - return nullptr; + + scoped_refptr<DisplayItemList> display_list = + DisplayItemList::Create(clip, DisplayItemListSettings()); + auto* item = display_list->CreateAndAppendItem<DrawingDisplayItem>(); + skia::RefPtr<SkPicture> picture = + skia::AdoptRef(recorder.endRecordingAsPicture()); + item->SetNew(picture.Pass()); + + display_list->Finalize(); + return display_list; } private: @@ -355,19 +418,16 @@ class CircleContentLayerClient : public ContentLayerClient { 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)); +INSTANTIATE_TEST_CASE_P(PixelResourceTest, + LayerTreeHostMasksForBackgroundFiltersPixelTest, + ::testing::Values(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)); TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest, MaskOfLayerWithBackgroundFilter) { @@ -387,7 +447,7 @@ TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest, background->AddChild(blur); FilterOperations filters; - filters.Append(FilterOperation::CreateBlurFilter(1.5f)); + filters.Append(FilterOperation::CreateGrayscaleFilter(1.0)); blur->SetBackgroundFilters(filters); gfx::Size mask_bounds(100, 100); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc index a5286a2473e..1eb32ba6440 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc @@ -22,7 +22,6 @@ class LayerTreeHostSynchronousPixelTest : public LayerTreePixelTest { LayerTreePixelTest::InitializeSettings(settings); settings->single_thread_proxy_scheduler = false; settings->use_zero_copy = true; - settings->use_one_copy = false; } void BeginTest() override { @@ -37,7 +36,7 @@ TEST_F(LayerTreeHostSynchronousPixelTest, OneContentLayer) { FakeContentLayerClient client; SkPaint green_paint; green_paint.setColor(SkColorSetARGB(255, 0, 255, 0)); - client.add_draw_rect(gfx::RectF(bounds), green_paint); + client.add_draw_rect(gfx::Rect(bounds), green_paint); scoped_refptr<PictureLayer> root = PictureLayer::Create(layer_settings(), &client); root->SetBounds(bounds); @@ -68,7 +67,7 @@ TEST_F(LayerTreeHostSynchronousGPUPixelTest, OneContentLayer) { FakeContentLayerClient client; SkPaint green_paint; green_paint.setColor(SkColorSetARGB(255, 0, 255, 0)); - client.add_draw_rect(gfx::RectF(bounds), green_paint); + client.add_draw_rect(gfx::Rect(bounds), green_paint); scoped_refptr<PictureLayer> root = PictureLayer::Create(layer_settings(), &client); root->SetBounds(bounds); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc index 7a0af81f4e4..f013e989d3c 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc @@ -6,6 +6,7 @@ #include "cc/layers/picture_layer.h" #include "cc/output/copy_output_request.h" #include "cc/playback/display_item_list.h" +#include "cc/playback/display_item_list_settings.h" #include "cc/playback/drawing_display_item.h" #include "cc/test/layer_tree_pixel_test.h" #include "cc/test/test_gpu_memory_buffer_manager.h" @@ -28,15 +29,12 @@ class LayerTreeHostTilesPixelTest : public LayerTreePixelTest { protected: void InitializeSettings(LayerTreeSettings* settings) override { LayerTreePixelTest::InitializeSettings(settings); - settings->use_display_lists = true; switch (raster_mode_) { case PARTIAL_ONE_COPY: - settings->use_one_copy = true; settings->use_zero_copy = false; settings->use_persistent_map_for_gpu_memory_buffers = true; break; case FULL_ONE_COPY: - settings->use_one_copy = true; settings->use_zero_copy = false; settings->use_persistent_map_for_gpu_memory_buffers = false; break; @@ -101,9 +99,10 @@ class BlueYellowClient : public ContentLayerClient { scoped_refptr<DisplayItemList> PaintContentsToDisplayList( const gfx::Rect& clip, PaintingControlSetting painting_status) override { - bool use_cached_picture = false; + DisplayItemListSettings settings; + settings.use_cached_picture = false; scoped_refptr<DisplayItemList> display_list = - DisplayItemList::Create(clip, use_cached_picture); + DisplayItemList::Create(clip, settings); SkPictureRecorder recorder; skia::RefPtr<SkCanvas> canvas = skia::SharePtr( @@ -133,6 +132,7 @@ class BlueYellowClient : public ContentLayerClient { } bool FillsBoundsCompletely() const override { return true; } + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } void set_blue_top(bool b) { blue_top_ = b; } @@ -160,6 +160,7 @@ class LayerTreeHostTilesTestPartialInvalidation // only re-raster the stuff in the rect. If it doesn't do partial raster // it would re-raster the whole thing instead. client_.set_blue_top(false); + Finish(); picture_layer_->SetNeedsDisplayRect(gfx::Rect(50, 50, 100, 100)); // Add a copy request to see what happened! @@ -188,6 +189,13 @@ TEST_F(LayerTreeHostTilesTestPartialInvalidation, } TEST_F(LayerTreeHostTilesTestPartialInvalidation, + PartialRaster_MultiThread_OneCopy) { + RunRasterPixelTest( + true, PARTIAL_ONE_COPY, picture_layer_, + base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png"))); +} + +TEST_F(LayerTreeHostTilesTestPartialInvalidation, FullRaster_MultiThread_OneCopy) { RunRasterPixelTest( true, FULL_ONE_COPY, picture_layer_, diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc index 6d9c9c67199..fe10a47a6de 100644 --- a/chromium/cc/trees/layer_tree_host_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest.cc @@ -26,17 +26,18 @@ #include "cc/output/copy_output_result.h" #include "cc/output/output_surface.h" #include "cc/output/swap_promise.h" +#include "cc/playback/display_item_list_settings.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/test/fake_content_layer_client.h" +#include "cc/test/fake_display_list_recording_source.h" #include "cc/test/fake_layer_tree_host_client.h" #include "cc/test/fake_output_surface.h" #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" @@ -109,6 +110,80 @@ class LayerTreeHostTestSetNeedsCommitInsideLayout : public LayerTreeHostTest { SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsCommitInsideLayout); +class LayerTreeHostTestFrameOrdering : public LayerTreeHostTest { + protected: + enum MainOrder : int { + MAIN_START = 1, + MAIN_LAYOUT, + MAIN_COMMIT_COMPLETE, + MAIN_DID_BEGIN_FRAME, + MAIN_END, + }; + + enum ImplOrder : int { + IMPL_START = 1, + IMPL_COMMIT, + IMPL_COMMIT_COMPLETE, + IMPL_ACTIVATE, + IMPL_DRAW, + IMPL_SWAP, + IMPL_END, + }; + + template <typename T> + bool CheckStep(T next, T* var) { + int expected = next - 1; + EXPECT_EQ(expected, *var); + bool correct = expected == *var; + *var = next; + return correct; + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void Layout() override { EXPECT_TRUE(CheckStep(MAIN_LAYOUT, &main_)); } + + void DidCommit() override { + EXPECT_TRUE(CheckStep(MAIN_COMMIT_COMPLETE, &main_)); + } + + void DidBeginMainFrame() override { + EXPECT_TRUE(CheckStep(MAIN_DID_BEGIN_FRAME, &main_)); + } + + void BeginCommitOnThread(LayerTreeHostImpl* impl) override { + EXPECT_TRUE(CheckStep(IMPL_COMMIT, &impl_)); + } + + void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { + EXPECT_TRUE(CheckStep(IMPL_COMMIT_COMPLETE, &impl_)); + } + + void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override { + EXPECT_TRUE(CheckStep(IMPL_ACTIVATE, &impl_)); + } + + void DrawLayersOnThread(LayerTreeHostImpl* impl) override { + EXPECT_TRUE(CheckStep(IMPL_DRAW, &impl_)); + } + + void SwapBuffersCompleteOnThread(LayerTreeHostImpl* impl) override { + EXPECT_TRUE(CheckStep(IMPL_SWAP, &impl_)); + + EndTest(); + } + + void AfterTest() override { + EXPECT_TRUE(CheckStep(MAIN_END, &main_)); + EXPECT_TRUE(CheckStep(IMPL_END, &impl_)); + } + + MainOrder main_ = MAIN_START; + ImplOrder impl_ = IMPL_START; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestFrameOrdering); + class LayerTreeHostTestSetNeedsUpdateInsideLayout : public LayerTreeHostTest { protected: void BeginTest() override { PostSetNeedsCommitToMainThread(); } @@ -272,6 +347,79 @@ class LayerTreeHostTestReadyToDrawNonEmpty // single threaded mode. SINGLE_THREAD_TEST_F(LayerTreeHostTestReadyToDrawNonEmpty); +// This tests if we get the READY_TO_DRAW signal and draw if we become invisible +// and then become visible again. +class LayerTreeHostTestReadyToDrawVisibility : public LayerTreeHostTest { + public: + LayerTreeHostTestReadyToDrawVisibility() + : LayerTreeHostTest(), + toggled_visibility_(false), + did_notify_ready_to_draw_(false), + did_draw_(false) {} + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void SetupTree() override { + client_.set_fill_with_nonsolid_color(true); + scoped_refptr<FakePictureLayer> root_layer = + FakePictureLayer::Create(layer_settings(), &client_); + root_layer->SetBounds(gfx::Size(1024, 1024)); + root_layer->SetIsDrawable(true); + + layer_tree_host()->SetRootLayer(root_layer); + LayerTreeHostTest::SetupTree(); + } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + if (!toggled_visibility_) { + { + DebugScopedSetMainThread main(proxy()); + layer_tree_host()->SetVisible(false); + } + toggled_visibility_ = true; + EXPECT_FALSE(host_impl->visible()); + } + } + + void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) override { + // Sometimes the worker thread posts NotifyReadyToDraw in the extremely + // short duration of time between PrepareTiles and SetVisible(false) so we + // might get two NotifyReadyToDraw signals for this test. + did_notify_ready_to_draw_ = true; + } + + void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { + EXPECT_FALSE(did_draw_); + did_draw_ = true; + EndTest(); + } + + void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) override { + if (!host_impl->visible()) { + { + DebugScopedSetMainThread main(proxy()); + layer_tree_host()->SetVisible(true); + } + EXPECT_TRUE(host_impl->visible()); + } + } + + void AfterTest() override { + EXPECT_TRUE(did_notify_ready_to_draw_); + EXPECT_TRUE(did_draw_); + } + + private: + FakeContentLayerClient client_; + bool toggled_visibility_; + bool did_notify_ready_to_draw_; + bool did_draw_; +}; + +// Note: With this test setup, we only get tiles flagged as REQUIRED_FOR_DRAW in +// single threaded mode. +SINGLE_THREAD_TEST_F(LayerTreeHostTestReadyToDrawVisibility); + class LayerTreeHostFreeWorkerContextResourcesTest : public LayerTreeHostTest { public: scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override { @@ -316,7 +464,7 @@ class LayerTreeHostFreeWorkerContextResourcesTest : public LayerTreeHostTest { explicit MockSetWorkerContextShouldAggressivelyFreeResourcesOutputSurface( bool delegated_rendering) : FakeOutputSurface(TestContextProvider::Create(), - TestContextProvider::Create(), + TestContextProvider::CreateWorker(), delegated_rendering) {} MOCK_METHOD1(SetWorkerContextShouldAggressivelyFreeResources, void(bool is_visible)); @@ -443,7 +591,6 @@ class LayerTreeHostTestPushPropertiesTo : public LayerTreeHostTest { protected: void SetupTree() override { scoped_refptr<Layer> root = Layer::Create(layer_settings()); - root->CreateRenderSurface(); root->SetBounds(gfx::Size(10, 10)); layer_tree_host()->SetRootLayer(root); LayerTreeHostTest::SetupTree(); @@ -589,7 +736,7 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest { DrawResult draw_result) override { EXPECT_EQ(DRAW_SUCCESS, draw_result); - gfx::RectF root_damage_rect; + gfx::Rect root_damage_rect; if (!frame_data->render_passes.empty()) root_damage_rect = frame_data->render_passes.back()->damage_rect; @@ -713,7 +860,6 @@ class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest { void SetupTree() override { root_layer_ = Layer::Create(layer_settings()); root_layer_->SetBounds(gfx::Size(10, 20)); - root_layer_->CreateRenderSurface(); scaled_layer_ = FakePictureLayer::Create(layer_settings(), &client_); scaled_layer_->SetBounds(gfx::Size(1, 1)); @@ -764,7 +910,6 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate void SetupTree() override { root_layer_ = Layer::Create(layer_settings()); root_layer_->SetBounds(gfx::Size(10, 20)); - root_layer_->CreateRenderSurface(); bool paint_scrollbar = true; bool has_thumb = false; @@ -813,6 +958,69 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate); +class LayerTreeHostTestDeviceScaleFactorChange : public LayerTreeHostTest { + public: + void InitializeSettings(LayerTreeSettings* settings) override { + settings->layer_transforms_should_scale_layer_contents = true; + } + + void SetupTree() override { + root_layer_ = Layer::Create(layer_settings()); + root_layer_->SetBounds(gfx::Size(10, 20)); + + child_layer_ = FakePictureLayer::Create(layer_settings(), &client_); + child_layer_->SetBounds(gfx::Size(10, 10)); + root_layer_->AddChild(child_layer_); + + layer_tree_host()->SetRootLayer(root_layer_); + LayerTreeHostTest::SetupTree(); + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void DidCommit() override { + if (layer_tree_host()->source_frame_number() == 1) + layer_tree_host()->SetDeviceScaleFactor(4.f); + } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + if (host_impl->sync_tree()->source_frame_number() == 1) { + EXPECT_EQ(4.f, host_impl->sync_tree()->device_scale_factor()); + if (host_impl->pending_tree()) { + // The active tree's device scale factor shouldn't change until + // activation. + EXPECT_EQ(1.f, host_impl->active_tree()->device_scale_factor()); + } + } + } + + DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, + LayerTreeHostImpl::FrameData* frame_data, + DrawResult draw_result) override { + if (host_impl->active_tree()->source_frame_number() == 0) { + EXPECT_EQ(1.f, host_impl->active_tree()->device_scale_factor()); + } else { + gfx::Rect root_damage_rect = + frame_data->render_passes.back()->damage_rect; + EXPECT_EQ(gfx::Rect(host_impl->active_tree()->root_layer()->bounds()), + root_damage_rect); + EXPECT_EQ(4.f, host_impl->active_tree()->device_scale_factor()); + EndTest(); + } + + return draw_result; + } + + void AfterTest() override {} + + private: + FakeContentLayerClient client_; + scoped_refptr<Layer> root_layer_; + scoped_refptr<Layer> child_layer_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeviceScaleFactorChange); + class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest { public: LayerTreeHostTestSetNextCommitForcesRedraw() @@ -837,7 +1045,7 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest { DrawResult draw_result) override { EXPECT_EQ(DRAW_SUCCESS, draw_result); - gfx::RectF root_damage_rect; + gfx::Rect root_damage_rect; if (!frame_data->render_passes.empty()) root_damage_rect = frame_data->render_passes.back()->damage_rect; @@ -937,7 +1145,7 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest { DrawResult draw_result) override { EXPECT_EQ(DRAW_SUCCESS, draw_result); - gfx::RectF root_damage_rect; + gfx::Rect root_damage_rect; if (!frame_data->render_passes.empty()) root_damage_rect = frame_data->render_passes.back()->damage_rect; @@ -1004,17 +1212,15 @@ class LayerTreeHostTestDamageWithScale : public LayerTreeHostTest { void SetupTree() override { client_.set_fill_with_nonsolid_color(true); - scoped_ptr<FakePicturePile> pile( - new FakePicturePile(LayerTreeSettings().minimum_contents_scale, - LayerTreeSettings().default_tile_grid_size)); + scoped_ptr<FakeDisplayListRecordingSource> recording( + new FakeDisplayListRecordingSource); root_layer_ = FakePictureLayer::CreateWithRecordingSource( - layer_settings(), &client_, pile.Pass()); + layer_settings(), &client_, recording.Pass()); root_layer_->SetBounds(gfx::Size(50, 50)); - pile.reset(new FakePicturePile(LayerTreeSettings().minimum_contents_scale, - LayerTreeSettings().default_tile_grid_size)); + recording.reset(new FakeDisplayListRecordingSource); child_layer_ = FakePictureLayer::CreateWithRecordingSource( - layer_settings(), &client_, pile.Pass()); + layer_settings(), &client_, recording.Pass()); child_layer_->SetBounds(gfx::Size(25, 25)); child_layer_->SetIsDrawable(true); child_layer_->SetContentsOpaque(true); @@ -1041,7 +1247,7 @@ class LayerTreeHostTestDamageWithScale : public LayerTreeHostTest { DrawResult draw_result) override { EXPECT_EQ(DRAW_SUCCESS, draw_result); - gfx::RectF root_damage_rect; + gfx::Rect root_damage_rect; if (!frame_data->render_passes.empty()) root_damage_rect = frame_data->render_passes.back()->damage_rect; @@ -1242,22 +1448,24 @@ class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest { void SetupTree() override { LayerTreeHostTest::SetupTree(); + Layer* root_layer = layer_tree_host()->root_layer(); + scoped_refptr<FakePictureLayer> layer = FakePictureLayer::Create(layer_settings(), &client_); layer->set_always_update_resources(true); scroll_layer_ = layer; - Layer* root_layer = layer_tree_host()->root_layer(); - scroll_layer_->SetScrollClipLayerId(root_layer->id()); - scroll_layer_->SetIsContainerForFixedPositionLayers(true); scroll_layer_->SetBounds(gfx::Size(2 * root_layer->bounds().width(), 2 * root_layer->bounds().height())); scroll_layer_->SetScrollOffset(gfx::ScrollOffset()); - 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(NULL, root_layer, - scroll_layer_.get(), NULL); + + CreateVirtualViewportLayers(root_layer, + scroll_layer_, + root_layer->bounds(), + root_layer->bounds(), + layer_tree_host(), + layer_settings()); + layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 2.f); } @@ -1348,17 +1556,22 @@ class TestOpacityChangeLayerDelegate : public ContentLayerClient { 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); + NOTIMPLEMENTED(); } scoped_refptr<DisplayItemList> PaintContentsToDisplayList( const gfx::Rect& clip, PaintingControlSetting picture_control) override { - NOTIMPLEMENTED(); - return nullptr; + // Set layer opacity to 0. + if (test_layer_) + test_layer_->SetOpacity(0.f); + + // Return a dummy display list. + scoped_refptr<DisplayItemList> display_list = + DisplayItemList::Create(clip, DisplayItemListSettings()); + return display_list; } bool FillsBoundsCompletely() const override { return false; } + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } private: Layer* test_layer_; @@ -1428,7 +1641,7 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers // Should only do one commit. EXPECT_EQ(0, impl->active_tree()->source_frame_number()); // Device scale factor should come over to impl. - EXPECT_NEAR(impl->device_scale_factor(), 1.5f, 0.00001f); + EXPECT_NEAR(impl->active_tree()->device_scale_factor(), 1.5f, 0.00001f); // Both layers are on impl. ASSERT_EQ(1u, impl->active_tree()->root_layer()->children().size()); @@ -1466,8 +1679,8 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers EXPECT_FLOAT_EQ(1.5f, child->MaximumTilingContentsScale()); gfx::Transform scale_transform; - scale_transform.Scale(impl->device_scale_factor(), - impl->device_scale_factor()); + scale_transform.Scale(impl->active_tree()->device_scale_factor(), + impl->active_tree()->device_scale_factor()); // The root layer is scaled by 2x. gfx::Transform root_screen_space_transform = scale_transform; @@ -1627,7 +1840,6 @@ class LayerTreeHostTestCompositeImmediatelyStateTransitions void InitializeSettings(LayerTreeSettings* settings) override { settings->single_thread_proxy_scheduler = false; settings->use_zero_copy = true; - settings->use_one_copy = false; } void BeginTest() override { @@ -1878,6 +2090,10 @@ class LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor } void ScheduledActionInvalidateOutputSurface() override { + // Do not call ImplThreadTaskRunner after the test ended because of the + // possibility of use-after-free due to a race. + if (TestEnded()) + return; ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind( @@ -1900,7 +2116,8 @@ class LayerTreeHostTestAbortedCommitDoesntStallDisabledVsync : public LayerTreeHostTestAbortedCommitDoesntStall { void InitializeSettings(LayerTreeSettings* settings) override { LayerTreeHostTestAbortedCommitDoesntStall::InitializeSettings(settings); - settings->renderer_settings.disable_gpu_vsync = true; + settings->wait_for_beginframe_interval = false; + settings->renderer_settings.disable_display_vsync = true; } }; @@ -1945,17 +2162,22 @@ class LayerTreeHostTestChangeLayerPropertiesInPaintContents void PaintContents(SkCanvas* canvas, const gfx::Rect& clip, PaintingControlSetting picture_control) override { - layer_->SetBounds(gfx::Size(2, 2)); + NOTIMPLEMENTED(); } scoped_refptr<DisplayItemList> PaintContentsToDisplayList( const gfx::Rect& clip, PaintingControlSetting picture_control) override { - NOTIMPLEMENTED(); - return nullptr; + layer_->SetBounds(gfx::Size(2, 2)); + + // Return a dummy display list. + scoped_refptr<DisplayItemList> display_list = + DisplayItemList::Create(clip, DisplayItemListSettings()); + return display_list; } bool FillsBoundsCompletely() const override { return false; } + size_t GetApproximateUnsharedMemoryUsage() const override { return 0; } private: Layer* layer_; @@ -2465,7 +2687,6 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { void SetupTree() override { root_ = PushPropertiesCountingLayer::Create(layer_settings()); - root_->CreateRenderSurface(); child_ = PushPropertiesCountingLayer::Create(layer_settings()); child2_ = PushPropertiesCountingLayer::Create(layer_settings()); grandchild_ = PushPropertiesCountingLayer::Create(layer_settings()); @@ -2479,7 +2700,6 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { child2_->AddChild(leaf_always_pushing_layer_); other_root_ = PushPropertiesCountingLayer::Create(layer_settings()); - other_root_->CreateRenderSurface(); // Don't set the root layer here. LayerTreeHostTest::SetupTree(); @@ -2857,7 +3077,6 @@ class LayerTreeHostTestPropertyChangesDuringUpdateArePushed void SetupTree() override { root_ = Layer::Create(layer_settings()); - root_->CreateRenderSurface(); root_->SetBounds(gfx::Size(1, 1)); bool paint_scrollbar = true; @@ -2914,7 +3133,6 @@ class LayerTreeHostTestSetDrawableCausesCommit : public LayerTreeHostTest { void SetupTree() override { root_ = PushPropertiesCountingLayer::Create(layer_settings()); - root_->CreateRenderSurface(); child_ = PushPropertiesCountingLayer::Create(layer_settings()); root_->AddChild(child_); @@ -2976,7 +3194,6 @@ class LayerTreeHostTestCasePushPropertiesThreeGrandChildren void SetupTree() override { root_ = PushPropertiesCountingLayer::Create(layer_settings()); - root_->CreateRenderSurface(); child_ = PushPropertiesCountingLayer::Create(layer_settings()); grandchild1_ = PushPropertiesCountingLayer::Create(layer_settings()); grandchild2_ = PushPropertiesCountingLayer::Create(layer_settings()); @@ -3522,7 +3739,6 @@ class LayerTreeHostTestPushHiddenLayer : public LayerTreeHostTest { protected: void SetupTree() override { root_layer_ = Layer::Create(layer_settings()); - root_layer_->CreateRenderSurface(); root_layer_->SetPosition(gfx::Point()); root_layer_->SetBounds(gfx::Size(10, 10)); @@ -3617,55 +3833,6 @@ class LayerTreeHostTestUpdateLayerInEmptyViewport : public LayerTreeHostTest { MULTI_THREAD_TEST_F(LayerTreeHostTestUpdateLayerInEmptyViewport); -class LayerTreeHostTestMaxTransferBufferUsageBytes : public LayerTreeHostTest { - protected: - void InitializeSettings(LayerTreeSettings* settings) override { - // Testing async uploads. - settings->use_zero_copy = false; - settings->use_one_copy = false; - } - - scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override { - scoped_refptr<TestContextProvider> context_provider = - TestContextProvider::Create(); - context_provider->SetMaxTransferBufferUsageBytes(512 * 512); - if (delegating_renderer()) - return FakeOutputSurface::CreateDelegating3d(context_provider); - else - return FakeOutputSurface::Create3d(context_provider); - } - - void SetupTree() override { - client_.set_fill_with_nonsolid_color(true); - scoped_refptr<FakePictureLayer> root_layer = - FakePictureLayer::Create(layer_settings(), &client_); - root_layer->SetBounds(gfx::Size(1024, 1024)); - root_layer->SetIsDrawable(true); - - layer_tree_host()->SetRootLayer(root_layer); - LayerTreeHostTest::SetupTree(); - } - - void BeginTest() override { PostSetNeedsCommitToMainThread(); } - - void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { - TestWebGraphicsContext3D* context = TestContext(); - - // Expect that the transfer buffer memory used is equal to the - // MaxTransferBufferUsageBytes value set in CreateOutputSurface. - EXPECT_EQ(512 * 512u, context->max_used_transfer_buffer_usage_bytes()); - EndTest(); - } - - void AfterTest() override {} - - private: - FakeContentLayerClient client_; -}; - -// Impl-side painting is a multi-threaded compositor feature. -MULTI_THREAD_TEST_F(LayerTreeHostTestMaxTransferBufferUsageBytes); - class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface : public LayerTreeHostTest { protected: @@ -3782,7 +3949,6 @@ class TestSwapPromise : public SwapPromise { 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; @@ -3805,6 +3971,53 @@ class TestSwapPromise : public SwapPromise { TestSwapPromiseResult* result_; }; +class PinnedLayerTreeSwapPromise : public LayerTreeHostTest { + protected: + void BeginTest() override { + PostSetNextCommitForcesRedrawToMainThread(); + PostSetNeedsCommitToMainThread(); + } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + int frame = host_impl->active_tree()->source_frame_number(); + if (frame == -1) { + host_impl->active_tree()->QueuePinnedSwapPromise(make_scoped_ptr( + new TestSwapPromise(&pinned_active_swap_promise_result_))); + host_impl->pending_tree()->QueueSwapPromise( + make_scoped_ptr(new TestSwapPromise(&pending_swap_promise_result_))); + host_impl->active_tree()->QueueSwapPromise( + make_scoped_ptr(new TestSwapPromise(&active_swap_promise_result_))); + } + } + + void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override { + EndTest(); + } + + void AfterTest() override { + // The pending swap promise should activate and swap. + EXPECT_TRUE(pending_swap_promise_result_.did_activate_called); + EXPECT_TRUE(pending_swap_promise_result_.did_swap_called); + + // The active swap promise should fail to swap (it is cancelled by + // the activation of a new frame). + EXPECT_FALSE(active_swap_promise_result_.did_activate_called); + EXPECT_FALSE(active_swap_promise_result_.did_swap_called); + EXPECT_TRUE(active_swap_promise_result_.did_not_swap_called); + EXPECT_EQ(active_swap_promise_result_.reason, SwapPromise::SWAP_FAILS); + + // The pinned active swap promise should not activate, but should swap. + EXPECT_FALSE(pinned_active_swap_promise_result_.did_activate_called); + EXPECT_TRUE(pinned_active_swap_promise_result_.did_swap_called); + } + + TestSwapPromiseResult pending_swap_promise_result_; + TestSwapPromiseResult active_swap_promise_result_; + TestSwapPromiseResult pinned_active_swap_promise_result_; +}; + +MULTI_THREAD_TEST_F(PinnedLayerTreeSwapPromise); + class LayerTreeHostTestBreakSwapPromise : public LayerTreeHostTest { protected: LayerTreeHostTestBreakSwapPromise() @@ -4219,22 +4432,21 @@ class LayerTreeHostTestGpuRasterizationDefault : public LayerTreeHostTest { void SetupTree() override { LayerTreeHostTest::SetupTree(); - scoped_refptr<PictureLayer> layer = - PictureLayer::Create(layer_settings(), &layer_client_); + scoped_ptr<FakeDisplayListRecordingSource> recording_source( + new FakeDisplayListRecordingSource); + recording_source_ = recording_source.get(); + + scoped_refptr<FakePictureLayer> layer = + FakePictureLayer::CreateWithRecordingSource( + layer_settings(), &layer_client_, recording_source.Pass()); + layer_ = layer.get(); layer->SetBounds(gfx::Size(10, 10)); layer->SetIsDrawable(true); layer_tree_host()->root_layer()->AddChild(layer); } void BeginTest() override { - Layer* root = layer_tree_host()->root_layer(); - PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0)); - RecordingSource* recording_source = layer->GetRecordingSourceForTesting(); - - // Verify default values. - EXPECT_TRUE(root->IsSuitableForGpuRasterization()); - EXPECT_TRUE(layer->IsSuitableForGpuRasterization()); - EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization()); + // Verify default value. EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger()); // Setting gpu rasterization trigger does not enable gpu rasterization. @@ -4245,11 +4457,17 @@ class LayerTreeHostTestGpuRasterizationDefault : public LayerTreeHostTest { } void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + EXPECT_TRUE(recording_source_->IsSuitableForGpuRasterization()); + EXPECT_TRUE(layer_->IsSuitableForGpuRasterization()); + EXPECT_FALSE(host_impl->pending_tree()->use_gpu_rasterization()); EXPECT_FALSE(host_impl->use_gpu_rasterization()); } void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + EXPECT_TRUE(recording_source_->IsSuitableForGpuRasterization()); + EXPECT_TRUE(layer_->IsSuitableForGpuRasterization()); + EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization()); EXPECT_FALSE(host_impl->use_gpu_rasterization()); EndTest(); @@ -4258,10 +4476,64 @@ class LayerTreeHostTestGpuRasterizationDefault : public LayerTreeHostTest { void AfterTest() override {} FakeContentLayerClient layer_client_; + FakePictureLayer* layer_; + FakeDisplayListRecordingSource* recording_source_; }; MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationDefault); +class LayerTreeHostTestEmptyLayerGpuRasterization : public LayerTreeHostTest { + protected: + void SetupTree() override { + LayerTreeHostTest::SetupTree(); + + scoped_ptr<FakeDisplayListRecordingSource> recording_source( + new FakeDisplayListRecordingSource); + recording_source_ = recording_source.get(); + + scoped_refptr<FakePictureLayer> layer = + FakePictureLayer::CreateWithRecordingSource( + layer_settings(), &layer_client_, recording_source.Pass()); + layer_ = layer.get(); + layer->SetBounds(gfx::Size()); + layer->SetIsDrawable(true); + layer_tree_host()->root_layer()->AddChild(layer); + } + + void BeginTest() override { + // Setting gpu rasterization trigger does not enable gpu rasterization. + layer_tree_host()->SetHasGpuRasterizationTrigger(true); + EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger()); + + PostSetNeedsCommitToMainThread(); + } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + EXPECT_TRUE(recording_source_->IsSuitableForGpuRasterization()); + EXPECT_TRUE(layer_->IsSuitableForGpuRasterization()); + + EXPECT_FALSE(host_impl->pending_tree()->use_gpu_rasterization()); + EXPECT_FALSE(host_impl->use_gpu_rasterization()); + } + + void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + EXPECT_TRUE(recording_source_->IsSuitableForGpuRasterization()); + EXPECT_TRUE(layer_->IsSuitableForGpuRasterization()); + + EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization()); + EXPECT_FALSE(host_impl->use_gpu_rasterization()); + EndTest(); + } + + void AfterTest() override {} + + FakeContentLayerClient layer_client_; + FakePictureLayer* layer_; + FakeDisplayListRecordingSource* recording_source_; +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestEmptyLayerGpuRasterization); + class LayerTreeHostTestGpuRasterizationEnabled : public LayerTreeHostTest { protected: void InitializeSettings(LayerTreeSettings* settings) override { @@ -4272,22 +4544,21 @@ class LayerTreeHostTestGpuRasterizationEnabled : public LayerTreeHostTest { void SetupTree() override { LayerTreeHostTest::SetupTree(); - scoped_refptr<PictureLayer> layer = - PictureLayer::Create(layer_settings(), &layer_client_); + scoped_ptr<FakeDisplayListRecordingSource> recording_source( + new FakeDisplayListRecordingSource); + recording_source_ = recording_source.get(); + + scoped_refptr<FakePictureLayer> layer = + FakePictureLayer::CreateWithRecordingSource( + layer_settings(), &layer_client_, recording_source.Pass()); + layer_ = layer.get(); layer->SetBounds(gfx::Size(10, 10)); layer->SetIsDrawable(true); layer_tree_host()->root_layer()->AddChild(layer); } void BeginTest() override { - Layer* root = layer_tree_host()->root_layer(); - PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0)); - RecordingSource* recording_source = layer->GetRecordingSourceForTesting(); - - // Verify default values. - EXPECT_TRUE(root->IsSuitableForGpuRasterization()); - EXPECT_TRUE(layer->IsSuitableForGpuRasterization()); - EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization()); + // Verify default value. EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger()); // Gpu rasterization trigger is relevant. @@ -4295,23 +4566,29 @@ class LayerTreeHostTestGpuRasterizationEnabled : public LayerTreeHostTest { EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger()); // Content-based veto is relevant as well. - recording_source->SetUnsuitableForGpuRasterizationForTesting(); - EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization()); - EXPECT_FALSE(layer->IsSuitableForGpuRasterization()); + recording_source_->SetUnsuitableForGpuRasterization(); + // Veto will take effect when layers are updated. // The results will be verified after commit is completed below. - // Since we are manually marking picture pile as unsuitable, + // Since we are manually marking the source as unsuitable, // make sure that the layer gets a chance to update. - layer->SetNeedsDisplay(); + layer_->SetNeedsDisplay(); PostSetNeedsCommitToMainThread(); } void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + // Ensure the suitability bit sticks. + EXPECT_FALSE(recording_source_->IsSuitableForGpuRasterization()); + EXPECT_FALSE(layer_->IsSuitableForGpuRasterization()); + EXPECT_FALSE(host_impl->pending_tree()->use_gpu_rasterization()); EXPECT_FALSE(host_impl->use_gpu_rasterization()); } void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + EXPECT_FALSE(recording_source_->IsSuitableForGpuRasterization()); + EXPECT_FALSE(layer_->IsSuitableForGpuRasterization()); + EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization()); EXPECT_FALSE(host_impl->use_gpu_rasterization()); EndTest(); @@ -4320,6 +4597,8 @@ class LayerTreeHostTestGpuRasterizationEnabled : public LayerTreeHostTest { void AfterTest() override {} FakeContentLayerClient layer_client_; + FakePictureLayer* layer_; + FakeDisplayListRecordingSource* recording_source_; }; MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationEnabled); @@ -4334,22 +4613,22 @@ class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest { void SetupTree() override { LayerTreeHostTest::SetupTree(); + scoped_ptr<FakeDisplayListRecordingSource> recording_source( + new FakeDisplayListRecordingSource); + recording_source_ = recording_source.get(); + scoped_refptr<FakePictureLayer> layer = - FakePictureLayer::Create(layer_settings(), &layer_client_); + FakePictureLayer::CreateWithRecordingSource( + layer_settings(), &layer_client_, recording_source.Pass()); + layer_ = layer.get(); + layer->SetBounds(gfx::Size(10, 10)); layer->SetIsDrawable(true); layer_tree_host()->root_layer()->AddChild(layer); } void BeginTest() override { - Layer* root = layer_tree_host()->root_layer(); - PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0)); - RecordingSource* recording_source = layer->GetRecordingSourceForTesting(); - - // Verify default values. - EXPECT_TRUE(root->IsSuitableForGpuRasterization()); - EXPECT_TRUE(layer->IsSuitableForGpuRasterization()); - EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization()); + // Verify default value. EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger()); // With gpu rasterization forced, gpu rasterization trigger is irrelevant. @@ -4357,23 +4636,29 @@ class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest { EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger()); // Content-based veto is irrelevant as well. - recording_source->SetUnsuitableForGpuRasterizationForTesting(); - EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization()); - EXPECT_FALSE(layer->IsSuitableForGpuRasterization()); + recording_source_->SetUnsuitableForGpuRasterization(); + // Veto will take effect when layers are updated. // The results will be verified after commit is completed below. - // Since we are manually marking picture pile as unsuitable, + // Since we are manually marking the source as unsuitable, // make sure that the layer gets a chance to update. - layer->SetNeedsDisplay(); + layer_->SetNeedsDisplay(); PostSetNeedsCommitToMainThread(); } void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + // Ensure the suitability bit sticks. + EXPECT_FALSE(recording_source_->IsSuitableForGpuRasterization()); + EXPECT_FALSE(layer_->IsSuitableForGpuRasterization()); + EXPECT_TRUE(host_impl->sync_tree()->use_gpu_rasterization()); EXPECT_TRUE(host_impl->use_gpu_rasterization()); } void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { + EXPECT_FALSE(recording_source_->IsSuitableForGpuRasterization()); + EXPECT_FALSE(layer_->IsSuitableForGpuRasterization()); + EXPECT_TRUE(host_impl->active_tree()->use_gpu_rasterization()); EXPECT_TRUE(host_impl->use_gpu_rasterization()); EndTest(); @@ -4382,93 +4667,12 @@ class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest { void AfterTest() override {} FakeContentLayerClient layer_client_; + FakePictureLayer* layer_; + FakeDisplayListRecordingSource* recording_source_; }; SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationForced); -class LayerTreeHostTestContinuousPainting : public LayerTreeHostTest { - public: - LayerTreeHostTestContinuousPainting() - : num_commits_(0), num_draws_(0), bounds_(20, 20), child_layer_(NULL) {} - - protected: - enum { kExpectedNumCommits = 10 }; - - void SetupTree() override { - scoped_refptr<Layer> root_layer = Layer::Create(layer_settings()); - root_layer->SetBounds(bounds_); - root_layer->CreateRenderSurface(); - - child_layer_ = FakePictureLayer::Create(layer_settings(), &client_); - child_layer_->SetBounds(bounds_); - child_layer_->SetIsDrawable(true); - root_layer->AddChild(child_layer_); - - layer_tree_host()->SetRootLayer(root_layer); - layer_tree_host()->SetViewportSize(bounds_); - LayerTreeHostTest::SetupTree(); - } - - void BeginTest() override { - MainThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind( - &LayerTreeHostTestContinuousPainting::EnableContinuousPainting, - base::Unretained(this))); - // Wait 50x longer than expected. - double milliseconds_per_frame = - 1000.0 / layer_tree_host()->settings().renderer_settings.refresh_rate; - MainThreadTaskRunner()->PostDelayedTask( - FROM_HERE, - base::Bind( - &LayerTreeHostTestContinuousPainting::DisableContinuousPainting, - base::Unretained(this)), - base::TimeDelta::FromMilliseconds(50 * kExpectedNumCommits * - milliseconds_per_frame)); - } - - void BeginMainFrame(const BeginFrameArgs& args) override { - child_layer_->SetNeedsDisplay(); - } - - void AfterTest() override { - EXPECT_LE(kExpectedNumCommits, num_commits_); - EXPECT_LE(kExpectedNumCommits, num_draws_); - EXPECT_LE(kExpectedNumCommits, child_layer_->update_count()); - } - - void DrawLayersOnThread(LayerTreeHostImpl* impl) override { - if (++num_draws_ == kExpectedNumCommits) - EndTest(); - } - - void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { - ++num_commits_; - } - - private: - void EnableContinuousPainting() { - LayerTreeDebugState debug_state = layer_tree_host()->debug_state(); - debug_state.continuous_painting = true; - layer_tree_host()->SetDebugState(debug_state); - } - - void DisableContinuousPainting() { - LayerTreeDebugState debug_state = layer_tree_host()->debug_state(); - debug_state.continuous_painting = false; - layer_tree_host()->SetDebugState(debug_state); - EndTest(); - } - - int num_commits_; - int num_draws_; - const gfx::Size bounds_; - FakeContentLayerClient client_; - scoped_refptr<FakePictureLayer> child_layer_; -}; - -MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousPainting); - class LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame : public LayerTreeHostTest { public: @@ -4478,7 +4682,6 @@ class LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame : will_begin_impl_frame_count_(0), did_finish_impl_frame_count_(0) {} void BeginTest() override { - // Kick off the test with a commit. PostSetNeedsCommitToMainThread(); } @@ -4524,6 +4727,70 @@ class LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame); +::testing::AssertionResult AssertFrameTimeContained( + const char* haystack_expr, + const char* needle_expr, + const std::vector<BeginFrameArgs> haystack, + const BeginFrameArgs needle) { + auto failure = ::testing::AssertionFailure() + << needle.frame_time << " (" << needle_expr + << ") not found in " << haystack_expr; + + if (haystack.size() == 0) { + failure << " which is empty."; + } else { + failure << " which contains:\n"; + for (size_t i = 0; i < haystack.size(); i++) { + if (haystack[i].frame_time == needle.frame_time) + return ::testing::AssertionSuccess(); + failure << " [" << i << "]: " << haystack[i].frame_time << "\n"; + } + } + + return failure; +} + +class LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime + : public LayerTreeHostTest { + public: + LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime() + : impl_frame_args_(), will_begin_impl_frame_count_(0) {} + + void BeginTest() override { + // Kick off the test with a commit. + PostSetNeedsCommitToMainThread(); + } + + void WillBeginImplFrameOnThread(LayerTreeHostImpl* impl, + const BeginFrameArgs& args) override { + impl_frame_args_.push_back(args); + + will_begin_impl_frame_count_++; + if (will_begin_impl_frame_count_ < 10) + PostSetNeedsCommitToMainThread(); + } + + void BeginMainFrame(const BeginFrameArgs& args) override { + ASSERT_GT(impl_frame_args_.size(), 0U) + << "BeginMainFrame called before BeginImplFrame called!"; + EXPECT_PRED_FORMAT2(AssertFrameTimeContained, impl_frame_args_, args); + } + + void SendBeginMainFrameNotExpectedSoon() override { EndTest(); } + + void AfterTest() override { + EXPECT_GT(impl_frame_args_.size(), 0U); + EXPECT_GE(will_begin_impl_frame_count_, 10); + } + + private: + std::vector<BeginFrameArgs> impl_frame_args_; + int will_begin_impl_frame_count_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime); + class LayerTreeHostTestSendBeginFramesToChildren : public LayerTreeHostTest { public: LayerTreeHostTestSendBeginFramesToChildren() @@ -4657,7 +4924,6 @@ class LayerTreeHostTestSynchronousCompositeSwapPromise void InitializeSettings(LayerTreeSettings* settings) override { settings->single_thread_proxy_scheduler = false; settings->use_zero_copy = true; - settings->use_one_copy = false; } void BeginTest() override { @@ -4790,21 +5056,19 @@ class LayerTreeHostTestCrispUpAfterPinchEnds : public LayerTreeHostTest { pinch->SetIsContainerForFixedPositionLayers(true); root->AddChild(pinch); - scoped_ptr<FakePicturePile> pile( - new FakePicturePile(LayerTreeSettings().minimum_contents_scale, - LayerTreeSettings().default_tile_grid_size)); - pile->SetPlaybackAllowedEvent(&playback_allowed_event_); + scoped_ptr<FakeDisplayListRecordingSource> recording( + new FakeDisplayListRecordingSource); + recording->SetPlaybackAllowedEvent(&playback_allowed_event_); scoped_refptr<FakePictureLayer> layer = FakePictureLayer::CreateWithRecordingSource(layer_settings(), &client_, - pile.Pass()); + recording.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()->RegisterViewportLayers(NULL, root, pinch, nullptr); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f); layer_tree_host()->SetRootLayer(root); LayerTreeHostTest::SetupTree(); @@ -4961,10 +5225,6 @@ MULTI_THREAD_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(); @@ -4999,12 +5259,11 @@ class RasterizeWithGpuRasterizationCreatesResources : public LayerTreeHostTest { scoped_refptr<Layer> root = Layer::Create(layer_settings()); root->SetBounds(gfx::Size(500, 500)); - scoped_ptr<FakePicturePile> pile( - new FakePicturePile(LayerTreeSettings().minimum_contents_scale, - LayerTreeSettings().default_tile_grid_size)); + scoped_ptr<FakeDisplayListRecordingSource> recording( + new FakeDisplayListRecordingSource); scoped_refptr<FakePictureLayer> layer = FakePictureLayer::CreateWithRecordingSource(layer_settings(), &client_, - pile.Pass()); + recording.Pass()); layer->SetBounds(gfx::Size(500, 500)); layer->SetContentsOpaque(true); root->AddChild(layer); @@ -5041,12 +5300,11 @@ class GpuRasterizationRasterizesBorderTiles : public LayerTreeHostTest { void SetupTree() override { client_.set_fill_with_nonsolid_color(true); - scoped_ptr<FakePicturePile> pile( - new FakePicturePile(LayerTreeSettings().minimum_contents_scale, - LayerTreeSettings().default_tile_grid_size)); + scoped_ptr<FakeDisplayListRecordingSource> recording( + new FakeDisplayListRecordingSource); scoped_refptr<FakePictureLayer> root = FakePictureLayer::CreateWithRecordingSource(layer_settings(), &client_, - pile.Pass()); + recording.Pass()); root->SetBounds(gfx::Size(10000, 10000)); root->SetContentsOpaque(true); @@ -5094,21 +5352,19 @@ class LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles pinch->SetIsContainerForFixedPositionLayers(true); root->AddChild(pinch); - scoped_ptr<FakePicturePile> pile( - new FakePicturePile(LayerTreeSettings().minimum_contents_scale, - LayerTreeSettings().default_tile_grid_size)); - pile->SetPlaybackAllowedEvent(&playback_allowed_event_); + scoped_ptr<FakeDisplayListRecordingSource> recording( + new FakeDisplayListRecordingSource); + recording->SetPlaybackAllowedEvent(&playback_allowed_event_); scoped_refptr<FakePictureLayer> layer = FakePictureLayer::CreateWithRecordingSource(layer_settings(), &client_, - pile.Pass()); + recording.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()->RegisterViewportLayers(NULL, root, pinch, nullptr); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f); layer_tree_host()->SetRootLayer(root); LayerTreeHostTest::SetupTree(); @@ -5495,12 +5751,10 @@ class LayerTreeHostTestUpdateCopyRequests : public LayerTreeHostTest { case 1: child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest( base::Bind(CopyOutputCallback))); - EXPECT_TRUE( - root->draw_properties().layer_or_descendant_has_copy_request); + EXPECT_GT(root->num_layer_or_descendants_with_copy_request(), 0); break; case 2: - EXPECT_FALSE( - root->draw_properties().layer_or_descendant_has_copy_request); + EXPECT_EQ(root->num_layer_or_descendants_with_copy_request(), 0); EndTest(); break; } @@ -6057,5 +6311,87 @@ class LayerTreeTestPageScaleFlags : public LayerTreeTest { SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestPageScaleFlags); +class LayerTreeHostScrollingAndScalingUpdatesLayers : public LayerTreeHostTest { + public: + LayerTreeHostScrollingAndScalingUpdatesLayers() + : requested_update_layers_(false), commit_count_(0) {} + + void SetupTree() override { + LayerTreeHostTest::SetupTree(); + Layer* root_layer = layer_tree_host()->root_layer(); + scoped_refptr<Layer> scroll_layer = Layer::Create(layer_settings()); + CreateVirtualViewportLayers(root_layer, scroll_layer, root_layer->bounds(), + root_layer->bounds(), layer_tree_host(), + layer_settings()); + } + + void BeginTest() override { + LayerTreeHostCommon::ScrollUpdateInfo scroll; + scroll.layer_id = layer_tree_host()->root_layer()->id(); + scroll.scroll_delta = gfx::Vector2d(0, 33); + scroll_info_.scrolls.push_back(scroll); + + scale_info_.page_scale_delta = 2.71f; + + PostSetNeedsCommitToMainThread(); + } + + void BeginMainFrame(const BeginFrameArgs& args) override { + switch (commit_count_) { + case 0: + requested_update_layers_ = false; + layer_tree_host()->ApplyScrollAndScale(&no_op_info_); + EXPECT_FALSE(requested_update_layers_); + break; + case 1: + requested_update_layers_ = false; + layer_tree_host()->ApplyScrollAndScale(&scale_info_); + EXPECT_TRUE(requested_update_layers_); + break; + case 2: + requested_update_layers_ = false; + layer_tree_host()->ApplyScrollAndScale(&scroll_info_); + EXPECT_TRUE(requested_update_layers_); + EndTest(); + break; + default: + NOTREACHED(); + } + } + + void DidSetNeedsUpdateLayers() override { requested_update_layers_ = true; } + + void DidCommit() override { + if (++commit_count_ < 3) + PostSetNeedsCommitToMainThread(); + } + + void AfterTest() override {} + + ScrollAndScaleSet scroll_info_; + ScrollAndScaleSet scale_info_; + ScrollAndScaleSet no_op_info_; + bool requested_update_layers_; + int commit_count_; +}; + +MULTI_THREAD_TEST_F(LayerTreeHostScrollingAndScalingUpdatesLayers); + +class LayerTreeHostTestDestroyWhileInitializingOutputSurface + : public LayerTreeHostTest { + protected: + void BeginTest() override { + // By ending the test immediately we start initialization of an output + // surface but destroy the LTH before it completes. This test verifies + // that this works correctly and the output surface is destroyed on + // the correct thread. + EndTest(); + } + + void AfterTest() override {} +}; + +MULTI_THREAD_TEST_F(LayerTreeHostTestDestroyWhileInitializingOutputSurface); + } // namespace } // 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 9b16e39cb83..c9f922020b2 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc @@ -8,6 +8,8 @@ #include "cc/animation/layer_animation_controller.h" #include "cc/animation/scroll_offset_animation_curve.h" #include "cc/animation/timing_function.h" +#include "cc/animation/transform_operations.h" +#include "cc/base/completion_event.h" #include "cc/base/time_util.h" #include "cc/layers/layer.h" #include "cc/layers/layer_impl.h" @@ -227,8 +229,6 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimationsGetDeleted); class LayerTreeHostAnimationTestAddAnimationWithTimingFunction : public LayerTreeHostAnimationTest { public: - LayerTreeHostAnimationTestAddAnimationWithTimingFunction() {} - void SetupTree() override { LayerTreeHostAnimationTest::SetupTree(); picture_ = FakePictureLayer::Create(layer_settings(), &client_); @@ -240,6 +240,10 @@ class LayerTreeHostAnimationTestAddAnimationWithTimingFunction void AnimateLayers(LayerTreeHostImpl* host_impl, base::TimeTicks monotonic_time) override { + // TODO(ajuma): This test only checks the active tree. Add checks for + // pending tree too. + if (!host_impl->active_tree()->root_layer()) + return; LayerAnimationController* controller_impl = host_impl->active_tree()->root_layer()->children()[0]-> layer_animation_controller(); @@ -276,8 +280,6 @@ SINGLE_AND_MULTI_THREAD_TEST_F( class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes : public LayerTreeHostAnimationTest { public: - LayerTreeHostAnimationTestSynchronizeAnimationStartTimes() {} - void SetupTree() override { LayerTreeHostAnimationTest::SetupTree(); picture_ = FakePictureLayer::Create(layer_settings(), &client_); @@ -331,8 +333,6 @@ SINGLE_AND_MULTI_THREAD_TEST_F( class LayerTreeHostAnimationTestAnimationFinishedEvents : public LayerTreeHostAnimationTest { public: - LayerTreeHostAnimationTestAnimationFinishedEvents() {} - void BeginTest() override { PostAddInstantAnimationToMainThread(layer_tree_host()->root_layer()); } @@ -404,8 +404,6 @@ SINGLE_AND_MULTI_THREAD_TEST_F( class LayerTreeHostAnimationTestLayerAddedWithAnimation : public LayerTreeHostAnimationTest { public: - LayerTreeHostAnimationTestLayerAddedWithAnimation() {} - void BeginTest() override { PostSetNeedsCommitToMainThread(); } void DidCommit() override { @@ -547,49 +545,6 @@ class LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit); -// Make sure the main thread can still execute animations when CanDraw() is not -// true. -class LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw - : public LayerTreeHostAnimationTest { - public: - LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw() : started_times_(0) {} - - void SetupTree() override { - LayerTreeHostAnimationTest::SetupTree(); - picture_ = FakePictureLayer::Create(layer_settings(), &client_); - picture_->SetBounds(gfx::Size(4, 4)); - picture_->set_layer_animation_delegate(this); - layer_tree_host()->root_layer()->AddChild(picture_); - } - - void BeginTest() override { - layer_tree_host()->SetViewportSize(gfx::Size()); - PostAddAnimationToMainThread(picture_.get()); - } - - void NotifyAnimationStarted(base::TimeTicks monotonic_time, - Animation::TargetProperty target_property, - int group) override { - started_times_++; - } - - void NotifyAnimationFinished(base::TimeTicks monotonic_time, - Animation::TargetProperty target_property, - int group) override { - EndTest(); - } - - void AfterTest() override { EXPECT_EQ(1, started_times_); } - - private: - int started_times_; - FakeContentLayerClient client_; - scoped_refptr<FakePictureLayer> picture_; -}; - -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw); - // Animations should not be started when frames are being skipped due to // checkerboard. class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations @@ -610,7 +565,6 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations void BeginTest() override { prevented_draw_ = 0; - added_animations_ = 0; started_times_ = 0; PostSetNeedsCommitToMainThread(); @@ -619,7 +573,8 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, LayerTreeHostImpl::FrameData* frame_data, DrawResult draw_result) override { - if (added_animations_ < 2) + // Don't checkerboard when the first animation wants to start. + if (host_impl->active_tree()->source_frame_number() < 2) return draw_result; if (TestEnded()) return draw_result; @@ -635,12 +590,10 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations case 1: // The animation is longer than 1 BeginFrame interval. AddOpacityTransitionToLayer(picture_.get(), 0.1, 0.2f, 0.8f, false); - added_animations_++; break; case 2: // This second animation will not be drawn so it should not start. AddAnimatedTransformToLayer(picture_.get(), 0.1, 5, 5); - added_animations_++; break; } } @@ -662,7 +615,6 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations } int prevented_draw_; - int added_animations_; int started_times_; FakeContentLayerClient client_; scoped_refptr<FakePictureLayer> picture_; @@ -677,8 +629,6 @@ MULTI_THREAD_TEST_F( class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated : public LayerTreeHostAnimationTest { public: - LayerTreeHostAnimationTestScrollOffsetChangesArePropagated() {} - void SetupTree() override { LayerTreeHostAnimationTest::SetupTree(); @@ -921,13 +871,77 @@ class LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers MULTI_THREAD_BLOCKNOTIFY_TEST_F( LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers); +class LayerTreeHostAnimationTestPendingTreeAnimatesFirstCommit + : public LayerTreeHostAnimationTest { + public: + void SetupTree() override { + LayerTreeHostAnimationTest::SetupTree(); + + layer_ = FakePictureLayer::Create(layer_settings(), &client_); + layer_->SetBounds(gfx::Size(2, 2)); + // Transform the layer to 4,4 to start. + gfx::Transform start_transform; + start_transform.Translate(4.0, 4.0); + layer_->SetTransform(start_transform); + + layer_tree_host()->root_layer()->AddChild(layer_); + } + + void BeginTest() override { + // Add a translate from 6,7 to 8,9. + TransformOperations start; + start.AppendTranslate(6.f, 7.f, 0.f); + TransformOperations end; + end.AppendTranslate(8.f, 9.f, 0.f); + AddAnimatedTransformToLayer(layer_.get(), 4.0, start, end); + + PostSetNeedsCommitToMainThread(); + } + + void WillPrepareTiles(LayerTreeHostImpl* host_impl) override { + if (host_impl->sync_tree()->source_frame_number() != 0) + return; + + // After checking this on the sync tree, we will activate, which will cause + // PrepareTiles to happen again (which races with the test exiting). + if (TestEnded()) + return; + + LayerImpl* root = host_impl->sync_tree()->root_layer(); + LayerImpl* child = root->children()[0]; + LayerAnimationController* controller_impl = + child->layer_animation_controller(); + Animation* animation = controller_impl->GetAnimation(Animation::TRANSFORM); + + // The animation should be starting for the first frame. + EXPECT_EQ(Animation::STARTING, animation->run_state()); + + // And the transform should be propogated to the sync tree layer, at its + // starting state which is 6,7. + gfx::Transform expected_transform; + expected_transform.Translate(6.0, 7.0); + EXPECT_EQ(expected_transform, child->draw_transform()); + // And the sync tree layer should know it is animating. + EXPECT_TRUE(child->screen_space_transform_is_animating()); + + controller_impl->AbortAnimations(Animation::TRANSFORM); + EndTest(); + } + + void AfterTest() override {} + + FakeContentLayerClient client_; + scoped_refptr<Layer> layer_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F( + LayerTreeHostAnimationTestPendingTreeAnimatesFirstCommit); + // When a layer with an animation is removed from the tree and later re-added, // the animation should resume. class LayerTreeHostAnimationTestAnimatedLayerRemovedAndAdded : public LayerTreeHostAnimationTest { public: - LayerTreeHostAnimationTestAnimatedLayerRemovedAndAdded() {} - void SetupTree() override { LayerTreeHostAnimationTest::SetupTree(); layer_ = Layer::Create(layer_settings()); @@ -1030,6 +1044,228 @@ class LayerTreeHostAnimationTestAddAnimationAfterAnimating SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostAnimationTestAddAnimationAfterAnimating); +class LayerTreeHostAnimationTestRemoveAnimation + : public LayerTreeHostAnimationTest { + public: + void SetupTree() override { + LayerTreeHostAnimationTest::SetupTree(); + layer_ = FakePictureLayer::Create(layer_settings(), &client_); + layer_->SetBounds(gfx::Size(4, 4)); + layer_tree_host()->root_layer()->AddChild(layer_); + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void DidCommit() override { + switch (layer_tree_host()->source_frame_number()) { + case 1: + AddAnimatedTransformToLayer(layer_.get(), 1.0, 5, 5); + break; + case 2: + LayerAnimationController* controller = + layer_->layer_animation_controller(); + Animation* animation = controller->GetAnimation(Animation::TRANSFORM); + layer_->RemoveAnimation(animation->id()); + gfx::Transform transform; + transform.Translate(10.f, 10.f); + layer_->SetTransform(transform); + + // Do something that causes property trees to get rebuilt. This is + // intended to simulate the conditions that caused the bug whose fix + // this is testing (the test will pass without it but won't test what + // we want it to). We were updating the wrong transform node at the end + // of an animation (we were assuming the layer with the finished + // animation still had its own transform node). But nodes can only get + // added/deleted when something triggers a rebuild. Adding a layer + // triggers a rebuild, and since the layer that had an animation before + // no longer has one, it doesn't get a transform node in the rebuild. + layer_->AddChild(Layer::Create(layer_settings())); + break; + } + } + + void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { + LayerImpl* root = host_impl->active_tree()->root_layer(); + LayerImpl* child = root->children()[0]; + switch (host_impl->active_tree()->source_frame_number()) { + case 0: + // No animation yet. + break; + case 1: + // Animation is started. + EXPECT_TRUE(child->screen_space_transform_is_animating()); + break; + case 2: { + // The animation is removed, the transform that was set afterward is + // applied. + gfx::Transform expected_transform; + expected_transform.Translate(10.f, 10.f); + EXPECT_EQ(expected_transform, child->draw_transform()); + EXPECT_FALSE(child->screen_space_transform_is_animating()); + EndTest(); + break; + } + default: + NOTREACHED(); + } + } + + void AfterTest() override {} + + private: + scoped_refptr<Layer> layer_; + FakeContentLayerClient client_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestRemoveAnimation); + +class LayerTreeHostAnimationTestIsAnimating + : public LayerTreeHostAnimationTest { + public: + void SetupTree() override { + LayerTreeHostAnimationTest::SetupTree(); + layer_ = FakePictureLayer::Create(layer_settings(), &client_); + layer_->SetBounds(gfx::Size(4, 4)); + layer_tree_host()->root_layer()->AddChild(layer_); + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void DidCommit() override { + switch (layer_tree_host()->source_frame_number()) { + case 1: + AddAnimatedTransformToLayer(layer_.get(), 1.0, 5, 5); + break; + case 2: + LayerAnimationController* controller = + layer_->layer_animation_controller(); + Animation* animation = controller->GetAnimation(Animation::TRANSFORM); + layer_->RemoveAnimation(animation->id()); + break; + } + } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + LayerImpl* root = host_impl->sync_tree()->root_layer(); + LayerImpl* child = root->children()[0]; + switch (host_impl->sync_tree()->source_frame_number()) { + case 0: + // No animation yet. + break; + case 1: + // Animation is started. + EXPECT_TRUE(child->screen_space_transform_is_animating()); + break; + case 2: + // The animation is removed/stopped. + EXPECT_FALSE(child->screen_space_transform_is_animating()); + EndTest(); + break; + default: + NOTREACHED(); + } + } + + void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { + LayerImpl* root = host_impl->active_tree()->root_layer(); + LayerImpl* child = root->children()[0]; + switch (host_impl->active_tree()->source_frame_number()) { + case 0: + // No animation yet. + break; + case 1: + // Animation is started. + EXPECT_TRUE(child->screen_space_transform_is_animating()); + break; + case 2: + // The animation is removed/stopped. + EXPECT_FALSE(child->screen_space_transform_is_animating()); + EndTest(); + break; + default: + NOTREACHED(); + } + } + + void AfterTest() override {} + + private: + scoped_refptr<Layer> layer_; + FakeContentLayerClient client_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestIsAnimating); + +class LayerTreeHostAnimationTestAnimationFinishesDuringCommit + : public LayerTreeHostAnimationTest { + public: + LayerTreeHostAnimationTestAnimationFinishesDuringCommit() + : signalled_(false) {} + + void SetupTree() override { + LayerTreeHostAnimationTest::SetupTree(); + layer_ = FakePictureLayer::Create(layer_settings(), &client_); + layer_->SetBounds(gfx::Size(4, 4)); + layer_tree_host()->root_layer()->AddChild(layer_); + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void DidCommit() override { + if (layer_tree_host()->source_frame_number() == 1) + AddAnimatedTransformToLayer(layer_.get(), 0.04, 5, 5); + } + + void WillCommit() override { + if (layer_tree_host()->source_frame_number() == 2) { + // Block until the animation finishes on the compositor thread. Since + // animations have already been ticked on the main thread, when the commit + // happens the state on the main thread will be consistent with having a + // running animation but the state on the compositor thread will be + // consistent with having only a finished animation. + completion_.Wait(); + } + } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + switch (host_impl->sync_tree()->source_frame_number()) { + case 1: + PostSetNeedsCommitToMainThread(); + break; + case 2: + gfx::Transform expected_transform; + expected_transform.Translate(5.f, 5.f); + LayerImpl* layer_impl = + host_impl->sync_tree()->root_layer()->children()[0]; + EXPECT_EQ(expected_transform, layer_impl->draw_transform()); + EndTest(); + break; + } + } + + void UpdateAnimationState(LayerTreeHostImpl* host_impl, + bool has_unfinished_animation) override { + if (host_impl->active_tree()->source_frame_number() == 1 && + !has_unfinished_animation && !signalled_) { + // The animation has finished, so allow the main thread to commit. + completion_.Signal(); + signalled_ = true; + } + } + + void AfterTest() override {} + + private: + scoped_refptr<Layer> layer_; + FakeContentLayerClient client_; + CompletionEvent completion_; + bool signalled_; +}; + +// An animation finishing during commit can only happen when we have a separate +// compositor thread. +MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimationFinishesDuringCommit); + class LayerTreeHostAnimationTestNotifyAnimationFinished : public LayerTreeHostAnimationTest { public: @@ -1045,7 +1281,6 @@ class LayerTreeHostAnimationTestNotifyAnimationFinished } void BeginTest() override { - layer_tree_host()->SetViewportSize(gfx::Size()); PostAddLongAnimationToMainThread(picture_.get()); } diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation_timelines.cc b/chromium/cc/trees/layer_tree_host_unittest_animation_timelines.cc index 4bf8e83d221..ca7e754b1fb 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_animation_timelines.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_animation_timelines.cc @@ -13,6 +13,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/completion_event.h" #include "cc/base/time_util.h" #include "cc/layers/layer.h" #include "cc/layers/layer_impl.h" @@ -443,53 +444,6 @@ class LayerTreeHostTimelinesTestLayerAddedWithAnimation SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostTimelinesTestLayerAddedWithAnimation); -// Make sure the main thread can still execute animations when CanDraw() is not -// true. -// Evolved from LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw -class LayerTreeHostTimelinesTestRunAnimationWhenNotCanDraw - : public LayerTreeHostTimelinesTest { - public: - LayerTreeHostTimelinesTestRunAnimationWhenNotCanDraw() : started_times_(0) {} - - void SetupTree() override { - LayerTreeHostTimelinesTest::SetupTree(); - picture_ = FakePictureLayer::Create(layer_settings(), &client_); - picture_->SetBounds(gfx::Size(4, 4)); - layer_tree_host()->root_layer()->AddChild(picture_); - - AttachPlayersToTimeline(); - player_child_->AttachLayer(picture_->id()); - player_child_->set_layer_animation_delegate(this); - } - - void BeginTest() override { - layer_tree_host()->SetViewportSize(gfx::Size()); - PostAddAnimationToMainThreadPlayer(player_child_.get()); - } - - void NotifyAnimationStarted(base::TimeTicks monotonic_time, - Animation::TargetProperty target_property, - int group) override { - started_times_++; - } - - void NotifyAnimationFinished(base::TimeTicks monotonic_time, - Animation::TargetProperty target_property, - int group) override { - EndTest(); - } - - void AfterTest() override { EXPECT_EQ(1, started_times_); } - - private: - int started_times_; - FakeContentLayerClient client_; - scoped_refptr<FakePictureLayer> picture_; -}; - -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostTimelinesTestRunAnimationWhenNotCanDraw); - // Animations should not be started when frames are being skipped due to // checkerboard. // Evolved from LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations. @@ -515,7 +469,6 @@ class LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations void BeginTest() override { prevented_draw_ = 0; - added_animations_ = 0; started_times_ = 0; PostSetNeedsCommitToMainThread(); @@ -524,7 +477,8 @@ class LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, LayerTreeHostImpl::FrameData* frame_data, DrawResult draw_result) override { - if (added_animations_ < 2) + // Don't checkerboard when the first animation wants to start. + if (host_impl->active_tree()->source_frame_number() < 2) return draw_result; if (TestEnded()) return draw_result; @@ -541,12 +495,10 @@ class LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations // The animation is longer than 1 BeginFrame interval. AddOpacityTransitionToPlayer(player_child_.get(), 0.1, 0.2f, 0.8f, false); - added_animations_++; break; case 2: // This second animation will not be drawn so it should not start. AddAnimatedTransformToPlayer(player_child_.get(), 0.1, 5, 5); - added_animations_++; break; } } @@ -568,7 +520,6 @@ class LayerTreeHostTimelinesTestCheckerboardDoesntStartAnimations } int prevented_draw_; - int added_animations_; int started_times_; FakeContentLayerClient client_; scoped_refptr<FakePictureLayer> picture_; @@ -919,5 +870,133 @@ class LayerTreeHostTimelinesTestAddAnimationAfterAnimating SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostTimelinesTestAddAnimationAfterAnimating); +class LayerTreeHostTimelinesTestRemoveAnimation + : public LayerTreeHostTimelinesTest { + public: + void SetupTree() override { + LayerTreeHostTimelinesTest::SetupTree(); + layer_ = FakePictureLayer::Create(layer_settings(), &client_); + layer_->SetBounds(gfx::Size(4, 4)); + layer_tree_host()->root_layer()->AddChild(layer_); + + AttachPlayersToTimeline(); + + player_->AttachLayer(layer_tree_host()->root_layer()->id()); + player_child_->AttachLayer(layer_->id()); + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void DidCommit() override { + switch (layer_tree_host()->source_frame_number()) { + case 1: + AddAnimatedTransformToPlayer(player_child_.get(), 1.0, 5, 5); + break; + case 2: + LayerAnimationController* controller = + player_child_->element_animations()->layer_animation_controller(); + Animation* animation = controller->GetAnimation(Animation::TRANSFORM); + player_child_->RemoveAnimation(animation->id()); + gfx::Transform transform; + transform.Translate(10.f, 10.f); + layer_->SetTransform(transform); + + // Do something that causes property trees to get rebuilt. + layer_->AddChild(Layer::Create(layer_settings())); + break; + } + } + + void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { + if (host_impl->active_tree()->source_frame_number() < 2) + return; + gfx::Transform expected_transform; + expected_transform.Translate(10.f, 10.f); + EXPECT_EQ(expected_transform, host_impl->active_tree() + ->root_layer() + ->children()[0] + ->draw_transform()); + EndTest(); + } + + void AfterTest() override {} + + private: + scoped_refptr<Layer> layer_; + FakeContentLayerClient client_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTimelinesTestRemoveAnimation); + +class LayerTreeHostTimelinesTestAnimationFinishesDuringCommit + : public LayerTreeHostTimelinesTest { + public: + void SetupTree() override { + LayerTreeHostTimelinesTest::SetupTree(); + layer_ = FakePictureLayer::Create(layer_settings(), &client_); + layer_->SetBounds(gfx::Size(4, 4)); + layer_tree_host()->root_layer()->AddChild(layer_); + + AttachPlayersToTimeline(); + + player_->AttachLayer(layer_tree_host()->root_layer()->id()); + player_child_->AttachLayer(layer_->id()); + } + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void DidCommit() override { + if (layer_tree_host()->source_frame_number() == 1) + AddAnimatedTransformToPlayer(player_child_.get(), 0.04, 5, 5); + } + + void WillCommit() override { + if (layer_tree_host()->source_frame_number() == 2) { + // Block until the animation finishes on the compositor thread. Since + // animations have already been ticked on the main thread, when the commit + // happens the state on the main thread will be consistent with having a + // running animation but the state on the compositor thread will be + // consistent with having only a finished animation. + completion_.Wait(); + } + } + + void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { + switch (host_impl->sync_tree()->source_frame_number()) { + case 1: + PostSetNeedsCommitToMainThread(); + break; + case 2: + gfx::Transform expected_transform; + expected_transform.Translate(5.f, 5.f); + LayerImpl* layer_impl = + host_impl->sync_tree()->root_layer()->children()[0]; + EXPECT_EQ(expected_transform, layer_impl->draw_transform()); + EndTest(); + break; + } + } + + void UpdateAnimationState(LayerTreeHostImpl* host_impl, + bool has_unfinished_animation) override { + if (host_impl->active_tree()->source_frame_number() == 1 && + !has_unfinished_animation) { + // The animation has finished, so allow the main thread to commit. + completion_.Signal(); + } + } + + void AfterTest() override {} + + private: + scoped_refptr<Layer> layer_; + FakeContentLayerClient client_; + CompletionEvent completion_; +}; + +// An animation finishing during commit can only happen when we have a separate +// compositor thread. +MULTI_THREAD_TEST_F(LayerTreeHostTimelinesTestAnimationFinishesDuringCommit); + } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc index d25d047d0a7..34a70b9ab45 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_context.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc @@ -33,7 +33,7 @@ #include "cc/test/fake_scrollbar.h" #include "cc/test/fake_video_frame_provider.h" #include "cc/test/layer_tree_test.h" -#include "cc/test/render_pass_test_common.h" +#include "cc/test/render_pass_test_utils.h" #include "cc/test/test_context_provider.h" #include "cc/test/test_shared_bitmap_manager.h" #include "cc/test/test_web_graphics_context_3d.h" @@ -382,6 +382,70 @@ class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface SINGLE_AND_MULTI_THREAD_TEST_F( LayerTreeHostClientNotReadyDoesNotCreateOutputSurface); +// This tests the OutputSurface release logic in the following sequence. +// SetUp LTH and create and init OutputSurface +// LTH::SetVisible(false); +// LTH::ReleaseOutputSurface(); +// ... +// LTH::SetVisible(true); +// Create and init new OutputSurface +class LayerTreeHostClientTakeAwayOutputSurface + : public LayerTreeHostContextTest { + public: + LayerTreeHostClientTakeAwayOutputSurface() + : LayerTreeHostContextTest(), setos_counter_(0) {} + + void BeginTest() override { PostSetNeedsCommitToMainThread(); } + + void RequestNewOutputSurface() override { + if (layer_tree_host()->visible()) + CreateAndSetOutputSurface(); + } + + void CreateAndSetOutputSurface() { + scoped_ptr<OutputSurface> surface = + LayerTreeHostContextTest::CreateOutputSurface(); + CHECK(surface); + setos_counter_++; + layer_tree_host()->SetOutputSurface(surface.Pass()); + } + + void HideAndReleaseOutputSurface() { + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); + layer_tree_host()->SetVisible(false); + scoped_ptr<OutputSurface> surface = + layer_tree_host()->ReleaseOutputSurface(); + CHECK(surface); + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&LayerTreeHostClientTakeAwayOutputSurface::MakeVisible, + base::Unretained(this))); + } + + void DidInitializeOutputSurface() override { + EXPECT_TRUE(layer_tree_host()->visible()); + if (setos_counter_ == 1) { + MainThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&LayerTreeHostClientTakeAwayOutputSurface:: + HideAndReleaseOutputSurface, + base::Unretained(this))); + } else { + EndTest(); + } + } + + void MakeVisible() { + EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); + layer_tree_host()->SetVisible(true); + } + + void AfterTest() override {} + + int setos_counter_; +}; + +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostClientTakeAwayOutputSurface); + class MultipleCompositeDoesNotCreateOutputSurface : public LayerTreeHostContextTest { public: @@ -391,7 +455,6 @@ class MultipleCompositeDoesNotCreateOutputSurface void InitializeSettings(LayerTreeSettings* settings) override { settings->single_thread_proxy_scheduler = false; settings->use_zero_copy = true; - settings->use_one_copy = false; } void RequestNewOutputSurface() override { @@ -431,7 +494,6 @@ class FailedCreateDoesNotCreateExtraOutputSurface void InitializeSettings(LayerTreeSettings* settings) override { settings->single_thread_proxy_scheduler = false; settings->use_zero_copy = true; - settings->use_one_copy = false; } void RequestNewOutputSurface() override { @@ -485,7 +547,6 @@ class LayerTreeHostContextTestCommitAfterDelayedOutputSurface void InitializeSettings(LayerTreeSettings* settings) override { settings->single_thread_proxy_scheduler = false; settings->use_zero_copy = true; - settings->use_one_copy = false; } void RequestNewOutputSurface() override { @@ -528,7 +589,6 @@ class LayerTreeHostContextTestAvoidUnnecessaryComposite void InitializeSettings(LayerTreeSettings* settings) override { settings->single_thread_proxy_scheduler = false; settings->use_zero_copy = true; - settings->use_one_copy = false; } void RequestNewOutputSurface() override { @@ -565,7 +625,7 @@ class LayerTreeHostContextTestLostContextSucceedsWithContent // Paint non-solid color. SkPaint paint; paint.setColor(SkColorSetARGB(100, 80, 200, 200)); - client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint); + client_.add_draw_rect(gfx::Rect(5, 5), paint); layer_ = FakePictureLayer::Create(layer_settings(), &client_); layer_->SetBounds(gfx::Size(10, 10)); @@ -643,7 +703,7 @@ class LayerTreeHostContextTestLostContextAndEvictTextures // Paint non-solid color. SkPaint paint; paint.setColor(SkColorSetARGB(100, 80, 200, 200)); - client_.add_draw_rect(gfx::Rect(0, 0, 5, 5), paint); + client_.add_draw_rect(gfx::Rect(5, 5), paint); scoped_refptr<FakePictureLayer> picture_layer = FakePictureLayer::Create(layer_settings(), &client_); @@ -857,7 +917,7 @@ class LayerTreeHostContextTestDontUseLostResources scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); - scoped_ptr<TestRenderPass> pass_for_quad = TestRenderPass::Create(); + scoped_ptr<RenderPass> pass_for_quad = RenderPass::Create(); pass_for_quad->SetNew( // AppendOneOfEveryQuadType() makes a RenderPass quad with this id. RenderPassId(2, 1), @@ -865,13 +925,14 @@ class LayerTreeHostContextTestDontUseLostResources gfx::Rect(0, 0, 10, 10), gfx::Transform()); - scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); + scoped_ptr<RenderPass> pass = RenderPass::Create(); pass->SetNew(RenderPassId(1, 1), gfx::Rect(0, 0, 10, 10), gfx::Rect(0, 0, 10, 10), gfx::Transform()); - pass->AppendOneOfEveryQuadType(child_resource_provider_.get(), - RenderPassId(2, 1)); + uint32_t mailbox_sync_point; + AddOneOfEveryQuadType(pass.get(), child_resource_provider_.get(), + RenderPassId(2, 1), &mailbox_sync_point); frame_data->render_pass_list.push_back(pass_for_quad.Pass()); frame_data->render_pass_list.push_back(pass.Pass()); @@ -950,12 +1011,12 @@ class LayerTreeHostContextTestDontUseLostResources color_video_frame_ = VideoFrame::CreateColorFrame( gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta()); hw_video_frame_ = VideoFrame::WrapNativeTexture( - media::VideoFrame::ARGB, + media::PIXEL_FORMAT_ARGB, 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()); scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture( - media::VideoFrame::ARGB, + media::PIXEL_FORMAT_ARGB, 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()); @@ -1521,67 +1582,6 @@ class UIResourceLostEviction : public UIResourceLostTestSimple { SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostEviction); -class LayerTreeHostContextTestSurfaceCreateCallback - : public LayerTreeHostContextTest { - public: - LayerTreeHostContextTestSurfaceCreateCallback() - : LayerTreeHostContextTest() {} - - void SetupTree() override { - picture_layer_ = FakePictureLayer::Create(layer_settings(), &client_); - picture_layer_->SetBounds(gfx::Size(10, 20)); - layer_tree_host()->SetRootLayer(picture_layer_); - - LayerTreeHostContextTest::SetupTree(); - } - - void BeginTest() override { PostSetNeedsCommitToMainThread(); } - - void DidCommit() override { - switch (layer_tree_host()->source_frame_number()) { - case 1: - EXPECT_EQ(1u, picture_layer_->output_surface_created_count()); - layer_tree_host()->SetNeedsCommit(); - break; - case 2: - EXPECT_EQ(1u, picture_layer_->output_surface_created_count()); - layer_tree_host()->SetNeedsCommit(); - break; - case 3: - EXPECT_EQ(1u, picture_layer_->output_surface_created_count()); - break; - case 4: - EXPECT_EQ(2u, picture_layer_->output_surface_created_count()); - layer_tree_host()->SetNeedsCommit(); - break; - } - } - - void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { - LayerTreeHostContextTest::CommitCompleteOnThread(impl); - switch (LastCommittedSourceFrameNumber(impl)) { - case 0: - break; - case 1: - break; - case 2: - LoseContext(); - break; - case 3: - EndTest(); - break; - } - } - - void AfterTest() override {} - - protected: - FakeContentLayerClient client_; - scoped_refptr<FakePictureLayer> picture_layer_; -}; - -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback); - class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame : public LayerTreeHostContextTest { protected: diff --git a/chromium/cc/trees/layer_tree_host_unittest_damage.cc b/chromium/cc/trees/layer_tree_host_unittest_damage.cc index fc5cacf087e..20667bf54a2 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_damage.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_damage.cc @@ -55,17 +55,17 @@ class LayerTreeHostDamageTestSetNeedsRedraw RenderSurfaceImpl* root_surface = impl->active_tree()->root_layer()->render_surface(); - gfx::RectF root_damage = + gfx::Rect root_damage = root_surface->damage_tracker()->current_damage_rect(); switch (draw_count_) { case 0: // The first frame has full damage. - EXPECT_EQ(gfx::RectF(10.f, 10.f).ToString(), root_damage.ToString()); + EXPECT_EQ(gfx::Rect(10, 10), root_damage); break; case 1: // The second frame has full damage. - EXPECT_EQ(gfx::RectF(10.f, 10.f).ToString(), root_damage.ToString()); + EXPECT_EQ(gfx::Rect(10, 10), root_damage); EndTest(); break; case 2: @@ -117,17 +117,17 @@ class LayerTreeHostDamageTestSetViewportSize RenderSurfaceImpl* root_surface = impl->active_tree()->root_layer()->render_surface(); - gfx::RectF root_damage = + gfx::Rect root_damage = root_surface->damage_tracker()->current_damage_rect(); switch (draw_count_) { case 0: // The first frame has full damage. - EXPECT_EQ(gfx::RectF(10.f, 10.f).ToString(), root_damage.ToString()); + EXPECT_EQ(gfx::Rect(10, 10), root_damage); break; case 1: // The second frame has full damage. - EXPECT_EQ(gfx::RectF(15.f, 15.f).ToString(), root_damage.ToString()); + EXPECT_EQ(gfx::Rect(15, 15), root_damage); EndTest(); break; case 2: @@ -260,7 +260,7 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest { RenderSurfaceImpl* root_surface = host_impl->active_tree()->root_layer()->render_surface(); - gfx::RectF root_damage = + gfx::Rect root_damage = root_surface->damage_tracker()->current_damage_rect(); root_damage.Intersect(root_surface->content_rect()); @@ -268,13 +268,12 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest { switch (source_frame) { case 0: // The first frame draws and clears any damage. - EXPECT_EQ(gfx::RectF(root_surface->content_rect()).ToString(), - root_damage.ToString()); + EXPECT_EQ(root_surface->content_rect(), root_damage); EXPECT_FALSE(frame_data->has_no_damage); break; case 1: // If we get a frame without damage then we don't draw. - EXPECT_EQ(gfx::RectF().ToString(), root_damage.ToString()); + EXPECT_EQ(gfx::Rect(), root_damage); EXPECT_TRUE(frame_data->has_no_damage); // Then we set full damage for the next frame. @@ -282,8 +281,7 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest { break; case 2: // The whole frame should be damaged as requested. - EXPECT_EQ(gfx::RectF(root_surface->content_rect()).ToString(), - root_damage.ToString()); + EXPECT_EQ(root_surface->content_rect(), root_damage); EXPECT_FALSE(frame_data->has_no_damage); // Just a part of the next frame should be damaged. @@ -292,8 +290,7 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest { case 3: // The update rect in the child should be damaged and the damaged area // should match the invalidation. - EXPECT_EQ(gfx::RectF(100+10, 100+11, 12, 13).ToString(), - root_damage.ToString()); + EXPECT_EQ(gfx::Rect(100 + 10, 100 + 11, 12, 13), root_damage); EXPECT_FALSE(frame_data->has_no_damage); // If we damage part of the frame, but also damage the full @@ -303,8 +300,7 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest { break; case 4: // The whole frame is damaged. - EXPECT_EQ(gfx::RectF(root_surface->content_rect()).ToString(), - root_damage.ToString()); + EXPECT_EQ(root_surface->content_rect(), root_damage); EXPECT_FALSE(frame_data->has_no_damage); EndTest(); @@ -362,9 +358,9 @@ class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest { root_layer->AddChild(scrollbar_layer); gfx::RectF content_rect(content_layer->position(), - content_layer->bounds()); + gfx::SizeF(content_layer->bounds())); gfx::RectF scrollbar_rect(scrollbar_layer->position(), - scrollbar_layer->bounds()); + gfx::SizeF(scrollbar_layer->bounds())); EXPECT_FALSE(content_rect.Intersects(scrollbar_rect)); LayerTreeHostDamageTest::SetupTree(); @@ -387,7 +383,7 @@ class LayerTreeHostDamageTestScrollbarDoesDamage EXPECT_EQ(DRAW_SUCCESS, draw_result); RenderSurfaceImpl* root_surface = host_impl->active_tree()->root_layer()->render_surface(); - gfx::RectF root_damage = + gfx::Rect root_damage = root_surface->damage_tracker()->current_damage_rect(); root_damage.Intersect(root_surface->content_rect()); switch (did_swaps_) { @@ -421,10 +417,10 @@ class LayerTreeHostDamageTestScrollbarDoesDamage case 1: // 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->PushScrollOffsetFromMainThread( - scroll_layer->BaseScrollOffset()); - host_impl->SetNeedsRedraw(); + MainThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&LayerTreeHostDamageTestScrollbarDoesDamage:: + ModifyContentLayerPosition, + base::Unretained(this))); break; case 2: scroll_layer->ScrollBy(gfx::Vector2dF(10.f, 10.f)); @@ -441,6 +437,14 @@ class LayerTreeHostDamageTestScrollbarDoesDamage } } + void ModifyContentLayerPosition() { + EXPECT_EQ(1, did_swaps_); + Layer* root = layer_tree_host()->root_layer(); + Layer* scroll_clip_layer = root->child_at(0); + Layer* scroll_layer = scroll_clip_layer->child_at(0); + scroll_layer->SetPosition(gfx::Point(10, 10)); + } + void ResizeScrollLayer() { EXPECT_EQ(3, did_swaps_); Layer* root = layer_tree_host()->root_layer(); @@ -470,7 +474,7 @@ class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage EXPECT_EQ(DRAW_SUCCESS, draw_result); RenderSurfaceImpl* root_surface = host_impl->active_tree()->root_layer()->render_surface(); - gfx::RectF root_damage = + gfx::Rect root_damage = root_surface->damage_tracker()->current_damage_rect(); root_damage.Intersect(root_surface->content_rect()); int frame = host_impl->active_tree()->source_frame_number(); diff --git a/chromium/cc/trees/layer_tree_host_unittest_delegated.cc b/chromium/cc/trees/layer_tree_host_unittest_delegated.cc index 2ebb337e807..f5aafaf2efc 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_delegated.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_delegated.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/location.h" +#include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "base/time/time.h" @@ -1748,14 +1749,23 @@ class DelegatedFrameIsActivatedDuringCommit } void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override { + base::AutoLock lock(activate_count_lock_); ++activate_count_; } void DidCommit() override { + // The first frame doesn't cause anything to be returned so it does not + // need to wait for activation. + if (layer_tree_host()->source_frame_number() > 1) { + base::AutoLock lock(activate_count_lock_); + // The activate happened before commit is done on the main side. + EXPECT_EQ(activate_count_, layer_tree_host()->source_frame_number()); + } + switch (layer_tree_host()->source_frame_number()) { case 1: { - // The first frame has been activated. Set a new frame, and - // expect the next commit to finish *after* it is activated. + // The first frame has been committed and will activate. Set a new + // frame, and expect the next commit to finish *after* it is activated. scoped_ptr<DelegatedFrameData> frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 555); @@ -1779,27 +1789,9 @@ class DelegatedFrameIsActivatedDuringCommit } void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { - switch (host_impl->active_tree()->source_frame_number()) { - case 0: { - // The activate for the 1st frame should have happened before now. - EXPECT_EQ(1, activate_count_); - break; - } - case 1: { - // The activate for the 2nd frame should have happened before now. - EXPECT_EQ(2, activate_count_); - break; - } - case 2: { - // The activate to remove the layer should have happened before now. - EXPECT_EQ(3, activate_count_); - break; - } - case 3: { - NOTREACHED(); - break; - } - } + // The activate didn't happen before commit is done on the impl side (but it + // should happen before the main thread is done). + EXPECT_EQ(activate_count_, host_impl->sync_tree()->source_frame_number()); } void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override { @@ -1817,6 +1809,7 @@ class DelegatedFrameIsActivatedDuringCommit EndTest(); } + base::Lock activate_count_lock_; int activate_count_; size_t returned_resource_count_; }; diff --git a/chromium/cc/trees/layer_tree_host_unittest_picture.cc b/chromium/cc/trees/layer_tree_host_unittest_picture.cc index 7a0d7bfa520..9c5d00eddb1 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_picture.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_picture.cc @@ -210,6 +210,10 @@ class LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree picture_->SetBounds(gfx::Size(100, 100000)); root->AddChild(picture_); + // picture_'s transform is going to be changing on the compositor thread, so + // force it to have a transform node by making it scrollable. + picture_->SetScrollClipLayerId(root->id()); + layer_tree_host()->SetRootLayer(root); LayerTreeHostPictureTest::SetupTree(); } @@ -406,7 +410,7 @@ class LayerTreeHostPictureTestRSLLMembershipWithScale picture_->SetBounds(gfx::Size(100, 100)); pinch_->AddChild(picture_); - layer_tree_host()->RegisterViewportLayers(NULL, root, pinch_, pinch_); + layer_tree_host()->RegisterViewportLayers(NULL, root, pinch_, nullptr); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f); layer_tree_host()->SetRootLayer(root); LayerTreeHostPictureTest::SetupTree(); @@ -420,6 +424,7 @@ class LayerTreeHostPictureTestRSLLMembershipWithScale frame_ = 0; draws_in_frame_ = 0; last_frame_drawn_ = -1; + ready_to_draw_ = false; PostSetNeedsCommitToMainThread(); } @@ -428,19 +433,25 @@ class LayerTreeHostPictureTestRSLLMembershipWithScale LayerImpl* pinch = root->children()[0]; LayerImpl* gchild = pinch->children()[0]; FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild); + ready_to_draw_ = false; switch (frame_) { case 0: - // On 1st commit the layer has tilings. - EXPECT_GT(picture->tilings()->num_tilings(), 0u); + // On 1st commit the pending layer has tilings. + ASSERT_EQ(1u, picture->tilings()->num_tilings()); + EXPECT_EQ(1.f, picture->tilings()->tiling_at(0)->contents_scale()); break; case 1: - // On 2nd commit, the layer is transparent, so does not have tilings. - EXPECT_EQ(0u, picture->tilings()->num_tilings()); + // On 2nd commit, the pending layer is transparent, so has a stale + // value. + ASSERT_EQ(1u, picture->tilings()->num_tilings()); + EXPECT_EQ(1.f, picture->tilings()->tiling_at(0)->contents_scale()); break; case 2: - // On 3rd commit, the layer is visible again, so has tilings. - EXPECT_GT(picture->tilings()->num_tilings(), 0u); + // On 3rd commit, the pending layer is visible again, so has tilings and + // is updated for the pinch. + ASSERT_EQ(1u, picture->tilings()->num_tilings()); + EXPECT_EQ(2.f, picture->tilings()->tiling_at(0)->contents_scale()); } } @@ -470,30 +481,29 @@ class LayerTreeHostPictureTestRSLLMembershipWithScale // 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))); + + // Need to wait for ready to draw here so that the pinch is + // entirely complete, otherwise another draw might come in before + // the commit occurs. + if (ready_to_draw_) { + ++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()); + // On 2nd commit, this active layer is transparent, so does not update + // tilings. It has the high res scale=2 from the previous frame, and + // also a scale=1 copied from the pending layer's stale value during + // activation. + EXPECT_EQ(2u, picture->picture_layer_tiling_set()->num_tilings()); + ++frame_; MainThreadTaskRunner()->PostTask( FROM_HERE, @@ -524,6 +534,16 @@ class LayerTreeHostPictureTestRSLLMembershipWithScale } } + void NotifyReadyToDrawOnThread(LayerTreeHostImpl* impl) override { + ready_to_draw_ = true; + if (frame_ == 0) { + // The ready to draw can race with a draw in which everything is + // actually ready. Therefore, just issue one more extra draw + // here to force notify->draw ordering. + impl->SetNeedsRedraw(); + } + } + void AfterTest() override {} FakeContentLayerClient client_; @@ -532,12 +552,12 @@ class LayerTreeHostPictureTestRSLLMembershipWithScale int frame_; int draws_in_frame_; int last_frame_drawn_; + bool ready_to_draw_; }; // 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_TEST_F(LayerTreeHostPictureTestRSLLMembershipWithScale); +MULTI_THREAD_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 66340e7bbff..d4057cfa10a 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_proxy.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_proxy.cc @@ -4,6 +4,8 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "cc/test/fake_content_layer_client.h" +#include "cc/test/fake_picture_layer.h" #include "cc/test/layer_tree_test.h" #include "cc/trees/thread_proxy.h" @@ -71,9 +73,16 @@ PROXY_TEST_SCHEDULED_ACTION(ProxyTestScheduledActionsBasic); class ThreadProxyTest : public ProxyTest { protected: - ThreadProxyTest() {} + ThreadProxyTest() + : update_check_layer_( + FakePictureLayer::Create(layer_settings(), &client_)) {} ~ThreadProxyTest() override {} + void SetupTree() override { + layer_tree_host()->SetRootLayer(update_check_layer_); + ProxyTest::SetupTree(); + } + const ThreadProxy::MainThreadOnly& ThreadProxyMainOnly() const { DCHECK(proxy()); DCHECK(proxy()->HasImplThread()); @@ -86,6 +95,10 @@ class ThreadProxyTest : public ProxyTest { return static_cast<const ThreadProxy*>(proxy())->impl(); } + protected: + FakeContentLayerClient client_; + scoped_refptr<FakePictureLayer> update_check_layer_; + private: DISALLOW_COPY_AND_ASSIGN(ThreadProxyTest); }; @@ -96,19 +109,26 @@ class ThreadProxyTestSetNeedsCommit : public ThreadProxyTest { ~ThreadProxyTestSetNeedsCommit() override {} void BeginTest() override { - EXPECT_FALSE(ThreadProxyMainOnly().commit_requested); - EXPECT_FALSE(ThreadProxyMainOnly().commit_request_sent_to_impl_thread); + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); proxy()->SetNeedsCommit(); - EXPECT_TRUE(ThreadProxyMainOnly().commit_requested); - EXPECT_TRUE(ThreadProxyMainOnly().commit_request_sent_to_impl_thread); + EXPECT_EQ(ThreadProxy::COMMIT_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); } void DidBeginMainFrame() override { - EXPECT_FALSE(ThreadProxyMainOnly().commit_requested); - EXPECT_FALSE(ThreadProxyMainOnly().commit_request_sent_to_impl_thread); + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().current_pipeline_stage); + } + void DidCommit() override { + EXPECT_EQ(1, update_check_layer_->update_count()); + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().current_pipeline_stage); EndTest(); } @@ -118,4 +138,153 @@ class ThreadProxyTestSetNeedsCommit : public ThreadProxyTest { THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsCommit); +class ThreadProxyTestSetNeedsAnimate : public ThreadProxyTest { + protected: + ThreadProxyTestSetNeedsAnimate() {} + ~ThreadProxyTestSetNeedsAnimate() override {} + + void BeginTest() override { + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + + proxy()->SetNeedsAnimate(); + + EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + } + + void DidBeginMainFrame() override { + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().current_pipeline_stage); + } + + void DidCommit() override { + EXPECT_EQ(0, update_check_layer_->update_count()); + EndTest(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsAnimate); +}; + +THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsAnimate); + +class ThreadProxyTestSetNeedsUpdateLayers : public ThreadProxyTest { + protected: + ThreadProxyTestSetNeedsUpdateLayers() {} + ~ThreadProxyTestSetNeedsUpdateLayers() override {} + + void BeginTest() override { + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + + proxy()->SetNeedsUpdateLayers(); + + EXPECT_EQ(ThreadProxy::UPDATE_LAYERS_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + } + + void DidBeginMainFrame() override { + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().current_pipeline_stage); + } + + void DidCommit() override { + EXPECT_EQ(1, update_check_layer_->update_count()); + EndTest(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsUpdateLayers); +}; + +THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsUpdateLayers); + +class ThreadProxyTestSetNeedsUpdateLayersWhileAnimating + : public ThreadProxyTest { + protected: + ThreadProxyTestSetNeedsUpdateLayersWhileAnimating() {} + ~ThreadProxyTestSetNeedsUpdateLayersWhileAnimating() override {} + + void BeginTest() override { proxy()->SetNeedsAnimate(); } + + void WillBeginMainFrame() override { + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, + ThreadProxyMainOnly().current_pipeline_stage); + EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, + ThreadProxyMainOnly().final_pipeline_stage); + + proxy()->SetNeedsUpdateLayers(); + + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ThreadProxy::UPDATE_LAYERS_PIPELINE_STAGE, + ThreadProxyMainOnly().final_pipeline_stage); + } + + void DidBeginMainFrame() override { + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().current_pipeline_stage); + } + + void DidCommit() override { + EXPECT_EQ(1, update_check_layer_->update_count()); + EndTest(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsUpdateLayersWhileAnimating); +}; + +THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsUpdateLayersWhileAnimating); + +class ThreadProxyTestSetNeedsCommitWhileAnimating : public ThreadProxyTest { + protected: + ThreadProxyTestSetNeedsCommitWhileAnimating() {} + ~ThreadProxyTestSetNeedsCommitWhileAnimating() override {} + + void BeginTest() override { proxy()->SetNeedsAnimate(); } + + void WillBeginMainFrame() override { + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, + ThreadProxyMainOnly().current_pipeline_stage); + EXPECT_EQ(ThreadProxy::ANIMATE_PIPELINE_STAGE, + ThreadProxyMainOnly().final_pipeline_stage); + + proxy()->SetNeedsCommit(); + + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ThreadProxy::COMMIT_PIPELINE_STAGE, + ThreadProxyMainOnly().final_pipeline_stage); + } + + void DidBeginMainFrame() override { + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().max_requested_pipeline_stage); + EXPECT_EQ(ThreadProxy::NO_PIPELINE_STAGE, + ThreadProxyMainOnly().current_pipeline_stage); + } + + void DidCommit() override { + EXPECT_EQ(1, update_check_layer_->update_count()); + EndTest(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsCommitWhileAnimating); +}; + +THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsCommitWhileAnimating); + } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc index dc075b563cf..79fde4f24a6 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc @@ -28,7 +28,24 @@ namespace cc { namespace { -class LayerTreeHostScrollTest : public LayerTreeTest {}; +class LayerTreeHostScrollTest : public LayerTreeTest { + protected: + void SetupTree() override { + LayerTreeTest::SetupTree(); + Layer* root_layer = layer_tree_host()->root_layer(); + + // Create an effective max_scroll_offset of (100, 100). + gfx::Size scroll_layer_bounds(root_layer->bounds().width() + 100, + root_layer->bounds().height() + 100); + + CreateVirtualViewportLayers(root_layer, + root_layer->bounds(), + root_layer->bounds(), + scroll_layer_bounds, + layer_tree_host(), + layer_settings()); + } +}; class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest { public: @@ -39,24 +56,13 @@ class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest { num_scrolls_(0) {} void BeginTest() override { - Layer* root_layer = layer_tree_host()->root_layer(); - scoped_refptr<Layer> scroll_layer = Layer::Create(layer_settings()); - root_layer->AddChild(scroll_layer); - // Create an effective max_scroll_offset of (100, 100). - scroll_layer->SetBounds(gfx::Size(root_layer->bounds().width() + 100, - root_layer->bounds().height() + 100)); - scroll_layer->SetIsDrawable(true); - scroll_layer->SetIsContainerForFixedPositionLayers(true); - scroll_layer->SetScrollClipLayerId(root_layer->id()); - scroll_layer->SetScrollOffset(initial_scroll_); - layer_tree_host()->RegisterViewportLayers(NULL, root_layer, scroll_layer, - NULL); + layer_tree_host()->outer_viewport_scroll_layer()->SetScrollOffset( + initial_scroll_); PostSetNeedsCommitToMainThread(); } void Layout() override { - Layer* root = layer_tree_host()->root_layer(); - Layer* scroll_layer = root->children()[0].get(); + Layer* scroll_layer = layer_tree_host()->outer_viewport_scroll_layer(); if (!layer_tree_host()->source_frame_number()) { EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset()); } else { @@ -71,7 +77,7 @@ class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest { void DrawLayersOnThread(LayerTreeHostImpl* impl) override { LayerImpl* root = impl->active_tree()->root_layer(); - LayerImpl* scroll_layer = root->children()[0]; + LayerImpl* scroll_layer = impl->OuterViewportScrollLayer(); EXPECT_VECTOR_EQ(gfx::Vector2d(), scroll_layer->ScrollDelta()); scroll_layer->SetScrollClipLayer(root->id()); @@ -86,8 +92,8 @@ class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest { PostSetNeedsCommitToMainThread(); break; case 1: - EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), second_scroll_); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), scroll_amount_); + EXPECT_VECTOR_EQ(second_scroll_, scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(scroll_amount_, scroll_layer->ScrollDelta()); EndTest(); break; } @@ -119,36 +125,26 @@ class LayerTreeHostScrollTestScrollMultipleRedraw : initial_scroll_(40, 10), scroll_amount_(-3, 17), num_scrolls_(0) {} void BeginTest() override { - Layer* root_layer = layer_tree_host()->root_layer(); - scroll_layer_ = Layer::Create(layer_settings()); - root_layer->AddChild(scroll_layer_); - // Create an effective max_scroll_offset of (100, 100). - scroll_layer_->SetBounds(gfx::Size(root_layer->bounds().width() + 100, - root_layer->bounds().height() + 100)); - scroll_layer_->SetIsDrawable(true); - scroll_layer_->SetIsContainerForFixedPositionLayers(true); - scroll_layer_->SetScrollClipLayerId(root_layer->id()); + scroll_layer_ = layer_tree_host()->outer_viewport_scroll_layer(); scroll_layer_->SetScrollOffset(initial_scroll_); - layer_tree_host()->RegisterViewportLayers(NULL, root_layer, scroll_layer_, - NULL); PostSetNeedsCommitToMainThread(); } void BeginCommitOnThread(LayerTreeHostImpl* impl) override { switch (layer_tree_host()->source_frame_number()) { case 0: - EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer_->scroll_offset()); break; case 1: EXPECT_VECTOR_EQ( - scroll_layer_->scroll_offset(), gfx::ScrollOffsetWithDelta(initial_scroll_, - scroll_amount_ + scroll_amount_)); + scroll_amount_ + scroll_amount_), + scroll_layer_->scroll_offset()); case 2: EXPECT_VECTOR_EQ( - scroll_layer_->scroll_offset(), gfx::ScrollOffsetWithDelta(initial_scroll_, - scroll_amount_ + scroll_amount_)); + scroll_amount_ + scroll_amount_), + scroll_layer_->scroll_offset()); break; } } @@ -159,30 +155,30 @@ class LayerTreeHostScrollTestScrollMultipleRedraw if (impl->active_tree()->source_frame_number() == 0 && impl->SourceAnimationFrameNumberForTesting() == 1) { // First draw after first commit. - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), scroll_layer->ScrollDelta()); scroll_layer->ScrollBy(scroll_amount_); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), scroll_amount_); + EXPECT_VECTOR_EQ(scroll_amount_, scroll_layer->ScrollDelta()); - EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), initial_scroll_); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->BaseScrollOffset()); PostSetNeedsRedrawToMainThread(); } else if (impl->active_tree()->source_frame_number() == 0 && impl->SourceAnimationFrameNumberForTesting() == 2) { // Second draw after first commit. EXPECT_EQ(scroll_layer->ScrollDelta(), scroll_amount_); scroll_layer->ScrollBy(scroll_amount_); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), - scroll_amount_ + scroll_amount_); + EXPECT_VECTOR_EQ(scroll_amount_ + scroll_amount_, + scroll_layer->ScrollDelta()); - EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer_->scroll_offset()); PostSetNeedsCommitToMainThread(); } else if (impl->active_tree()->source_frame_number() == 1) { // Third or later draw after second commit. EXPECT_GE(impl->SourceAnimationFrameNumberForTesting(), 3u); - EXPECT_VECTOR_EQ(scroll_layer_->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), scroll_layer_->ScrollDelta()); EXPECT_VECTOR_EQ( - scroll_layer_->scroll_offset(), gfx::ScrollOffsetWithDelta(initial_scroll_, - scroll_amount_ + scroll_amount_)); + scroll_amount_ + scroll_amount_), + scroll_layer_->scroll_offset()); EndTest(); } } @@ -221,34 +217,31 @@ class LayerTreeHostScrollTestScrollAbortedCommit num_impl_commits_(0), num_impl_scrolls_(0) {} - void BeginTest() override { PostSetNeedsCommitToMainThread(); } + void BeginTest() override { + layer_tree_host()->outer_viewport_scroll_layer()->SetScrollOffset( + initial_scroll_); + PostSetNeedsCommitToMainThread(); + } void SetupTree() override { LayerTreeHostScrollTest::SetupTree(); - Layer* root_layer = layer_tree_host()->root_layer(); - scoped_refptr<Layer> root_scroll_layer = Layer::Create(layer_settings()); - root_scroll_layer->SetScrollClipLayerId(root_layer->id()); - root_scroll_layer->SetScrollOffset(initial_scroll_); - root_scroll_layer->SetBounds(gfx::Size(200, 200)); - root_scroll_layer->SetIsDrawable(true); - root_scroll_layer->SetIsContainerForFixedPositionLayers(true); - root_layer->AddChild(root_scroll_layer); - - layer_tree_host()->RegisterViewportLayers(NULL, root_layer, - root_scroll_layer, NULL); + + gfx::Size scroll_layer_bounds(200, 200); + layer_tree_host()->outer_viewport_scroll_layer()->SetBounds( + scroll_layer_bounds); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); } void WillBeginMainFrame() override { num_will_begin_main_frames_++; Layer* root_scroll_layer = - layer_tree_host()->root_layer()->children()[0].get(); + layer_tree_host()->outer_viewport_scroll_layer(); switch (num_will_begin_main_frames_) { case 1: // This will not be aborted because of the initial prop changes. EXPECT_EQ(0, num_impl_scrolls_); EXPECT_EQ(0, layer_tree_host()->source_frame_number()); - EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(initial_scroll_, root_scroll_layer->scroll_offset()); EXPECT_EQ(1.f, layer_tree_host()->page_scale_factor()); break; case 2: @@ -257,8 +250,8 @@ class LayerTreeHostScrollTestScrollAbortedCommit EXPECT_EQ(1, num_impl_scrolls_); EXPECT_EQ(1, layer_tree_host()->source_frame_number()); EXPECT_VECTOR_EQ( - root_scroll_layer->scroll_offset(), - gfx::ScrollOffsetWithDelta(initial_scroll_, impl_scroll_)); + gfx::ScrollOffsetWithDelta(initial_scroll_, impl_scroll_), + root_scroll_layer->scroll_offset()); EXPECT_EQ(impl_scale_, layer_tree_host()->page_scale_factor()); PostSetNeedsRedrawToMainThread(); break; @@ -268,9 +261,9 @@ class LayerTreeHostScrollTestScrollAbortedCommit // The source frame number still increases even with the abort. EXPECT_EQ(2, layer_tree_host()->source_frame_number()); EXPECT_VECTOR_EQ( - root_scroll_layer->scroll_offset(), gfx::ScrollOffsetWithDelta(initial_scroll_, - impl_scroll_ + impl_scroll_)); + impl_scroll_ + impl_scroll_), + root_scroll_layer->scroll_offset()); EXPECT_EQ(impl_scale_ * impl_scale_, layer_tree_host()->page_scale_factor()); root_scroll_layer->SetScrollOffset(gfx::ScrollOffsetWithDelta( @@ -282,8 +275,8 @@ class LayerTreeHostScrollTestScrollAbortedCommit EXPECT_EQ(3, layer_tree_host()->source_frame_number()); gfx::Vector2dF delta = impl_scroll_ + impl_scroll_ + impl_scroll_ + second_main_scroll_; - EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(), - gfx::ScrollOffsetWithDelta(initial_scroll_, delta)); + EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(initial_scroll_, delta), + root_scroll_layer->scroll_offset()); // End the test by drawing to verify this commit is also aborted. PostSetNeedsRedrawToMainThread(); @@ -302,20 +295,19 @@ class LayerTreeHostScrollTestScrollAbortedCommit } void DrawLayersOnThread(LayerTreeHostImpl* impl) override { - LayerImpl* root_scroll_layer = - impl->active_tree()->root_layer()->children()[0]; + LayerImpl* root_scroll_layer = impl->OuterViewportScrollLayer(); if (impl->active_tree()->source_frame_number() == 0 && impl->SourceAnimationFrameNumberForTesting() == 1) { // First draw - EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), root_scroll_layer->ScrollDelta()); root_scroll_layer->ScrollBy(impl_scroll_); - EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), impl_scroll_); - EXPECT_VECTOR_EQ(root_scroll_layer->BaseScrollOffset(), initial_scroll_); + EXPECT_VECTOR_EQ(impl_scroll_, root_scroll_layer->ScrollDelta()); + EXPECT_VECTOR_EQ(initial_scroll_, root_scroll_layer->BaseScrollOffset()); EXPECT_EQ(1.f, impl->active_tree()->page_scale_delta()); EXPECT_EQ(1.f, impl->active_tree()->current_page_scale_factor()); - impl->SetPageScaleOnActiveTree(impl_scale_); + impl->active_tree()->SetPageScaleOnActiveTree(impl_scale_); EXPECT_EQ(impl_scale_, impl->active_tree()->page_scale_delta()); EXPECT_EQ(impl_scale_, impl->active_tree()->current_page_scale_factor()); @@ -326,16 +318,16 @@ class LayerTreeHostScrollTestScrollAbortedCommit // Test a second draw after an aborted commit. // The scroll/scale values should be baked into the offset/scale factor // since the main thread consumed but aborted the begin frame. - EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), root_scroll_layer->ScrollDelta()); root_scroll_layer->ScrollBy(impl_scroll_); - EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), impl_scroll_); + EXPECT_VECTOR_EQ(impl_scroll_, root_scroll_layer->ScrollDelta()); EXPECT_VECTOR_EQ( - root_scroll_layer->BaseScrollOffset(), - gfx::ScrollOffsetWithDelta(initial_scroll_, impl_scroll_)); + gfx::ScrollOffsetWithDelta(initial_scroll_, impl_scroll_), + root_scroll_layer->BaseScrollOffset()); EXPECT_EQ(1.f, impl->active_tree()->page_scale_delta()); EXPECT_EQ(impl_scale_, impl->active_tree()->current_page_scale_factor()); - impl->SetPageScaleOnActiveTree(impl_scale_ * impl_scale_); + impl->active_tree()->SetPageScaleOnActiveTree(impl_scale_ * impl_scale_); EXPECT_EQ(impl_scale_, impl->active_tree()->page_scale_delta()); EXPECT_EQ(impl_scale_ * impl_scale_, impl->active_tree()->current_page_scale_factor()); @@ -350,18 +342,18 @@ class LayerTreeHostScrollTestScrollAbortedCommit EXPECT_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d()); root_scroll_layer->ScrollBy(impl_scroll_); impl->SetNeedsCommit(); - EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), impl_scroll_); + EXPECT_VECTOR_EQ(impl_scroll_, root_scroll_layer->ScrollDelta()); gfx::Vector2dF delta = impl_scroll_ + impl_scroll_ + second_main_scroll_; - EXPECT_VECTOR_EQ(root_scroll_layer->BaseScrollOffset(), - gfx::ScrollOffsetWithDelta(initial_scroll_, delta)); + EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(initial_scroll_, delta), + root_scroll_layer->BaseScrollOffset()); } else if (impl->active_tree()->source_frame_number() == 2 && impl->SourceAnimationFrameNumberForTesting() == 4) { // Final draw after the second aborted commit. - EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), root_scroll_layer->ScrollDelta()); gfx::Vector2dF delta = impl_scroll_ + impl_scroll_ + impl_scroll_ + second_main_scroll_; - EXPECT_VECTOR_EQ(root_scroll_layer->BaseScrollOffset(), - gfx::ScrollOffsetWithDelta(initial_scroll_, delta)); + EXPECT_VECTOR_EQ(gfx::ScrollOffsetWithDelta(initial_scroll_, delta), + root_scroll_layer->BaseScrollOffset()); EndTest(); } else { // Commit for source frame 3 is aborted. @@ -409,49 +401,36 @@ class LayerTreeHostScrollTestFractionalScroll : public LayerTreeHostScrollTest { void SetupTree() override { LayerTreeHostScrollTest::SetupTree(); - Layer* root_layer = layer_tree_host()->root_layer(); - scoped_refptr<Layer> root_scroll_layer = Layer::Create(layer_settings()); - root_scroll_layer->SetScrollClipLayerId(root_layer->id()); - root_scroll_layer->SetBounds( - gfx::Size(root_layer->bounds().width() + 100, - root_layer->bounds().height() + 100)); - root_scroll_layer->SetIsDrawable(true); - root_scroll_layer->SetIsContainerForFixedPositionLayers(true); - root_layer->AddChild(root_scroll_layer); - - layer_tree_host()->RegisterViewportLayers(NULL, root_layer, - root_scroll_layer, NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); } void BeginTest() override { PostSetNeedsCommitToMainThread(); } void DrawLayersOnThread(LayerTreeHostImpl* impl) override { - LayerImpl* root = impl->active_tree()->root_layer(); - LayerImpl* scroll_layer = root->children()[0]; + LayerImpl* scroll_layer = impl->OuterViewportScrollLayer(); // Check that a fractional scroll delta is correctly accumulated over // multiple commits. switch (impl->active_tree()->source_frame_number()) { case 0: - EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), gfx::Vector2d(0, 0)); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d(0, 0)); + EXPECT_VECTOR_EQ(gfx::Vector2d(0, 0), scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2d(0, 0), scroll_layer->ScrollDelta()); PostSetNeedsCommitToMainThread(); break; case 1: - 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)); + EXPECT_VECTOR_EQ(gfx::ToFlooredVector2d(scroll_amount_), + scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2dF(fmod(scroll_amount_.x(), 1.0f), 0.0f), + scroll_layer->ScrollDelta()); PostSetNeedsCommitToMainThread(); break; case 2: EXPECT_VECTOR_EQ( - scroll_layer->BaseScrollOffset(), - gfx::ToFlooredVector2d(scroll_amount_ + scroll_amount_)); + gfx::ToFlooredVector2d(scroll_amount_ + scroll_amount_), + scroll_layer->BaseScrollOffset()); EXPECT_VECTOR_EQ( - scroll_layer->ScrollDelta(), - gfx::Vector2dF(fmod(2.0f * scroll_amount_.x(), 1.0f), 0.0f)); + gfx::Vector2dF(fmod(2.0f * scroll_amount_.x(), 1.0f), 0.0f), + scroll_layer->ScrollDelta()); EndTest(); break; } @@ -483,13 +462,16 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { root_scroll_layer_ = FakePictureLayer::Create(layer_settings(), &fake_content_layer_client_); root_scroll_layer_->SetBounds(gfx::Size(110, 110)); - root_scroll_layer_->SetPosition(gfx::Point()); - root_scroll_layer_->SetIsDrawable(true); - root_scroll_layer_->SetScrollClipLayerId(root_layer->id()); - root_scroll_layer_->SetIsContainerForFixedPositionLayers(true); - root_layer->AddChild(root_scroll_layer_); + + CreateVirtualViewportLayers(root_layer.get(), + root_scroll_layer_, + root_layer->bounds(), + root_layer->bounds(), + layer_tree_host(), + layer_settings()); + child_layer_ = FakePictureLayer::Create(layer_settings(), &fake_content_layer_client_); @@ -508,8 +490,11 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { child_layer_->SetPosition(gfx::Point(60, 5)); } + scoped_refptr<Layer> outer_container_layer = + layer_tree_host()->outer_viewport_scroll_layer()->parent(); + child_layer_->SetIsDrawable(true); - child_layer_->SetScrollClipLayerId(root_layer->id()); + child_layer_->SetScrollClipLayerId(outer_container_layer->id()); child_layer_->SetBounds(root_scroll_layer_->bounds()); root_scroll_layer_->AddChild(child_layer_); @@ -524,9 +509,7 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { expected_scroll_layer_->SetScrollOffset(initial_offset_); layer_tree_host()->SetRootLayer(root_layer); - layer_tree_host()->RegisterViewportLayers(NULL, root_layer, - root_scroll_layer_, NULL); - LayerTreeHostScrollTest::SetupTree(); + LayerTreeTest::SetupTree(); } void BeginTest() override { PostSetNeedsCommitToMainThread(); } @@ -577,9 +560,9 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { } void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { - LayerImpl* root_impl = impl->active_tree()->root_layer(); + LayerImpl* inner_scroll = impl->InnerViewportScrollLayer(); FakePictureLayerImpl* root_scroll_layer_impl = - static_cast<FakePictureLayerImpl*>(root_impl->children()[0]); + static_cast<FakePictureLayerImpl*>(impl->OuterViewportScrollLayer()); FakePictureLayerImpl* child_layer_impl = static_cast<FakePictureLayerImpl*>( root_scroll_layer_impl->children()[0]); @@ -593,7 +576,7 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest { expected_no_scroll_layer_impl = child_layer_impl; } - EXPECT_VECTOR_EQ(gfx::Vector2d(), root_impl->ScrollDelta()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), inner_scroll->ScrollDelta()); EXPECT_VECTOR_EQ(gfx::Vector2d(), expected_no_scroll_layer_impl->ScrollDelta()); @@ -772,29 +755,19 @@ class LayerTreeHostScrollTestSimple : public LayerTreeHostScrollTest { void SetupTree() override { LayerTreeHostScrollTest::SetupTree(); - Layer* root_layer = layer_tree_host()->root_layer(); - scoped_refptr<Layer> root_scroll_layer = Layer::Create(layer_settings()); - root_scroll_layer->SetScrollClipLayerId(root_layer->id()); - root_scroll_layer->SetScrollOffset(initial_scroll_); - root_scroll_layer->SetBounds( - gfx::Size(root_layer->bounds().width() + 100, - root_layer->bounds().height() + 100)); - root_scroll_layer->SetIsDrawable(true); - root_scroll_layer->SetIsContainerForFixedPositionLayers(true); - root_layer->AddChild(root_scroll_layer); - - layer_tree_host()->RegisterViewportLayers(NULL, root_layer, - root_scroll_layer, NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); } - void BeginTest() override { PostSetNeedsCommitToMainThread(); } + void BeginTest() override { + layer_tree_host()->outer_viewport_scroll_layer()->SetScrollOffset( + initial_scroll_); + PostSetNeedsCommitToMainThread(); + } void Layout() override { - Layer* root = layer_tree_host()->root_layer(); - Layer* scroll_layer = root->children()[0].get(); + Layer* scroll_layer = layer_tree_host()->outer_viewport_scroll_layer(); if (!layer_tree_host()->source_frame_number()) { - EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset()); } else { EXPECT_VECTOR_EQ( scroll_layer->scroll_offset(), @@ -820,7 +793,7 @@ class LayerTreeHostScrollTestSimple : public LayerTreeHostScrollTest { impl->SetNeedsRedraw(); LayerImpl* root = impl->active_tree()->root_layer(); - LayerImpl* scroll_layer = root->children()[0]; + LayerImpl* scroll_layer = impl->OuterViewportScrollLayer(); LayerImpl* pending_root = impl->active_tree()->FindPendingTreeLayerById(root->id()); @@ -828,11 +801,11 @@ class LayerTreeHostScrollTestSimple : public LayerTreeHostScrollTest { case 0: if (!impl->pending_tree()) { impl->BlockNotifyReadyToActivateForTesting(true); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), scroll_layer->ScrollDelta()); scroll_layer->ScrollBy(impl_thread_scroll1_); - EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), initial_scroll_); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll1_); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(impl_thread_scroll1_, scroll_layer->ScrollDelta()); PostSetNeedsCommitToMainThread(); // CommitCompleteOnThread will trigger this function again @@ -843,26 +816,27 @@ class LayerTreeHostScrollTestSimple : public LayerTreeHostScrollTest { EXPECT_EQ(impl->pending_tree()->source_frame_number(), 1); scroll_layer->ScrollBy(impl_thread_scroll2_); - EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), initial_scroll_); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), - impl_thread_scroll1_ + impl_thread_scroll2_); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(impl_thread_scroll1_ + impl_thread_scroll2_, + scroll_layer->ScrollDelta()); - LayerImpl* pending_scroll_layer = pending_root->children()[0]; + LayerImpl* pending_scroll_layer = + impl->pending_tree()->OuterViewportScrollLayer(); EXPECT_VECTOR_EQ( - pending_scroll_layer->BaseScrollOffset(), gfx::ScrollOffsetWithDelta( - initial_scroll_, main_thread_scroll_ + impl_thread_scroll1_)); - EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), - impl_thread_scroll2_); + initial_scroll_, main_thread_scroll_ + impl_thread_scroll1_), + pending_scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(impl_thread_scroll2_, + pending_scroll_layer->ScrollDelta()); } break; case 1: EXPECT_FALSE(impl->pending_tree()); EXPECT_VECTOR_EQ( - scroll_layer->BaseScrollOffset(), gfx::ScrollOffsetWithDelta( - initial_scroll_, main_thread_scroll_ + impl_thread_scroll1_)); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll2_); + initial_scroll_, main_thread_scroll_ + impl_thread_scroll1_), + scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(impl_thread_scroll2_, scroll_layer->ScrollDelta()); EndTest(); break; } @@ -900,27 +874,17 @@ class LayerTreeHostScrollTestImplOnlyScroll : public LayerTreeHostScrollTest { void SetupTree() override { LayerTreeHostScrollTest::SetupTree(); - Layer* root_layer = layer_tree_host()->root_layer(); - scoped_refptr<Layer> root_scroll_layer = Layer::Create(layer_settings()); - root_scroll_layer->SetScrollClipLayerId(root_layer->id()); - root_scroll_layer->SetScrollOffset(initial_scroll_); - root_scroll_layer->SetBounds( - gfx::Size(root_layer->bounds().width() + 100, - root_layer->bounds().height() + 100)); - root_scroll_layer->SetIsDrawable(true); - root_scroll_layer->SetIsContainerForFixedPositionLayers(true); - root_layer->AddChild(root_scroll_layer); - - layer_tree_host()->RegisterViewportLayers(NULL, root_layer, - root_scroll_layer, NULL); layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f); } - void BeginTest() override { PostSetNeedsCommitToMainThread(); } + void BeginTest() override { + layer_tree_host()->outer_viewport_scroll_layer()->SetScrollOffset( + initial_scroll_); + PostSetNeedsCommitToMainThread(); + } void WillCommit() override { - Layer* root = layer_tree_host()->root_layer(); - Layer* scroll_layer = root->children()[0].get(); + Layer* scroll_layer = layer_tree_host()->outer_viewport_scroll_layer(); switch (layer_tree_host()->source_frame_number()) { case 0: EXPECT_TRUE(scroll_layer->needs_push_properties()); @@ -938,11 +902,11 @@ class LayerTreeHostScrollTestImplOnlyScroll : public LayerTreeHostScrollTest { // Scroll after the 2nd commit has started. if (impl->active_tree()->source_frame_number() == 0) { LayerImpl* active_root = impl->active_tree()->root_layer(); - LayerImpl* active_scroll_layer = active_root->children()[0]; + LayerImpl* active_scroll_layer = impl->OuterViewportScrollLayer(); ASSERT_TRUE(active_root); ASSERT_TRUE(active_scroll_layer); active_scroll_layer->ScrollBy(impl_thread_scroll_); - impl->SetPageScaleOnActiveTree(impl_scale_); + impl->active_tree()->SetPageScaleOnActiveTree(impl_scale_); } } @@ -951,38 +915,39 @@ class LayerTreeHostScrollTestImplOnlyScroll : public LayerTreeHostScrollTest { // the second commit. LayerImpl* active_root = impl->active_tree()->root_layer(); LayerImpl* active_scroll_layer = - active_root ? active_root->children()[0] : NULL; + active_root ? impl->OuterViewportScrollLayer() : NULL; LayerImpl* pending_root = impl->pending_tree()->root_layer(); - LayerImpl* pending_scroll_layer = pending_root->children()[0]; + LayerImpl* pending_scroll_layer = + impl->pending_tree()->OuterViewportScrollLayer(); ASSERT_TRUE(pending_root); ASSERT_TRUE(pending_scroll_layer); switch (impl->pending_tree()->source_frame_number()) { case 0: - EXPECT_VECTOR_EQ(pending_scroll_layer->BaseScrollOffset(), - initial_scroll_); - EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(initial_scroll_, + pending_scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), pending_scroll_layer->ScrollDelta()); 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->BaseScrollOffset(), - initial_scroll_); - EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), - impl_thread_scroll_); + EXPECT_VECTOR_EQ(initial_scroll_, + pending_scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(impl_thread_scroll_, + pending_scroll_layer->ScrollDelta()); ASSERT_TRUE(active_root); - EXPECT_VECTOR_EQ(active_scroll_layer->BaseScrollOffset(), - initial_scroll_); - EXPECT_VECTOR_EQ(active_scroll_layer->ScrollDelta(), - impl_thread_scroll_); + EXPECT_VECTOR_EQ(initial_scroll_, + active_scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(impl_thread_scroll_, + active_scroll_layer->ScrollDelta()); break; case 2: // On the next commit, this delta should have been sent and applied. EXPECT_VECTOR_EQ( - pending_scroll_layer->BaseScrollOffset(), - gfx::ScrollOffsetWithDelta(initial_scroll_, impl_thread_scroll_)); - EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), gfx::Vector2d()); + gfx::ScrollOffsetWithDelta(initial_scroll_, impl_thread_scroll_), + pending_scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), pending_scroll_layer->ScrollDelta()); break; } } @@ -991,20 +956,19 @@ class LayerTreeHostScrollTestImplOnlyScroll : public LayerTreeHostScrollTest { if (impl->pending_tree()) impl->SetNeedsRedraw(); - LayerImpl* root = impl->active_tree()->root_layer(); - LayerImpl* scroll_layer = root->children()[0]; + LayerImpl* scroll_layer = impl->OuterViewportScrollLayer(); switch (impl->active_tree()->source_frame_number()) { case 0: - EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), initial_scroll_); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d()); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(gfx::Vector2d(), scroll_layer->ScrollDelta()); 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->BaseScrollOffset(), initial_scroll_); - EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll_); + EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->BaseScrollOffset()); + EXPECT_VECTOR_EQ(impl_thread_scroll_, scroll_layer->ScrollDelta()); EXPECT_EQ(impl_scale_, impl->active_tree()->page_scale_delta()); EXPECT_EQ(impl_scale_, impl->active_tree()->current_page_scale_factor()); @@ -1035,17 +999,11 @@ class LayerTreeHostScrollTestScrollZeroMaxScrollOffset public: LayerTreeHostScrollTestScrollZeroMaxScrollOffset() {} - void SetupTree() override { - LayerTreeTest::SetupTree(); - scoped_refptr<Layer> scroll_layer = Layer::Create(layer_settings()); - layer_tree_host()->root_layer()->AddChild(scroll_layer); - } - void BeginTest() override { PostSetNeedsCommitToMainThread(); } void DrawLayersOnThread(LayerTreeHostImpl* impl) override { LayerImpl* root = impl->active_tree()->root_layer(); - LayerImpl* scroll_layer = root->children()[0]; + LayerImpl* scroll_layer = impl->OuterViewportScrollLayer(); scroll_layer->SetScrollClipLayer(root->id()); // Set max_scroll_offset = (100, 100). @@ -1108,6 +1066,19 @@ class ThreadCheckingInputHandlerClient : public InputHandlerClient { } } + void UpdateRootLayerStateForSynchronousInputHandler( + const gfx::ScrollOffset& total_scroll_offset, + const gfx::ScrollOffset& max_scroll_offset, + const gfx::SizeF& scrollable_size, + float page_scale_factor, + float min_page_scale_factor, + float max_page_scale_factor) override { + if (!task_runner_->BelongsToCurrentThread()) { + ADD_FAILURE() << "UpdateRootLayerStateForSynchronousInputHandler called " + << " on wrong thread"; + } + } + private: base::SingleThreadTaskRunner* task_runner_; bool* received_stop_flinging_; @@ -1161,22 +1132,30 @@ class LayerTreeHostScrollTestLayerStructureChange : scroll_destroy_whole_tree_(false) {} void SetupTree() override { - scoped_refptr<Layer> root_layer = Layer::Create(layer_settings()); + LayerTreeTest::SetupTree(); + Layer* root_layer = layer_tree_host()->root_layer(); root_layer->SetBounds(gfx::Size(10, 10)); + CreateVirtualViewportLayers(root_layer, + root_layer->bounds(), + root_layer->bounds(), + root_layer->bounds(), + layer_tree_host(), + layer_settings()); + + Layer* outer_scroll_layer = + layer_tree_host()->outer_viewport_scroll_layer(); + Layer* root_scroll_layer = - CreateScrollLayer(root_layer.get(), &root_scroll_layer_client_); - CreateScrollLayer(root_layer.get(), &sibling_scroll_layer_client_); + CreateScrollLayer(outer_scroll_layer, &root_scroll_layer_client_); + CreateScrollLayer(outer_scroll_layer, &sibling_scroll_layer_client_); CreateScrollLayer(root_scroll_layer, &child_scroll_layer_client_); - - layer_tree_host()->SetRootLayer(root_layer); - LayerTreeHostScrollTest::SetupTree(); } void BeginTest() override { PostSetNeedsCommitToMainThread(); } void DrawLayersOnThread(LayerTreeHostImpl* impl) override { - LayerImpl* root = impl->active_tree()->root_layer(); + LayerImpl* root = impl->OuterViewportScrollLayer(); switch (impl->active_tree()->source_frame_number()) { case 0: root->child_at(0)->SetScrollDelta(gfx::Vector2dF(5, 5)); @@ -1194,6 +1173,7 @@ class LayerTreeHostScrollTestLayerStructureChange virtual void DidScroll(Layer* layer) { if (scroll_destroy_whole_tree_) { + layer_tree_host()->RegisterViewportLayers(NULL, NULL, NULL, NULL); layer_tree_host()->SetRootLayer(NULL); EndTest(); return; diff --git a/chromium/cc/trees/layer_tree_host_unittest_video.cc b/chromium/cc/trees/layer_tree_host_unittest_video.cc index 31854ac68a9..2ae61bda512 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_video.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_video.cc @@ -49,19 +49,17 @@ class LayerTreeHostVideoTestSetNeedsDisplay DrawResult draw_result) override { LayerImpl* root_layer = host_impl->active_tree()->root_layer(); RenderSurfaceImpl* root_surface = root_layer->render_surface(); - gfx::RectF damage_rect = + gfx::Rect damage_rect = root_surface->damage_tracker()->current_damage_rect(); switch (num_draws_) { case 0: // First frame the whole viewport is damaged. - EXPECT_EQ(gfx::RectF(0.f, 0.f, 20.f, 20.f).ToString(), - damage_rect.ToString()); + EXPECT_EQ(gfx::Rect(0, 0, 20, 20), damage_rect); break; case 1: // Second frame the video layer is damaged. - EXPECT_EQ(gfx::RectF(6.f, 6.f, 8.f, 10.f).ToString(), - damage_rect.ToString()); + EXPECT_EQ(gfx::Rect(6, 6, 8, 10), damage_rect); EndTest(); break; } diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc index d4d2dee7f23..7cf7ddbce64 100644 --- a/chromium/cc/trees/layer_tree_impl.cc +++ b/chromium/cc/trees/layer_tree_impl.cc @@ -19,7 +19,6 @@ #include "cc/base/synced_property.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" @@ -47,19 +46,19 @@ LayerTreeImpl::LayerTreeImpl( : layer_tree_host_impl_(layer_tree_host_impl), source_frame_number_(-1), hud_layer_(0), - currently_scrolling_layer_(NULL), - 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), + currently_scrolling_layer_id_(Layer::INVALID_ID), + overscroll_elasticity_layer_id_(Layer::INVALID_ID), + page_scale_layer_id_(Layer::INVALID_ID), + inner_viewport_scroll_layer_id_(Layer::INVALID_ID), + outer_viewport_scroll_layer_id_(Layer::INVALID_ID), page_scale_factor_(page_scale_factor), min_page_scale_factor_(0), max_page_scale_factor_(0), + hide_pinch_scrollbars_near_min_scale_(false), + device_scale_factor_(1.f), elastic_overscroll_(elastic_overscroll), - scrolling_layer_id_from_previous_tree_(0), viewport_size_invalid_(false), needs_update_draw_properties_(true), needs_full_tree_sync_(true), @@ -68,8 +67,7 @@ LayerTreeImpl::LayerTreeImpl( render_surface_layer_list_id_(0), top_controls_shrink_blink_size_(false), top_controls_height_(0), - top_controls_shown_ratio_(top_controls_shown_ratio) { -} + top_controls_shown_ratio_(top_controls_shown_ratio) {} LayerTreeImpl::~LayerTreeImpl() { BreakSwapPromises(IsActiveTree() ? SwapPromise::SWAP_FAILS @@ -114,53 +112,28 @@ void LayerTreeImpl::GatherFrameTimingRequestIds( }); } -bool LayerTreeImpl::IsExternalScrollActive() const { - return root_layer_scroll_offset_delegate_ && - root_layer_scroll_offset_delegate_->IsExternalScrollActive(); -} - -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; - outer_viewport_scroll_layer_ = NULL; - page_scale_layer_ = NULL; layer_tree_host_impl_->OnCanDrawStateChangedForTree(); } LayerImpl* LayerTreeImpl::InnerViewportScrollLayer() const { - return inner_viewport_scroll_layer_; + return LayerById(inner_viewport_scroll_layer_id_); } LayerImpl* LayerTreeImpl::OuterViewportScrollLayer() const { - return outer_viewport_scroll_layer_; + return LayerById(outer_viewport_scroll_layer_id_); } gfx::ScrollOffset LayerTreeImpl::TotalScrollOffset() const { gfx::ScrollOffset offset; - if (inner_viewport_scroll_layer_) - offset += inner_viewport_scroll_layer_->CurrentScrollOffset(); + if (InnerViewportScrollLayer()) + offset += InnerViewportScrollLayer()->CurrentScrollOffset(); - if (outer_viewport_scroll_layer_) - offset += outer_viewport_scroll_layer_->CurrentScrollOffset(); + if (OuterViewportScrollLayer()) + offset += OuterViewportScrollLayer()->CurrentScrollOffset(); return offset; } @@ -168,24 +141,16 @@ gfx::ScrollOffset LayerTreeImpl::TotalScrollOffset() const { gfx::ScrollOffset LayerTreeImpl::TotalMaxScrollOffset() const { gfx::ScrollOffset offset; - if (inner_viewport_scroll_layer_) - offset += inner_viewport_scroll_layer_->MaxScrollOffset(); + if (InnerViewportScrollLayer()) + offset += InnerViewportScrollLayer()->MaxScrollOffset(); - if (outer_viewport_scroll_layer_) - offset += outer_viewport_scroll_layer_->MaxScrollOffset(); + if (OuterViewportScrollLayer()) + offset += OuterViewportScrollLayer()->MaxScrollOffset(); return offset; } 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; - inner_viewport_scroll_layer_ = NULL; - outer_viewport_scroll_layer_ = NULL; - page_scale_layer_ = NULL; - currently_scrolling_layer_ = NULL; - render_surface_layer_list_.clear(); set_needs_update_draw_properties(); return root_layer_.Pass(); @@ -197,7 +162,7 @@ static void UpdateClipTreeForBoundsDeltaOnLayer(LayerImpl* layer, ClipNode* clip_node = clip_tree->Node(layer->clip_tree_index()); if (clip_node) { DCHECK_EQ(layer->id(), clip_node->owner_id); - gfx::Size bounds = layer->bounds(); + gfx::SizeF bounds = gfx::SizeF(layer->bounds()); if (clip_node->data.clip.size() != bounds) { clip_node->data.clip.set_size(bounds); clip_tree->set_needs_update(true); @@ -243,25 +208,22 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { target_tree->set_top_controls_height(top_controls_height_); target_tree->PushTopControls(nullptr); + target_tree->set_hide_pinch_scrollbars_near_min_scale( + hide_pinch_scrollbars_near_min_scale_); + // 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->SetDeviceScaleFactor(device_scale_factor()); target_tree->elastic_overscroll()->PushPendingToActive(); target_tree->pending_page_scale_animation_ = pending_page_scale_animation_.Pass(); - if (page_scale_layer_ && inner_viewport_scroll_layer_) { - target_tree->SetViewportLayersFromIds( - 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->SetViewportLayersFromIds( + overscroll_elasticity_layer_id_, page_scale_layer_id_, + inner_viewport_scroll_layer_id_, outer_viewport_scroll_layer_id_); target_tree->RegisterSelection(selection_); @@ -287,38 +249,39 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) { } LayerImpl* LayerTreeImpl::InnerViewportContainerLayer() const { - return inner_viewport_scroll_layer_ - ? inner_viewport_scroll_layer_->scroll_clip_layer() + return InnerViewportScrollLayer() + ? InnerViewportScrollLayer()->scroll_clip_layer() : NULL; } LayerImpl* LayerTreeImpl::OuterViewportContainerLayer() const { - return outer_viewport_scroll_layer_ - ? outer_viewport_scroll_layer_->scroll_clip_layer() + return OuterViewportScrollLayer() + ? OuterViewportScrollLayer()->scroll_clip_layer() : NULL; } LayerImpl* LayerTreeImpl::CurrentlyScrollingLayer() const { DCHECK(IsActiveTree()); - return currently_scrolling_layer_; + return LayerById(currently_scrolling_layer_id_); } void LayerTreeImpl::SetCurrentlyScrollingLayer(LayerImpl* layer) { - if (currently_scrolling_layer_ == layer) + DCHECK_IMPLIES(layer, layer != OuterViewportScrollLayer()); + + int new_id = layer ? layer->id() : Layer::INVALID_ID; + if (currently_scrolling_layer_id_ == new_id) return; - if (currently_scrolling_layer_ && - currently_scrolling_layer_->scrollbar_animation_controller()) - currently_scrolling_layer_->scrollbar_animation_controller() - ->DidScrollEnd(); - currently_scrolling_layer_ = layer; + if (CurrentlyScrollingLayer() && + CurrentlyScrollingLayer()->scrollbar_animation_controller()) + CurrentlyScrollingLayer()->scrollbar_animation_controller()->DidScrollEnd(); + currently_scrolling_layer_id_ = new_id; if (layer && layer->scrollbar_animation_controller()) layer->scrollbar_animation_controller()->DidScrollBegin(); } void LayerTreeImpl::ClearCurrentlyScrollingLayer() { SetCurrentlyScrollingLayer(NULL); - scrolling_layer_id_from_previous_tree_ = 0; } namespace { @@ -463,34 +426,35 @@ void LayerTreeImpl::DidUpdatePageScale() { set_needs_update_draw_properties(); - if (root_layer_scroll_offset_delegate_) { - root_layer_scroll_offset_delegate_->UpdateRootLayerState( - TotalScrollOffset(), TotalMaxScrollOffset(), ScrollableSize(), - current_page_scale_factor(), min_page_scale_factor_, - max_page_scale_factor_); - } - - if (page_scale_layer() && page_scale_layer()->transform_tree_index() != -1) { + if (PageScaleLayer() && PageScaleLayer()->transform_tree_index() != -1) { TransformNode* node = property_trees_.transform_tree.Node( - page_scale_layer()->transform_tree_index()); + PageScaleLayer()->transform_tree_index()); node->data.post_local_scale_factor = current_page_scale_factor(); node->data.needs_local_transform_update = true; // TODO(enne): property trees can't ask the layer these things, but // the page scale layer should *just* be the page scale. - DCHECK_EQ(page_scale_layer()->position().ToString(), + DCHECK_EQ(PageScaleLayer()->position().ToString(), gfx::PointF().ToString()); - DCHECK_EQ(page_scale_layer()->transform_origin().ToString(), + DCHECK_EQ(PageScaleLayer()->transform_origin().ToString(), gfx::Point3F().ToString()); node->data.update_post_local_transform(gfx::PointF(), gfx::Point3F()); property_trees_.transform_tree.set_needs_update(true); } - ForceScrollbarParameterUpdateAfterScaleChange(page_scale_layer()); + ForceScrollbarParameterUpdateAfterScaleChange(PageScaleLayer()); + HideInnerViewportScrollbarsIfNeeded(); +} + +void LayerTreeImpl::SetDeviceScaleFactor(float device_scale_factor) { + if (device_scale_factor == device_scale_factor_) + return; + device_scale_factor_ = device_scale_factor; - HideInnerViewportScrollbarsIfNearMinimumScale(); + if (IsActiveTree()) + layer_tree_host_impl_->SetFullRootLayerDamage(); } -void LayerTreeImpl::HideInnerViewportScrollbarsIfNearMinimumScale() { +void LayerTreeImpl::HideInnerViewportScrollbarsIfNeeded() { if (!InnerViewportContainerLayer()) return; @@ -500,15 +464,14 @@ void LayerTreeImpl::HideInnerViewportScrollbarsIfNearMinimumScale() { if (!scrollbars) return; + float minimum_scale_to_show_at = min_page_scale_factor() * 1.05f; + bool hide_scrollbars = + hide_pinch_scrollbars_near_min_scale_ && + (current_page_scale_factor() < minimum_scale_to_show_at); + 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); - } + it != scrollbars->end(); ++it) + (*it)->SetHideLayerAndSubtree(hide_scrollbars); } SyncedProperty<ScaleGroup>* LayerTreeImpl::page_scale_factor() { @@ -559,29 +522,39 @@ void LayerTreeImpl::SetViewportLayersFromIds( 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_); + overscroll_elasticity_layer_id_ = overscroll_elasticity_layer_id; + page_scale_layer_id_ = page_scale_layer_id; + inner_viewport_scroll_layer_id_ = inner_viewport_scroll_layer_id; + outer_viewport_scroll_layer_id_ = outer_viewport_scroll_layer_id; - inner_viewport_scroll_layer_ = - LayerById(inner_viewport_scroll_layer_id); - DCHECK(inner_viewport_scroll_layer_); - - outer_viewport_scroll_layer_ = - LayerById(outer_viewport_scroll_layer_id); - DCHECK(outer_viewport_scroll_layer_ || - outer_viewport_scroll_layer_id == Layer::INVALID_ID); - - HideInnerViewportScrollbarsIfNearMinimumScale(); + HideInnerViewportScrollbarsIfNeeded(); } void LayerTreeImpl::ClearViewportLayers() { - page_scale_layer_ = NULL; - inner_viewport_scroll_layer_ = NULL; - outer_viewport_scroll_layer_ = NULL; + overscroll_elasticity_layer_id_ = Layer::INVALID_ID; + page_scale_layer_id_ = Layer::INVALID_ID; + inner_viewport_scroll_layer_id_ = Layer::INVALID_ID; + outer_viewport_scroll_layer_id_ = Layer::INVALID_ID; +} + +#if DCHECK_IS_ON() +int SanityCheckCopyRequestCounts(LayerImpl* layer) { + int count = layer->HasCopyRequest() ? 1 : 0; + for (size_t i = 0; i < layer->children().size(); ++i) { + count += SanityCheckCopyRequestCounts(layer->child_at(i)); + } + DCHECK_EQ(count, layer->num_layer_or_descendants_with_copy_request()) + << ", id: " << layer->id(); + return count; } +#endif bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) { +#if DCHECK_IS_ON() + if (root_layer()) + SanityCheckCopyRequestCounts(root_layer()); +#endif + if (!needs_update_draw_properties_) return true; @@ -606,8 +579,6 @@ bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) { 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 = (layer_tree_host_impl_->GetDrawMode() != DRAW_MODE_RESOURCELESS_SOFTWARE); @@ -617,10 +588,10 @@ bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) { LayerTreeHostCommon::CalcDrawPropsImplInputs inputs( root_layer(), DrawViewportSize(), layer_tree_host_impl_->DrawTransform(), device_scale_factor(), - current_page_scale_factor(), page_scale_layer, - inner_viewport_scroll_layer_, outer_viewport_scroll_layer_, + current_page_scale_factor(), PageScaleLayer(), + InnerViewportScrollLayer(), OuterViewportScrollLayer(), elastic_overscroll()->Current(IsActiveTree()), - overscroll_elasticity_layer_, resource_provider()->max_texture_size(), + OverscrollElasticityLayer(), 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, @@ -751,9 +722,10 @@ bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) { } void LayerTreeImpl::BuildPropertyTreesForTesting() { + LayerTreeHostCommon::PreCalculateMetaInformationForTesting(root_layer_.get()); PropertyTreeBuilder::BuildPropertyTrees( - root_layer_.get(), page_scale_layer_, inner_viewport_scroll_layer_, - outer_viewport_scroll_layer_, current_page_scale_factor(), + root_layer_.get(), PageScaleLayer(), InnerViewportScrollLayer(), + OuterViewportScrollLayer(), current_page_scale_factor(), device_scale_factor(), gfx::Rect(DrawViewportSize()), layer_tree_host_impl_->DrawTransform(), &property_trees_); } @@ -771,13 +743,20 @@ const Region& LayerTreeImpl::UnoccludedScreenSpaceRegion() const { return unoccluded_screen_space_region_; } -gfx::Size LayerTreeImpl::ScrollableSize() const { +gfx::SizeF LayerTreeImpl::ScrollableSize() const { LayerImpl* root_scroll_layer = OuterViewportScrollLayer() ? OuterViewportScrollLayer() : InnerViewportScrollLayer(); if (!root_scroll_layer || root_scroll_layer->children().empty()) - return gfx::Size(); - return root_scroll_layer->children()[0]->bounds(); + return gfx::SizeF(); + + gfx::SizeF content_size = + root_scroll_layer->children()[0]->BoundsForScrolling(); + gfx::SizeF viewport_size = + root_scroll_layer->scroll_clip_layer()->BoundsForScrolling(); + + content_size.SetToMax(viewport_size); + return content_size; } LayerImpl* LayerTreeImpl::LayerById(int id) const { @@ -807,23 +786,12 @@ size_t LayerTreeImpl::NumLayers() { return layer_id_map_.size(); } -void LayerTreeImpl::PushPersistedState(LayerTreeImpl* pending_tree) { - pending_tree->SetCurrentlyScrollingLayer( - LayerTreeHostCommon::FindLayerInSubtree(pending_tree->root_layer(), - currently_scrolling_layer_ ? currently_scrolling_layer_->id() : 0)); -} - void LayerTreeImpl::DidBecomeActive() { if (next_activation_forces_redraw_) { layer_tree_host_impl_->SetFullRootLayerDamage(); next_activation_forces_redraw_ = false; } - if (scrolling_layer_id_from_previous_tree_) { - currently_scrolling_layer_ = LayerTreeHostCommon::FindLayerInSubtree( - root_layer(), scrolling_layer_id_from_previous_tree_); - } - // Always reset this flag on activation, as we would only have activated // if we were in a good state. layer_tree_host_impl_->ResetRequiresHighResToDraw(); @@ -893,10 +861,6 @@ FrameRateCounter* LayerTreeImpl::frame_rate_counter() const { return layer_tree_host_impl_->fps_counter(); } -PaintTimeCounter* LayerTreeImpl::paint_time_counter() const { - return layer_tree_host_impl_->paint_time_counter(); -} - MemoryHistory* LayerTreeImpl::memory_history() const { return layer_tree_host_impl_->memory_history(); } @@ -905,10 +869,6 @@ 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(); } @@ -1062,46 +1022,15 @@ void LayerTreeImpl::AsValueInto(base::trace_event::TracedValue* state) const { for (auto* swap_promise : swap_promise_list_) state->AppendDouble(swap_promise->TraceId()); state->EndArray(); -} - -void LayerTreeImpl::SetRootLayerScrollOffsetDelegate( - LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate) { - if (root_layer_scroll_offset_delegate_ == root_layer_scroll_offset_delegate) - return; - - 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(), - current_page_scale_factor(), min_page_scale_factor(), - max_page_scale_factor()); - - DistributeRootScrollOffset(); - } -} - -void LayerTreeImpl::UpdateRootScrollOffsetDelegate() { - DCHECK(root_layer_scroll_offset_delegate_); - gfx::ScrollOffset offset = InnerViewportScrollLayer()->CurrentScrollOffset(); - - if (OuterViewportScrollLayer()) - offset += OuterViewportScrollLayer()->CurrentScrollOffset(); - - root_layer_scroll_offset_delegate_->UpdateRootLayerState( - offset, TotalMaxScrollOffset(), ScrollableSize(), - current_page_scale_factor(), min_page_scale_factor(), - max_page_scale_factor()); + state->BeginArray("pinned_swap_promise_trace_ids"); + for (auto* swap_promise : pinned_swap_promise_list_) + state->AppendDouble(swap_promise->TraceId()); + state->EndArray(); } -void LayerTreeImpl::DistributeRootScrollOffset() { - if (!root_layer_scroll_offset_delegate_) - return; - - gfx::ScrollOffset root_offset = - root_layer_scroll_offset_delegate_->GetTotalScrollOffset(); - +void LayerTreeImpl::DistributeRootScrollOffset( + const gfx::ScrollOffset& root_offset) { if (!InnerViewportScrollLayer()) return; @@ -1115,6 +1044,7 @@ void LayerTreeImpl::DistributeRootScrollOffset() { OuterViewportScrollLayer()->CurrentScrollOffset(); // It may be nothing has changed. + DCHECK(inner_viewport_offset + outer_viewport_offset == TotalScrollOffset()); if (inner_viewport_offset + outer_viewport_offset == root_offset) return; @@ -1125,13 +1055,9 @@ void LayerTreeImpl::DistributeRootScrollOffset() { outer_viewport_offset.SetToMin(max_outer_viewport_scroll_offset); outer_viewport_offset.SetToMax(gfx::ScrollOffset()); - OuterViewportScrollLayer()->SetCurrentScrollOffsetFromDelegate( - outer_viewport_offset); + OuterViewportScrollLayer()->SetCurrentScrollOffset(outer_viewport_offset); inner_viewport_offset = root_offset - outer_viewport_offset; - InnerViewportScrollLayer()->SetCurrentScrollOffsetFromDelegate( - inner_viewport_offset); - - UpdateRootScrollOffsetDelegate(); + InnerViewportScrollLayer()->SetCurrentScrollOffset(inner_viewport_offset); } void LayerTreeImpl::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) { @@ -1139,23 +1065,37 @@ void LayerTreeImpl::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) { swap_promise_list_.push_back(swap_promise.Pass()); } +void LayerTreeImpl::QueuePinnedSwapPromise( + scoped_ptr<SwapPromise> swap_promise) { + DCHECK(IsActiveTree()); + DCHECK(swap_promise); + pinned_swap_promise_list_.push_back(swap_promise.Pass()); +} + 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(); + for (auto* swap_promise : swap_promise_list_) + swap_promise->DidNotSwap(SwapPromise::SWAP_FAILS); + swap_promise_list_.clear(); + swap_promise_list_.swap(*new_swap_promise); } void LayerTreeImpl::FinishSwapPromises(CompositorFrameMetadata* metadata) { for (auto* swap_promise : swap_promise_list_) swap_promise->DidSwap(metadata); swap_promise_list_.clear(); + for (auto* swap_promise : pinned_swap_promise_list_) + swap_promise->DidSwap(metadata); + pinned_swap_promise_list_.clear(); } void LayerTreeImpl::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) { for (auto* swap_promise : swap_promise_list_) swap_promise->DidNotSwap(reason); swap_promise_list_.clear(); + for (auto* swap_promise : pinned_swap_promise_list_) + swap_promise->DidNotSwap(reason); + pinned_swap_promise_list_.clear(); } void LayerTreeImpl::DidModifyTilePriorities() { @@ -1262,7 +1202,7 @@ static inline bool LayerClipsSubtree(LayerType* layer) { static bool PointHitsRect( const gfx::PointF& screen_space_point, const gfx::Transform& local_space_to_screen_space_transform, - const gfx::RectF& local_space_rect, + const gfx::Rect& local_space_rect, float* distance_to_camera) { // If the transform is not invertible, then assume that this point doesn't hit // this rect. @@ -1285,7 +1225,7 @@ static bool PointHitsRect( if (clipped) return false; - if (!local_space_rect.Contains(hit_test_point_in_local_space)) + if (!gfx::RectF(local_space_rect).Contains(hit_test_point_in_local_space)) return false; if (distance_to_camera) { @@ -1361,7 +1301,7 @@ static bool PointIsClippedBySurfaceOrClipRect( static bool PointHitsLayer(const LayerImpl* layer, const gfx::PointF& screen_space_point, float* distance_to_intersection) { - gfx::RectF content_rect(layer->bounds()); + gfx::Rect content_rect(layer->bounds()); if (!PointHitsRect(screen_space_point, layer->screen_space_transform(), content_rect, @@ -1555,6 +1495,14 @@ static ViewportSelectionBound ComputeViewportSelectionBound( gfx::PointF screen_bottom = MathUtil::MapPoint( layer->screen_space_transform(), layer_bottom, &clipped); + // MapPoint can produce points with NaN components (even when no inputs are + // NaN). Since consumers of ViewportSelectionBounds may round |edge_top| or + // |edge_bottom| (and since rounding will crash on NaN), we return an empty + // bound instead. + if (std::isnan(screen_top.x()) || std::isnan(screen_top.y()) || + std::isnan(screen_bottom.x()) || std::isnan(screen_bottom.y())) + return ViewportSelectionBound(); + const float inv_scale = 1.f / device_scale_factor; viewport_bound.edge_top = gfx::ScalePoint(screen_top, inv_scale); viewport_bound.edge_bottom = gfx::ScalePoint(screen_bottom, inv_scale); @@ -1627,39 +1575,71 @@ scoped_ptr<PendingPageScaleAnimation> } bool LayerTreeImpl::IsAnimatingFilterProperty(const LayerImpl* layer) const { + LayerTreeType tree_type = + IsActiveTree() ? LayerTreeType::ACTIVE : LayerTreeType::PENDING; return layer_tree_host_impl_->animation_host() ? layer_tree_host_impl_->animation_host() - ->IsAnimatingFilterProperty(layer->id()) + ->IsAnimatingFilterProperty(layer->id(), tree_type) : false; } bool LayerTreeImpl::IsAnimatingOpacityProperty(const LayerImpl* layer) const { + LayerTreeType tree_type = + IsActiveTree() ? LayerTreeType::ACTIVE : LayerTreeType::PENDING; return layer_tree_host_impl_->animation_host() ? layer_tree_host_impl_->animation_host() - ->IsAnimatingOpacityProperty(layer->id()) + ->IsAnimatingOpacityProperty(layer->id(), tree_type) : false; } bool LayerTreeImpl::IsAnimatingTransformProperty(const LayerImpl* layer) const { + LayerTreeType tree_type = + IsActiveTree() ? LayerTreeType::ACTIVE : LayerTreeType::PENDING; + return layer_tree_host_impl_->animation_host() + ? layer_tree_host_impl_->animation_host() + ->IsAnimatingTransformProperty(layer->id(), tree_type) + : false; +} + +bool LayerTreeImpl::HasPotentiallyRunningFilterAnimation( + const LayerImpl* layer) const { + LayerTreeType tree_type = + IsActiveTree() ? LayerTreeType::ACTIVE : LayerTreeType::PENDING; return layer_tree_host_impl_->animation_host() ? layer_tree_host_impl_->animation_host() - ->IsAnimatingTransformProperty(layer->id()) + ->HasPotentiallyRunningFilterAnimation(layer->id(), + tree_type) : false; } bool LayerTreeImpl::HasPotentiallyRunningOpacityAnimation( const LayerImpl* layer) const { + LayerTreeType tree_type = + IsActiveTree() ? LayerTreeType::ACTIVE : LayerTreeType::PENDING; return layer_tree_host_impl_->animation_host() ? layer_tree_host_impl_->animation_host() - ->HasPotentiallyRunningOpacityAnimation(layer->id()) + ->HasPotentiallyRunningOpacityAnimation(layer->id(), + tree_type) : false; } bool LayerTreeImpl::HasPotentiallyRunningTransformAnimation( const LayerImpl* layer) const { + LayerTreeType tree_type = + IsActiveTree() ? LayerTreeType::ACTIVE : LayerTreeType::PENDING; + return layer_tree_host_impl_->animation_host() + ? layer_tree_host_impl_->animation_host() + ->HasPotentiallyRunningTransformAnimation(layer->id(), + tree_type) + : false; +} + +bool LayerTreeImpl::HasAnyAnimationTargetingProperty( + const LayerImpl* layer, + Animation::TargetProperty property) const { return layer_tree_host_impl_->animation_host() ? layer_tree_host_impl_->animation_host() - ->HasPotentiallyRunningTransformAnimation(layer->id()) + ->HasAnyAnimationTargetingProperty(layer->id(), property) : false; } @@ -1686,27 +1666,33 @@ bool LayerTreeImpl::TransformIsAnimatingOnImplOnly( } bool LayerTreeImpl::HasOnlyTranslationTransforms(const LayerImpl* layer) const { + LayerTreeType tree_type = + IsActiveTree() ? LayerTreeType::ACTIVE : LayerTreeType::PENDING; return layer_tree_host_impl_->animation_host() ? layer_tree_host_impl_->animation_host() - ->HasOnlyTranslationTransforms(layer->id()) + ->HasOnlyTranslationTransforms(layer->id(), tree_type) : true; } bool LayerTreeImpl::MaximumTargetScale(const LayerImpl* layer, float* max_scale) const { *max_scale = 0.f; + LayerTreeType tree_type = + IsActiveTree() ? LayerTreeType::ACTIVE : LayerTreeType::PENDING; return layer_tree_host_impl_->animation_host() ? layer_tree_host_impl_->animation_host()->MaximumTargetScale( - layer->id(), max_scale) + layer->id(), tree_type, max_scale) : true; } bool LayerTreeImpl::AnimationStartScale(const LayerImpl* layer, float* start_scale) const { *start_scale = 0.f; + LayerTreeType tree_type = + IsActiveTree() ? LayerTreeType::ACTIVE : LayerTreeType::PENDING; return layer_tree_host_impl_->animation_host() ? layer_tree_host_impl_->animation_host()->AnimationStartScale( - layer->id(), start_scale) + layer->id(), tree_type, start_scale) : true; } diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h index 973df977733..ed4413a4e6e 100644 --- a/chromium/cc/trees/layer_tree_impl.h +++ b/chromium/cc/trees/layer_tree_impl.h @@ -42,7 +42,6 @@ class LayerTreeSettings; class MemoryHistory; class OutputSurface; class PageScaleAnimation; -class PaintTimeCounter; class PictureLayerImpl; class Proxy; class ResourceProvider; @@ -83,10 +82,8 @@ class CC_EXPORT LayerTreeImpl { ResourceProvider* resource_provider() const; TileManager* tile_manager() const; FrameRateCounter* frame_rate_counter() const; - 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; @@ -166,10 +163,10 @@ class CC_EXPORT LayerTreeImpl { int inner_viewport_scroll_layer_id, int outer_viewport_scroll_layer_id); void ClearViewportLayers(); - LayerImpl* overscroll_elasticity_layer() { - return overscroll_elasticity_layer_; + LayerImpl* OverscrollElasticityLayer() { + return LayerById(overscroll_elasticity_layer_id_); } - LayerImpl* page_scale_layer() { return page_scale_layer_; } + LayerImpl* PageScaleLayer() { return LayerById(page_scale_layer_id_); } void ApplySentScrollAndScaleDeltasFromAbortedCommit(); SkColor background_color() const { return background_color_; } @@ -198,6 +195,13 @@ class CC_EXPORT LayerTreeImpl { SyncedProperty<ScaleGroup>* page_scale_factor(); const SyncedProperty<ScaleGroup>* page_scale_factor() const; + void SetDeviceScaleFactor(float device_scale_factor); + float device_scale_factor() const { return device_scale_factor_; } + + void set_hide_pinch_scrollbars_near_min_scale(bool hide) { + hide_pinch_scrollbars_near_min_scale_ = hide; + } + SyncedElasticOverscroll* elastic_overscroll() { return elastic_overscroll_.get(); } @@ -242,7 +246,7 @@ class CC_EXPORT LayerTreeImpl { // These return the size of the root scrollable area and the size of // the user-visible scrolling viewport, in CSS layout coordinates. - gfx::Size ScrollableSize() const; + gfx::SizeF ScrollableSize() const; gfx::SizeF ScrollableViewportSize() const; gfx::Rect RootScrollLayerDeviceViewportBounds() const; @@ -257,8 +261,6 @@ class CC_EXPORT LayerTreeImpl { AnimationRegistrar* GetAnimationRegistrar() const; - void PushPersistedState(LayerTreeImpl* pending_tree); - void DidBecomeActive(); // Set on the active tree when the viewport size recently changed @@ -270,17 +272,36 @@ class CC_EXPORT LayerTreeImpl { // Useful for debug assertions, probably shouldn't be used for anything else. Proxy* proxy() const; - void SetRootLayerScrollOffsetDelegate( - LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate); - void UpdateRootScrollOffsetDelegate(); - // Distribute the rool scroll between outer and inner viewport scroll layer. + // Distribute the root scroll between outer and inner viewport scroll layer. // The outer viewport scroll layer scrolls first. - void DistributeRootScrollOffset(); + void DistributeRootScrollOffset(const gfx::ScrollOffset& root_offset); + + void ApplyScroll(LayerImpl* layer, ScrollState* scroll_state) { + layer_tree_host_impl_->ApplyScroll(layer, scroll_state); + } // Call this function when you expect there to be a swap buffer. // See swap_promise.h for how to use SwapPromise. + // + // A swap promise queued by QueueSwapPromise travels with the layer + // information currently associated with the tree. For example, when + // a pending tree is activated, the swap promise is passed to the + // active tree along with the layer information. Similarly, when a + // new activation overwrites layer information on the active tree, + // queued swap promises are broken. void QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise); + // Queue a swap promise, pinned to this tree. Pinned swap promises + // may only be queued on the active tree. + // + // An active tree pinned swap promise will see only DidSwap() or + // DidNotSwap(SWAP_FAILS). No DidActivate() will be seen because + // that has already happened prior to queueing of the swap promise. + // + // Pinned active tree swap promises will not be broken prematurely + // on the active tree if a new tree is activated. + void QueuePinnedSwapPromise(scoped_ptr<SwapPromise> swap_promise); + // Take the |new_swap_promise| and append it to |swap_promise_list_|. void PassSwapPromises(ScopedPtrVector<SwapPromise>* new_swap_promise); void FinishSwapPromises(CompositorFrameMetadata* metadata); @@ -342,16 +363,18 @@ class CC_EXPORT LayerTreeImpl { void GatherFrameTimingRequestIds(std::vector<int64_t>* request_ids); - bool IsExternalScrollActive() const; - void DidUpdateScrollOffset(int layer_id); - bool IsAnimatingFilterProperty(const LayerImpl* layer) const; bool IsAnimatingOpacityProperty(const LayerImpl* layer) const; bool IsAnimatingTransformProperty(const LayerImpl* layer) const; + bool HasPotentiallyRunningFilterAnimation(const LayerImpl* layer) const; bool HasPotentiallyRunningOpacityAnimation(const LayerImpl* layer) const; bool HasPotentiallyRunningTransformAnimation(const LayerImpl* layer) const; + bool HasAnyAnimationTargetingProperty( + const LayerImpl* layer, + Animation::TargetProperty property) const; + bool FilterIsAnimatingOnImplOnly(const LayerImpl* layer) const; bool OpacityIsAnimatingOnImplOnly(const LayerImpl* layer) const; bool TransformIsAnimatingOnImplOnly(const LayerImpl* layer) const; @@ -385,28 +408,30 @@ class CC_EXPORT LayerTreeImpl { bool SetPageScaleFactorLimits(float min_page_scale_factor, float max_page_scale_factor); void DidUpdatePageScale(); - void HideInnerViewportScrollbarsIfNearMinimumScale(); + void HideInnerViewportScrollbarsIfNeeded(); 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_; 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_; + int currently_scrolling_layer_id_; + int overscroll_elasticity_layer_id_; + int page_scale_layer_id_; + int inner_viewport_scroll_layer_id_; + int outer_viewport_scroll_layer_id_; LayerSelection selection_; scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor_; float min_page_scale_factor_; float max_page_scale_factor_; + bool hide_pinch_scrollbars_near_min_scale_; + + float device_scale_factor_; scoped_refptr<SyncedElasticOverscroll> elastic_overscroll_; @@ -416,9 +441,6 @@ class CC_EXPORT LayerTreeImpl { std::vector<PictureLayerImpl*> picture_layers_; std::vector<LayerImpl*> layers_with_copy_output_request_; - // Persisted state for non-impl-side-painting. - int scrolling_layer_id_from_previous_tree_; - // 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 @@ -437,6 +459,7 @@ class CC_EXPORT LayerTreeImpl { bool has_ever_been_drawn_; ScopedPtrVector<SwapPromise> swap_promise_list_; + ScopedPtrVector<SwapPromise> pinned_swap_promise_list_; UIResourceRequestQueue ui_resource_request_queue_; diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc index 81a566fe7f3..ba5fc7b9eae 100644 --- a/chromium/cc/trees/layer_tree_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_impl_unittest.cc @@ -22,13 +22,13 @@ namespace { class LayerTreeImplTest : public LayerTreeHostCommonTest { public: - LayerTreeImplTest() { + LayerTreeImplTest() : output_surface_(FakeOutputSurface::Create3d()) { LayerTreeSettings settings; settings.layer_transforms_should_scale_layer_contents = true; - settings.scrollbar_show_scale_threshold = 1.1f; + settings.verify_property_trees = true; host_impl_.reset(new FakeLayerTreeHostImpl( settings, &proxy_, &shared_bitmap_manager_, &task_graph_runner_)); - EXPECT_TRUE(host_impl_->InitializeRenderer(FakeOutputSurface::Create3d())); + EXPECT_TRUE(host_impl_->InitializeRenderer(output_surface_.get())); } FakeLayerTreeHostImpl& host_impl() { return *host_impl_; } @@ -43,6 +43,7 @@ class LayerTreeImplTest : public LayerTreeHostCommonTest { TestSharedBitmapManager shared_bitmap_manager_; TestTaskGraphRunner task_graph_runner_; FakeImplProxy proxy_; + scoped_ptr<OutputSurface> output_surface_; scoped_ptr<FakeLayerTreeHostImpl> host_impl_; }; @@ -91,6 +92,49 @@ TEST_F(LayerTreeImplTest, HitTestingForSingleLayer) { EXPECT_EQ(12345, result_layer->id()); } +TEST_F(LayerTreeImplTest, UpdateViewportAndHitTest) { + // Ensures that the viewport rect is correctly updated by the clip tree. + TestSharedBitmapManager shared_bitmap_manager; + TestTaskGraphRunner task_graph_runner; + FakeImplProxy proxy; + LayerTreeSettings settings; + settings.verify_property_trees = true; + scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(); + scoped_ptr<FakeLayerTreeHostImpl> host_impl; + host_impl.reset(new FakeLayerTreeHostImpl( + settings, &proxy, &shared_bitmap_manager, &task_graph_runner)); + EXPECT_TRUE(host_impl->InitializeRenderer(output_surface.get())); + scoped_ptr<LayerImpl> root = + LayerImpl::Create(host_impl->active_tree(), 12345); + + gfx::Transform identity_matrix; + gfx::Point3F transform_origin; + gfx::PointF position; + gfx::Size bounds(100, 100); + SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin, + position, bounds, true, false, true); + root->SetDrawsContent(true); + + host_impl->SetViewportSize(root->bounds()); + host_impl->active_tree()->SetRootLayer(root.Pass()); + host_impl->UpdateNumChildrenAndDrawPropertiesForActiveTree(); + EXPECT_EQ( + gfx::RectF(gfx::SizeF(bounds)), + host_impl->active_tree()->property_trees()->clip_tree.ViewportClip()); + EXPECT_EQ(gfx::Rect(bounds), + host_impl->RootLayer()->visible_rect_from_property_trees()); + + gfx::Size new_bounds(50, 50); + host_impl->SetViewportSize(new_bounds); + gfx::Point test_point(51, 51); + host_impl->active_tree()->FindLayerThatIsHitByPoint(test_point); + EXPECT_EQ( + gfx::RectF(gfx::SizeF(new_bounds)), + host_impl->active_tree()->property_trees()->clip_tree.ViewportClip()); + EXPECT_EQ(gfx::Rect(new_bounds), + host_impl->RootLayer()->visible_rect_from_property_trees()); +} + TEST_F(LayerTreeImplTest, HitTestingForSingleLayerAndHud) { scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 12345); @@ -972,6 +1016,9 @@ TEST_F(LayerTreeImplTest, HitTestingRespectsScrollParents) { // This should cause scroll child and its descendants to be affected by // |child|'s clip. scroll_child->SetScrollParent(child.get()); + scoped_ptr<std::set<LayerImpl*>> scroll_children(new std::set<LayerImpl*>); + scroll_children->insert(scroll_child.get()); + child->SetScrollChildren(scroll_children.release()); SetLayerPropertiesForTesting(grand_child.get(), identity_matrix, transform_origin, position, bounds, true, @@ -1293,6 +1340,7 @@ TEST_F(LayerTreeImplTest, MakeScrollbarsInvisibleNearMinPageScale) { const bool kIsOverlayScrollbar = true; LayerTreeImpl* active_tree = host_impl().active_tree(); + active_tree->set_hide_pinch_scrollbars_near_min_scale(true); scoped_ptr<LayerImpl> scroll_layer = LayerImpl::Create(active_tree, 1); scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer = @@ -1340,11 +1388,11 @@ TEST_F(LayerTreeImplTest, MakeScrollbarsInvisibleNearMinPageScale) { 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); + active_tree->PushPageScaleFromMainThread(1.04f, 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); + active_tree->PushPageScaleFromMainThread(1.06f, 1.0f, 4.0f); EXPECT_FALSE(vertical_scrollbar_layer->hide_layer_and_subtree()); EXPECT_FALSE(horizontal_scrollbar_layer->hide_layer_and_subtree()); @@ -1448,14 +1496,14 @@ TEST_F(LayerTreeImplTest, float device_scale_factor = 3.f; float page_scale_factor = 5.f; - gfx::Size scaled_bounds_for_root = gfx::ToCeiledSize( - gfx::ScaleSize(root->bounds(), device_scale_factor * page_scale_factor)); + gfx::Size scaled_bounds_for_root = gfx::ScaleToCeiledSize( + root->bounds(), device_scale_factor * page_scale_factor); host_impl().SetViewportSize(scaled_bounds_for_root); - host_impl().SetDeviceScaleFactor(device_scale_factor); + host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor); host_impl().active_tree()->PushPageScaleFromMainThread( page_scale_factor, page_scale_factor, page_scale_factor); - host_impl().SetPageScaleOnActiveTree(page_scale_factor); + host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor); host_impl().active_tree()->SetRootLayer(root.Pass()); host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 1, Layer::INVALID_ID); @@ -1907,14 +1955,14 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) { float device_scale_factor = 3.f; float page_scale_factor = 5.f; - gfx::Size scaled_bounds_for_root = gfx::ToCeiledSize( - gfx::ScaleSize(root->bounds(), device_scale_factor * page_scale_factor)); + gfx::Size scaled_bounds_for_root = gfx::ScaleToCeiledSize( + root->bounds(), device_scale_factor * page_scale_factor); host_impl().SetViewportSize(scaled_bounds_for_root); - host_impl().SetDeviceScaleFactor(device_scale_factor); + host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor); host_impl().active_tree()->PushPageScaleFromMainThread( page_scale_factor, page_scale_factor, page_scale_factor); - host_impl().SetPageScaleOnActiveTree(page_scale_factor); + host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor); host_impl().active_tree()->SetRootLayer(root.Pass()); host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 1, Layer::INVALID_ID); @@ -1960,6 +2008,69 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) { EXPECT_TRUE(output.end.visible); } +TEST_F(LayerTreeImplTest, SelectionBoundsWithLargeTransforms) { + int root_id = 1; + int child_id = 2; + int grand_child_id = 3; + + scoped_ptr<LayerImpl> root = + LayerImpl::Create(host_impl().active_tree(), root_id); + gfx::Size bounds(100, 100); + gfx::Transform identity_matrix; + gfx::Point3F transform_origin; + gfx::PointF position; + + SetLayerPropertiesForTesting(root.get(), identity_matrix, transform_origin, + position, bounds, true, false, true); + + gfx::Transform large_transform; + large_transform.Scale(SkDoubleToMScalar(1e37), SkDoubleToMScalar(1e37)); + large_transform.RotateAboutYAxis(30); + + { + scoped_ptr<LayerImpl> child = + LayerImpl::Create(host_impl().active_tree(), child_id); + SetLayerPropertiesForTesting(child.get(), large_transform, transform_origin, + position, bounds, true, false, false); + + scoped_ptr<LayerImpl> grand_child = + LayerImpl::Create(host_impl().active_tree(), grand_child_id); + SetLayerPropertiesForTesting(grand_child.get(), large_transform, + transform_origin, position, bounds, true, + false, false); + grand_child->SetDrawsContent(true); + + child->AddChild(grand_child.Pass()); + root->AddChild(child.Pass()); + } + + host_impl().SetViewportSize(root->bounds()); + host_impl().active_tree()->SetRootLayer(root.Pass()); + host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree(); + + 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 = grand_child_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 = grand_child_id; + + host_impl().active_tree()->RegisterSelection(input); + + ViewportSelection output; + host_impl().active_tree()->GetViewportSelection(&output); + + // edge_bottom and edge_top aren't allowed to have NaNs, so the selection + // should be empty. + EXPECT_EQ(ViewportSelectionBound(), output.start); + EXPECT_EQ(ViewportSelectionBound(), output.end); +} + TEST_F(LayerTreeImplTest, NumLayersTestOne) { EXPECT_EQ(0u, host_impl().active_tree()->NumLayers()); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1); diff --git a/chromium/cc/trees/layer_tree_settings.cc b/chromium/cc/trees/layer_tree_settings.cc index 92d7dda7040..414abb3fab3 100644 --- a/chromium/cc/trees/layer_tree_settings.cc +++ b/chromium/cc/trees/layer_tree_settings.cc @@ -10,6 +10,7 @@ #include "base/command_line.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" +#include "ui/gfx/buffer_types.h" namespace cc { @@ -24,7 +25,6 @@ LayerTreeSettings::LayerTreeSettings() use_external_begin_frame_source(false), main_frame_before_activation_enabled(false), using_synchronous_renderer_compositor(false), - report_overscroll_only_for_scrollable_axes(false), accelerated_animation_enabled(true), can_use_lcd_text(true), use_distance_field_text(false), @@ -37,7 +37,6 @@ LayerTreeSettings::LayerTreeSettings() 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), timeout_and_draw_when_animation_checkerboards(true), layer_transforms_should_scale_layer_contents(false), @@ -47,33 +46,30 @@ LayerTreeSettings::LayerTreeSettings() top_controls_show_threshold(0.5f), top_controls_hide_threshold(0.5f), 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)), - // At 256x256 tiles, 128 tiles cover an area of 2048x4096 pixels. - max_tiles_for_interest_area(128), + // 3000 pixels should give sufficient area for prepainting. + tiling_interest_area_padding(3000), 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), strict_layer_property_change_checking(false), - use_one_copy(true), use_zero_copy(false), use_persistent_map_for_gpu_memory_buffers(false), enable_elastic_overscroll(false), - use_image_texture_target(GL_TEXTURE_2D), + use_image_texture_targets( + static_cast<size_t>(gfx::BufferFormat::LAST) + 1, + GL_TEXTURE_2D), ignore_root_layer_flings(false), scheduled_raster_task_limit(32), use_occlusion_for_tile_prioritization(false), record_full_layer(false), - use_display_lists(false), verify_property_trees(false), - gather_pixel_refs(false), + image_decode_tasks_enabled(false), use_compositor_animation_timelines(false), - invert_viewport_scroll_order(false) { -} + wait_for_beginframe_interval(true), + max_staging_buffer_usage_in_bytes(32 * 1024 * 1024) {} LayerTreeSettings::~LayerTreeSettings() {} @@ -87,8 +83,7 @@ SchedulerSettings LayerTreeSettings::ToSchedulerSettings() const { timeout_and_draw_when_animation_checkerboards; scheduler_settings.using_synchronous_renderer_compositor = using_synchronous_renderer_compositor; - scheduler_settings.throttle_frame_production = - !renderer_settings.disable_gpu_vsync; + scheduler_settings.throttle_frame_production = wait_for_beginframe_interval; scheduler_settings.background_frame_interval = base::TimeDelta::FromSecondsD(1.0 / background_animation_rate); return scheduler_settings; diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h index 6334f94bb13..f6656d5bf55 100644 --- a/chromium/cc/trees/layer_tree_settings.h +++ b/chromium/cc/trees/layer_tree_settings.h @@ -5,6 +5,8 @@ #ifndef CC_TREES_LAYER_TREE_SETTINGS_H_ #define CC_TREES_LAYER_TREE_SETTINGS_H_ +#include <vector> + #include "base/basictypes.h" #include "cc/base/cc_export.h" #include "cc/debug/layer_tree_debug_state.h" @@ -33,7 +35,6 @@ class CC_EXPORT LayerTreeSettings { bool use_external_begin_frame_source; bool main_frame_before_activation_enabled; bool using_synchronous_renderer_compositor; - bool report_overscroll_only_for_scrollable_axes; bool accelerated_animation_enabled; bool can_use_lcd_text; bool use_distance_field_text; @@ -52,7 +53,6 @@ class CC_EXPORT LayerTreeSettings { 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 timeout_and_draw_when_animation_checkerboards; bool layer_transforms_should_scale_layer_contents; @@ -62,31 +62,28 @@ class CC_EXPORT LayerTreeSettings { float top_controls_show_threshold; float top_controls_hide_threshold; 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; - size_t max_tiles_for_interest_area; + size_t tiling_interest_area_padding; 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; bool strict_layer_property_change_checking; - bool use_one_copy; bool use_zero_copy; bool use_persistent_map_for_gpu_memory_buffers; bool enable_elastic_overscroll; - unsigned use_image_texture_target; + // An array of image texture targets for each GpuMemoryBuffer format. + std::vector<unsigned> use_image_texture_targets; bool ignore_root_layer_flings; size_t scheduled_raster_task_limit; bool use_occlusion_for_tile_prioritization; bool record_full_layer; - bool use_display_lists; bool verify_property_trees; - bool gather_pixel_refs; + bool image_decode_tasks_enabled; bool use_compositor_animation_timelines; - bool invert_viewport_scroll_order; + bool wait_for_beginframe_interval; + int max_staging_buffer_usage_in_bytes; LayerTreeDebugState initial_debug_state; diff --git a/chromium/cc/trees/mutator_host_client.h b/chromium/cc/trees/mutator_host_client.h index 56123b4a62a..93f8f1334d8 100644 --- a/chromium/cc/trees/mutator_host_client.h +++ b/chromium/cc/trees/mutator_host_client.h @@ -36,6 +36,11 @@ class MutatorHostClient { LayerTreeType tree_type, const gfx::ScrollOffset& scroll_offset) = 0; + virtual void LayerTransformIsPotentiallyAnimatingChanged( + int layer_id, + LayerTreeType tree_type, + bool is_animating) = 0; + virtual void ScrollOffsetAnimationFinished() = 0; virtual gfx::ScrollOffset GetScrollOffsetForAnimation(int layer_id) const = 0; }; diff --git a/chromium/cc/trees/occlusion.cc b/chromium/cc/trees/occlusion.cc index 6a714962747..e86a1a05e32 100644 --- a/chromium/cc/trees/occlusion.cc +++ b/chromium/cc/trees/occlusion.cc @@ -58,7 +58,10 @@ gfx::Rect Occlusion::GetUnoccludedContentRect( gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization); bool ok = draw_transform_.GetInverse(&inverse_draw_transform); - DCHECK(ok); + // TODO(ajuma): Skip drawing layers with uninvertible draw transforms, and + // change this to a DCHECK. crbug.com/517170 + if (!ok) + return content_rect; gfx::Rect unoccluded_rect = MathUtil::ProjectEnclosingClippedRect( inverse_draw_transform, unoccluded_rect_in_target_surface); diff --git a/chromium/cc/trees/occlusion_tracker.cc b/chromium/cc/trees/occlusion_tracker.cc index 996adc895af..b86f8547db8 100644 --- a/chromium/cc/trees/occlusion_tracker.cc +++ b/chromium/cc/trees/occlusion_tracker.cc @@ -10,7 +10,6 @@ #include "cc/base/region.h" #include "cc/layers/layer.h" #include "cc/layers/layer_impl.h" -#include "cc/layers/render_surface.h" #include "cc/layers/render_surface_impl.h" #include "ui/gfx/geometry/quad_f.h" #include "ui/gfx/geometry/rect_conversions.h" diff --git a/chromium/cc/trees/occlusion_tracker_perftest.cc b/chromium/cc/trees/occlusion_tracker_perftest.cc index 209399dce11..01b63de6279 100644 --- a/chromium/cc/trees/occlusion_tracker_perftest.cc +++ b/chromium/cc/trees/occlusion_tracker_perftest.cc @@ -35,13 +35,14 @@ class OcclusionTrackerPerfTest : public testing::Test { base::TimeDelta::FromMilliseconds(kTimeLimitMillis), kTimeCheckInterval), proxy_(base::ThreadTaskRunnerHandle::Get(), nullptr), - impl_(&proxy_) {} + impl_(&proxy_), + output_surface_(FakeOutputSurface::Create3d()) {} void CreateHost() { LayerTreeSettings settings; host_impl_ = LayerTreeHostImpl::Create(settings, &client_, &proxy_, &stats_, &shared_bitmap_manager_, nullptr, &task_graph_runner_, 1); - host_impl_->InitializeRenderer(FakeOutputSurface::Create3d()); + host_impl_->InitializeRenderer(output_surface_.get()); scoped_ptr<LayerImpl> root_layer = LayerImpl::Create(active_tree(), 1); root_layer->SetHasRenderSurface(true); @@ -71,6 +72,7 @@ class OcclusionTrackerPerfTest : public testing::Test { FakeRenderingStatsInstrumentation stats_; TestSharedBitmapManager shared_bitmap_manager_; TestTaskGraphRunner task_graph_runner_; + scoped_ptr<OutputSurface> output_surface_; scoped_ptr<LayerTreeHostImpl> host_impl_; }; diff --git a/chromium/cc/trees/occlusion_tracker_unittest.cc b/chromium/cc/trees/occlusion_tracker_unittest.cc index 08cfcf7290e..88779d018c3 100644 --- a/chromium/cc/trees/occlusion_tracker_unittest.cc +++ b/chromium/cc/trees/occlusion_tracker_unittest.cc @@ -195,7 +195,6 @@ class OcclusionTrackerTest : public testing::Test { void DestroyLayers() { root_ = nullptr; - render_surface_layer_list_ = nullptr; render_surface_layer_list_impl_.clear(); replica_layers_.clear(); mask_layers_.clear(); @@ -310,7 +309,6 @@ class OcclusionTrackerTest : public testing::Test { scoped_ptr<FakeLayerTreeHost> host_; // These hold ownership of the layers for the duration of the test. scoped_ptr<LayerImpl> root_; - scoped_ptr<RenderSurfaceLayerList> render_surface_layer_list_; LayerImplList render_surface_layer_list_impl_; LayerIterator layer_iterator_begin_; LayerIterator layer_iterator_; diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc index 05fa3947f0c..d45d065279c 100644 --- a/chromium/cc/trees/property_tree.cc +++ b/chromium/cc/trees/property_tree.cc @@ -23,8 +23,7 @@ template <typename T> PropertyTree<T>::~PropertyTree() { } -TransformTree::TransformTree() : source_to_parent_updates_allowed_(true) { -} +TransformTree::TransformTree() : source_to_parent_updates_allowed_(true) {} TransformTree::~TransformTree() { } @@ -49,7 +48,7 @@ void PropertyTree<T>::clear() { template class PropertyTree<TransformNode>; template class PropertyTree<ClipNode>; -template class PropertyTree<OpacityNode>; +template class PropertyTree<EffectNode>; TransformNodeData::TransformNodeData() : target_id(-1), @@ -60,6 +59,8 @@ TransformNodeData::TransformNodeData() ancestors_are_invertible(true), is_animated(false), to_screen_is_animated(false), + has_only_translation_animations(true), + to_screen_has_scale_animation(false), flattens_inherited_transform(false), node_and_ancestors_are_flat(true), node_and_ancestors_have_only_integer_translation(true), @@ -70,8 +71,11 @@ TransformNodeData::TransformNodeData() affected_by_outer_viewport_bounds_delta_x(false), affected_by_outer_viewport_bounds_delta_y(false), layer_scale_factor(1.0f), - post_local_scale_factor(1.0f) { -} + post_local_scale_factor(1.0f), + local_maximum_animation_target_scale(0.f), + local_starting_animation_scale(0.f), + combined_maximum_animation_target_scale(0.f), + combined_starting_animation_scale(0.f) {} TransformNodeData::~TransformNodeData() { } @@ -94,11 +98,21 @@ void TransformNodeData::update_post_local_transform( transform_origin.z()); } -ClipNodeData::ClipNodeData() : transform_id(-1), target_id(-1) { -} +ClipNodeData::ClipNodeData() + : transform_id(-1), + target_id(-1), + use_only_parent_clip(false), + layer_clipping_uses_only_local_clip(false), + layer_visibility_uses_only_local_clip(false), + render_surface_is_clipped(false), + layers_are_clipped(false) {} -OpacityNodeData::OpacityNodeData() : opacity(1.f), screen_space_opacity(1.f) { -} +EffectNodeData::EffectNodeData() + : opacity(1.f), + screen_space_opacity(1.f), + has_render_surface(false), + transform_id(0), + clip_id(0) {} void TransformTree::clear() { PropertyTree<TransformNode>::clear(); @@ -147,6 +161,10 @@ bool TransformTree::ComputeTransformWithSourceSublayerScale( if (!source_node->data.needs_sublayer_scale) return success; + if (source_node->data.sublayer_scale.x() == 0 || + source_node->data.sublayer_scale.y() == 0) + return false; + transform->Scale(1.f / source_node->data.sublayer_scale.x(), 1.f / source_node->data.sublayer_scale.y()); return success; @@ -170,10 +188,12 @@ void TransformTree::UpdateTransforms(int id) { if (node->data.needs_local_transform_update || NeedsSourceToParentUpdate(node)) UpdateLocalTransform(node); + else + UndoSnapping(node); UpdateScreenSpaceTransform(node, parent_node, target_node); UpdateSublayerScale(node); UpdateTargetSpaceTransform(node, target_node); - UpdateIsAnimated(node, parent_node); + UpdateAnimationProperties(node, parent_node); UpdateSnapping(node); UpdateNodeAndAncestorsHaveIntegerTranslations(node, parent_node); } @@ -380,10 +400,9 @@ void TransformTree::UpdateTargetSpaceTransform(TransformNode* node, 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; + int target_id = target_node->id; ComputeTransformWithDestinationSublayerScale(node->id, target_id, &node->data.to_target); } @@ -392,12 +411,101 @@ void TransformTree::UpdateTargetSpaceTransform(TransformNode* node, node->data.ancestors_are_invertible = false; } -void TransformTree::UpdateIsAnimated(TransformNode* node, - TransformNode* parent_node) { +void TransformTree::UpdateAnimationProperties(TransformNode* node, + TransformNode* parent_node) { + bool ancestor_is_animating = false; + bool ancestor_is_animating_scale = false; + float ancestor_maximum_target_scale = 0.f; + float ancestor_starting_animation_scale = 0.f; if (parent_node) { - node->data.to_screen_is_animated = - node->data.is_animated || parent_node->data.to_screen_is_animated; + ancestor_is_animating = parent_node->data.to_screen_is_animated; + ancestor_is_animating_scale = + parent_node->data.to_screen_has_scale_animation; + ancestor_maximum_target_scale = + parent_node->data.combined_maximum_animation_target_scale; + ancestor_starting_animation_scale = + parent_node->data.combined_starting_animation_scale; + } + node->data.to_screen_is_animated = + node->data.is_animated || ancestor_is_animating; + node->data.to_screen_has_scale_animation = + !node->data.has_only_translation_animations || + ancestor_is_animating_scale; + + // Once we've failed to compute a maximum animated scale at an ancestor, we + // continue to fail. + bool failed_at_ancestor = + ancestor_is_animating_scale && ancestor_maximum_target_scale == 0.f; + + // Computing maximum animated scale in the presence of non-scale/translation + // transforms isn't supported. + bool failed_for_non_scale_or_translation = + !node->data.to_target.IsScaleOrTranslation(); + + // We don't attempt to accumulate animation scale from multiple nodes with + // scale animations, because of the risk of significant overestimation. For + // example, one node might be increasing scale from 1 to 10 at the same time + // as another node is decreasing scale from 10 to 1. Naively combining these + // scales would produce a scale of 100. + bool failed_for_multiple_scale_animations = + ancestor_is_animating_scale && + !node->data.has_only_translation_animations; + + if (failed_at_ancestor || failed_for_non_scale_or_translation || + failed_for_multiple_scale_animations) { + node->data.combined_maximum_animation_target_scale = 0.f; + node->data.combined_starting_animation_scale = 0.f; + + // This ensures that descendants know we've failed to compute a maximum + // animated scale. + node->data.to_screen_has_scale_animation = true; + return; + } + + if (!node->data.to_screen_has_scale_animation) { + node->data.combined_maximum_animation_target_scale = 0.f; + node->data.combined_starting_animation_scale = 0.f; + return; + } + + // At this point, we know exactly one of this node or an ancestor is animating + // scale. + if (node->data.has_only_translation_animations) { + // An ancestor is animating scale. + gfx::Vector2dF local_scales = + MathUtil::ComputeTransform2dScaleComponents(node->data.local, 0.f); + float max_local_scale = std::max(local_scales.x(), local_scales.y()); + node->data.combined_maximum_animation_target_scale = + max_local_scale * ancestor_maximum_target_scale; + node->data.combined_starting_animation_scale = + max_local_scale * ancestor_starting_animation_scale; + return; } + + if (node->data.local_starting_animation_scale == 0.f || + node->data.local_maximum_animation_target_scale == 0.f) { + node->data.combined_maximum_animation_target_scale = 0.f; + node->data.combined_starting_animation_scale = 0.f; + return; + } + + gfx::Vector2dF ancestor_scales = + parent_node ? MathUtil::ComputeTransform2dScaleComponents( + parent_node->data.to_target, 0.f) + : gfx::Vector2dF(1.f, 1.f); + float max_ancestor_scale = std::max(ancestor_scales.x(), ancestor_scales.y()); + node->data.combined_maximum_animation_target_scale = + max_ancestor_scale * node->data.local_maximum_animation_target_scale; + node->data.combined_starting_animation_scale = + max_ancestor_scale * node->data.local_starting_animation_scale; +} + +void TransformTree::UndoSnapping(TransformNode* node) { + // to_parent transform has the scroll snap from previous frame baked in. + // We need to undo it and use the un-snapped transform to compute current + // target and screen space transforms. + node->data.to_parent.Translate(-node->data.scroll_snap.x(), + -node->data.scroll_snap.y()); } void TransformTree::UpdateSnapping(TransformNode* node) { @@ -424,8 +532,8 @@ void TransformTree::UpdateSnapping(TransformNode* node) { // Now that we have our scroll delta, we must apply it to each of our // combined, to/from matrices. + node->data.to_target = rounded; 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()); @@ -479,11 +587,11 @@ bool TransformTree::HasNodesAffectedByOuterViewportBoundsDelta() const { return !nodes_affected_by_outer_viewport_bounds_delta_.empty(); } -void OpacityTree::UpdateOpacities(int id) { - OpacityNode* node = Node(id); +void EffectTree::UpdateOpacities(int id) { + EffectNode* node = Node(id); node->data.screen_space_opacity = node->data.opacity; - OpacityNode* parent_node = parent(node); + EffectNode* parent_node = parent(node); if (parent_node) node->data.screen_space_opacity *= parent_node->data.screen_space_opacity; } @@ -499,6 +607,22 @@ void TransformTree::UpdateNodeAndAncestorsHaveIntegerTranslations( parent_node->data.node_and_ancestors_have_only_integer_translation; } +void ClipTree::SetViewportClip(gfx::RectF viewport_rect) { + if (size() < 2) + return; + ClipNode* node = Node(1); + if (viewport_rect == node->data.clip) + return; + node->data.clip = viewport_rect; + set_needs_update(true); +} + +gfx::RectF ClipTree::ViewportClip() { + const unsigned long min_size = 1; + DCHECK_GT(size(), min_size); + return Node(1)->data.clip; +} + PropertyTrees::PropertyTrees() : needs_rebuild(true), sequence_number(0) { } diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h index 0ec77bc5bbe..49d159e2a5d 100644 --- a/chromium/cc/trees/property_tree.h +++ b/chromium/cc/trees/property_tree.h @@ -9,7 +9,7 @@ #include "base/basictypes.h" #include "cc/base/cc_export.h" -#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/scroll_offset.h" #include "ui/gfx/transform.h" @@ -75,6 +75,8 @@ struct CC_EXPORT TransformNodeData { bool is_animated : 1; bool to_screen_is_animated : 1; + bool has_only_translation_animations : 1; + bool to_screen_has_scale_animation : 1; // Flattening, when needed, is only applied to a node's inherited transform, // never to its local transform. @@ -105,6 +107,24 @@ struct CC_EXPORT TransformNodeData { // TODO(vollick): will be moved when accelerated effects are implemented. float post_local_scale_factor; + // The maximum scale that that node's |local| transform will have during + // current animations, considering only scales at keyframes not including the + // starting keyframe of each animation. + float local_maximum_animation_target_scale; + + // The maximum scale that this node's |local| transform will have during + // current animatons, considering only the starting scale of each animation. + float local_starting_animation_scale; + + // The maximum scale that this node's |to_target| transform will have during + // current animations, considering only scales at keyframes not incuding the + // starting keyframe of each animation. + float combined_maximum_animation_target_scale; + + // The maximum scale that this node's |to_target| transform will have during + // current animations, considering only the starting scale of each animation. + float combined_starting_animation_scale; + gfx::Vector2dF sublayer_scale; // TODO(vollick): will be moved when accelerated effects are implemented. @@ -136,21 +156,31 @@ struct CC_EXPORT ClipNodeData { ClipNodeData(); gfx::RectF clip; - gfx::RectF combined_clip; + gfx::RectF combined_clip_in_target_space; + gfx::RectF clip_in_target_space; int transform_id; int target_id; + bool use_only_parent_clip : 1; + bool layer_clipping_uses_only_local_clip : 1; + bool layer_visibility_uses_only_local_clip : 1; + bool render_surface_is_clipped : 1; + bool layers_are_clipped : 1; }; typedef TreeNode<ClipNodeData> ClipNode; -struct CC_EXPORT OpacityNodeData { - OpacityNodeData(); +struct CC_EXPORT EffectNodeData { + EffectNodeData(); float opacity; float screen_space_opacity; + + bool has_render_surface; + int transform_id; + int clip_id; }; -typedef TreeNode<OpacityNodeData> OpacityNode; +typedef TreeNode<EffectNodeData> EffectNode; template <typename T> class CC_EXPORT PropertyTree { @@ -185,6 +215,8 @@ class CC_EXPORT PropertyTree { void set_needs_update(bool needs_update) { needs_update_ = needs_update; } bool needs_update() const { return needs_update_; } + int next_available_id() const { return static_cast<int>(size()); } + private: // Copy and assign are permitted. This is how we do tree sync. std::vector<T> nodes_; @@ -293,7 +325,9 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> { void UpdateSublayerScale(TransformNode* node); void UpdateTargetSpaceTransform(TransformNode* node, TransformNode* target_node); - void UpdateIsAnimated(TransformNode* node, TransformNode* parent_node); + void UpdateAnimationProperties(TransformNode* node, + TransformNode* parent_node); + void UndoSnapping(TransformNode* node); void UpdateSnapping(TransformNode* node); void UpdateNodeAndAncestorsHaveIntegerTranslations( TransformNode* node, @@ -307,9 +341,13 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> { std::vector<int> nodes_affected_by_outer_viewport_bounds_delta_; }; -class CC_EXPORT ClipTree final : public PropertyTree<ClipNode> {}; +class CC_EXPORT ClipTree final : public PropertyTree<ClipNode> { + public: + void SetViewportClip(gfx::RectF viewport_rect); + gfx::RectF ViewportClip(); +}; -class CC_EXPORT OpacityTree final : public PropertyTree<OpacityNode> { +class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> { public: void UpdateOpacities(int id); }; @@ -319,7 +357,7 @@ class CC_EXPORT PropertyTrees final { PropertyTrees(); TransformTree transform_tree; - OpacityTree opacity_tree; + EffectTree effect_tree; ClipTree clip_tree; bool needs_rebuild; int sequence_number; diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc index 28ad43f3091..a5e209c7303 100644 --- a/chromium/cc/trees/property_tree_builder.cc +++ b/chromium/cc/trees/property_tree_builder.cc @@ -20,16 +20,20 @@ class LayerTreeHost; namespace { +static const int kInvalidPropertyTreeNodeId = -1; +static const int kRootPropertyTreeNodeId = 0; +static const int kUnclippedRootClipTreeNodeId = 0; + template <typename LayerType> struct DataForRecursion { TransformTree* transform_tree; ClipTree* clip_tree; - OpacityTree* opacity_tree; + EffectTree* effect_tree; LayerType* transform_tree_parent; LayerType* transform_fixed_parent; - LayerType* render_target; + int render_target; int clip_tree_parent; - int opacity_tree_parent; + int effect_tree_parent; const LayerType* page_scale_layer; const LayerType* inner_viewport_scroll_layer; const LayerType* outer_viewport_scroll_layer; @@ -39,7 +43,6 @@ struct DataForRecursion { bool affected_by_inner_viewport_bounds_delta; bool affected_by_outer_viewport_bounds_delta; bool should_flatten; - bool ancestor_clips_subtree; const gfx::Transform* device_transform; gfx::Vector2dF scroll_compensation_adjustment; int sequence_number; @@ -68,9 +71,9 @@ static bool RequiresClipNode(LayerType* layer, int parent_transform_id, bool is_clipped) { const bool render_surface_applies_clip = - layer->render_surface() && is_clipped; + layer->has_render_surface() && is_clipped; const bool render_surface_may_grow_due_to_clip_children = - layer->render_surface() && layer->num_unclipped_descendants() > 0; + layer->has_render_surface() && layer->num_unclipped_descendants() > 0; if (layer->masks_to_bounds() || layer->mask_layer() || render_surface_may_grow_due_to_clip_children) @@ -79,11 +82,7 @@ static bool RequiresClipNode(LayerType* layer, 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; + return true; } template <typename LayerType> @@ -94,36 +93,42 @@ static bool LayerClipsSubtree(LayerType* layer) { template <typename LayerType> void AddClipNodeIfNeeded(const DataForRecursion<LayerType>& data_from_ancestor, LayerType* layer, + bool created_render_surface, 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(); + bool is_root = !layer->parent(); + bool ancestor_clips_subtree = is_root || parent->data.layers_are_clipped; - data_for_children->ancestor_clips_subtree = false; + bool layers_are_clipped = 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()) + layers_are_clipped = true; + else if (!ancestor_clips_subtree) has_unclipped_surface = true; } else { - data_for_children->ancestor_clips_subtree = ancestor_clips_subtree; + layers_are_clipped = ancestor_clips_subtree; } - if (LayerClipsSubtree(layer)) - data_for_children->ancestor_clips_subtree = true; - - if (has_unclipped_surface) - parent_id = 0; + bool layer_clips_subtree = LayerClipsSubtree(layer); + if (layer_clips_subtree) + layers_are_clipped = true; + if (has_unclipped_surface) { + parent_id = kUnclippedRootClipTreeNodeId; + data_for_children->effect_tree->Node(data_for_children->render_target) + ->data.clip_id = kUnclippedRootClipTreeNodeId; + } if (!RequiresClipNode(layer, data_from_ancestor, parent->data.transform_id, - data_for_children->ancestor_clips_subtree)) { + ancestor_clips_subtree)) { // Unclipped surfaces reset the clip rect. data_for_children->clip_tree_parent = parent_id; + DCHECK_EQ(layers_are_clipped, data_for_children->clip_tree->Node(parent_id) + ->data.layers_are_clipped); } else { LayerType* transform_parent = data_for_children->transform_tree_parent; if (layer->position_constraint().is_fixed_position() && @@ -131,19 +136,48 @@ void AddClipNodeIfNeeded(const DataForRecursion<LayerType>& data_from_ancestor, 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.clip = + gfx::RectF(gfx::PointF() + layer->offset_to_transform_parent(), + gfx::SizeF(layer->bounds())); node.data.transform_id = transform_parent->transform_tree_index(); - node.data.target_id = - data_for_children->render_target->transform_tree_index(); + if (layer->has_render_surface()) { + node.data.target_id = + data_from_ancestor.effect_tree->Node(data_for_children->render_target) + ->data.transform_id; + } else { + node.data.target_id = + data_for_children->effect_tree->Node(data_for_children->render_target) + ->data.transform_id; + } node.owner_id = layer->id(); + if (ancestor_clips_subtree) { + node.data.use_only_parent_clip = !layer_clips_subtree; + // If the layer has render surface, the target has changed and so we use + // only the local clip for layer clipping. + node.data.layer_clipping_uses_only_local_clip = + layer->has_render_surface(); + } else { + node.data.use_only_parent_clip = false; + node.data.layer_clipping_uses_only_local_clip = true; + } + + // If render surface clips subtree and has unclipped descendants, the + // surface isn't clipped and we don't want to use ancestor's clips while + // calculating visible rect. + node.data.layer_visibility_uses_only_local_clip = + layer->has_render_surface() && layer->num_unclipped_descendants() && + layer_clips_subtree; + node.data.render_surface_is_clipped = layer->has_render_surface() && + ancestor_clips_subtree && + !layer->num_unclipped_descendants(); + node.data.layers_are_clipped = layers_are_clipped; + 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); + layer->SetClipTreeIndex(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 @@ -154,6 +188,7 @@ template <typename LayerType> bool AddTransformNodeIfNeeded( const DataForRecursion<LayerType>& data_from_ancestor, LayerType* layer, + bool created_render_surface, DataForRecursion<LayerType>* data_for_children) { const bool is_root = !layer->parent(); const bool is_page_scale_layer = layer == data_from_ancestor.page_scale_layer; @@ -165,18 +200,24 @@ bool AddTransformNodeIfNeeded( const bool has_potentially_animated_transform = layer->HasPotentiallyRunningTransformAnimation(); - const bool has_animated_transform = layer->TransformIsAnimating(); - const bool has_surface = !!layer->render_surface(); + // A transform node is needed even for a finished animation, since differences + // in the timing of animation state updates can mean that an animation that's + // in the Finished state at tree-building time on the main thread is still in + // the Running state right after commit on the compositor thread. + const bool has_any_transform_animation = + layer->HasAnyAnimationTargetingProperty(Animation::TRANSFORM); + + const bool has_surface = layer->has_render_surface(); bool requires_node = is_root || is_scrollable || has_significant_transform || - has_potentially_animated_transform || has_surface || - is_fixed || is_page_scale_layer; + has_any_transform_animation || has_surface || is_fixed || + is_page_scale_layer; LayerType* transform_parent = GetTransformParent(data_from_ancestor, layer); DCHECK_IMPLIES(!is_root, transform_parent); - int parent_index = 0; + int parent_index = kRootPropertyTreeNodeId; if (transform_parent) parent_index = transform_parent->transform_tree_index(); @@ -247,12 +288,32 @@ bool AddTransformNodeIfNeeded( // Surfaces inherently flatten transforms. data_for_children->should_flatten = layer->should_flatten_transform() || has_surface; + DCHECK_GT(data_from_ancestor.effect_tree->size(), 0u); + node->data.target_id = - data_from_ancestor.render_target->transform_tree_index(); + data_for_children->effect_tree->Node(data_from_ancestor.render_target) + ->data.transform_id; 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; + data_for_children->effect_tree->Node(data_for_children->render_target) + ->data.transform_id; + DCHECK_NE(node->data.target_id, kInvalidPropertyTreeNodeId); + + node->data.is_animated = has_potentially_animated_transform; + if (has_potentially_animated_transform) { + float maximum_animation_target_scale = 0.f; + if (layer->MaximumTargetScale(&maximum_animation_target_scale)) { + node->data.local_maximum_animation_target_scale = + maximum_animation_target_scale; + } + + float starting_animation_scale = 0.f; + if (layer->AnimationStartScale(&starting_animation_scale)) { + node->data.local_starting_animation_scale = starting_animation_scale; + } + + node->data.has_only_translation_animations = + layer->HasOnlyTranslationTransforms(); + } float post_local_scale_factor = 1.0f; if (is_root) { @@ -339,34 +400,53 @@ bool IsAnimatingOpacity(LayerImpl* layer) { } template <typename LayerType> -void AddOpacityNodeIfNeeded( +bool AddEffectNodeIfNeeded( 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; + const bool has_render_surface = layer->has_render_surface(); + bool requires_node = + is_root || has_transparency || has_animated_opacity || has_render_surface; - int parent_id = data_from_ancestor.opacity_tree_parent; + int parent_id = data_from_ancestor.effect_tree_parent; if (!requires_node) { - layer->SetOpacityTreeIndex(parent_id); - data_for_children->opacity_tree_parent = parent_id; - return; + layer->SetEffectTreeIndex(parent_id); + data_for_children->effect_tree_parent = parent_id; + return false; } - OpacityNode node; + EffectNode node; node.owner_id = layer->id(); node.data.opacity = layer->opacity(); node.data.screen_space_opacity = layer->opacity(); - if (!is_root) + node.data.has_render_surface = has_render_surface; + if (!is_root) { + // For every effect node, we create a transform node, so it's safe to use + // the next available id from the transform tree as this effect node's + // transform id. + node.data.transform_id = + data_from_ancestor.transform_tree->next_available_id(); + node.data.clip_id = data_from_ancestor.clip_tree_parent; + node.data.screen_space_opacity *= - data_from_ancestor.opacity_tree->Node(parent_id) + data_from_ancestor.effect_tree->Node(parent_id) ->data.screen_space_opacity; - data_for_children->opacity_tree_parent = - data_for_children->opacity_tree->Insert(node, parent_id); - layer->SetOpacityTreeIndex(data_for_children->opacity_tree_parent); + } else { + // Root render surface acts the unbounded and untransformed to draw content + // into. Transform node created from root layer (includes device scale + // factor) and clip node created from root layer (include viewports) applies + // to root render surface's content, but not root render surface itself. + node.data.transform_id = kRootPropertyTreeNodeId; + node.data.clip_id = kUnclippedRootClipTreeNodeId; + } + data_for_children->effect_tree_parent = + data_for_children->effect_tree->Insert(node, parent_id); + layer->SetEffectTreeIndex(data_for_children->effect_tree_parent); + return has_render_surface; } template <typename LayerType> @@ -375,16 +455,21 @@ void BuildPropertyTreesInternal( 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); + bool created_render_surface = + AddEffectNodeIfNeeded(data_from_parent, layer, &data_for_children); + + if (created_render_surface) { + data_for_children.render_target = data_for_children.effect_tree_parent; + layer->set_draw_blend_mode(SkXfermode::kSrcOver_Mode); + } else { + layer->set_draw_blend_mode(layer->blend_mode()); + } - if (data_from_parent.opacity_tree) - AddOpacityNodeIfNeeded(data_from_parent, layer, &data_for_children); + bool created_transform_node = AddTransformNodeIfNeeded( + data_from_parent, layer, created_render_surface, &data_for_children); + AddClipNodeIfNeeded(data_from_parent, layer, created_render_surface, + created_transform_node, &data_for_children); if (layer == data_from_parent.page_scale_layer) data_for_children.in_subtree_of_page_scale_layer = true; @@ -432,12 +517,12 @@ void BuildPropertyTreesTopLevelInternal( 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.effect_tree = &property_trees->effect_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.render_target = kRootPropertyTreeNodeId; + data_for_recursion.clip_tree_parent = kUnclippedRootClipTreeNodeId; + data_for_recursion.effect_tree_parent = kInvalidPropertyTreeNodeId; data_for_recursion.page_scale_layer = page_scale_layer; data_for_recursion.inner_viewport_scroll_layer = inner_viewport_scroll_layer; data_for_recursion.outer_viewport_scroll_layer = outer_viewport_scroll_layer; @@ -447,19 +532,18 @@ void BuildPropertyTreesTopLevelInternal( data_for_recursion.affected_by_inner_viewport_bounds_delta = false; data_for_recursion.affected_by_outer_viewport_bounds_delta = 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.effect_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); + root_clip.data.clip = gfx::RectF(viewport); + root_clip.data.transform_id = kRootPropertyTreeNodeId; + data_for_recursion.clip_tree_parent = data_for_recursion.clip_tree->Insert( + root_clip, kUnclippedRootClipTreeNodeId); BuildPropertyTreesInternal(root_layer, data_for_recursion); property_trees->needs_rebuild = false; @@ -468,7 +552,7 @@ void BuildPropertyTreesTopLevelInternal( // building. property_trees->transform_tree.set_needs_update(false); property_trees->clip_tree.set_needs_update(true); - property_trees->opacity_tree.set_needs_update(false); + property_trees->effect_tree.set_needs_update(false); } void PropertyTreeBuilder::BuildPropertyTrees( diff --git a/chromium/cc/trees/property_tree_builder.h b/chromium/cc/trees/property_tree_builder.h index f877aebe3dd..a6cc52b4c6d 100644 --- a/chromium/cc/trees/property_tree_builder.h +++ b/chromium/cc/trees/property_tree_builder.h @@ -16,8 +16,6 @@ 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, const Layer* inner_viewport_scroll_layer, diff --git a/chromium/cc/trees/property_tree_unittest.cc b/chromium/cc/trees/property_tree_unittest.cc index 8497dca6af1..e72a9ad83a8 100644 --- a/chromium/cc/trees/property_tree_unittest.cc +++ b/chromium/cc/trees/property_tree_unittest.cc @@ -529,10 +529,10 @@ TEST(PropertyTreeTest, FlatteningWhenDestinationHasOnlyFlatAncestors) { TEST(PropertyTreeTest, ScreenSpaceOpacityUpdateTest) { // This tests that screen space opacity is updated for the subtree when // opacity of a node changes. - OpacityTree tree; + EffectTree tree; - int parent = tree.Insert(OpacityNode(), 0); - int child = tree.Insert(OpacityNode(), parent); + int parent = tree.Insert(EffectNode(), 0); + int child = tree.Insert(EffectNode(), parent); EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 1.f); tree.Node(parent)->data.opacity = 0.5f; diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h index d403ae0eb6d..b40bb2f93e4 100644 --- a/chromium/cc/trees/proxy.h +++ b/chromium/cc/trees/proxy.h @@ -60,7 +60,9 @@ class CC_EXPORT Proxy { // Will call LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted // with the result of this function. - virtual void SetOutputSurface(scoped_ptr<OutputSurface> output_surface) = 0; + virtual void SetOutputSurface(OutputSurface* output_surface) = 0; + + virtual void ReleaseOutputSurface() = 0; // Indicates that the compositing surface associated with our context is // ready to use. @@ -93,14 +95,8 @@ class CC_EXPORT Proxy { virtual void Start() = 0; virtual void Stop() = 0; // Must be called before deleting the proxy. - // Forces 3D commands on all contexts to wait for all previous SwapBuffers - // to finish before executing in the GPU process. - virtual void ForceSerializeOnSwapBuffers() = 0; - virtual bool SupportsImplScrolling() const = 0; - virtual void SetDebugState(const LayerTreeDebugState& debug_state) = 0; - virtual void SetChildrenNeedBeginFrames(bool children_need_begin_frames) = 0; virtual void SetAuthoritativeVSyncInterval( diff --git a/chromium/cc/trees/proxy_impl.h b/chromium/cc/trees/proxy_impl.h new file mode 100644 index 00000000000..3a6c82bd50b --- /dev/null +++ b/chromium/cc/trees/proxy_impl.h @@ -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. + +#ifndef CC_TREES_PROXY_IMPL_H_ +#define CC_TREES_PROXY_IMPL_H_ + +#include "base/memory/weak_ptr.h" +#include "cc/base/cc_export.h" + +namespace cc { + +// TODO(khushalsagar): The impl side of ThreadProxy. It is currently defined as +// an interface with the implementation provided by ThreadProxy and will be +// made an independent class. +// The methods added to this interface should only use the CompositorThreadOnly +// variables from ThreadProxy. +// See crbug/527200 +class CC_EXPORT ProxyImpl { + public: + // Callback for impl side commands received from the channel. + virtual void SetThrottleFrameProductionOnImpl(bool throttle) = 0; + virtual void SetLayerTreeHostClientReadyOnImpl() = 0; + + // TODO(khushalsagar): Rename as GetWeakPtr() once ThreadProxy is split. + virtual base::WeakPtr<ProxyImpl> GetImplWeakPtr() = 0; + + protected: + virtual ~ProxyImpl() {} +}; + +} // namespace cc + +#endif // CC_TREES_PROXY_IMPL_H_ diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h new file mode 100644 index 00000000000..71230b43055 --- /dev/null +++ b/chromium/cc/trees/proxy_main.h @@ -0,0 +1,40 @@ +// 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_TREES_PROXY_MAIN_H_ +#define CC_TREES_PROXY_MAIN_H_ + +#include "base/memory/weak_ptr.h" +#include "cc/base/cc_export.h" + +namespace cc { +class ThreadedChannel; + +// TODO(khushalsagar): The main side of ThreadProxy. It is currently defined as +// an interface with the implementation provided by ThreadProxy and will be +// made an independent class. +// The methods added to this interface should only use the MainThreadOnly or +// BlockedMainThread variables from ThreadProxy. +// See crbug/527200. +class CC_EXPORT ProxyMain { + public: + // TODO(khushalsagar): Make this ChannelMain*. When ProxyMain and + // ProxyImpl are split, ProxyImpl will be passed a reference to ChannelImpl + // at creation. Right now we just set it directly from ThreadedChannel + // when the impl side is initialized. + virtual void SetChannel(scoped_ptr<ThreadedChannel> threaded_channel) = 0; + + // Callback for main side commands received from the Channel. + virtual void DidCompleteSwapBuffers() = 0; + + // TODO(khushalsagar): Rename as GetWeakPtr() once ThreadProxy is split. + virtual base::WeakPtr<ProxyMain> GetMainWeakPtr() = 0; + + protected: + virtual ~ProxyMain() {} +}; + +} // namespace cc + +#endif // CC_TREES_PROXY_MAIN_H_ diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc index b6d120b4805..49f614c5220 100644 --- a/chromium/cc/trees/single_thread_proxy.cc +++ b/chromium/cc/trees/single_thread_proxy.cc @@ -66,6 +66,7 @@ SingleThreadProxy::SingleThreadProxy( scoped_ptr<CompositorTimingHistory> compositor_timing_history( new CompositorTimingHistory( + CompositorTimingHistory::BROWSER_UMA, layer_tree_host->rendering_stats_instrumentation())); scheduler_on_impl_thread_ = Scheduler::Create( @@ -122,10 +123,11 @@ void SingleThreadProxy::SetLayerTreeHostClientReady() { void SingleThreadProxy::SetVisible(bool visible) { 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(). } void SingleThreadProxy::SetThrottleFrameProduction(bool throttle) { @@ -146,8 +148,16 @@ void SingleThreadProxy::RequestNewOutputSurface() { layer_tree_host_->RequestNewOutputSurface(); } -void SingleThreadProxy::SetOutputSurface( - scoped_ptr<OutputSurface> output_surface) { +void SingleThreadProxy::ReleaseOutputSurface() { + // |layer_tree_host_| should already be aware of this. + DCHECK(layer_tree_host_->output_surface_lost()); + + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidLoseOutputSurface(); + return layer_tree_host_impl_->ReleaseOutputSurface(); +} + +void SingleThreadProxy::SetOutputSurface(OutputSurface* output_surface) { DCHECK(Proxy::IsMainThread()); DCHECK(layer_tree_host_->output_surface_lost()); DCHECK(output_surface_creation_requested_); @@ -157,7 +167,7 @@ void SingleThreadProxy::SetOutputSurface( { DebugScopedSetMainThreadBlocked main_thread_blocked(this); DebugScopedSetImplThread impl(this); - success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass()); + success = layer_tree_host_impl_->InitializeRenderer(output_surface); } if (success) { @@ -189,7 +199,7 @@ void SingleThreadProxy::SetNeedsAnimate() { animate_requested_ = true; DebugScopedSetImplThread impl(this); if (scheduler_on_impl_thread_) - scheduler_on_impl_thread_->SetNeedsCommit(); + scheduler_on_impl_thread_->SetNeedsBeginMainFrame(); } void SingleThreadProxy::SetNeedsUpdateLayers() { @@ -198,24 +208,6 @@ 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()); @@ -245,7 +237,6 @@ void SingleThreadProxy::DoCommit() { blocking_main_thread_task_runner())); layer_tree_host_impl_->BeginCommit(); - layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get()); // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 // is fixed. @@ -271,6 +262,11 @@ void SingleThreadProxy::DoCommit() { DCHECK_EQ(1.f, scroll_info->page_scale_delta); #endif + if (scheduler_on_impl_thread_) + scheduler_on_impl_thread_->DidCommit(); + + layer_tree_host_impl_->CommitComplete(); + // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 // is fixed. tracked_objects::ScopedTracker tracking_profile8( @@ -286,17 +282,12 @@ void SingleThreadProxy::DoCommit() { } void SingleThreadProxy::CommitComplete() { + // Commit complete happens on the main side after activate to satisfy any + // SetNextCommitWaitsForActivation calls. DCHECK(!layer_tree_host_impl_->pending_tree()) << "Activation is expected to have synchronously occurred by now."; DCHECK(commit_blocking_task_runner_); - if (scheduler_on_impl_thread_) - scheduler_on_impl_thread_->DidCommit(); - - // 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(); @@ -313,7 +304,7 @@ void SingleThreadProxy::SetNeedsCommit() { commit_requested_ = true; DebugScopedSetImplThread impl(this); if (scheduler_on_impl_thread_) - scheduler_on_impl_thread_->SetNeedsCommit(); + scheduler_on_impl_thread_->SetNeedsBeginMainFrame(); } void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) { @@ -424,7 +415,7 @@ void SingleThreadProxy::SetNeedsRedrawRectOnImplThread( void SingleThreadProxy::SetNeedsCommitOnImplThread() { client_->ScheduleComposite(); if (scheduler_on_impl_thread_) - scheduler_on_impl_thread_->SetNeedsCommit(); + scheduler_on_impl_thread_->SetNeedsBeginMainFrame(); } void SingleThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) { @@ -447,11 +438,6 @@ void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread( bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; } void SingleThreadProxy::DidActivateSyncTree() { - // 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. @@ -595,7 +581,8 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { layer_tree_host_impl_->PrepareTiles(); layer_tree_host_impl_->SynchronouslyInitializeAllTiles(); - DoAnimate(); + // TODO(danakj): Don't do this last... we prepared the wrong things. D: + layer_tree_host_impl_->Animate(); LayerTreeHostImpl::FrameData frame; DoComposite(&frame); @@ -609,16 +596,6 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { } } -void SingleThreadProxy::ForceSerializeOnSwapBuffers() { - { - DebugScopedSetImplThread impl(this); - if (layer_tree_host_impl_->renderer()) { - DCHECK(!layer_tree_host_->output_surface_lost()); - layer_tree_host_impl_->renderer()->DoNoOp(); - } - } -} - bool SingleThreadProxy::SupportsImplScrolling() const { return false; } @@ -883,7 +860,7 @@ void SingleThreadProxy::ScheduledActionCommit() { void SingleThreadProxy::ScheduledActionAnimate() { TRACE_EVENT0("cc", "ScheduledActionAnimate"); DebugScopedSetImplThread impl(this); - DoAnimate(); + layer_tree_host_impl_->Animate(); } void SingleThreadProxy::ScheduledActionActivateSyncTree() { diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h index 8bec2b133f9..3caf1399bf1 100644 --- a/chromium/cc/trees/single_thread_proxy.h +++ b/chromium/cc/trees/single_thread_proxy.h @@ -38,7 +38,8 @@ class CC_EXPORT SingleThreadProxy : public Proxy, void FinishAllRendering() override; bool IsStarted() const override; bool CommitToActiveTree() const override; - void SetOutputSurface(scoped_ptr<OutputSurface>) override; + void SetOutputSurface(OutputSurface* output_surface) override; + void ReleaseOutputSurface() override; void SetLayerTreeHostClientReady() override; void SetVisible(bool visible) override; void SetThrottleFrameProduction(bool throttle) override; @@ -55,7 +56,6 @@ class CC_EXPORT SingleThreadProxy : public Proxy, void MainThreadHasStoppedFlinging() override {} void Start() override; void Stop() override; - void ForceSerializeOnSwapBuffers() override; bool SupportsImplScrolling() const override; bool MainFrameWillHappenForTesting() override; void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override; @@ -110,8 +110,6 @@ class CC_EXPORT SingleThreadProxy : public Proxy, scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) override; - void SetDebugState(const LayerTreeDebugState& debug_state) override {} - void RequestNewOutputSurface(); // Called by the legacy path where RenderWidget does the scheduling. @@ -128,7 +126,6 @@ class CC_EXPORT SingleThreadProxy : public Proxy, 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(LayerTreeHostImpl::FrameData* frame); diff --git a/chromium/cc/trees/thread_proxy.cc b/chromium/cc/trees/thread_proxy.cc index 533c4906a01..ca6eb73d5cd 100644 --- a/chromium/cc/trees/thread_proxy.cc +++ b/chromium/cc/trees/thread_proxy.cc @@ -71,20 +71,22 @@ ThreadProxy::ThreadProxy( TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy"); DCHECK(IsMainThread()); DCHECK(this->layer_tree_host()); + // TODO(khushalsagar): Move this to LayerTreeHost#InitializeThreaded once + // ThreadProxy is split. LayerTreeHost creates the channel and passes it to + // ProxyMain#SetChannel. + SetChannel(ThreadedChannel::Create(this, main_task_runner, impl_task_runner)); } ThreadProxy::MainThreadOnly::MainThreadOnly(ThreadProxy* proxy, int layer_tree_host_id) : layer_tree_host_id(layer_tree_host_id), - animate_requested(false), - commit_requested(false), - commit_request_sent_to_impl_thread(false), + max_requested_pipeline_stage(NO_PIPELINE_STAGE), + current_pipeline_stage(NO_PIPELINE_STAGE), + final_pipeline_stage(NO_PIPELINE_STAGE), started(false), prepare_tiles_pending(false), - can_cancel_commit(true), defer_commits(false), - weak_factory(proxy) { -} + weak_factory(proxy) {} ThreadProxy::MainThreadOnly::~MainThreadOnly() {} @@ -125,6 +127,11 @@ ThreadProxy::~ThreadProxy() { DCHECK(!main().started); } +void ThreadProxy::SetChannel(scoped_ptr<ThreadedChannel> threaded_channel) { + threaded_channel_ = threaded_channel.Pass(); + main().channel_main = threaded_channel_.get(); +} + void ThreadProxy::FinishAllRendering() { DCHECK(Proxy::IsMainThread()); DCHECK(!main().defer_commits); @@ -153,13 +160,10 @@ bool ThreadProxy::CommitToActiveTree() const { void ThreadProxy::SetLayerTreeHostClientReady() { TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReady"); - Proxy::ImplThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ThreadProxy::SetLayerTreeHostClientReadyOnImplThread, - impl_thread_weak_ptr_)); + main().channel_main->SetLayerTreeHostClientReadyOnImpl(); } -void ThreadProxy::SetLayerTreeHostClientReadyOnImplThread() { +void ThreadProxy::SetLayerTreeHostClientReadyOnImpl() { TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReadyOnImplThread"); impl().scheduler->SetCanStart(); } @@ -189,13 +193,10 @@ void ThreadProxy::SetVisibleOnImplThread(CompletionEvent* completion, 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)); + main().channel_main->SetThrottleFrameProductionOnImpl(throttle); } -void ThreadProxy::SetThrottleFrameProductionOnImplThread(bool throttle) { +void ThreadProxy::SetThrottleFrameProductionOnImpl(bool throttle) { TRACE_EVENT1("cc", "ThreadProxy::SetThrottleFrameProductionOnImplThread", "throttle", throttle); impl().scheduler->SetThrottleFrameProduction(throttle); @@ -212,11 +213,22 @@ void ThreadProxy::RequestNewOutputSurface() { layer_tree_host()->RequestNewOutputSurface(); } -void ThreadProxy::SetOutputSurface(scoped_ptr<OutputSurface> output_surface) { +void ThreadProxy::SetOutputSurface(OutputSurface* output_surface) { Proxy::ImplThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread, - impl_thread_weak_ptr_, base::Passed(&output_surface))); + FROM_HERE, base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread, + impl_thread_weak_ptr_, output_surface)); +} + +void ThreadProxy::ReleaseOutputSurface() { + DCHECK(IsMainThread()); + DCHECK(layer_tree_host()->output_surface_lost()); + + DebugScopedSetMainThreadBlocked main_thread_blocked(this); + CompletionEvent completion; + Proxy::ImplThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&ThreadProxy::ReleaseOutputSurfaceOnImplThread, + impl_thread_weak_ptr_, &completion)); + completion.Wait(); } void ThreadProxy::DidInitializeOutputSurface( @@ -238,15 +250,21 @@ void ThreadProxy::SetRendererCapabilitiesMainThreadCopy( main().renderer_capabilities_main_thread_copy = capabilities; } -void ThreadProxy::SendCommitRequestToImplThreadIfNeeded() { +bool ThreadProxy::SendCommitRequestToImplThreadIfNeeded( + CommitPipelineStage required_stage) { DCHECK(IsMainThread()); - if (main().commit_request_sent_to_impl_thread) - return; - main().commit_request_sent_to_impl_thread = true; + DCHECK_NE(NO_PIPELINE_STAGE, required_stage); + bool already_posted = + main().max_requested_pipeline_stage != NO_PIPELINE_STAGE; + main().max_requested_pipeline_stage = + std::max(main().max_requested_pipeline_stage, required_stage); + if (already_posted) + return false; Proxy::ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ThreadProxy::SetNeedsCommitOnImplThread, impl_thread_weak_ptr_)); + return true; } void ThreadProxy::DidCompletePageScaleAnimation() { @@ -262,35 +280,40 @@ const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const { void ThreadProxy::SetNeedsAnimate() { DCHECK(IsMainThread()); - if (main().animate_requested) - return; - - TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimate"); - main().animate_requested = true; - SendCommitRequestToImplThreadIfNeeded(); + if (SendCommitRequestToImplThreadIfNeeded(ANIMATE_PIPELINE_STAGE)) { + TRACE_EVENT_INSTANT0("cc", "ThreadProxy::SetNeedsAnimate", + TRACE_EVENT_SCOPE_THREAD); + } } void ThreadProxy::SetNeedsUpdateLayers() { DCHECK(IsMainThread()); - - if (main().commit_request_sent_to_impl_thread) + // If we are currently animating, make sure we also update the layers. + if (main().current_pipeline_stage == ANIMATE_PIPELINE_STAGE) { + main().final_pipeline_stage = + std::max(main().final_pipeline_stage, UPDATE_LAYERS_PIPELINE_STAGE); return; - TRACE_EVENT0("cc", "ThreadProxy::SetNeedsUpdateLayers"); - - SendCommitRequestToImplThreadIfNeeded(); + } + if (SendCommitRequestToImplThreadIfNeeded(UPDATE_LAYERS_PIPELINE_STAGE)) { + TRACE_EVENT_INSTANT0("cc", "ThreadProxy::SetNeedsUpdateLayers", + TRACE_EVENT_SCOPE_THREAD); + } } void ThreadProxy::SetNeedsCommit() { DCHECK(IsMainThread()); - // Unconditionally set here to handle SetNeedsCommit calls during a commit. - main().can_cancel_commit = false; - - if (main().commit_requested) + // If we are currently animating, make sure we don't skip the commit. Note + // that requesting a commit during the layer update stage means we need to + // schedule another full commit. + if (main().current_pipeline_stage == ANIMATE_PIPELINE_STAGE) { + main().final_pipeline_stage = + std::max(main().final_pipeline_stage, COMMIT_PIPELINE_STAGE); return; - TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommit"); - main().commit_requested = true; - - SendCommitRequestToImplThreadIfNeeded(); + } + if (SendCommitRequestToImplThreadIfNeeded(COMMIT_PIPELINE_STAGE)) { + TRACE_EVENT_INSTANT0("cc", "ThreadProxy::SetNeedsCommit", + TRACE_EVENT_SCOPE_THREAD); + } } void ThreadProxy::UpdateRendererCapabilitiesOnImplThread() { @@ -335,9 +358,7 @@ void ThreadProxy::DidSwapBuffersCompleteOnImplThread() { "ThreadProxy::DidSwapBuffersCompleteOnImplThread"); DCHECK(IsImplThread()); impl().scheduler->DidSwapBuffersComplete(); - Proxy::MainThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_)); + impl().channel_impl->DidCompleteSwapBuffers(); } void ThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) { @@ -374,7 +395,7 @@ void ThreadProxy::NotifyReadyToDraw() { void ThreadProxy::SetNeedsCommitOnImplThread() { TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread"); DCHECK(IsImplThread()); - impl().scheduler->SetNeedsCommit(); + impl().scheduler->SetNeedsBeginMainFrame(); } void ThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) { @@ -441,12 +462,15 @@ void ThreadProxy::SetDeferCommitsOnImplThread(bool defer_commits) const { bool ThreadProxy::CommitRequested() const { DCHECK(IsMainThread()); - return main().commit_requested; + // TODO(skyostil): Split this into something like CommitRequested() and + // CommitInProgress(). + return main().current_pipeline_stage != NO_PIPELINE_STAGE || + main().max_requested_pipeline_stage >= COMMIT_PIPELINE_STAGE; } bool ThreadProxy::BeginMainFrameRequested() const { DCHECK(IsMainThread()); - return main().commit_request_sent_to_impl_thread; + return main().max_requested_pipeline_stage != NO_PIPELINE_STAGE; } void ThreadProxy::SetNeedsRedrawOnImplThread() { @@ -596,42 +620,10 @@ void ThreadProxy::Stop() { main().started = false; } -void ThreadProxy::ForceSerializeOnSwapBuffers() { - DebugScopedSetMainThreadBlocked main_thread_blocked(this); - CompletionEvent completion; - Proxy::ImplThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ThreadProxy::ForceSerializeOnSwapBuffersOnImplThread, - impl_thread_weak_ptr_, - &completion)); - completion.Wait(); -} - -void ThreadProxy::ForceSerializeOnSwapBuffersOnImplThread( - CompletionEvent* completion) { - if (impl().layer_tree_host_impl->renderer()) - impl().layer_tree_host_impl->renderer()->DoNoOp(); - completion->Signal(); -} - bool ThreadProxy::SupportsImplScrolling() const { return true; } -void ThreadProxy::SetDebugState(const LayerTreeDebugState& debug_state) { - Proxy::ImplThreadTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ThreadProxy::SetDebugStateOnImplThread, - impl_thread_weak_ptr_, - debug_state)); -} - -void ThreadProxy::SetDebugStateOnImplThread( - const LayerTreeDebugState& debug_state) { - DCHECK(IsImplThread()); - impl().scheduler->SetContinuousPainting(debug_state.continuous_painting); -} - void ThreadProxy::FinishAllRenderingOnImplThread(CompletionEvent* completion) { TRACE_EVENT0("cc", "ThreadProxy::FinishAllRenderingOnImplThread"); DCHECK(IsImplThread()); @@ -680,6 +672,7 @@ void ThreadProxy::BeginMainFrame( begin_main_frame_state->begin_frame_id); TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame"); DCHECK(IsMainThread()); + DCHECK_EQ(NO_PIPELINE_STAGE, main().current_pipeline_stage); if (main().defer_commits) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit", @@ -696,9 +689,8 @@ void ThreadProxy::BeginMainFrame( // remaining swap promises. ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host()); - main().commit_requested = false; - main().commit_request_sent_to_impl_thread = false; - main().animate_requested = false; + main().final_pipeline_stage = main().max_requested_pipeline_stage; + main().max_requested_pipeline_stage = NO_PIPELINE_STAGE; if (!layer_tree_host()->visible()) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD); @@ -720,16 +712,7 @@ void ThreadProxy::BeginMainFrame( return; } - // Do not notify the impl thread of commit requests that occur during - // the apply/animate/layout part of the BeginMainFrameAndCommit process since - // those commit requests will get painted immediately. Once we have done - // the paint, main().commit_requested will be set to false to allow new commit - // requests to be scheduled. - // On the other hand, the animate_requested flag should remain cleared - // here so that any animation requests generated by the apply or animate - // callbacks will trigger another frame. - main().commit_requested = true; - main().commit_request_sent_to_impl_thread = true; + main().current_pipeline_stage = ANIMATE_PIPELINE_STAGE; layer_tree_host()->ApplyScrollAndScale( begin_main_frame_state->scroll_info.get()); @@ -748,32 +731,20 @@ void ThreadProxy::BeginMainFrame( layer_tree_host()->Layout(); TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame"); - // Clear the commit flag after updating animations and layout here --- objects - // that only layout when painted will trigger another SetNeedsCommit inside - // UpdateLayers. - main().commit_requested = false; - main().commit_request_sent_to_impl_thread = false; bool can_cancel_this_commit = - main().can_cancel_commit && !begin_main_frame_state->evicted_ui_resources; - main().can_cancel_commit = true; + main().final_pipeline_stage < COMMIT_PIPELINE_STAGE && + !begin_main_frame_state->evicted_ui_resources; - bool updated = layer_tree_host()->UpdateLayers(); + main().current_pipeline_stage = UPDATE_LAYERS_PIPELINE_STAGE; + bool should_update_layers = + main().final_pipeline_stage >= UPDATE_LAYERS_PIPELINE_STAGE; + bool updated = should_update_layers && layer_tree_host()->UpdateLayers(); 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 - // main().commit_request_sent_to_impl_thread = true. We need to force that - // call to happen again now so that the commit request is sent to the impl - // thread. - if (main().animate_requested) { - // Forces SetNeedsAnimate to consider posting a commit task. - main().animate_requested = false; - SetNeedsAnimate(); - } - + main().current_pipeline_stage = COMMIT_PIPELINE_STAGE; if (!updated && can_cancel_this_commit) { TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD); Proxy::ImplThreadTaskRunner()->PostTask( @@ -784,6 +755,7 @@ void ThreadProxy::BeginMainFrame( // 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 // went through, and input should no longer be throttled, etc. + main().current_pipeline_stage = NO_PIPELINE_STAGE; layer_tree_host()->CommitComplete(); layer_tree_host()->DidBeginMainFrame(); layer_tree_host()->BreakSwapPromises(SwapPromise::COMMIT_NO_UPDATE); @@ -812,6 +784,7 @@ void ThreadProxy::BeginMainFrame( completion.Wait(); } + main().current_pipeline_stage = NO_PIPELINE_STAGE; layer_tree_host()->CommitComplete(); layer_tree_host()->DidBeginMainFrame(); } @@ -865,22 +838,7 @@ 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); - } + impl().layer_tree_host_impl->Animate(); } void ThreadProxy::ScheduledActionCommit() { @@ -891,7 +849,6 @@ void ThreadProxy::ScheduledActionCommit() { blocked_main().main_thread_inside_commit = true; impl().layer_tree_host_impl->BeginCommit(); - layer_tree_host()->BeginCommitOnImplThread(impl().layer_tree_host_impl.get()); layer_tree_host()->FinishCommitOnImplThread( impl().layer_tree_host_impl.get()); blocked_main().main_thread_inside_commit = false; @@ -1060,6 +1017,11 @@ void ThreadProxy::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) { void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread"); DCHECK(IsImplThread()); + + // TODO(khushalsagar): ThreadedChannel will create ProxyImpl here and pass a + // reference to itself. + impl().channel_impl = threaded_channel_.get(); + impl().layer_tree_host_impl = layer_tree_host()->CreateLayerTreeHostImpl(this); @@ -1067,7 +1029,8 @@ void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { layer_tree_host()->settings().ToSchedulerSettings()); scoped_ptr<CompositorTimingHistory> compositor_timing_history( - new CompositorTimingHistory(impl().rendering_stats_instrumentation)); + new CompositorTimingHistory(CompositorTimingHistory::RENDERER_UMA, + impl().rendering_stats_instrumentation)); impl().scheduler = Scheduler::Create( this, scheduler_settings, impl().layer_tree_host_id, @@ -1080,12 +1043,12 @@ void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) { } void ThreadProxy::InitializeOutputSurfaceOnImplThread( - scoped_ptr<OutputSurface> output_surface) { + OutputSurface* output_surface) { TRACE_EVENT0("cc", "ThreadProxy::InitializeOutputSurfaceOnImplThread"); DCHECK(IsImplThread()); LayerTreeHostImpl* host_impl = impl().layer_tree_host_impl.get(); - bool success = host_impl->InitializeRenderer(output_surface.Pass()); + bool success = host_impl->InitializeRenderer(output_surface); RendererCapabilities capabilities; if (success) { capabilities = @@ -1103,6 +1066,17 @@ void ThreadProxy::InitializeOutputSurfaceOnImplThread( impl().scheduler->DidCreateAndInitializeOutputSurface(); } +void ThreadProxy::ReleaseOutputSurfaceOnImplThread( + CompletionEvent* completion) { + DCHECK(IsImplThread()); + + // Unlike DidLoseOutputSurfaceOnImplThread, we don't need to call + // LayerTreeHost::DidLoseOutputSurface since it already knows. + impl().scheduler->DidLoseOutputSurface(); + impl().layer_tree_host_impl->ReleaseOutputSurface(); + completion->Signal(); +} + void ThreadProxy::FinishGLOnImplThread(CompletionEvent* completion) { TRACE_EVENT0("cc", "ThreadProxy::FinishGLOnImplThread"); DCHECK(IsImplThread()); @@ -1281,4 +1255,12 @@ void ThreadProxy::PostFrameTimingEvents( main_frame_events.Pass()); } +base::WeakPtr<ProxyMain> ThreadProxy::GetMainWeakPtr() { + return main_thread_weak_ptr_; +} + +base::WeakPtr<ProxyImpl> ThreadProxy::GetImplWeakPtr() { + return impl_thread_weak_ptr_; +} + } // namespace cc diff --git a/chromium/cc/trees/thread_proxy.h b/chromium/cc/trees/thread_proxy.h index ca76e42669b..a6b3cf735dc 100644 --- a/chromium/cc/trees/thread_proxy.h +++ b/chromium/cc/trees/thread_proxy.h @@ -17,6 +17,7 @@ #include "cc/scheduler/scheduler.h" #include "cc/trees/layer_tree_host_impl.h" #include "cc/trees/proxy.h" +#include "cc/trees/threaded_channel.h" namespace base { class SingleThreadTaskRunner; @@ -25,13 +26,20 @@ class SingleThreadTaskRunner; namespace cc { class BeginFrameSource; +class ChannelImpl; +class ChannelMain; class ContextProvider; class InputHandlerClient; class LayerTreeHost; +class ProxyImpl; +class ProxyMain; class Scheduler; class ScopedThreadProxy; +class ThreadedChannel; class CC_EXPORT ThreadProxy : public Proxy, + public ProxyMain, + public ProxyImpl, NON_EXPORTED_BASE(LayerTreeHostImplClient), NON_EXPORTED_BASE(SchedulerClient) { public: @@ -54,26 +62,42 @@ class CC_EXPORT ThreadProxy : public Proxy, bool evicted_ui_resources; }; + // Commits between the main and impl threads are processed through a pipeline + // with the following stages. For efficiency we can early out at any stage if + // we decide that no further processing is necessary. + enum CommitPipelineStage { + NO_PIPELINE_STAGE, + ANIMATE_PIPELINE_STAGE, + UPDATE_LAYERS_PIPELINE_STAGE, + COMMIT_PIPELINE_STAGE, + }; + struct MainThreadOnly { MainThreadOnly(ThreadProxy* proxy, int layer_tree_host_id); ~MainThreadOnly(); const int layer_tree_host_id; - // Set only when SetNeedsAnimate is called. - bool animate_requested; - // Set only when SetNeedsCommit is called. - bool commit_requested; - // Set by SetNeedsAnimate, SetNeedsUpdateLayers, and SetNeedsCommit. - bool commit_request_sent_to_impl_thread; + // The furthest pipeline stage which has been requested for the next + // commit. + CommitPipelineStage max_requested_pipeline_stage; + // The commit pipeline stage that is currently being processed. + CommitPipelineStage current_pipeline_stage; + // The commit pipeline stage at which processing for the current commit + // will stop. Only valid while we are executing the pipeline (i.e., + // |current_pipeline_stage| is set to a pipeline stage). + CommitPipelineStage final_pipeline_stage; bool started; bool prepare_tiles_pending; - bool can_cancel_commit; bool defer_commits; RendererCapabilities renderer_capabilities_main_thread_copy; + // TODO(khushalsagar): Make this scoped_ptr<ChannelMain> when ProxyMain + // and ProxyImpl are split. + ChannelMain* channel_main; + base::WeakPtrFactory<ThreadProxy> weak_factory; }; @@ -117,8 +141,6 @@ class CC_EXPORT ThreadProxy : public Proxy, bool input_throttled_until_commit; - base::TimeTicks animation_time; - // Whether a commit has been completed since the last time animations were // ticked. If this happens, we need to animate again. bool did_commit_after_animating; @@ -134,6 +156,9 @@ class CC_EXPORT ThreadProxy : public Proxy, BeginFrameArgs last_processed_begin_main_frame_args; scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl; + + ChannelImpl* channel_impl; + base::WeakPtrFactory<ThreadProxy> weak_factory; }; @@ -145,7 +170,7 @@ class CC_EXPORT ThreadProxy : public Proxy, void FinishAllRendering() override; bool IsStarted() const override; bool CommitToActiveTree() const override; - void SetOutputSurface(scoped_ptr<OutputSurface>) override; + void SetOutputSurface(OutputSurface* output_surface) override; void SetLayerTreeHostClientReady() override; void SetVisible(bool visible) override; void SetThrottleFrameProduction(bool throttle) override; @@ -162,12 +187,11 @@ class CC_EXPORT ThreadProxy : public Proxy, void MainThreadHasStoppedFlinging() override; void Start() override; void Stop() override; - void ForceSerializeOnSwapBuffers() override; bool SupportsImplScrolling() const override; - void SetDebugState(const LayerTreeDebugState& debug_state) override; bool MainFrameWillHappenForTesting() override; void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override; void SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) override; + void ReleaseOutputSurface() override; // LayerTreeHostImplClient implementation void UpdateRendererCapabilitiesOnImplThread() override; @@ -222,6 +246,16 @@ class CC_EXPORT ThreadProxy : public Proxy, void SendBeginFramesToChildren(const BeginFrameArgs& args) override; void SendBeginMainFrameNotExpectedSoon() override; + // ProxyMain implementation + base::WeakPtr<ProxyMain> GetMainWeakPtr() override; + void SetChannel(scoped_ptr<ThreadedChannel> threaded_channel) override; + void DidCompleteSwapBuffers() override; + + // ProxyImpl implementation + base::WeakPtr<ProxyImpl> GetImplWeakPtr() override; + void SetThrottleFrameProductionOnImpl(bool throttle) override; + void SetLayerTreeHostClientReadyOnImpl() override; + protected: ThreadProxy( LayerTreeHost* layer_tree_host, @@ -237,13 +271,15 @@ class CC_EXPORT ThreadProxy : public Proxy, scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state); void BeginMainFrameNotExpectedSoon(); void DidCommitAndDrawFrame(); - void DidCompleteSwapBuffers(); void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue); void DidLoseOutputSurface(); void RequestNewOutputSurface(); void DidInitializeOutputSurface(bool success, const RendererCapabilities& capabilities); - void SendCommitRequestToImplThreadIfNeeded(); + // Returns |true| if the request was actually sent, |false| if one was + // already outstanding. + bool SendCommitRequestToImplThreadIfNeeded( + CommitPipelineStage required_stage); void DidCompletePageScaleAnimation(); // Called on impl thread. @@ -253,25 +289,21 @@ class CC_EXPORT ThreadProxy : public Proxy, void BeginMainFrameAbortedOnImplThread(CommitEarlyOutReason reason); void FinishAllRenderingOnImplThread(CompletionEvent* completion); void InitializeImplOnImplThread(CompletionEvent* completion); - void SetLayerTreeHostClientReadyOnImplThread(); void SetVisibleOnImplThread(CompletionEvent* completion, bool visible); - void SetThrottleFrameProductionOnImplThread(bool throttle); void HasInitializedOutputSurfaceOnImplThread( CompletionEvent* completion, bool* has_initialized_output_surface); void DeleteContentsTexturesOnImplThread(CompletionEvent* completion); - void InitializeOutputSurfaceOnImplThread( - scoped_ptr<OutputSurface> output_surface); + void InitializeOutputSurfaceOnImplThread(OutputSurface* output_surface); + void ReleaseOutputSurfaceOnImplThread(CompletionEvent* completion); void FinishGLOnImplThread(CompletionEvent* completion); void LayerTreeHostClosedOnImplThread(CompletionEvent* completion); DrawResult DrawSwapInternal(bool forced_draw); - void ForceSerializeOnSwapBuffersOnImplThread(CompletionEvent* completion); void MainFrameWillHappenOnImplThreadForTesting(CompletionEvent* completion, bool* main_frame_will_happen); 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; void PostFrameTimingEvents( scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events, @@ -292,6 +324,9 @@ class CC_EXPORT ThreadProxy : public Proxy, CompositorThreadOnly compositor_thread_vars_unsafe_; CompositorThreadOnly& impl(); + // TODO(khushalsagar): Remove this. Temporary variable to hold the channel. + scoped_ptr<ThreadedChannel> threaded_channel_; + base::WeakPtr<ThreadProxy> main_thread_weak_ptr_; base::WeakPtr<ThreadProxy> impl_thread_weak_ptr_; diff --git a/chromium/cc/trees/threaded_channel.cc b/chromium/cc/trees/threaded_channel.cc new file mode 100644 index 00000000000..3bc44c93efa --- /dev/null +++ b/chromium/cc/trees/threaded_channel.cc @@ -0,0 +1,60 @@ +// 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/trees/threaded_channel.h" + +#include "base/bind.h" +#include "base/single_thread_task_runner.h" +#include "base/trace_event/trace_event.h" + +namespace cc { + +scoped_ptr<ThreadedChannel> ThreadedChannel::Create( + ThreadProxy* thread_proxy, + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) { + return make_scoped_ptr( + new ThreadedChannel(thread_proxy, main_task_runner, impl_task_runner)); +} + +ThreadedChannel::ThreadedChannel( + ThreadProxy* thread_proxy, + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) + : proxy_main_(thread_proxy), + proxy_impl_(thread_proxy), + main_task_runner_(main_task_runner), + impl_task_runner_(impl_task_runner) {} + +void ThreadedChannel::SetThrottleFrameProductionOnImpl(bool throttle) { + ImplThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&ProxyImpl::SetThrottleFrameProductionOnImpl, + proxy_impl_->GetImplWeakPtr(), throttle)); +} + +void ThreadedChannel::SetLayerTreeHostClientReadyOnImpl() { + ImplThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&ProxyImpl::SetLayerTreeHostClientReadyOnImpl, + proxy_impl_->GetImplWeakPtr())); +} + +void ThreadedChannel::DidCompleteSwapBuffers() { + MainThreadTaskRunner()->PostTask( + FROM_HERE, base::Bind(&ProxyMain::DidCompleteSwapBuffers, + proxy_main_->GetMainWeakPtr())); +} + +ThreadedChannel::~ThreadedChannel() { + TRACE_EVENT0("cc", "ThreadChannel::~ThreadChannel"); +} + +base::SingleThreadTaskRunner* ThreadedChannel::MainThreadTaskRunner() const { + return main_task_runner_.get(); +} + +base::SingleThreadTaskRunner* ThreadedChannel::ImplThreadTaskRunner() const { + return impl_task_runner_.get(); +} + +} // namespace cc diff --git a/chromium/cc/trees/threaded_channel.h b/chromium/cc/trees/threaded_channel.h new file mode 100644 index 00000000000..70238f3ded5 --- /dev/null +++ b/chromium/cc/trees/threaded_channel.h @@ -0,0 +1,106 @@ +// 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_TREES_THREADED_CHANNEL_H_ +#define CC_TREES_THREADED_CHANNEL_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "cc/base/cc_export.h" +#include "cc/trees/channel_impl.h" +#include "cc/trees/channel_main.h" +#include "cc/trees/proxy_impl.h" +#include "cc/trees/proxy_main.h" +#include "cc/trees/thread_proxy.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace cc { +class ChannelImpl; +class ChannelMain; +class ProxyImpl; +class ProxyMain; +class ThreadProxy; + +// An implementation of ChannelMain and ChannelImpl that sends commands between +// ProxyMain and ProxyImpl across thread boundaries. +// +// LayerTreeHost creates ThreadedChannel and passes the ownership to ProxyMain. +// The object life cycle and communication across threads is as follows: +// +// +// Main Thread | Impl Thread +// LayerTreeHost->InitializeProxy | +// | | +// ProxyMain->Start() | +// | ThreadedChannel +// --------------------------------------------------------------------------- +// ChannelMain::InitializeImpl ---PostTask---> ThreadedChannel:: +// InitializeImplOnImplThread +// | +// ProxyImpl::Create +// | +// ProxyImpl->Initialize() +// . +// . +// ProxyImpl::ScheduledActionBegin +// OutputSurfaceCreation +// | +// ChannelImpl::RequestNewOutputSurface +// ---------------------------------------------------------------------------- +// | +// ProxyMain->RequestNewOutputSurface()<----PostTask-------- +// . +// . +// ProxyMain->LayerTreeHostClosed +// | +// --------------------------------------------------------------------------- +// ChannelMain::SetLayerTreeClosedOnImpl---PostTask---> ProxyImpl-> +// SetLayerTreeClosed +// ---------------------------------------------------------------------------- + +class CC_EXPORT ThreadedChannel : public ChannelMain, public ChannelImpl { + public: + static scoped_ptr<ThreadedChannel> Create( + // TODO(khushalsagar): Make this ProxyMain* and write the initialization + // sequence. Currently ThreadProxy implements both so we pass the pointer + // and set ProxyImpl. + ThreadProxy* thread_proxy, + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner); + + ~ThreadedChannel() override; + + // ChannelMain Implementation + void SetThrottleFrameProductionOnImpl(bool throttle) override; + void SetLayerTreeHostClientReadyOnImpl() override; + + // ChannelImpl Implementation + void DidCompleteSwapBuffers() override; + + protected: + ThreadedChannel(ThreadProxy* thread_proxy, + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, + scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner); + + private: + base::SingleThreadTaskRunner* MainThreadTaskRunner() const; + base::SingleThreadTaskRunner* ImplThreadTaskRunner() const; + + ProxyMain* proxy_main_; + + ProxyImpl* proxy_impl_; + + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; + + scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(ThreadedChannel); +}; + +} // namespace cc + +#endif // CC_TREES_THREADED_CHANNEL_H_ |