diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-07-31 15:50:41 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-08-30 12:35:23 +0000 |
commit | 7b2ffa587235a47d4094787d72f38102089f402a (patch) | |
tree | 30e82af9cbab08a7fa028bb18f4f2987a3f74dfa /chromium/cc | |
parent | d94af01c90575348c4e81a418257f254b6f8d225 (diff) |
BASELINE: Update Chromium to 76.0.3809.94
Change-Id: I321c3f5f929c105aec0f98c5091ef6108822e647
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/cc')
203 files changed, 4833 insertions, 2972 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn index 0878b2fdfea..b0fde3505e6 100644 --- a/chromium/cc/BUILD.gn +++ b/chromium/cc/BUILD.gn @@ -269,6 +269,7 @@ cc_component("cc") { "tiles/tiling_set_raster_queue_all.h", "tiles/tiling_set_raster_queue_required.cc", "tiles/tiling_set_raster_queue_required.h", + "trees/animation_effect_timings.h", "trees/animation_options.h", "trees/clip_expander.cc", "trees/clip_expander.h", @@ -318,6 +319,9 @@ cc_component("cc") { "trees/occlusion.h", "trees/occlusion_tracker.cc", "trees/occlusion_tracker.h", + "trees/paint_holding_commit_trigger.h", + "trees/presentation_time_callback_buffer.cc", + "trees/presentation_time_callback_buffer.h", "trees/property_animation_state.cc", "trees/property_animation_state.h", "trees/property_tree.cc", @@ -696,6 +700,7 @@ cc_test("cc_unittests") { "trees/layer_tree_impl_unittest.cc", "trees/occlusion_tracker_unittest.cc", "trees/occlusion_unittest.cc", + "trees/presentation_time_callback_buffer_unittest.cc", "trees/property_tree_unittest.cc", "trees/swap_promise_manager_unittest.cc", "trees/tree_synchronizer_unittest.cc", diff --git a/chromium/cc/DEPS b/chromium/cc/DEPS index 6f352e8c510..0186be319b6 100644 --- a/chromium/cc/DEPS +++ b/chromium/cc/DEPS @@ -33,6 +33,7 @@ include_rules = [ "+third_party/libyuv", "+third_party/skia/include", "+third_party/skia/src/core/SkRemoteGlyphCache.h", + "+ui/events/types", "+ui/latency", "+ui/gfx", "+ui/gl", diff --git a/chromium/cc/animation/DEPS b/chromium/cc/animation/DEPS index 80d05f0a872..bc229ac9da9 100644 --- a/chromium/cc/animation/DEPS +++ b/chromium/cc/animation/DEPS @@ -7,6 +7,7 @@ include_rules = [ "+cc/output/filter_operations.h", "+cc/test", "+cc/trees/animation_options.h", + "+cc/trees/animation_effect_timings.h", "+cc/trees/element_id.h", "+cc/trees/mutator_host.h", "+cc/trees/mutator_host_client.h", diff --git a/chromium/cc/animation/animation.cc b/chromium/cc/animation/animation.cc index 3974409adfd..2e4c5eb69ac 100644 --- a/chromium/cc/animation/animation.cc +++ b/chromium/cc/animation/animation.cc @@ -41,16 +41,6 @@ scoped_refptr<Animation> Animation::CreateImplInstance() const { return Animation::Create(id()); } -ElementId Animation::element_id_of_keyframe_effect( - KeyframeEffectId keyframe_effect_id) const { - DCHECK(GetKeyframeEffectById(keyframe_effect_id)); - return GetKeyframeEffectById(keyframe_effect_id)->element_id(); -} - -bool Animation::IsElementAttached(ElementId id) const { - return base::ContainsKey(element_to_keyframe_effect_id_map_, id); -} - void Animation::SetAnimationHost(AnimationHost* animation_host) { animation_host_ = animation_host; } diff --git a/chromium/cc/animation/animation.h b/chromium/cc/animation/animation.h index feb33026e2a..14a988505a9 100644 --- a/chromium/cc/animation/animation.h +++ b/chromium/cc/animation/animation.h @@ -47,9 +47,6 @@ class CC_ANIMATION_EXPORT Animation : public base::RefCounted<Animation> { int id() const { return id_; } typedef size_t KeyframeEffectId; - ElementId element_id_of_keyframe_effect( - KeyframeEffectId keyframe_effect_id) const; - bool IsElementAttached(ElementId id) const; // Parent AnimationHost. Animation can be detached from AnimationTimeline. AnimationHost* animation_host() { return animation_host_; } diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc index cbd6d8e5ad8..ccb6a42ba3c 100644 --- a/chromium/cc/animation/animation_host.cc +++ b/chromium/cc/animation/animation_host.cc @@ -47,6 +47,19 @@ AnimationWorkletMutationState ToAnimationWorkletMutationState( } } +bool TickAnimationsIf(AnimationHost::AnimationsList animations, + base::TimeTicks monotonic_time, + bool (*predicate)(const Animation&)) { + bool did_tick = false; + for (auto& it : animations) { + if (predicate(*it)) { + it->Tick(monotonic_time); + did_tick = true; + } + } + return did_tick; +} + } // namespace std::unique_ptr<AnimationHost> AnimationHost::CreateMainInstance() { @@ -129,25 +142,35 @@ void AnimationHost::RemoveAnimationTimeline( SetNeedsPushProperties(); } +void AnimationHost::UpdateRegisteredElementIds(ElementListType changed_list) { + for (auto map_entry : element_to_animations_map_) { + if (mutator_host_client()->IsElementInPropertyTrees(map_entry.first, + changed_list)) + map_entry.second->ElementIdRegistered(map_entry.first, changed_list); + else + map_entry.second->ElementIdUnregistered(map_entry.first, changed_list); + } +} + void AnimationHost::InitClientAnimationState() { for (auto map_entry : element_to_animations_map_) map_entry.second->InitClientAnimationState(); } -void AnimationHost::RegisterElement(ElementId element_id, - ElementListType list_type) { +void AnimationHost::RegisterElementId(ElementId element_id, + ElementListType list_type) { scoped_refptr<ElementAnimations> element_animations = GetElementAnimationsForElementId(element_id); if (element_animations) - element_animations->ElementRegistered(element_id, list_type); + element_animations->ElementIdRegistered(element_id, list_type); } -void AnimationHost::UnregisterElement(ElementId element_id, - ElementListType list_type) { +void AnimationHost::UnregisterElementId(ElementId element_id, + ElementListType list_type) { scoped_refptr<ElementAnimations> element_animations = GetElementAnimationsForElementId(element_id); if (element_animations) - element_animations->ElementUnregistered(element_id, list_type); + element_animations->ElementIdUnregistered(element_id, list_type); } void AnimationHost::RegisterKeyframeEffectForElement( @@ -348,31 +371,23 @@ void AnimationHost::TickMutator(base::TimeTicks monotonic_time, return; } -bool AnimationHost::ActivateAnimations() { +bool AnimationHost::ActivateAnimations(MutatorEvents* mutator_events) { if (!NeedsTickAnimations()) return false; + auto* animation_events = static_cast<AnimationEvents*>(mutator_events); + TRACE_EVENT0("cc", "AnimationHost::ActivateAnimations"); AnimationsList ticking_animations_copy = ticking_animations_; - for (auto& it : ticking_animations_copy) + for (auto& it : ticking_animations_copy) { it->ActivateKeyframeEffects(); + // Finish animations which no longer affect active or pending elements. + it->UpdateState(false, animation_events); + } return true; } -bool TickAnimationsIf(AnimationHost::AnimationsList animations, - base::TimeTicks monotonic_time, - bool (*predicate)(const Animation&)) { - bool did_tick = false; - for (auto& it : animations) { - if (predicate(*it)) { - it->Tick(monotonic_time); - did_tick = true; - } - } - return did_tick; -} - bool AnimationHost::TickAnimations(base::TimeTicks monotonic_time, const ScrollTree& scroll_tree, bool is_active_tree) { @@ -522,6 +537,15 @@ bool AnimationHost::IsAnimatingFilterProperty(ElementId element_id, : false; } +bool AnimationHost::IsAnimatingBackdropFilterProperty( + ElementId element_id, + ElementListType list_type) const { + auto element_animations = GetElementAnimationsForElementId(element_id); + return element_animations ? element_animations->IsCurrentlyAnimatingProperty( + TargetProperty::BACKDROP_FILTER, list_type) + : false; +} + bool AnimationHost::IsAnimatingOpacityProperty( ElementId element_id, ElementListType list_type) const { @@ -552,6 +576,16 @@ bool AnimationHost::HasPotentiallyRunningFilterAnimation( : false; } +bool AnimationHost::HasPotentiallyRunningBackdropFilterAnimation( + ElementId element_id, + ElementListType list_type) const { + auto element_animations = GetElementAnimationsForElementId(element_id); + return element_animations + ? element_animations->IsPotentiallyAnimatingProperty( + TargetProperty::BACKDROP_FILTER, list_type) + : false; +} + bool AnimationHost::HasPotentiallyRunningOpacityAnimation( ElementId element_id, ElementListType list_type) const { @@ -582,15 +616,6 @@ bool AnimationHost::HasAnyAnimationTargetingProperty( return element_animations->HasAnyAnimationTargetingProperty(property); } -bool AnimationHost::HasOnlyTranslationTransforms( - ElementId element_id, - ElementListType list_type) const { - auto element_animations = GetElementAnimationsForElementId(element_id); - return element_animations - ? element_animations->HasOnlyTranslationTransforms(list_type) - : true; -} - bool AnimationHost::AnimationsPreserveAxisAlignment( ElementId element_id) const { auto element_animations = GetElementAnimationsForElementId(element_id); @@ -599,18 +624,17 @@ bool AnimationHost::AnimationsPreserveAxisAlignment( : true; } -float AnimationHost::MaximumTargetScale(ElementId element_id, - ElementListType list_type) const { - auto element_animations = GetElementAnimationsForElementId(element_id); - return element_animations ? element_animations->MaximumTargetScale(list_type) - : kNotScaled; -} - -float AnimationHost::AnimationStartScale(ElementId element_id, - ElementListType list_type) const { - auto element_animations = GetElementAnimationsForElementId(element_id); - return element_animations ? element_animations->AnimationStartScale(list_type) - : kNotScaled; +void AnimationHost::GetAnimationScales(ElementId element_id, + ElementListType list_type, + float* maximum_scale, + float* starting_scale) const { + if (auto element_animations = GetElementAnimationsForElementId(element_id)) { + element_animations->GetAnimationScales(list_type, maximum_scale, + starting_scale); + return; + } + *maximum_scale = kNotScaled; + *starting_scale = kNotScaled; } bool AnimationHost::IsElementAnimating(ElementId element_id) const { diff --git a/chromium/cc/animation/animation_host.h b/chromium/cc/animation/animation_host.h index b5bff9ac843..45fca14a5b7 100644 --- a/chromium/cc/animation/animation_host.h +++ b/chromium/cc/animation/animation_host.h @@ -90,12 +90,16 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, bool supports_impl_scrolling) const override; void ClearMutators() override; + // Processes the current |element_to_animations_map_|, registering animations + // which can now be animated and unregistering those that can't based on the + // elements in the |changed_list|. + void UpdateRegisteredElementIds(ElementListType changed_list) override; void InitClientAnimationState() override; - void RegisterElement(ElementId element_id, - ElementListType list_type) override; - void UnregisterElement(ElementId element_id, + void RegisterElementId(ElementId element_id, ElementListType list_type) override; + void UnregisterElementId(ElementId element_id, + ElementListType list_type) override; void SetMutatorHostClient(MutatorHostClient* client) override; @@ -107,7 +111,7 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, void SetScrollAnimationDurationForTesting(base::TimeDelta duration) override; bool NeedsTickAnimations() const override; - bool ActivateAnimations() override; + bool ActivateAnimations(MutatorEvents* events) override; bool TickAnimations(base::TimeTicks monotonic_time, const ScrollTree& scroll_tree, bool is_active_tree) override; @@ -125,6 +129,9 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, bool IsAnimatingFilterProperty(ElementId element_id, ElementListType list_type) const override; + bool IsAnimatingBackdropFilterProperty( + ElementId element_id, + ElementListType list_type) const override; bool IsAnimatingOpacityProperty(ElementId element_id, ElementListType list_type) const override; bool IsAnimatingTransformProperty(ElementId element_id, @@ -133,6 +140,9 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, bool HasPotentiallyRunningFilterAnimation( ElementId element_id, ElementListType list_type) const override; + bool HasPotentiallyRunningBackdropFilterAnimation( + ElementId element_id, + ElementListType list_type) const override; bool HasPotentiallyRunningOpacityAnimation( ElementId element_id, ElementListType list_type) const override; @@ -144,14 +154,12 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost, ElementId element_id, TargetProperty::Type property) const override; - bool HasOnlyTranslationTransforms(ElementId element_id, - ElementListType list_type) const override; bool AnimationsPreserveAxisAlignment(ElementId element_id) const override; - float MaximumTargetScale(ElementId element_id, - ElementListType list_type) const override; - float AnimationStartScale(ElementId element_id, - ElementListType list_type) const override; + void GetAnimationScales(ElementId element_id, + ElementListType list_type, + float* maximum_scale, + float* starting_scale) const override; bool IsElementAnimating(ElementId element_id) const override; bool HasTickingKeyframeModelForTesting(ElementId element_id) const override; diff --git a/chromium/cc/animation/animation_host_unittest.cc b/chromium/cc/animation/animation_host_unittest.cc index f2f4bd650ed..9290174cded 100644 --- a/chromium/cc/animation/animation_host_unittest.cc +++ b/chromium/cc/animation/animation_host_unittest.cc @@ -32,12 +32,12 @@ class AnimationHostTest : public AnimationTimelinesTest { ~AnimationHostTest() override = default; void AttachWorkletAnimation() { - client_.RegisterElement(element_id_, ElementListType::ACTIVE); - client_impl_.RegisterElement(element_id_, ElementListType::PENDING); - client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id_, ElementListType::PENDING); + client_impl_.RegisterElementId(element_id_, ElementListType::ACTIVE); worklet_animation_ = WorkletAnimation::Create( - worklet_animation_id_, "test_name", 1, nullptr, nullptr); + worklet_animation_id_, "test_name", 1, nullptr, nullptr, nullptr); int cc_id = worklet_animation_->id(); worklet_animation_->AttachElement(element_id_); host_->AddAnimationTimeline(timeline_); @@ -121,8 +121,8 @@ TEST_F(AnimationHostTest, ImplOnlyTimeline) { } TEST_F(AnimationHostTest, ImplOnlyScrollAnimationUpdateTargetIfDetached) { - client_.RegisterElement(element_id_, ElementListType::ACTIVE); - client_impl_.RegisterElement(element_id_, ElementListType::PENDING); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id_, ElementListType::PENDING); gfx::ScrollOffset target_offset(0., 2.); gfx::ScrollOffset current_offset(0., 1.); @@ -173,7 +173,7 @@ TEST_F(AnimationHostTest, FastLayerTreeMutatorUpdateTakesEffectInSameFrame) { // Push the opacity animation to the impl thread. host_->PushPropertiesTo(host_impl_); - host_impl_->ActivateAnimations(); + host_impl_->ActivateAnimations(nullptr); // Ticking host should cause layer tree mutator to update output state which // should take effect in the same animation frame. @@ -207,7 +207,7 @@ TEST_F(AnimationHostTest, LayerTreeMutatorsIsMutatedWithCorrectInputState) { start_opacity, end_opacity, true); host_->PushPropertiesTo(host_impl_); - host_impl_->ActivateAnimations(); + host_impl_->ActivateAnimations(nullptr); EXPECT_CALL(*mock_mutator, MutateRef(_)); @@ -232,7 +232,7 @@ TEST_F(AnimationHostTest, LayerTreeMutatorsIsMutatedOnlyWhenInputChanges) { start_opacity, end_opacity, true); host_->PushPropertiesTo(host_impl_); - host_impl_->ActivateAnimations(); + host_impl_->ActivateAnimations(nullptr); EXPECT_CALL(*mock_mutator, MutateRef(_)).Times(1); @@ -306,9 +306,9 @@ TEST_F(AnimationHostTest, LayerTreeMutatorUpdateReflectsScrollAnimations) { int animation_id2 = 12; WorkletAnimationId worklet_animation_id{333, 22}; - client_.RegisterElement(element_id, ElementListType::ACTIVE); - client_impl_.RegisterElement(element_id, ElementListType::PENDING); - client_impl_.RegisterElement(element_id, ElementListType::ACTIVE); + client_.RegisterElementId(element_id, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id, ElementListType::PENDING); + client_impl_.RegisterElementId(element_id, ElementListType::ACTIVE); host_impl_->AddAnimationTimeline(timeline_); PropertyTrees property_trees; @@ -340,7 +340,7 @@ TEST_F(AnimationHostTest, LayerTreeMutatorUpdateReflectsScrollAnimations) { // Create a worklet animation that is bound to the scroll timeline. scoped_refptr<WorkletAnimation> worklet_animation( new WorkletAnimation(animation_id2, worklet_animation_id, "test_name", 1, - std::move(scroll_timeline), nullptr, true)); + std::move(scroll_timeline), nullptr, nullptr, true)); worklet_animation->AttachElement(element_id); timeline_->AttachAnimation(worklet_animation); diff --git a/chromium/cc/animation/animation_unittest.cc b/chromium/cc/animation/animation_unittest.cc index 1ffadf9a9cf..9ae34304bf0 100644 --- a/chromium/cc/animation/animation_unittest.cc +++ b/chromium/cc/animation/animation_unittest.cc @@ -55,8 +55,9 @@ TEST_F(AnimationTest, AttachDetachLayerIfTimelineAttached) { timeline_->AttachAnimation(animation_); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id_)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id_)); EXPECT_TRUE(timeline_->needs_push_properties()); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); @@ -70,8 +71,8 @@ TEST_F(AnimationTest, AttachDetachLayerIfTimelineAttached) { EXPECT_TRUE(animation_impl_); EXPECT_FALSE(animation_impl_->element_animations(keyframe_effect_id_)); - EXPECT_FALSE( - animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id_)); + EXPECT_FALSE(animation_impl_->GetKeyframeEffectById(keyframe_effect_id_) + ->element_id()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); EXPECT_FALSE(timeline_->needs_push_properties()); @@ -80,8 +81,9 @@ TEST_F(AnimationTest, AttachDetachLayerIfTimelineAttached) { EXPECT_EQ(animation_->GetKeyframeEffectById(keyframe_effect_id_), GetKeyframeEffectForElementId(element_id_)); EXPECT_TRUE(animation_->element_animations(keyframe_effect_id_)); - EXPECT_EQ(animation_->element_id_of_keyframe_effect(keyframe_effect_id_), - element_id_); + EXPECT_EQ( + animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id(), + element_id_); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); host_->PushPropertiesTo(host_impl_); @@ -89,28 +91,31 @@ TEST_F(AnimationTest, AttachDetachLayerIfTimelineAttached) { EXPECT_EQ(animation_impl_->GetKeyframeEffectById(keyframe_effect_id_), GetImplKeyframeEffectForLayerId(element_id_)); EXPECT_TRUE(animation_impl_->element_animations(keyframe_effect_id_)); - EXPECT_EQ(animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id_), - element_id_); + EXPECT_EQ( + animation_impl_->GetKeyframeEffectById(keyframe_effect_id_)->element_id(), + element_id_); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); animation_->DetachElement(); EXPECT_FALSE(GetKeyframeEffectForElementId(element_id_)); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id_)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id_)); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id()); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); host_->PushPropertiesTo(host_impl_); EXPECT_FALSE(GetImplKeyframeEffectForLayerId(element_id_)); EXPECT_FALSE(animation_impl_->element_animations(keyframe_effect_id_)); - EXPECT_FALSE( - animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id_)); + EXPECT_FALSE(animation_impl_->GetKeyframeEffectById(keyframe_effect_id_) + ->element_id()); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); timeline_->DetachAnimation(animation_); EXPECT_FALSE(animation_->animation_timeline()); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id_)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id_)); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id_)->element_id()); EXPECT_TRUE(timeline_->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id_) ->needs_push_properties()); @@ -168,9 +173,9 @@ TEST_F(AnimationTest, AttachDetachTimelineIfLayerAttached) { } TEST_F(AnimationTest, PropertiesMutate) { - client_.RegisterElement(element_id_, ElementListType::ACTIVE); - client_impl_.RegisterElement(element_id_, ElementListType::PENDING); - client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id_, ElementListType::PENDING); + client_impl_.RegisterElementId(element_id_, ElementListType::ACTIVE); host_->AddAnimationTimeline(timeline_); @@ -194,6 +199,9 @@ TEST_F(AnimationTest, PropertiesMutate) { const int transform_x = 10; const int transform_y = 20; + const float start_invert = .8f; + const float end_invert = .6f; + const double duration = 1.; AddOpacityTransitionToAnimation(animation_.get(), duration, start_opacity, @@ -203,6 +211,8 @@ TEST_F(AnimationTest, PropertiesMutate) { transform_y, keyframe_effect_id_); AddAnimatedFilterToAnimation(animation_.get(), duration, start_brightness, end_brightness, keyframe_effect_id_); + AddAnimatedBackdropFilterToAnimation(animation_.get(), duration, start_invert, + end_invert, keyframe_effect_id_); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); host_->PushPropertiesTo(host_impl_); @@ -214,6 +224,8 @@ TEST_F(AnimationTest, PropertiesMutate) { TargetProperty::TRANSFORM)); EXPECT_FALSE(client_.IsPropertyMutated(element_id_, ElementListType::ACTIVE, TargetProperty::FILTER)); + EXPECT_FALSE(client_.IsPropertyMutated(element_id_, ElementListType::ACTIVE, + TargetProperty::BACKDROP_FILTER)); EXPECT_FALSE(client_impl_.IsPropertyMutated( element_id_, ElementListType::ACTIVE, TargetProperty::OPACITY)); @@ -221,16 +233,18 @@ TEST_F(AnimationTest, PropertiesMutate) { element_id_, ElementListType::ACTIVE, TargetProperty::TRANSFORM)); EXPECT_FALSE(client_impl_.IsPropertyMutated( element_id_, ElementListType::ACTIVE, TargetProperty::FILTER)); + EXPECT_FALSE(client_impl_.IsPropertyMutated( + element_id_, ElementListType::ACTIVE, TargetProperty::BACKDROP_FILTER)); - host_impl_->ActivateAnimations(); + host_impl_->ActivateAnimations(nullptr); base::TimeTicks time; time += base::TimeDelta::FromSecondsD(0.1); - TickAnimationsTransferEvents(time, 3u); + TickAnimationsTransferEvents(time, 4u); CheckKeyframeEffectAndTimelineNeedsPushProperties(false, keyframe_effect_id_); time += base::TimeDelta::FromSecondsD(duration); - TickAnimationsTransferEvents(time, 3u); + TickAnimationsTransferEvents(time, 4u); CheckKeyframeEffectAndTimelineNeedsPushProperties(true, keyframe_effect_id_); client_.ExpectOpacityPropertyMutated(element_id_, ElementListType::ACTIVE, @@ -239,6 +253,8 @@ TEST_F(AnimationTest, PropertiesMutate) { transform_x, transform_y); client_.ExpectFilterPropertyMutated(element_id_, ElementListType::ACTIVE, end_brightness); + client_.ExpectBackdropFilterPropertyMutated( + element_id_, ElementListType::ACTIVE, end_invert); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::ACTIVE, end_opacity); @@ -246,6 +262,8 @@ TEST_F(AnimationTest, PropertiesMutate) { element_id_, ElementListType::ACTIVE, transform_x, transform_y); client_impl_.ExpectFilterPropertyMutated(element_id_, ElementListType::ACTIVE, end_brightness); + client_impl_.ExpectBackdropFilterPropertyMutated( + element_id_, ElementListType::ACTIVE, end_invert); client_impl_.ExpectOpacityPropertyMutated( element_id_, ElementListType::PENDING, end_opacity); @@ -253,15 +271,17 @@ TEST_F(AnimationTest, PropertiesMutate) { element_id_, ElementListType::PENDING, transform_x, transform_y); client_impl_.ExpectFilterPropertyMutated( element_id_, ElementListType::PENDING, end_brightness); + client_impl_.ExpectBackdropFilterPropertyMutated( + element_id_, ElementListType::PENDING, end_invert); } TEST_F(AnimationTest, AttachTwoAnimationsToOneLayer) { TestAnimationDelegate delegate1; TestAnimationDelegate delegate2; - client_.RegisterElement(element_id_, ElementListType::ACTIVE); - client_impl_.RegisterElement(element_id_, ElementListType::PENDING); - client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id_, ElementListType::PENDING); + client_impl_.RegisterElementId(element_id_, ElementListType::ACTIVE); scoped_refptr<Animation> animation1 = Animation::Create(100); scoped_refptr<Animation> animation2 = Animation::Create(200); @@ -304,7 +324,7 @@ TEST_F(AnimationTest, AttachTwoAnimationsToOneLayer) { transform_y, keyframe_effect_id2); host_->PushPropertiesTo(host_impl_); - host_impl_->ActivateAnimations(); + host_impl_->ActivateAnimations(nullptr); EXPECT_FALSE(delegate1.started()); EXPECT_FALSE(delegate1.finished()); @@ -355,9 +375,9 @@ TEST_F(AnimationTest, AttachTwoAnimationsToOneLayer) { } TEST_F(AnimationTest, AddRemoveAnimationToNonAttachedAnimation) { - client_.RegisterElement(element_id_, ElementListType::ACTIVE); - client_impl_.RegisterElement(element_id_, ElementListType::PENDING); - client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id_, ElementListType::PENDING); + client_impl_.RegisterElementId(element_id_, ElementListType::ACTIVE); animation_->AddKeyframeEffect( std::make_unique<KeyframeEffect>(keyframe_effect_id_)); @@ -412,7 +432,7 @@ TEST_F(AnimationTest, AddRemoveAnimationToNonAttachedAnimation) { EXPECT_FALSE(client_impl_.IsPropertyMutated( element_id_, ElementListType::ACTIVE, TargetProperty::FILTER)); - host_impl_->ActivateAnimations(); + host_impl_->ActivateAnimations(nullptr); base::TimeTicks time; time += base::TimeDelta::FromSecondsD(0.1); @@ -435,7 +455,7 @@ TEST_F(AnimationTest, AddRemoveAnimationToNonAttachedAnimation) { } TEST_F(AnimationTest, AddRemoveAnimationCausesSetNeedsCommit) { - client_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); host_->AddAnimationTimeline(timeline_); animation_->AddKeyframeEffect( std::make_unique<KeyframeEffect>(keyframe_effect_id_)); @@ -613,8 +633,10 @@ TEST_F(AnimationTest, timeline_->AttachAnimation(animation_); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id1)); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id1)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2)); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id1)->element_id()); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id2)->element_id()); EXPECT_TRUE(timeline_->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); @@ -630,14 +652,16 @@ TEST_F(AnimationTest, animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id1); EXPECT_TRUE(animation_->element_animations(keyframe_effect_id1)); - EXPECT_EQ(animation_->element_id_of_keyframe_effect(keyframe_effect_id1), - element_id_); + EXPECT_EQ( + animation_->GetKeyframeEffectById(keyframe_effect_id1)->element_id(), + element_id_); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); - EXPECT_NE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2), - element_id_); + EXPECT_NE( + animation_->GetKeyframeEffectById(keyframe_effect_id2)->element_id(), + element_id_); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); @@ -650,8 +674,9 @@ TEST_F(AnimationTest, animation_->AttachElementForKeyframeEffect(element_id_, keyframe_effect_id2); EXPECT_TRUE(animation_->element_animations(keyframe_effect_id2)); - EXPECT_EQ(animation_->element_id_of_keyframe_effect(keyframe_effect_id2), - element_id_); + EXPECT_EQ( + animation_->GetKeyframeEffectById(keyframe_effect_id2)->element_id(), + element_id_); EXPECT_TRUE(animation_->GetKeyframeEffectById(keyframe_effect_id2) ->needs_push_properties()); @@ -668,20 +693,24 @@ TEST_F(AnimationTest, animation_impl_->GetKeyframeEffectById(keyframe_effect_id2))); EXPECT_TRUE(animation_impl_->element_animations(keyframe_effect_id1)); - EXPECT_EQ(animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id1), - element_id_); + EXPECT_EQ( + animation_impl_->GetKeyframeEffectById(keyframe_effect_id1)->element_id(), + element_id_); EXPECT_TRUE(animation_impl_->element_animations(keyframe_effect_id2)); - EXPECT_EQ(animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id2), - element_id_); + EXPECT_EQ( + animation_impl_->GetKeyframeEffectById(keyframe_effect_id2)->element_id(), + element_id_); animation_->DetachElement(); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id1)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id1)); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id1)->element_id()); EXPECT_FALSE(element_animations->HasKeyframeEffectForTesting( animation_->GetKeyframeEffectById(keyframe_effect_id1))); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2)); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id2)->element_id()); EXPECT_FALSE(element_animations->HasKeyframeEffectForTesting( animation_->GetKeyframeEffectById(keyframe_effect_id2))); @@ -693,13 +722,13 @@ TEST_F(AnimationTest, host_->PushPropertiesTo(host_impl_); EXPECT_FALSE(animation_impl_->element_animations(keyframe_effect_id1)); - EXPECT_FALSE( - animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id1)); + EXPECT_FALSE(animation_impl_->GetKeyframeEffectById(keyframe_effect_id1) + ->element_id()); EXPECT_FALSE(element_animations_impl->HasKeyframeEffectForTesting( animation_impl_->GetKeyframeEffectById(keyframe_effect_id1))); EXPECT_FALSE(animation_impl_->element_animations(keyframe_effect_id2)); - EXPECT_FALSE( - animation_impl_->element_id_of_keyframe_effect(keyframe_effect_id2)); + EXPECT_FALSE(animation_impl_->GetKeyframeEffectById(keyframe_effect_id2) + ->element_id()); EXPECT_FALSE(element_animations_impl->HasKeyframeEffectForTesting( animation_impl_->GetKeyframeEffectById(keyframe_effect_id2))); @@ -707,9 +736,11 @@ TEST_F(AnimationTest, EXPECT_FALSE(animation_->animation_timeline()); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id1)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id1)); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id1)->element_id()); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2)); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id2)->element_id()); EXPECT_TRUE(timeline_->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) @@ -739,8 +770,10 @@ TEST_F(AnimationTest, EXPECT_FALSE(animation_->element_animations(keyframe_effect_id1)); EXPECT_FALSE(animation_->element_animations(keyframe_effect_id2)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id1)); - EXPECT_FALSE(animation_->element_id_of_keyframe_effect(keyframe_effect_id2)); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id1)->element_id()); + EXPECT_FALSE( + animation_->GetKeyframeEffectById(keyframe_effect_id2)->element_id()); EXPECT_TRUE(timeline_->needs_push_properties()); EXPECT_FALSE(animation_->GetKeyframeEffectById(keyframe_effect_id1) ->needs_push_properties()); @@ -823,9 +856,9 @@ TEST_F(AnimationTest, TEST_F(AnimationTest, TickingAnimationsFromTwoKeyframeEffects) { TestAnimationDelegate delegate1; - client_.RegisterElement(element_id_, ElementListType::ACTIVE); - client_impl_.RegisterElement(element_id_, ElementListType::PENDING); - client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id_, ElementListType::PENDING); + client_impl_.RegisterElementId(element_id_, ElementListType::ACTIVE); KeyframeEffectId keyframe_effect_id1 = animation_->NextKeyframeEffectId(); @@ -865,7 +898,7 @@ TEST_F(AnimationTest, TickingAnimationsFromTwoKeyframeEffects) { AddAnimatedTransformToAnimation(animation_.get(), duration, transform_x, transform_y, keyframe_effect_id2); host_->PushPropertiesTo(host_impl_); - host_impl_->ActivateAnimations(); + host_impl_->ActivateAnimations(nullptr); EXPECT_FALSE(delegate1.started()); EXPECT_FALSE(delegate1.finished()); @@ -926,9 +959,18 @@ TEST_F(AnimationTest, TickingState) { KeyframeEffect* keyframe_effect = animation_->GetKeyframeEffectById(keyframe_effect_id); EXPECT_FALSE(keyframe_effect->is_ticking()); - client_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); EXPECT_TRUE(keyframe_effect->is_ticking()); - client_.UnregisterElement(element_id_, ElementListType::ACTIVE); + + client_.UnregisterElementId(element_id_, ElementListType::ACTIVE); + // The keyframe keeps ticking until the next call to UpdateState where it can + // generate a finished event. + EXPECT_TRUE(keyframe_effect->is_ticking()); + + // The next call to UpdateState should remove the animation from ticking. We + // could also assert that the finish event was generated if we also track the + // state in the KeyframeModel correctly. + host_->UpdateAnimationState(true, nullptr); EXPECT_FALSE(keyframe_effect->is_ticking()); } diff --git a/chromium/cc/animation/element_animations.cc b/chromium/cc/animation/element_animations.cc index 797464ee5e8..12b9f0ffd16 100644 --- a/chromium/cc/animation/element_animations.cc +++ b/chromium/cc/animation/element_animations.cc @@ -65,11 +65,11 @@ void ElementAnimations::InitAffectedElementTypes() { DCHECK(animation_host_); DCHECK(animation_host_->mutator_host_client()); - if (animation_host_->mutator_host_client()->IsElementInList( + if (animation_host_->mutator_host_client()->IsElementInPropertyTrees( element_id_, ElementListType::ACTIVE)) { set_has_element_in_active_list(true); } - if (animation_host_->mutator_host_client()->IsElementInList( + if (animation_host_->mutator_host_client()->IsElementInPropertyTrees( element_id_, ElementListType::PENDING)) { set_has_element_in_pending_list(true); } @@ -80,6 +80,7 @@ TargetProperties ElementAnimations::GetPropertiesMaskForAnimationState() { properties[TargetProperty::TRANSFORM] = true; properties[TargetProperty::OPACITY] = true; properties[TargetProperty::FILTER] = true; + properties[TargetProperty::BACKDROP_FILTER] = true; return properties; } @@ -111,8 +112,8 @@ void ElementAnimations::ClearAffectedElementTypes( RemoveKeyframeEffectsFromTicking(); } -void ElementAnimations::ElementRegistered(ElementId element_id, - ElementListType list_type) { +void ElementAnimations::ElementIdRegistered(ElementId element_id, + ElementListType list_type) { DCHECK_EQ(element_id_, element_id); bool had_element_in_any_list = has_element_in_any_list(); @@ -126,16 +127,13 @@ void ElementAnimations::ElementRegistered(ElementId element_id, UpdateKeyframeEffectsTickingState(); } -void ElementAnimations::ElementUnregistered(ElementId element_id, - ElementListType list_type) { +void ElementAnimations::ElementIdUnregistered(ElementId element_id, + ElementListType list_type) { DCHECK_EQ(this->element_id(), element_id); if (list_type == ElementListType::ACTIVE) set_has_element_in_active_list(false); else set_has_element_in_pending_list(false); - - if (!has_element_in_any_list()) - RemoveKeyframeEffectsFromTicking(); } void ElementAnimations::AddKeyframeEffect(KeyframeEffect* keyframe_effect) { @@ -212,15 +210,6 @@ void ElementAnimations::NotifyAnimationAborted(const AnimationEvent& event) { UpdateClientAnimationState(); } -bool ElementAnimations::HasOnlyTranslationTransforms( - ElementListType list_type) const { - for (auto& keyframe_effect : keyframe_effects_list_) { - if (!keyframe_effect.HasOnlyTranslationTransforms(list_type)) - return false; - } - return true; -} - bool ElementAnimations::AnimationsPreserveAxisAlignment() const { for (auto& keyframe_effect : keyframe_effects_list_) { if (!keyframe_effect.AnimationsPreserveAxisAlignment()) @@ -229,40 +218,25 @@ bool ElementAnimations::AnimationsPreserveAxisAlignment() const { return true; } -float ElementAnimations::AnimationStartScale(ElementListType list_type) const { - float start_scale = kNotScaled; - - for (auto& keyframe_effect : keyframe_effects_list_) { - if (keyframe_effect.HasOnlyTranslationTransforms(list_type)) - continue; - float keyframe_effect_start_scale = kNotScaled; - bool success = keyframe_effect.AnimationStartScale( - list_type, &keyframe_effect_start_scale); - if (!success) - return kNotScaled; - // Union: a maximum. - start_scale = std::max(start_scale, keyframe_effect_start_scale); - } - - return start_scale; -} - -float ElementAnimations::MaximumTargetScale(ElementListType list_type) const { - float max_scale = kNotScaled; - +void ElementAnimations::GetAnimationScales(ElementListType list_type, + float* maximum_scale, + float* starting_scale) const { + *maximum_scale = kNotScaled; + *starting_scale = kNotScaled; for (auto& keyframe_effect : keyframe_effects_list_) { - if (keyframe_effect.HasOnlyTranslationTransforms(list_type)) - continue; - float keyframe_effect_max_scale = kNotScaled; - bool success = keyframe_effect.MaximumTargetScale( - list_type, &keyframe_effect_max_scale); - if (!success) - return kNotScaled; - // Union: a maximum. - max_scale = std::max(max_scale, keyframe_effect_max_scale); + float keyframe_effect_maximum_scale = kNotScaled; + float keyframe_effect_starting_scale = kNotScaled; + bool success = keyframe_effect.GetAnimationScales( + list_type, &keyframe_effect_maximum_scale, + &keyframe_effect_starting_scale); + if (!success) { + *maximum_scale = kNotScaled; + *starting_scale = kNotScaled; + return; + } + *maximum_scale = std::max(*maximum_scale, keyframe_effect_maximum_scale); + *starting_scale = std::max(*starting_scale, keyframe_effect_starting_scale); } - - return max_scale; } bool ElementAnimations::ScrollOffsetAnimationWasInterrupted() const { @@ -289,10 +263,24 @@ void ElementAnimations::NotifyClientFilterAnimated( const FilterOperations& filters, int target_property_id, KeyframeModel* keyframe_model) { - if (KeyframeModelAffectsActiveElements(keyframe_model)) - OnFilterAnimated(ElementListType::ACTIVE, filters, keyframe_model); - if (KeyframeModelAffectsPendingElements(keyframe_model)) - OnFilterAnimated(ElementListType::PENDING, filters, keyframe_model); + switch (keyframe_model->target_property_id()) { + case TargetProperty::BACKDROP_FILTER: + if (KeyframeModelAffectsActiveElements(keyframe_model)) + OnBackdropFilterAnimated(ElementListType::ACTIVE, filters, + keyframe_model); + if (KeyframeModelAffectsPendingElements(keyframe_model)) + OnBackdropFilterAnimated(ElementListType::PENDING, filters, + keyframe_model); + break; + case TargetProperty::FILTER: + if (KeyframeModelAffectsActiveElements(keyframe_model)) + OnFilterAnimated(ElementListType::ACTIVE, filters, keyframe_model); + if (KeyframeModelAffectsPendingElements(keyframe_model)) + OnFilterAnimated(ElementListType::PENDING, filters, keyframe_model); + break; + default: + NOTREACHED(); + } } void ElementAnimations::NotifyClientTransformOperationsAnimated( @@ -369,8 +357,12 @@ void ElementAnimations::UpdateClientAnimationState() { element_id_map, ElementListType::ACTIVE, diff_active, active_state_); } - float maximum_scale = MaximumTargetScale(ElementListType::ACTIVE); - float starting_scale = AnimationStartScale(ElementListType::ACTIVE); + float maximum_scale = kNotScaled; + float starting_scale = kNotScaled; + if (transform_element_id) { + GetAnimationScales(ElementListType::ACTIVE, &maximum_scale, + &starting_scale); + } if (maximum_scale != active_maximum_scale_ || starting_scale != active_starting_scale_) { animation_host_->mutator_host_client()->AnimationScalesChanged( @@ -389,8 +381,12 @@ void ElementAnimations::UpdateClientAnimationState() { pending_state_); } - float maximum_scale = MaximumTargetScale(ElementListType::PENDING); - float starting_scale = AnimationStartScale(ElementListType::PENDING); + float maximum_scale = kNotScaled; + float starting_scale = kNotScaled; + if (transform_element_id) { + GetAnimationScales(ElementListType::PENDING, &maximum_scale, + &starting_scale); + } if (maximum_scale != pending_maximum_scale_ || starting_scale != pending_starting_scale_) { animation_host_->mutator_host_client()->AnimationScalesChanged( @@ -464,6 +460,18 @@ void ElementAnimations::OnFilterAnimated(ElementListType list_type, target_element_id, list_type, filters); } +void ElementAnimations::OnBackdropFilterAnimated( + ElementListType list_type, + const FilterOperations& backdrop_filters, + KeyframeModel* keyframe_model) { + ElementId target_element_id = CalculateTargetElementId(this, keyframe_model); + DCHECK(target_element_id); + DCHECK(animation_host_); + DCHECK(animation_host_->mutator_host_client()); + animation_host_->mutator_host_client()->SetElementBackdropFilterMutated( + target_element_id, list_type, backdrop_filters); +} + void ElementAnimations::OnOpacityAnimated(ElementListType list_type, float opacity, KeyframeModel* keyframe_model) { diff --git a/chromium/cc/animation/element_animations.h b/chromium/cc/animation/element_animations.h index 911106b04d8..e2a46551787 100644 --- a/chromium/cc/animation/element_animations.h +++ b/chromium/cc/animation/element_animations.h @@ -52,8 +52,11 @@ class CC_ANIMATION_EXPORT ElementAnimations void ClearAffectedElementTypes(const PropertyToElementIdMap& element_id_map); - void ElementRegistered(ElementId element_id, ElementListType list_type); - void ElementUnregistered(ElementId element_id, ElementListType list_type); + // Called when |element_id| is available to animate in |list_type|. + void ElementIdRegistered(ElementId element_id, ElementListType list_type); + + // Called when |element_id| is no longer avialable to animate in |list_type|. + void ElementIdUnregistered(ElementId element_id, ElementListType list_type); void AddKeyframeEffect(KeyframeEffect* keyframe_effect); void RemoveKeyframeEffect(KeyframeEffect* keyframe_effect); @@ -107,19 +110,17 @@ class CC_ANIMATION_EXPORT ElementAnimations has_element_in_pending_list_ = has_element_in_pending_list; } - bool HasOnlyTranslationTransforms(ElementListType list_type) const; - bool AnimationsPreserveAxisAlignment() const; - // Returns the maximum of starting animation scale along any dimension at any - // destination in active scale animations, or kNotScaled if there is no active - // scale animation or the starting scale cannot be computed. - float AnimationStartScale(ElementListType list_type) const; - - // Returns the maximum scale along any dimension at any destination in active - // scale animations, or kNotScaled if there is no active scale animation or - // the maximum scale cannot be computed. - float MaximumTargetScale(ElementListType list_type) const; + // Gets scales transform animations. On return, |maximum_scale| is the maximum + // scale along any dimension at any destination in active scale animations, + // and |starting_scale| is the maximum of starting animation scale along any + // dimension at any destination in active scale animations. They are set to + // kNotScaled if there is no active scale animation or the scales cannot be + // computed. + void GetAnimationScales(ElementListType list_type, + float* maximum_scale, + float* starting_scale) const; bool ScrollOffsetAnimationWasInterrupted() const; @@ -179,6 +180,9 @@ class CC_ANIMATION_EXPORT ElementAnimations void OnFilterAnimated(ElementListType list_type, const FilterOperations& filters, KeyframeModel* keyframe_model); + void OnBackdropFilterAnimated(ElementListType list_type, + const FilterOperations& backdrop_filters, + KeyframeModel* keyframe_model); void OnOpacityAnimated(ElementListType list_type, float opacity, KeyframeModel* keyframe_model); diff --git a/chromium/cc/animation/element_animations_unittest.cc b/chromium/cc/animation/element_animations_unittest.cc index ee842dc9751..f093553fe15 100644 --- a/chromium/cc/animation/element_animations_unittest.cc +++ b/chromium/cc/animation/element_animations_unittest.cc @@ -60,11 +60,13 @@ class ElementAnimationsTest : public AnimationTimelinesTest { TEST_F(ElementAnimationsTest, AttachToLayerInActiveTree) { // Set up the layer which is in active tree for main thread and not // yet passed onto the impl thread. - client_.RegisterElement(element_id_, ElementListType::ACTIVE); - client_impl_.RegisterElement(element_id_, ElementListType::PENDING); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id_, ElementListType::PENDING); - EXPECT_TRUE(client_.IsElementInList(element_id_, ElementListType::ACTIVE)); - EXPECT_FALSE(client_.IsElementInList(element_id_, ElementListType::PENDING)); + EXPECT_TRUE( + client_.IsElementInPropertyTrees(element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE( + client_.IsElementInPropertyTrees(element_id_, ElementListType::PENDING)); AttachTimelineAnimationLayer(); @@ -79,17 +81,17 @@ TEST_F(ElementAnimationsTest, AttachToLayerInActiveTree) { EXPECT_TRUE(element_animations_impl_->has_element_in_pending_list()); // Create the layer in the impl active tree. - client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id_, ElementListType::ACTIVE); EXPECT_TRUE(element_animations_impl_->has_element_in_active_list()); EXPECT_TRUE(element_animations_impl_->has_element_in_pending_list()); - EXPECT_TRUE( - client_impl_.IsElementInList(element_id_, ElementListType::ACTIVE)); - EXPECT_TRUE( - client_impl_.IsElementInList(element_id_, ElementListType::PENDING)); + EXPECT_TRUE(client_impl_.IsElementInPropertyTrees(element_id_, + ElementListType::ACTIVE)); + EXPECT_TRUE(client_impl_.IsElementInPropertyTrees(element_id_, + ElementListType::PENDING)); // kill layer on main thread. - client_.UnregisterElement(element_id_, ElementListType::ACTIVE); + client_.UnregisterElementId(element_id_, ElementListType::ACTIVE); EXPECT_EQ(element_animations_, animation_->keyframe_effect()->element_animations()); EXPECT_FALSE(element_animations_->has_element_in_active_list()); @@ -103,14 +105,14 @@ TEST_F(ElementAnimationsTest, AttachToLayerInActiveTree) { EXPECT_TRUE(element_animations_impl_->has_element_in_pending_list()); // Kill layer on impl thread in pending tree. - client_impl_.UnregisterElement(element_id_, ElementListType::PENDING); + client_impl_.UnregisterElementId(element_id_, ElementListType::PENDING); EXPECT_EQ(element_animations_impl_, animation_impl_->keyframe_effect()->element_animations()); EXPECT_TRUE(element_animations_impl_->has_element_in_active_list()); EXPECT_FALSE(element_animations_impl_->has_element_in_pending_list()); // Kill layer on impl thread in active tree. - client_impl_.UnregisterElement(element_id_, ElementListType::ACTIVE); + client_impl_.UnregisterElementId(element_id_, ElementListType::ACTIVE); EXPECT_EQ(element_animations_impl_, animation_impl_->keyframe_effect()->element_animations()); EXPECT_FALSE(element_animations_impl_->has_element_in_active_list()); @@ -152,15 +154,15 @@ TEST_F(ElementAnimationsTest, AttachToNotYetCreatedLayer) { EXPECT_FALSE(element_animations_impl_->has_element_in_pending_list()); // Create layer. - client_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); EXPECT_TRUE(element_animations_->has_element_in_active_list()); EXPECT_FALSE(element_animations_->has_element_in_pending_list()); - client_impl_.RegisterElement(element_id_, ElementListType::PENDING); + client_impl_.RegisterElementId(element_id_, ElementListType::PENDING); EXPECT_FALSE(element_animations_impl_->has_element_in_active_list()); EXPECT_TRUE(element_animations_impl_->has_element_in_pending_list()); - client_impl_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_impl_.RegisterElementId(element_id_, ElementListType::ACTIVE); EXPECT_TRUE(element_animations_impl_->has_element_in_active_list()); EXPECT_TRUE(element_animations_impl_->has_element_in_pending_list()); } @@ -836,6 +838,50 @@ TEST_F(ElementAnimationsTest, FilterTransition) { EXPECT_FALSE(animation_->keyframe_effect()->HasTickingKeyframeModel()); } +TEST_F(ElementAnimationsTest, BackdropFilterTransition) { + CreateTestLayer(true, false); + AttachTimelineAnimationLayer(); + + auto events = CreateEventsForTesting(); + + std::unique_ptr<KeyframedFilterAnimationCurve> curve( + KeyframedFilterAnimationCurve::Create()); + + FilterOperations start_filters; + start_filters.Append(FilterOperation::CreateInvertFilter(0.f)); + curve->AddKeyframe( + FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr)); + FilterOperations end_filters; + end_filters.Append(FilterOperation::CreateInvertFilter(1.f)); + curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), + end_filters, nullptr)); + + std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( + std::move(curve), 1, 0, TargetProperty::BACKDROP_FILTER)); + animation_->AddKeyframeModel(std::move(keyframe_model)); + + animation_->Tick(kInitialTickTime); + animation_->UpdateState(true, events.get()); + EXPECT_TRUE(animation_->keyframe_effect()->HasTickingKeyframeModel()); + EXPECT_EQ(start_filters, + client_.GetBackdropFilters(element_id_, ElementListType::ACTIVE)); + + animation_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(500)); + animation_->UpdateState(true, events.get()); + EXPECT_EQ( + 1u, + client_.GetBackdropFilters(element_id_, ElementListType::ACTIVE).size()); + EXPECT_EQ( + FilterOperation::CreateInvertFilter(0.5f), + client_.GetBackdropFilters(element_id_, ElementListType::ACTIVE).at(0)); + + animation_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); + animation_->UpdateState(true, events.get()); + EXPECT_EQ(end_filters, + client_.GetBackdropFilters(element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(animation_->keyframe_effect()->HasTickingKeyframeModel()); +} + TEST_F(ElementAnimationsTest, ScrollOffsetTransition) { CreateTestLayer(true, false); AttachTimelineAnimationLayer(); @@ -1764,6 +1810,8 @@ TEST_F(ElementAnimationsTest, InactiveObserverGetsTicked) { animation_impl_->AddKeyframeModel(CreateKeyframeModel( std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.5f, 1.f)), id, TargetProperty::OPACITY)); + animation_impl_->GetKeyframeModel(TargetProperty::OPACITY) + ->set_affects_active_elements(false); // Without an observer, the animation shouldn't progress to the STARTING // state. @@ -1800,6 +1848,8 @@ TEST_F(ElementAnimationsTest, InactiveObserverGetsTicked) { client_impl_.GetOpacity(element_id_, ElementListType::PENDING)); CreateTestImplLayer(ElementListType::ACTIVE); + animation_impl_->GetKeyframeModel(TargetProperty::OPACITY) + ->set_affects_active_elements(true); // Now that an active observer has been added, the animation should still // initially tick at its starting point, but should now progress to RUNNING. @@ -2162,25 +2212,35 @@ TEST_F(ElementAnimationsTest, FinishedAndAbortedEventsForGroup) { EXPECT_EQ(TargetProperty::OPACITY, events->events_[1].target_property); } -TEST_F(ElementAnimationsTest, HasOnlyTranslationTransforms) { +TEST_F(ElementAnimationsTest, GetAnimationScalesNotScaled) { CreateTestLayer(true, false); AttachTimelineAnimationLayer(); CreateImplTimelineAndAnimation(); - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::ACTIVE)); - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::PENDING)); + float max_scale = 999; + float start_scale = 999; + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); + EXPECT_EQ(kNotScaled, max_scale); + EXPECT_EQ(kNotScaled, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); + EXPECT_EQ(kNotScaled, max_scale); + EXPECT_EQ(kNotScaled, start_scale); animation_impl_->AddKeyframeModel(CreateKeyframeModel( std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)), 1, TargetProperty::OPACITY)); // Opacity animations aren't non-translation transforms. - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::ACTIVE)); - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::PENDING)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); + EXPECT_EQ(kNotScaled, max_scale); + EXPECT_EQ(kNotScaled, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); + EXPECT_EQ(kNotScaled, max_scale); + EXPECT_EQ(kNotScaled, start_scale); std::unique_ptr<KeyframedTransformAnimationCurve> curve1( KeyframedTransformAnimationCurve::Create()); @@ -2197,58 +2257,17 @@ TEST_F(ElementAnimationsTest, HasOnlyTranslationTransforms) { animation_impl_->AddKeyframeModel(std::move(keyframe_model)); // The only transform animation we've added is a translation. - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::ACTIVE)); - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::PENDING)); - - std::unique_ptr<KeyframedTransformAnimationCurve> curve2( - KeyframedTransformAnimationCurve::Create()); - - TransformOperations operations2; - curve2->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr)); - operations2.AppendScale(2.0, 3.0, 4.0); - curve2->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operations2, nullptr)); - - keyframe_model = - KeyframeModel::Create(std::move(curve2), 3, 3, TargetProperty::TRANSFORM); - keyframe_model->set_affects_active_elements(false); - animation_impl_->AddKeyframeModel(std::move(keyframe_model)); - - // A scale animation is not a translation. - EXPECT_FALSE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::PENDING)); - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::ACTIVE)); - - animation_impl_->ActivateKeyframeEffects(); - EXPECT_FALSE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::PENDING)); - EXPECT_FALSE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::ACTIVE)); - - animation_impl_->keyframe_effect() - ->GetKeyframeModelById(3) - ->set_affects_pending_elements(false); - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::PENDING)); - EXPECT_FALSE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::ACTIVE)); - - animation_impl_->keyframe_effect()->GetKeyframeModelById(3)->SetRunState( - KeyframeModel::FINISHED, TicksFromSecondsF(0.0)); - - // Only unfinished animations should be considered by - // HasOnlyTranslationTransforms. - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::PENDING)); - EXPECT_TRUE(animation_impl_->keyframe_effect()->HasOnlyTranslationTransforms( - ElementListType::ACTIVE)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); + EXPECT_EQ(kNotScaled, max_scale); + EXPECT_EQ(kNotScaled, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); + EXPECT_EQ(kNotScaled, max_scale); + EXPECT_EQ(kNotScaled, start_scale); } -TEST_F(ElementAnimationsTest, AnimationStartScale) { +TEST_F(ElementAnimationsTest, GetAnimationScales) { CreateTestLayer(true, false); AttachTimelineAnimationLayer(); CreateImplTimelineAndAnimation(); @@ -2256,43 +2275,51 @@ TEST_F(ElementAnimationsTest, AnimationStartScale) { std::unique_ptr<KeyframedTransformAnimationCurve> curve1( KeyframedTransformAnimationCurve::Create()); - TransformOperations operations1; - operations1.AppendScale(2.0, 3.0, 4.0); + TransformOperations operations1a; + operations1a.AppendScale(2.0, 3.0, 4.0); curve1->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr)); - TransformOperations operations2; + TransformKeyframe::Create(base::TimeDelta(), operations1a, nullptr)); + TransformOperations operations1b; + operations1b.AppendScale(5.0, 4.0, 3.0); curve1->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operations2, nullptr)); + base::TimeDelta::FromSecondsD(1.0), operations1b, nullptr)); std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( std::move(curve1), 1, 1, TargetProperty::TRANSFORM)); keyframe_model->set_affects_active_elements(false); animation_impl_->AddKeyframeModel(std::move(keyframe_model)); - float start_scale = 0.f; - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::PENDING, &start_scale)); + float max_scale = kNotScaled; + float start_scale = kNotScaled; + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); + EXPECT_EQ(5.f, max_scale); EXPECT_EQ(4.f, start_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::ACTIVE, &start_scale)); - EXPECT_EQ(0.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); + EXPECT_EQ(kNotScaled, max_scale); + EXPECT_EQ(kNotScaled, start_scale); animation_impl_->ActivateKeyframeEffects(); - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::PENDING, &start_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); + EXPECT_EQ(5.f, max_scale); EXPECT_EQ(4.f, start_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::ACTIVE, &start_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); + EXPECT_EQ(5.f, max_scale); EXPECT_EQ(4.f, start_scale); std::unique_ptr<KeyframedTransformAnimationCurve> curve2( KeyframedTransformAnimationCurve::Create()); - TransformOperations operations3; + TransformOperations operations2a; + operations2a.AppendScale(1.0, 2.0, 3.0); curve2->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), operations3, nullptr)); - operations3.AppendScale(6.0, 5.0, 4.0); + TransformKeyframe::Create(base::TimeDelta(), operations2a, nullptr)); + TransformOperations operations2b; + operations2b.AppendScale(6.0, 5.0, 4.0); curve2->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operations3, nullptr)); + base::TimeDelta::FromSecondsD(1.0), operations2b, nullptr)); animation_impl_->RemoveKeyframeModel(1); keyframe_model = @@ -2306,163 +2333,54 @@ TEST_F(ElementAnimationsTest, AnimationStartScale) { std::unique_ptr<KeyframedTransformAnimationCurve> curve3( KeyframedTransformAnimationCurve::Create()); - TransformOperations operations4; - operations4.AppendScale(5.0, 3.0, 1.0); + TransformOperations operations3a; + operations3a.AppendScale(5.0, 3.0, 1.0); curve3->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), operations4, nullptr)); - TransformOperations operations5; + TransformKeyframe::Create(base::TimeDelta(), operations3a, nullptr)); + TransformOperations operations3b; + operations3b.AppendScale(1.5, 2.5, 3.5); curve3->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operations5, nullptr)); + base::TimeDelta::FromSecondsD(1.0), operations3b, nullptr)); keyframe_model = KeyframeModel::Create(std::move(curve3), 3, 3, TargetProperty::TRANSFORM); keyframe_model->set_affects_active_elements(false); animation_impl_->AddKeyframeModel(std::move(keyframe_model)); - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::PENDING, &start_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); + EXPECT_EQ(3.5f, max_scale); EXPECT_EQ(6.f, start_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::ACTIVE, &start_scale)); - EXPECT_EQ(0.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); + EXPECT_EQ(kNotScaled, max_scale); + EXPECT_EQ(kNotScaled, start_scale); animation_impl_->ActivateKeyframeEffects(); - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::PENDING, &start_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); + EXPECT_EQ(3.5f, max_scale); EXPECT_EQ(6.f, start_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::ACTIVE, &start_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); + EXPECT_EQ(3.5f, max_scale); EXPECT_EQ(6.f, start_scale); animation_impl_->keyframe_effect()->GetKeyframeModelById(2)->SetRunState( KeyframeModel::FINISHED, TicksFromSecondsF(0.0)); - // Only unfinished animations should be considered by - // AnimationStartScale. - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::PENDING, &start_scale)); + // Only unfinished animations should be considered by GetAnimationScales. + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); + EXPECT_EQ(3.5f, max_scale); EXPECT_EQ(5.f, start_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->AnimationStartScale( - ElementListType::ACTIVE, &start_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); + EXPECT_EQ(3.5f, max_scale); EXPECT_EQ(5.f, start_scale); } -TEST_F(ElementAnimationsTest, MaximumTargetScale) { - CreateTestLayer(true, false); - AttachTimelineAnimationLayer(); - CreateImplTimelineAndAnimation(); - - float max_scale = 0.f; - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); - EXPECT_EQ(0.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); - EXPECT_EQ(0.f, max_scale); - - std::unique_ptr<KeyframedTransformAnimationCurve> curve1( - KeyframedTransformAnimationCurve::Create()); - - TransformOperations operations1; - curve1->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr)); - operations1.AppendScale(2.0, 3.0, 4.0); - curve1->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operations1, nullptr)); - - std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create( - std::move(curve1), 1, 1, TargetProperty::TRANSFORM)); - keyframe_model->set_affects_active_elements(false); - animation_impl_->AddKeyframeModel(std::move(keyframe_model)); - - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); - EXPECT_EQ(4.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); - EXPECT_EQ(0.f, max_scale); - - animation_impl_->ActivateKeyframeEffects(); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); - EXPECT_EQ(4.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); - EXPECT_EQ(4.f, max_scale); - - std::unique_ptr<KeyframedTransformAnimationCurve> curve2( - KeyframedTransformAnimationCurve::Create()); - - TransformOperations operations2; - curve2->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr)); - operations2.AppendScale(6.0, 5.0, 4.0); - curve2->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operations2, nullptr)); - - keyframe_model = - KeyframeModel::Create(std::move(curve2), 2, 2, TargetProperty::TRANSFORM); - keyframe_model->set_affects_active_elements(false); - animation_impl_->AddKeyframeModel(std::move(keyframe_model)); - - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); - EXPECT_EQ(6.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); - EXPECT_EQ(4.f, max_scale); - - animation_impl_->ActivateKeyframeEffects(); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); - EXPECT_EQ(6.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); - EXPECT_EQ(6.f, max_scale); - - std::unique_ptr<KeyframedTransformAnimationCurve> curve3( - KeyframedTransformAnimationCurve::Create()); - - TransformOperations operations3; - curve3->AddKeyframe( - TransformKeyframe::Create(base::TimeDelta(), operations3, nullptr)); - operations3.AppendPerspective(6.0); - curve3->AddKeyframe(TransformKeyframe::Create( - base::TimeDelta::FromSecondsD(1.0), operations3, nullptr)); - - keyframe_model = - KeyframeModel::Create(std::move(curve3), 3, 3, TargetProperty::TRANSFORM); - keyframe_model->set_affects_active_elements(false); - animation_impl_->AddKeyframeModel(std::move(keyframe_model)); - - EXPECT_FALSE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); - EXPECT_EQ(6.f, max_scale); - - animation_impl_->ActivateKeyframeEffects(); - EXPECT_FALSE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); - EXPECT_FALSE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); - - animation_impl_->keyframe_effect()->GetKeyframeModelById(3)->SetRunState( - KeyframeModel::FINISHED, TicksFromSecondsF(0.0)); - animation_impl_->keyframe_effect()->GetKeyframeModelById(2)->SetRunState( - KeyframeModel::FINISHED, TicksFromSecondsF(0.0)); - - // Only unfinished animations should be considered by - // MaximumTargetScale. - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); - EXPECT_EQ(4.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); - EXPECT_EQ(4.f, max_scale); -} - -TEST_F(ElementAnimationsTest, MaximumTargetScaleWithDirection) { +TEST_F(ElementAnimationsTest, GetAnimationScalesWithDirection) { CreateTestLayer(true, false); AttachTimelineAnimationLayer(); CreateImplTimelineAndAnimation(); @@ -2483,83 +2401,100 @@ TEST_F(ElementAnimationsTest, MaximumTargetScaleWithDirection) { KeyframeModel* keyframe_model = keyframe_model_owned.get(); animation_impl_->AddKeyframeModel(std::move(keyframe_model_owned)); - float max_scale = 0.f; + float max_scale = 999; + float start_scale = 999; EXPECT_GT(keyframe_model->playback_rate(), 0.0); // NORMAL direction with positive playback rate. keyframe_model->set_direction(KeyframeModel::Direction::NORMAL); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); EXPECT_EQ(6.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); + EXPECT_EQ(3.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); EXPECT_EQ(6.f, max_scale); + EXPECT_EQ(3.f, start_scale); // ALTERNATE direction with positive playback rate. keyframe_model->set_direction(KeyframeModel::Direction::ALTERNATE_NORMAL); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); EXPECT_EQ(6.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); + EXPECT_EQ(3.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); EXPECT_EQ(6.f, max_scale); + EXPECT_EQ(3.f, start_scale); // REVERSE direction with positive playback rate. keyframe_model->set_direction(KeyframeModel::Direction::REVERSE); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); EXPECT_EQ(3.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); + EXPECT_EQ(6.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); EXPECT_EQ(3.f, max_scale); + EXPECT_EQ(6.f, start_scale); // ALTERNATE reverse direction. keyframe_model->set_direction(KeyframeModel::Direction::REVERSE); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); EXPECT_EQ(3.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); + EXPECT_EQ(6.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); EXPECT_EQ(3.f, max_scale); + EXPECT_EQ(6.f, start_scale); keyframe_model->set_playback_rate(-1.0); // NORMAL direction with negative playback rate. keyframe_model->set_direction(KeyframeModel::Direction::NORMAL); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); EXPECT_EQ(3.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); + EXPECT_EQ(6.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); EXPECT_EQ(3.f, max_scale); + EXPECT_EQ(6.f, start_scale); // ALTERNATE direction with negative playback rate. keyframe_model->set_direction(KeyframeModel::Direction::ALTERNATE_NORMAL); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); EXPECT_EQ(3.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); + EXPECT_EQ(6.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); EXPECT_EQ(3.f, max_scale); + EXPECT_EQ(6.f, start_scale); // REVERSE direction with negative playback rate. keyframe_model->set_direction(KeyframeModel::Direction::REVERSE); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); EXPECT_EQ(6.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); + EXPECT_EQ(3.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); EXPECT_EQ(6.f, max_scale); + EXPECT_EQ(3.f, start_scale); // ALTERNATE reverse direction with negative playback rate. keyframe_model->set_direction(KeyframeModel::Direction::REVERSE); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::PENDING, &max_scale)); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::PENDING, &max_scale, &start_scale)); EXPECT_EQ(6.f, max_scale); - EXPECT_TRUE(animation_impl_->keyframe_effect()->MaximumTargetScale( - ElementListType::ACTIVE, &max_scale)); + EXPECT_EQ(3.f, start_scale); + EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales( + ElementListType::ACTIVE, &max_scale, &start_scale)); EXPECT_EQ(6.f, max_scale); + EXPECT_EQ(3.f, start_scale); } TEST_F(ElementAnimationsTest, NewlyPushedAnimationWaitsForActivation) { @@ -3348,6 +3283,221 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenFilterAnimationChanges) { element_id_, ElementListType::ACTIVE)); } +TEST_F(ElementAnimationsTest, + ObserverNotifiedWhenBackdropFilterAnimationChanges) { + CreateTestLayer(true, true); + AttachTimelineAnimationLayer(); + CreateImplTimelineAndAnimation(); + + auto events = CreateEventsForTesting(); + + EXPECT_FALSE(client_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + // Case 1: An animation that's allowed to run until its finish point. + AddAnimatedBackdropFilterToAnimation(animation_.get(), 1.0, 0.f, 1.f); + EXPECT_TRUE(client_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_TRUE(client_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + PushProperties(); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_TRUE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->ActivateKeyframeEffects(); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_TRUE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_TRUE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->Tick(kInitialTickTime); + animation_impl_->UpdateState(true, events.get()); + + animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + events->events_.clear(); + + // Finish the animation. + animation_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); + animation_->UpdateState(true, nullptr); + EXPECT_FALSE(client_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + PushProperties(); + + // Finished animations are pushed, but animations_impl hasn't yet ticked + // at/past the end of the animation. + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_TRUE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000)); + animation_impl_->UpdateState(true, events.get()); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + // Case 2: An animation that's removed before it finishes. + int keyframe_model_id = + AddAnimatedBackdropFilterToAnimation(animation_.get(), 10.0, 0.f, 1.f); + EXPECT_TRUE(client_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_TRUE(client_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + PushProperties(); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_TRUE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->ActivateKeyframeEffects(); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_TRUE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); + animation_impl_->UpdateState(true, events.get()); + + animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + events->events_.clear(); + + animation_->RemoveKeyframeModel(keyframe_model_id); + EXPECT_FALSE(client_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + PushProperties(); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_TRUE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->ActivateKeyframeEffects(); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + // Case 3: An animation that's aborted before it finishes. + keyframe_model_id = + AddAnimatedBackdropFilterToAnimation(animation_.get(), 10.0, 0.f, 0.5f); + EXPECT_TRUE(client_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_TRUE(client_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + PushProperties(); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_TRUE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->ActivateKeyframeEffects(); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_TRUE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(2000)); + animation_impl_->UpdateState(true, events.get()); + + animation_->keyframe_effect()->NotifyKeyframeModelStarted(events->events_[0]); + events->events_.clear(); + + animation_impl_->AbortKeyframeModelsWithProperty( + TargetProperty::BACKDROP_FILTER, false); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(4000)); + animation_impl_->UpdateState(true, events.get()); + + element_animations_->NotifyAnimationAborted(events->events_[0]); + EXPECT_FALSE(client_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + // Case 4 : An animation that's not in effect. + keyframe_model_id = + AddAnimatedBackdropFilterToAnimation(animation_.get(), 1.0, 0.f, 0.5f); + animation_->keyframe_effect() + ->GetKeyframeModelById(keyframe_model_id) + ->set_time_offset(base::TimeDelta::FromMilliseconds(-10000)); + animation_->keyframe_effect() + ->GetKeyframeModelById(keyframe_model_id) + ->set_fill_mode(KeyframeModel::FillMode::NONE); + + PushProperties(); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::PENDING)); + EXPECT_FALSE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); + + animation_impl_->ActivateKeyframeEffects(); + EXPECT_TRUE(client_impl_.GetHasPotentialBackdropFilterAnimation( + element_id_, ElementListType::ACTIVE)); + EXPECT_FALSE(client_impl_.GetBackdropFilterIsCurrentlyAnimating( + element_id_, ElementListType::ACTIVE)); +} + TEST_F(ElementAnimationsTest, ClippedOpacityValues) { CreateTestLayer(false, false); AttachTimelineAnimationLayer(); @@ -3704,9 +3854,11 @@ TEST_F(ElementAnimationsTest, DestroyTestMainLayerBeforePushProperties) { EXPECT_EQ(1u, host_->ticking_animations_for_testing().size()); DestroyTestMainLayer(); + host_->UpdateAnimationState(true, nullptr); EXPECT_EQ(0u, host_->ticking_animations_for_testing().size()); PushProperties(); + host_impl_->ActivateAnimations(nullptr); EXPECT_EQ(0u, host_->ticking_animations_for_testing().size()); EXPECT_EQ(0u, host_impl_->ticking_animations_for_testing().size()); } diff --git a/chromium/cc/animation/keyframe_effect.cc b/chromium/cc/animation/keyframe_effect.cc index 6a6dc76a121..d1d55431893 100644 --- a/chromium/cc/animation/keyframe_effect.cc +++ b/chromium/cc/animation/keyframe_effect.cc @@ -183,13 +183,11 @@ void KeyframeEffect::RemoveFromTicking() { void KeyframeEffect::UpdateState(bool start_ready_keyframe_models, AnimationEvents* events) { DCHECK(has_bound_element_animations()); - if (!element_animations_->has_element_in_active_list()) - return; // Animate hasn't been called, this happens if an element has been added // between the Commit and Draw phases. if (last_tick_time_ == base::TimeTicks()) - return; + start_ready_keyframe_models = false; if (start_ready_keyframe_models) PromoteStartedKeyframeModels(events); @@ -204,6 +202,9 @@ void KeyframeEffect::UpdateState(bool start_ready_keyframe_models, PromoteStartedKeyframeModels(events); } } + + if (!element_animations()->has_element_in_any_list()) + RemoveFromTicking(); } void KeyframeEffect::UpdateTickingState() { @@ -460,27 +461,6 @@ bool KeyframeEffect::HasNonDeletedKeyframeModel() const { return false; } -bool KeyframeEffect::HasOnlyTranslationTransforms( - ElementListType list_type) const { - for (const auto& keyframe_model : keyframe_models_) { - if (keyframe_model->is_finished() || - keyframe_model->target_property_id() != TargetProperty::TRANSFORM) - continue; - - if ((list_type == ElementListType::ACTIVE && - !keyframe_model->affects_active_elements()) || - (list_type == ElementListType::PENDING && - !keyframe_model->affects_pending_elements())) - continue; - - const TransformAnimationCurve* transform_animation_curve = - keyframe_model->curve()->ToTransformAnimationCurve(); - if (!transform_animation_curve->IsTranslation()) - return false; - } - return true; -} - bool KeyframeEffect::AnimationsPreserveAxisAlignment() const { for (const auto& keyframe_model : keyframe_models_) { if (keyframe_model->is_finished() || @@ -495,9 +475,13 @@ bool KeyframeEffect::AnimationsPreserveAxisAlignment() const { return true; } -bool KeyframeEffect::AnimationStartScale(ElementListType list_type, - float* start_scale) const { - *start_scale = 0.f; +bool KeyframeEffect::GetAnimationScales(ElementListType list_type, + float* maximum_scale, + float* starting_scale) const { + *maximum_scale = kNotScaled; + *starting_scale = kNotScaled; + bool maximum_scale_valid = true; + bool starting_scale_valid = true; for (const auto& keyframe_model : keyframe_models_) { if (keyframe_model->is_finished() || keyframe_model->target_property_id() != TargetProperty::TRANSFORM) @@ -509,41 +493,9 @@ bool KeyframeEffect::AnimationStartScale(ElementListType list_type, !keyframe_model->affects_pending_elements())) continue; - bool forward_direction = true; - switch (keyframe_model->direction()) { - case KeyframeModel::Direction::NORMAL: - case KeyframeModel::Direction::ALTERNATE_NORMAL: - forward_direction = keyframe_model->playback_rate() >= 0.0; - break; - case KeyframeModel::Direction::REVERSE: - case KeyframeModel::Direction::ALTERNATE_REVERSE: - forward_direction = keyframe_model->playback_rate() < 0.0; - break; - } - const TransformAnimationCurve* transform_animation_curve = keyframe_model->curve()->ToTransformAnimationCurve(); - float keyframe_model_start_scale = 0.f; - if (!transform_animation_curve->AnimationStartScale( - forward_direction, &keyframe_model_start_scale)) - return false; - *start_scale = std::max(*start_scale, keyframe_model_start_scale); - } - return true; -} - -bool KeyframeEffect::MaximumTargetScale(ElementListType list_type, - float* max_scale) const { - *max_scale = 0.f; - for (const auto& keyframe_model : keyframe_models_) { - if (keyframe_model->is_finished() || - keyframe_model->target_property_id() != TargetProperty::TRANSFORM) - continue; - - if ((list_type == ElementListType::ACTIVE && - !keyframe_model->affects_active_elements()) || - (list_type == ElementListType::PENDING && - !keyframe_model->affects_pending_elements())) + if (transform_animation_curve->IsTranslation()) continue; bool forward_direction = true; @@ -558,15 +510,32 @@ bool KeyframeEffect::MaximumTargetScale(ElementListType list_type, break; } - const TransformAnimationCurve* transform_animation_curve = - keyframe_model->curve()->ToTransformAnimationCurve(); - float keyframe_model_scale = 0.f; - if (!transform_animation_curve->MaximumTargetScale(forward_direction, - &keyframe_model_scale)) + if (maximum_scale_valid) { + float keyframe_model_maximum_scale = kNotScaled; + if (transform_animation_curve->MaximumTargetScale( + forward_direction, &keyframe_model_maximum_scale)) { + *maximum_scale = std::max(*maximum_scale, keyframe_model_maximum_scale); + } else { + maximum_scale_valid = false; + *maximum_scale = kNotScaled; + } + } + + if (starting_scale_valid) { + float keyframe_model_starting_scale = kNotScaled; + if (transform_animation_curve->AnimationStartScale( + forward_direction, &keyframe_model_starting_scale)) { + *starting_scale = + std::max(*starting_scale, keyframe_model_starting_scale); + } else { + starting_scale_valid = false; + *starting_scale = kNotScaled; + } + } + + if (!maximum_scale_valid && !starting_scale_valid) return false; - *max_scale = std::max(*max_scale, keyframe_model_scale); } - return true; } @@ -681,6 +650,15 @@ void KeyframeEffect::PurgeKeyframeModelsMarkedForDeletion(bool impl_only) { }); } +void KeyframeEffect::PurgeDeletedKeyframeModels() { + base::EraseIf(keyframe_models_, + [](const std::unique_ptr<KeyframeModel>& keyframe_model) { + return keyframe_model->run_state() == + KeyframeModel::WAITING_FOR_DELETION && + !keyframe_model->affects_pending_elements(); + }); +} + void KeyframeEffect::PushNewKeyframeModelsToImplThread( KeyframeEffect* keyframe_effect_impl) const { // Any new KeyframeModels owned by the main thread's Animation are @@ -746,22 +724,15 @@ void KeyframeEffect::RemoveKeyframeModelsCompletedOnMainThread( // elements, and should stop affecting active elements after the next call // to ActivateKeyframeEffects. If already WAITING_FOR_DELETION, they can be // removed immediately. - auto& keyframe_models = keyframe_effect_impl->keyframe_models_; - for (const auto& keyframe_model : keyframe_models) { + for (const std::unique_ptr<KeyframeModel>& keyframe_model : + keyframe_effect_impl->keyframe_models_) { if (IsCompleted(keyframe_model.get(), this)) { keyframe_model->set_affects_pending_elements(false); keyframe_model_completed = true; } } - auto affects_active_only_and_is_waiting_for_deletion = - [](const std::unique_ptr<KeyframeModel>& keyframe_model) { - return keyframe_model->run_state() == - KeyframeModel::WAITING_FOR_DELETION && - !keyframe_model->affects_pending_elements(); - }; - base::EraseIf(keyframe_models, - affects_active_only_and_is_waiting_for_deletion); + keyframe_effect_impl->PurgeDeletedKeyframeModels(); if (has_bound_element_animations() && keyframe_model_completed) element_animations_->SetNeedsPushProperties(); } diff --git a/chromium/cc/animation/keyframe_effect.h b/chromium/cc/animation/keyframe_effect.h index 500f0bd5352..3bcb0347439 100644 --- a/chromium/cc/animation/keyframe_effect.h +++ b/chromium/cc/animation/keyframe_effect.h @@ -121,19 +121,17 @@ class CC_ANIMATION_EXPORT KeyframeEffect { bool HasNonDeletedKeyframeModel() const; - bool HasOnlyTranslationTransforms(ElementListType list_type) const; - bool AnimationsPreserveAxisAlignment() const; - // Sets |start_scale| to the maximum of starting keyframe_model scale along - // any dimension at any destination in active KeyframeModels. Returns false - // if the starting scale cannot be computed. - bool AnimationStartScale(ElementListType, float* start_scale) const; - - // Sets |max_scale| to the maximum scale along any dimension at any - // destination in active KeyframeModels. Returns false if the maximum scale - // cannot be computed. - bool MaximumTargetScale(ElementListType, float* max_scale) const; + // Gets scales transform animations. On return, |maximum_scale| is the maximum + // scale along any dimension at any destination in active scale animations, + // and |starting_scale| is the maximum of starting animation scale along any + // dimension at any destination in active scale animations. They are set to + // kNotScaled if there is no active scale animation or the scales cannot be + // computed. Returns false if the scales cannot be computed. + bool GetAnimationScales(ElementListType, + float* maximum_scale, + float* starting_scale) const; // Returns true if there is a keyframe_model that is either currently // animating the given property or scheduled to animate this property in the @@ -169,6 +167,7 @@ class CC_ANIMATION_EXPORT KeyframeEffect { private: void StartKeyframeModels(base::TimeTicks monotonic_time); void PromoteStartedKeyframeModels(AnimationEvents* events); + void PurgeDeletedKeyframeModels(); void MarkKeyframeModelsForDeletion(base::TimeTicks, AnimationEvents* events); void MarkFinishedKeyframeModels(base::TimeTicks monotonic_time); diff --git a/chromium/cc/animation/keyframed_animation_curve_unittest.cc b/chromium/cc/animation/keyframed_animation_curve_unittest.cc index 05ab2145f74..4b678bdfac6 100644 --- a/chromium/cc/animation/keyframed_animation_curve_unittest.cc +++ b/chromium/cc/animation/keyframed_animation_curve_unittest.cc @@ -602,30 +602,6 @@ TEST(KeyframedAnimationCurveTest, StepsTimingFunctionStepAtEnd) { } } -// Tests a frames timing function. -TEST(KeyframedAnimationCurveTest, FramesTimingFunction) { - std::unique_ptr<KeyframedFloatAnimationCurve> curve( - KeyframedFloatAnimationCurve::Create()); - curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, - FramesTimingFunction::Create(5))); - curve->AddKeyframe( - FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr)); - - struct Expected { - double time; - float value; - } expectations[] = { - {0.0, 0.f}, {0.1999, 0.f}, {0.2001, 0.25f}, {0.3999, 0.25f}, - {0.4001, 0.5f}, {0.5999, 0.5f}, {0.6001, 0.75f}, {0.7999, 0.75f}, - {0.8001, 1.f}, {1.0, 1.f}, - }; - for (const auto& expectation : expectations) { - EXPECT_FLOAT_EQ( - expectation.value, - curve->GetValue(base::TimeDelta::FromSecondsD(expectation.time))); - } -} - // Tests that animations that are translations are correctly identified. TEST(KeyframedAnimationCurveTest, IsTranslation) { std::unique_ptr<KeyframedTransformAnimationCurve> curve( @@ -916,23 +892,6 @@ TEST(KeyframedAnimationCurveTest, StepsTimingEndInputsOutsideZeroOneRange) { EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f))); } -// Tests that a frames timing function works as expected for inputs outside of -// range [0,1] -TEST(KeyframedAnimationCurveTest, FramesTimingInputsOutsideZeroOneRange) { - std::unique_ptr<KeyframedFloatAnimationCurve> curve( - KeyframedFloatAnimationCurve::Create()); - curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, - FramesTimingFunction::Create(5))); - curve->AddKeyframe( - FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr)); - // Curve timing function producing timing outputs outside of range [0,1]. - curve->SetTimingFunction( - CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f)); - - EXPECT_FLOAT_EQ(-0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f))); - EXPECT_FLOAT_EQ(2.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f))); -} - // Tests that an animation with a curve timing function and multiple keyframes // works as expected. TEST(KeyframedAnimationCurveTest, CurveTimingMultipleKeyframes) { diff --git a/chromium/cc/animation/scroll_timeline.cc b/chromium/cc/animation/scroll_timeline.cc index 16ef8ded216..cc4b5bf7140 100644 --- a/chromium/cc/animation/scroll_timeline.cc +++ b/chromium/cc/animation/scroll_timeline.cc @@ -47,25 +47,33 @@ std::unique_ptr<ScrollTimeline> ScrollTimeline::CreateImplInstance() const { time_range_, fill_); } +bool ScrollTimeline::IsActive(const ScrollTree& scroll_tree, + bool is_active_tree) const { + // If pending tree with our scroller hasn't been activated, or the scroller + // has been removed (e.g. if it is no longer composited). + if ((is_active_tree && !active_id_) || (!is_active_tree && !pending_id_)) + return false; + + ElementId scroller_id = + is_active_tree ? active_id_.value() : pending_id_.value(); + // The scroller is not in the ScrollTree if it is not currently scrollable + // (e.g. has overflow: visible). In this case the timeline is not active. + return scroll_tree.FindNodeFromElementId(scroller_id); +} + base::Optional<base::TimeTicks> ScrollTimeline::CurrentTime( const ScrollTree& scroll_tree, bool is_active_tree) const { - // We may be asked for the CurrentTime before the pending tree with our - // scroller has been activated, or after the scroller has been removed (e.g. - // if it is no longer composited). In these cases the best we can do is to - // return an unresolved time value. - if ((is_active_tree && !active_id_) || (!is_active_tree && !pending_id_)) + // If the timeline is not active return unresolved value by the spec. + // https://github.com/WICG/scroll-animations/issues/31 + // https://wicg.github.io/scroll-animations/#current-time-algorithm + if (!IsActive(scroll_tree, is_active_tree)) return base::nullopt; ElementId scroller_id = is_active_tree ? active_id_.value() : pending_id_.value(); - - // The scroller may not be in the ScrollTree if it is not currently scrollable - // (e.g. has overflow: visible). By the spec, return an unresolved time value. const ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(scroller_id); - if (!scroll_node) - return base::nullopt; gfx::ScrollOffset offset = scroll_tree.GetPixelSnappedScrollOffset(scroll_node->id); diff --git a/chromium/cc/animation/scroll_timeline.h b/chromium/cc/animation/scroll_timeline.h index 759d2615d32..152c1a642db 100644 --- a/chromium/cc/animation/scroll_timeline.h +++ b/chromium/cc/animation/scroll_timeline.h @@ -41,6 +41,11 @@ class CC_ANIMATION_EXPORT ScrollTimeline { // compositor. std::unique_ptr<ScrollTimeline> CreateImplInstance() const; + // ScrollTimeline is active if the scroll node exists in active or pending + // scroll tree. + virtual bool IsActive(const ScrollTree& scroll_tree, + bool is_active_tree) const; + // Calculate the current time of the ScrollTimeline. This is either a // base::TimeTicks value or base::nullopt if the current time is unresolved. // The internal calculations are performed using doubles and the result is diff --git a/chromium/cc/animation/scroll_timeline_unittest.cc b/chromium/cc/animation/scroll_timeline_unittest.cc index 490b9428466..0b62b8f4ec8 100644 --- a/chromium/cc/animation/scroll_timeline_unittest.cc +++ b/chromium/cc/animation/scroll_timeline_unittest.cc @@ -181,8 +181,8 @@ TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) { base::nullopt, base::nullopt, 100, KeyframeModel::FillMode::NONE); - // Now create an impl version of the ScrollTimeline. Initilly this should only - // have a pending scroller id, as the active tree may not yet have the + // Now create an impl version of the ScrollTimeline. Initially this should + // only have a pending scroller id, as the active tree may not yet have the // scroller in it (as in this case). std::unique_ptr<ScrollTimeline> impl_timeline = main_timeline.CreateImplInstance(); @@ -379,4 +379,41 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesFillMode) { time_range, fill_auto_timeline.CurrentTime(scroll_tree(), false)); } +TEST_F(ScrollTimelineTest, Activeness) { + // ScrollTimeline with zero scroller id is inactive. + ScrollTimeline inactive_timeline1(base::nullopt, ScrollTimeline::ScrollDown, + base::nullopt, base::nullopt, 100, + KeyframeModel::FillMode::NONE); + EXPECT_FALSE( + inactive_timeline1.IsActive(scroll_tree(), false /*is_active_tree*/)); + EXPECT_FALSE( + inactive_timeline1.IsActive(scroll_tree(), true /*is_active_tree*/)); + + // ScrollTimeline with a scroller that is not in the scroll tree is + // inactive. + ScrollTimeline inactive_timeline2(ElementId(2), ScrollTimeline::ScrollDown, + base::nullopt, base::nullopt, 100, + KeyframeModel::FillMode::NONE); + EXPECT_FALSE( + inactive_timeline2.IsActive(scroll_tree(), false /*is_active_tree*/)); + // Activate the scroll tree. + inactive_timeline2.PromoteScrollTimelinePendingToActive(); + EXPECT_FALSE( + inactive_timeline2.IsActive(scroll_tree(), true /*is_active_tree*/)); + + ScrollTimeline active_timeline(scroller_id(), ScrollTimeline::ScrollDown, + base::nullopt, base::nullopt, 100, + KeyframeModel::FillMode::NONE); + EXPECT_TRUE( + active_timeline.IsActive(scroll_tree(), false /*is_active_tree*/)); + EXPECT_FALSE( + active_timeline.IsActive(scroll_tree(), true /*is_active_tree*/)); + + // Activate the scroll tree. + active_timeline.PromoteScrollTimelinePendingToActive(); + EXPECT_TRUE( + active_timeline.IsActive(scroll_tree(), false /*is_active_tree*/)); + EXPECT_TRUE(active_timeline.IsActive(scroll_tree(), true /*is_active_tree*/)); +} + } // namespace cc diff --git a/chromium/cc/animation/single_keyframe_effect_animation.cc b/chromium/cc/animation/single_keyframe_effect_animation.cc index d102c3924b3..a467e5ee4e3 100644 --- a/chromium/cc/animation/single_keyframe_effect_animation.cc +++ b/chromium/cc/animation/single_keyframe_effect_animation.cc @@ -62,7 +62,7 @@ scoped_refptr<Animation> SingleKeyframeEffectAnimation::CreateImplInstance() } ElementId SingleKeyframeEffectAnimation::element_id() const { - return element_id_of_keyframe_effect(GetKeyframeEffect()->id()); + return GetKeyframeEffect()->element_id(); } void SingleKeyframeEffectAnimation::AttachElement(ElementId element_id) { diff --git a/chromium/cc/animation/timing_function.cc b/chromium/cc/animation/timing_function.cc index 6b6110d986a..1c80aeeb28d 100644 --- a/chromium/cc/animation/timing_function.cc +++ b/chromium/cc/animation/timing_function.cc @@ -85,7 +85,7 @@ TimingFunction::Type StepsTimingFunction::GetType() const { } double StepsTimingFunction::GetValue(double t) const { - return GetPreciseValue(t); + return GetPreciseValue(t, TimingFunction::LimitDirection::RIGHT); } std::unique_ptr<TimingFunction> StepsTimingFunction::Clone() const { @@ -96,9 +96,15 @@ double StepsTimingFunction::Velocity(double x) const { return 0; } -double StepsTimingFunction::GetPreciseValue(double t) const { +double StepsTimingFunction::GetPreciseValue(double t, + LimitDirection direction) const { const double steps = static_cast<double>(steps_); double current_step = std::floor((steps * t) + GetStepsStartOffset()); + // Adjust step if using a left limit at a discontinuous step boundary. + if (direction == LimitDirection::LEFT && + steps * t - std::floor(steps * t) == 0) { + current_step -= 1; + } if (t >= 0 && current_step < 0) current_step = 0; if (t <= 1 && current_step > steps) @@ -118,36 +124,4 @@ float StepsTimingFunction::GetStepsStartOffset() const { } } -std::unique_ptr<FramesTimingFunction> FramesTimingFunction::Create(int frames) { - return base::WrapUnique(new FramesTimingFunction(frames)); -} - -FramesTimingFunction::FramesTimingFunction(int frames) : frames_(frames) {} - -FramesTimingFunction::~FramesTimingFunction() = default; - -TimingFunction::Type FramesTimingFunction::GetType() const { - return Type::FRAMES; -} - -double FramesTimingFunction::GetValue(double t) const { - return GetPreciseValue(t); -} - -std::unique_ptr<TimingFunction> FramesTimingFunction::Clone() const { - return base::WrapUnique(new FramesTimingFunction(*this)); -} - -double FramesTimingFunction::Velocity(double x) const { - return 0; -} - -double FramesTimingFunction::GetPreciseValue(double t) const { - const double frames = static_cast<double>(frames_); - double output_progress = std::floor(frames * t) / (frames - 1); - if (t <= 1 && output_progress > 1) - output_progress = 1; - return output_progress; -} - } // namespace cc diff --git a/chromium/cc/animation/timing_function.h b/chromium/cc/animation/timing_function.h index 77969ac4188..4212bb28864 100644 --- a/chromium/cc/animation/timing_function.h +++ b/chromium/cc/animation/timing_function.h @@ -20,7 +20,10 @@ class CC_ANIMATION_EXPORT TimingFunction { TimingFunction& operator=(const TimingFunction&) = delete; // Note that LINEAR is a nullptr TimingFunction (for now). - enum class Type { LINEAR, CUBIC_BEZIER, STEPS, FRAMES }; + enum class Type { LINEAR, CUBIC_BEZIER, STEPS }; + + // Which limit to apply at a discontinuous boundary. + enum class LimitDirection { LEFT, RIGHT }; virtual Type GetType() const = 0; virtual double GetValue(double t) const = 0; @@ -87,7 +90,7 @@ class CC_ANIMATION_EXPORT StepsTimingFunction : public TimingFunction { int steps() const { return steps_; } StepPosition step_position() const { return step_position_; } - double GetPreciseValue(double t) const; + double GetPreciseValue(double t, LimitDirection limit_direction) const; private: StepsTimingFunction(int steps, StepPosition step_position); @@ -98,28 +101,6 @@ class CC_ANIMATION_EXPORT StepsTimingFunction : public TimingFunction { StepPosition step_position_; }; -class CC_ANIMATION_EXPORT FramesTimingFunction : public TimingFunction { - public: - static std::unique_ptr<FramesTimingFunction> Create(int frames); - ~FramesTimingFunction() override; - - FramesTimingFunction& operator=(const FramesTimingFunction&) = delete; - - // TimingFunction implementation. - Type GetType() const override; - double GetValue(double t) const override; - std::unique_ptr<TimingFunction> Clone() const override; - double Velocity(double time) const override; - - int frames() const { return frames_; } - double GetPreciseValue(double t) const; - - private: - explicit FramesTimingFunction(int frames); - - int frames_; -}; - } // namespace cc #endif // CC_ANIMATION_TIMING_FUNCTION_H_ diff --git a/chromium/cc/animation/worklet_animation.cc b/chromium/cc/animation/worklet_animation.cc index 09f4de569cb..a6d109fac1b 100644 --- a/chromium/cc/animation/worklet_animation.cc +++ b/chromium/cc/animation/worklet_animation.cc @@ -8,6 +8,7 @@ #include "cc/animation/animation_id_provider.h" #include "cc/animation/keyframe_effect.h" #include "cc/animation/scroll_timeline.h" +#include "cc/trees/animation_effect_timings.h" #include "cc/trees/animation_options.h" namespace cc { @@ -19,6 +20,7 @@ WorkletAnimation::WorkletAnimation( double playback_rate, std::unique_ptr<ScrollTimeline> scroll_timeline, std::unique_ptr<AnimationOptions> options, + std::unique_ptr<AnimationEffectTimings> effect_timings, bool is_controlling_instance) : WorkletAnimation(cc_animation_id, worklet_animation_id, @@ -26,6 +28,7 @@ WorkletAnimation::WorkletAnimation( playback_rate, std::move(scroll_timeline), std::move(options), + std::move(effect_timings), is_controlling_instance, nullptr) {} @@ -36,6 +39,7 @@ WorkletAnimation::WorkletAnimation( double playback_rate, std::unique_ptr<ScrollTimeline> scroll_timeline, std::unique_ptr<AnimationOptions> options, + std::unique_ptr<AnimationEffectTimings> effect_timings, bool is_controlling_instance, std::unique_ptr<KeyframeEffect> effect) : SingleKeyframeEffectAnimation(cc_animation_id, std::move(effect)), @@ -44,9 +48,11 @@ WorkletAnimation::WorkletAnimation( scroll_timeline_(std::move(scroll_timeline)), playback_rate_(playback_rate), options_(std::move(options)), + effect_timings_(std::move(effect_timings)), local_time_(base::nullopt), start_time_(base::nullopt), last_current_time_(base::nullopt), + has_pending_tree_lock_(false), state_(State::PENDING), is_impl_instance_(is_controlling_instance) {} @@ -57,10 +63,12 @@ scoped_refptr<WorkletAnimation> WorkletAnimation::Create( const std::string& name, double playback_rate, std::unique_ptr<ScrollTimeline> scroll_timeline, - std::unique_ptr<AnimationOptions> options) { + std::unique_ptr<AnimationOptions> options, + std::unique_ptr<AnimationEffectTimings> effect_timings) { return WrapRefCounted(new WorkletAnimation( AnimationIdProvider::NextAnimationId(), worklet_animation_id, name, - playback_rate, std::move(scroll_timeline), std::move(options), false)); + playback_rate, std::move(scroll_timeline), std::move(options), + std::move(effect_timings), false)); } scoped_refptr<Animation> WorkletAnimation::CreateImplInstance() const { @@ -68,9 +76,9 @@ scoped_refptr<Animation> WorkletAnimation::CreateImplInstance() const { if (scroll_timeline_) impl_timeline = scroll_timeline_->CreateImplInstance(); - return WrapRefCounted( - new WorkletAnimation(id(), worklet_animation_id_, name(), playback_rate_, - std::move(impl_timeline), CloneOptions(), true)); + return WrapRefCounted(new WorkletAnimation( + id(), worklet_animation_id_, name(), playback_rate_, + std::move(impl_timeline), CloneOptions(), CloneEffectTimings(), true)); } void WorkletAnimation::PushPropertiesTo(Animation* animation_impl) { @@ -103,37 +111,61 @@ void WorkletAnimation::UpdateInputState(MutatorInputState* input_state, base::TimeTicks monotonic_time, const ScrollTree& scroll_tree, bool is_active_tree) { + bool is_timeline_active = IsTimelineActive(scroll_tree, is_active_tree); // Record the monotonic time to be the start time first time state is // generated. This time is used as the origin for computing the current time. // The start time of scroll-linked animations is always initialized to zero. // See: https://github.com/w3c/csswg-drafts/issues/2075 - if (!start_time_.has_value()) + // To stay consistent with blink::WorkletAnimation, record start time only + // when the timeline becomes active. + if (!start_time_.has_value() && is_timeline_active) start_time_ = scroll_timeline_ ? base::TimeTicks() : monotonic_time; + if (is_active_tree && has_pending_tree_lock_) + return; + // Skip running worklet animations with unchanged input time and reuse // their value from the previous animation call. if (!NeedsUpdate(monotonic_time, scroll_tree, is_active_tree)) return; - double current_time = + DCHECK(is_timeline_active || state_ == State::REMOVED); + + base::Optional<base::TimeDelta> current_time = CurrentTime(monotonic_time, scroll_tree, is_active_tree); - // TODO(yigu): If current_time becomes newly unresolved and last_current_time_ - // is resolved, we apply the last current time to the animation if the scroll - // timeline becomes newly inactive. See https://crbug.com/906050. + + // When the timeline is inactive (only the case with scroll timelines), the + // animation holds its last current time and last current output. This + // means we don't need to produce any new input state. See also: + // https://drafts.csswg.org/web-animations/#responding-to-a-newly-inactive-timeline + if (!is_timeline_active) + current_time = last_current_time_; + + if (!current_time) + return; last_current_time_ = current_time; + // Prevent active tree mutations from queuing up until pending tree is + // activated to preserve flow of time for scroll timelines. + has_pending_tree_lock_ = !is_active_tree && scroll_timeline_; + switch (state_) { case State::PENDING: // TODO(yigu): cc side WorkletAnimation is only capable of handling single // keyframe effect at the moment. We should pass in the number of effects // once Worklet Group Effect is fully implemented in cc. // https://crbug.com/767043. - input_state->Add({worklet_animation_id(), name(), current_time, - CloneOptions(), 1 /* num_effects */}); + input_state->Add({worklet_animation_id(), name(), + current_time->InMillisecondsF(), CloneOptions(), + CloneEffectTimings()}); state_ = State::RUNNING; break; case State::RUNNING: - input_state->Update({worklet_animation_id(), current_time}); + // TODO(jortaylo): EffectTimings need to be sent to the worklet during + // updates, otherwise the timing info will become outdated. + // https://crbug.com/915344. + input_state->Update( + {worklet_animation_id(), current_time->InMillisecondsF()}); break; case State::REMOVED: input_state->Remove(worklet_animation_id()); @@ -160,8 +192,7 @@ void WorkletAnimation::SetPlaybackRate(double playback_rate) { if (start_time_ && last_current_time_) { // Update startTime in order to maintain previous currentTime and, // as a result, prevent the animation from jumping. - base::TimeDelta current_time = - base::TimeDelta::FromMillisecondsD(last_current_time_.value()); + base::TimeDelta current_time = last_current_time_.value(); start_time_ = start_time_.value() + current_time / playback_rate_ - current_time / playback_rate; } @@ -175,41 +206,47 @@ void WorkletAnimation::UpdatePlaybackRate(double playback_rate) { SetNeedsPushProperties(); } -double WorkletAnimation::CurrentTime(base::TimeTicks monotonic_time, - const ScrollTree& scroll_tree, - bool is_active_tree) { +base::Optional<base::TimeDelta> WorkletAnimation::CurrentTime( + base::TimeTicks monotonic_time, + const ScrollTree& scroll_tree, + bool is_active_tree) { + DCHECK(IsTimelineActive(scroll_tree, is_active_tree)); base::TimeTicks timeline_time; if (scroll_timeline_) { base::Optional<base::TimeTicks> scroll_monotonic_time = scroll_timeline_->CurrentTime(scroll_tree, is_active_tree); if (!scroll_monotonic_time) - return std::numeric_limits<double>::quiet_NaN(); + return base::nullopt; timeline_time = scroll_monotonic_time.value(); } else { timeline_time = monotonic_time; } - return (timeline_time - start_time_.value()).InMillisecondsF() * - playback_rate_; + return (timeline_time - start_time_.value()) * playback_rate_; } bool WorkletAnimation::NeedsUpdate(base::TimeTicks monotonic_time, const ScrollTree& scroll_tree, bool is_active_tree) { - // If we don't have a start time it means that an update was never sent to - // the worklet therefore we need one. - if (!start_time_.has_value()) - return true; - - DCHECK(state_ == State::PENDING || last_current_time_.has_value()); if (state_ == State::REMOVED) return true; - double current_time = + // When the timeline is inactive we apply the last current time to the + // animation. + if (!IsTimelineActive(scroll_tree, is_active_tree)) + return false; + + base::Optional<base::TimeDelta> current_time = CurrentTime(monotonic_time, scroll_tree, is_active_tree); bool needs_update = last_current_time_ != current_time; return needs_update; } +bool WorkletAnimation::IsTimelineActive(const ScrollTree& scroll_tree, + bool is_active_tree) const { + return !scroll_timeline_ || + scroll_timeline_->IsActive(scroll_tree, is_active_tree); +} + void WorkletAnimation::UpdateScrollTimeline( base::Optional<ElementId> scroller_id, base::Optional<double> start_scroll_offset, @@ -225,6 +262,7 @@ void WorkletAnimation::UpdateScrollTimeline( void WorkletAnimation::PromoteScrollTimelinePendingToActive() { if (scroll_timeline_) scroll_timeline_->PromoteScrollTimelinePendingToActive(); + ReleasePendingTreeLock(); } void WorkletAnimation::RemoveKeyframeModel(int keyframe_model_id) { diff --git a/chromium/cc/animation/worklet_animation.h b/chromium/cc/animation/worklet_animation.h index d558e1b9a8d..508c0be4cf4 100644 --- a/chromium/cc/animation/worklet_animation.h +++ b/chromium/cc/animation/worklet_animation.h @@ -20,6 +20,7 @@ FORWARD_DECLARE_TEST(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe); } // namespace class AnimationOptions; +class AnimationEffectTimings; class ScrollTimeline; // A WorkletAnimation is an animation that allows its animation @@ -42,13 +43,15 @@ class CC_ANIMATION_EXPORT WorkletAnimation final double playback_rate, std::unique_ptr<ScrollTimeline> scroll_timeline, std::unique_ptr<AnimationOptions> options, + std::unique_ptr<AnimationEffectTimings> effect_timings, bool is_controlling_instance); static scoped_refptr<WorkletAnimation> Create( WorkletAnimationId worklet_animation_id, const std::string& name, double playback_rate, std::unique_ptr<ScrollTimeline> scroll_timeline, - std::unique_ptr<AnimationOptions> options); + std::unique_ptr<AnimationOptions> options, + std::unique_ptr<AnimationEffectTimings> effect_timings); scoped_refptr<Animation> CreateImplInstance() const override; WorkletAnimationId worklet_animation_id() { return worklet_animation_id_; } @@ -87,6 +90,8 @@ class CC_ANIMATION_EXPORT WorkletAnimation final void RemoveKeyframeModel(int keyframe_model_id) override; + void ReleasePendingTreeLock() { has_pending_tree_lock_ = false; } + private: FRIEND_TEST_ALL_PREFIXES(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe); @@ -96,16 +101,19 @@ class CC_ANIMATION_EXPORT WorkletAnimation final double playback_rate, std::unique_ptr<ScrollTimeline> scroll_timeline, std::unique_ptr<AnimationOptions> options, + std::unique_ptr<AnimationEffectTimings> effect_timings, bool is_controlling_instance, std::unique_ptr<KeyframeEffect> effect); ~WorkletAnimation() override; // Returns the current time to be passed into the underlying AnimationWorklet. - // The current time is based on the timeline associated with the animation. - double CurrentTime(base::TimeTicks monotonic_time, - const ScrollTree& scroll_tree, - bool is_active_tree); + // The current time is based on the timeline associated with the animation and + // in case of scroll timeline it may be nullopt when the associated scrolling + // node is not available in the particular ScrollTree. + base::Optional<base::TimeDelta> CurrentTime(base::TimeTicks monotonic_time, + const ScrollTree& scroll_tree, + bool is_active_tree); // Returns true if the worklet animation needs to be updated which happens iff // its current time is going to be different from last time given these input. @@ -117,10 +125,17 @@ class CC_ANIMATION_EXPORT WorkletAnimation final return options_ ? options_->Clone() : nullptr; } + std::unique_ptr<AnimationEffectTimings> CloneEffectTimings() const { + return effect_timings_ ? effect_timings_->Clone() : nullptr; + } + // Updates the playback rate of the Impl thread instance. // Called by the UI thread WorletAnimation instance during commit. void SetPlaybackRate(double playback_rate); + bool IsTimelineActive(const ScrollTree& scroll_tree, + bool is_active_tree) const; + WorkletAnimationId worklet_animation_id_; std::string name_; @@ -142,6 +157,7 @@ class CC_ANIMATION_EXPORT WorkletAnimation final double playback_rate_; std::unique_ptr<AnimationOptions> options_; + std::unique_ptr<AnimationEffectTimings> effect_timings_; // Local time is used as an input to the keyframe effect of this animation. // The value comes from the user script that runs inside the animation worklet @@ -149,9 +165,16 @@ class CC_ANIMATION_EXPORT WorkletAnimation final base::Optional<base::TimeDelta> local_time_; base::Optional<base::TimeTicks> start_time_; - // Last current time used for updatig. We use this to skip updating if current - // time has not changed since last update. - base::Optional<double> last_current_time_; + + // Last current time used for updating. We use this to skip updating if + // current time has not changed since last update. + base::Optional<base::TimeDelta> last_current_time_; + + // To ensure that 'time' progresses forward for scroll animations, we guard + // against allowing active tree mutations while the pending tree has a + // lock in the worklet. The lock is established when updating the input state + // for the pending tree and release on pending tree activation. + bool has_pending_tree_lock_; State state_; diff --git a/chromium/cc/animation/worklet_animation_unittest.cc b/chromium/cc/animation/worklet_animation_unittest.cc index a1801ac3674..4d0e61ea073 100644 --- a/chromium/cc/animation/worklet_animation_unittest.cc +++ b/chromium/cc/animation/worklet_animation_unittest.cc @@ -12,10 +12,12 @@ #include "cc/trees/property_tree.h" #include "testing/gmock/include/gmock/gmock.h" +using ::testing::_; +using ::testing::Invoke; using ::testing::Mock; using ::testing::NiceMock; using ::testing::Return; -using ::testing::_; +using ::testing::Unused; namespace cc { @@ -33,11 +35,11 @@ class WorkletAnimationTest : public AnimationTimelinesTest { ~WorkletAnimationTest() override = default; void AttachWorkletAnimation() { - client_.RegisterElement(element_id_, ElementListType::ACTIVE); + client_.RegisterElementId(element_id_, ElementListType::ACTIVE); worklet_animation_ = WrapRefCounted( new WorkletAnimation(1, worklet_animation_id_, "test_name", 1, nullptr, - nullptr, true /* controlling instance*/)); + nullptr, nullptr, true /* controlling instance*/)); worklet_animation_->AttachElement(element_id_); host_->AddAnimationTimeline(timeline_); timeline_->AttachAnimation(worklet_animation_); @@ -58,6 +60,7 @@ class MockScrollTimeline : public ScrollTimeline { KeyframeModel::FillMode::NONE) {} MOCK_CONST_METHOD2(CurrentTime, base::Optional<base::TimeTicks>(const ScrollTree&, bool)); + MOCK_CONST_METHOD2(IsActive, bool(const ScrollTree&, bool)); }; TEST_F(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe) { @@ -67,7 +70,7 @@ TEST_F(WorkletAnimationTest, NonImplInstanceDoesNotTickKeyframe) { scoped_refptr<WorkletAnimation> worklet_animation = WrapRefCounted(new WorkletAnimation( - 1, worklet_animation_id_, "test_name", 1, nullptr, nullptr, + 1, worklet_animation_id_, "test_name", 1, nullptr, nullptr, nullptr, false /* not impl instance*/, std::move(effect))); EXPECT_CALL(*mock_effect, Tick(_)).Times(0); @@ -111,12 +114,13 @@ TEST_F(WorkletAnimationTest, LocalTimeIsUsedWhenTicking) { TEST_F(WorkletAnimationTest, CurrentTimeCorrectlyUsesScrollTimeline) { auto scroll_timeline = std::make_unique<MockScrollTimeline>(); + EXPECT_CALL(*scroll_timeline, IsActive(_, _)).WillRepeatedly(Return(true)); EXPECT_CALL(*scroll_timeline, CurrentTime(_, _)) .WillRepeatedly(Return( (base::TimeTicks() + base::TimeDelta::FromMilliseconds(1234)))); scoped_refptr<WorkletAnimation> worklet_animation = WorkletAnimation::Create(worklet_animation_id_, "test_name", 1, - std::move(scroll_timeline), nullptr); + std::move(scroll_timeline), nullptr, nullptr); ScrollTree scroll_tree; std::unique_ptr<MutatorInputState> state = @@ -131,7 +135,7 @@ TEST_F(WorkletAnimationTest, CurrentTimeCorrectlyUsesScrollTimeline) { TEST_F(WorkletAnimationTest, CurrentTimeFromRegularTimelineIsOffsetByStartTime) { scoped_refptr<WorkletAnimation> worklet_animation = WorkletAnimation::Create( - worklet_animation_id_, "test_name", 1, nullptr, nullptr); + worklet_animation_id_, "test_name", 1, nullptr, nullptr, nullptr); base::TimeTicks first_ticks = base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111); @@ -169,7 +173,7 @@ TEST_F(WorkletAnimationTest, DocumentTimelineSetPlaybackRate) { const double playback_rate_half = 0.5; scoped_refptr<WorkletAnimation> worklet_animation = WorkletAnimation::Create(worklet_animation_id_, "test_name", - playback_rate_double, nullptr, nullptr); + playback_rate_double, nullptr, nullptr, nullptr); base::TimeTicks first_ticks = base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111); @@ -219,27 +223,24 @@ TEST_F(WorkletAnimationTest, ScrollTimelineSetPlaybackRate) { const double playback_rate_half = 0.5; auto scroll_timeline = std::make_unique<MockScrollTimeline>(); - EXPECT_CALL(*scroll_timeline, CurrentTime(_, _)) - // First UpdateInputState call. - .WillOnce( - Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(50))) - // First UpdateInputState call. - .WillOnce( - Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(50))) - // Second UpdateInputState call. - .WillRepeatedly( - Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(100))); - scoped_refptr<WorkletAnimation> worklet_animation = WorkletAnimation::Create( worklet_animation_id_, "test_name", playback_rate_double, - std::move(scroll_timeline), nullptr); + std::move(scroll_timeline), nullptr, nullptr); + const MockScrollTimeline* mock_timeline = + static_cast<const MockScrollTimeline*>( + worklet_animation->scroll_timeline()); ScrollTree scroll_tree; std::unique_ptr<MutatorInputState> state = std::make_unique<MutatorInputState>(); // Start the animation. + EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(*mock_timeline, CurrentTime(_, _)) + .WillRepeatedly( + Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(50))); worklet_animation->UpdateInputState(state.get(), base::TimeTicks(), scroll_tree, true); + Mock::VerifyAndClearExpectations(&mock_timeline); std::unique_ptr<AnimationWorkletInput> input = state->TakeWorkletState(worklet_animation_id_.worklet_id); @@ -253,8 +254,13 @@ TEST_F(WorkletAnimationTest, ScrollTimelineSetPlaybackRate) { state.reset(new MutatorInputState()); // Continue playing the animation. + EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(*mock_timeline, CurrentTime(_, _)) + .WillRepeatedly( + Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(100))); worklet_animation->UpdateInputState(state.get(), base::TimeTicks(), scroll_tree, true); + Mock::VerifyAndClearExpectations(&mock_timeline); input = state->TakeWorkletState(worklet_animation_id_.worklet_id); // Verify that the current time is updated half as fast as the timeline time. @@ -262,6 +268,59 @@ TEST_F(WorkletAnimationTest, ScrollTimelineSetPlaybackRate) { input->updated_animations[0].current_time); } +// Verifies correcteness of worklet animation current time when inactive +// timeline becomes active and then inactive again. +TEST_F(WorkletAnimationTest, InactiveScrollTimeline) { + auto scroll_timeline = std::make_unique<MockScrollTimeline>(); + + scoped_refptr<WorkletAnimation> worklet_animation = WorkletAnimation::Create( + worklet_animation_id_, "test_name", /*playback_rate*/ 1, + std::move(scroll_timeline), nullptr, nullptr); + + const MockScrollTimeline* mock_timeline = + static_cast<const MockScrollTimeline*>( + worklet_animation->scroll_timeline()); + ScrollTree scroll_tree; + std::unique_ptr<MutatorInputState> state = + std::make_unique<MutatorInputState>(); + + // Start the animation with inactive timeline. + EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(false)); + worklet_animation->UpdateInputState(state.get(), base::TimeTicks(), + scroll_tree, true); + Mock::VerifyAndClearExpectations(&mock_timeline); + std::unique_ptr<AnimationWorkletInput> input = + state->TakeWorkletState(worklet_animation_id_.worklet_id); + EXPECT_FALSE(input); + state.reset(new MutatorInputState()); + + // Now the timeline is active. + EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(*mock_timeline, CurrentTime(_, _)) + .WillRepeatedly( + Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(100))); + worklet_animation->UpdateInputState(state.get(), base::TimeTicks(), + scroll_tree, true); + Mock::VerifyAndClearExpectations(&mock_timeline); + input = state->TakeWorkletState(worklet_animation_id_.worklet_id); + // Verify that the current time is updated when the timeline becomes newly + // active. + EXPECT_EQ(100, input->added_and_updated_animations[0].current_time); + state.reset(new MutatorInputState()); + + // Now the timeline is inactive. + EXPECT_CALL(*mock_timeline, IsActive(_, _)).WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_timeline, CurrentTime(_, _)) + .WillRepeatedly( + Return(base::TimeTicks() + base::TimeDelta::FromMilliseconds(200))); + worklet_animation->UpdateInputState(state.get(), base::TimeTicks(), + scroll_tree, true); + Mock::VerifyAndClearExpectations(&mock_timeline); + input = state->TakeWorkletState(worklet_animation_id_.worklet_id); + // No update of the input state when the timeline is inactive. + EXPECT_FALSE(input); +} + // This test verifies that worklet animation state is properly updated. TEST_F(WorkletAnimationTest, UpdateInputStateProducesCorrectState) { AttachWorkletAnimation(); @@ -369,6 +428,63 @@ TEST_F(WorkletAnimationTest, SkipUnchangedAnimations) { EXPECT_EQ(input->removed_animations.size(), 1u); } +base::Optional<base::TimeTicks> FakeIncreasingScrollTimelineTime(Unused, + Unused) { + static base::TimeTicks current_time; + current_time += base::TimeDelta::FromSecondsD(0.1); + return current_time; +} + +// This test verifies that worklet animation gets skipped properly if a pending +// mutation cycle is holding a lock on the worklet. +TEST_F(WorkletAnimationTest, SkipLockedAnimations) { + auto scroll_timeline = std::make_unique<MockScrollTimeline>(); + EXPECT_CALL(*scroll_timeline, IsActive(_, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(*scroll_timeline, CurrentTime(_, _)) + .WillRepeatedly(Invoke(FakeIncreasingScrollTimelineTime)); + scoped_refptr<WorkletAnimation> worklet_animation = + WorkletAnimation::Create(worklet_animation_id_, "test_name", 1, + std::move(scroll_timeline), nullptr, nullptr); + + ScrollTree scroll_tree; + std::unique_ptr<MutatorInputState> state = + std::make_unique<MutatorInputState>(); + + base::TimeTicks time; + worklet_animation->UpdateInputState(state.get(), time, scroll_tree, true); + std::unique_ptr<AnimationWorkletInput> input = + state->TakeWorkletState(worklet_animation_id_.worklet_id); + EXPECT_EQ(input->added_and_updated_animations.size(), 1u); + EXPECT_EQ(input->updated_animations.size(), 0u); + + state.reset(new MutatorInputState()); + // Different scroll time causes the input state to be updated. + worklet_animation->UpdateInputState(state.get(), time, scroll_tree, true); + input = state->TakeWorkletState(worklet_animation_id_.worklet_id); + EXPECT_EQ(input->updated_animations.size(), 1u); + + state.reset(new MutatorInputState()); + // Different scroll time causes the input state to be updated. Pending + // mutation will grab a lock. + worklet_animation->UpdateInputState(state.get(), time, scroll_tree, false); + input = state->TakeWorkletState(worklet_animation_id_.worklet_id); + EXPECT_EQ(input->updated_animations.size(), 1u); + + state.reset(new MutatorInputState()); + // Pending lock has not been released. + worklet_animation->UpdateInputState(state.get(), time, scroll_tree, true); + input = state->TakeWorkletState(worklet_animation_id_.worklet_id); + EXPECT_FALSE(input); + + worklet_animation->ReleasePendingTreeLock(); + + state.reset(new MutatorInputState()); + // Pending lock has been released. + worklet_animation->UpdateInputState(state.get(), time, scroll_tree, true); + input = state->TakeWorkletState(worklet_animation_id_.worklet_id); + EXPECT_EQ(input->updated_animations.size(), 1u); +} + } // namespace } // namespace cc diff --git a/chromium/cc/base/rtree.h b/chromium/cc/base/rtree.h index 24909814298..83504eac64a 100644 --- a/chromium/cc/base/rtree.h +++ b/chromium/cc/base/rtree.h @@ -230,60 +230,54 @@ auto RTree<T>::BuildRecursive(std::vector<Branch<T>>* branches, int level) remainder = kMinChildren - 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 = kMaxChildren; - if (remainder != 0) { - // if need be, omit some nodes to make up for remainder - if (remainder <= kMaxChildren - kMinChildren) { - increment_by -= remainder; - remainder = 0; - } else { - increment_by = kMinChildren; - remainder -= kMaxChildren - kMinChildren; - } + while (current_branch < branches->size()) { + int increment_by = kMaxChildren; + if (remainder != 0) { + // if need be, omit some nodes to make up for remainder + if (remainder <= kMaxChildren - kMinChildren) { + increment_by -= remainder; + remainder = 0; + } else { + increment_by = kMinChildren; + remainder -= kMaxChildren - kMinChildren; } - Node<T>* node = AllocateNodeAtLevel(level); - node->num_children = 1; - node->children[0] = (*branches)[current_branch]; - - Branch<T> branch; - branch.bounds = (*branches)[current_branch].bounds; - branch.subtree = node; + } + Node<T>* node = AllocateNodeAtLevel(level); + node->num_children = 1; + node->children[0] = (*branches)[current_branch]; + + Branch<T> branch; + branch.bounds = (*branches)[current_branch].bounds; + branch.subtree = node; + ++current_branch; + int x = branch.bounds.x(); + int y = branch.bounds.y(); + int right = branch.bounds.right(); + int bottom = branch.bounds.bottom(); + for (int k = 1; k < increment_by && current_branch < branches->size(); + ++k) { + // We use a custom union instead of gfx::Rect::Union here, since this + // bypasses some empty checks and extra setters, which improves + // performance. + auto& bounds = (*branches)[current_branch].bounds; + x = std::min(x, bounds.x()); + y = std::min(y, bounds.y()); + right = std::max(right, bounds.right()); + bottom = std::max(bottom, bounds.bottom()); + + node->children[k] = (*branches)[current_branch]; + ++node->num_children; ++current_branch; - int x = branch.bounds.x(); - int y = branch.bounds.y(); - int right = branch.bounds.right(); - int bottom = branch.bounds.bottom(); - for (int k = 1; k < increment_by && current_branch < branches->size(); - ++k) { - // We use a custom union instead of gfx::Rect::Union here, since this - // bypasses some empty checks and extra setters, which improves - // performance. - auto& bounds = (*branches)[current_branch].bounds; - x = std::min(x, bounds.x()); - y = std::min(y, bounds.y()); - right = std::max(right, bounds.right()); - bottom = std::max(bottom, bounds.bottom()); - - node->children[k] = (*branches)[current_branch]; - ++node->num_children; - ++current_branch; - } - branch.bounds.SetRect(x, y, base::ClampSub(right, x), - base::ClampSub(bottom, y)); - - DCHECK_LT(new_branch_index, current_branch); - (*branches)[new_branch_index] = std::move(branch); - ++new_branch_index; } + branch.bounds.SetRect(x, y, base::ClampSub(right, x), + base::ClampSub(bottom, y)); + + DCHECK_LT(new_branch_index, current_branch); + (*branches)[new_branch_index] = std::move(branch); + ++new_branch_index; } branches->resize(new_branch_index); return BuildRecursive(branches, level + 1); diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc index 6f2da14d012..a1f8b53f202 100644 --- a/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc +++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark_impl.cc @@ -65,8 +65,8 @@ void RunBenchmark(RasterSource* raster_source, image_settings->images_to_skip = {}; image_settings->image_to_current_frame_index = {}; - PlaybackImageProvider image_provider(image_decode_cache, - std::move(image_settings)); + PlaybackImageProvider image_provider( + image_decode_cache, gfx::ColorSpace(), std::move(image_settings)); RasterSource::PlaybackSettings settings; settings.image_provider = &image_provider; diff --git a/chromium/cc/debug/layer_tree_debug_state.cc b/chromium/cc/debug/layer_tree_debug_state.cc index 6b51ff0b6f5..8c154cc8f55 100644 --- a/chromium/cc/debug/layer_tree_debug_state.cc +++ b/chromium/cc/debug/layer_tree_debug_state.cc @@ -12,6 +12,7 @@ namespace cc { LayerTreeDebugState::LayerTreeDebugState() : show_fps_counter(false), show_debug_borders(false), + show_layout_shift_regions(false), show_paint_rects(false), show_property_changed_rects(false), show_surface_damage_rects(false), @@ -49,7 +50,7 @@ bool LayerTreeDebugState::ShowHudRects() const { show_surface_damage_rects || show_screen_space_rects || show_touch_event_handler_rects || show_wheel_event_handler_rects || show_scroll_event_handler_rects || show_non_fast_scrollable_rects || - show_layer_animation_bounds_rects; + show_layer_animation_bounds_rects || show_layout_shift_regions; } bool LayerTreeDebugState::ShowMemoryStats() const { @@ -61,6 +62,7 @@ bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a, return ( a.show_fps_counter == b.show_fps_counter && a.show_debug_borders == b.show_debug_borders && + a.show_layout_shift_regions == b.show_layout_shift_regions && 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 && @@ -85,6 +87,7 @@ LayerTreeDebugState LayerTreeDebugState::Unite(const LayerTreeDebugState& a, r.show_fps_counter |= b.show_fps_counter; r.show_debug_borders |= b.show_debug_borders; + r.show_layout_shift_regions |= b.show_layout_shift_regions; r.show_paint_rects |= b.show_paint_rects; r.show_property_changed_rects |= b.show_property_changed_rects; r.show_surface_damage_rects |= b.show_surface_damage_rects; diff --git a/chromium/cc/debug/layer_tree_debug_state.h b/chromium/cc/debug/layer_tree_debug_state.h index c7438b6fe48..50dd2308edb 100644 --- a/chromium/cc/debug/layer_tree_debug_state.h +++ b/chromium/cc/debug/layer_tree_debug_state.h @@ -32,6 +32,7 @@ class CC_DEBUG_EXPORT LayerTreeDebugState { bool show_fps_counter; DebugBorderTypes show_debug_borders; + bool show_layout_shift_regions; bool show_paint_rects; bool show_property_changed_rects; bool show_surface_damage_rects; diff --git a/chromium/cc/input/event_listener_properties.h b/chromium/cc/input/event_listener_properties.h index a66ee2e6c65..f8891fe17e5 100644 --- a/chromium/cc/input/event_listener_properties.h +++ b/chromium/cc/input/event_listener_properties.h @@ -8,8 +8,8 @@ namespace cc { enum class EventListenerClass { - // This includes the pointerrawmove events which are non-rAF-aligned. - kPointerRawMove, + // This includes the pointerrawupdate events which are non-rAF-aligned. + kPointerRawUpdate, // This value includes "touchstart", "touchmove", and "pointer" events. kTouchStartOrMove, // This value includes "wheel" and "mousewheel" events. diff --git a/chromium/cc/input/input_handler.cc b/chromium/cc/input/input_handler.cc index 7105340cbbe..60e08fc8f96 100644 --- a/chromium/cc/input/input_handler.cc +++ b/chromium/cc/input/input_handler.cc @@ -10,6 +10,8 @@ InputHandlerScrollResult::InputHandlerScrollResult() : did_scroll(false), did_overscroll_root(false) { } -InputHandlerPointerResult::InputHandlerPointerResult() : type(kUnhandled) {} +InputHandlerPointerResult::InputHandlerPointerResult() + : type(kUnhandled), + scroll_units(ui::input_types::ScrollGranularity::kScrollByPrecisePixel) {} } // namespace cc diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h index 6b39c27ef56..0c41e257c7d 100644 --- a/chromium/cc/input/input_handler.h +++ b/chromium/cc/input/input_handler.h @@ -17,6 +17,7 @@ #include "cc/input/touch_action.h" #include "cc/trees/element_id.h" #include "cc/trees/swap_promise_monitor.h" +#include "ui/events/types/scroll_types.h" namespace gfx { class Point; @@ -41,6 +42,9 @@ struct CC_EXPORT InputHandlerPointerResult { // the pointer event. PointerResultType type; + // Tells what scroll_units should be used. + ui::input_types::ScrollGranularity scroll_units; + // If the input handler processed the event as a scrollbar scroll, it will // return a gfx::ScrollOffset that produces the necessary scroll. However, // it is still the client's responsibility to generate the gesture scrolls @@ -48,9 +52,6 @@ struct CC_EXPORT InputHandlerPointerResult { // pointer event (due to the latency attribution that happens at the // InputHandlerProxy level). gfx::ScrollOffset scroll_offset; - - // TODO(arakeri): Extend this structure to contain scroll_units and - // element_id. For now, assume kPrecisePixels and root layer scroll. }; struct CC_EXPORT InputHandlerScrollResult { @@ -188,7 +189,8 @@ class CC_EXPORT InputHandler { // ScrollBegin() returned SCROLL_STARTED. virtual InputHandlerScrollResult ScrollBy(ScrollState* scroll_state) = 0; - virtual void MouseMoveAt(const gfx::Point& mouse_position) = 0; + virtual InputHandlerPointerResult MouseMoveAt( + const gfx::Point& mouse_position) = 0; virtual InputHandlerPointerResult MouseDown( const gfx::PointF& mouse_position) = 0; virtual InputHandlerPointerResult MouseUp( @@ -204,9 +206,10 @@ class CC_EXPORT InputHandler { virtual void RequestUpdateForSynchronousInputHandler() = 0; // Called when the root scroll offset has been changed in the synchronous - // input handler by the application (outside of input event handling). + // input handler by the application (outside of input event handling). Offset + // is expected in "content/page coordinates". virtual void SetSynchronousInputHandlerRootScrollOffset( - const gfx::ScrollOffset& root_offset) = 0; + const gfx::ScrollOffset& root_content_offset) = 0; virtual void PinchGestureBegin() = 0; virtual void PinchGestureUpdate(float magnify_delta, diff --git a/chromium/cc/input/scroll_snap_data.cc b/chromium/cc/input/scroll_snap_data.cc index b09ded1e84f..2121d1ca658 100644 --- a/chromium/cc/input/scroll_snap_data.cc +++ b/chromium/cc/input/scroll_snap_data.cc @@ -112,6 +112,9 @@ void SnapContainerData::AddSnapAreaData(SnapAreaData snap_area_data) { bool SnapContainerData::FindSnapPosition( const SnapSelectionStrategy& strategy, gfx::ScrollOffset* snap_position) const { + if (scroll_snap_type_.is_none) + return false; + gfx::ScrollOffset base_position = strategy.base_position(); SnapAxis axis = scroll_snap_type_.axis; bool should_snap_on_x = strategy.ShouldSnapOnX() && diff --git a/chromium/cc/input/scroll_snap_data.h b/chromium/cc/input/scroll_snap_data.h index 9938c0b7486..f68d90320c9 100644 --- a/chromium/cc/input/scroll_snap_data.h +++ b/chromium/cc/input/scroll_snap_data.h @@ -154,11 +154,15 @@ struct SnapAreaData { typedef std::vector<SnapAreaData> SnapAreaList; -// Snap container is a scroll container that has non-'none' value for -// scroll-snap-type. It can be snapped to one of its snap areas when a scroll -// happens. +// Snap container is a scroll container that at least one snap area assigned to +// it. If the snap-type is not 'none', then it can be snapped to one of its +// snap areas when a scroll happens. // This data structure describes the data needed for SnapCoordinator to perform // snapping in the snap container. +// +// Note that the snap area data should only be used when snap-type is not 'none' +// There is not guarantee that this information is up-to-date otherwise. In +// fact, we skip updating these info as an optiomization. class CC_EXPORT SnapContainerData { public: SnapContainerData(); diff --git a/chromium/cc/input/scrollbar.h b/chromium/cc/input/scrollbar.h index bd785ff779b..ec23fef5f0d 100644 --- a/chromium/cc/input/scrollbar.h +++ b/chromium/cc/input/scrollbar.h @@ -11,6 +11,7 @@ #include "ui/gfx/geometry/rect.h" static const int kPixelsPerLineStep = 40; +static const float kMinFractionToStepWhenPaging = 0.875f; namespace cc { @@ -23,7 +24,9 @@ enum ScrollbarPart { TICKMARKS, BACK_BUTTON, FORWARD_BUTTON, - NO_PART + BACK_TRACK, + FORWARD_TRACK, + NO_PART, }; class Scrollbar { diff --git a/chromium/cc/input/scrollbar_controller.cc b/chromium/cc/input/scrollbar_controller.cc index 403d3ceaaf8..d29a2574cc6 100644 --- a/chromium/cc/input/scrollbar_controller.cc +++ b/chromium/cc/input/scrollbar_controller.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "cc/base/math_util.h" #include "cc/input/scrollbar.h" #include "cc/input/scrollbar_controller.h" #include "cc/trees/layer_tree_impl.h" @@ -14,7 +15,10 @@ namespace cc { ScrollbarController::ScrollbarController( LayerTreeHostImpl* layer_tree_host_impl) : layer_tree_host_impl_(layer_tree_host_impl), - scrollbar_scroll_is_active_(false) {} + scrollbar_scroll_is_active_(false), + thumb_drag_in_progress_(false), + currently_captured_scrollbar_(nullptr), + previous_pointer_position_(gfx::PointF(0, 0)) {} // Performs hit test and prepares scroll deltas that will be used by GSB and // GSU. @@ -22,12 +26,115 @@ InputHandlerPointerResult ScrollbarController::HandleMouseDown( const gfx::PointF position_in_widget) { InputHandlerPointerResult scroll_result; LayerImpl* layer_impl = GetLayerHitByPoint(position_in_widget); - if (layer_impl && layer_impl->is_scrollbar()) { - scrollbar_scroll_is_active_ = true; - scroll_result.type = PointerResultType::kScrollbarScroll; - scroll_result.scroll_offset = - GetScrollStateBasedOnHitTest(layer_impl, position_in_widget); + + // If a non-custom scrollbar layer was not found, we return early as there is + // no point in setting additional state in the ScrollbarController. + if (!(layer_impl && layer_impl->ToScrollbarLayer())) + return scroll_result; + + currently_captured_scrollbar_ = layer_impl->ToScrollbarLayer(); + scroll_result.type = PointerResultType::kScrollbarScroll; + layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); + scroll_result.scroll_offset = + GetScrollDeltaFromPointerDown(position_in_widget); + previous_pointer_position_ = position_in_widget; + scrollbar_scroll_is_active_ = true; + if (thumb_drag_in_progress_) { + scroll_result.scroll_units = + ui::input_types::ScrollGranularity::kScrollByPrecisePixel; + } else { + // TODO(arakeri): This needs to be updated to kLine once cc implements + // handling it. crbug.com/959441 + scroll_result.scroll_units = + ui::input_types::ScrollGranularity::kScrollByPixel; } + + return scroll_result; +} + +// Performs hit test and prepares scroll deltas that will be used by GSU. +InputHandlerPointerResult ScrollbarController::HandleMouseMove( + const gfx::PointF position_in_widget) { + InputHandlerPointerResult scroll_result; + if (!thumb_drag_in_progress_) + return scroll_result; + + scroll_result.type = PointerResultType::kScrollbarScroll; + const ScrollbarOrientation orientation = + currently_captured_scrollbar_->orientation(); + if (orientation == ScrollbarOrientation::VERTICAL) + scroll_result.scroll_offset.set_y(position_in_widget.y() - + previous_pointer_position_.y()); + else + scroll_result.scroll_offset.set_x(position_in_widget.x() - + previous_pointer_position_.x()); + + LayerImpl* owner_scroll_layer = + layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId( + currently_captured_scrollbar_->scroll_element_id()); + + // Calculating the delta by which the scroller layer should move when + // dragging the thumb depends on the following factors: + // - scrollbar_track_length + // - scrollbar_thumb_length + // - scroll_layer_length + // - viewport_length + // - device_scale_factor + // - position_in_widget + // + // When a thumb drag is in progress, for every pixel that the pointer moves, + // the delta for the corresponding scroll_layer needs to be scaled by the + // following ratio: + // scaled_scroller_to_scrollbar_ratio = + // (scroll_layer_length - viewport_length) / + // (scrollbar_track_length - scrollbar_thumb_length) + // + // |<--------------------- scroll_layer_length -------------------------->| + // + // +------------------------------------------------+...................... + // | | . + // |<-------------- viewport_length --------------->| . + // | | . + // | | . + // | | . + // | | . + // | | . + // | | . + // | | . + // | | . + // | | . + // | |<------- scrollbar_track_length --------->| | . + // | | . + // +--+-----+----------------------------+-------+--+...................... + // |<|| |############################| ||>| + // +--+-----+----------------------------+-------+--+ + // + // |<- scrollbar_thumb_length ->| + // + layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries(); + float scroll_layer_length = + currently_captured_scrollbar_->scroll_layer_length(); + float scrollbar_track_length = currently_captured_scrollbar_->TrackLength(); + gfx::Rect thumb_rect(currently_captured_scrollbar_->ComputeThumbQuadRect()); + float scrollbar_thumb_length = orientation == ScrollbarOrientation::VERTICAL + ? thumb_rect.height() + : thumb_rect.width(); + + float viewport_length = + orientation == ScrollbarOrientation::VERTICAL + ? owner_scroll_layer->scroll_container_bounds().height() + : (owner_scroll_layer->scroll_container_bounds().width()); + float scaled_scroller_to_scrollbar_ratio = + ((scroll_layer_length - viewport_length) / + (scrollbar_track_length - scrollbar_thumb_length)) * + layer_tree_host_impl_->active_tree()->device_scale_factor(); + scroll_result.scroll_offset.Scale(scaled_scroller_to_scrollbar_ratio); + previous_pointer_position_ = position_in_widget; + // Thumb drags have more granularity and are purely dependent on the pointer + // movement. Hence we use kPrecisePixel when dragging the thumb. + scroll_result.scroll_units = + ui::input_types::ScrollGranularity::kScrollByPrecisePixel; + return scroll_result; } @@ -39,6 +146,7 @@ InputHandlerPointerResult ScrollbarController::HandleMouseUp( scrollbar_scroll_is_active_ = false; scroll_result.type = PointerResultType::kScrollbarScroll; } + thumb_drag_in_progress_ = false; return scroll_result; } @@ -57,20 +165,62 @@ LayerImpl* ScrollbarController::GetLayerHitByPoint( return layer_impl; } +int ScrollbarController::GetScrollDeltaForScrollbarPart( + ScrollbarPart scrollbar_part) { + int scroll_delta = 0; + int viewport_length = 0; + LayerImpl* owner_scroll_layer = nullptr; + + switch (scrollbar_part) { + case ScrollbarPart::BACK_BUTTON: + case ScrollbarPart::FORWARD_BUTTON: + scroll_delta = kPixelsPerLineStep; + break; + case ScrollbarPart::BACK_TRACK: + case ScrollbarPart::FORWARD_TRACK: + owner_scroll_layer = + layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId( + currently_captured_scrollbar_->scroll_element_id()); + viewport_length = + currently_captured_scrollbar_->orientation() == + ScrollbarOrientation::VERTICAL + ? owner_scroll_layer->scroll_container_bounds().height() + : (owner_scroll_layer->scroll_container_bounds().width()); + scroll_delta = viewport_length * kMinFractionToStepWhenPaging; + break; + default: + scroll_delta = 0; + } + return scroll_delta * + layer_tree_host_impl_->active_tree()->device_scale_factor(); +} + // Determines the scroll offsets based on hit test results. -gfx::ScrollOffset ScrollbarController::GetScrollStateBasedOnHitTest( - const LayerImpl* scrollbar_layer_impl, +gfx::ScrollOffset ScrollbarController::GetScrollDeltaFromPointerDown( const gfx::PointF position_in_widget) { - const ScrollbarLayerImplBase* scrollbar_layer = - static_cast<const ScrollbarLayerImplBase*>(scrollbar_layer_impl); - const ScrollbarOrientation orientation = scrollbar_layer->orientation(); + const ScrollbarOrientation orientation = + currently_captured_scrollbar_->orientation(); - ScrollbarPart scrollbar_part = - scrollbar_layer->IdentifyScrollbarPart(position_in_widget); + // position_in_widget needs to be transformed and made relative to the + // scrollbar layer because hit testing assumes layer relative coordinates. + ScrollbarPart scrollbar_part = ScrollbarPart::NO_PART; + gfx::Transform inverse_screen_space_transform( + gfx::Transform::kSkipInitialization); + if (!currently_captured_scrollbar_->ScreenSpaceTransform().GetInverse( + &inverse_screen_space_transform)) + return gfx::ScrollOffset(0, 0); - float scroll_delta = - layer_tree_host_impl_->active_tree()->device_scale_factor() * - kPixelsPerLineStep; + bool clipped; + gfx::PointF scroller_relative_position(MathUtil::ProjectPoint( + inverse_screen_space_transform, position_in_widget, &clipped)); + + if (clipped) + return gfx::ScrollOffset(0, 0); + + scrollbar_part = currently_captured_scrollbar_->IdentifyScrollbarPart( + scroller_relative_position); + + float scroll_delta = GetScrollDeltaForScrollbarPart(scrollbar_part); // See CreateScrollStateForGesture for more information on how these values // will be interpreted. @@ -82,7 +232,19 @@ gfx::ScrollOffset ScrollbarController::GetScrollStateBasedOnHitTest( return orientation == ScrollbarOrientation::VERTICAL ? gfx::ScrollOffset(0, scroll_delta) // Down arrow : gfx::ScrollOffset(scroll_delta, 0); // Right arrow + } else if (scrollbar_part == ScrollbarPart::THUMB) { + // Offsets are calculated in HandleMouseMove. + thumb_drag_in_progress_ = true; + } else if (scrollbar_part == ScrollbarPart::BACK_TRACK) { + return orientation == ScrollbarOrientation::VERTICAL + ? gfx::ScrollOffset(0, -scroll_delta) // Track click up + : gfx::ScrollOffset(-scroll_delta, 0); // Track click left + } else if (scrollbar_part == ScrollbarPart::FORWARD_TRACK) { + return orientation == ScrollbarOrientation::VERTICAL + ? gfx::ScrollOffset(0, scroll_delta) // Track click down + : gfx::ScrollOffset(scroll_delta, 0); // Track click right } + return gfx::ScrollOffset(0, 0); } diff --git a/chromium/cc/input/scrollbar_controller.h b/chromium/cc/input/scrollbar_controller.h index 0434f78bd11..3ce462461bf 100644 --- a/chromium/cc/input/scrollbar_controller.h +++ b/chromium/cc/input/scrollbar_controller.h @@ -22,17 +22,31 @@ class CC_EXPORT ScrollbarController { InputHandlerPointerResult HandleMouseDown( const gfx::PointF position_in_widget); + InputHandlerPointerResult HandleMouseMove( + const gfx::PointF position_in_widget); InputHandlerPointerResult HandleMouseUp(const gfx::PointF position_in_widget); private: // Returns a gfx::ScrollOffset object which contains scroll deltas for the // synthetic Gesture events. - gfx::ScrollOffset GetScrollStateBasedOnHitTest( - const LayerImpl* scrollbar_layer_impl, + gfx::ScrollOffset GetScrollDeltaFromPointerDown( const gfx::PointF position_in_widget); LayerImpl* GetLayerHitByPoint(const gfx::PointF position_in_widget); + int GetScrollDeltaForScrollbarPart(ScrollbarPart scrollbar_part); + LayerTreeHostImpl* layer_tree_host_impl_; + + // Used to safeguard against firing GSE without firing GSB and GSU. For + // example, if mouse is pressed outside the scrollbar but released after + // moving inside the scrollbar, a GSE will get queued up without this flag. bool scrollbar_scroll_is_active_; + + // Used to tell if the scrollbar thumb is getting dragged. + bool thumb_drag_in_progress_; + const ScrollbarLayerImplBase* currently_captured_scrollbar_; + + // This is relative to the RenderWidget's origin. + gfx::PointF previous_pointer_position_; }; } // namespace cc diff --git a/chromium/cc/input/snap_fling_controller_unittest.cc b/chromium/cc/input/snap_fling_controller_unittest.cc index 5deb03cb565..ebbf5b18cfd 100644 --- a/chromium/cc/input/snap_fling_controller_unittest.cc +++ b/chromium/cc/input/snap_fling_controller_unittest.cc @@ -77,9 +77,10 @@ TEST_F(SnapFlingControllerTest, CreatesAndAnimatesCurveOnFirstInertialGSU) { EXPECT_CALL(mock_client_, GetSnapFlingInfo(testing::_, testing::_, testing::_)) - .WillOnce(DoAll(testing::SetArgPointee<1>(gfx::Vector2dF(0, 0)), - testing::SetArgPointee<2>(gfx::Vector2dF(0, 100)), - testing::Return(true))); + .WillOnce( + testing::DoAll(testing::SetArgPointee<1>(gfx::Vector2dF(0, 0)), + testing::SetArgPointee<2>(gfx::Vector2dF(0, 100)), + testing::Return(true))); EXPECT_CALL(mock_client_, RequestAnimationForSnapFling()).Times(1); EXPECT_CALL(mock_client_, ScrollByForSnapFling(testing::_)).Times(1); EXPECT_TRUE(controller_->HandleGestureScrollUpdate(gsu)); diff --git a/chromium/cc/layers/heads_up_display_layer.cc b/chromium/cc/layers/heads_up_display_layer.cc index 6d7044e2703..e291e6ee99a 100644 --- a/chromium/cc/layers/heads_up_display_layer.cc +++ b/chromium/cc/layers/heads_up_display_layer.cc @@ -65,6 +65,15 @@ std::unique_ptr<LayerImpl> HeadsUpDisplayLayer::CreateLayerImpl( return HeadsUpDisplayLayerImpl::Create(tree_impl, id()); } +const std::vector<gfx::Rect>& HeadsUpDisplayLayer::LayoutShiftRects() const { + return layout_shift_rects_; +} + +void HeadsUpDisplayLayer::SetLayoutShiftRects( + const std::vector<gfx::Rect>& rects) { + layout_shift_rects_ = rects; +} + void HeadsUpDisplayLayer::PushPropertiesTo(LayerImpl* layer) { Layer::PushPropertiesTo(layer); TRACE_EVENT0("cc", "HeadsUpDisplayLayer::PushPropertiesTo"); @@ -72,6 +81,7 @@ void HeadsUpDisplayLayer::PushPropertiesTo(LayerImpl* layer) { static_cast<HeadsUpDisplayLayerImpl*>(layer); layer_impl->SetHUDTypeface(typeface_); + layer_impl->SetLayoutShiftRects(layout_shift_rects_); } } // namespace cc diff --git a/chromium/cc/layers/heads_up_display_layer.h b/chromium/cc/layers/heads_up_display_layer.h index 1337fb639fb..1dea4e99e44 100644 --- a/chromium/cc/layers/heads_up_display_layer.h +++ b/chromium/cc/layers/heads_up_display_layer.h @@ -12,6 +12,7 @@ #include "cc/layers/layer.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkTypeface.h" +#include "ui/gfx/geometry/rect.h" namespace cc { @@ -25,6 +26,9 @@ class CC_EXPORT HeadsUpDisplayLayer : public Layer { void UpdateLocationAndSize(const gfx::Size& device_viewport, float device_scale_factor); + const std::vector<gfx::Rect>& LayoutShiftRects() const; + void SetLayoutShiftRects(const std::vector<gfx::Rect>& rects); + std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; // Layer overrides. @@ -38,6 +42,7 @@ class CC_EXPORT HeadsUpDisplayLayer : public Layer { ~HeadsUpDisplayLayer() override; sk_sp<SkTypeface> typeface_; + std::vector<gfx::Rect> layout_shift_rects_; }; } // namespace cc diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc index 0a9ea808774..75431c15d8f 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.cc +++ b/chromium/cc/layers/heads_up_display_layer_impl.cc @@ -10,6 +10,7 @@ #include <algorithm> #include <vector> +#include "base/memory/shared_memory_mapping.h" #include "base/numerics/safe_conversions.h" #include "base/optional.h" #include "base/single_thread_task_runner.h" @@ -156,12 +157,12 @@ class HudSoftwareBacking : public ResourcePool::SoftwareBacking { const base::trace_event::MemoryAllocatorDumpGuid& buffer_dump_guid, uint64_t tracing_process_id, int importance) const override { - pmd->CreateSharedMemoryOwnershipEdge( - buffer_dump_guid, shared_memory->mapped_id(), importance); + pmd->CreateSharedMemoryOwnershipEdge(buffer_dump_guid, + shared_mapping.guid(), importance); } LayerTreeFrameSink* layer_tree_frame_sink; - std::unique_ptr<base::SharedMemory> shared_memory; + base::WritableSharedMemoryMapping shared_mapping; }; bool HeadsUpDisplayLayerImpl::WillDraw( @@ -320,15 +321,14 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( auto backing = std::make_unique<HudSoftwareBacking>(); backing->layer_tree_frame_sink = layer_tree_frame_sink; backing->shared_bitmap_id = viz::SharedBitmap::GenerateId(); - backing->shared_memory = viz::bitmap_allocation::AllocateMappedBitmap( - pool_resource.size(), pool_resource.format()); + base::MappedReadOnlyRegion mapped_region = + viz::bitmap_allocation::AllocateSharedBitmap(pool_resource.size(), + pool_resource.format()); + backing->shared_mapping = std::move(mapped_region.mapping); - mojo::ScopedSharedBufferHandle handle = - viz::bitmap_allocation::DuplicateAndCloseMappedBitmap( - backing->shared_memory.get(), pool_resource.size(), - pool_resource.format()); - layer_tree_frame_sink->DidAllocateSharedBitmap(std::move(handle), - backing->shared_bitmap_id); + layer_tree_frame_sink->DidAllocateSharedBitmap( + viz::bitmap_allocation::ToMojoHandle(std::move(mapped_region.region)), + backing->shared_bitmap_id); pool_resource.set_software_backing(std::move(backing)); } @@ -443,7 +443,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture( auto* backing = static_cast<HudSoftwareBacking*>(pool_resource.software_backing()); sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect( - info, backing->shared_memory->memory(), info.minRowBytes()); + info, backing->shared_mapping.memory(), info.minRowBytes()); SkiaPaintCanvas canvas(surface->getCanvas()); DrawHudContents(&canvas); @@ -514,6 +514,16 @@ void HeadsUpDisplayLayerImpl::SetHUDTypeface(sk_sp<SkTypeface> typeface) { NoteLayerPropertyChanged(); } +const std::vector<gfx::Rect>& HeadsUpDisplayLayerImpl::LayoutShiftRects() + const { + return layout_shift_rects_; +} + +void HeadsUpDisplayLayerImpl::SetLayoutShiftRects( + const std::vector<gfx::Rect>& rects) { + layout_shift_rects_ = rects; +} + void HeadsUpDisplayLayerImpl::PushPropertiesTo(LayerImpl* layer) { LayerImpl::PushPropertiesTo(layer); @@ -521,6 +531,7 @@ void HeadsUpDisplayLayerImpl::PushPropertiesTo(LayerImpl* layer) { static_cast<HeadsUpDisplayLayerImpl*>(layer); layer_impl->SetHUDTypeface(typeface_); + layer_impl->SetLayoutShiftRects(layout_shift_rects_); } void HeadsUpDisplayLayerImpl::UpdateHudContents() { @@ -594,11 +605,11 @@ void HeadsUpDisplayLayerImpl::DrawText(PaintCanvas* canvas, if (align == TextAlign::kCenter) { auto width = - font.measureText(text.c_str(), text.length(), kUTF8_SkTextEncoding); + font.measureText(text.c_str(), text.length(), SkTextEncoding::kUTF8); x -= width * 0.5f; } else if (align == TextAlign::kRight) { auto width = - font.measureText(text.c_str(), text.length(), kUTF8_SkTextEncoding); + font.measureText(text.c_str(), text.length(), SkTextEncoding::kUTF8); x -= width; } @@ -953,7 +964,7 @@ void HeadsUpDisplayLayerImpl::DrawDebugRect( SkFont label_font(typeface_, kFontHeight); const SkScalar label_text_width = label_font.measureText( - label_text.c_str(), label_text.length(), kUTF8_SkTextEncoding); + label_text.c_str(), label_text.length(), SkTextEncoding::kUTF8); canvas->drawRect(SkRect::MakeWH(label_text_width + 2 * kPadding, kFontHeight + 2 * kPadding), label_flags); @@ -980,6 +991,9 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects( std::string label_text; switch (debug_rects[i].type) { + case LAYOUT_SHIFT_RECT_TYPE: + // TODO(rnasri@): Handle layout shift rects drawing. + break; case PAINT_RECT_TYPE: new_paint_rects.push_back(debug_rects[i]); continue; diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h index 7f209eb7267..4b1f4bf6ee2 100644 --- a/chromium/cc/layers/heads_up_display_layer_impl.h +++ b/chromium/cc/layers/heads_up_display_layer_impl.h @@ -64,6 +64,8 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl { bool IsAnimatingHUDContents() const { return fade_step_ > 0; } void SetHUDTypeface(sk_sp<SkTypeface> typeface); + void SetLayoutShiftRects(const std::vector<gfx::Rect>& rects); + const std::vector<gfx::Rect>& LayoutShiftRects() const; // This evicts hud quad appended during render pass preparation. void EvictHudQuad(const viz::RenderPassList& list); @@ -148,6 +150,7 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl { sk_sp<SkSurface> staging_surface_; sk_sp<SkTypeface> typeface_; + std::vector<gfx::Rect> layout_shift_rects_; float internal_contents_scale_; gfx::Size internal_content_bounds_; diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc index 54907feef3d..24db5b0a3cc 100644 --- a/chromium/cc/layers/layer.cc +++ b/chromium/cc/layers/layer.cc @@ -601,6 +601,10 @@ void Layer::SetBackdropFilterBounds(const gfx::RRectF& backdrop_filter_bounds) { inputs_.backdrop_filter_bounds = backdrop_filter_bounds; } +void Layer::ClearBackdropFilterBounds() { + inputs_.backdrop_filter_bounds.reset(); +} + void Layer::SetBackdropFilterQuality(const float quality) { inputs_.backdrop_filter_quality = quality; } @@ -615,7 +619,7 @@ void Layer::SetFiltersOrigin(const gfx::PointF& filters_origin) { SetNeedsCommit(); } -void Layer::SetRoundedCorner(const std::array<uint32_t, 4>& corner_radii) { +void Layer::SetRoundedCorner(const gfx::RoundedCornersF& corner_radii) { DCHECK(IsPropertyChangeAllowed()); if (inputs_.corner_radii == corner_radii) return; @@ -1264,9 +1268,22 @@ void Layer::SetShouldFlattenTransform(bool should_flatten) { SetSubtreePropertyChanged(); } +#if DCHECK_IS_ON() +std::string Layer::DebugName() const { + if (inputs_.client) { + if (auto debug_info = inputs_.client->TakeDebugInfo(this)) + return debug_info->ToBaseValue()->FindKey("layer_name")->GetString(); + } + return ""; +} +#endif + std::string Layer::ToString() const { return base::StringPrintf( "layer_id: %d\n" +#if DCHECK_IS_ON() + " name: %s\n" +#endif " Bounds: %s\n" " ElementId: %s\n" " OffsetToTransformParent: %s\n" @@ -1276,7 +1293,11 @@ std::string Layer::ToString() const { " effect_tree_index: %d\n" " scroll_tree_index: %d\n" " transform_tree_index: %d\n", - id(), bounds().ToString().c_str(), element_id().ToString().c_str(), + id(), +#if DCHECK_IS_ON() + DebugName().c_str(), +#endif + bounds().ToString().c_str(), element_id().ToString().c_str(), offset_to_transform_parent().ToString().c_str(), position().ToString().c_str(), scrollable(), clip_tree_index(), effect_tree_index(), scroll_tree_index(), transform_tree_index()); @@ -1394,6 +1415,7 @@ void Layer::SetStickyPositionConstraint( if (inputs_.sticky_position_constraint == constraint) return; inputs_.sticky_position_constraint = constraint; + SetSubtreePropertyChanged(); SetPropertyTreesNeedRebuild(); SetNeedsCommit(); } @@ -1598,6 +1620,10 @@ void Layer::OnFilterAnimated(const FilterOperations& filters) { inputs_.filters = filters; } +void Layer::OnBackdropFilterAnimated(const FilterOperations& backdrop_filters) { + inputs_.backdrop_filters = backdrop_filters; +} + void Layer::OnOpacityAnimated(float opacity) { inputs_.opacity = opacity; } diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h index 5a2fa5bff11..04740451da9 100644 --- a/chromium/cc/layers/layer.h +++ b/chromium/cc/layers/layer.h @@ -34,6 +34,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/geometry/point3_f.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/geometry/scroll_offset.h" #include "ui/gfx/rrect_f.h" #include "ui/gfx/transform.h" @@ -249,16 +250,13 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // Set or get the rounded corner radii which is applied to the layer and its // subtree (as if they are together as a single composited entity) when // blitting into their target. Setting this makes the layer masked to bounds. - void SetRoundedCorner(const std::array<uint32_t, 4>& corner_radii); - const std::array<uint32_t, 4>& corner_radii() const { + void SetRoundedCorner(const gfx::RoundedCornersF& corner_radii); + const gfx::RoundedCornersF& corner_radii() const { return inputs_.corner_radii; } // Returns true if any of the corner has a non-zero radius set. - bool HasRoundedCorner() const { - return corner_radii()[0] + corner_radii()[1] + corner_radii()[2] + - corner_radii()[3]; - } + bool HasRoundedCorner() const { return !corner_radii().IsEmpty(); } // Set or get the flag that disables the requirement of a render surface for // this layer due to it having rounded corners. This improves performance at @@ -318,7 +316,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { } void SetBackdropFilterBounds(const gfx::RRectF& backdrop_filter_bounds); - const gfx::RRectF& backdrop_filter_bounds() const { + void ClearBackdropFilterBounds(); + const base::Optional<gfx::RRectF>& backdrop_filter_bounds() const { return inputs_.backdrop_filter_bounds; } @@ -337,7 +336,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // Set or get whether this layer should be a hit test target void SetHitTestable(bool should_hit_test); - bool HitTestable() const; + virtual bool HitTestable() const; // Set or gets if this layer is a container for fixed position layers in its // subtree. Such layers will be positioned and transformed relative to this @@ -799,6 +798,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { return should_flatten_screen_space_transform_from_property_tree_; } +#if DCHECK_IS_ON() + // For debugging, containing information about the associated DOM, etc. + std::string DebugName() const; +#endif + std::string ToString() const; // Called when a property has been modified in a way that the layer knows @@ -878,6 +882,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { // Interactions with attached animations. void OnFilterAnimated(const FilterOperations& filters); + void OnBackdropFilterAnimated(const FilterOperations& backdrop_filters); void OnOpacityAnimated(float opacity); void OnTransformAnimated(const gfx::Transform& transform); @@ -954,13 +959,13 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> { FilterOperations filters; FilterOperations backdrop_filters; - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; gfx::PointF filters_origin; float backdrop_filter_quality; // Corner clip radius for the 4 corners of the layer in the following order: // top left, top right, bottom right, bottom left - std::array<uint32_t, 4> corner_radii; + gfx::RoundedCornersF corner_radii; // If set, disables this layer's rounded corner from triggering a render // surface on itself if possible. diff --git a/chromium/cc/layers/layer_client.h b/chromium/cc/layers/layer_client.h index c7bb4862c2f..fb4b6408f29 100644 --- a/chromium/cc/layers/layer_client.h +++ b/chromium/cc/layers/layer_client.h @@ -29,7 +29,7 @@ class CC_EXPORT LayerClient { // A pointer to the layer is provided for the convenience of layer clients // which service multiple layers. virtual std::unique_ptr<base::trace_event::TracedValue> TakeDebugInfo( - Layer* layer) = 0; + const Layer* layer) = 0; virtual void DidChangeScrollbarsHiddenIfOverlay(bool) = 0; diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc index 580dd90ba22..86ccf0fc4aa 100644 --- a/chromium/cc/layers/layer_impl.cc +++ b/chromium/cc/layers/layer_impl.cc @@ -143,7 +143,7 @@ void LayerImpl::PopulateSharedQuadState(viz::SharedQuadState* state, draw_properties_.rounded_corner_bounds, draw_properties_.clip_rect, draw_properties_.is_clipped, contents_opaque, draw_properties_.opacity, - effect_node->has_render_surface ? SkBlendMode::kSrcOver + effect_node->HasRenderSurface() ? SkBlendMode::kSrcOver : effect_node->blend_mode, GetSortingContextId()); state->is_fast_rounded_corner = draw_properties_.is_fast_rounded_corner; @@ -169,7 +169,7 @@ void LayerImpl::PopulateScaledSharedQuadState(viz::SharedQuadState* state, draw_properties().rounded_corner_bounds, draw_properties().clip_rect, draw_properties().is_clipped, contents_opaque, draw_properties().opacity, - effect_node->has_render_surface ? SkBlendMode::kSrcOver + effect_node->HasRenderSurface() ? SkBlendMode::kSrcOver : effect_node->blend_mode, GetSortingContextId()); state->is_fast_rounded_corner = draw_properties().is_fast_rounded_corner; @@ -524,6 +524,12 @@ bool LayerImpl::IsActive() const { } gfx::Size LayerImpl::bounds() const { + // As an optimization, we do not need to include the viewport bounds delta if + // the layer is not a viewport layer. + if (viewport_layer_type_ == NOT_VIEWPORT_LAYER) { + DCHECK(ViewportBoundsDelta().IsZero()); + return bounds_; + } auto viewport_bounds_delta = gfx::ToCeiledVector2d(ViewportBoundsDelta()); return gfx::Size(bounds_.width() + viewport_bounds_delta.x(), bounds_.height() + viewport_bounds_delta.y()); diff --git a/chromium/cc/layers/layer_impl_test_properties.h b/chromium/cc/layers/layer_impl_test_properties.h index c29aee7fb31..0d2c134b2b4 100644 --- a/chromium/cc/layers/layer_impl_test_properties.h +++ b/chromium/cc/layers/layer_impl_test_properties.h @@ -49,7 +49,7 @@ struct CC_EXPORT LayerImplTestProperties { float opacity; FilterOperations filters; FilterOperations backdrop_filters; - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; float backdrop_filter_quality; gfx::PointF filters_origin; SkBlendMode blend_mode; @@ -70,6 +70,7 @@ struct CC_EXPORT LayerImplTestProperties { bool user_scrollable_vertical = true; OverscrollBehavior overscroll_behavior; base::Optional<SnapContainerData> snap_container_data; + gfx::RRectF rounded_corner_bounds; }; } // namespace cc diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc index f969da4f3bb..0a02373e4d9 100644 --- a/chromium/cc/layers/layer_unittest.cc +++ b/chromium/cc/layers/layer_unittest.cc @@ -351,8 +351,7 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { grand_child->PushPropertiesTo(grand_child_impl.get())); EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); - const std::array<uint32_t, 4> radii{1, 2, 3, 4}; - EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetRoundedCorner(radii)); + EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetRoundedCorner({1, 2, 3, 4})); EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( root->PushPropertiesTo(root_impl.get()); child->PushPropertiesTo(child_impl.get()); @@ -430,6 +429,40 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) { child2->PushPropertiesTo(child2_impl.get()); grand_child->PushPropertiesTo(grand_child_impl.get())); + // Setting the sticky constraints requires a subtree change. It shouldn't be + // required if they don't change. + LayerStickyPositionConstraint arbitrary_constraint; + arbitrary_constraint.is_sticky = true; + arbitrary_constraint.is_anchored_top = true; + arbitrary_constraint.top_offset = 50; + EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); + EXECUTE_AND_VERIFY_SUBTREE_CHANGED( + root->SetStickyPositionConstraint(arbitrary_constraint)); + EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( + root->PushPropertiesTo(root_impl.get()); + child->PushPropertiesTo(child_impl.get()); + child2->PushPropertiesTo(child2_impl.get()); + grand_child->PushPropertiesTo(grand_child_impl.get()); + layer_tree_host_->ClearLayersThatShouldPushProperties()); + + EXECUTE_AND_VERIFY_SUBTREE_NOT_CHANGED( + root->SetStickyPositionConstraint(arbitrary_constraint)); + EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( + root->PushPropertiesTo(root_impl.get()); + child->PushPropertiesTo(child_impl.get()); + child2->PushPropertiesTo(child2_impl.get()); + grand_child->PushPropertiesTo(grand_child_impl.get())); + + arbitrary_constraint.top_offset = 10; + EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); + EXECUTE_AND_VERIFY_SUBTREE_CHANGED( + root->SetStickyPositionConstraint(arbitrary_constraint)); + EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET( + root->PushPropertiesTo(root_impl.get()); + child->PushPropertiesTo(child_impl.get()); + child2->PushPropertiesTo(child2_impl.get()); + grand_child->PushPropertiesTo(grand_child_impl.get())); + gfx::PointF arbitrary_point_f = gfx::PointF(0.125f, 0.25f); EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1); root->SetPosition(arbitrary_point_f); diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc index ca94e661013..e6fcf5ff6ec 100644 --- a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc +++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc @@ -73,10 +73,10 @@ void PaintedOverlayScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { scrollbar_layer->SetThumbThickness(thumb_thickness_); scrollbar_layer->SetThumbLength(thumb_length_); if (scrollbar_->Orientation() == HORIZONTAL) { - scrollbar_layer->SetTrackStart(track_rect_.x() - location_.x()); + scrollbar_layer->SetTrackStart(track_rect_.x()); scrollbar_layer->SetTrackLength(track_rect_.width()); } else { - scrollbar_layer->SetTrackStart(track_rect_.y() - location_.y()); + scrollbar_layer->SetTrackStart(track_rect_.y()); scrollbar_layer->SetTrackLength(track_rect_.height()); } diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc index ddf202b095a..deda561b810 100644 --- a/chromium/cc/layers/painted_scrollbar_layer.cc +++ b/chromium/cc/layers/painted_scrollbar_layer.cc @@ -74,12 +74,10 @@ void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { scrollbar_layer->SetForwardButtonRect(forward_button_rect_); scrollbar_layer->SetThumbLength(thumb_length_); if (scrollbar_->Orientation() == HORIZONTAL) { - scrollbar_layer->SetTrackStart( - track_rect_.x() - location_.x()); + scrollbar_layer->SetTrackStart(track_rect_.x()); scrollbar_layer->SetTrackLength(track_rect_.width()); } else { - scrollbar_layer->SetTrackStart( - track_rect_.y() - location_.y()); + scrollbar_layer->SetTrackStart(track_rect_.y()); scrollbar_layer->SetTrackLength(track_rect_.height()); } diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc index 66275d92f98..0788e665719 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc +++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc @@ -217,6 +217,36 @@ gfx::Rect PaintedScrollbarLayerImpl::ForwardButtonRect() const { return forward_button_rect_; } +gfx::Rect PaintedScrollbarLayerImpl::BackTrackRect() const { + gfx::Rect thumb_rect = ComputeThumbQuadRect(); + if (orientation() == HORIZONTAL) { + int rect_x = back_button_rect_.x() + back_button_rect_.width(); + int rect_y = back_button_rect_.y(); + return gfx::Rect(rect_x, rect_y, thumb_rect.x() - rect_x, + back_button_rect_.height()); + } else { + int rect_x = back_button_rect_.x(); + int rect_y = back_button_rect_.y() + back_button_rect_.height(); + return gfx::Rect(rect_x, rect_y, back_button_rect_.width(), + thumb_rect.y() - rect_y); + } +} + +gfx::Rect PaintedScrollbarLayerImpl::ForwardTrackRect() const { + gfx::Rect thumb_rect = ComputeThumbQuadRect(); + if (orientation() == HORIZONTAL) { + int rect_x = thumb_rect.x() + thumb_rect.width(); + int rect_y = thumb_rect.y(); + return gfx::Rect(rect_x, rect_y, forward_button_rect_.x() - rect_x, + forward_button_rect_.height()); + } else { + int rect_x = thumb_rect.x(); + int rect_y = thumb_rect.y() + thumb_rect.height(); + return gfx::Rect(rect_x, rect_y, forward_button_rect_.width(), + forward_button_rect_.y() - rect_y); + } +} + void PaintedScrollbarLayerImpl::SetTrackLength(int track_length) { if (track_length_ == track_length) return; diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.h b/chromium/cc/layers/painted_scrollbar_layer_impl.h index 13a9b4f41db..37be215c49c 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_impl.h +++ b/chromium/cc/layers/painted_scrollbar_layer_impl.h @@ -62,6 +62,8 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase { gfx::Rect BackButtonRect() const override; gfx::Rect ForwardButtonRect() const override; + gfx::Rect BackTrackRect() const override; + gfx::Rect ForwardTrackRect() const override; int ThumbThickness() const override; LayerTreeSettings::ScrollbarAnimator GetScrollbarAnimator() const override; diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc index bef40d67ea2..d2d4c6af676 100644 --- a/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc +++ b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc @@ -80,8 +80,10 @@ TEST(PaintedScrollbarLayerImplTest, Occlusion) { const viz::DrawQuad* thumb_draw_quad = impl.quad_list().ElementAt(0); const viz::DrawQuad* track_draw_quad = impl.quad_list().ElementAt(1); - EXPECT_EQ(viz::DrawQuad::TEXTURE_CONTENT, thumb_draw_quad->material); - EXPECT_EQ(viz::DrawQuad::TEXTURE_CONTENT, track_draw_quad->material); + EXPECT_EQ(viz::DrawQuad::Material::kTextureContent, + thumb_draw_quad->material); + EXPECT_EQ(viz::DrawQuad::Material::kTextureContent, + track_draw_quad->material); const viz::TextureDrawQuad* thumb_quad = viz::TextureDrawQuad::MaterialCast(thumb_draw_quad); diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc index 9f53aa0cb72..b9cbcd3241a 100644 --- a/chromium/cc/layers/picture_layer_impl.cc +++ b/chromium/cc/layers/picture_layer_impl.cc @@ -484,8 +484,8 @@ void PictureLayerImpl::AppendQuads(viz::RenderPass* render_pass, shared_quad_state, offset_geometry_rect, offset_visible_geometry_rect, needs_blending, draw_info.resource_id_for_export(), texture_rect, - draw_info.resource_size(), draw_info.contents_swizzled(), - draw_info.is_premultiplied(), nearest_neighbor_, + draw_info.resource_size(), draw_info.is_premultiplied(), + nearest_neighbor_, !layer_tree_impl()->settings().enable_edge_anti_aliasing); ValidateQuadResources(quad); has_draw_quad = true; diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc index 1ecd3df1423..d98fed6c1d0 100644 --- a/chromium/cc/layers/picture_layer_impl_unittest.cc +++ b/chromium/cc/layers/picture_layer_impl_unittest.cc @@ -1508,7 +1508,7 @@ TEST_F(PictureLayerImplTest, DisallowTileDrawQuads) { active_layer()->DidDraw(nullptr); ASSERT_EQ(1u, render_pass->quad_list.size()); - EXPECT_EQ(viz::DrawQuad::PICTURE_CONTENT, + EXPECT_EQ(viz::DrawQuad::Material::kPictureContent, render_pass->quad_list.front()->material); EXPECT_EQ(render_pass->quad_list.front()->rect, layer_rect); EXPECT_FALSE(render_pass->quad_list.front()->needs_blending); @@ -1545,7 +1545,7 @@ TEST_F(PictureLayerImplTest, ResourcelessPartialRecording) { gfx::Rect quad_visible = gfx::IntersectRects(scaled_visible, scaled_recorded); ASSERT_EQ(1U, render_pass->quad_list.size()); - EXPECT_EQ(viz::DrawQuad::PICTURE_CONTENT, + EXPECT_EQ(viz::DrawQuad::Material::kPictureContent, render_pass->quad_list.front()->material); const viz::DrawQuad* quad = render_pass->quad_list.front(); EXPECT_EQ(quad_visible, quad->rect); @@ -1621,7 +1621,7 @@ TEST_F(PictureLayerImplTest, FarScrolledQuadsShifted) { last_height = draw_quad->rect.height(); } EXPECT_LT(last_y, 5000); - EXPECT_EQ(draw_quad->material, viz::DrawQuad::TILED_CONTENT); + EXPECT_EQ(draw_quad->material, viz::DrawQuad::Material::kTiledContent); auto transform = [draw_quad](const gfx::Rect& rect) { gfx::RectF result(rect); @@ -1699,7 +1699,7 @@ TEST_F(PictureLayerImplTest, FarScrolledSolidColorQuadsShifted) { last_height = draw_quad->rect.height(); } EXPECT_LT(last_y, 5000); - EXPECT_EQ(draw_quad->material, viz::DrawQuad::SOLID_COLOR); + EXPECT_EQ(draw_quad->material, viz::DrawQuad::Material::kSolidColor); auto transform = [draw_quad](const gfx::Rect& rect) { gfx::RectF result(rect); @@ -3931,9 +3931,9 @@ TEST_F(PictureLayerImplTestWithDelegatingRenderer, // Even when OOM, quads should be produced, and should be different material // from quads with resource. EXPECT_LT(max_tiles, render_pass->quad_list.size()); - EXPECT_EQ(viz::DrawQuad::Material::TILED_CONTENT, + EXPECT_EQ(viz::DrawQuad::Material::kTiledContent, render_pass->quad_list.front()->material); - EXPECT_EQ(viz::DrawQuad::Material::SOLID_COLOR, + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, render_pass->quad_list.back()->material); } @@ -4657,8 +4657,8 @@ void PictureLayerImplTest::TestQuadsForSolidColor(bool test_for_solid, EXPECT_EQ(4u, render_pass->quad_list.size()); viz::DrawQuad::Material expected = - test_for_solid ? viz::DrawQuad::Material::SOLID_COLOR - : viz::DrawQuad::Material::TILED_CONTENT; + test_for_solid ? viz::DrawQuad::Material::kSolidColor + : viz::DrawQuad::Material::kTiledContent; EXPECT_EQ(expected, render_pass->quad_list.front()->material); } @@ -5283,7 +5283,7 @@ TEST_F(PictureLayerImplTest, CompositedImageIgnoreIdealContentsScale) { active_layer->DidDraw(nullptr); ASSERT_FALSE(render_pass->quad_list.empty()); - EXPECT_EQ(viz::DrawQuad::TILED_CONTENT, + EXPECT_EQ(viz::DrawQuad::Material::kTiledContent, render_pass->quad_list.front()->material); // Tiles are ready at correct scale, so should not set had_incomplete_tile. diff --git a/chromium/cc/layers/recording_source_unittest.cc b/chromium/cc/layers/recording_source_unittest.cc index dbdcaa17c49..34f3508c062 100644 --- a/chromium/cc/layers/recording_source_unittest.cc +++ b/chromium/cc/layers/recording_source_unittest.cc @@ -16,6 +16,10 @@ namespace cc { namespace { +gfx::ColorSpace DefaultColorSpace() { + return gfx::ColorSpace::CreateSRGB(); +} + std::unique_ptr<FakeRecordingSource> CreateRecordingSource( const gfx::Rect& viewport) { gfx::Rect layer_rect(viewport.right(), viewport.bottom()); @@ -106,7 +110,8 @@ TEST(RecordingSourceTest, DiscardableImagesWithTransform) { std::vector<const DrawImage*> images; raster_source->GetDiscardableImagesInRect(gfx::Rect(130, 0, 128, 128), &images); - DrawImage image(*images[0], scale, PaintImage::kDefaultFrameIndex); + DrawImage image(*images[0], scale, PaintImage::kDefaultFrameIndex, + DefaultColorSpace()); EXPECT_EQ(1u, images.size()); EXPECT_FLOAT_EQ(scale, image.scale().width()); EXPECT_FLOAT_EQ(scale, image.scale().height()); diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc index ea81934163c..6acd6825c0b 100644 --- a/chromium/cc/layers/render_surface_impl.cc +++ b/chromium/cc/layers/render_surface_impl.cc @@ -153,7 +153,7 @@ const FilterOperations& RenderSurfaceImpl::BackdropFilters() const { return OwningEffectNode()->backdrop_filters; } -const gfx::RRectF& RenderSurfaceImpl::BackdropFilterBounds() const { +base::Optional<gfx::RRectF> RenderSurfaceImpl::BackdropFilterBounds() const { return OwningEffectNode()->backdrop_filter_bounds; } @@ -573,7 +573,7 @@ void RenderSurfaceImpl::TileMaskLayer( constexpr float backdrop_filter_quality = 1.0; switch (temp_quad->material) { - case viz::DrawQuad::TILED_CONTENT: { + case viz::DrawQuad::Material::kTiledContent: { DCHECK_EQ(1U, temp_quad->resources.count); // When the |temp_quad| is actually a texture, we need to calculate // |mask_uv_rect|. The |mask_uv_rect| is the normalized sub-rect for @@ -622,7 +622,7 @@ void RenderSurfaceImpl::TileMaskLayer( !layer_tree_impl_->settings().enable_edge_anti_aliasing, backdrop_filter_quality); } break; - case viz::DrawQuad::SOLID_COLOR: { + case viz::DrawQuad::Material::kSolidColor: { SkColor temp_color = viz::SolidColorDrawQuad::MaterialCast(temp_quad)->color; // Check the alpha channel of the color. We apply the mask by @@ -642,7 +642,7 @@ void RenderSurfaceImpl::TileMaskLayer( !layer_tree_impl_->settings().enable_edge_anti_aliasing, backdrop_filter_quality); } break; - case viz::DrawQuad::DEBUG_BORDER: + case viz::DrawQuad::Material::kDebugBorder: NOTIMPLEMENTED(); break; default: diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h index 15dd8c98384..89a270cf933 100644 --- a/chromium/cc/layers/render_surface_impl.h +++ b/chromium/cc/layers/render_surface_impl.h @@ -159,7 +159,7 @@ class CC_EXPORT RenderSurfaceImpl { const FilterOperations& Filters() const; const FilterOperations& BackdropFilters() const; - const gfx::RRectF& BackdropFilterBounds() const; + base::Optional<gfx::RRectF> BackdropFilterBounds() const; gfx::PointF FiltersOrigin() const; gfx::Transform SurfaceScale() const; diff --git a/chromium/cc/layers/render_surface_unittest.cc b/chromium/cc/layers/render_surface_unittest.cc index 2176380091b..577594b0abe 100644 --- a/chromium/cc/layers/render_surface_unittest.cc +++ b/chromium/cc/layers/render_surface_unittest.cc @@ -68,7 +68,7 @@ class FakePictureLayerImplForRenderSurfaceTest : public FakePictureLayerImpl { for (const auto& rect : quad_rects_) { auto* quad = render_pass->CreateAndAppendDrawQuad<viz::TileDrawQuad>(); quad->SetNew(shared_quad_state, rect, rect, needs_blending, 0, - gfx::RectF(rect), bounds(), false, false, false, false); + gfx::RectF(rect), bounds(), false, false, false); } } diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.cc b/chromium/cc/layers/scrollbar_layer_impl_base.cc index fb4ed8fb758..419b0517b81 100644 --- a/chromium/cc/layers/scrollbar_layer_impl_base.cc +++ b/chromium/cc/layers/scrollbar_layer_impl_base.cc @@ -290,6 +290,14 @@ gfx::Rect ScrollbarLayerImplBase::ForwardButtonRect() const { return gfx::Rect(0, 0); } +gfx::Rect ScrollbarLayerImplBase::BackTrackRect() const { + return gfx::Rect(0, 0); +} + +gfx::Rect ScrollbarLayerImplBase::ForwardTrackRect() const { + return gfx::Rect(0, 0); +} + // This manages identifying which part of a composited scrollbar got hit based // on the position_in_widget. ScrollbarPart ScrollbarLayerImplBase::IdentifyScrollbarPart( @@ -298,9 +306,19 @@ ScrollbarPart ScrollbarLayerImplBase::IdentifyScrollbarPart( position_in_widget.y()); if (BackButtonRect().Contains(pointer_location)) return ScrollbarPart::BACK_BUTTON; + if (ForwardButtonRect().Contains(pointer_location)) return ScrollbarPart::FORWARD_BUTTON; + if (ComputeThumbQuadRect().Contains(pointer_location)) + return ScrollbarPart::THUMB; + + if (BackTrackRect().Contains(pointer_location)) + return ScrollbarPart::BACK_TRACK; + + if (ForwardTrackRect().Contains(pointer_location)) + return ScrollbarPart::FORWARD_TRACK; + // TODO(arakeri): Once crbug.com/952314 is fixed, add a DCHECK to verify that // the point that is passed in is within the TrackRect. Also, please note that // hit testing other scrollbar parts is not yet implemented. diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.h b/chromium/cc/layers/scrollbar_layer_impl_base.h index 5255f520e4f..b1c225235b5 100644 --- a/chromium/cc/layers/scrollbar_layer_impl_base.h +++ b/chromium/cc/layers/scrollbar_layer_impl_base.h @@ -66,8 +66,12 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl { virtual LayerTreeSettings::ScrollbarAnimator GetScrollbarAnimator() const; + virtual float TrackLength() const = 0; + virtual int ThumbLength() const = 0; virtual gfx::Rect BackButtonRect() const; virtual gfx::Rect ForwardButtonRect() const; + virtual gfx::Rect BackTrackRect() const; + virtual gfx::Rect ForwardTrackRect() const; virtual ScrollbarPart IdentifyScrollbarPart( const gfx::PointF position_in_widget) const; // Only PaintedOverlayScrollbar(Aura Overlay Scrollbar) need to know @@ -82,8 +86,6 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl { bool is_overlay); ~ScrollbarLayerImplBase() override; - virtual int ThumbLength() const = 0; - virtual float TrackLength() const = 0; virtual int TrackStart() const = 0; // Indicates whether the thumb length can be changed without going back to the // main thread. diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc index c46e3eef674..3320d74868f 100644 --- a/chromium/cc/layers/scrollbar_layer_unittest.cc +++ b/chromium/cc/layers/scrollbar_layer_unittest.cc @@ -414,10 +414,13 @@ TEST_F(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) { root_layer->SetScrollOffset(gfx::ScrollOffset(0, 0)); scrollbar_layer->SetBounds(gfx::Size(70, 10)); scrollbar_layer->SetScrollElementId(root_layer->element_id()); + + // The track_rect should be relative to the scrollbar's origin. scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10)); - scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); + scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(10, 10, 50, 10)); scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10); scrollbar_layer->fake_scrollbar()->set_thumb_length(4); + LayerImpl* root_layer_impl = nullptr; PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr; @@ -452,10 +455,13 @@ TEST_F(ScrollbarLayerTest, ThumbRect) { root_layer->SetScrollOffset(gfx::ScrollOffset(0, 0)); scrollbar_layer->SetBounds(gfx::Size(70, 10)); scrollbar_layer->SetScrollElementId(root_layer->element_id()); + + // The track_rect should be relative to the scrollbar's origin. scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10)); - scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); + scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(10, 10, 50, 10)); scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10); scrollbar_layer->fake_scrollbar()->set_thumb_length(4); + layer_tree_host_->UpdateLayers(); LayerImpl* root_layer_impl = nullptr; PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr; @@ -493,7 +499,7 @@ TEST_F(ScrollbarLayerTest, ThumbRect) { // Shrink the scrollbar layer to cover only the track. scrollbar_layer->SetBounds(gfx::Size(50, 10)); scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10)); - scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); + scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 10, 50, 10)); UPDATE_AND_EXTRACT_LAYER_POINTERS(); EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(), @@ -502,7 +508,7 @@ TEST_F(ScrollbarLayerTest, ThumbRect) { // Shrink the track in the non-scrolling dimension so that it only covers the // middle third of the scrollbar layer (this does not affect the thumb // position). - scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 12, 50, 6)); + scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 12, 50, 6)); UPDATE_AND_EXTRACT_LAYER_POINTERS(); EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(), @@ -582,7 +588,7 @@ TEST_F(ScrollbarLayerTest, SolidColorDrawQuads) { const auto& quads = render_pass->quad_list; ASSERT_EQ(1u, quads.size()); - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material); + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material); EXPECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect); } @@ -597,7 +603,7 @@ TEST_F(ScrollbarLayerTest, SolidColorDrawQuads) { const auto& quads = render_pass->quad_list; ASSERT_EQ(1u, quads.size()); - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material); + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material); EXPECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect); } @@ -612,7 +618,7 @@ TEST_F(ScrollbarLayerTest, SolidColorDrawQuads) { const auto& quads = render_pass->quad_list; ASSERT_EQ(1u, quads.size()); - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material); + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material); EXPECT_EQ(gfx::Rect(1, 0, 98, 3), quads.front()->rect); } } @@ -669,7 +675,7 @@ TEST_F(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) { const auto& quads = render_pass->quad_list; ASSERT_EQ(1u, quads.size()); - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material); + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material); EXPECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect); } } diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.cc b/chromium/cc/layers/solid_color_scrollbar_layer.cc index c73f241a7ad..e91ad78fd38 100644 --- a/chromium/cc/layers/solid_color_scrollbar_layer.cc +++ b/chromium/cc/layers/solid_color_scrollbar_layer.cc @@ -76,6 +76,8 @@ void SolidColorScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { SolidColorScrollbarLayerImpl* scrollbar_layer = static_cast<SolidColorScrollbarLayerImpl*>(layer); + DCHECK(!scrollbar_layer->HitTestable()); + scrollbar_layer->SetScrollElementId( solid_color_scrollbar_layer_inputs_.scroll_element_id); } @@ -96,4 +98,10 @@ void SolidColorScrollbarLayer::SetScrollElementId(ElementId element_id) { SetNeedsCommit(); } +bool SolidColorScrollbarLayer::HitTestable() const { + // Android scrollbars can't be interacted with by user input. They should + // avoid hit testing so we don't enter any scrollbar scrolling code paths. + return false; +} + } // namespace cc diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.h b/chromium/cc/layers/solid_color_scrollbar_layer.h index 67c4adb2463..0b937b48b09 100644 --- a/chromium/cc/layers/solid_color_scrollbar_layer.h +++ b/chromium/cc/layers/solid_color_scrollbar_layer.h @@ -34,6 +34,8 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface, void SetNeedsDisplayRect(const gfx::Rect& rect) override; + bool HitTestable() const override; + // ScrollbarLayerInterface void SetScrollElementId(ElementId element_id) override; diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc index 2ab831c59dd..b96e4bc3b68 100644 --- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc +++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc @@ -58,6 +58,7 @@ SolidColorScrollbarLayerImpl::SolidColorScrollbarLayerImpl( void SolidColorScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) { ScrollbarLayerImplBase::PushPropertiesTo(layer); + DCHECK(!layer->HitTestable()); } int SolidColorScrollbarLayerImpl::ThumbThickness() const { diff --git a/chromium/cc/layers/surface_layer.cc b/chromium/cc/layers/surface_layer.cc index f2750e47cf6..ec1c8646a40 100644 --- a/chromium/cc/layers/surface_layer.cc +++ b/chromium/cc/layers/surface_layer.cc @@ -113,6 +113,10 @@ void SurfaceLayer::SetHasPointerEventsNone(bool has_pointer_events_none) { SetNeedsCommit(); } +void SurfaceLayer::SetIsReflection(bool is_reflection) { + is_reflection_ = true; +} + void SurfaceLayer::SetMayContainVideo(bool may_contain_video) { may_contain_video_ = may_contain_video; } @@ -150,6 +154,7 @@ void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) { // Unless the client explicitly calls SetSurfaceId again after this // commit, don't block on |surface_range_| again. deadline_in_frames_ = 0u; + layer_impl->SetIsReflection(is_reflection_); layer_impl->SetStretchContentToFillBounds(stretch_content_to_fill_bounds_); layer_impl->SetSurfaceHitTestable(surface_hit_testable_); layer_impl->SetHasPointerEventsNone(has_pointer_events_none_); diff --git a/chromium/cc/layers/surface_layer.h b/chromium/cc/layers/surface_layer.h index 9d15812f813..30e329a7ab9 100644 --- a/chromium/cc/layers/surface_layer.h +++ b/chromium/cc/layers/surface_layer.h @@ -44,7 +44,9 @@ class CC_EXPORT SurfaceLayer : public Layer { void SetHasPointerEventsNone(bool has_pointer_events_none); - void SetMayContainVideo(bool); + void SetIsReflection(bool is_reflection); + + void SetMayContainVideo(bool may_contain_video); // Layer overrides. std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; @@ -90,6 +92,9 @@ class CC_EXPORT SurfaceLayer : public Layer { // TODO(sunxd): consider renaming it to oopif_has_pointer_events_none_ for // disambiguation. bool has_pointer_events_none_ = false; + + // This surface layer is reflecting the root surface of another display. + bool is_reflection_ = false; }; } // namespace cc diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc index 299d343bcf7..9d4a37a49d5 100644 --- a/chromium/cc/layers/surface_layer_impl.cc +++ b/chromium/cc/layers/surface_layer_impl.cc @@ -83,6 +83,14 @@ void SurfaceLayerImpl::SetHasPointerEventsNone(bool has_pointer_events_none) { NoteLayerPropertyChanged(); } +void SurfaceLayerImpl::SetIsReflection(bool is_reflection) { + if (is_reflection_ == is_reflection) + return; + + is_reflection_ = is_reflection; + NoteLayerPropertyChanged(); +} + void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) { LayerImpl::PushPropertiesTo(layer); SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer); @@ -93,6 +101,7 @@ void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) { layer_impl->SetStretchContentToFillBounds(stretch_content_to_fill_bounds_); layer_impl->SetSurfaceHitTestable(surface_hit_testable_); layer_impl->SetHasPointerEventsNone(has_pointer_events_none_); + layer_impl->SetIsReflection(is_reflection_); } bool SurfaceLayerImpl::WillDraw( @@ -108,17 +117,40 @@ bool SurfaceLayerImpl::WillDraw( update_submission_state_callback_.Run(will_draw); } - return surface_range_.IsValid() && will_draw; + return will_draw; } void SurfaceLayerImpl::AppendQuads(viz::RenderPass* render_pass, AppendQuadsData* append_quads_data) { AppendRainbowDebugBorder(render_pass); - if (!surface_range_.IsValid()) + + float device_scale_factor = layer_tree_impl()->device_scale_factor(); + + gfx::Rect quad_rect(gfx::ScaleToEnclosingRect( + gfx::Rect(bounds()), device_scale_factor, device_scale_factor)); + gfx::Rect visible_quad_rect = + draw_properties().occlusion_in_content_space.GetUnoccludedContentRect( + gfx::Rect(bounds())); + + visible_quad_rect = gfx::ScaleToEnclosingRect( + visible_quad_rect, device_scale_factor, device_scale_factor); + visible_quad_rect = gfx::IntersectRects(quad_rect, visible_quad_rect); + + if (visible_quad_rect.IsEmpty()) return; - auto* primary = CreateSurfaceDrawQuad(render_pass, surface_range_); - if (primary) { + viz::SharedQuadState* shared_quad_state = + render_pass->CreateAndAppendSharedQuadState(); + + PopulateScaledSharedQuadState(shared_quad_state, device_scale_factor, + device_scale_factor, contents_opaque()); + + if (surface_range_.IsValid()) { + auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>(); + quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, + surface_range_, background_color(), + stretch_content_to_fill_bounds_, has_pointer_events_none_); + quad->is_reflection = is_reflection_; // Add the primary surface ID as a dependency. append_quads_data->activation_dependencies.push_back(surface_range_.end()); if (deadline_in_frames_) { @@ -129,7 +161,13 @@ void SurfaceLayerImpl::AppendQuads(viz::RenderPass* render_pass, } else { append_quads_data->use_default_lower_bound_deadline = true; } + } else { + auto* quad = + render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>(); + quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, + background_color(), false /* force_anti_aliasing_off */); } + // Unless the client explicitly specifies otherwise, don't block on // |surface_range_| more than once. deadline_in_frames_ = 0u; @@ -144,42 +182,6 @@ gfx::Rect SurfaceLayerImpl::GetEnclosingRectInTargetSpace() const { layer_tree_impl()->device_scale_factor()); } -viz::SurfaceDrawQuad* SurfaceLayerImpl::CreateSurfaceDrawQuad( - viz::RenderPass* render_pass, - const viz::SurfaceRange& surface_range) { - DCHECK(surface_range.end().is_valid()); - - float device_scale_factor = layer_tree_impl()->device_scale_factor(); - - gfx::Rect quad_rect(gfx::ScaleToEnclosingRect( - gfx::Rect(bounds()), device_scale_factor, device_scale_factor)); - gfx::Rect visible_quad_rect = - draw_properties().occlusion_in_content_space.GetUnoccludedContentRect( - gfx::Rect(bounds())); - - visible_quad_rect = gfx::ScaleToEnclosingRect( - visible_quad_rect, device_scale_factor, device_scale_factor); - visible_quad_rect = gfx::IntersectRects(quad_rect, visible_quad_rect); - - if (visible_quad_rect.IsEmpty()) - return nullptr; - - viz::SharedQuadState* shared_quad_state = - render_pass->CreateAndAppendSharedQuadState(); - - PopulateScaledSharedQuadState(shared_quad_state, device_scale_factor, - device_scale_factor, contents_opaque()); - - auto* surface_draw_quad = - render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>(); - surface_draw_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, - surface_range, background_color(), - stretch_content_to_fill_bounds_, - has_pointer_events_none_); - - return surface_draw_quad; -} - void SurfaceLayerImpl::GetDebugBorderProperties(SkColor* color, float* width) const { *color = DebugColors::SurfaceLayerBorderColor(); diff --git a/chromium/cc/layers/surface_layer_impl.h b/chromium/cc/layers/surface_layer_impl.h index 1c3849f95a0..97b1f6ce9d0 100644 --- a/chromium/cc/layers/surface_layer_impl.h +++ b/chromium/cc/layers/surface_layer_impl.h @@ -61,6 +61,9 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl { void SetHasPointerEventsNone(bool has_pointer_events_none); bool has_pointer_events_none() const { return has_pointer_events_none_; } + void SetIsReflection(bool is_reflection); + bool is_reflection() const { return is_reflection_; } + // LayerImpl overrides. std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; void PushPropertiesTo(LayerImpl* layer) override; @@ -75,10 +78,6 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl { SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id, UpdateSubmissionStateCB); private: - viz::SurfaceDrawQuad* CreateSurfaceDrawQuad( - viz::RenderPass* render_pass, - const viz::SurfaceRange& surface_range); - void GetDebugBorderProperties(SkColor* color, float* width) const override; void AppendRainbowDebugBorder(viz::RenderPass* render_pass); void AsValueInto(base::trace_event::TracedValue* dict) const override; @@ -91,6 +90,7 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl { bool stretch_content_to_fill_bounds_ = false; bool surface_hit_testable_ = false; bool has_pointer_events_none_ = false; + bool is_reflection_ = false; bool will_draw_ = false; }; diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc index 9d2e07594a9..6944908fbb2 100644 --- a/chromium/cc/layers/texture_layer_impl.cc +++ b/chromium/cc/layers/texture_layer_impl.cc @@ -110,15 +110,9 @@ void TextureLayerImpl::AppendQuads(viz::RenderPass* render_pass, LayerTreeFrameSink* sink = layer_tree_impl()->layer_tree_frame_sink(); for (const auto& pair : to_register_bitmaps_) { - // Because we may want to notify a display compositor about this - // base::SharedMemory more than one time, we need to be able to keep - // making handles to share with it, so we can't close the - // base::SharedMemory. - mojo::ScopedSharedBufferHandle handle = - viz::bitmap_allocation::DuplicateWithoutClosingMappedBitmap( - pair.second->shared_memory(), pair.second->size(), - pair.second->format()); - sink->DidAllocateSharedBitmap(std::move(handle), pair.first); + sink->DidAllocateSharedBitmap(viz::bitmap_allocation::ToMojoHandle( + pair.second->shared_region().Duplicate()), + pair.first); } // All |to_register_bitmaps_| have been registered above, so we can move them // all to the |registered_bitmaps_|. diff --git a/chromium/cc/layers/texture_layer_impl_unittest.cc b/chromium/cc/layers/texture_layer_impl_unittest.cc index eaad5053f05..13a352cd982 100644 --- a/chromium/cc/layers/texture_layer_impl_unittest.cc +++ b/chromium/cc/layers/texture_layer_impl_unittest.cc @@ -56,7 +56,8 @@ TEST(TextureLayerImplTest, Occlusion) { auto resource = viz::TransferableResource::MakeGL( gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(gpu::CommandBufferNamespace::GPU_IO, - gpu::CommandBufferId::FromUnsafeValue(0x234), 0x456)); + gpu::CommandBufferId::FromUnsafeValue(0x234), 0x456), + layer_size, false /* is_overlay_candidate */); TextureLayerImpl* texture_layer_impl = impl.AddChildToRoot<TextureLayerImpl>(); diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc index 64697a6c848..7aec79fdf9a 100644 --- a/chromium/cc/layers/texture_layer_unittest.cc +++ b/chromium/cc/layers/texture_layer_unittest.cc @@ -129,11 +129,13 @@ struct CommonResourceObjects { base::Unretained(&mock_callback_), mailbox_name2_); const uint32_t arbitrary_target1 = GL_TEXTURE_2D; const uint32_t arbitrary_target2 = GL_TEXTURE_EXTERNAL_OES; + gfx::Size size(128, 128); resource1_ = viz::TransferableResource::MakeGL( - mailbox_name1_, GL_LINEAR, arbitrary_target1, sync_token1_); + mailbox_name1_, GL_LINEAR, arbitrary_target1, sync_token1_, size, + false /* is_overlay_candidate */); resource2_ = viz::TransferableResource::MakeGL( - mailbox_name2_, GL_LINEAR, arbitrary_target2, sync_token2_); - gfx::Size size(128, 128); + mailbox_name2_, GL_LINEAR, arbitrary_target2, sync_token2_, size, + false /* is_overlay_candidate */); shared_bitmap_id_ = viz::SharedBitmap::GenerateId(); sw_release_callback_ = base::BindRepeating( &MockReleaseCallback::Release2, base::Unretained(&mock_callback_), @@ -686,9 +688,11 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest { &TextureLayerImplWithMailboxThreadedCallback::ReleaseCallback, base::Unretained(this), mailbox_char)); + const gfx::Size size(64, 64); auto resource = viz::TransferableResource::MakeGL( MailboxFromChar(mailbox_char), GL_LINEAR, GL_TEXTURE_2D, - SyncTokenFromUInt(static_cast<uint32_t>(mailbox_char))); + SyncTokenFromUInt(static_cast<uint32_t>(mailbox_char)), size, + false /* is_overlay_candidate */); layer_->SetTransferableResource(resource, std::move(callback)); // Damage the layer so we send a new frame with the new resource to the // Display compositor. @@ -763,8 +767,10 @@ class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest { viz::SingleReleaseCallback::Create(base::BindOnce( &TextureLayerMailboxIsActivatedDuringCommit::ReleaseCallback, base::Unretained(this), sync_token)); + constexpr gfx::Size size(64, 64); auto resource = viz::TransferableResource::MakeGL( - MailboxFromChar(mailbox_char), GL_LINEAR, GL_TEXTURE_2D, sync_token); + MailboxFromChar(mailbox_char), GL_LINEAR, GL_TEXTURE_2D, sync_token, + size, false /* is_overlay_candidate */); layer_->SetTransferableResource(resource, std::move(callback)); } @@ -1023,9 +1029,10 @@ class TextureLayerNoExtraCommitForMailboxTest return true; } - *resource = viz::TransferableResource::MakeGL(MailboxFromChar('1'), - GL_LINEAR, GL_TEXTURE_2D, - SyncTokenFromUInt(0x123)); + constexpr gfx::Size size(64, 64); + *resource = viz::TransferableResource::MakeGL( + MailboxFromChar('1'), GL_LINEAR, GL_TEXTURE_2D, + SyncTokenFromUInt(0x123), size, false /* is_overlay_candidate */); *release_callback = viz::SingleReleaseCallback::Create(base::BindOnce( &TextureLayerNoExtraCommitForMailboxTest::ResourceReleased, base::Unretained(this))); @@ -1107,9 +1114,11 @@ class TextureLayerChangeInvisibleMailboxTest } viz::TransferableResource MakeResource(char name) { + constexpr gfx::Size size(64, 64); return viz::TransferableResource::MakeGL( MailboxFromChar(name), GL_LINEAR, GL_TEXTURE_2D, - SyncTokenFromUInt(static_cast<uint32_t>(name))); + SyncTokenFromUInt(static_cast<uint32_t>(name)), size, + false /* is_overlay_candidate */); } void ResourceReleased(const gpu::SyncToken& sync_token, bool lost_resource) { @@ -1216,8 +1225,10 @@ class TextureLayerReleaseResourcesBase SharedBitmapIdRegistrar* bitmap_registrar, viz::TransferableResource* resource, std::unique_ptr<viz::SingleReleaseCallback>* release_callback) override { + constexpr gfx::Size size(64, 64); *resource = viz::TransferableResource::MakeGL( - MailboxFromChar('1'), GL_LINEAR, GL_TEXTURE_2D, SyncTokenFromUInt(1)); + MailboxFromChar('1'), GL_LINEAR, GL_TEXTURE_2D, SyncTokenFromUInt(1), + size, false /* is_overlay_candidate */); *release_callback = viz::SingleReleaseCallback::Create( base::BindOnce(&TextureLayerReleaseResourcesBase::ResourceReleased, base::Unretained(this))); @@ -1293,9 +1304,11 @@ class TextureLayerWithResourceMainThreadDeleted : public LayerTreeTest { viz::SingleReleaseCallback::Create(base::BindOnce( &TextureLayerWithResourceMainThreadDeleted::ReleaseCallback, base::Unretained(this))); + constexpr gfx::Size size(64, 64); auto resource = viz::TransferableResource::MakeGL( MailboxFromChar(mailbox_char), GL_LINEAR, GL_TEXTURE_2D, - SyncTokenFromUInt(static_cast<uint32_t>(mailbox_char))); + SyncTokenFromUInt(static_cast<uint32_t>(mailbox_char)), size, + false /* is_overlay_candidate */); layer_->SetTransferableResource(resource, std::move(callback)); } @@ -1363,9 +1376,11 @@ class TextureLayerWithResourceImplThreadDeleted : public LayerTreeTest { viz::SingleReleaseCallback::Create(base::BindOnce( &TextureLayerWithResourceImplThreadDeleted::ReleaseCallback, base::Unretained(this))); + constexpr gfx::Size size(64, 64); auto resource = viz::TransferableResource::MakeGL( MailboxFromChar(mailbox_char), GL_LINEAR, GL_TEXTURE_2D, - SyncTokenFromUInt(static_cast<uint32_t>(mailbox_char))); + SyncTokenFromUInt(static_cast<uint32_t>(mailbox_char)), size, + false /* is_overlay_candidate */); layer_->SetTransferableResource(resource, std::move(callback)); } @@ -1518,7 +1533,7 @@ class SoftwareTextureLayerSwitchTreesTest : public SoftwareTextureLayerTest { id_ = viz::SharedBitmap::GenerateId(); bitmap_ = base::MakeRefCounted<CrossThreadSharedBitmap>( - id_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size, + id_, viz::bitmap_allocation::AllocateSharedBitmap(size, format), size, format); } @@ -1622,7 +1637,7 @@ class SoftwareTextureLayerPurgeMemoryTest : public SoftwareTextureLayerTest { id_ = viz::SharedBitmap::GenerateId(); bitmap_ = base::MakeRefCounted<CrossThreadSharedBitmap>( - id_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size, + id_, viz::bitmap_allocation::AllocateSharedBitmap(size, format), size, format); } @@ -1702,11 +1717,11 @@ class SoftwareTextureLayerMultipleRegisterTest id1_ = viz::SharedBitmap::GenerateId(); bitmap1_ = base::MakeRefCounted<CrossThreadSharedBitmap>( - id1_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size, + id1_, viz::bitmap_allocation::AllocateSharedBitmap(size, format), size, format); id2_ = viz::SharedBitmap::GenerateId(); bitmap2_ = base::MakeRefCounted<CrossThreadSharedBitmap>( - id2_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size, + id2_, viz::bitmap_allocation::AllocateSharedBitmap(size, format), size, format); } @@ -1796,11 +1811,11 @@ class SoftwareTextureLayerRegisterUnregisterTest id1_ = viz::SharedBitmap::GenerateId(); bitmap1_ = base::MakeRefCounted<CrossThreadSharedBitmap>( - id1_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size, + id1_, viz::bitmap_allocation::AllocateSharedBitmap(size, format), size, format); id2_ = viz::SharedBitmap::GenerateId(); bitmap2_ = base::MakeRefCounted<CrossThreadSharedBitmap>( - id2_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size, + id2_, viz::bitmap_allocation::AllocateSharedBitmap(size, format), size, format); } @@ -1885,7 +1900,7 @@ class SoftwareTextureLayerLoseFrameSinkTest : public SoftwareTextureLayerTest { id_ = viz::SharedBitmap::GenerateId(); bitmap_ = base::MakeRefCounted<CrossThreadSharedBitmap>( - id_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size, + id_, viz::bitmap_allocation::AllocateSharedBitmap(size, format), size, format); } @@ -2000,7 +2015,7 @@ class SoftwareTextureLayerUnregisterRegisterTest id_ = viz::SharedBitmap::GenerateId(); bitmap_ = base::MakeRefCounted<CrossThreadSharedBitmap>( - id_, viz::bitmap_allocation::AllocateMappedBitmap(size, format), size, + id_, viz::bitmap_allocation::AllocateSharedBitmap(size, format), size, format); } diff --git a/chromium/cc/layers/video_frame_provider.h b/chromium/cc/layers/video_frame_provider.h index af413093231..7ae08903b6b 100644 --- a/chromium/cc/layers/video_frame_provider.h +++ b/chromium/cc/layers/video_frame_provider.h @@ -93,6 +93,10 @@ class CC_EXPORT VideoFrameProvider { // frame missed its intended deadline. virtual void PutCurrentFrame() = 0; + // Returns the interval at which the provider expects to have new frames for + // the client. + virtual base::TimeDelta GetPreferredRenderInterval() = 0; + protected: virtual ~VideoFrameProvider() {} }; diff --git a/chromium/cc/layers/video_layer.h b/chromium/cc/layers/video_layer.h index 0ae52c85ee1..45cacd34d0f 100644 --- a/chromium/cc/layers/video_layer.h +++ b/chromium/cc/layers/video_layer.h @@ -8,7 +8,7 @@ #include "base/callback.h" #include "cc/cc_export.h" #include "cc/layers/layer.h" -#include "media/base/video_rotation.h" +#include "media/base/video_transformation.h" namespace media { class VideoFrame; } diff --git a/chromium/cc/layers/video_layer_impl.h b/chromium/cc/layers/video_layer_impl.h index 0f715c7d319..5d3aa87a9de 100644 --- a/chromium/cc/layers/video_layer_impl.h +++ b/chromium/cc/layers/video_layer_impl.h @@ -10,7 +10,7 @@ #include "cc/cc_export.h" #include "cc/layers/layer_impl.h" #include "components/viz/common/resources/release_callback.h" -#include "media/base/video_rotation.h" +#include "media/base/video_transformation.h" namespace media { class VideoFrame; diff --git a/chromium/cc/layers/video_layer_impl_unittest.cc b/chromium/cc/layers/video_layer_impl_unittest.cc index a8ba9a7ccdd..e70372f5b65 100644 --- a/chromium/cc/layers/video_layer_impl_unittest.cc +++ b/chromium/cc/layers/video_layer_impl_unittest.cc @@ -328,7 +328,7 @@ TEST(VideoLayerImplTest, SoftwareVideoFrameGeneratesYUVQuad) { EXPECT_EQ(1u, impl.quad_list().size()); const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0); - ASSERT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material); + ASSERT_EQ(viz::DrawQuad::Material::kYuvVideoContent, draw_quad->material); const auto* yuv_draw_quad = static_cast<const viz::YUVVideoDrawQuad*>(draw_quad); @@ -366,7 +366,7 @@ TEST(VideoLayerImplTest, HibitSoftwareVideoFrameGeneratesYUVQuad) { EXPECT_EQ(1u, impl.quad_list().size()); const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0); - ASSERT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material); + ASSERT_EQ(viz::DrawQuad::Material::kYuvVideoContent, draw_quad->material); const auto* yuv_draw_quad = static_cast<const viz::YUVVideoDrawQuad*>(draw_quad); @@ -408,7 +408,7 @@ TEST(VideoLayerImplTest, NativeYUVFrameGeneratesYUVQuad) { EXPECT_EQ(1u, impl.quad_list().size()); const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0); - ASSERT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material); + ASSERT_EQ(viz::DrawQuad::Material::kYuvVideoContent, draw_quad->material); const auto* yuv_draw_quad = static_cast<const viz::YUVVideoDrawQuad*>(draw_quad); @@ -451,7 +451,7 @@ TEST(VideoLayerImplTest, NativeARGBFrameGeneratesTextureQuad) { EXPECT_EQ(1u, impl.quad_list().size()); const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0); - ASSERT_EQ(viz::DrawQuad::TEXTURE_CONTENT, draw_quad->material); + ASSERT_EQ(viz::DrawQuad::Material::kTextureContent, draw_quad->material); const viz::TextureDrawQuad* texture_draw_quad = viz::TextureDrawQuad::MaterialCast(draw_quad); diff --git a/chromium/cc/layers/viewport.cc b/chromium/cc/layers/viewport.cc index c8985f23b49..8bbe7293b32 100644 --- a/chromium/cc/layers/viewport.cc +++ b/chromium/cc/layers/viewport.cc @@ -34,7 +34,7 @@ void Viewport::Pan(const gfx::Vector2dF& delta) { host_impl_->active_tree()); } -Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta, +Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& physical_delta, const gfx::Point& viewport_point, bool is_direct_manipulation, bool affect_browser_controls, @@ -42,28 +42,30 @@ Viewport::ScrollResult Viewport::ScrollBy(const gfx::Vector2dF& delta, if (!OuterScrollNode()) return ScrollResult(); - gfx::Vector2dF content_delta = delta; + gfx::Vector2dF scroll_node_delta = physical_delta; - if (affect_browser_controls && ShouldBrowserControlsConsumeScroll(delta)) - content_delta -= ScrollBrowserControls(delta); + if (affect_browser_controls && + ShouldBrowserControlsConsumeScroll(physical_delta)) + scroll_node_delta -= ScrollBrowserControls(physical_delta); - gfx::Vector2dF pending_content_delta = content_delta; + gfx::Vector2dF pending_scroll_node_delta = scroll_node_delta; // Attempt to scroll inner viewport first. - pending_content_delta -= host_impl_->ScrollSingleNode( - InnerScrollNode(), pending_content_delta, viewport_point, + pending_scroll_node_delta -= host_impl_->ScrollSingleNode( + InnerScrollNode(), pending_scroll_node_delta, viewport_point, is_direct_manipulation, &scroll_tree()); // Now attempt to scroll the outer viewport. if (scroll_outer_viewport) { - pending_content_delta -= host_impl_->ScrollSingleNode( - OuterScrollNode(), pending_content_delta, viewport_point, + pending_scroll_node_delta -= host_impl_->ScrollSingleNode( + OuterScrollNode(), pending_scroll_node_delta, viewport_point, is_direct_manipulation, &scroll_tree()); } ScrollResult result; - result.consumed_delta = delta - AdjustOverscroll(pending_content_delta); - result.content_scrolled_delta = content_delta - pending_content_delta; + result.consumed_delta = + physical_delta - AdjustOverscroll(pending_scroll_node_delta); + result.content_scrolled_delta = scroll_node_delta - pending_scroll_node_delta; return result; } diff --git a/chromium/cc/layers/viewport.h b/chromium/cc/layers/viewport.h index b5c00b80d08..9143b58b747 100644 --- a/chromium/cc/layers/viewport.h +++ b/chromium/cc/layers/viewport.h @@ -46,10 +46,12 @@ class CC_EXPORT Viewport { // Scrolls the viewport, applying the unique bubbling between the inner and // outer viewport unless the scroll_outer_viewport bit is off. Scrolls can be - // consumed by browser controls. - ScrollResult ScrollBy(const gfx::Vector2dF& delta, + // consumed by browser controls. The delta is in physical pixels, that is, it + // will be scaled by the page scale to ensure the content moves + // |physical_delta| number of pixels. + ScrollResult ScrollBy(const gfx::Vector2dF& physical_delta, const gfx::Point& viewport_point, - bool is_wheel_scroll, + bool is_direct_manipulation, bool affect_browser_controls, bool scroll_outer_viewport); diff --git a/chromium/cc/paint/discardable_image_map_unittest.cc b/chromium/cc/paint/discardable_image_map_unittest.cc index 2b9eee61fc1..8e4a0734995 100644 --- a/chromium/cc/paint/discardable_image_map_unittest.cc +++ b/chromium/cc/paint/discardable_image_map_unittest.cc @@ -56,11 +56,14 @@ class DiscardableImageMapTest : public testing::Test { const DiscardableImageMap& image_map, const gfx::Rect& rect) { std::vector<const DrawImage*> draw_image_ptrs; + // Choose a not-SRGB-and-not-invalid target color space to verify that it + // is passed correctly to the resulting DrawImages. + gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50(); image_map.GetDiscardableImagesInRect(rect, &draw_image_ptrs); std::vector<DrawImage> draw_images; for (const auto* image : draw_image_ptrs) - draw_images.push_back( - DrawImage(*image, 1.f, PaintImage::kDefaultFrameIndex)); + draw_images.push_back(DrawImage( + *image, 1.f, PaintImage::kDefaultFrameIndex, target_color_space)); std::vector<PositionScaleDrawImage> position_draw_images; std::vector<DrawImage> results; @@ -77,6 +80,7 @@ class DiscardableImageMapTest : public testing::Test { for (size_t i = 0; i < draw_images.size(); ++i) { EXPECT_TRUE(draw_images[i].paint_image() == position_draw_images[i].image); + EXPECT_EQ(draw_images[i].target_color_space(), target_color_space); } return position_draw_images; } diff --git a/chromium/cc/paint/draw_image.cc b/chromium/cc/paint/draw_image.cc index f7d5cbe86f7..8e920f6cce8 100644 --- a/chromium/cc/paint/draw_image.cc +++ b/chromium/cc/paint/draw_image.cc @@ -40,24 +40,28 @@ DrawImage::DrawImage(PaintImage image, const SkIRect& src_rect, SkFilterQuality filter_quality, const SkMatrix& matrix, - base::Optional<size_t> frame_index) + base::Optional<size_t> frame_index, + const base::Optional<gfx::ColorSpace>& color_space) : paint_image_(std::move(image)), src_rect_(src_rect), filter_quality_(filter_quality), - frame_index_(frame_index) { + frame_index_(frame_index), + target_color_space_(color_space) { matrix_is_decomposable_ = ExtractScale(matrix, &scale_); } DrawImage::DrawImage(const DrawImage& other, float scale_adjustment, - size_t frame_index) + size_t frame_index, + const gfx::ColorSpace& color_space) : paint_image_(other.paint_image_), src_rect_(other.src_rect_), filter_quality_(other.filter_quality_), scale_(SkSize::Make(other.scale_.width() * scale_adjustment, other.scale_.height() * scale_adjustment)), matrix_is_decomposable_(other.matrix_is_decomposable_), - frame_index_(frame_index) {} + frame_index_(frame_index), + target_color_space_(color_space) {} DrawImage::DrawImage(const DrawImage& other) = default; DrawImage::DrawImage(DrawImage&& other) = default; @@ -69,7 +73,8 @@ DrawImage& DrawImage::operator=(const DrawImage& other) = default; bool DrawImage::operator==(const DrawImage& other) const { return paint_image_ == other.paint_image_ && src_rect_ == other.src_rect_ && filter_quality_ == other.filter_quality_ && scale_ == other.scale_ && - matrix_is_decomposable_ == other.matrix_is_decomposable_; + matrix_is_decomposable_ == other.matrix_is_decomposable_ && + target_color_space_ == other.target_color_space_; } } // namespace cc diff --git a/chromium/cc/paint/draw_image.h b/chromium/cc/paint/draw_image.h index 63653793afe..c1c6957baa8 100644 --- a/chromium/cc/paint/draw_image.h +++ b/chromium/cc/paint/draw_image.h @@ -13,12 +13,13 @@ #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/core/SkRefCnt.h" +#include "ui/gfx/color_space.h" #include "ui/gfx/geometry/size_f.h" namespace cc { // A DrawImage is a logical snapshot in time and space of a PaintImage. It -// includes decisions about scaling, animation frame, etc. +// includes decisions about scaling, animation frame, final colorspace, etc. // It has not been decoded yet. DrawImage turns into DecodedDrawImage via // ImageDecodeCache::GetDecodedImageForDraw during playback. class CC_PAINT_EXPORT DrawImage { @@ -29,9 +30,14 @@ class CC_PAINT_EXPORT DrawImage { const SkIRect& src_rect, SkFilterQuality filter_quality, const SkMatrix& matrix, - base::Optional<size_t> frame_index = base::nullopt); - // Constructs a DrawImage from |other| by adjusting its scale and frame. - DrawImage(const DrawImage& other, float scale_adjustment, size_t frame_index); + base::Optional<size_t> frame_index = base::nullopt, + const base::Optional<gfx::ColorSpace>& color_space = base::nullopt); + // Constructs a DrawImage from |other| by adjusting its scale and setting a + // new color_space. + DrawImage(const DrawImage& other, + float scale_adjustment, + size_t frame_index, + const gfx::ColorSpace& color_space); DrawImage(const DrawImage& other); DrawImage(DrawImage&& other); ~DrawImage(); @@ -46,6 +52,10 @@ class CC_PAINT_EXPORT DrawImage { const SkIRect& src_rect() const { return src_rect_; } SkFilterQuality filter_quality() const { return filter_quality_; } bool matrix_is_decomposable() const { return matrix_is_decomposable_; } + const gfx::ColorSpace& target_color_space() const { + DCHECK(target_color_space_.has_value()); + return *target_color_space_; + } PaintImage::FrameKey frame_key() const { return paint_image_.GetKeyForFrame(frame_index()); } @@ -61,6 +71,7 @@ class CC_PAINT_EXPORT DrawImage { SkSize scale_; bool matrix_is_decomposable_; base::Optional<size_t> frame_index_; + base::Optional<gfx::ColorSpace> target_color_space_; }; } // namespace cc diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc index ff7b98fcc86..9e96fdbc3a3 100644 --- a/chromium/cc/paint/image_transfer_cache_entry.cc +++ b/chromium/cc/paint/image_transfer_cache_entry.cc @@ -5,7 +5,6 @@ #include "cc/paint/image_transfer_cache_entry.h" #include <utility> -#include <vector> #include "base/bind_helpers.h" #include "base/logging.h" @@ -16,6 +15,8 @@ #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkPixmap.h" +#include "third_party/skia/include/core/SkYUVAIndex.h" +#include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/skia/include/gpu/GrTypes.h" @@ -143,29 +144,67 @@ ServiceImageTransferCacheEntry::ServiceImageTransferCacheEntry( ServiceImageTransferCacheEntry& ServiceImageTransferCacheEntry::operator=( ServiceImageTransferCacheEntry&& other) = default; -bool ServiceImageTransferCacheEntry::BuildFromDecodedData( +bool ServiceImageTransferCacheEntry::BuildFromHardwareDecodedImage( GrContext* context, - base::span<const uint8_t> decoded_image, - size_t row_bytes, - const SkImageInfo& image_info, + std::vector<sk_sp<SkImage>> plane_images, + size_t buffer_byte_size, bool needs_mips, sk_sp<SkColorSpace> target_color_space) { context_ = context; - has_mips_ = needs_mips; - size_ = image_info.computeByteSize(row_bytes); - if (size_ == SIZE_MAX) + + // 1) Extract the planar textures from |plane_images|. + std::vector<GrBackendTexture> plane_backend_textures(3u); + DCHECK_EQ(3u, plane_images.size()); + for (size_t plane = 0; plane < 3u; plane++) { + plane_backend_textures[plane] = plane_images[plane]->getBackendTexture( + true /* flushPendingGrContextIO */); + if (!plane_backend_textures[plane].isValid()) { + DLOG(ERROR) << "Invalid backend texture found"; + return false; + } + if (needs_mips) { + // TODO(andrescj): generate mipmaps when requested. This will require some + // resource management: we either let Skia own the new textures or we take + // ownership and delete them in |destroy_callback|. + NOTIMPLEMENTED(); + } + } + plane_images_ = std::move(plane_images); + + // 2) Create a SkImage backed by the YUV textures extracted above. There are + // two assumptions here: + // + // - SkYUVColorSpace::kJPEG_SkYUVColorSpace is used for the YUV-to-RGB + // matrix. + // - The color space of the resulting image is sRGB. + // + // TODO(andrescj): support other YUV-to-RGB conversions and embedded color + // profiles. + SkYUVAIndex plane_indices[] = { + SkYUVAIndex{0, SkColorChannel::kR}, SkYUVAIndex{1, SkColorChannel::kR}, + SkYUVAIndex{2, SkColorChannel::kR}, SkYUVAIndex{-1, SkColorChannel::kR}}; + image_ = SkImage::MakeFromYUVATextures( + context_, SkYUVColorSpace::kJPEG_SkYUVColorSpace, + plane_backend_textures.data(), plane_indices, + plane_images_[0]->dimensions(), kTopLeft_GrSurfaceOrigin); + if (!image_) { + DLOG(ERROR) << "Could not create YUV SkImage"; return false; - DCHECK_LE(size_, decoded_image.size()); + } - uint32_t width; - uint32_t height; - if (!base::CheckedNumeric<int>(image_info.width()).AssignIfValid(&width) || - !base::CheckedNumeric<int>(image_info.height()).AssignIfValid(&height)) { + // 3) Perform color space conversion if necessary. + if (target_color_space) + image_ = image_->makeColorSpace(target_color_space); + if (!image_) { + DLOG(ERROR) << "Could not do color space conversion"; return false; } - return MakeSkImage(SkPixmap(image_info, decoded_image.data(), row_bytes), - width, height, target_color_space); + // 4) Fill out the rest of the information. + has_mips_ = false; + size_ = buffer_byte_size; + fits_on_gpu_ = true; + return true; } size_t ServiceImageTransferCacheEntry::CachedSize() const { @@ -276,6 +315,14 @@ void ServiceImageTransferCacheEntry::EnsureMips() { if (has_mips_) return; + if (!plane_images_.empty()) { + // TODO(andrescj): generate mipmaps for hardware-accelerated decodes when + // requested. This will require some resource management: we either let Skia + // own the new textures or we take ownership and delete them in + // |destroy_callback_|. + NOTIMPLEMENTED(); + } + has_mips_ = true; // TODO(ericrk): consider adding in the DeleteSkImageAndPreventCaching // optimization from GpuImageDecodeCache where we forcefully remove the diff --git a/chromium/cc/paint/image_transfer_cache_entry.h b/chromium/cc/paint/image_transfer_cache_entry.h index 5385c5b741f..e55a60d894f 100644 --- a/chromium/cc/paint/image_transfer_cache_entry.h +++ b/chromium/cc/paint/image_transfer_cache_entry.h @@ -8,6 +8,8 @@ #include <stddef.h> #include <stdint.h> +#include <vector> + #include "base/atomic_sequence_num.h" #include "base/containers/span.h" #include "cc/paint/transfer_cache_entry.h" @@ -16,7 +18,6 @@ class GrContext; class SkColorSpace; class SkImage; -struct SkImageInfo; class SkPixmap; namespace cc { @@ -60,21 +61,35 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry ServiceImageTransferCacheEntry& operator=( ServiceImageTransferCacheEntry&& other); - // Populates this entry using |decoded_image| described by |row_bytes| and - // |image_info|. The image is uploaded to the GPU if its dimensions are both - // at most |context_|->maxTextureSize(). - bool BuildFromDecodedData(GrContext* context, - base::span<const uint8_t> decoded_image, - size_t row_bytes, - const SkImageInfo& image_info, - bool needs_mips, - sk_sp<SkColorSpace> target_color_space); + // Populates this entry using the result of a hardware decode. The assumption + // is that |plane_images| are backed by textures that are in turn backed by a + // buffer (dmabuf in Chrome OS) containing the planes of the decoded image. + // |buffer_byte_size| is the size of the buffer. We assume the following: + // + // - |plane_images| represents a YUV 4:2:0 triplanar image. + // - The backing textures don't have mipmaps. We will generate the mipmaps if + // |needs_mips| is true. + // - The conversion from YUV to RGB will be performed assuming a JPEG image. + // - The colorspace of the resulting RGB image is sRGB. We will convert from + // this to |target_color_space| (if non-null). + // + // Returns true if the entry can be built, false otherwise. + // + // TODO(andrescj): actually generate the mipmaps when |needs_mips| is true. + bool BuildFromHardwareDecodedImage(GrContext* context, + std::vector<sk_sp<SkImage>> plane_images, + size_t buffer_byte_size, + bool needs_mips, + sk_sp<SkColorSpace> target_color_space); // ServiceTransferCacheEntry implementation: size_t CachedSize() const final; bool Deserialize(GrContext* context, base::span<const uint8_t> data) final; bool fits_on_gpu() const { return fits_on_gpu_; } + const std::vector<sk_sp<SkImage>>& plane_images() const { + return plane_images_; + } const sk_sp<SkImage>& image() const { return image_; } // Ensures the cached image has mips. @@ -87,6 +102,7 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry sk_sp<SkColorSpace> target_color_space); GrContext* context_ = nullptr; + std::vector<sk_sp<SkImage>> plane_images_; sk_sp<SkImage> image_; bool has_mips_ = false; size_t size_ = 0; diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc index c1cf6f7a30a..9af0e518b94 100644 --- a/chromium/cc/paint/oop_pixeltest.cc +++ b/chromium/cc/paint/oop_pixeltest.cc @@ -82,8 +82,16 @@ class OopPixelTest : public testing::Test, /*enable_oop_rasterization=*/false, /*support_locking=*/true); gpu::ContextResult result = gles2_context_provider_->BindToCurrentThread(); DCHECK_EQ(result, gpu::ContextResult::kSuccess); - CHECK_EQ(gles2_context_provider_->ContextCapabilities().max_texture_size, - raster_context_provider_->ContextCapabilities().max_texture_size); + const int gles2_max_texture_size = + gles2_context_provider_->ContextCapabilities().max_texture_size; + gpu_image_cache_.reset(new GpuImageDecodeCache( + gles2_context_provider_.get(), false, kRGBA_8888_SkColorType, + kWorkingSetSize, gles2_max_texture_size, + PaintImage::kDefaultGeneratorClientId)); + + const int raster_max_texture_size = + raster_context_provider_->ContextCapabilities().max_texture_size; + ASSERT_EQ(raster_max_texture_size, gles2_max_texture_size); } // gpu::raster::GrShaderCache::Client implementation. @@ -100,24 +108,12 @@ class OopPixelTest : public testing::Test, &gr_shader_cache_, &activity_flags_); gpu::ContextResult result = raster_context_provider_->BindToCurrentThread(); DCHECK_EQ(result, gpu::ContextResult::kSuccess); - } - - void CreateGpuImageCache(const gfx::ColorSpace& color_space) { - const int gles2_max_texture_size = - raster_context_provider_->ContextCapabilities().max_texture_size; - gpu_image_cache_.reset(new GpuImageDecodeCache( - gles2_context_provider_.get(), false, kRGBA_8888_SkColorType, - kWorkingSetSize, gles2_max_texture_size, - PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace())); - } - - void CreateOopImageCache(const gfx::ColorSpace& color_space) { const int raster_max_texture_size = raster_context_provider_->ContextCapabilities().max_texture_size; oop_image_cache_.reset(new GpuImageDecodeCache( raster_context_provider_.get(), true, kRGBA_8888_SkColorType, kWorkingSetSize, raster_max_texture_size, - PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace())); + PaintImage::kDefaultGeneratorClientId)); } class RasterOptions { @@ -156,13 +152,12 @@ class OopPixelTest : public testing::Test, SkBitmap Raster(scoped_refptr<DisplayItemList> display_item_list, const RasterOptions& options) { - CreateOopImageCache(options.color_space); - GURL url("https://example.com/foo"); TestInProcessContextProvider::ScopedRasterContextLock lock( raster_context_provider_.get(), url.possibly_invalid_spec().c_str()); PlaybackImageProvider image_provider(oop_image_cache_.get(), + options.color_space, PlaybackImageProvider::Settings()); gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL(); @@ -263,8 +258,6 @@ class OopPixelTest : public testing::Test, SkBitmap RasterExpectedBitmap( scoped_refptr<DisplayItemList> display_item_list, const RasterOptions& options) { - CreateGpuImageCache(options.color_space); - TestInProcessContextProvider::ScopedRasterContextLock lock( gles2_context_provider_.get()); gles2_context_provider_->GrContext()->resetContext(); @@ -286,6 +279,7 @@ class OopPixelTest : public testing::Test, options.shader_with_animated_images->set_has_animated_images(true); PlaybackImageProvider image_provider(gpu_image_cache_.get(), + options.color_space, PlaybackImageProvider::Settings()); auto raster_source = recording.CreateRasterSource(); diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc index 7c047cd1019..1359b6362e6 100644 --- a/chromium/cc/paint/paint_op_buffer.cc +++ b/chromium/cc/paint/paint_op_buffer.cc @@ -1207,22 +1207,9 @@ void DrawImageOp::RasterWithFlags(const DrawImageOp* op, const PaintFlags* flags, SkCanvas* canvas, const PlaybackParams& params) { - // TODO(crbug.com/931704): make sure to support the case where paint worklet - // generated images are used in other raster work such as canvas2d. + DCHECK(!op->image.IsPaintWorklet()); SkPaint paint = flags ? flags->ToSkPaint() : SkPaint(); - if (op->image.IsPaintWorklet()) { - DCHECK(params.image_provider); - ImageProvider::ScopedResult result = - params.image_provider->GetRasterContent(DrawImage(op->image)); - - DCHECK(IsScaleAdjustmentIdentity(op->scale_adjustment)); - SkAutoCanvasRestore save_restore(canvas, true); - canvas->translate(op->left, op->top); - result.paint_record()->Playback(canvas, params); - return; - } - if (!params.image_provider) { const bool needs_scale = !IsScaleAdjustmentIdentity(op->scale_adjustment); SkAutoCanvasRestore save_restore(canvas, needs_scale); @@ -1261,15 +1248,32 @@ void DrawImageOp::RasterWithFlags(const DrawImageOp* op, canvas->drawImage(decoded_image.image().get(), op->left, op->top, &paint); } -// TODO(xidachen): ensure paint worklet generated images are correctly handled. void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op, const PaintFlags* flags, SkCanvas* canvas, const PlaybackParams& params) { + SkPaint paint = flags ? flags->ToSkPaint() : SkPaint(); + // TODO(crbug.com/931704): make sure to support the case where paint worklet + // generated images are used in other raster work such as canvas2d. + if (op->image.IsPaintWorklet()) { + DCHECK(params.image_provider); + ImageProvider::ScopedResult result = + params.image_provider->GetRasterContent(DrawImage(op->image)); + + DCHECK(IsScaleAdjustmentIdentity(op->scale_adjustment)); + SkAutoCanvasRestore save_restore(canvas, true); + canvas->concat( + SkMatrix::MakeRectToRect(op->src, op->dst, SkMatrix::kFill_ScaleToFit)); + canvas->clipRect(op->src); + canvas->saveLayer(&op->src, &paint); + DCHECK(result && result.paint_record()); + result.paint_record()->Playback(canvas, params); + return; + } + // TODO(enne): Probably PaintCanvas should just use the skia enum directly. SkCanvas::SrcRectConstraint skconstraint = static_cast<SkCanvas::SrcRectConstraint>(op->constraint); - SkPaint paint = flags ? flags->ToSkPaint() : SkPaint(); if (!params.image_provider) { SkRect adjusted_src = AdjustSrcRectForScale(op->src, op->scale_adjustment); diff --git a/chromium/cc/paint/paint_op_buffer_fuzzer.cc b/chromium/cc/paint/paint_op_buffer_fuzzer.cc index d7fcd2edcb7..7e033867dfa 100644 --- a/chromium/cc/paint/paint_op_buffer_fuzzer.cc +++ b/chromium/cc/paint/paint_op_buffer_fuzzer.cc @@ -35,6 +35,7 @@ class FontSupport : public gpu::ServiceFontManager::Client { return it->second; return CreateBuffer(shm_id); } + void ReportProgress() override {} private: scoped_refptr<gpu::Buffer> CreateBuffer(uint32_t shm_id) { diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc index 0f6f7b74eca..f40f19a4ac6 100644 --- a/chromium/cc/paint/paint_op_buffer_unittest.cc +++ b/chromium/cc/paint/paint_op_buffer_unittest.cc @@ -439,6 +439,18 @@ TEST(PaintOpBufferTest, DiscardableImagesTracking_PaintWorkletImage) { EXPECT_TRUE(buffer.HasDiscardableImages()); } +TEST(PaintOpBufferTest, DiscardableImagesTracking_PaintWorkletImageRect) { + scoped_refptr<TestPaintWorkletInput> input = + base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(32.0f, 32.0f)); + PaintOpBuffer buffer; + PaintImage image = CreatePaintWorkletPaintImage(input); + SkRect src = SkRect::MakeEmpty(); + SkRect dst = SkRect::MakeEmpty(); + buffer.push<DrawImageRectOp>(image, src, dst, nullptr, + PaintCanvas::kStrict_SrcRectConstraint); + EXPECT_TRUE(buffer.HasDiscardableImages()); +} + TEST(PaintOpBufferTest, DiscardableImagesTracking_DrawImageRect) { PaintOpBuffer buffer; PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100)); @@ -2844,7 +2856,7 @@ MATCHER_P2(MatchesShader, flags, scale, "") { return true; } -TEST(PaintOpBufferTest, RasterPaintWorkletImage1) { +TEST(PaintOpBufferTest, RasterPaintWorkletImageRectBasicCase) { sk_sp<PaintOpBuffer> paint_worklet_buffer = sk_make_sp<PaintOpBuffer>(); PaintFlags noop_flags; SkRect savelayer_rect = SkRect::MakeXYWH(0, 0, 100, 100); @@ -2862,22 +2874,29 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImage1) { scoped_refptr<TestPaintWorkletInput> input = base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(100, 100)); PaintImage image = CreatePaintWorkletPaintImage(input); - blink_buffer.push<DrawImageOp>(image, 0.0f, 0.0f, nullptr); + SkRect src = SkRect::MakeXYWH(0, 0, 100, 100); + SkRect dst = SkRect::MakeXYWH(0, 0, 100, 100); + blink_buffer.push<DrawImageRectOp>(image, src, dst, nullptr, + PaintCanvas::kStrict_SrcRectConstraint); testing::StrictMock<MockCanvas> canvas; testing::Sequence s; EXPECT_CALL(canvas, willSave()).InSequence(s); + EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s); + EXPECT_CALL(canvas, willSave()).InSequence(s); EXPECT_CALL(canvas, didConcat(SkMatrix::MakeTrans(8.0f, 8.0f))); EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s); EXPECT_CALL(canvas, OnDrawRectWithColor(0u)); EXPECT_CALL(canvas, willRestore()).InSequence(s); EXPECT_CALL(canvas, willRestore()).InSequence(s); + EXPECT_CALL(canvas, willRestore()).InSequence(s); + EXPECT_CALL(canvas, willRestore()).InSequence(s); blink_buffer.Playback(&canvas, PlaybackParams(&provider)); } -TEST(PaintOpBufferTest, RasterPaintWorkletImage2) { +TEST(PaintOpBufferTest, RasterPaintWorkletImageRectTranslated) { sk_sp<PaintOpBuffer> paint_worklet_buffer = sk_make_sp<PaintOpBuffer>(); PaintFlags noop_flags; SkRect savelayer_rect = SkRect::MakeXYWH(0, 0, 10, 10); @@ -2897,13 +2916,107 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImage2) { scoped_refptr<TestPaintWorkletInput> input = base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(100, 100)); PaintImage image = CreatePaintWorkletPaintImage(input); - blink_buffer.push<DrawImageOp>(image, 5.0f, 7.0f, nullptr); + SkRect src = SkRect::MakeXYWH(0, 0, 100, 100); + SkRect dst = SkRect::MakeXYWH(5, 7, 100, 100); + blink_buffer.push<DrawImageRectOp>(image, src, dst, nullptr, + PaintCanvas::kStrict_SrcRectConstraint); testing::StrictMock<MockCanvas> canvas; testing::Sequence s; EXPECT_CALL(canvas, willSave()).InSequence(s); + EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s); + EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s); EXPECT_CALL(canvas, didConcat(SkMatrix::MakeTrans(5.0f, 7.0f))); + EXPECT_CALL(canvas, willSave()).InSequence(s); + EXPECT_CALL(canvas, didConcat(MatchesInvScale(scale_adjustment[0]))); + EXPECT_CALL(canvas, onDrawImage(NonLazyImage(), 0.0f, 0.0f, + MatchesQuality(quality[0]))); + EXPECT_CALL(canvas, willRestore()).InSequence(s); + EXPECT_CALL(canvas, willRestore()).InSequence(s); + EXPECT_CALL(canvas, willRestore()).InSequence(s); + EXPECT_CALL(canvas, willRestore()).InSequence(s); + + blink_buffer.Playback(&canvas, PlaybackParams(&provider)); +} + +TEST(PaintOpBufferTest, RasterPaintWorkletImageRectScaled) { + sk_sp<PaintOpBuffer> paint_worklet_buffer = sk_make_sp<PaintOpBuffer>(); + PaintFlags noop_flags; + SkRect savelayer_rect = SkRect::MakeXYWH(0, 0, 10, 10); + paint_worklet_buffer->push<SaveLayerOp>(&savelayer_rect, &noop_flags); + PaintFlags draw_flags; + draw_flags.setFilterQuality(kLow_SkFilterQuality); + PaintImage paint_image = CreateDiscardablePaintImage(gfx::Size(10, 10)); + paint_worklet_buffer->push<DrawImageOp>(paint_image, 0.0f, 0.0f, &draw_flags); + + std::vector<SkSize> src_rect_offset = {SkSize::MakeEmpty()}; + std::vector<SkSize> scale_adjustment = {SkSize::Make(0.2f, 0.2f)}; + std::vector<SkFilterQuality> quality = {kHigh_SkFilterQuality}; + MockImageProvider provider(src_rect_offset, scale_adjustment, quality); + provider.SetRecord(paint_worklet_buffer); + + PaintOpBuffer blink_buffer; + scoped_refptr<TestPaintWorkletInput> input = + base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(100, 100)); + PaintImage image = CreatePaintWorkletPaintImage(input); + SkRect src = SkRect::MakeXYWH(0, 0, 100, 100); + SkRect dst = SkRect::MakeXYWH(0, 0, 200, 150); + blink_buffer.push<DrawImageRectOp>(image, src, dst, nullptr, + PaintCanvas::kStrict_SrcRectConstraint); + + testing::StrictMock<MockCanvas> canvas; + testing::Sequence s; + + EXPECT_CALL(canvas, willSave()).InSequence(s); + EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s); + EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s); + EXPECT_CALL(canvas, didConcat(SkMatrix::MakeScale(2.f, 1.5f))); + EXPECT_CALL(canvas, willSave()).InSequence(s); + EXPECT_CALL(canvas, didConcat(MatchesInvScale(scale_adjustment[0]))); + EXPECT_CALL(canvas, onDrawImage(NonLazyImage(), 0.0f, 0.0f, + MatchesQuality(quality[0]))); + EXPECT_CALL(canvas, willRestore()).InSequence(s); + EXPECT_CALL(canvas, willRestore()).InSequence(s); + EXPECT_CALL(canvas, willRestore()).InSequence(s); + EXPECT_CALL(canvas, willRestore()).InSequence(s); + + blink_buffer.Playback(&canvas, PlaybackParams(&provider)); +} + +TEST(PaintOpBufferTest, RasterPaintWorkletImageRectClipped) { + sk_sp<PaintOpBuffer> paint_worklet_buffer = sk_make_sp<PaintOpBuffer>(); + PaintFlags noop_flags; + SkRect savelayer_rect = SkRect::MakeXYWH(0, 0, 60, 60); + paint_worklet_buffer->push<SaveLayerOp>(&savelayer_rect, &noop_flags); + PaintFlags draw_flags; + draw_flags.setFilterQuality(kLow_SkFilterQuality); + PaintImage paint_image = CreateDiscardablePaintImage(gfx::Size(10, 10)); + // One rect inside the src-rect, one outside. + paint_worklet_buffer->push<DrawImageOp>(paint_image, 0.0f, 0.0f, &draw_flags); + paint_worklet_buffer->push<DrawImageOp>(paint_image, 50.0f, 50.0f, + &draw_flags); + + std::vector<SkSize> src_rect_offset = {SkSize::MakeEmpty()}; + std::vector<SkSize> scale_adjustment = {SkSize::Make(0.2f, 0.2f)}; + std::vector<SkFilterQuality> quality = {kHigh_SkFilterQuality}; + MockImageProvider provider(src_rect_offset, scale_adjustment, quality); + provider.SetRecord(paint_worklet_buffer); + + PaintOpBuffer blink_buffer; + scoped_refptr<TestPaintWorkletInput> input = + base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(100, 100)); + PaintImage image = CreatePaintWorkletPaintImage(input); + SkRect src = SkRect::MakeXYWH(0, 0, 20, 20); + SkRect dst = SkRect::MakeXYWH(0, 0, 20, 20); + blink_buffer.push<DrawImageRectOp>(image, src, dst, nullptr, + PaintCanvas::kStrict_SrcRectConstraint); + + testing::StrictMock<MockCanvas> canvas; + testing::Sequence s; + + EXPECT_CALL(canvas, willSave()).InSequence(s); + EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s); EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s); EXPECT_CALL(canvas, willSave()).InSequence(s); EXPECT_CALL(canvas, didConcat(MatchesInvScale(scale_adjustment[0]))); @@ -2912,6 +3025,7 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImage2) { EXPECT_CALL(canvas, willRestore()).InSequence(s); EXPECT_CALL(canvas, willRestore()).InSequence(s); EXPECT_CALL(canvas, willRestore()).InSequence(s); + EXPECT_CALL(canvas, willRestore()).InSequence(s); blink_buffer.Playback(&canvas, PlaybackParams(&provider)); } diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc index 74366585d97..6dd4d8bb6a4 100644 --- a/chromium/cc/paint/paint_op_reader.cc +++ b/chromium/cc/paint/paint_op_reader.cc @@ -357,6 +357,7 @@ void PaintOpReader::Read(PaintImage* image) { if (transfer_cache_entry_id == kInvalidImageTransferCacheEntryId) return; + // The transfer cache entry for an image may not exist if the upload fails. if (auto* entry = options_.transfer_cache->GetEntryAs<ServiceImageTransferCacheEntry>( transfer_cache_entry_id)) { @@ -366,10 +367,6 @@ void PaintOpReader::Read(PaintImage* image) { .set_id(PaintImage::GetNextId()) .set_image(entry->image(), PaintImage::kNonLazyStableId) .TakePaintImage(); - } else { - // If a transfer cache id exists, we must have a valid entry for it in the - // cache. - SetInvalid(); } } diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc index 836565414f8..b0277f51a5b 100644 --- a/chromium/cc/paint/record_paint_canvas.cc +++ b/chromium/cc/paint/record_paint_canvas.cc @@ -246,6 +246,7 @@ void RecordPaintCanvas::drawImage(const PaintImage& image, SkScalar left, SkScalar top, const PaintFlags* flags) { + DCHECK(!image.IsPaintWorklet()); list_->push<DrawImageOp>(image, left, top, flags); } diff --git a/chromium/cc/paint/render_surface_filters.cc b/chromium/cc/paint/render_surface_filters.cc index d82fdd069fa..0a9cb8bca72 100644 --- a/chromium/cc/paint/render_surface_filters.cc +++ b/chromium/cc/paint/render_surface_filters.cc @@ -11,6 +11,7 @@ #include "cc/paint/filter_operation.h" #include "cc/paint/filter_operations.h" #include "cc/paint/paint_filter.h" +#include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkImageFilter.h" #include "third_party/skia/include/core/SkRegion.h" #include "third_party/skia/include/effects/SkAlphaThresholdFilter.h" @@ -26,31 +27,31 @@ namespace cc { namespace { -void GetBrightnessMatrix(float amount, SkScalar matrix[20]) { +void GetBrightnessMatrix(float amount, float matrix[20]) { // Spec implementation // (http://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html#brightnessEquivalent) // <feFunc[R|G|B] type="linear" slope="[amount]"> - memset(matrix, 0, 20 * sizeof(SkScalar)); + memset(matrix, 0, 20 * sizeof(float)); matrix[0] = matrix[6] = matrix[12] = amount; matrix[18] = 1.f; } -void GetSaturatingBrightnessMatrix(float amount, SkScalar matrix[20]) { +void GetSaturatingBrightnessMatrix(float amount, float matrix[20]) { // Legacy implementation used by internal clients. // <feFunc[R|G|B] type="linear" intercept="[amount]"/> - memset(matrix, 0, 20 * sizeof(SkScalar)); + memset(matrix, 0, 20 * sizeof(float)); matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f; - matrix[4] = matrix[9] = matrix[14] = amount * 255.f; + matrix[4] = matrix[9] = matrix[14] = amount; } -void GetContrastMatrix(float amount, SkScalar matrix[20]) { - memset(matrix, 0, 20 * sizeof(SkScalar)); +void GetContrastMatrix(float amount, float matrix[20]) { + memset(matrix, 0, 20 * sizeof(float)); matrix[0] = matrix[6] = matrix[12] = amount; - matrix[4] = matrix[9] = matrix[14] = (-0.5f * amount + 0.5f) * 255.f; + matrix[4] = matrix[9] = matrix[14] = (-0.5f * amount + 0.5f); matrix[18] = 1.f; } -void GetSaturateMatrix(float amount, SkScalar matrix[20]) { +void GetSaturateMatrix(float amount, float matrix[20]) { // Note, these values are computed to ensure MatrixNeedsClamping is false // for amount in [0..1] matrix[0] = 0.213f + 0.787f * amount; @@ -69,7 +70,7 @@ void GetSaturateMatrix(float amount, SkScalar matrix[20]) { matrix[18] = 1.f; } -void GetHueRotateMatrix(float hue, SkScalar matrix[20]) { +void GetHueRotateMatrix(float hue, float matrix[20]) { float cos_hue = cosf(hue * base::kPiFloat / 180.f); float sin_hue = sinf(hue * base::kPiFloat / 180.f); matrix[0] = 0.213f + cos_hue * 0.787f - sin_hue * 0.213f; @@ -89,20 +90,20 @@ void GetHueRotateMatrix(float hue, SkScalar matrix[20]) { matrix[19] = 0.f; } -void GetInvertMatrix(float amount, SkScalar matrix[20]) { - memset(matrix, 0, 20 * sizeof(SkScalar)); +void GetInvertMatrix(float amount, float matrix[20]) { + memset(matrix, 0, 20 * sizeof(float)); matrix[0] = matrix[6] = matrix[12] = 1.f - 2.f * amount; - matrix[4] = matrix[9] = matrix[14] = amount * 255.f; + matrix[4] = matrix[9] = matrix[14] = amount; matrix[18] = 1.f; } -void GetOpacityMatrix(float amount, SkScalar matrix[20]) { - memset(matrix, 0, 20 * sizeof(SkScalar)); +void GetOpacityMatrix(float amount, float matrix[20]) { + memset(matrix, 0, 20 * sizeof(float)); matrix[0] = matrix[6] = matrix[12] = 1.f; matrix[18] = amount; } -void GetGrayscaleMatrix(float amount, SkScalar matrix[20]) { +void GetGrayscaleMatrix(float amount, float matrix[20]) { // Note, these values are computed to ensure MatrixNeedsClamping is false // for amount in [0..1] matrix[0] = 0.2126f + 0.7874f * amount; @@ -124,7 +125,7 @@ void GetGrayscaleMatrix(float amount, SkScalar matrix[20]) { matrix[18] = 1.f; } -void GetSepiaMatrix(float amount, SkScalar matrix[20]) { +void GetSepiaMatrix(float amount, float matrix[20]) { matrix[0] = 0.393f + 0.607f * amount; matrix[1] = 0.769f - 0.769f * amount; matrix[2] = 0.189f - 0.189f * amount; @@ -144,10 +145,10 @@ void GetSepiaMatrix(float amount, SkScalar matrix[20]) { matrix[18] = 1.f; } -sk_sp<PaintFilter> CreateMatrixImageFilter(const SkScalar matrix[20], +sk_sp<PaintFilter> CreateMatrixImageFilter(const float matrix[20], sk_sp<PaintFilter> input) { - return sk_make_sp<ColorFilterPaintFilter>( - SkColorFilters::MatrixRowMajor255(matrix), std::move(input)); + return sk_make_sp<ColorFilterPaintFilter>(SkColorFilters::Matrix(matrix), + std::move(input)); } } // namespace @@ -157,7 +158,7 @@ sk_sp<PaintFilter> RenderSurfaceFilters::BuildImageFilter( const gfx::SizeF& size, const gfx::Vector2dF& offset) { sk_sp<PaintFilter> image_filter; - SkScalar matrix[20]; + float matrix[20]; for (size_t i = 0; i < filters.size(); ++i) { const FilterOperation& op = filters.at(i); switch (op.type()) { @@ -271,7 +272,7 @@ sk_sp<PaintFilter> RenderSurfaceFilters::BuildImageFilter( has_input = !!color_paint_filter->input(); } - if (cf && cf->asColorMatrix(matrix) && !has_input) { + if (cf && cf->asAColorMatrix(matrix) && !has_input) { image_filter = CreateMatrixImageFilter(matrix, std::move(image_filter)); } else if (image_filter) { diff --git a/chromium/cc/paint/skia_paint_canvas.cc b/chromium/cc/paint/skia_paint_canvas.cc index 17829b3eb1a..45e6e8fd6a0 100644 --- a/chromium/cc/paint/skia_paint_canvas.cc +++ b/chromium/cc/paint/skia_paint_canvas.cc @@ -241,6 +241,7 @@ void SkiaPaintCanvas::drawImage(const PaintImage& image, SkScalar left, SkScalar top, const PaintFlags* flags) { + DCHECK(!image.IsPaintWorklet()); base::Optional<ScopedRasterFlags> scoped_flags; if (flags) { scoped_flags.emplace(flags, image_provider_, canvas_->getTotalMatrix(), diff --git a/chromium/cc/paint/transfer_cache_unittest.cc b/chromium/cc/paint/transfer_cache_unittest.cc index 7b606ab9110..7eb83e82dd2 100644 --- a/chromium/cc/paint/transfer_cache_unittest.cc +++ b/chromium/cc/paint/transfer_cache_unittest.cc @@ -11,6 +11,7 @@ #include "cc/paint/raw_memory_transfer_cache_entry.h" #include "cc/paint/transfer_cache_entry.h" #include "cc/test/test_in_process_context_provider.h" +#include "components/viz/test/test_gpu_service_holder.h" #include "gpu/command_buffer/client/client_transfer_cache.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h" #include "gpu/command_buffer/client/gles2_implementation.h" @@ -20,7 +21,6 @@ #include "gpu/command_buffer/service/service_transfer_cache.h" #include "gpu/config/gpu_switches.h" #include "gpu/ipc/raster_in_process_context.h" -#include "gpu/ipc/test_gpu_thread_holder.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkImage.h" #include "ui/gl/gl_implementation.h" @@ -48,7 +48,7 @@ class TransferCacheTest : public testing::Test { context_ = std::make_unique<gpu::RasterInProcessContext>(); auto result = context_->Initialize( - gpu::GetTestGpuThreadHolder()->GetTaskExecutor(), attribs, + viz::TestGpuServiceHolder::GetInstance()->task_executor(), attribs, gpu::SharedMemoryLimits(), &gpu_memory_buffer_manager_, &image_factory_, /*gpu_channel_manager_delegate=*/nullptr, nullptr, nullptr); diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.cc b/chromium/cc/raster/bitmap_raster_buffer_provider.cc index f94e220c0f0..754ff6979a0 100644 --- a/chromium/cc/raster/bitmap_raster_buffer_provider.cc +++ b/chromium/cc/raster/bitmap_raster_buffer_provider.cc @@ -9,6 +9,7 @@ #include <algorithm> +#include "base/memory/shared_memory_mapping.h" #include "base/strings/stringprintf.h" #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event.h" @@ -32,12 +33,12 @@ class BitmapSoftwareBacking : public ResourcePool::SoftwareBacking { const base::trace_event::MemoryAllocatorDumpGuid& buffer_dump_guid, uint64_t tracing_process_id, int importance) const override { - pmd->CreateSharedMemoryOwnershipEdge( - buffer_dump_guid, shared_memory->mapped_id(), importance); + pmd->CreateSharedMemoryOwnershipEdge(buffer_dump_guid, mapping.guid(), + importance); } LayerTreeFrameSink* frame_sink; - std::unique_ptr<base::SharedMemory> shared_memory; + base::WritableSharedMemoryMapping mapping; }; class BitmapRasterBufferImpl : public RasterBuffer { @@ -107,14 +108,12 @@ BitmapRasterBufferProvider::AcquireBufferForRaster( auto backing = std::make_unique<BitmapSoftwareBacking>(); backing->frame_sink = frame_sink_; backing->shared_bitmap_id = viz::SharedBitmap::GenerateId(); - backing->shared_memory = - viz::bitmap_allocation::AllocateMappedBitmap(size, viz::RGBA_8888); - - mojo::ScopedSharedBufferHandle handle = - viz::bitmap_allocation::DuplicateAndCloseMappedBitmap( - backing->shared_memory.get(), size, viz::RGBA_8888); - frame_sink_->DidAllocateSharedBitmap(std::move(handle), - backing->shared_bitmap_id); + base::MappedReadOnlyRegion mapped_region = + viz::bitmap_allocation::AllocateSharedBitmap(size, viz::RGBA_8888); + backing->mapping = std::move(mapped_region.mapping); + frame_sink_->DidAllocateSharedBitmap( + viz::bitmap_allocation::ToMojoHandle(std::move(mapped_region.region)), + backing->shared_bitmap_id); resource.set_software_backing(std::move(backing)); } @@ -122,7 +121,7 @@ BitmapRasterBufferProvider::AcquireBufferForRaster( static_cast<BitmapSoftwareBacking*>(resource.software_backing()); return std::make_unique<BitmapRasterBufferImpl>( - size, color_space, backing->shared_memory->memory(), resource_content_id, + size, color_space, backing->mapping.memory(), resource_content_id, previous_content_id); } @@ -132,13 +131,6 @@ viz::ResourceFormat BitmapRasterBufferProvider::GetResourceFormat() const { return viz::RGBA_8888; } -bool BitmapRasterBufferProvider::IsResourceSwizzleRequired() const { - // This value only used by gpu compositing. Software compositing resources - // are all in the native skia byte ordering, and the display compositor will - // do its drawing in the same order. - return false; -} - bool BitmapRasterBufferProvider::IsResourcePremultiplied() const { return true; } diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.h b/chromium/cc/raster/bitmap_raster_buffer_provider.h index e91ac1a4248..bdf1fc8d06d 100644 --- a/chromium/cc/raster/bitmap_raster_buffer_provider.h +++ b/chromium/cc/raster/bitmap_raster_buffer_provider.h @@ -36,7 +36,6 @@ class CC_EXPORT BitmapRasterBufferProvider : public RasterBufferProvider { uint64_t previous_content_id) override; void Flush() override; viz::ResourceFormat GetResourceFormat() const override; - bool IsResourceSwizzleRequired() const override; bool IsResourcePremultiplied() const override; bool CanPartialRasterIntoProvidedResource() const override; bool IsResourceReadyToDraw( diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc index 45f9f93d6d9..79c32f61b5d 100644 --- a/chromium/cc/raster/gpu_raster_buffer_provider.cc +++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc @@ -386,11 +386,6 @@ viz::ResourceFormat GpuRasterBufferProvider::GetResourceFormat() const { return tile_format_; } -bool GpuRasterBufferProvider::IsResourceSwizzleRequired() const { - // This doesn't require a swizzle because we rasterize to the correct format. - return false; -} - bool GpuRasterBufferProvider::IsResourcePremultiplied() const { return !ShouldUnpremultiplyAndDitherResource(GetResourceFormat()); } diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.h b/chromium/cc/raster/gpu_raster_buffer_provider.h index 52fb765d560..e6a435978a7 100644 --- a/chromium/cc/raster/gpu_raster_buffer_provider.h +++ b/chromium/cc/raster/gpu_raster_buffer_provider.h @@ -48,7 +48,6 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider { uint64_t previous_content_id) override; void Flush() override; viz::ResourceFormat GetResourceFormat() const override; - bool IsResourceSwizzleRequired() const override; bool IsResourcePremultiplied() const override; bool CanPartialRasterIntoProvidedResource() const override; bool IsResourceReadyToDraw( diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.cc b/chromium/cc/raster/one_copy_raster_buffer_provider.cc index 4a248642b8d..daf5a89f012 100644 --- a/chromium/cc/raster/one_copy_raster_buffer_provider.cc +++ b/chromium/cc/raster/one_copy_raster_buffer_provider.cc @@ -189,10 +189,6 @@ viz::ResourceFormat OneCopyRasterBufferProvider::GetResourceFormat() const { return tile_format_; } -bool OneCopyRasterBufferProvider::IsResourceSwizzleRequired() const { - return !viz::PlatformColor::SameComponentOrder(GetResourceFormat()); -} - bool OneCopyRasterBufferProvider::IsResourcePremultiplied() const { // TODO(ericrk): Handle unpremultiply/dither in one-copy case as well. // https://crbug.com/789153 diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.h b/chromium/cc/raster/one_copy_raster_buffer_provider.h index a307c01cfb6..370e6cbf43c 100644 --- a/chromium/cc/raster/one_copy_raster_buffer_provider.h +++ b/chromium/cc/raster/one_copy_raster_buffer_provider.h @@ -51,7 +51,6 @@ class CC_EXPORT OneCopyRasterBufferProvider : public RasterBufferProvider { uint64_t previous_content_id) override; void Flush() override; viz::ResourceFormat GetResourceFormat() const override; - bool IsResourceSwizzleRequired() const override; bool IsResourcePremultiplied() const override; bool CanPartialRasterIntoProvidedResource() const override; bool IsResourceReadyToDraw( diff --git a/chromium/cc/raster/playback_image_provider.cc b/chromium/cc/raster/playback_image_provider.cc index 4e8cff91335..cbda15cb848 100644 --- a/chromium/cc/raster/playback_image_provider.cc +++ b/chromium/cc/raster/playback_image_provider.cc @@ -19,8 +19,10 @@ void UnrefImageFromCache(DrawImage draw_image, PlaybackImageProvider::PlaybackImageProvider( ImageDecodeCache* cache, + const gfx::ColorSpace& target_color_space, base::Optional<Settings>&& settings) : cache_(cache), + target_color_space_(target_color_space), settings_(std::move(settings)) { DCHECK(cache_); } @@ -53,7 +55,7 @@ ImageProvider::ScopedResult PlaybackImageProvider::GetRasterContent( ? PaintImage::kDefaultFrameIndex : it->second; - DrawImage adjusted_image(draw_image, 1.f, frame_index); + DrawImage adjusted_image(draw_image, 1.f, frame_index, target_color_space_); if (!cache_->UseCacheForDrawImage(adjusted_image)) { return ScopedResult(DecodedDrawImage( paint_image.GetSkImage(), SkSize::Make(0, 0), SkSize::Make(1.f, 1.f), diff --git a/chromium/cc/raster/playback_image_provider.h b/chromium/cc/raster/playback_image_provider.h index 864ec2568ac..70991ca2692 100644 --- a/chromium/cc/raster/playback_image_provider.h +++ b/chromium/cc/raster/playback_image_provider.h @@ -37,6 +37,7 @@ class CC_EXPORT PlaybackImageProvider : public ImageProvider { // If no settings are provided, all images are skipped during rasterization. PlaybackImageProvider(ImageDecodeCache* cache, + const gfx::ColorSpace& target_color_space, base::Optional<Settings>&& settings); PlaybackImageProvider(const PlaybackImageProvider&) = delete; PlaybackImageProvider(PlaybackImageProvider&& other); @@ -51,6 +52,7 @@ class CC_EXPORT PlaybackImageProvider : public ImageProvider { private: ImageDecodeCache* cache_; + gfx::ColorSpace target_color_space_; base::Optional<Settings> settings_; }; diff --git a/chromium/cc/raster/playback_image_provider_unittest.cc b/chromium/cc/raster/playback_image_provider_unittest.cc index c5995098160..28d26f9e6b0 100644 --- a/chromium/cc/raster/playback_image_provider_unittest.cc +++ b/chromium/cc/raster/playback_image_provider_unittest.cc @@ -66,7 +66,7 @@ class MockDecodeCache : public StubDecodeCache { TEST(PlaybackImageProviderTest, SkipsAllImages) { MockDecodeCache cache; - PlaybackImageProvider provider(&cache, base::nullopt); + PlaybackImageProvider provider(&cache, gfx::ColorSpace(), base::nullopt); SkIRect rect = SkIRect::MakeWH(10, 10); SkMatrix matrix = SkMatrix::I(); @@ -93,7 +93,8 @@ TEST(PlaybackImageProviderTest, SkipsSomeImages) { settings.emplace(); settings->images_to_skip = {skip_image.stable_id()}; - PlaybackImageProvider provider(&cache, std::move(settings)); + PlaybackImageProvider provider(&cache, gfx::ColorSpace(), + std::move(settings)); SkIRect rect = SkIRect::MakeWH(10, 10); SkMatrix matrix = SkMatrix::I(); @@ -107,7 +108,8 @@ TEST(PlaybackImageProviderTest, RefAndUnrefDecode) { base::Optional<PlaybackImageProvider::Settings> settings; settings.emplace(); - PlaybackImageProvider provider(&cache, std::move(settings)); + PlaybackImageProvider provider(&cache, gfx::ColorSpace(), + std::move(settings)); { SkRect rect = SkRect::MakeWH(10, 10); @@ -135,7 +137,8 @@ TEST(PlaybackImageProviderTest, SwapsGivenFrames) { settings.emplace(); settings->image_to_current_frame_index = image_to_frame; - PlaybackImageProvider provider(&cache, std::move(settings)); + PlaybackImageProvider provider(&cache, gfx::ColorSpace(), + std::move(settings)); SkIRect rect = SkIRect::MakeWH(10, 10); SkMatrix matrix = SkMatrix::I(); @@ -151,7 +154,8 @@ TEST(PlaybackImageProviderTest, BitmapImages) { base::Optional<PlaybackImageProvider::Settings> settings; settings.emplace(); - PlaybackImageProvider provider(&cache, std::move(settings)); + PlaybackImageProvider provider(&cache, gfx::ColorSpace(), + std::move(settings)); { SkIRect rect = SkIRect::MakeWH(10, 10); @@ -172,7 +176,8 @@ TEST(PlaybackImageProviderTest, IgnoresImagesNotSupportedByCache) { cache.set_use_cache_for_draw_image(false); base::Optional<PlaybackImageProvider::Settings> settings; settings.emplace(); - PlaybackImageProvider provider(&cache, std::move(settings)); + PlaybackImageProvider provider(&cache, gfx::ColorSpace(), + std::move(settings)); { SkIRect rect = SkIRect::MakeWH(10, 10); SkMatrix matrix = SkMatrix::I(); diff --git a/chromium/cc/raster/raster_buffer_provider.cc b/chromium/cc/raster/raster_buffer_provider.cc index f5935e2f90c..6252168a3b1 100644 --- a/chromium/cc/raster/raster_buffer_provider.cc +++ b/chromium/cc/raster/raster_buffer_provider.cc @@ -72,10 +72,13 @@ void RasterBufferProvider::PlaybackToMemory( DCHECK(IsSupportedPlaybackToMemoryFormat(format)) << format; + SkColorType color_type = + ResourceFormatToClosestSkColorType(gpu_compositing, format); + // Uses kPremul_SkAlphaType since the result is not known to be opaque. - SkImageInfo info = - SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType, - target_color_space.ToSkColorSpace()); + SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), color_type, + kPremul_SkAlphaType, + target_color_space.ToSkColorSpace()); // Use unknown pixel geometry to disable LCD text. SkSurfaceProps surface_props(0, kUnknown_SkPixelGeometry); diff --git a/chromium/cc/raster/raster_buffer_provider.h b/chromium/cc/raster/raster_buffer_provider.h index a4755ccfda0..a23befca140 100644 --- a/chromium/cc/raster/raster_buffer_provider.h +++ b/chromium/cc/raster/raster_buffer_provider.h @@ -61,9 +61,6 @@ class CC_EXPORT RasterBufferProvider { // Returns the format to use for the tiles. virtual viz::ResourceFormat GetResourceFormat() const = 0; - // Determine if the resource requires swizzling. - virtual bool IsResourceSwizzleRequired() const = 0; - // Determines if the resource is premultiplied. virtual bool IsResourcePremultiplied() const = 0; diff --git a/chromium/cc/raster/raster_source_unittest.cc b/chromium/cc/raster/raster_source_unittest.cc index 21338cf9c19..0bd9e4fc367 100644 --- a/chromium/cc/raster/raster_source_unittest.cc +++ b/chromium/cc/raster/raster_source_unittest.cc @@ -266,19 +266,25 @@ TEST(RasterSourceTest, PixelRefIteratorDiscardableRefsOneTile) { // Tile sized iterators. These should find only one pixel ref. { + gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB(); std::vector<const DrawImage*> images; raster->GetDiscardableImagesInRect(gfx::Rect(0, 0, 256, 256), &images); EXPECT_EQ(1u, images.size()); - DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex); + DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex, + target_color_space); EXPECT_EQ(discardable_image[0][0], images[0]->paint_image()); + EXPECT_EQ(target_color_space, image.target_color_space()); } // Shifted tile sized iterators. These should find only one pixel ref. { + gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50(); std::vector<const DrawImage*> images; raster->GetDiscardableImagesInRect(gfx::Rect(260, 260, 256, 256), &images); EXPECT_EQ(1u, images.size()); - DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex); + DrawImage image(*images[0], 1.f, PaintImage::kDefaultFrameIndex, + target_color_space); EXPECT_EQ(discardable_image[1][1], images[0]->paint_image()); + EXPECT_EQ(target_color_space, image.target_color_space()); } // Ensure there's no discardable pixel refs in the empty cell { diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc index 6f491eb7a47..bce36db08b2 100644 --- a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc +++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc @@ -204,10 +204,6 @@ viz::ResourceFormat ZeroCopyRasterBufferProvider::GetResourceFormat() const { return tile_format_; } -bool ZeroCopyRasterBufferProvider::IsResourceSwizzleRequired() const { - return !viz::PlatformColor::SameComponentOrder(GetResourceFormat()); -} - bool ZeroCopyRasterBufferProvider::IsResourcePremultiplied() const { return true; } diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.h b/chromium/cc/raster/zero_copy_raster_buffer_provider.h index 6bb0e333976..653228c7c65 100644 --- a/chromium/cc/raster/zero_copy_raster_buffer_provider.h +++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.h @@ -42,7 +42,6 @@ class CC_EXPORT ZeroCopyRasterBufferProvider : public RasterBufferProvider { uint64_t previous_content_id) override; void Flush() override; viz::ResourceFormat GetResourceFormat() const override; - bool IsResourceSwizzleRequired() const override; bool IsResourcePremultiplied() const override; bool CanPartialRasterIntoProvidedResource() const override; bool IsResourceReadyToDraw( diff --git a/chromium/cc/resources/cross_thread_shared_bitmap.cc b/chromium/cc/resources/cross_thread_shared_bitmap.cc index 642bd39d89e..edd1e5234ef 100644 --- a/chromium/cc/resources/cross_thread_shared_bitmap.cc +++ b/chromium/cc/resources/cross_thread_shared_bitmap.cc @@ -6,12 +6,15 @@ namespace cc { -CrossThreadSharedBitmap::CrossThreadSharedBitmap( - const viz::SharedBitmapId& id, - std::unique_ptr<base::SharedMemory> memory, - const gfx::Size& size, - viz::ResourceFormat format) - : id_(id), memory_(std::move(memory)), size_(size), format_(format) {} +CrossThreadSharedBitmap::CrossThreadSharedBitmap(const viz::SharedBitmapId& id, + base::MappedReadOnlyRegion shm, + const gfx::Size& size, + viz::ResourceFormat format) + : id_(id), + region_(std::move(shm.region)), + mapping_(std::move(shm.mapping)), + size_(size), + format_(format) {} CrossThreadSharedBitmap::~CrossThreadSharedBitmap() = default; diff --git a/chromium/cc/resources/cross_thread_shared_bitmap.h b/chromium/cc/resources/cross_thread_shared_bitmap.h index f594ef19df5..6d7017a6ace 100644 --- a/chromium/cc/resources/cross_thread_shared_bitmap.h +++ b/chromium/cc/resources/cross_thread_shared_bitmap.h @@ -7,8 +7,9 @@ #include <memory> +#include "base/memory/read_only_shared_memory_region.h" #include "base/memory/ref_counted.h" -#include "base/memory/shared_memory.h" +#include "base/memory/shared_memory_mapping.h" #include "cc/cc_export.h" #include "components/viz/common/resources/resource_format.h" #include "components/viz/common/resources/shared_bitmap.h" @@ -16,22 +17,25 @@ namespace cc { -// This class holds ownership of a base::SharedMemory segment for use as a -// composited resource, and is refcounted in order to share ownership with the -// LayerTreeHost, via TextureLayer, which needs access to the base::SharedMemory -// from the compositor thread. -// Because all the fields exposed are const, they can be used from any thread -// without conflict, as they only read existing states. +// This class holds ownership of a base::ReadOnlySharedMemoryRegion and its +// base::WritableSharedMemoryMapping for use as a composited resource, and is +// refcounted in order to share ownership with the LayerTreeHost, via +// TextureLayer, which needs access to the base::ReadOnlySharedMemory from +// the compositor thread. Because all the fields exposed are const, they can +// be used from any thread without conflict, as they only read existing states. class CC_EXPORT CrossThreadSharedBitmap : public base::RefCountedThreadSafe<CrossThreadSharedBitmap> { public: CrossThreadSharedBitmap(const viz::SharedBitmapId& id, - std::unique_ptr<base::SharedMemory> memory, + base::MappedReadOnlyRegion shm, const gfx::Size& size, viz::ResourceFormat format); const viz::SharedBitmapId& id() const { return id_; } - const base::SharedMemory* shared_memory() const { return memory_.get(); } + const base::ReadOnlySharedMemoryRegion& shared_region() const { + return region_; + } + void* memory() const { return mapping_.memory(); } const gfx::Size& size() const { return size_; } viz::ResourceFormat format() const { return format_; } @@ -41,7 +45,8 @@ class CC_EXPORT CrossThreadSharedBitmap ~CrossThreadSharedBitmap(); const viz::SharedBitmapId id_; - const std::unique_ptr<const base::SharedMemory> memory_; + const base::ReadOnlySharedMemoryRegion region_; + base::WritableSharedMemoryMapping mapping_; const gfx::Size size_; const viz::ResourceFormat format_; }; diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc index 7818ee15a1f..9c73860e220 100644 --- a/chromium/cc/resources/resource_pool.cc +++ b/chromium/cc/resources/resource_pool.cc @@ -321,7 +321,7 @@ bool ResourcePool::PrepareForExport(const InUsePoolResource& in_use_resource) { resource->mark_avoid_reuse(); return false; } - transferable = viz::TransferableResource::MakeGLOverlay( + transferable = viz::TransferableResource::MakeGL( gpu_backing->mailbox, GL_LINEAR, gpu_backing->texture_target, gpu_backing->mailbox_sync_token, resource->size(), gpu_backing->overlay_candidate); diff --git a/chromium/cc/scheduler/compositor_frame_reporting_controller.cc b/chromium/cc/scheduler/compositor_frame_reporting_controller.cc index f1587ed158d..1b17021fd22 100644 --- a/chromium/cc/scheduler/compositor_frame_reporting_controller.cc +++ b/chromium/cc/scheduler/compositor_frame_reporting_controller.cc @@ -31,8 +31,8 @@ void CompositorFrameReportingController::WillBeginImplFrame() { void CompositorFrameReportingController::WillBeginMainFrame() { DCHECK(reporters_[PipelineStage::kBeginImplFrame]); - DCHECK_NE(reporters_[PipelineStage::kBeginMainFrame], - reporters_[PipelineStage::kBeginImplFrame]); + DCHECK(reporters_[PipelineStage::kBeginMainFrame] != + reporters_[PipelineStage::kBeginImplFrame]); reporters_[PipelineStage::kBeginImplFrame]->StartStage( "SendBeginMainFrameToCommit"); AdvanceReporterStage(PipelineStage::kBeginImplFrame, diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc index 5fdf97c2ebf..f9fed94544d 100644 --- a/chromium/cc/scheduler/scheduler.cc +++ b/chromium/cc/scheduler/scheduler.cc @@ -933,17 +933,6 @@ bool Scheduler::ShouldDropBeginFrame(const viz::BeginFrameArgs& args) const { return true; } - // We shouldn't be handling missed frames in the browser process (i.e. where - // commit_to_active_tree is set) since we don't know if we should create a - // frame at this time. Doing so leads to issues like crbug.com/882907. This - // early-out is a short term fix to keep fling animations smooth. - // TODO(bokan): In the long term, the display compositor should decide - // whether to issue a missed frame; it is tracked in - // https://crbug.com/930890. - if (args.type == viz::BeginFrameArgs::MISSED && - settings_.commit_to_active_tree) - return true; - return false; } diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc index a4433d47f1d..29479c7dd3c 100644 --- a/chromium/cc/scheduler/scheduler_state_machine.cc +++ b/chromium/cc/scheduler/scheduler_state_machine.cc @@ -365,11 +365,6 @@ bool SchedulerStateMachine::ShouldDraw() const { if (forced_redraw_state_ == ForcedRedrawOnTimeoutState::WAITING_FOR_DRAW) return true; - // Delay draws when we have pending animation worklet updates to give them - // time to produce output before we draw. - if (processing_animation_worklets_for_active_tree_) - return false; - return needs_redraw_; } diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc index 489cd110217..676b83ee4ae 100644 --- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc @@ -2725,7 +2725,7 @@ TEST(SchedulerStateMachineTest, AllowSkippingActiveTreeFirstDraws) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE); } -TEST(SchedulerStateMachineTest, BlockDrawIfAnimationWorkletsPending) { +TEST(SchedulerStateMachineTest, DelayDrawIfAnimationWorkletsPending) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); SET_UP_STATE(state) @@ -2774,6 +2774,8 @@ TEST(SchedulerStateMachineTest, BlockDrawIfAnimationWorkletsPending) { EXPECT_EQ(SchedulerStateMachine::BeginImplFrameDeadlineMode::IMMEDIATE, state.CurrentBeginImplFrameDeadlineMode()); + // AnimationWorkletState does not effect CanDraw, only whether an early draw + // deadline should be used (crbug/937975). state.SetNeedsRedraw(true); state.OnBeginImplFrameDeadline(); EXPECT_IMPL_FRAME_STATE( @@ -2782,7 +2784,7 @@ TEST(SchedulerStateMachineTest, BlockDrawIfAnimationWorkletsPending) { state.NotifyAnimationWorkletStateChange( SchedulerStateMachine::AnimationWorkletState::PROCESSING, SchedulerStateMachine::TreeType::ACTIVE); - EXPECT_FALSE(state.ShouldDraw()); + EXPECT_TRUE(state.ShouldDraw()); state.NotifyAnimationWorkletStateChange( SchedulerStateMachine::AnimationWorkletState::IDLE, SchedulerStateMachine::TreeType::ACTIVE); diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc index 35c81fd8416..2f5deee74de 100644 --- a/chromium/cc/scheduler/scheduler_unittest.cc +++ b/chromium/cc/scheduler/scheduler_unittest.cc @@ -639,26 +639,6 @@ TEST_F(SchedulerTest, VideoNeedsBeginFrames) { EXPECT_FALSE(scheduler_->begin_frames_expected()); } -// As a short term fix for https://crbug.com/882907, we should skip MISSED -// frames from the browser compositor. -// TODO(bokan): In the long term, the display compositor should decide -// whether to issue a missed frame; it is tracked in -// https://crbug.com/930890. -TEST_F(SchedulerTest, BrowserCompositorSkipsMissedBeginFrames) { - scheduler_settings_.commit_to_active_tree = true; - SetUpScheduler(EXTERNAL_BFS); - scheduler_->SetNeedsBeginMainFrame(); - - task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval()); - viz::BeginFrameArgs args = - fake_external_begin_frame_source_->CreateBeginFrameArgs( - BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock()); - args.type = viz::BeginFrameArgs::MISSED; - - fake_external_begin_frame_source_->TestOnBeginFrame(args); - EXPECT_FALSE(client_->IsInsideBeginImplFrame()); -} - TEST_F(SchedulerTest, RequestCommit) { SetUpScheduler(EXTERNAL_BFS); diff --git a/chromium/cc/tiles/checker_image_tracker.cc b/chromium/cc/tiles/checker_image_tracker.cc index 2308d922a35..6eda401d7a5 100644 --- a/chromium/cc/tiles/checker_image_tracker.cc +++ b/chromium/cc/tiles/checker_image_tracker.cc @@ -387,6 +387,7 @@ void CheckerImageTracker::UpdateDecodeState(const DrawImage& draw_image, std::max(decode_state->scale.fHeight, draw_image.scale().fHeight)); decode_state->filter_quality = std::max(decode_state->filter_quality, draw_image.filter_quality()); + decode_state->color_space = draw_image.target_color_space(); decode_state->frame_index = draw_image.frame_index(); } @@ -426,7 +427,7 @@ void CheckerImageTracker::ScheduleNextImageDecode() { it->second.filter_quality, SkMatrix::MakeScale(it->second.scale.width(), it->second.scale.height()), - it->second.frame_index); + it->second.frame_index, it->second.color_space); outstanding_image_decode_.emplace(candidate); break; } diff --git a/chromium/cc/tiles/checker_image_tracker.h b/chromium/cc/tiles/checker_image_tracker.h index f59f5a27620..ee5578f8fef 100644 --- a/chromium/cc/tiles/checker_image_tracker.h +++ b/chromium/cc/tiles/checker_image_tracker.h @@ -139,6 +139,7 @@ class CC_EXPORT CheckerImageTracker { DecodePolicy policy = DecodePolicy::SYNC; SkFilterQuality filter_quality = kNone_SkFilterQuality; SkSize scale = SkSize::MakeEmpty(); + gfx::ColorSpace color_space; size_t frame_index = PaintImage::kDefaultFrameIndex; }; diff --git a/chromium/cc/tiles/checker_image_tracker_unittest.cc b/chromium/cc/tiles/checker_image_tracker_unittest.cc index 44cba670c23..47dc8ab1306 100644 --- a/chromium/cc/tiles/checker_image_tracker_unittest.cc +++ b/chromium/cc/tiles/checker_image_tracker_unittest.cc @@ -125,7 +125,7 @@ class CheckerImageTrackerTest : public testing::Test, .TakePaintImage(), SkIRect::MakeWH(dimension, dimension), kNone_SkFilterQuality, SkMatrix::I(), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, gfx::ColorSpace()); } bool ShouldCheckerImage(const DrawImage& draw_image, WhichTree tree) { @@ -433,7 +433,8 @@ TEST_F(CheckerImageTrackerTest, CheckersOnlyStaticCompletedImages) { .set_paint_image_generator(CreatePaintImageGenerator(image_size)) .TakePaintImage(), SkIRect::MakeWH(image_size.width(), image_size.height()), - kNone_SkFilterQuality, SkMatrix::I(), PaintImage::kDefaultFrameIndex); + kNone_SkFilterQuality, SkMatrix::I(), PaintImage::kDefaultFrameIndex, + gfx::ColorSpace()); EXPECT_FALSE( ShouldCheckerImage(completed_paint_image, WhichTree::PENDING_TREE)); } @@ -460,10 +461,12 @@ TEST_F(CheckerImageTrackerTest, ChoosesMaxScaleAndQuality) { SetUpTracker(true); DrawImage image = CreateImage(ImageType::CHECKERABLE); - DrawImage scaled_image1(image, 0.5f, PaintImage::kDefaultFrameIndex); + DrawImage scaled_image1(image, 0.5f, PaintImage::kDefaultFrameIndex, + gfx::ColorSpace()); DrawImage scaled_image2 = DrawImage(image.paint_image(), image.src_rect(), kHigh_SkFilterQuality, - SkMatrix::MakeScale(1.8f), PaintImage::kDefaultFrameIndex); + SkMatrix::MakeScale(1.8f), PaintImage::kDefaultFrameIndex, + gfx::ColorSpace()); std::vector<DrawImage> draw_images = {scaled_image1, scaled_image2}; CheckerImageTracker::ImageDecodeQueue image_decode_queue = @@ -538,7 +541,7 @@ TEST_F(CheckerImageTrackerTest, UseSrcRectForSize) { DrawImage image = CreateImage(ImageType::CHECKERABLE); image = DrawImage(image.paint_image(), SkIRect::MakeWH(200, 200), image.filter_quality(), SkMatrix::I(), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, image.target_color_space()); EXPECT_FALSE(ShouldCheckerImage(image, WhichTree::PENDING_TREE)); } diff --git a/chromium/cc/tiles/decoded_image_tracker.cc b/chromium/cc/tiles/decoded_image_tracker.cc index 197b749f63e..5db3f198b6d 100644 --- a/chromium/cc/tiles/decoded_image_tracker.cc +++ b/chromium/cc/tiles/decoded_image_tracker.cc @@ -39,6 +39,7 @@ DecodedImageTracker::~DecodedImageTracker() { void DecodedImageTracker::QueueImageDecode( const PaintImage& image, + const gfx::ColorSpace& target_color_space, base::OnceCallback<void(bool)> callback) { size_t frame_index = PaintImage::kDefaultFrameIndex; TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), @@ -49,7 +50,7 @@ void DecodedImageTracker::QueueImageDecode( // our own. auto image_bounds = SkIRect::MakeWH(image.width(), image.height()); DrawImage draw_image(image, image_bounds, kNone_SkFilterQuality, - SkMatrix::I(), frame_index); + SkMatrix::I(), frame_index, target_color_space); image_controller_->QueueImageDecode( draw_image, base::BindOnce(&DecodedImageTracker::ImageDecodeFinished, base::Unretained(this), std::move(callback), diff --git a/chromium/cc/tiles/decoded_image_tracker.h b/chromium/cc/tiles/decoded_image_tracker.h index a5f99abe5dd..4803dfa3a2e 100644 --- a/chromium/cc/tiles/decoded_image_tracker.h +++ b/chromium/cc/tiles/decoded_image_tracker.h @@ -38,6 +38,7 @@ class CC_EXPORT DecodedImageTracker { // completion. The callback takes a bool indicating whether the decode was // successful or not. void QueueImageDecode(const PaintImage& image, + const gfx::ColorSpace& target_color_space, base::OnceCallback<void(bool)> callback); // Unlock all locked images - used to respond to memory pressure or diff --git a/chromium/cc/tiles/decoded_image_tracker_unittest.cc b/chromium/cc/tiles/decoded_image_tracker_unittest.cc index e481894e866..8ffb4817bea 100644 --- a/chromium/cc/tiles/decoded_image_tracker_unittest.cc +++ b/chromium/cc/tiles/decoded_image_tracker_unittest.cc @@ -86,18 +86,44 @@ class DecodedImageTrackerTest : public testing::Test { TEST_F(DecodedImageTrackerTest, QueueImageLocksImages) { bool locked = false; decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), + CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), base::BindOnce([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); EXPECT_EQ(1u, image_controller()->num_locked_images()); } +TEST_F(DecodedImageTrackerTest, Colorspace) { + bool locked = false; + gfx::ColorSpace decoded_color_space( + gfx::ColorSpace::PrimaryID::XYZ_D50, + gfx::ColorSpace::TransferID::IEC61966_2_1); + gfx::ColorSpace srgb_color_space = gfx::ColorSpace::CreateSRGB(); + auto paint_image = CreateDiscardablePaintImage(gfx::Size(1, 1)); + decoded_image_tracker()->QueueImageDecode( + paint_image, decoded_color_space, + base::BindOnce([](bool* locked, bool success) { *locked = true; }, + base::Unretained(&locked))); + + // Check that the decoded color space images are locked, but if the color + // space differs then that image is not locked. Note that we use the high + // filter quality here, since it shouldn't matter and the checks should + // succeed anyway. + DrawImage locked_draw_image( + paint_image, SkIRect::MakeWH(1, 1), kHigh_SkFilterQuality, SkMatrix::I(), + PaintImage::kDefaultFrameIndex, decoded_color_space); + EXPECT_TRUE(image_controller()->IsDrawImageLocked(locked_draw_image)); + DrawImage srgb_draw_image(paint_image, SkIRect::MakeWH(1, 1), + kHigh_SkFilterQuality, SkMatrix::I(), + PaintImage::kDefaultFrameIndex, srgb_color_space); + EXPECT_FALSE(image_controller()->IsDrawImageLocked(srgb_draw_image)); +} + TEST_F(DecodedImageTrackerTest, ImagesTimeOut) { // Add an image, this will start a 250ms timeout to release it. bool locked = false; decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), + CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), base::BindOnce([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); @@ -109,7 +135,7 @@ TEST_F(DecodedImageTrackerTest, ImagesTimeOut) { // Add an image, this will not start a new timeout, as one is pending. decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), + CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), base::BindOnce([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); @@ -130,7 +156,7 @@ TEST_F(DecodedImageTrackerTest, ImageUsedInDraw) { bool locked = false; auto paint_image_1 = CreateDiscardablePaintImage(gfx::Size(1, 1)); decoded_image_tracker()->QueueImageDecode( - paint_image_1, + paint_image_1, gfx::ColorSpace(), base::BindOnce([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); @@ -138,7 +164,7 @@ TEST_F(DecodedImageTrackerTest, ImageUsedInDraw) { auto paint_image_2 = CreateDiscardablePaintImage(gfx::Size(1, 1)); decoded_image_tracker()->QueueImageDecode( - paint_image_2, + paint_image_2, gfx::ColorSpace(), base::BindOnce([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); @@ -146,9 +172,11 @@ TEST_F(DecodedImageTrackerTest, ImageUsedInDraw) { // Create dummy draw images for each: DrawImage draw_image_1(paint_image_1, SkIRect::MakeWH(1, 1), - kHigh_SkFilterQuality, SkMatrix::I(), 0); + kHigh_SkFilterQuality, SkMatrix::I(), 0, + gfx::ColorSpace()); DrawImage draw_image_2(paint_image_2, SkIRect::MakeWH(1, 1), - kHigh_SkFilterQuality, SkMatrix::I(), 0); + kHigh_SkFilterQuality, SkMatrix::I(), 0, + gfx::ColorSpace()); // Both should be in the cache: EXPECT_TRUE(image_controller()->IsDrawImageLocked(draw_image_1)); @@ -166,13 +194,13 @@ TEST_F(DecodedImageTrackerTest, UnlockAllImages) { // Insert two images: bool locked = false; decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), + CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), base::BindOnce([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); EXPECT_EQ(1u, image_controller()->num_locked_images()); decoded_image_tracker()->QueueImageDecode( - CreateDiscardablePaintImage(gfx::Size(1, 1)), + CreateDiscardablePaintImage(gfx::Size(1, 1)), gfx::ColorSpace(), base::BindOnce([](bool* locked, bool success) { *locked = true; }, base::Unretained(&locked))); EXPECT_TRUE(locked); diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc index eaff9df998b..30ce3e45e4d 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache.cc @@ -437,20 +437,24 @@ GpuImageDecodeCache::InUseCacheKey::FromDrawImage(const DrawImage& draw_image) { GpuImageDecodeCache::InUseCacheKey::InUseCacheKey(const DrawImage& draw_image) : frame_key(draw_image.frame_key()), upload_scale_mip_level(CalculateUploadScaleMipLevel(draw_image)), - filter_quality(CalculateDesiredFilterQuality(draw_image)) {} + filter_quality(CalculateDesiredFilterQuality(draw_image)), + target_color_space(draw_image.target_color_space()) {} bool GpuImageDecodeCache::InUseCacheKey::operator==( const InUseCacheKey& other) const { return frame_key == other.frame_key && upload_scale_mip_level == other.upload_scale_mip_level && - filter_quality == other.filter_quality; + filter_quality == other.filter_quality && + target_color_space == other.target_color_space; } size_t GpuImageDecodeCache::InUseCacheKeyHash::operator()( const InUseCacheKey& cache_key) const { - return base::HashInts(cache_key.frame_key.hash(), - base::HashInts(cache_key.upload_scale_mip_level, - cache_key.filter_quality)); + return base::HashInts( + cache_key.target_color_space.GetHash(), + base::HashInts(cache_key.frame_key.hash(), + base::HashInts(cache_key.upload_scale_mip_level, + cache_key.filter_quality))); } GpuImageDecodeCache::InUseCacheEntry::InUseCacheEntry( @@ -773,17 +777,20 @@ void GpuImageDecodeCache::UploadedImageData::ReportUsageStats() const { usage_stats_.first_lock_wasted); } -GpuImageDecodeCache::ImageData::ImageData(PaintImage::Id paint_image_id, - DecodedDataMode mode, - size_t size, - SkFilterQuality quality, - int upload_scale_mip_level, - bool needs_mips, - bool is_bitmap_backed, - bool is_yuv_format) +GpuImageDecodeCache::ImageData::ImageData( + PaintImage::Id paint_image_id, + DecodedDataMode mode, + size_t size, + const gfx::ColorSpace& target_color_space, + SkFilterQuality quality, + int upload_scale_mip_level, + bool needs_mips, + bool is_bitmap_backed, + bool is_yuv_format) : paint_image_id(paint_image_id), mode(mode), size(size), + target_color_space(target_color_space), quality(quality), upload_scale_mip_level(upload_scale_mip_level), needs_mips(needs_mips), @@ -853,8 +860,7 @@ GpuImageDecodeCache::GpuImageDecodeCache( SkColorType color_type, size_t max_working_set_bytes, int max_texture_size, - PaintImage::GeneratorClientId generator_client_id, - sk_sp<SkColorSpace> target_color_space) + PaintImage::GeneratorClientId generator_client_id) : color_type_(color_type), use_transfer_cache_(use_transfer_cache), context_(context), @@ -862,8 +868,7 @@ GpuImageDecodeCache::GpuImageDecodeCache( generator_client_id_(generator_client_id), persistent_cache_(PersistentCache::NO_AUTO_EVICT), max_working_set_bytes_(max_working_set_bytes), - max_working_set_items_(kMaxItemsInWorkingSet), - target_color_space_(std::move(target_color_space)) { + max_working_set_items_(kMaxItemsInWorkingSet) { // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview). // Don't register a dump provider in these cases. if (base::ThreadTaskRunnerHandle::IsSet()) { @@ -886,17 +891,6 @@ GpuImageDecodeCache::~GpuImageDecodeCache() { // It is safe to unregister, even if we didn't register in the constructor. base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( this); - - // TODO(vmpstr): If we don't have a client name, it may cause problems in - // unittests, since most tests don't set the name but some do. The UMA system - // expects the name to be always the same. This assertion is violated in the - // tests that do set the name. - if (GetClientNameForMetrics()) { - UMA_HISTOGRAM_CUSTOM_COUNTS( - base::StringPrintf("Compositing.%s.CachedImagesCount.Gpu", - GetClientNameForMetrics()), - lifetime_max_items_in_cache_, 1, 1000, 20); - } } ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRef( @@ -1588,9 +1582,6 @@ bool GpuImageDecodeCache::EnsureCapacity(size_t required_size) { "GpuImageDecodeCache::EnsureCapacity"); lock_.AssertAcquired(); - lifetime_max_items_in_cache_ = - std::max(lifetime_max_items_in_cache_, persistent_cache_.size()); - // While we are over preferred item capacity, we iterate through our set of // cached image data in LRU order, removing unreferenced images. for (auto it = persistent_cache_.rbegin(); @@ -1669,7 +1660,7 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image, return; } - TRACE_EVENT0("cc", "GpuImageDecodeCache::DecodeImage"); + TRACE_EVENT0("cc,benchmark", "GpuImageDecodeCache::DecodeImage"); RecordImageMipLevelUMA(image_data->upload_scale_mip_level); image_data->decode.ResetData(); @@ -1791,7 +1782,10 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, image_data->decode.mark_used(); sk_sp<SkColorSpace> color_space = - SupportsColorSpaceConversion() ? target_color_space_ : nullptr; + SupportsColorSpaceConversion() && + draw_image.target_color_space().IsValid() + ? draw_image.target_color_space().ToSkColorSpace() + : nullptr; // The value of |decoded_target_colorspace| takes into account the fact // that we might need to ignore an embedded image color space if |color_type_| // does not support color space conversions or that color conversion might @@ -1874,7 +1868,7 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, uploaded_image = CreateImageFromYUVATexturesInternal( uploaded_y_image.get(), uploaded_u_image.get(), uploaded_v_image.get(), image_width, image_height, &yuva_color_space, - decoded_target_colorspace); + color_space, decoded_target_colorspace); } // At-raster may have decoded this while we were unlocked. If so, ignore our @@ -2032,6 +2026,7 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) { return base::WrapRefCounted(new ImageData( draw_image.paint_image().stable_id(), mode, data_size, + draw_image.target_color_space(), CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level, needs_mips, is_bitmap_backed, is_yuv)); } @@ -2112,6 +2107,7 @@ void GpuImageDecodeCache::UnlockImage(ImageData* image_data) { images_pending_unlock_.push_back(image_data->upload.y_image().get()); images_pending_unlock_.push_back(image_data->upload.u_image().get()); images_pending_unlock_.push_back(image_data->upload.v_image().get()); + yuv_images_pending_unlock_.push_back(image_data->upload.image()); } else { images_pending_unlock_.push_back(image_data->upload.image().get()); } @@ -2142,11 +2138,32 @@ void GpuImageDecodeCache::UnlockImage(ImageData* image_data) { } } +// YUV images are handled slightly differently because they are not themselves +// registered with the discardable memory system. We cannot use +// GlIdFromSkImage on these YUV SkImages to flush pending operations because +// doing so will flatten it to RGB. +void GpuImageDecodeCache::FlushYUVImages( + std::vector<sk_sp<SkImage>>* yuv_images) { + CheckContextLockAcquiredIfNecessary(); + lock_.AssertAcquired(); + for (auto& image : *yuv_images) { + image->flush(context_->GrContext()); + } + yuv_images->clear(); +} + // We always run pending operations in the following order: -// Lock > Unlock > Delete +// > Lock +// > Flush YUV images that will be unlocked +// > Unlock +// > Flush YUV images that will be deleted +// > Delete // This ensures that: // a) We never fully unlock an image that's pending lock (lock before unlock) // b) We never delete an image that has pending locks/unlocks. +// c) We never unlock or delete the underlying texture planes for a YUV +// image before all operations referencing it have completed. +// // As this can be run at-raster, to unlock/delete an image that was just used, // we need to call GlIdFromSkImage, which flushes pending IO on the image, // rather than just using a cached GL ID. @@ -2164,6 +2181,7 @@ void GpuImageDecodeCache::RunPendingContextThreadOperations() { } images_pending_complete_lock_.clear(); + FlushYUVImages(&yuv_images_pending_unlock_); for (auto* image : images_pending_unlock_) { context_->ContextGL()->UnlockDiscardableTextureCHROMIUM( GlIdFromSkImage(image)); @@ -2176,8 +2194,7 @@ void GpuImageDecodeCache::RunPendingContextThreadOperations() { } ids_pending_unlock_.clear(); - yuv_images_pending_deletion_.clear(); - + FlushYUVImages(&yuv_images_pending_deletion_); for (auto& image : images_pending_deletion_) { uint32_t texture_id = GlIdFromSkImage(image.get()); if (context_->ContextGL()->LockDiscardableTextureCHROMIUM(texture_id)) { @@ -2322,6 +2339,10 @@ bool GpuImageDecodeCache::IsCompatible(const ImageData* image_data, image_data->upload_scale_mip_level; bool quality_is_compatible = CalculateDesiredFilterQuality(draw_image) <= image_data->quality; + bool color_is_compatible = + image_data->target_color_space == draw_image.target_color_space(); + if (!color_is_compatible) + return false; if (is_scaled && (!scale_is_compatible || !quality_is_compatible)) return false; return true; @@ -2423,7 +2444,7 @@ sk_sp<SkColorSpace> GpuImageDecodeCache::ColorSpaceForImageDecode( return nullptr; if (mode == DecodedDataMode::kCpu) - return target_color_space_; + return image.target_color_space().ToSkColorSpace(); // For kGpu or kTransferCache images color conversion is handled during // upload, so keep the original colorspace here. @@ -2443,6 +2464,7 @@ sk_sp<SkImage> GpuImageDecodeCache::CreateImageFromYUVATexturesInternal( const size_t image_width, const size_t image_height, const SkYUVColorSpace* yuva_color_space, + sk_sp<SkColorSpace> target_color_space, sk_sp<SkColorSpace> decoded_color_space) const { DCHECK(uploaded_y_image); DCHECK(uploaded_u_image); @@ -2460,8 +2482,6 @@ sk_sp<SkImage> GpuImageDecodeCache::CreateImageFromYUVATexturesInternal( indices[SkYUVAIndex::kV_Index] = {2, SkColorChannel::kR}; indices[SkYUVAIndex::kA_Index] = {-1, SkColorChannel::kR}; - sk_sp<SkColorSpace> target_color_space = - SupportsColorSpaceConversion() ? target_color_space_ : nullptr; if (target_color_space && SkColorSpace::Equals(target_color_space.get(), decoded_color_space.get())) { target_color_space = nullptr; @@ -2551,13 +2571,18 @@ void GpuImageDecodeCache::UpdateMipsIfNeeded(const DrawImage& draw_image, SkYUVColorSpace yuva_color_space = SkYUVColorSpace::kRec601_SkYUVColorSpace; size_t width = image_y_with_mips_owned->width(); size_t height = image_y_with_mips_owned->height(); + sk_sp<SkColorSpace> color_space = + SupportsColorSpaceConversion() && + draw_image.target_color_space().IsValid() + ? draw_image.target_color_space().ToSkColorSpace() + : nullptr; sk_sp<SkColorSpace> decoded_color_space = ColorSpaceForImageDecode(draw_image, image_data->mode); sk_sp<SkImage> yuv_image_with_mips_owned = CreateImageFromYUVATexturesInternal( image_y_with_mips_owned.get(), image_u_with_mips_owned.get(), image_v_with_mips_owned.get(), width, height, &yuva_color_space, - decoded_color_space); + color_space, decoded_color_space); // In case of lost context if (!yuv_image_with_mips_owned) { DLOG(WARNING) << "TODO(crbug.com/740737): Context was lost. Early out."; diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h index 3c3ff52532c..81ca6286703 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache.h +++ b/chromium/cc/tiles/gpu_image_decode_cache.h @@ -108,8 +108,7 @@ class CC_EXPORT GpuImageDecodeCache SkColorType color_type, size_t max_working_set_bytes, int max_texture_size, - PaintImage::GeneratorClientId client_id, - sk_sp<SkColorSpace> target_color_space); + PaintImage::GeneratorClientId client_id); ~GpuImageDecodeCache() override; // Returns the GL texture ID backing the given SkImage. @@ -443,6 +442,7 @@ class CC_EXPORT GpuImageDecodeCache ImageData(PaintImage::Id paint_image_id, DecodedDataMode mode, size_t size, + const gfx::ColorSpace& target_color_space, SkFilterQuality quality, int upload_scale_mip_level, bool needs_mips, @@ -456,6 +456,7 @@ class CC_EXPORT GpuImageDecodeCache const PaintImage::Id paint_image_id; const DecodedDataMode mode; const size_t size; + gfx::ColorSpace target_color_space; SkFilterQuality quality; int upload_scale_mip_level; bool needs_mips = false; @@ -501,6 +502,7 @@ class CC_EXPORT GpuImageDecodeCache PaintImage::FrameKey frame_key; int upload_scale_mip_level; SkFilterQuality filter_quality; + gfx::ColorSpace target_color_space; }; struct InUseCacheKeyHash { size_t operator()(const InUseCacheKey&) const; @@ -551,6 +553,7 @@ class CC_EXPORT GpuImageDecodeCache const size_t image_width, const size_t image_height, const SkYUVColorSpace* yuva_color_space, + sk_sp<SkColorSpace> target_color_space, sk_sp<SkColorSpace> decoded_color_space) const; scoped_refptr<GpuImageDecodeCache::ImageData> CreateImageData( @@ -590,6 +593,10 @@ class CC_EXPORT GpuImageDecodeCache void UploadImageIfNecessary(const DrawImage& draw_image, ImageData* image_data); + // Flush pending operations on context_->GrContext() for each element of + // |yuv_images| and then clear the vector. + void FlushYUVImages(std::vector<sk_sp<SkImage>>* yuv_images); + // Runs pending operations that required the |context_| lock to be held, but // were queued up during a time when the |context_| lock was unavailable. // These including deleting, unlocking, and locking textures. @@ -657,16 +664,14 @@ class CC_EXPORT GpuImageDecodeCache std::vector<sk_sp<SkImage>> images_pending_deletion_; // Images that are backed by planar textures must be handled differently // to avoid inadvertently flattening to RGB and creating additional textures. + // See comment in RunPendingContextThreadOperations(). std::vector<sk_sp<SkImage>> yuv_images_pending_deletion_; + std::vector<sk_sp<SkImage>> yuv_images_pending_unlock_; const sk_sp<SkColorSpace> target_color_space_; std::vector<uint32_t> ids_pending_unlock_; std::vector<uint32_t> ids_pending_deletion_; - // Records the maximum number of items in the cache over the lifetime of the - // cache. This is updated anytime we are requested to reduce cache usage. - size_t lifetime_max_items_in_cache_ = 0u; - std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; }; diff --git a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc index f7d485e215e..a3b7e86666e 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc @@ -47,20 +47,19 @@ class GpuImageDecodeCachePerfTest kTimeCheckInterval), context_provider_(base::MakeRefCounted<TestInProcessContextProvider>( UseTransferCache(), - false /* support_locking */)) { + false /* support_locking */)), + cache_(context_provider_.get(), + UseTransferCache(), + kRGBA_8888_SkColorType, + kCacheSize, + MaxTextureSize(), + PaintImage::kDefaultGeneratorClientId) { // Initializing context here is ok because image decode cache does not use // context provider in its constructor. gpu::ContextResult result = context_provider_->BindToCurrentThread(); DCHECK_EQ(result, gpu::ContextResult::kSuccess); } - void CreateCache(sk_sp<SkColorSpace> color_space = nullptr) { - cache_ = std::make_unique<GpuImageDecodeCache>( - context_provider_.get(), UseTransferCache(), kRGBA_8888_SkColorType, - kCacheSize, MaxTextureSize(), PaintImage::kDefaultGeneratorClientId, - std::move(color_space)); - } - protected: size_t MaxTextureSize() const { switch (GetParam()) { @@ -89,7 +88,7 @@ class GpuImageDecodeCachePerfTest base::LapTimer timer_; scoped_refptr<TestInProcessContextProvider> context_provider_; - std::unique_ptr<GpuImageDecodeCache> cache_; + GpuImageDecodeCache cache_; }; INSTANTIATE_TEST_SUITE_P(P, @@ -99,7 +98,6 @@ INSTANTIATE_TEST_SUITE_P(P, TestMode::kSw)); TEST_P(GpuImageDecodeCachePerfTest, DecodeWithColorConversion) { - CreateCache(gfx::ColorSpace::CreateXYZD50().ToSkColorSpace()); timer_.Reset(); do { DrawImage image( @@ -108,10 +106,11 @@ TEST_P(GpuImageDecodeCachePerfTest, DecodeWithColorConversion) { .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId()) .TakePaintImage(), SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality, - CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u); + CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u, + gfx::ColorSpace::CreateXYZD50()); - DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image); - cache_->DrawWithImageFinished(image, decoded_image); + DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image); + cache_.DrawWithImageFinished(image, decoded_image); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -132,7 +131,6 @@ TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) { context_provider_->GrContext(), SkBudgeted::kNo, SkImageInfo::MakeN32Premul(2048, 2048)); - CreateCache(); timer_.Reset(); do { DrawImage image( @@ -141,9 +139,9 @@ TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) { .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId()) .TakePaintImage(), SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality, - CreateMatrix(SkSize::Make(0.6f, 0.6f)), 0u); + CreateMatrix(SkSize::Make(0.6f, 0.6f)), 0u, gfx::ColorSpace()); - DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image); + DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image); if (GetParam() == TestMode::kGpu) { SkPaint paint; @@ -154,7 +152,7 @@ TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) { surface->flush(); } - cache_->DrawWithImageFinished(image, decoded_image); + cache_.DrawWithImageFinished(image, decoded_image); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); @@ -164,21 +162,21 @@ TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) { TEST_P(GpuImageDecodeCachePerfTest, AcquireExistingImages) { timer_.Reset(); - CreateCache(gfx::ColorSpace::CreateXYZD50().ToSkColorSpace()); DrawImage image( PaintImageBuilder::WithDefault() .set_id(PaintImage::GetNextId()) .set_image(CreateImage(1024, 2048), PaintImage::GetNextContentId()) .TakePaintImage(), SkIRect::MakeWH(1024, 2048), kMedium_SkFilterQuality, - CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u); + CreateMatrix(SkSize::Make(1.0f, 1.0f)), 0u, + gfx::ColorSpace::CreateXYZD50()); - DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image); - cache_->DrawWithImageFinished(image, decoded_image); + DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image); + cache_.DrawWithImageFinished(image, decoded_image); do { - DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image); - cache_->DrawWithImageFinished(image, decoded_image); + DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(image); + cache_.DrawWithImageFinished(image, decoded_image); timer_.NextLap(); } while (!timer_.HasTimeLimitExpired()); diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc index 087f8b26620..77f3210c518 100644 --- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc @@ -283,15 +283,10 @@ class GpuImageDecodeCacheTest } std::unique_ptr<GpuImageDecodeCache> CreateCache() { - return CreateCache(DefaultColorSpace()); - } - - std::unique_ptr<GpuImageDecodeCache> CreateCache( - const gfx::ColorSpace& color_space) { return std::make_unique<GpuImageDecodeCache>( context_provider_.get(), use_transfer_cache_, color_type_, kGpuMemoryLimitBytes, max_texture_size_, - PaintImage::kDefaultGeneratorClientId, color_space.ToSkColorSpace()); + PaintImage::kDefaultGeneratorClientId); } // Returns dimensions for an image that will not fit in GPU memory and hence @@ -446,7 +441,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -455,7 +450,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) { DrawImage another_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -477,7 +472,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -490,7 +485,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) { DrawImage another_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); @@ -518,7 +513,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), kHigh_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -526,7 +521,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) { DrawImage another_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); + kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, + DefaultColorSpace()); ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -548,7 +544,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -559,7 +555,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) { second_image, SkIRect::MakeWH(second_image.width(), second_image.height()), quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -584,7 +580,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -598,7 +594,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -608,7 +604,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) { DrawImage third_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -630,7 +626,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -639,7 +635,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -649,7 +645,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) { DrawImage third_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( third_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(third_result.need_unref); @@ -673,7 +669,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) { PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize()); DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); + kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, + DefaultColorSpace()); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -686,7 +683,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); + kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, + DefaultColorSpace()); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -707,7 +705,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -749,7 +747,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -791,7 +789,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -822,7 +820,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -865,7 +863,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -912,7 +910,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -941,7 +939,7 @@ TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -971,7 +969,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1005,7 +1003,7 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1041,7 +1039,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1075,7 +1073,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), kLow_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1087,7 +1085,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) { DrawImage larger_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult larger_result = cache->GetTaskForImageAndRef( larger_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(larger_result.need_unref); @@ -1129,7 +1127,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) { PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1140,7 +1138,8 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) { DrawImage higher_quality_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); + kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, + DefaultColorSpace()); ImageDecodeCache::TaskResult hq_result = cache->GetTaskForImageAndRef( higher_quality_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(hq_result.need_unref); @@ -1182,7 +1181,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1221,7 +1220,7 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1264,7 +1263,7 @@ TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1307,7 +1306,7 @@ TEST_P(GpuImageDecodeCacheTest, DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. @@ -1345,7 +1344,7 @@ TEST_P(GpuImageDecodeCacheTest, DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); // Must hold context lock before calling GetDecodedImageForDraw / // DrawWithImageFinished. @@ -1382,7 +1381,7 @@ TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1410,7 +1409,7 @@ TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) { image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1436,7 +1435,7 @@ TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) { DrawImage draw_image( image, SkIRect::MakeXYWH(0, 0, image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1462,7 +1461,7 @@ TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); { ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); @@ -1524,7 +1523,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -1539,7 +1538,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -1572,7 +1571,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -1591,7 +1590,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -1615,9 +1614,10 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable); // Create an image with kLow_FilterQuality. - DrawImage low_draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), - kLow_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); + DrawImage low_draw_image(image, + SkIRect::MakeWH(image.width(), image.height()), + kLow_SkFilterQuality, matrix, + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult low_result = cache->GetTaskForImageAndRef( low_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(low_result.need_unref); @@ -1627,7 +1627,8 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { // should get a new task/ref. DrawImage medium_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), - kMedium_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); + kMedium_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, + DefaultColorSpace()); ImageDecodeCache::TaskResult medium_result = cache->GetTaskForImageAndRef( medium_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(medium_result.need_unref); @@ -1637,7 +1638,8 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) { // Get the same image at kHigh_FilterQuality. We should re-use medium. DrawImage high_quality_draw_image( image, SkIRect::MakeWH(image.width(), image.height()), - kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex); + kHigh_SkFilterQuality, matrix, PaintImage::kDefaultFrameIndex, + DefaultColorSpace()); ImageDecodeCache::TaskResult high_quality_result = cache->GetTaskForImageAndRef(high_quality_draw_image, ImageDecodeCache::TracingInfo()); @@ -1666,7 +1668,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1688,7 +1690,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) { DrawImage draw_image_mips( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image_mips)); cache->DrawWithImageFinished(draw_image_mips, decoded_draw_image); @@ -1702,7 +1704,7 @@ TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) { SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), kLow_SkFilterQuality, matrix, - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image); @@ -1730,7 +1732,7 @@ TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1781,13 +1783,13 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); PaintImage image2 = CreatePaintImageInternal(GetNormalImageSize()); DrawImage draw_image2( image2, SkIRect::MakeWH(image2.width(), image2.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); // Add an image to the cache and un-ref it. { @@ -1864,7 +1866,7 @@ TEST_P(GpuImageDecodeCacheTest, ClearCache) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1894,7 +1896,7 @@ TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1919,16 +1921,64 @@ TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) { EXPECT_EQ(cache->GetNumCacheEntriesForTesting(), 0u); } -TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImage) { +TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) { + auto cache = CreateCache(); + bool is_decomposable = true; + SkFilterQuality quality = kHigh_SkFilterQuality; + + gfx::ColorSpace color_space_a = gfx::ColorSpace::CreateSRGB(); + gfx::ColorSpace color_space_b = gfx::ColorSpace::CreateXYZD50(); + + PaintImage first_image = CreatePaintImageInternal(gfx::Size(100, 100)); + DrawImage first_draw_image( + first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, color_space_a); + ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( + first_draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(first_result.need_unref); + EXPECT_TRUE(first_result.task); + + DrawImage second_draw_image( + first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, color_space_b); + ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( + second_draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(second_result.need_unref); + EXPECT_TRUE(second_result.task); + EXPECT_TRUE(first_result.task.get() != second_result.task.get()); + + DrawImage third_draw_image( + first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, color_space_a); + ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef( + third_draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(third_result.need_unref); + EXPECT_TRUE(third_result.task.get() == first_result.task.get()); + + TestTileTaskRunner::ProcessTask(first_result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(first_result.task.get()); + TestTileTaskRunner::ProcessTask(second_result.task->dependencies()[0].get()); + TestTileTaskRunner::ProcessTask(second_result.task.get()); + + cache->UnrefImage(first_draw_image); + cache->UnrefImage(second_draw_image); + cache->UnrefImage(third_draw_image); +} + +TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) { auto cache = CreateCache(); bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; + gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); PaintImage image = CreateLargePaintImageForSoftwareFallback(); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1966,9 +2016,10 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 1u); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + 1u, DefaultColorSpace()); auto decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -1978,7 +2029,8 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { cache->DrawWithImageFinished(draw_image, decoded_image); // Scaled. - DrawImage scaled_draw_image(draw_image, 0.5f, 2u); + DrawImage scaled_draw_image(draw_image, 0.5f, 2u, + draw_image.target_color_space()); decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(scaled_draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -1994,7 +2046,8 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) { ASSERT_LT(subset_height, test_image_size.height()); DrawImage subset_draw_image( image, SkIRect::MakeWH(subset_width, subset_height), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u); + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u, + DefaultColorSpace()); decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(subset_draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -2014,7 +2067,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) { DrawImage first_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -2028,7 +2081,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) { DrawImage second_draw_image( first_image, SkIRect::MakeWH(first_image.width(), first_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); @@ -2069,7 +2122,7 @@ TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); const size_t bytes_for_test_image = GetBytesNeededForSingleImage(test_image_size); @@ -2116,7 +2169,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); // The image counts against our budget. viz::ContextProvider::ScopedContextLock context_lock(context_provider()); @@ -2130,7 +2183,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) { CreatePaintImageInternal(GetNormalImageSize()), SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); // Should be at raster. ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( @@ -2157,7 +2210,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); const size_t bytes_for_test_image = GetBytesNeededForSingleImage(test_image_size); @@ -2179,7 +2232,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { CreatePaintImageInternal(test_image_size), SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); // Should be at raster. ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( @@ -2198,16 +2251,16 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) { TEST_P(GpuImageDecodeCacheTest, ColorConversionDuringDecodeForLargeImageNonSRGBColorSpace) { - gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); - auto cache = CreateCache(color_space); + auto cache = CreateCache(); bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; + gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50(); PaintImage image = CreateLargePaintImageForSoftwareFallback(); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2253,16 +2306,16 @@ TEST_P(GpuImageDecodeCacheTest, TEST_P(GpuImageDecodeCacheTest, ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) { - gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65(); - auto cache = CreateCache(color_space); + auto cache = CreateCache(); bool is_decomposable = true; const SkFilterQuality quality = kHigh_SkFilterQuality; + gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65(); PaintImage image = CreatePaintImageInternal(gfx::Size(11, 12)); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2314,7 +2367,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadNoScale) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2339,7 +2392,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskHasNoDeps) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2363,7 +2416,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskCancelled) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2380,8 +2433,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) { // YUV bitmap images do not happen, so this test will always skip for YUV. return; } - auto color_space = gfx::ColorSpace::CreateDisplayP3D65(); - auto cache = CreateCache(color_space); + auto cache = CreateCache(); const bool should_cache_sw_image = cache->SupportsColorSpaceConversion() && !use_transfer_cache_; @@ -2389,10 +2441,10 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) { SkFilterQuality quality = kHigh_SkFilterQuality; PaintImage image = CreateBitmapImageInternal(GetLargeImageSize()); - DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), - quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + DrawImage draw_image( + image, SkIRect::MakeWH(image.width(), image.height()), quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, gfx::ColorSpace::CreateDisplayP3D65()); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2404,8 +2456,9 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) { auto sw_image = cache->GetSWImageDecodeForTesting(draw_image); ASSERT_EQ(!!sw_image, should_cache_sw_image); if (should_cache_sw_image) { - EXPECT_TRUE(SkColorSpace::Equals(sw_image->colorSpace(), - color_space.ToSkColorSpace().get())); + EXPECT_TRUE(SkColorSpace::Equals( + sw_image->colorSpace(), + gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace().get())); } } @@ -2422,7 +2475,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadDownscaled) { DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); viz::ContextProvider::ScopedContextLock context_lock(context_provider()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2447,7 +2500,7 @@ TEST_P(GpuImageDecodeCacheTest, KeepOnlyLast2ContentIds) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_draw_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); @@ -2504,7 +2557,7 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); const int expected_width = @@ -2551,7 +2604,7 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_image = EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image)); ASSERT_TRUE(decoded_image.image()); @@ -2571,16 +2624,15 @@ TEST_P(GpuImageDecodeCacheTest, DecodeToScaleNoneQuality) { TEST_P(GpuImageDecodeCacheTest, BasicMips) { auto decode_and_check_mips = [this](SkFilterQuality filter_quality, - SkSize scale, - const gfx::ColorSpace& color_space, + SkSize scale, gfx::ColorSpace color_space, bool should_have_mips) { - auto cache = CreateCache(color_space); + auto cache = CreateCache(); bool is_decomposable = true; PaintImage image = CreatePaintImageInternal(GetNormalImageSize()); DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(scale, is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, color_space); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2656,7 +2708,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2701,7 +2753,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2754,7 +2806,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2792,7 +2844,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) { DrawImage draw_image( image, SkIRect::MakeWH(image.width(), image.height()), filter_quality, CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -2873,7 +2925,7 @@ TEST_P(GpuImageDecodeCacheTest, GetBorderlineLargeDecodedImageForDraw) { almost_too_large_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); diff --git a/chromium/cc/tiles/image_controller_unittest.cc b/chromium/cc/tiles/image_controller_unittest.cc index 05c82a46340..1c3e0d3b215 100644 --- a/chromium/cc/tiles/image_controller_unittest.cc +++ b/chromium/cc/tiles/image_controller_unittest.cc @@ -233,7 +233,7 @@ DrawImage CreateDiscardableDrawImage(gfx::Size size) { return DrawImage(CreateDiscardablePaintImage(size), SkIRect::MakeWH(size.width(), size.height()), kNone_SkFilterQuality, SkMatrix::I(), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, gfx::ColorSpace()); } DrawImage CreateBitmapDrawImage(gfx::Size size) { diff --git a/chromium/cc/tiles/paint_worklet_image_cache.cc b/chromium/cc/tiles/paint_worklet_image_cache.cc index 639bf7d19b1..d0bd702cae7 100644 --- a/chromium/cc/tiles/paint_worklet_image_cache.cc +++ b/chromium/cc/tiles/paint_worklet_image_cache.cc @@ -48,10 +48,7 @@ void PaintWorkletImageCache::SetPaintWorkletLayerPainter( scoped_refptr<TileTask> PaintWorkletImageCache::GetTaskForPaintWorkletImage( const DrawImage& image) { - // As described in crbug.com/939192, the |painter_| could be null, and we - // should not create any raster task. - if (!painter_) - return nullptr; + DCHECK(painter_); DCHECK(image.paint_image().IsPaintWorklet()); return base::MakeRefCounted<PaintWorkletTaskImpl>(this, image.paint_image()); } @@ -74,6 +71,8 @@ void PaintWorkletImageCache::PaintImageInTask(const PaintImage& paint_image) { // matches the PaintGeneratedImage::Draw. sk_sp<PaintRecord> record = painter_->Paint(paint_image.paint_worklet_input()); + if (!record) + return; { base::AutoLock hold(records_lock_); // It is possible for two or more threads to both pass through the first @@ -89,10 +88,7 @@ void PaintWorkletImageCache::PaintImageInTask(const PaintImage& paint_image) { std::pair<sk_sp<PaintRecord>, base::OnceCallback<void()>> PaintWorkletImageCache::GetPaintRecordAndRef(PaintWorkletInput* input) { base::AutoLock hold(records_lock_); - // If the |painter_| was null when GetTaskForPaintWorkletImage was called - // there will be no cache entry for this input. - if (records_.find(input) == records_.end()) - return std::make_pair(sk_make_sp<PaintOpBuffer>(), base::DoNothing::Once()); + DCHECK(records_.find(input) != records_.end()); records_[input].used_ref_count++; records_[input].num_of_frames_not_accessed = 0u; // The PaintWorkletImageCache object lives as long as the LayerTreeHostImpl, diff --git a/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc b/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc index 6ae3c0a0036..7af4b9340c6 100644 --- a/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc +++ b/chromium/cc/tiles/paint_worklet_image_cache_unittest.cc @@ -257,29 +257,5 @@ TEST(PaintWorkletImageCacheTest, CacheEntryLookup) { } } -TEST(PaintWorkletImageCacheTest, TaskIsNullWhenPainterIsNull) { - TestPaintWorkletImageCache cache; - PaintImage paint_image = CreatePaintImage(100, 100); - scoped_refptr<TileTask> task = - GetTaskForPaintWorkletImage(paint_image, &cache); - EXPECT_EQ(task, nullptr); -} - -TEST(PaintWorkletImageCacheTest, - RecordAndCallbackAreEmptyWhenInputWasntPainted) { - TestPaintWorkletImageCache cache; - std::unique_ptr<TestPaintWorkletLayerPainter> painter = - std::make_unique<TestPaintWorkletLayerPainter>(); - cache.SetPaintWorkletLayerPainter(std::move(painter)); - - // We request a record and callback without ever painting the input. - PaintImage paint_image = CreatePaintImage(100, 100); - std::pair<sk_sp<PaintRecord>, base::OnceCallback<void()>> result = - cache.GetPaintRecordAndRef(paint_image.paint_worklet_input()); - EXPECT_EQ(result.first->total_op_count(), 0u); - // This is an empty callback, running it should not crash. - std::move(result.second).Run(); -} - } // namespace } // namespace cc diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc index c2bb32f6e81..f858a180756 100644 --- a/chromium/cc/tiles/software_image_decode_cache.cc +++ b/chromium/cc/tiles/software_image_decode_cache.cc @@ -16,7 +16,6 @@ #include "cc/base/histograms.h" #include "cc/raster/tile_task.h" #include "cc/tiles/mipmap_util.h" -#include "ui/gfx/color_space.h" #include "ui/gfx/skia_util.h" using base::trace_event::MemoryAllocatorDump; @@ -143,10 +142,8 @@ void RecordLockExistingCachedImageHistogram(TilePriority::PriorityBin bin, SoftwareImageDecodeCache::SoftwareImageDecodeCache( SkColorType color_type, size_t locked_memory_limit_bytes, - PaintImage::GeneratorClientId generator_client_id, - sk_sp<SkColorSpace> target_color_space) + PaintImage::GeneratorClientId generator_client_id) : decoded_images_(ImageMRUCache::NO_AUTO_EVICT), - target_color_space_(std::move(target_color_space)), locked_images_budget_(locked_memory_limit_bytes), color_type_(color_type), generator_client_id_(generator_client_id), @@ -167,16 +164,6 @@ SoftwareImageDecodeCache::~SoftwareImageDecodeCache() { // It is safe to unregister, even if we didn't register in the constructor. base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( this); - // TODO(vmpstr): If we don't have a client name, it may cause problems in - // unittests, since most tests don't set the name but some do. The UMA system - // expects the name to be always the same. This assertion is violated in the - // tests that do set the name. - if (GetClientNameForMetrics()) { - UMA_HISTOGRAM_CUSTOM_COUNTS( - base::StringPrintf("Compositing.%s.CachedImagesCount.Software", - GetClientNameForMetrics()), - lifetime_max_items_in_cache_, 1, 1000, 20); - } } ImageDecodeCache::TaskResult SoftwareImageDecodeCache::GetTaskForImageAndRef( @@ -316,8 +303,8 @@ void SoftwareImageDecodeCache::UnrefImage(const CacheKey& key) { void SoftwareImageDecodeCache::DecodeImageInTask(const CacheKey& key, const PaintImage& paint_image, DecodeTaskType task_type) { - TRACE_EVENT1("cc", "SoftwareImageDecodeCache::DecodeImageInTask", "key", - key.ToString()); + TRACE_EVENT1("cc,benchmark", "SoftwareImageDecodeCache::DecodeImageInTask", + "key", key.ToString()); base::AutoLock lock(lock_); auto image_it = decoded_images_.Peek(key); @@ -367,9 +354,8 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary( // If we can use the original decode, we'll definitely need a decode. if (key.type() == CacheKey::kOriginal) { base::AutoUnlock release(lock_); - local_cache_entry = - Utils::DoDecodeImage(key, paint_image, color_type_, target_color_space_, - generator_client_id_); + local_cache_entry = Utils::DoDecodeImage(key, paint_image, color_type_, + generator_client_id_); } else { // Attempt to find a cached decode to generate a scaled/subrected decode // from. @@ -396,9 +382,8 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary( DCHECK(!should_decode_to_scale || !key.is_nearest_neighbor()); if (should_decode_to_scale) { base::AutoUnlock release(lock_); - local_cache_entry = - Utils::DoDecodeImage(key, paint_image, color_type_, - target_color_space_, generator_client_id_); + local_cache_entry = Utils::DoDecodeImage(key, paint_image, color_type_, + generator_client_id_); } // Couldn't decode to scale or find a cached candidate. Create the @@ -423,9 +408,9 @@ void SoftwareImageDecodeCache::DecodeImageIfNecessary( key.type() == CacheKey::kSubrectOriginal ? SkIRect::MakeWH(paint_image.width(), paint_image.height()) : gfx::RectToSkIRect(key.src_rect()); - DrawImage candidate_draw_image(paint_image, src_rect, - kNone_SkFilterQuality, SkMatrix::I(), - key.frame_key().frame_index()); + DrawImage candidate_draw_image( + paint_image, src_rect, kNone_SkFilterQuality, SkMatrix::I(), + key.frame_key().frame_index(), key.target_color_space()); candidate_key.emplace( CacheKey::FromDrawImage(candidate_draw_image, color_type_)); } @@ -526,7 +511,9 @@ bool SoftwareImageDecodeCache::UseCacheForDrawImage( // Cache images that need to be converted to a non-sRGB color space. // TODO(ccameron): Consider caching when any color conversion is required. // https://crbug.com/791828 - if (target_color_space_ && !target_color_space_->isSRGB()) { + const gfx::ColorSpace& dst_color_space = draw_image.target_color_space(); + if (dst_color_space.IsValid() && + dst_color_space != gfx::ColorSpace::CreateSRGB()) { return true; } @@ -587,8 +574,6 @@ void SoftwareImageDecodeCache::DrawWithImageFinished( void SoftwareImageDecodeCache::ReduceCacheUsageUntilWithinLimit(size_t limit) { TRACE_EVENT0("cc", "SoftwareImageDecodeCache::ReduceCacheUsageUntilWithinLimit"); - lifetime_max_items_in_cache_ = - std::max(lifetime_max_items_in_cache_, decoded_images_.size()); for (auto it = decoded_images_.rbegin(); decoded_images_.size() > limit && it != decoded_images_.rend();) { if (it->second->ref_count != 0) { diff --git a/chromium/cc/tiles/software_image_decode_cache.h b/chromium/cc/tiles/software_image_decode_cache.h index eb7cc161f1d..c3b7c03303d 100644 --- a/chromium/cc/tiles/software_image_decode_cache.h +++ b/chromium/cc/tiles/software_image_decode_cache.h @@ -34,8 +34,7 @@ class CC_EXPORT SoftwareImageDecodeCache SoftwareImageDecodeCache(SkColorType color_type, size_t locked_memory_limit_bytes, - PaintImage::GeneratorClientId generator_client_id, - sk_sp<SkColorSpace> target_color_space); + PaintImage::GeneratorClientId generator_client_id); ~SoftwareImageDecodeCache() override; // ImageDecodeCache overrides. @@ -151,16 +150,12 @@ class CC_EXPORT SoftwareImageDecodeCache PaintImage::FrameKeyHash> frame_key_to_image_keys_; - const sk_sp<SkColorSpace> target_color_space_; MemoryBudget locked_images_budget_; const SkColorType color_type_; const PaintImage::GeneratorClientId generator_client_id_; size_t max_items_in_cache_; - // Records the maximum number of items in the cache over the lifetime of the - // cache. This is updated anytime we are requested to reduce cache usage. - size_t lifetime_max_items_in_cache_ = 0u; }; } // namespace cc diff --git a/chromium/cc/tiles/software_image_decode_cache_perftest.cc b/chromium/cc/tiles/software_image_decode_cache_perftest.cc index f873c9774bb..fb99fb7c3f6 100644 --- a/chromium/cc/tiles/software_image_decode_cache_perftest.cc +++ b/chromium/cc/tiles/software_image_decode_cache_perftest.cc @@ -63,7 +63,8 @@ class SoftwareImageDecodeCachePerfTest : public testing::Test { PaintImage::GetNextContentId()) .TakePaintImage(), subrect, quality, - CreateMatrix(SkSize::Make(scale.first, scale.second)), 0u); + CreateMatrix(SkSize::Make(scale.first, scale.second)), 0u, + gfx::ColorSpace()); } } } diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest.cc b/chromium/cc/tiles/software_image_decode_cache_unittest.cc index 18f6d88444b..3e31e7a9a4b 100644 --- a/chromium/cc/tiles/software_image_decode_cache_unittest.cc +++ b/chromium/cc/tiles/software_image_decode_cache_unittest.cc @@ -23,13 +23,9 @@ size_t kLockedMemoryLimitBytes = 128 * 1024 * 1024; class TestSoftwareImageDecodeCache : public SoftwareImageDecodeCache { public: TestSoftwareImageDecodeCache() - : TestSoftwareImageDecodeCache(DefaultColorSpace()) {} - - explicit TestSoftwareImageDecodeCache(const gfx::ColorSpace& color_space) : SoftwareImageDecodeCache(kN32_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId, - color_space.ToSkColorSpace()) {} + PaintImage::kDefaultGeneratorClientId) {} }; SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) { @@ -58,7 +54,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyNoneQuality) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kNone_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -80,7 +76,7 @@ TEST(SoftwareImageDecodeCacheTest, paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kLow_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -98,7 +94,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropsToLowIfMipLevel0) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -117,7 +113,7 @@ TEST(SoftwareImageDecodeCacheTest, LowUnscalableFormatStaysLow) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kLow_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kARGB_4444_SkColorType); @@ -136,7 +132,7 @@ TEST(SoftwareImageDecodeCacheTest, HighUnscalableFormatBecomesLow) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kHigh_SkFilterQuality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kARGB_4444_SkColorType); @@ -155,7 +151,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityKeptLowIfUpscale) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kLow_SkFilterQuality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -175,7 +171,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQuality) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.4f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -194,7 +190,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfEnlarging) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -214,7 +210,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfIdentity) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -235,7 +231,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -256,7 +252,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -277,7 +273,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -298,7 +294,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_5Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -318,7 +314,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_0cale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -338,7 +334,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityAt0_75Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -358,7 +354,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_5Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -377,7 +373,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_49Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -396,7 +392,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_1Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -415,7 +411,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_01Scale) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -435,7 +431,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.2f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -454,7 +450,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyUpscaleIsLowQuality) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(2.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -477,7 +473,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToMediumIfTooLarge) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.45f, 0.45f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -497,7 +493,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -517,7 +513,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToLowIfIdentity) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -538,7 +534,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -559,7 +555,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -594,7 +590,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyDownscaleMipLevelWithRounding) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(0.2f, 0.2f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -614,7 +610,7 @@ TEST(SoftwareImageDecodeCacheTest, OriginalDecodesAreEqual) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -628,7 +624,7 @@ TEST(SoftwareImageDecodeCacheTest, OriginalDecodesAreEqual) { DrawImage another_draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto another_key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( another_draw_image, kN32_SkColorType); @@ -651,7 +647,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRect) { paint_image, SkIRect::MakeXYWH(25, 35, paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -672,7 +668,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRectWithScale) { paint_image, SkIRect::MakeXYWH(20, 30, paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( draw_image, kN32_SkColorType); @@ -693,7 +689,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -702,7 +698,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) { DrawImage another_draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult another_result = cache.GetTaskForImageAndRef( another_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(another_result.need_unref); @@ -723,7 +719,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageProcessUnrefCancel) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -753,7 +749,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kHigh_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult high_quality_result = cache.GetTaskForImageAndRef(high_quality_draw_image, ImageDecodeCache::TracingInfo()); @@ -764,7 +760,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), kNone_SkFilterQuality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult none_quality_result = cache.GetTaskForImageAndRef(none_quality_draw_image, ImageDecodeCache::TracingInfo()); @@ -788,7 +784,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) { DrawImage half_size_draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult half_size_result = cache.GetTaskForImageAndRef( half_size_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(half_size_result.need_unref); @@ -797,7 +793,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) { DrawImage quarter_size_draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult quarter_size_result = cache.GetTaskForImageAndRef(quarter_size_draw_image, ImageDecodeCache::TracingInfo()); @@ -822,7 +818,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) { first_paint_image, SkIRect::MakeWH(first_paint_image.width(), first_paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult first_result = cache.GetTaskForImageAndRef( first_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(first_result.need_unref); @@ -833,18 +829,75 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) { second_paint_image, SkIRect::MakeWH(second_paint_image.width(), second_paint_image.height()), quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); + ImageDecodeCache::TaskResult second_result = cache.GetTaskForImageAndRef( + second_draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(second_result.need_unref); + EXPECT_TRUE(second_result.task); + EXPECT_TRUE(first_result.task.get() != second_result.task.get()); + + TestTileTaskRunner::ProcessTask(first_result.task.get()); + TestTileTaskRunner::ProcessTask(second_result.task.get()); + + cache.UnrefImage(first_draw_image); + cache.UnrefImage(second_draw_image); +} + +// crbug.com/709341 +#if defined(MEMORY_SANITIZER) +#define MAYBE_GetTaskForImageDifferentColorSpace \ + DISABLED_GetTaskForImageDifferentColorSpace +#else +#define MAYBE_GetTaskForImageDifferentColorSpace \ + GetTaskForImageDifferentColorSpace +#endif +TEST(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) { + TestSoftwareImageDecodeCache cache; + bool is_decomposable = true; + SkFilterQuality quality = kHigh_SkFilterQuality; + + gfx::ColorSpace color_space_a(gfx::ColorSpace::PrimaryID::XYZ_D50, + gfx::ColorSpace::TransferID::IEC61966_2_1); + gfx::ColorSpace color_space_b(gfx::ColorSpace::PrimaryID::SMPTE170M, + gfx::ColorSpace::TransferID::IEC61966_2_1); + gfx::ColorSpace color_space_c = gfx::ColorSpace::CreateSRGB(); + + PaintImage paint_image = CreatePaintImage(100, 100, color_space_a); + DrawImage first_draw_image( + paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, color_space_b); + ImageDecodeCache::TaskResult first_result = cache.GetTaskForImageAndRef( + first_draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(first_result.need_unref); + EXPECT_TRUE(first_result.task); + + DrawImage second_draw_image( + paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, color_space_c); ImageDecodeCache::TaskResult second_result = cache.GetTaskForImageAndRef( second_draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(second_result.need_unref); EXPECT_TRUE(second_result.task); EXPECT_TRUE(first_result.task.get() != second_result.task.get()); + DrawImage third_draw_image( + paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), + quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + PaintImage::kDefaultFrameIndex, color_space_b); + ImageDecodeCache::TaskResult third_result = cache.GetTaskForImageAndRef( + third_draw_image, ImageDecodeCache::TracingInfo()); + EXPECT_TRUE(third_result.need_unref); + EXPECT_TRUE(third_result.task); + EXPECT_TRUE(first_result.task.get() == third_result.task.get()); + TestTileTaskRunner::ProcessTask(first_result.task.get()); TestTileTaskRunner::ProcessTask(second_result.task.get()); cache.UnrefImage(first_draw_image); cache.UnrefImage(second_draw_image); + cache.UnrefImage(third_draw_image); } TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyDecoded) { @@ -856,7 +909,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyDecoded) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -885,7 +938,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyPrerolled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -920,7 +973,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -961,7 +1014,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1001,7 +1054,7 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDraw) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1034,7 +1087,7 @@ TEST(SoftwareImageDecodeCacheTest, paint_image, SkIRect::MakeXYWH(20, 30, paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1065,7 +1118,7 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); @@ -1090,7 +1143,7 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); @@ -1120,7 +1173,7 @@ TEST(SoftwareImageDecodeCacheTest, ZeroSizedImagesAreSkipped) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1144,7 +1197,7 @@ TEST(SoftwareImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) { paint_image, SkIRect::MakeXYWH(150, 150, paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1167,7 +1220,7 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityFilterIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1195,7 +1248,7 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityScaledSubrectIsHandled) { PaintImage paint_image = CreatePaintImage(100, 100); DrawImage draw_image(paint_image, SkIRect::MakeXYWH(10, 10, 80, 80), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1228,7 +1281,7 @@ TEST(SoftwareImageDecodeCacheTest, NoneQualityScaledSubrectIsHandled) { PaintImage paint_image = CreatePaintImage(100, 100); DrawImage draw_image(paint_image, SkIRect::MakeXYWH(10, 10, 80, 80), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1259,7 +1312,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt01_5ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1290,7 +1343,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt1_0ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1321,7 +1374,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_75ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1352,7 +1405,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_5ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1383,7 +1436,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_49ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1414,7 +1467,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_1ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1445,7 +1498,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_01ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1476,7 +1529,7 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_001ScaleIsHandled) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.001f, 0.001f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1500,11 +1553,11 @@ TEST(SoftwareImageDecodeCacheTest, DrawImage draw_image_50( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DrawImage draw_image_49( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result_50 = cache.GetTaskForImageAndRef( draw_image_50, ImageDecodeCache::TracingInfo()); @@ -1551,7 +1604,7 @@ TEST(SoftwareImageDecodeCacheTest, ClearCache) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef( draw_image, ImageDecodeCache::TracingInfo()); EXPECT_TRUE(result.need_unref); @@ -1586,9 +1639,10 @@ TEST(SoftwareImageDecodeCacheTest, CacheDecodesExpectedFrames) { bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; - DrawImage draw_image( - image, SkIRect::MakeWH(image.width(), image.height()), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 1u); + DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()), + quality, + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), + 1u, DefaultColorSpace()); auto decoded_image = cache.GetDecodedImageForDraw(draw_image); ASSERT_TRUE(decoded_image.image()); ASSERT_EQ(generator->frames_decoded().size(), 1u); @@ -1597,7 +1651,8 @@ TEST(SoftwareImageDecodeCacheTest, CacheDecodesExpectedFrames) { cache.DrawWithImageFinished(draw_image, decoded_image); // Scaled. - DrawImage scaled_draw_image(draw_image, 0.5f, 2u); + DrawImage scaled_draw_image(draw_image, 0.5f, 2u, + draw_image.target_color_space()); decoded_image = cache.GetDecodedImageForDraw(scaled_draw_image); ASSERT_TRUE(decoded_image.image()); ASSERT_EQ(generator->frames_decoded().size(), 1u); @@ -1608,7 +1663,8 @@ TEST(SoftwareImageDecodeCacheTest, CacheDecodesExpectedFrames) { // Subset. DrawImage subset_draw_image( image, SkIRect::MakeWH(5, 5), quality, - CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u); + CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u, + DefaultColorSpace()); decoded_image = cache.GetDecodedImageForDraw(subset_draw_image); ASSERT_TRUE(decoded_image.image()); ASSERT_EQ(generator->frames_decoded().size(), 1u); @@ -1628,7 +1684,7 @@ TEST(SoftwareImageDecodeCacheTest, SizeSubrectingIsHandled) { DefaultColorSpace().ToSkColorSpace(), false); DrawImage draw_image(paint_image, SkIRect::MakeXYWH(0, 0, 10, 10), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo()); @@ -1661,7 +1717,7 @@ TEST(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) { gfx::Size(100, 100), DefaultColorSpace().ToSkColorSpace()); DrawImage draw_image(paint_image, SkIRect::MakeWH(100, 100), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); EXPECT_TRUE(decoded_draw_image.image()); @@ -1671,7 +1727,7 @@ TEST(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) { DrawImage empty_draw_image( paint_image, SkIRect::MakeEmpty(), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage empty_decoded_draw_image = cache.GetDecodedImageForDraw(empty_draw_image); EXPECT_FALSE(empty_decoded_draw_image.image()); @@ -1679,16 +1735,16 @@ TEST(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) { } TEST(SoftwareImageDecodeCacheTest, BitmapImageColorConverted) { - gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateDisplayP3D65(); - TestSoftwareImageDecodeCache cache(target_color_space); + TestSoftwareImageDecodeCache cache; bool is_decomposable = true; SkFilterQuality quality = kHigh_SkFilterQuality; + gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateDisplayP3D65(); PaintImage paint_image = CreateBitmapImage(gfx::Size(100, 100)); DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, target_color_space); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); @@ -1712,7 +1768,7 @@ TEST(SoftwareImageDecodeCacheTest, BitmapImageNotColorConverted) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); // The cache should not support this image. EXPECT_FALSE(cache.UseCacheForDrawImage(draw_image)); @@ -1738,7 +1794,7 @@ TEST(SoftwareImageDecodeCacheTest, DISABLED_ContentIdCaching) { paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(scale, scale), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_draw_image = cache.GetDecodedImageForDraw(draw_image); EXPECT_TRUE(decoded_draw_image.image()); @@ -1777,7 +1833,7 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScale) { DrawImage draw_image1( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_image1 = cache.GetDecodedImageForDraw(draw_image1); ASSERT_TRUE(decoded_image1.image()); EXPECT_EQ(decoded_image1.image()->width(), 50); @@ -1794,7 +1850,7 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScale) { DrawImage draw_image2( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.25, 0.25), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_image2 = cache.GetDecodedImageForDraw(draw_image2); ASSERT_TRUE(decoded_image2.image()); EXPECT_EQ(decoded_image2.image()->width(), 25); @@ -1834,7 +1890,7 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScaleSubrect) { // subrect vetoes decode to scale. DrawImage draw_image(paint_image, SkIRect::MakeWH(50, 50), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image); ASSERT_TRUE(decoded_image.image()); EXPECT_EQ(decoded_image.image()->width(), 25); @@ -1870,7 +1926,7 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScaleNoneQuality) { DrawImage draw_image( paint_image, SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality, CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, DefaultColorSpace()); DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image); ASSERT_TRUE(decoded_image.image()); EXPECT_EQ(decoded_image.image()->width(), 100); diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc b/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc index 03d3e09e2f5..5052a2a5d21 100644 --- a/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc +++ b/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc @@ -50,7 +50,7 @@ class BaseTest : public testing::Test { ? SkIRect::MakeWH(paint_image().width(), paint_image().height()) : src_rect, kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(scale, scale), true), - PaintImage::kDefaultFrameIndex); + PaintImage::kDefaultFrameIndex, GetColorSpace()); } SoftwareImageDecodeCache& cache() { return *cache_; } @@ -80,8 +80,7 @@ class N32Cache : public virtual BaseTest { std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override { return std::make_unique<SoftwareImageDecodeCache>( kN32_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId, - GetColorSpace().ToSkColorSpace()); + PaintImage::kDefaultGeneratorClientId); } }; @@ -90,8 +89,7 @@ class RGBA4444Cache : public virtual BaseTest { std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override { return std::make_unique<SoftwareImageDecodeCache>( kARGB_4444_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId, - GetColorSpace().ToSkColorSpace()); + PaintImage::kDefaultGeneratorClientId); } }; @@ -100,8 +98,7 @@ class RGBA_F16Cache : public virtual BaseTest { std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override { return std::make_unique<SoftwareImageDecodeCache>( kRGBA_F16_SkColorType, kLockedMemoryLimitBytes, - PaintImage::kDefaultGeneratorClientId, - GetColorSpace().ToSkColorSpace()); + PaintImage::kDefaultGeneratorClientId); } }; @@ -138,6 +135,9 @@ class Predecode : public virtual BaseTest { const DrawImage& draw_image, const gfx::Size& expected_size) override { auto decoded = cache().GetDecodedImageForDraw(draw_image); + EXPECT_TRUE(SkColorSpace::Equals( + decoded.image()->colorSpace(), + draw_image.target_color_space().ToSkColorSpace().get())); SCOPED_TRACE(base::StringPrintf("Failure from line %d", line)); EXPECT_EQ(decoded.image()->width(), expected_size.width()); EXPECT_EQ(decoded.image()->height(), expected_size.height()); diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.cc b/chromium/cc/tiles/software_image_decode_cache_utils.cc index fac25c22ae6..b3dae159e5d 100644 --- a/chromium/cc/tiles/software_image_decode_cache_utils.cc +++ b/chromium/cc/tiles/software_image_decode_cache_utils.cc @@ -59,7 +59,6 @@ SoftwareImageDecodeCacheUtils::DoDecodeImage( const CacheKey& key, const PaintImage& paint_image, SkColorType color_type, - sk_sp<SkColorSpace> color_space, PaintImage::GeneratorClientId client_id) { SkISize target_size = SkISize::Make(key.target_size().width(), key.target_size().height()); @@ -75,7 +74,7 @@ SoftwareImageDecodeCacheUtils::DoDecodeImage( "SoftwareImageDecodeCacheUtils::DoDecodeImage - " "decode"); bool result = paint_image.Decode(target_pixels->data(), &target_info, - std::move(color_space), + key.target_color_space().ToSkColorSpace(), key.frame_key().frame_index(), client_id); if (!result) { target_pixels->Unlock(); @@ -181,7 +180,7 @@ SoftwareImageDecodeCacheUtils::CacheKey::FromDrawImage(const DrawImage& image, // the filter quality doesn't matter. Early out instead. if (target_size.IsEmpty()) { return CacheKey(frame_key, stable_id, kSubrectAndScale, false, src_rect, - target_size); + target_size, image.target_color_space()); } ProcessingType type = kOriginal; @@ -234,7 +233,7 @@ SoftwareImageDecodeCacheUtils::CacheKey::FromDrawImage(const DrawImage& image, } return CacheKey(frame_key, stable_id, type, is_nearest_neighbor, src_rect, - target_size); + target_size, image.target_color_space()); } SoftwareImageDecodeCacheUtils::CacheKey::CacheKey( @@ -243,13 +242,15 @@ SoftwareImageDecodeCacheUtils::CacheKey::CacheKey( ProcessingType type, bool is_nearest_neighbor, const gfx::Rect& src_rect, - const gfx::Size& target_size) + const gfx::Size& target_size, + const gfx::ColorSpace& target_color_space) : frame_key_(frame_key), stable_id_(stable_id), type_(type), is_nearest_neighbor_(is_nearest_neighbor), src_rect_(src_rect), - target_size_(target_size) { + target_size_(target_size), + target_color_space_(target_color_space) { if (type == kOriginal) { hash_ = frame_key_.hash(); } else { @@ -266,6 +267,8 @@ SoftwareImageDecodeCacheUtils::CacheKey::CacheKey( hash_ = base::HashInts(base::HashInts(src_rect_hash, target_size_hash), frame_key_.hash()); } + // Include the target color space in the hash regardless of scaling. + hash_ = base::HashInts(hash_, target_color_space.GetHash()); } SoftwareImageDecodeCacheUtils::CacheKey::CacheKey(const CacheKey& other) = @@ -287,6 +290,7 @@ std::string SoftwareImageDecodeCacheUtils::CacheKey::ToString() const { } str << "]\nis_nearest_neightbor[" << is_nearest_neighbor_ << "]\nsrc_rect[" << src_rect_.ToString() << "]\ntarget_size[" << target_size_.ToString() + << "]\ntarget_color_space[" << target_color_space_.ToString() << "]\nhash[" << hash_ << "]"; return str.str(); } diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.h b/chromium/cc/tiles/software_image_decode_cache_utils.h index 42d7b0205ce..835d68c8492 100644 --- a/chromium/cc/tiles/software_image_decode_cache_utils.h +++ b/chromium/cc/tiles/software_image_decode_cache_utils.h @@ -16,6 +16,7 @@ #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkImageInfo.h" #include "third_party/skia/include/core/SkSize.h" +#include "ui/gfx/color_space.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -56,6 +57,7 @@ class SoftwareImageDecodeCacheUtils { // image. DCHECK(!is_nearest_neighbor_ || type_ == kOriginal); return frame_key_ == other.frame_key_ && type_ == other.type_ && + target_color_space_ == other.target_color_space_ && (type_ == kOriginal || (src_rect_ == other.src_rect_ && target_size_ == other.target_size_)); } @@ -68,6 +70,9 @@ class SoftwareImageDecodeCacheUtils { bool is_nearest_neighbor() const { return is_nearest_neighbor_; } gfx::Rect src_rect() const { return src_rect_; } gfx::Size target_size() const { return target_size_; } + const gfx::ColorSpace& target_color_space() const { + return target_color_space_; + } size_t get_hash() const { return hash_; } @@ -89,7 +94,8 @@ class SoftwareImageDecodeCacheUtils { ProcessingType type, bool is_nearest_neighbor, const gfx::Rect& src_rect, - const gfx::Size& size); + const gfx::Size& size, + const gfx::ColorSpace& target_color_space); PaintImage::FrameKey frame_key_; // The stable id is does not factor into the cache key's value for hashing @@ -100,6 +106,7 @@ class SoftwareImageDecodeCacheUtils { bool is_nearest_neighbor_; gfx::Rect src_rect_; gfx::Size target_size_; + gfx::ColorSpace target_color_space_; size_t hash_; }; @@ -179,7 +186,6 @@ class SoftwareImageDecodeCacheUtils { const CacheKey& key, const PaintImage& image, SkColorType color_type, - sk_sp<SkColorSpace> color_space, PaintImage::GeneratorClientId client_id); static std::unique_ptr<CacheEntry> GenerateCacheEntryFromCandidate( const CacheKey& key, diff --git a/chromium/cc/tiles/tile_draw_info.cc b/chromium/cc/tiles/tile_draw_info.cc index 0c09fa281d7..f5c3138851a 100644 --- a/chromium/cc/tiles/tile_draw_info.cc +++ b/chromium/cc/tiles/tile_draw_info.cc @@ -22,7 +22,6 @@ void TileDrawInfo::AsValueInto(base::trace_event::TracedValue* state) const { void TileDrawInfo::SetResource(ResourcePool::InUsePoolResource resource, bool resource_is_checker_imaged, - bool contents_swizzled, bool is_premultiplied) { DCHECK(!resource_); DCHECK(resource); @@ -30,7 +29,6 @@ void TileDrawInfo::SetResource(ResourcePool::InUsePoolResource resource, mode_ = RESOURCE_MODE; is_resource_ready_to_draw_ = false; resource_is_checker_imaged_ = resource_is_checker_imaged; - contents_swizzled_ = contents_swizzled; is_premultiplied_ = is_premultiplied; resource_ = std::move(resource); } @@ -46,7 +44,6 @@ ResourcePool::InUsePoolResource TileDrawInfo::TakeResource() { DCHECK(resource_); is_resource_ready_to_draw_ = false; resource_is_checker_imaged_ = false; - contents_swizzled_ = false; is_premultiplied_ = false; return std::move(resource_); } diff --git a/chromium/cc/tiles/tile_draw_info.h b/chromium/cc/tiles/tile_draw_info.h index 993fcdc1c30..c38cc45a3bd 100644 --- a/chromium/cc/tiles/tile_draw_info.h +++ b/chromium/cc/tiles/tile_draw_info.h @@ -72,7 +72,6 @@ class CC_EXPORT TileDrawInfo { return solid_color_; } - bool contents_swizzled() const { return contents_swizzled_; } bool is_premultiplied() const { return is_premultiplied_; } bool requires_resource() const { @@ -98,7 +97,6 @@ class CC_EXPORT TileDrawInfo { void SetResource(ResourcePool::InUsePoolResource resource, bool resource_is_checker_imaged, - bool contents_swizzled, bool is_premultiplied); ResourcePool::InUsePoolResource TakeResource(); @@ -117,7 +115,6 @@ class CC_EXPORT TileDrawInfo { Mode mode_ = RESOURCE_MODE; SkColor solid_color_ = SK_ColorWHITE; ResourcePool::InUsePoolResource resource_; - bool contents_swizzled_ = false; bool is_premultiplied_ = false; bool is_resource_ready_to_draw_ = false; diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc index e797e6db4a4..165bb015145 100644 --- a/chromium/cc/tiles/tile_manager.cc +++ b/chromium/cc/tiles/tile_manager.cc @@ -40,37 +40,6 @@ namespace { // a tile is of solid color. const bool kUseColorEstimator = true; -DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER( - ScopedSoftwareRasterTaskTimer, - "Compositing.%s.RasterTask.RasterUs.Software", - "Compositing.%s.RasterTask.RasterPixelsPerMs2.Software") - -DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER( - ScopedGpuRasterTaskTimer, - "Compositing.%s.RasterTask.RasterUs.Gpu", - "Compositing.%s.RasterTask.RasterPixelsPerMs2.Gpu") - -class ScopedRasterTaskTimer { - public: - explicit ScopedRasterTaskTimer(bool use_gpu_rasterization) { - if (use_gpu_rasterization) - gpu_timer_.emplace(); - else - software_timer_.emplace(); - } - - void SetArea(int area) { - if (software_timer_) - software_timer_->SetArea(area); - if (gpu_timer_) - gpu_timer_->SetArea(area); - } - - private: - base::Optional<ScopedSoftwareRasterTaskTimer> software_timer_; - base::Optional<ScopedGpuRasterTaskTimer> gpu_timer_; -}; - // This class is wrapper for both ImageProvider and PaintWorkletImageProvider, // which is used in RasterSource::PlaybackSettings. It looks at the draw image // and decides which one of the two providers to dispatch the request to. @@ -132,7 +101,6 @@ class RasterTaskImpl : public TileTask { tile_tracing_id_(static_cast<void*>(tile)), new_content_id_(tile->id()), source_frame_number_(tile->source_frame_number()), - is_gpu_rasterization_(is_gpu_rasterization), raster_buffer_(std::move(raster_buffer)), image_provider_(std::move(image_provider)), url_(std::move(url)) { @@ -152,8 +120,6 @@ class RasterTaskImpl : public TileTask { frame_viewer_instrumentation::ScopedRasterTask raster_task( tile_tracing_id_, tile_resolution_, source_frame_number_, layer_id_); - ScopedRasterTaskTimer timer(is_gpu_rasterization_); - timer.SetArea(content_rect_.size().GetArea()); DCHECK(raster_source_); @@ -203,7 +169,6 @@ class RasterTaskImpl : public TileTask { void* tile_tracing_id_; uint64_t new_content_id_; int source_frame_number_; - bool is_gpu_rasterization_; std::unique_ptr<RasterBuffer> raster_buffer_; DispatchingImageProvider image_provider_; GURL url_; @@ -717,6 +682,8 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { MemoryUsage memory_usage(resource_pool_->memory_usage_bytes(), resource_pool_->resource_count()); + gfx::ColorSpace raster_color_space = client_->GetRasterColorSpace(); + std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue( client_->BuildRasterQueue(global_state_.tree_priority, RasterTilePriorityQueue::Type::ALL)); @@ -769,7 +736,8 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { DCHECK(prioritized_tile.should_decode_checkered_images_for_tile()); AddCheckeredImagesToDecodeQueue( - prioritized_tile, CheckerImageTracker::DecodeType::kRaster, + prioritized_tile, raster_color_space, + CheckerImageTracker::DecodeType::kRaster, &work_to_schedule.checker_image_decode_queue); continue; } @@ -825,13 +793,15 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { if (tile->raster_task_scheduled_with_checker_images() && prioritized_tile.should_decode_checkered_images_for_tile()) { AddCheckeredImagesToDecodeQueue( - prioritized_tile, CheckerImageTracker::DecodeType::kRaster, + prioritized_tile, raster_color_space, + CheckerImageTracker::DecodeType::kRaster, &work_to_schedule.checker_image_decode_queue); } } else { // Creating the raster task here will acquire resources, but // this resource usage has already been accounted for above. - auto raster_task = CreateRasterTask(prioritized_tile, &work_to_schedule); + auto raster_task = CreateRasterTask( + prioritized_tile, client_->GetRasterColorSpace(), &work_to_schedule); if (!raster_task) { continue; } @@ -871,7 +841,8 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() { if (tile->draw_info().is_checker_imaged() || tile->raster_task_scheduled_with_checker_images()) { AddCheckeredImagesToDecodeQueue( - prioritized_tile, CheckerImageTracker::DecodeType::kRaster, + prioritized_tile, raster_color_space, + CheckerImageTracker::DecodeType::kRaster, &work_to_schedule.checker_image_decode_queue); } } @@ -928,6 +899,7 @@ void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw( void TileManager::PartitionImagesForCheckering( const PrioritizedTile& prioritized_tile, + const gfx::ColorSpace& raster_color_space, std::vector<DrawImage>* sync_decoded_images, std::vector<PaintImage>* checkered_images, const gfx::Rect* invalidated_rect, @@ -950,7 +922,7 @@ void TileManager::PartitionImagesForCheckering( (*image_to_frame_index)[image.stable_id()] = frame_index; DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(), - frame_index); + frame_index, raster_color_space); if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree)) checkered_images->push_back(draw_image.paint_image()); else @@ -960,6 +932,7 @@ void TileManager::PartitionImagesForCheckering( void TileManager::AddCheckeredImagesToDecodeQueue( const PrioritizedTile& prioritized_tile, + const gfx::ColorSpace& raster_color_space, CheckerImageTracker::DecodeType decode_type, CheckerImageTracker::ImageDecodeQueue* image_decode_queue) { Tile* tile = prioritized_tile.tile(); @@ -972,7 +945,7 @@ void TileManager::AddCheckeredImagesToDecodeQueue( size_t frame_index = client_->GetFrameIndexForImage( original_draw_image->paint_image(), tree); DrawImage draw_image(*original_draw_image, tile->raster_transform().scale(), - frame_index); + frame_index, raster_color_space); if (checker_image_tracker_.ShouldCheckerImage(draw_image, tree)) { image_decode_queue->emplace_back(draw_image.paint_image(), decode_type); } @@ -1008,6 +981,8 @@ void TileManager::ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule) { graph_.Reset(); + gfx::ColorSpace raster_color_space = client_->GetRasterColorSpace(); + scoped_refptr<TileTask> required_for_activation_done_task = CreateTaskSetFinishedTask( &TileManager::DidFinishRunningTileTasksRequiredForActivation); @@ -1063,8 +1038,9 @@ void TileManager::ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule) { for (const PrioritizedTile& prioritized_tile : tiles_to_process_for_images) { std::vector<DrawImage> sync_decoded_images; std::vector<PaintImage> checkered_images; - PartitionImagesForCheckering(prioritized_tile, &sync_decoded_images, - &checkered_images, nullptr); + PartitionImagesForCheckering(prioritized_tile, raster_color_space, + &sync_decoded_images, &checkered_images, + nullptr); // Add the sync decoded images to |new_locked_images| so they can be added // to the task graph. @@ -1156,6 +1132,7 @@ void TileManager::ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule) { scoped_refptr<TileTask> TileManager::CreateRasterTask( const PrioritizedTile& prioritized_tile, + const gfx::ColorSpace& raster_color_space, PrioritizedWorkToSchedule* work_to_schedule) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "TileManager::CreateRasterTask"); @@ -1172,7 +1149,7 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( tile->id(), tile->invalidated_content_rect(), tile->invalidated_id(), &invalidated_rect); } - const gfx::ColorSpace& raster_color_space = client_->GetRasterColorSpace(); + bool partial_tile_decode = false; if (resource) { resource_content_id = tile->invalidated_id(); @@ -1203,8 +1180,8 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( base::flat_map<PaintImage::Id, size_t> image_id_to_current_frame_index; if (!skip_images) { PartitionImagesForCheckering( - prioritized_tile, &sync_decoded_images, &checkered_images, - partial_tile_decode ? &invalidated_rect : nullptr, + prioritized_tile, raster_color_space, &sync_decoded_images, + &checkered_images, partial_tile_decode ? &invalidated_rect : nullptr, &image_id_to_current_frame_index); } @@ -1268,7 +1245,7 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask( } PlaybackImageProvider image_provider(image_controller_.cache(), - std::move(settings)); + raster_color_space, std::move(settings)); PaintWorkletImageProvider paint_worklet_image_provider( image_controller_.paint_worklet_image_cache()); DispatchingImageProvider dispatching_image_provider( @@ -1340,11 +1317,10 @@ void TileManager::OnRasterTaskCompleted( TileDrawInfo& draw_info = tile->draw_info(); if (exported) { - bool needs_swizzle = raster_buffer_provider_->IsResourceSwizzleRequired(); bool is_premultiplied = raster_buffer_provider_->IsResourcePremultiplied(); draw_info.SetResource(std::move(resource), raster_task_was_scheduled_with_checker_images, - needs_swizzle, is_premultiplied); + is_premultiplied); } else { resource_pool_->ReleaseResource(std::move(resource)); draw_info.set_oom(); diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h index 30d55902837..015ce53e837 100644 --- a/chromium/cc/tiles/tile_manager.h +++ b/chromium/cc/tiles/tile_manager.h @@ -212,7 +212,7 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { } bool exported = resource_pool_->PrepareForExport(resource); DCHECK(exported); - draw_info.SetResource(std::move(resource), false, false, false); + draw_info.SetResource(std::move(resource), false, false); draw_info.set_resource_ready_for_draw(); } } @@ -355,6 +355,7 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { void FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(Tile* tile); scoped_refptr<TileTask> CreateRasterTask( const PrioritizedTile& prioritized_tile, + const gfx::ColorSpace& raster_color_space, PrioritizedWorkToSchedule* work_to_schedule); std::unique_ptr<EvictionTilePriorityQueue> @@ -387,12 +388,14 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient { void PartitionImagesForCheckering( const PrioritizedTile& prioritized_tile, + const gfx::ColorSpace& raster_color_space, std::vector<DrawImage>* sync_decoded_images, std::vector<PaintImage>* checkered_images, const gfx::Rect* invalidated_rect, base::flat_map<PaintImage::Id, size_t>* image_to_frame_index = nullptr); void AddCheckeredImagesToDecodeQueue( const PrioritizedTile& prioritized_tile, + const gfx::ColorSpace& raster_color_space, CheckerImageTracker::DecodeType decode_type, CheckerImageTracker::ImageDecodeQueue* image_decode_queue); diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc index 43f7f2a354f..9c6d1e0516b 100644 --- a/chromium/cc/tiles/tile_manager_unittest.cc +++ b/chromium/cc/tiles/tile_manager_unittest.cc @@ -1540,6 +1540,9 @@ class TestSoftwareBacking : public ResourcePool::SoftwareBacking { // into the pixels in the array. class TestSoftwareRasterBufferProvider : public FakeRasterBufferProviderImpl { public: + static constexpr bool kIsGpuCompositing = true; + static constexpr viz::ResourceFormat kResourceFormat = viz::RGBA_8888; + std::unique_ptr<RasterBuffer> AcquireBufferForRaster( const ResourcePool::InUsePoolResource& resource, uint64_t resource_content_id, @@ -1549,7 +1552,7 @@ class TestSoftwareRasterBufferProvider : public FakeRasterBufferProviderImpl { backing->shared_bitmap_id = viz::SharedBitmap::GenerateId(); backing->pixels = std::make_unique<uint32_t[]>( viz::ResourceSizes::CheckedSizeInBytes<size_t>(resource.size(), - viz::RGBA_8888)); + kResourceFormat)); resource.set_software_backing(std::move(backing)); } auto* backing = @@ -1572,9 +1575,9 @@ class TestSoftwareRasterBufferProvider : public FakeRasterBufferProviderImpl { const RasterSource::PlaybackSettings& playback_settings, const GURL& url) override { RasterBufferProvider::PlaybackToMemory( - pixels_, viz::RGBA_8888, size_, /*stride=*/0, raster_source, + pixels_, kResourceFormat, size_, /*stride=*/0, raster_source, raster_full_rect, /*playback_rect=*/raster_full_rect, transform, - gfx::ColorSpace(), /*gpu_compositing=*/true, playback_settings); + gfx::ColorSpace(), kIsGpuCompositing, playback_settings); } private: @@ -1805,8 +1808,11 @@ TEST_F(PixelInspectTileManagerTest, LowResHasNoImage) { EXPECT_TRUE(tile->draw_info().IsReadyToDraw()); gfx::Size resource_size = tile->draw_info().resource_size(); - auto info = SkImageInfo::MakeN32Premul(resource_size.width(), - resource_size.height()); + SkColorType ct = ResourceFormatToClosestSkColorType( + TestSoftwareRasterBufferProvider::kIsGpuCompositing, + TestSoftwareRasterBufferProvider::kResourceFormat); + auto info = SkImageInfo::Make(resource_size.width(), resource_size.height(), + ct, kPremul_SkAlphaType); // CreateLayerTreeFrameSink() sets up a software compositing, so the // tile resource will be a bitmap. auto* backing = static_cast<TestSoftwareBacking*>( @@ -3363,9 +3369,9 @@ TEST_F(DecodedImageTrackerTileManagerTest, DecodedImageTrackerDropsLocksOnUse) { // Add the images to our decoded_image_tracker. host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode( - image1, base::DoNothing()); + image1, gfx::ColorSpace(), base::DoNothing()); host_impl()->tile_manager()->decoded_image_tracker().QueueImageDecode( - image2, base::DoNothing()); + image2, gfx::ColorSpace(), base::DoNothing()); EXPECT_EQ(0u, host_impl() ->tile_manager() ->decoded_image_tracker() diff --git a/chromium/cc/trees/animation_effect_timings.h b/chromium/cc/trees/animation_effect_timings.h new file mode 100644 index 00000000000..c66ab652de0 --- /dev/null +++ b/chromium/cc/trees/animation_effect_timings.h @@ -0,0 +1,25 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_TREES_ANIMATION_EFFECT_TIMINGS_H_ +#define CC_TREES_ANIMATION_EFFECT_TIMINGS_H_ + +#include <memory> + +#include "cc/cc_export.h" + +namespace cc { + +// This class acts as opaque handle in cc while the actual implementation lives +// in blink. It is meant to facilitate plumbing the effect timings from blink +// main thread to worklet thread via cc animations machinery. +class CC_EXPORT AnimationEffectTimings { + public: + virtual ~AnimationEffectTimings() = default; + virtual std::unique_ptr<AnimationEffectTimings> Clone() const = 0; +}; + +} // namespace cc + +#endif // CC_TREES_ANIMATION_EFFECT_TIMINGS_H_ diff --git a/chromium/cc/trees/debug_rect_history.cc b/chromium/cc/trees/debug_rect_history.cc index 1fb0255a0cc..07e6bd172b0 100644 --- a/chromium/cc/trees/debug_rect_history.cc +++ b/chromium/cc/trees/debug_rect_history.cc @@ -8,6 +8,7 @@ #include "base/memory/ptr_util.h" #include "cc/base/math_util.h" +#include "cc/layers/heads_up_display_layer_impl.h" #include "cc/layers/layer_impl.h" #include "cc/layers/layer_list_iterator.h" #include "cc/layers/render_surface_impl.h" @@ -30,7 +31,7 @@ DebugRectHistory::~DebugRectHistory() = default; void DebugRectHistory::SaveDebugRectsForCurrentFrame( LayerTreeImpl* tree_impl, - LayerImpl* hud_layer, + HeadsUpDisplayLayerImpl* hud_layer, const RenderSurfaceList& render_surface_list, const LayerTreeDebugState& debug_state) { // For now, clear all rects from previous frames. In the future we may want to @@ -49,6 +50,9 @@ void DebugRectHistory::SaveDebugRectsForCurrentFrame( if (debug_state.show_non_fast_scrollable_rects) SaveNonFastScrollableRects(tree_impl); + if (debug_state.show_layout_shift_regions) + SaveLayoutShiftRects(hud_layer); + if (debug_state.show_paint_rects) SavePaintRects(tree_impl); @@ -62,6 +66,14 @@ void DebugRectHistory::SaveDebugRectsForCurrentFrame( SaveScreenSpaceRects(render_surface_list); } +void DebugRectHistory::SaveLayoutShiftRects(HeadsUpDisplayLayerImpl* hud) { + for (gfx::Rect rect : hud->LayoutShiftRects()) { + debug_rects_.push_back(DebugRect( + LAYOUT_SHIFT_RECT_TYPE, + MathUtil::MapEnclosingClippedRect(hud->ScreenSpaceTransform(), rect))); + } +} + void DebugRectHistory::SavePaintRects(LayerTreeImpl* tree_impl) { // We would like to visualize where any layer's paint rect (update rect) has // changed, regardless of whether this layer is skipped for actual drawing or diff --git a/chromium/cc/trees/debug_rect_history.h b/chromium/cc/trees/debug_rect_history.h index 94d1ee95c0e..d9b6da071b9 100644 --- a/chromium/cc/trees/debug_rect_history.h +++ b/chromium/cc/trees/debug_rect_history.h @@ -17,8 +17,9 @@ namespace cc { class LayerImpl; class LayerTreeDebugState; class LayerTreeImpl; +class HeadsUpDisplayLayerImpl; -// There are currently six types of debug rects: +// There are various types of debug rects: // // - Paint rects (update rects): regions of a layer that needed to be // re-uploaded to the texture resource; in most cases implying that they had to @@ -33,6 +34,9 @@ class LayerTreeImpl; // paint rects, (2) property- changed rects, and (3) newly exposed areas. // // - Screen space rects: this is the region the contents occupy in screen space. +// +// - Layout shift rects: regions of an animation frame that were shifted while +// the page is loading content. enum DebugRectType { PAINT_RECT_TYPE, PROPERTY_CHANGED_RECT_TYPE, @@ -43,6 +47,7 @@ enum DebugRectType { SCROLL_EVENT_HANDLER_RECT_TYPE, NON_FAST_SCROLLABLE_RECT_TYPE, ANIMATION_BOUNDS_RECT_TYPE, + LAYOUT_SHIFT_RECT_TYPE, }; struct DebugRect { @@ -79,7 +84,7 @@ class DebugRectHistory { // reset. void SaveDebugRectsForCurrentFrame( LayerTreeImpl* tree_impl, - LayerImpl* hud_layer, + HeadsUpDisplayLayerImpl* hud_layer, const RenderSurfaceList& render_surface_list, const LayerTreeDebugState& debug_state); @@ -88,6 +93,7 @@ class DebugRectHistory { private: DebugRectHistory(); + void SaveLayoutShiftRects(HeadsUpDisplayLayerImpl* hud); void SavePaintRects(LayerTreeImpl* tree_impl); void SavePropertyChangedRects(LayerTreeImpl* tree_impl, LayerImpl* hud_layer); void SaveSurfaceDamageRects(const RenderSurfaceList& render_surface_list); diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc index e32fa24aa1c..9c1bec65c92 100644 --- a/chromium/cc/trees/draw_property_utils.cc +++ b/chromium/cc/trees/draw_property_utils.cc @@ -49,7 +49,7 @@ static void PostConcatSurfaceContentsScale(const EffectNode* effect_node, // doesn't set effect ids on clip nodes. return; } - DCHECK(effect_node->has_render_surface); + DCHECK(effect_node->HasRenderSurface()); transform->matrix().postScale(effect_node->surface_contents_scale.x(), effect_node->surface_contents_scale.y(), 1.f); } @@ -458,7 +458,7 @@ static inline bool LayerShouldBeSkippedInternal( const TransformTree& transform_tree, const EffectTree& effect_tree) { const EffectNode* effect_node = effect_tree.Node(layer->effect_tree_index()); - if (effect_node->has_render_surface && effect_node->subtree_has_copy_request) + if (effect_node->HasRenderSurface() && effect_node->subtree_has_copy_request) return false; // If the layer transform is not invertible, it should be skipped. In case the @@ -509,7 +509,7 @@ static void SetSurfaceDrawOpacity(const EffectTree& tree, // (included) and its target surface (excluded). const EffectNode* node = tree.Node(render_surface->EffectTreeIndex()); float draw_opacity = tree.EffectiveOpacity(node); - for (node = tree.parent(node); node && !node->has_render_surface; + for (node = tree.parent(node); node && !node->HasRenderSurface(); node = tree.parent(node)) { draw_opacity *= tree.EffectiveOpacity(node); } @@ -656,7 +656,7 @@ static ConditionalClip LayerClipRect(PropertyTrees* property_trees, const EffectTree* effect_tree = &property_trees->effect_tree; const EffectNode* effect_node = effect_tree->Node(layer->effect_tree_index()); const EffectNode* target_node = - effect_node->has_render_surface + effect_node->HasRenderSurface() ? effect_node : effect_tree->Node(effect_node->target_id); bool include_expanding_clips = false; @@ -676,7 +676,7 @@ static std::pair<gfx::RRectF, bool> GetRoundedCornerRRect( // Return empty rrect if this node has a render surface but the function call // was made for a non render surface. - if (effect_node->has_render_surface && !for_render_surface) + if (effect_node->HasRenderSurface() && !for_render_surface) return kEmptyRoundedCornerInfo; // Traverse the parent chain up to the render target to find a node which has @@ -691,7 +691,7 @@ static std::pair<gfx::RRectF, bool> GetRoundedCornerRRect( // Simply break if we reached a node that has a render surface or is the // render target. - if (node->has_render_surface || node->id == target_id) + if (node->HasRenderSurface() || node->id == target_id) break; node = effect_tree->parent(node); @@ -723,7 +723,7 @@ static void UpdateRenderTarget(EffectTree* effect_tree) { if (i == EffectTree::kContentsRootNodeId) { // Render target of the node corresponding to root is itself. node->target_id = EffectTree::kContentsRootNodeId; - } else if (effect_tree->parent(node)->has_render_surface) { + } else if (effect_tree->parent(node)->HasRenderSurface()) { node->target_id = node->parent_id; } else { node->target_id = effect_tree->parent(node)->target_id; @@ -765,7 +765,7 @@ static void ComputeClips(PropertyTrees* property_trees) { void ConcatInverseSurfaceContentsScale(const EffectNode* effect_node, gfx::Transform* transform) { - DCHECK(effect_node->has_render_surface); + DCHECK(effect_node->HasRenderSurface()); if (effect_node->surface_contents_scale.x() != 0.0 && effect_node->surface_contents_scale.y() != 0.0) transform->Scale(1.0 / effect_node->surface_contents_scale.x(), diff --git a/chromium/cc/trees/effect_node.cc b/chromium/cc/trees/effect_node.cc index 3701e4c41f2..8c7a016eee4 100644 --- a/chromium/cc/trees/effect_node.cc +++ b/chromium/cc/trees/effect_node.cc @@ -17,7 +17,6 @@ EffectNode::EffectNode() screen_space_opacity(1.f), backdrop_filter_quality(1.f), blend_mode(SkBlendMode::kSrcOver), - has_render_surface(false), cache_render_surface(false), has_copy_request(false), hidden_by_backface_visibility(false), @@ -26,14 +25,17 @@ EffectNode::EffectNode() is_drawn(true), subtree_hidden(false), has_potential_filter_animation(false), + has_potential_backdrop_filter_animation(false), has_potential_opacity_animation(false), is_currently_animating_filter(false), + is_currently_animating_backdrop_filter(false), is_currently_animating_opacity(false), has_masking_child(false), is_masked(false), effect_changed(false), subtree_has_copy_request(false), is_fast_rounded_corner(false), + render_surface_reason(RenderSurfaceReason::kNone), transform_id(0), clip_id(0), target_id(1), @@ -43,12 +45,13 @@ EffectNode::EffectNode() EffectNode::EffectNode(const EffectNode& other) = default; +EffectNode::~EffectNode() = default; + bool EffectNode::operator==(const EffectNode& other) const { return id == other.id && parent_id == other.parent_id && stable_id == other.stable_id && opacity == other.opacity && screen_space_opacity == other.screen_space_opacity && backdrop_filter_quality == other.backdrop_filter_quality && - has_render_surface == other.has_render_surface && cache_render_surface == other.cache_render_surface && has_copy_request == other.has_copy_request && filters == other.filters && @@ -57,6 +60,9 @@ bool EffectNode::operator==(const EffectNode& other) const { filters_origin == other.filters_origin && rounded_corner_bounds == other.rounded_corner_bounds && is_fast_rounded_corner == other.is_fast_rounded_corner && + // The specific reason is just for tracing/testing/debugging, so just + // check whether a render surface is needed. + HasRenderSurface() == other.HasRenderSurface() && blend_mode == other.blend_mode && surface_contents_scale == other.surface_contents_scale && unscaled_mask_target_size == other.unscaled_mask_target_size && @@ -66,9 +72,13 @@ bool EffectNode::operator==(const EffectNode& other) const { is_drawn == other.is_drawn && subtree_hidden == other.subtree_hidden && has_potential_filter_animation == other.has_potential_filter_animation && + has_potential_backdrop_filter_animation == + other.has_potential_backdrop_filter_animation && has_potential_opacity_animation == other.has_potential_opacity_animation && is_currently_animating_filter == other.is_currently_animating_filter && + is_currently_animating_backdrop_filter == + other.is_currently_animating_backdrop_filter && is_currently_animating_opacity == other.is_currently_animating_opacity && has_masking_child == other.has_masking_child && @@ -83,6 +93,54 @@ bool EffectNode::operator==(const EffectNode& other) const { other.closest_ancestor_with_copy_request_id; } +const char* RenderSurfaceReasonToString(RenderSurfaceReason reason) { + switch (reason) { + case RenderSurfaceReason::kNone: + return "none"; + case RenderSurfaceReason::kRoot: + return "root"; + case RenderSurfaceReason::k3dTransformFlattening: + return "3d transform flattening"; + case RenderSurfaceReason::kBlendMode: + return "blend mode"; + case RenderSurfaceReason::kBlendModeDstIn: + return "blend mode kDstIn"; + case RenderSurfaceReason::kOpacity: + return "opacity"; + case RenderSurfaceReason::kOpacityAnimation: + return "opacity animation"; + case RenderSurfaceReason::kFilter: + return "filter"; + case RenderSurfaceReason::kFilterAnimation: + return "filter animation"; + case RenderSurfaceReason::kBackdropFilter: + return "backdrop filter"; + case RenderSurfaceReason::kBackdropFilterAnimation: + return "backdrop filter animation"; + case RenderSurfaceReason::kRoundedCorner: + return "rounded corner"; + case RenderSurfaceReason::kClipPath: + return "clip path"; + case RenderSurfaceReason::kClipAxisAlignment: + return "clip axis alignment"; + case RenderSurfaceReason::kMask: + return "mask"; + case RenderSurfaceReason::kRootOrIsolatedGroup: + return "root or isolated group"; + case RenderSurfaceReason::kTrilinearFiltering: + return "trilinear filtering"; + case RenderSurfaceReason::kCache: + return "cache"; + case RenderSurfaceReason::kCopyRequest: + return "copy request"; + case RenderSurfaceReason::kTest: + return "test"; + default: + NOTREACHED() << static_cast<int>(reason); + return ""; + } +} + void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const { value->SetInteger("id", id); value->SetInteger("parent_id", parent_id); @@ -90,8 +148,11 @@ void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const { value->SetDouble("opacity", opacity); value->SetDouble("backdrop_filter_quality", backdrop_filter_quality); value->SetBoolean("is_fast_rounded_corner", is_fast_rounded_corner); + if (!rounded_corner_bounds.IsEmpty()) { + MathUtil::AddToTracedValue("rounded_corner_bounds", rounded_corner_bounds, + value); + } value->SetString("blend_mode", SkBlendMode_Name(blend_mode)); - value->SetBoolean("has_render_surface", has_render_surface); value->SetBoolean("cache_render_surface", cache_render_surface); value->SetBoolean("has_copy_request", has_copy_request); value->SetBoolean("double_sided", double_sided); @@ -99,12 +160,16 @@ void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const { value->SetBoolean("is_drawn", is_drawn); value->SetBoolean("has_potential_filter_animation", has_potential_filter_animation); + value->SetBoolean("has_potential_backdrop_filter_animation", + has_potential_backdrop_filter_animation); value->SetBoolean("has_potential_opacity_animation", has_potential_opacity_animation); value->SetBoolean("has_masking_child", has_masking_child); value->SetBoolean("is_masked", is_masked); value->SetBoolean("effect_changed", effect_changed); - value->SetInteger("subtree_has_copy_request", subtree_has_copy_request); + value->SetBoolean("subtree_has_copy_request", subtree_has_copy_request); + value->SetString("render_surface_reason", + RenderSurfaceReasonToString(render_surface_reason)); value->SetInteger("transform_id", transform_id); value->SetInteger("clip_id", clip_id); value->SetInteger("target_id", target_id); diff --git a/chromium/cc/trees/effect_node.h b/chromium/cc/trees/effect_node.h index f9ad97132ad..340305e9355 100644 --- a/chromium/cc/trees/effect_node.h +++ b/chromium/cc/trees/effect_node.h @@ -20,9 +20,37 @@ class TracedValue; namespace cc { +enum class RenderSurfaceReason : uint8_t { + kNone, + kRoot, + k3dTransformFlattening, + kBlendMode, + kBlendModeDstIn, + kOpacity, + kOpacityAnimation, + kFilter, + kFilterAnimation, + kBackdropFilter, + kBackdropFilterAnimation, + kRoundedCorner, + kClipPath, + kClipAxisAlignment, + kMask, + kRootOrIsolatedGroup, + kTrilinearFiltering, + kCache, + kCopyRequest, + // This must be the last value because it's used in tracing code to know the + // number of reasons. + kTest, +}; + +CC_EXPORT const char* RenderSurfaceReasonToString(RenderSurfaceReason); + struct CC_EXPORT EffectNode { EffectNode(); EffectNode(const EffectNode& other); + ~EffectNode(); enum StableIdLabels { INVALID_STABLE_ID = 0 }; @@ -41,7 +69,7 @@ struct CC_EXPORT EffectNode { FilterOperations filters; FilterOperations backdrop_filters; - gfx::RRectF backdrop_filter_bounds; + base::Optional<gfx::RRectF> backdrop_filter_bounds; float backdrop_filter_quality; gfx::PointF filters_origin; @@ -55,7 +83,6 @@ struct CC_EXPORT EffectNode { gfx::Size unscaled_mask_target_size; - bool has_render_surface : 1; bool cache_render_surface : 1; bool has_copy_request : 1; bool hidden_by_backface_visibility : 1; @@ -69,10 +96,15 @@ struct CC_EXPORT EffectNode { // of exact timeline) filter animation. bool has_potential_filter_animation : 1; // Whether this node has a potentially running (i.e., irrespective + // of exact timeline) backdrop-filter animation. + bool has_potential_backdrop_filter_animation : 1; + // Whether this node has a potentially running (i.e., irrespective // of exact timeline) opacity animation. bool has_potential_opacity_animation : 1; // Whether this node has a currently running filter animation. bool is_currently_animating_filter : 1; + // Whether this node has a currently running backdrop-filter animation. + bool is_currently_animating_backdrop_filter : 1; // Whether this node has a currently running opacity animation. bool is_currently_animating_opacity : 1; // Whether this node has a child node with kDstIn blend mode. @@ -85,7 +117,10 @@ struct CC_EXPORT EffectNode { bool subtree_has_copy_request : 1; // If set, the effect node tries to not trigger a render surface due to it // having a rounded corner. - bool is_fast_rounded_corner; + bool is_fast_rounded_corner : 1; + // RenderSurfaceReason::kNone if this effect node should not create a render + // surface, or the reason that this effect node should create one. + RenderSurfaceReason render_surface_reason; // The transform node index of the transform to apply to this effect // node's content when rendering to a surface. int transform_id; @@ -102,6 +137,10 @@ struct CC_EXPORT EffectNode { int closest_ancestor_with_cached_render_surface_id; int closest_ancestor_with_copy_request_id; + bool HasRenderSurface() const { + return render_surface_reason != RenderSurfaceReason::kNone; + } + bool operator==(const EffectNode& other) const; void AsValueInto(base::trace_event::TracedValue* value) const; diff --git a/chromium/cc/trees/latency_info_swap_promise.cc b/chromium/cc/trees/latency_info_swap_promise.cc index 208582c6e3e..3d808aec191 100644 --- a/chromium/cc/trees/latency_info_swap_promise.cc +++ b/chromium/cc/trees/latency_info_swap_promise.cc @@ -23,11 +23,13 @@ void LatencyInfoSwapPromise::WillSwap(viz::CompositorFrameMetadata* metadata) { void LatencyInfoSwapPromise::DidSwap() {} -void LatencyInfoSwapPromise::DidNotSwap(DidNotSwapReason reason) { +SwapPromise::DidNotSwapAction LatencyInfoSwapPromise::DidNotSwap( + DidNotSwapReason reason) { latency_.Terminate(); // TODO(miletus): Turn this back on once per-event LatencyInfo tracking // is enabled in GPU side. // DCHECK(latency_.terminated); + return DidNotSwapAction::BREAK_PROMISE; } int64_t LatencyInfoSwapPromise::TraceId() const { diff --git a/chromium/cc/trees/latency_info_swap_promise.h b/chromium/cc/trees/latency_info_swap_promise.h index ecdd381fe14..5891dfeceba 100644 --- a/chromium/cc/trees/latency_info_swap_promise.h +++ b/chromium/cc/trees/latency_info_swap_promise.h @@ -27,7 +27,7 @@ class CC_EXPORT LatencyInfoSwapPromise : public SwapPromise { void DidActivate() override {} void WillSwap(viz::CompositorFrameMetadata* metadata) override; void DidSwap() override; - void DidNotSwap(DidNotSwapReason reason) override; + DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override; void OnCommit() override; int64_t TraceId() const override; diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc index cf7a0bc85ef..4e9a9393289 100644 --- a/chromium/cc/trees/layer_tree_host.cc +++ b/chromium/cc/trees/layer_tree_host.cc @@ -371,6 +371,10 @@ void LayerTreeHost::FinishCommitOnImplThread( DCHECK(host_impl->mutator_host()); mutator_host_->PushPropertiesTo(host_impl->mutator_host()); + // Updating elements affects whether animations are in effect based on their + // properties so run after pushing updated animation properties. + host_impl->UpdateElements(ElementListType::PENDING); + sync_tree->lifecycle().AdvanceTo(LayerTreeLifecycle::kNotSyncing); } @@ -564,8 +568,8 @@ void LayerTreeHost::StartDeferringCommits(base::TimeDelta timeout) { proxy_->StartDeferringCommits(timeout); } -void LayerTreeHost::StopDeferringCommits() { - proxy_->StopDeferringCommits(); +void LayerTreeHost::StopDeferringCommits(PaintHoldingCommitTrigger trigger) { + proxy_->StopDeferringCommits(trigger); } DISABLE_CFI_PERF @@ -719,11 +723,6 @@ void LayerTreeHost::DidPresentCompositorFrame( client_->DidPresentCompositorFrame(frame_token, feedback); } -void LayerTreeHost::DidGenerateLocalSurfaceIdAllocation( - const viz::LocalSurfaceIdAllocation& allocation) { - client_->DidGenerateLocalSurfaceIdAllocation(allocation); -} - void LayerTreeHost::DidCompletePageScaleAnimation() { did_complete_scale_animation_ = true; } @@ -1395,31 +1394,16 @@ void LayerTreeHost::SetLocalSurfaceIdAllocationFromParent( // parent agreed upon these without needing to further advance its sequence // number. When this occurs the child is already up-to-date and a commit here // is simply redundant. - // - // If |generated_child_surface_sequence_number_| is set, it means a child - // sequence number was generated and needs to be compared against. if (AreEmbedTokensEqual(current_local_surface_id_from_parent, local_surface_id_from_parent) && AreParentSequencesEqual(current_local_surface_id_from_parent, - local_surface_id_from_parent) && - (!generated_child_surface_sequence_number_ || - local_surface_id_from_parent.child_sequence_number() < - *generated_child_surface_sequence_number_)) { + local_surface_id_from_parent)) { return; } - generated_child_surface_sequence_number_.reset(); - UpdateDeferMainFrameUpdateInternal(); SetNeedsCommit(); } -uint32_t LayerTreeHost::GenerateChildSurfaceSequenceNumberSync() { - DCHECK(proxy_); - generated_child_surface_sequence_number_ = - proxy_->GenerateChildSurfaceSequenceNumberSync(); - return *generated_child_surface_sequence_number_; -} - void LayerTreeHost::RequestNewLocalSurfaceId() { // If surface synchronization is enabled, then we can still request a new // viz::LocalSurfaceId but that request will be deferred until we have a valid @@ -1443,8 +1427,8 @@ void LayerTreeHost::RegisterLayer(Layer* layer) { DCHECK(!in_paint_layer_contents_); layer_id_map_[layer->id()] = layer; if (!IsUsingLayerLists() && layer->element_id()) { - mutator_host_->RegisterElement(layer->element_id(), - ElementListType::ACTIVE); + mutator_host_->RegisterElementId(layer->element_id(), + ElementListType::ACTIVE); } } @@ -1452,8 +1436,8 @@ void LayerTreeHost::UnregisterLayer(Layer* layer) { DCHECK(LayerById(layer->id())); DCHECK(!in_paint_layer_contents_); if (!IsUsingLayerLists() && layer->element_id()) { - mutator_host_->UnregisterElement(layer->element_id(), - ElementListType::ACTIVE); + mutator_host_->UnregisterElementId(layer->element_id(), + ElementListType::ACTIVE); } layers_that_should_push_properties_.erase(layer); layer_id_map_.erase(layer->id()); @@ -1683,7 +1667,7 @@ void LayerTreeHost::RegisterElement(ElementId element_id, // Animation ElementIds are unregistered by |SetActiveRegisteredElementIds| // when using layer lists. if (!IsUsingLayerLists()) - mutator_host_->RegisterElement(element_id, list_type); + mutator_host_->RegisterElementId(element_id, list_type); } void LayerTreeHost::UnregisterElement(ElementId element_id, @@ -1691,31 +1675,14 @@ void LayerTreeHost::UnregisterElement(ElementId element_id, // Animation ElementIds are unregistered by |SetActiveRegisteredElementIds| // when using layer lists. if (!IsUsingLayerLists()) - mutator_host_->UnregisterElement(element_id, list_type); + mutator_host_->UnregisterElementId(element_id, list_type); element_layers_map_.erase(element_id); } -void LayerTreeHost::SetActiveRegisteredElementIds(const ElementIdSet& ids) { +void LayerTreeHost::UpdateActiveElements() { DCHECK(IsUsingLayerLists()); - - // Unregister ids that should no longer be registered. - for (auto id_iter = elements_in_property_trees_.begin(); - id_iter != elements_in_property_trees_.end();) { - const auto& id = *(id_iter++); - if (!ids.count(id)) { - mutator_host_->UnregisterElement(id, ElementListType::ACTIVE); - elements_in_property_trees_.erase(id); - } - } - - // Register new ids that were not already registered. - for (const auto& id : ids) { - if (!elements_in_property_trees_.count(id)) { - elements_in_property_trees_.insert(id); - mutator_host_->RegisterElement(id, ElementListType::ACTIVE); - } - } + mutator_host_->UpdateRegisteredElementIds(ElementListType::ACTIVE); } static void SetElementIdForTesting(Layer* layer) { @@ -1735,11 +1702,11 @@ void LayerTreeHost::BuildPropertyTreesForTesting() { gfx::Rect(device_viewport_size()), identity_transform, property_trees()); } -bool LayerTreeHost::IsElementInList(ElementId element_id, - ElementListType list_type) const { +bool LayerTreeHost::IsElementInPropertyTrees(ElementId element_id, + ElementListType list_type) const { if (IsUsingLayerLists()) { return list_type == ElementListType::ACTIVE && - elements_in_property_trees_.count(element_id); + property_trees()->HasElement(element_id); } return list_type == ElementListType::ACTIVE && LayerByElementId(element_id); } @@ -1767,6 +1734,23 @@ void LayerTreeHost::SetElementFilterMutated(ElementId element_id, layer->OnFilterAnimated(filters); } +void LayerTreeHost::SetElementBackdropFilterMutated( + ElementId element_id, + ElementListType list_type, + const FilterOperations& backdrop_filters) { + if (IsUsingLayerLists()) { + // In BlinkGenPropertyTrees/CompositeAfterPaint we always have property + // tree nodes and can set the backdrop_filter directly on the effect node. + property_trees_.effect_tree.OnBackdropFilterAnimated(element_id, + backdrop_filters); + return; + } + + Layer* layer = LayerByElementId(element_id); + DCHECK(layer); + layer->OnBackdropFilterAnimated(backdrop_filters); +} + void LayerTreeHost::SetElementOpacityMutated(ElementId element_id, ElementListType list_type, float opacity) { @@ -1897,8 +1881,8 @@ void LayerTreeHost::RequestBeginMainFrameNotExpected(bool new_state) { proxy_->RequestBeginMainFrameNotExpected(new_state); } -void LayerTreeHost::SetURLForUkm(const GURL& url) { - proxy_->SetURLForUkm(url); +void LayerTreeHost::SetSourceURL(ukm::SourceId source_id, const GURL& url) { + proxy_->SetSourceURL(source_id, url); } void LayerTreeHost::SetRenderFrameObserver( diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h index 9d7d39f86b1..b7cf9d9af7d 100644 --- a/chromium/cc/trees/layer_tree_host.h +++ b/chromium/cc/trees/layer_tree_host.h @@ -21,7 +21,6 @@ #include "base/containers/flat_set.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "base/time/time.h" #include "cc/benchmarks/micro_benchmark.h" @@ -248,7 +247,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void StartDeferringCommits(base::TimeDelta timeout); // Stop deferring commits immediately. - void StopDeferringCommits(); + void StopDeferringCommits(PaintHoldingCommitTrigger); // Returns whether there are any outstanding ScopedDeferMainFrameUpdate, // though commits may be deferred also when the local_surface_id_from_parent() @@ -451,11 +450,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { return local_surface_id_allocation_from_parent_; } - // Generates a new child surface sequence number (from a LocalSurfaceId). This - // results in disabling drawing until the LocalSurfaceIdAllocation is received - // via the active tree. This only works in single threaded mode. - uint32_t GenerateChildSurfaceSequenceNumberSync(); - // Requests the allocation of a new LocalSurfaceId on the compositor thread. void RequestNewLocalSurfaceId(); @@ -548,9 +542,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { void PushPropertyTreesTo(LayerTreeImpl* tree_impl); void PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl); - // TODO(flackr): This list should be on the property trees and pushed - // as part of PushPropertyTreesTo. - void PushRegisteredElementIdsTo(LayerTreeImpl* tree_impl); void PushSurfaceRangesTo(LayerTreeImpl* tree_impl); void PushLayerTreeHostPropertiesTo(LayerTreeHostImpl* host_impl); @@ -564,15 +555,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { Layer* layer); void UnregisterElement(ElementId element_id, ElementListType list_type); - // Registers the new active element ids, updating |registered_element_ids_|, - // and unregisters any element ids that were previously registered. This is - // similar to |RegisterElement| and |UnregisterElement| but for layer lists - // where we do not have a unique element id to layer mapping. - using ElementIdSet = std::unordered_set<ElementId, ElementIdHash>; - void SetActiveRegisteredElementIds(const ElementIdSet&); - const ElementIdSet& elements_in_property_trees() { - return elements_in_property_trees_; - } + void UpdateActiveElements(); void SetElementIdsForTesting(); @@ -610,8 +593,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback); - void DidGenerateLocalSurfaceIdAllocation( - const viz::LocalSurfaceIdAllocation& allocation); // Called when the compositor completed page scale animation. void DidCompletePageScaleAnimation(); void ApplyScrollAndScale(ScrollAndScaleSet* info); @@ -643,13 +624,17 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { bool IsUsingLayerLists() const; // MutatorHostClient implementation. - bool IsElementInList(ElementId element_id, - ElementListType list_type) const override; + bool IsElementInPropertyTrees(ElementId element_id, + ElementListType list_type) const override; void SetMutatorsNeedCommit() override; void SetMutatorsNeedRebuildPropertyTrees() override; void SetElementFilterMutated(ElementId element_id, ElementListType list_type, const FilterOperations& filters) override; + void SetElementBackdropFilterMutated( + ElementId element_id, + ElementListType list_type, + const FilterOperations& backdrop_filters) override; void SetElementOpacityMutated(ElementId element_id, ElementListType list_type, float opacity) override; @@ -685,7 +670,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { float recording_scale_factor() const { return recording_scale_factor_; } - void SetURLForUkm(const GURL& url); + void SetSourceURL(ukm::SourceId source_id, const GURL& url); void SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer); @@ -829,10 +814,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { bool new_local_surface_id_request_ = false; uint32_t defer_main_frame_update_count_ = 0; - // Last value returned from GenerateChildSurfaceSequenceNumberSync(). This is - // reset once a LocalSurfaceId is submitted with a higher id. - base::Optional<uint32_t> generated_child_surface_sequence_number_; - SkColor background_color_ = SK_ColorWHITE; LayerSelection selection_; @@ -874,10 +855,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient { // In layer-list mode, this map is only used for scrollable layers. std::unordered_map<ElementId, Layer*, ElementIdHash> element_layers_map_; - // The set of registered element ids when using layer list mode. In non-layer- - // list mode, |element_layers_map_| is used. - ElementIdSet elements_in_property_trees_; - bool in_paint_layer_contents_ = false; // This is true if atleast one layer in the layer tree has a copy request. We diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h index b54c5c1a35b..5ddc975a950 100644 --- a/chromium/cc/trees/layer_tree_host_client.h +++ b/chromium/cc/trees/layer_tree_host_client.h @@ -18,7 +18,6 @@ struct PresentationFeedback; } namespace viz { -class LocalSurfaceIdAllocation; struct BeginFrameArgs; } @@ -136,8 +135,6 @@ class LayerTreeHostClient { // the time from the start of BeginMainFrame to the Commit, or early out. virtual void RecordStartOfFrameMetrics() = 0; virtual void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) = 0; - virtual void DidGenerateLocalSurfaceIdAllocation( - const viz::LocalSurfaceIdAllocation& allocation) = 0; protected: virtual ~LayerTreeHostClient() {} diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc index cd56fec1beb..6eb7ec07102 100644 --- a/chromium/cc/trees/layer_tree_host_common.cc +++ b/chromium/cc/trees/layer_tree_host_common.cc @@ -326,23 +326,17 @@ static bool SkipForInvertibility(const LayerImpl* layer, bool non_root_copy_request = effect_node->closest_ancestor_with_copy_request_id > EffectTree::kContentsRootNodeId; + gfx::Transform from_target; // If there is a copy request, we check the invertibility of the transform // between the node corresponding to the layer and the node corresponding to // the copy request. Otherwise, we are interested in the invertibility of // screen space transform which is already cached on the transform node. - if (non_root_copy_request) { - // Null check is a temporary fix for crasher: https://crbug.com/939342 - if (effect_node == nullptr) - return false; - gfx::Transform from_target; - return !property_trees->GetFromTarget( - layer->transform_tree_index(), - effect_node->closest_ancestor_with_copy_request_id, &from_target); - } - // Null check is a temporary fix for crasher: https://crbug.com/939342 - if (transform_node == nullptr) - return false; - return !transform_node->ancestors_are_invertible; + return non_root_copy_request + ? !property_trees->GetFromTarget( + layer->transform_tree_index(), + effect_node->closest_ancestor_with_copy_request_id, + &from_target) + : !transform_node->ancestors_are_invertible; } static void ComputeInitialRenderSurfaceList( @@ -495,6 +489,38 @@ static void CalculateRenderSurfaceLayerList( render_surface_list); } +static void RecordRenderSurfaceReasonsForTracing( + const PropertyTrees* property_trees, + const RenderSurfaceList* render_surface_list) { + static const auto* tracing_enabled = + TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("cc"); + if (!*tracing_enabled || + // Don't output single root render surface. + render_surface_list->size() <= 1) + return; + + TRACE_EVENT_INSTANT1("cc", "RenderSurfaceReasonCount", + TRACE_EVENT_SCOPE_THREAD, "total", + render_surface_list->size()); + + // kTest is the last value which is not included for tracing. + constexpr auto kNumReasons = static_cast<size_t>(RenderSurfaceReason::kTest); + int reason_counts[kNumReasons] = {0}; + for (const auto* render_surface : *render_surface_list) { + const auto* effect_node = + property_trees->effect_tree.Node(render_surface->EffectTreeIndex()); + reason_counts[static_cast<size_t>(effect_node->render_surface_reason)]++; + } + for (size_t i = 0; i < kNumReasons; i++) { + if (!reason_counts[i]) + continue; + TRACE_EVENT_INSTANT1( + "cc", "RenderSurfaceReasonCount", TRACE_EVENT_SCOPE_THREAD, + RenderSurfaceReasonToString(static_cast<RenderSurfaceReason>(i)), + reason_counts[i]); + } +} + void CalculateDrawPropertiesInternal( LayerTreeHostCommon::CalcDrawPropsImplInputs* inputs, PropertyTreeOption property_tree_option) { @@ -610,6 +636,8 @@ void CalculateDrawPropertiesInternal( inputs->root_layer->layer_tree_impl(), inputs->property_trees, inputs->render_surface_list, inputs->max_texture_size); } + RecordRenderSurfaceReasonsForTracing(inputs->property_trees, + inputs->render_surface_list); // A root layer render_surface should always exist after // CalculateDrawProperties. diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc index 37d6f1c7bb0..93750755adb 100644 --- a/chromium/cc/trees/layer_tree_host_common_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc @@ -1329,7 +1329,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceForNonAxisAlignedClipping) { EffectTree& effect_tree = root->layer_tree_impl()->property_trees()->effect_tree; EffectNode* node = effect_tree.Node(clips_subtree->effect_tree_index()); - EXPECT_TRUE(node->has_render_surface); + EXPECT_TRUE(node->HasRenderSurface()); } TEST_F(LayerTreeHostCommonTest, EffectNodesForNonAxisAlignedClips) { @@ -3852,7 +3852,7 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithPreserves3d) { EXPECT_EQ(GetRenderSurface(front_facing_child), GetRenderSurface(root)); EXPECT_EQ(GetRenderSurface(back_facing_child), GetRenderSurface(root)); EXPECT_NE(GetRenderSurface(front_facing_surface), GetRenderSurface(root)); - // We expect that a has_render_surface was created but not used. + // We expect that a render surface was created but not used. EXPECT_NE(GetRenderSurface(back_facing_surface), GetRenderSurface(root)); EXPECT_NE(GetRenderSurface(back_facing_surface), GetRenderSurface(front_facing_surface)); @@ -10696,7 +10696,7 @@ TEST_F(LayerTreeHostCommonTest, RoundedCornerBounds) { const EffectNode* effect_node = effect_tree.Node(rounded_corner_layer_1->effect_tree_index()); gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), kRoundedCorner1Radius); EXPECT_EQ(rounded_corner_bounds_1.rect(), @@ -10706,7 +10706,7 @@ TEST_F(LayerTreeHostCommonTest, RoundedCornerBounds) { // surface. It also has 2 descendants that draw. effect_node = effect_tree.Node(rounded_corner_layer_2->effect_tree_index()); gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->has_render_surface); + EXPECT_TRUE(effect_node->HasRenderSurface()); EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), kRoundedCorner2Radius); EXPECT_EQ(rounded_corner_bounds_2.rect(), @@ -10716,7 +10716,7 @@ TEST_F(LayerTreeHostCommonTest, RoundedCornerBounds) { // the creation of a render surface. effect_node = effect_tree.Node(rounded_corner_layer_3->effect_tree_index()); gfx::RRectF rounded_corner_bounds_3 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->has_render_surface); + EXPECT_TRUE(effect_node->HasRenderSurface()); EXPECT_FLOAT_EQ(rounded_corner_bounds_3.GetSimpleRadius(), kRoundedCorner3Radius); EXPECT_EQ(rounded_corner_bounds_3.rect(), @@ -10726,7 +10726,7 @@ TEST_F(LayerTreeHostCommonTest, RoundedCornerBounds) { // rounded corner, it does not need a render surface. effect_node = effect_tree.Node(rounded_corner_layer_4->effect_tree_index()); gfx::RRectF rounded_corner_bounds_4 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_FLOAT_EQ(rounded_corner_bounds_4.GetSimpleRadius(), kRoundedCorner4Radius); EXPECT_EQ(rounded_corner_bounds_4.rect(), @@ -10891,7 +10891,7 @@ TEST_F(LayerTreeHostCommonTest, RoundedCornerBoundsInterveningRenderTarget) { const EffectNode* effect_node = effect_tree.Node(rounded_corner_layer_1->effect_tree_index()); gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), kRoundedCorner1Radius); EXPECT_EQ(rounded_corner_bounds_1.rect(), @@ -10901,7 +10901,7 @@ TEST_F(LayerTreeHostCommonTest, RoundedCornerBoundsInterveningRenderTarget) { // has a rounded corner, it does not need a render surface. effect_node = effect_tree.Node(rounded_corner_layer_2->effect_tree_index()); gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), kRoundedCorner2Radius); EXPECT_EQ(rounded_corner_bounds_2.rect(), @@ -11018,7 +11018,7 @@ TEST_F(LayerTreeHostCommonTest, RoundedCornerBoundsSiblingRenderTarget) { const EffectNode* effect_node = effect_tree.Node(rounded_corner_layer_1->effect_tree_index()); gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->has_render_surface); + EXPECT_TRUE(effect_node->HasRenderSurface()); EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), kRoundedCorner1Radius); EXPECT_EQ(rounded_corner_bounds_1.rect(), @@ -11028,7 +11028,7 @@ TEST_F(LayerTreeHostCommonTest, RoundedCornerBoundsSiblingRenderTarget) { // has a rounded corner, it does not need a render surface. effect_node = effect_tree.Node(rounded_corner_layer_2->effect_tree_index()); gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), kRoundedCorner2Radius); EXPECT_EQ(rounded_corner_bounds_2.rect(), @@ -11169,7 +11169,7 @@ TEST_F(LayerTreeHostCommonTest, FastRoundedCornerDoesNotTriggerRenderSurface) { const EffectNode* effect_node = effect_tree.Node(fast_rounded_corner_layer->effect_tree_index()); gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_TRUE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), kRoundedCorner1Radius); @@ -11179,7 +11179,7 @@ TEST_F(LayerTreeHostCommonTest, FastRoundedCornerDoesNotTriggerRenderSurface) { // Since this node has 2 descendants that draw, it will have a rounded corner. effect_node = effect_tree.Node(rounded_corner_layer->effect_tree_index()); gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->has_render_surface); + EXPECT_TRUE(effect_node->HasRenderSurface()); EXPECT_FALSE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), kRoundedCorner2Radius); @@ -11346,7 +11346,7 @@ TEST_F(LayerTreeHostCommonTest, const EffectNode* effect_node = effect_tree.Node(rounded_corner_layer_1->effect_tree_index()); gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->has_render_surface); + EXPECT_TRUE(effect_node->HasRenderSurface()); EXPECT_FALSE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), kRoundedCorner1Radius); @@ -11358,7 +11358,7 @@ TEST_F(LayerTreeHostCommonTest, effect_node = effect_tree.Node(fast_rounded_corner_layer_2->effect_tree_index()); gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_TRUE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), kRoundedCorner2Radius); @@ -11369,7 +11369,7 @@ TEST_F(LayerTreeHostCommonTest, // render surface. effect_node = effect_tree.Node(rounded_corner_layer_3->effect_tree_index()); gfx::RRectF rounded_corner_bounds_3 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->has_render_surface); + EXPECT_TRUE(effect_node->HasRenderSurface()); EXPECT_FALSE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_3.GetSimpleRadius(), kRoundedCorner3Radius); @@ -11379,7 +11379,7 @@ TEST_F(LayerTreeHostCommonTest, // Since this layer no descendants, it would no thave a render pass. effect_node = effect_tree.Node(rounded_corner_layer_4->effect_tree_index()); gfx::RRectF rounded_corner_bounds_4 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_FALSE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_4.GetSimpleRadius(), kRoundedCorner4Radius); @@ -11554,7 +11554,7 @@ TEST_F(LayerTreeHostCommonTest, const EffectNode* effect_node = effect_tree.Node(fast_rounded_corner_layer_1->effect_tree_index()); gfx::RRectF rounded_corner_bounds_1 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->has_render_surface); + EXPECT_TRUE(effect_node->HasRenderSurface()); EXPECT_TRUE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_1.GetSimpleRadius(), kRoundedCorner1Radius); @@ -11565,7 +11565,7 @@ TEST_F(LayerTreeHostCommonTest, // not have a render surface. effect_node = effect_tree.Node(rounded_corner_layer_1->effect_tree_index()); gfx::RRectF rounded_corner_bounds_2 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_FALSE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_2.GetSimpleRadius(), kRoundedCorner2Radius); @@ -11576,7 +11576,7 @@ TEST_F(LayerTreeHostCommonTest, // render surface. effect_node = effect_tree.Node(rounded_corner_layer_2->effect_tree_index()); gfx::RRectF rounded_corner_bounds_3 = effect_node->rounded_corner_bounds; - EXPECT_TRUE(effect_node->has_render_surface); + EXPECT_TRUE(effect_node->HasRenderSurface()); EXPECT_FALSE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_3.GetSimpleRadius(), kRoundedCorner3Radius); @@ -11586,7 +11586,7 @@ TEST_F(LayerTreeHostCommonTest, // Since this layer has no descendant, it does not need a render surface. effect_node = effect_tree.Node(rounded_corner_layer_3->effect_tree_index()); gfx::RRectF rounded_corner_bounds_4 = effect_node->rounded_corner_bounds; - EXPECT_FALSE(effect_node->has_render_surface); + EXPECT_FALSE(effect_node->HasRenderSurface()); EXPECT_FALSE(effect_node->is_fast_rounded_corner); EXPECT_FLOAT_EQ(rounded_corner_bounds_4.GetSimpleRadius(), kRoundedCorner4Radius); diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc index cb2dbe413f0..e2921219d25 100644 --- a/chromium/cc/trees/layer_tree_host_impl.cc +++ b/chromium/cc/trees/layer_tree_host_impl.cc @@ -9,18 +9,18 @@ #include <algorithm> #include <limits> -#include <map> -#include <set> -#include <unordered_map> -#include <utility> +#include <list> #include "base/auto_reset.h" #include "base/bind.h" #include "base/compiler_specific.h" #include "base/containers/adapters.h" #include "base/containers/flat_map.h" +#include "base/debug/crash_logging.h" +#include "base/debug/dump_without_crashing.h" #include "base/json/json_writer.h" #include "base/memory/ptr_util.h" +#include "base/memory/read_only_shared_memory_region.h" #include "base/metrics/histogram.h" #include "base/numerics/safe_conversions.h" #include "base/stl_util.h" @@ -79,6 +79,7 @@ #include "cc/trees/layer_tree_host_common.h" #include "cc/trees/layer_tree_impl.h" #include "cc/trees/mutator_host.h" +#include "cc/trees/presentation_time_callback_buffer.h" #include "cc/trees/render_frame_metadata.h" #include "cc/trees/render_frame_metadata_observer.h" #include "cc/trees/scroll_node.h" @@ -260,6 +261,24 @@ ui::FrameMetricsSettings LTHI_FrameMetricsSettings( return ui::FrameMetricsSettings(source, source_thread, compile_target); } +class ScopedPostAnimationEventsToMainThread { + public: + ScopedPostAnimationEventsToMainThread(MutatorHost* animation_host, + LayerTreeHostImplClient* client) + : events_(animation_host->CreateEvents()), client_(client) {} + + ~ScopedPostAnimationEventsToMainThread() { + if (!events_->IsEmpty()) + client_->PostAnimationEventsToMainThreadOnImplThread(std::move(events_)); + } + + MutatorEvents* events() { return events_.get(); } + + private: + std::unique_ptr<MutatorEvents> events_; + LayerTreeHostImplClient* client_; +}; + } // namespace DEFINE_SCOPED_UMA_HISTOGRAM_TIMER(PendingTreeDurationHistogramTimer, @@ -339,7 +358,8 @@ LayerTreeHostImpl::LayerTreeHostImpl( is_animating_for_snap_(false), paint_image_generator_client_id_(PaintImage::GetNextGeneratorClientId()), scrollbar_controller_(std::make_unique<ScrollbarController>(this)), - scroll_gesture_did_end_(false) { + scroll_gesture_did_end_(false), + weak_factory_(this) { DCHECK(mutator_host_); mutator_host_->SetMutatorHostClient(this); @@ -442,6 +462,10 @@ void LayerTreeHostImpl::CommitComplete() { if (CommitToActiveTree()) { active_tree_->HandleScrollbarShowRequestsFromMain(); + // Property tree nodes have been updated by the commit. Update elements + // available on active tree to start/stop ticking animations. + UpdateElements(ElementListType::ACTIVE); + // 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. @@ -464,7 +488,7 @@ void LayerTreeHostImpl::CommitComplete() { void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() { // LayerTreeHost may have changed the GPU rasterization flags state, which // may require an update of the tree resources. - UpdateTreeResourcesIfNeeded(); + UpdateTreeResourcesForGpuRasterizationIfNeeded(); sync_tree()->set_needs_update_draw_properties(); // We need an update immediately post-commit to have the opportunity to create @@ -546,9 +570,6 @@ bool LayerTreeHostImpl::CanDraw() const { return false; } - if (waiting_for_local_surface_id_) - return false; - if (resourceless_software_draw_) return true; @@ -635,6 +656,19 @@ void LayerTreeHostImpl::StartPageScaleAnimation( bool anchor_point, float page_scale, base::TimeDelta duration) { + // Temporary crash logging for https://crbug.com/845097. + static bool has_dumped_without_crashing = false; + if (settings().is_layer_tree_for_subframe && !has_dumped_without_crashing) { + has_dumped_without_crashing = true; + static auto* psf_oopif_animation_error = + base::debug::AllocateCrashKeyString("psf_oopif_animation_error", + base::debug::CrashKeySize::Size32); + base::debug::SetCrashKeyString( + psf_oopif_animation_error, + base::StringPrintf("%p", InnerViewportScrollNode())); + base::debug::DumpWithoutCrashing(); + } + if (!InnerViewportScrollNode()) return; @@ -1261,6 +1295,10 @@ void LayerTreeHostImpl::SetViewportDamage(const gfx::Rect& damage_rect) { viewport_damage_rect_.Union(damage_rect); } +void LayerTreeHostImpl::UpdateElements(ElementListType changed_list) { + mutator_host()->UpdateRegisteredElementIds(changed_list); +} + void LayerTreeHostImpl::InvalidateContentOnImplSide() { DCHECK(!pending_tree_); // Invalidation should never be ran outside the impl frame for non @@ -1389,7 +1427,7 @@ void LayerTreeHostImpl::RemoveRenderPasses(FrameData* frame) { // Remove orphan viz::RenderPassDrawQuads. for (auto it = pass->quad_list.begin(); it != pass->quad_list.end();) { - if (it->material != viz::DrawQuad::RENDER_PASS) { + if (it->material != viz::DrawQuad::Material::kRenderPass) { ++it; continue; } @@ -1437,7 +1475,7 @@ void LayerTreeHostImpl::RemoveRenderPasses(FrameData* frame) { continue; for (auto it = pass->quad_list.begin(); it != pass->quad_list.end(); ++it) { - if (it->material != viz::DrawQuad::RENDER_PASS) + if (it->material != viz::DrawQuad::Material::kRenderPass) continue; const viz::RenderPassDrawQuad* quad = viz::RenderPassDrawQuad::MaterialCast(*it); @@ -1759,38 +1797,22 @@ void LayerTreeHostImpl::DidReceiveCompositorFrameAck() { client_->DidReceiveCompositorFrameAckOnImplThread(); } -LayerTreeHostImpl::FrameTokenInfo::FrameTokenInfo( - uint32_t token, - base::TimeTicks cc_frame_time, - std::vector<LayerTreeHost::PresentationTimeCallback> callbacks) - : token(token), - cc_frame_time(cc_frame_time), - callbacks(std::move(callbacks)) {} - -LayerTreeHostImpl::FrameTokenInfo::FrameTokenInfo(FrameTokenInfo&&) = default; -LayerTreeHostImpl::FrameTokenInfo::~FrameTokenInfo() = default; - void LayerTreeHostImpl::DidPresentCompositorFrame( uint32_t frame_token, const gfx::PresentationFeedback& feedback) { - std::vector<LayerTreeHost::PresentationTimeCallback> all_callbacks; - while (!frame_token_infos_.empty()) { - auto info = frame_token_infos_.begin(); - if (viz::FrameTokenGT(info->token, frame_token)) - break; - - // Update compositor frame latency and smoothness stats only for frames - // that caused on-screen damage. - if (info->token == frame_token) - frame_metrics_.AddFrameDisplayed(info->cc_frame_time, feedback.timestamp); + PresentationTimeCallbackBuffer::PendingCallbacks activated = + presentation_time_callbacks_.PopPendingCallbacks(frame_token); - std::copy(std::make_move_iterator(info->callbacks.begin()), - std::make_move_iterator(info->callbacks.end()), - std::back_inserter(all_callbacks)); - frame_token_infos_.erase(info); + // Update compositor frame latency and smoothness stats only for frames + // that caused on-screen damage. + if (!activated.frame_time.is_null()) { + frame_metrics_.AddFrameDisplayed(activated.frame_time, feedback.timestamp); } + + // Send all the main-thread callbacks to the client in one batch. The client + // is in charge of posting them to the main thread. client_->DidPresentCompositorFrameOnImplThread( - frame_token, std::move(all_callbacks), feedback); + frame_token, std::move(activated.main_thread_callbacks), feedback); } void LayerTreeHostImpl::DidNotNeedBeginFrame() { @@ -1890,11 +1912,10 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() { metadata.content_source_id = active_tree_->content_source_id(); if (active_tree_->has_presentation_callbacks()) { - frame_token_infos_.emplace_back(metadata.frame_token, - CurrentBeginFrameArgs().frame_time, - active_tree_->TakePresentationCallbacks()); - - DCHECK_LE(frame_token_infos_.size(), 25u); + presentation_time_callbacks_.RegisterMainThreadPresentationCallbacks( + metadata.frame_token, active_tree_->TakePresentationCallbacks()); + presentation_time_callbacks_.RegisterFrameTime( + metadata.frame_token, CurrentBeginFrameArgs().frame_time); } if (GetDrawMode() == DRAW_MODE_RESOURCELESS_SOFTWARE) { @@ -2386,16 +2407,8 @@ bool LayerTreeHostImpl::UpdateGpuRasterizationStatus() { return true; } -void LayerTreeHostImpl::UpdateTreeResourcesIfNeeded() { - // For simplicity, clobber all resources when the color space changes. - // This is mostly to clear the image decode caches, which don't handle - // multiple color space at once. - int color_space_id = -1; - GetRasterColorSpaceAndId(&color_space_id); - bool color_space_changed = last_color_space_id_ != color_space_id; - last_color_space_id_ = color_space_id; - - if (!UpdateGpuRasterizationStatus() && !color_space_changed) +void LayerTreeHostImpl::UpdateTreeResourcesForGpuRasterizationIfNeeded() { + if (!UpdateGpuRasterizationStatus()) return; // Clean up and replace existing tile manager with another one that uses @@ -2867,6 +2880,7 @@ void LayerTreeHostImpl::ActivateSyncTree() { LayerTreeLifecycle::kSyncedPropertyTrees); TreeSynchronizer::PushLayerProperties(pending_tree(), active_tree()); + active_tree_->lifecycle().AdvanceTo( LayerTreeLifecycle::kSyncedLayerProperties); @@ -2874,6 +2888,10 @@ void LayerTreeHostImpl::ActivateSyncTree() { if (!pending_tree_->LayerListIsEmpty()) pending_tree_->property_trees()->ResetAllChangeTracking(); + // Property tree nodes have been updated by PushLayerProperties. Update + // elements available on active tree to start/stop ticking animations. + UpdateElements(ElementListType::ACTIVE); + active_tree_->lifecycle().AdvanceTo(LayerTreeLifecycle::kNotSyncing); // Now that we've synced everything from the pending tree to the active @@ -3098,15 +3116,13 @@ void LayerTreeHostImpl::CreateTileManagerResources() { viz::ResourceFormatToClosestSkColorType(/*gpu_compositing=*/true, tile_format), settings_.decoded_image_working_set_budget_bytes, max_texture_size_, - paint_image_generator_client_id_, - GetRasterColorSpace().ToSkColorSpace()); + paint_image_generator_client_id_); } else { bool gpu_compositing = !!layer_tree_frame_sink_->context_provider(); image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>( viz::ResourceFormatToClosestSkColorType(gpu_compositing, tile_format), settings_.decoded_image_working_set_budget_bytes, - paint_image_generator_client_id_, - GetRasterColorSpace().ToSkColorSpace()); + paint_image_generator_client_id_); } // Pass the single-threaded synchronous task graph runner to the worker pool @@ -3211,8 +3227,9 @@ void LayerTreeHostImpl::QueueImageDecode(int request_id, // Optimistically specify the current raster color space, since we assume that // it won't change. tile_manager_.decoded_image_tracker().QueueImageDecode( - image, base::BindOnce(&LayerTreeHostImpl::ImageDecodeFinished, - base::Unretained(this), request_id)); + image, GetRasterColorSpace(), + base::BindOnce(&LayerTreeHostImpl::ImageDecodeFinished, + weak_factory_.GetWeakPtr(), request_id)); tile_manager_.checker_image_tracker().DisallowCheckeringForImage(image); } @@ -4599,17 +4616,27 @@ void LayerTreeHostImpl::RequestUpdateForSynchronousInputHandler() { UpdateRootLayerStateForSynchronousInputHandler(); } +static gfx::Vector2dF ContentToPhysical(const gfx::Vector2dF& content_delta, + float page_scale_factor) { + gfx::Vector2dF physical_delta = content_delta; + physical_delta.Scale(page_scale_factor); + return physical_delta; +} + void LayerTreeHostImpl::SetSynchronousInputHandlerRootScrollOffset( - const gfx::ScrollOffset& root_offset) { - TRACE_EVENT2("cc", - "LayerTreeHostImpl::SetSynchronousInputHandlerRootScrollOffset", - "offset_x", root_offset.x(), "offset_y", root_offset.y()); + const gfx::ScrollOffset& root_content_offset) { + TRACE_EVENT2( + "cc", "LayerTreeHostImpl::SetSynchronousInputHandlerRootScrollOffset", + "offset_x", root_content_offset.x(), "offset_y", root_content_offset.y()); + + gfx::Vector2dF physical_delta = ContentToPhysical( + root_content_offset.DeltaFrom(viewport()->TotalScrollOffset()), + active_tree()->page_scale_factor_for_scroll()); - gfx::Vector2dF delta = root_offset.DeltaFrom(viewport()->TotalScrollOffset()); bool changed = !viewport() - ->ScrollBy(delta, + ->ScrollBy(physical_delta, /*viewport_point=*/gfx::Point(), - /*is_wheel_scroll=*/false, + /*is_direct_manipulation=*/false, /*affect_browser_controls=*/false, /*scroll_outer_viewport=*/true) .consumed_delta.IsZero(); @@ -4788,11 +4815,17 @@ InputHandlerPointerResult LayerTreeHostImpl::MouseUp( return result; } -void LayerTreeHostImpl::MouseMoveAt(const gfx::Point& viewport_point) { +InputHandlerPointerResult LayerTreeHostImpl::MouseMoveAt( + const gfx::Point& viewport_point) { + InputHandlerPointerResult result; + if (settings().compositor_threaded_scrollbar_scrolling) + result = + scrollbar_controller_->HandleMouseMove(gfx::PointF(viewport_point)); + // Early out if there are no animation controllers and avoid the hit test. // This happens on platforms without animated scrollbars. if (scrollbar_animation_controllers_.empty()) - return; + return result; gfx::PointF device_viewport_point = gfx::ScalePoint( gfx::PointF(viewport_point), active_tree_->device_scale_factor()); @@ -4839,9 +4872,11 @@ void LayerTreeHostImpl::MouseMoveAt(const gfx::Point& viewport_point) { } if (!new_animation_controller) - return; + return result; new_animation_controller->DidMouseMove(device_viewport_point); + + return result; } void LayerTreeHostImpl::MouseLeave() { @@ -5065,20 +5100,21 @@ bool LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time, } void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) { - std::unique_ptr<MutatorEvents> events = mutator_host_->CreateEvents(); + ScopedPostAnimationEventsToMainThread event_poster(mutator_host_.get(), + client_); - const bool has_active_animations = - mutator_host_->UpdateAnimationState(start_ready_animations, events.get()); - - if (!events->IsEmpty()) - client_->PostAnimationEventsToMainThreadOnImplThread(std::move(events)); + const bool has_active_animations = mutator_host_->UpdateAnimationState( + start_ready_animations, event_poster.events()); if (has_active_animations) SetNeedsOneBeginImplFrame(); } void LayerTreeHostImpl::ActivateAnimations() { - const bool activated = mutator_host_->ActivateAnimations(); + ScopedPostAnimationEventsToMainThread event_poster(mutator_host_.get(), + client_); + const bool activated = + mutator_host_->ActivateAnimations(event_poster.events()); if (activated) { // Activating an animation changes layer draw properties, such as // screen_space_transform_is_animating. So when we see a new animation get @@ -5335,7 +5371,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid, GLenum texture_target = GL_TEXTURE_2D; // For software compositing, shared memory will be allocated and the // UIResource will be copied into it. - std::unique_ptr<base::SharedMemory> shared_memory; + base::MappedReadOnlyRegion mapped_region; viz::SharedBitmapId shared_bitmap_id; bool overlay_candidate = false; @@ -5353,8 +5389,8 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid, BufferFormat(format), caps); } } else { - shared_memory = - viz::bitmap_allocation::AllocateMappedBitmap(upload_size, format); + mapped_region = + viz::bitmap_allocation::AllocateSharedBitmap(upload_size, format); shared_bitmap_id = viz::SharedBitmap::GenerateId(); } @@ -5379,7 +5415,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid, SkImageInfo::MakeN32Premul(gfx::SizeToSkISize(upload_size)); sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect( - dst_info, shared_memory->memory(), dst_info.minRowBytes()); + dst_info, mapped_region.mapping.memory(), dst_info.minRowBytes()); surface->getCanvas()->writePixels( src_info, const_cast<uint8_t*>(bitmap.GetPixels()), src_info.minRowBytes(), 0, 0); @@ -5415,7 +5451,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid, SkImageInfo dst_info = SkImageInfo::MakeN32Premul(gfx::SizeToSkISize(upload_size)); scaled_surface = SkSurface::MakeRasterDirect( - dst_info, shared_memory->memory(), dst_info.minRowBytes()); + dst_info, mapped_region.mapping.memory(), dst_info.minRowBytes()); } SkCanvas* scaled_canvas = scaled_surface->getCanvas(); scaled_canvas->scale(canvas_scale_x, canvas_scale_y); @@ -5453,16 +5489,14 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid, ->SharedImageInterface() ->GenUnverifiedSyncToken(); - transferable = viz::TransferableResource::MakeGLOverlay( + transferable = viz::TransferableResource::MakeGL( mailbox, GL_LINEAR, texture_target, sync_token, upload_size, overlay_candidate); transferable.format = format; } else { - mojo::ScopedSharedBufferHandle memory_handle = - viz::bitmap_allocation::DuplicateAndCloseMappedBitmap( - shared_memory.get(), upload_size, format); - layer_tree_frame_sink_->DidAllocateSharedBitmap(std::move(memory_handle), - shared_bitmap_id); + layer_tree_frame_sink_->DidAllocateSharedBitmap( + viz::bitmap_allocation::ToMojoHandle(std::move(mapped_region.region)), + shared_bitmap_id); transferable = viz::TransferableResource::MakeSoftware(shared_bitmap_id, upload_size, format); } @@ -5480,7 +5514,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid, data.opaque = bitmap.GetOpaque(); data.format = format; data.shared_bitmap_id = shared_bitmap_id; - data.shared_memory = std::move(shared_memory); + data.shared_mapping = std::move(mapped_region.mapping); data.mailbox = mailbox; data.resource_id_for_export = id; ui_resource_map_[uid] = std::move(data); @@ -5510,8 +5544,8 @@ void LayerTreeHostImpl::DeleteUIResourceBacking( UIResourceData data, const gpu::SyncToken& sync_token) { // Resources are either software or gpu backed, not both. - DCHECK(!(data.shared_memory && !data.mailbox.IsZero())); - if (data.shared_memory) + DCHECK(!(data.shared_mapping.IsValid() && !data.mailbox.IsZero())); + if (data.shared_mapping.IsValid()) layer_tree_frame_sink_->DidDeleteSharedBitmap(data.shared_bitmap_id); if (!data.mailbox.IsZero()) { auto* sii = @@ -5661,8 +5695,9 @@ bool LayerTreeHostImpl::ScrollAnimationUpdateTarget( return animation_updated; } -bool LayerTreeHostImpl::IsElementInList(ElementId element_id, - ElementListType list_type) const { +bool LayerTreeHostImpl::IsElementInPropertyTrees( + ElementId element_id, + ElementListType list_type) const { if (list_type == ElementListType::ACTIVE) return active_tree() && active_tree()->IsElementInPropertyTree(element_id); @@ -5710,6 +5745,20 @@ void LayerTreeHostImpl::SetElementFilterMutated( } } +void LayerTreeHostImpl::SetElementBackdropFilterMutated( + ElementId element_id, + ElementListType list_type, + const FilterOperations& backdrop_filters) { + if (list_type == ElementListType::ACTIVE) { + active_tree()->SetBackdropFilterMutated(element_id, backdrop_filters); + } else { + if (pending_tree()) + pending_tree()->SetBackdropFilterMutated(element_id, backdrop_filters); + if (recycle_tree()) + recycle_tree()->SetBackdropFilterMutated(element_id, backdrop_filters); + } +} + void LayerTreeHostImpl::SetElementOpacityMutated(ElementId element_id, ElementListType list_type, float opacity) { @@ -5892,7 +5941,7 @@ void LayerTreeHostImpl::InitializeUkm( ukm_manager_ = std::make_unique<UkmManager>(std::move(recorder)); } -void LayerTreeHostImpl::SetActiveURL(const GURL& url) { +void LayerTreeHostImpl::SetActiveURL(const GURL& url, ukm::SourceId source_id) { tile_manager_.set_active_url(url); // The active tree might still be from content for the previous page when the @@ -5901,48 +5950,14 @@ void LayerTreeHostImpl::SetActiveURL(const GURL& url) { // case. Also, since checkerboard stats are only recorded with user // interaction, it must be in progress when the navigation commits for this // case to occur. - if (ukm_manager_) - ukm_manager_->SetSourceURL(url); -} - -void LayerTreeHostImpl::OnLayerTreeLocalSurfaceIdAllocationChanged() { - if (!waiting_for_local_surface_id_) - return; - - const viz::LocalSurfaceId& current_id = - child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() - .local_surface_id(); - const viz::LocalSurfaceId& new_id = - active_tree() - ->local_surface_id_allocation_from_parent() - .local_surface_id(); - if ((current_id.embed_token() != new_id.embed_token()) || - (new_id.parent_sequence_number() > current_id.parent_sequence_number()) || - ((new_id.parent_sequence_number() == - current_id.parent_sequence_number()) && - (new_id.child_sequence_number() >= - current_id.child_sequence_number()))) { - waiting_for_local_surface_id_ = false; - client_->OnCanDrawStateChanged(CanDraw()); + if (ukm_manager_) { + // The source id has already been associated to the URL. + ukm_manager_->SetSourceId(source_id); } } -uint32_t LayerTreeHostImpl::GenerateChildSurfaceSequenceNumberSync() { - waiting_for_local_surface_id_ = true; - child_local_surface_id_allocator_.GenerateIdOrIncrementChild(); - client_->OnCanDrawStateChanged(CanDraw()); - return child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation() - .local_surface_id() - .child_sequence_number(); -} - void LayerTreeHostImpl::AllocateLocalSurfaceId() { - if (!settings_.automatically_allocate_surface_ids) - return; - child_local_surface_id_allocator_.GenerateId(); - client_->DidGenerateLocalSurfaceIdAllocationOnImplThread( - child_local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation()); } void LayerTreeHostImpl::RequestBeginFrameForAnimatedImages() { @@ -5958,4 +5973,8 @@ void LayerTreeHostImpl::RequestInvalidationForAnimatedImages() { client_->NeedsImplSideInvalidation(needs_first_draw_on_activation); } +base::WeakPtr<LayerTreeHostImpl> LayerTreeHostImpl::AsWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h index 18ccfb6763d..bb89bc998a4 100644 --- a/chromium/cc/trees/layer_tree_host_impl.h +++ b/chromium/cc/trees/layer_tree_host_impl.h @@ -7,17 +7,16 @@ #include <stddef.h> -#include <bitset> #include <memory> #include <set> -#include <string> #include <unordered_map> +#include <utility> #include <vector> #include "base/callback.h" -#include "base/containers/circular_deque.h" #include "base/containers/flat_map.h" #include "base/memory/memory_pressure_listener.h" +#include "base/memory/shared_memory_mapping.h" #include "base/sequenced_task_runner.h" #include "base/time/time.h" #include "cc/base/synced_property.h" @@ -42,6 +41,7 @@ #include "cc/trees/layer_tree_settings.h" #include "cc/trees/managed_memory_policy.h" #include "cc/trees/mutator_host_client.h" +#include "cc/trees/presentation_time_callback_buffer.h" #include "cc/trees/render_frame_metadata.h" #include "cc/trees/task_runner_provider.h" #include "cc/trees/ukm_manager.h" @@ -156,9 +156,6 @@ class LayerTreeHostImplClient { std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback) = 0; - virtual void DidGenerateLocalSurfaceIdAllocationOnImplThread( - const viz::LocalSurfaceIdAllocation& allocation) = 0; - virtual void NotifyAnimationWorkletStateChange( AnimationWorkletMutationState state, ElementListType tree_type) = 0; @@ -169,16 +166,14 @@ class LayerTreeHostImplClient { // LayerTreeHostImpl owns the LayerImpl trees as well as associated rendering // state. -class CC_EXPORT LayerTreeHostImpl - : public InputHandler, - public TileManagerClient, - public LayerTreeFrameSinkClient, - public BrowserControlsOffsetManagerClient, - public ScrollbarAnimationControllerClient, - public VideoFrameControllerClient, - public MutatorHostClient, - public ImageAnimationController::Client, - public base::SupportsWeakPtr<LayerTreeHostImpl> { +class CC_EXPORT LayerTreeHostImpl : public InputHandler, + public TileManagerClient, + public LayerTreeFrameSinkClient, + public BrowserControlsOffsetManagerClient, + public ScrollbarAnimationControllerClient, + public VideoFrameControllerClient, + public MutatorHostClient, + public ImageAnimationController::Client { public: // This structure is used to build all the state required for producing a // single CompositorFrame. The |render_passes| list becomes the set of @@ -219,7 +214,7 @@ class CC_EXPORT LayerTreeHostImpl // Backing for software compositing. viz::SharedBitmapId shared_bitmap_id; - std::unique_ptr<base::SharedMemory> shared_memory; + base::WritableSharedMemoryMapping shared_mapping; // Backing for gpu compositing. gpu::Mailbox mailbox; @@ -259,13 +254,14 @@ class CC_EXPORT LayerTreeHostImpl InputHandlerScrollResult ScrollBy(ScrollState* scroll_state) override; void RequestUpdateForSynchronousInputHandler() override; void SetSynchronousInputHandlerRootScrollOffset( - const gfx::ScrollOffset& root_offset) override; + const gfx::ScrollOffset& root_content_offset) override; void ScrollEnd(ScrollState* scroll_state, bool should_snap = false) override; InputHandlerPointerResult MouseDown( const gfx::PointF& viewport_point) override; InputHandlerPointerResult MouseUp(const gfx::PointF& viewport_point) override; - void MouseMoveAt(const gfx::Point& viewport_point) override; + InputHandlerPointerResult MouseMoveAt( + const gfx::Point& viewport_point) override; void MouseLeave() override; void PinchGestureBegin() override; @@ -311,6 +307,8 @@ class CC_EXPORT LayerTreeHostImpl void RequestBeginFrameForAnimatedImages() override; void RequestInvalidationForAnimatedImages() override; + base::WeakPtr<LayerTreeHostImpl> AsWeakPtr(); + void UpdateViewportContainerSizes(); void set_resourceless_software_draw_for_testing() { @@ -338,6 +336,10 @@ class CC_EXPORT LayerTreeHostImpl void SetFullViewportDamage(); void SetViewportDamage(const gfx::Rect& damage_rect); + // Updates registered ElementIds present in |changed_list|. Call this after + // changing the property trees for the |changed_list| trees. + void UpdateElements(ElementListType changed_list); + // Analogous to a commit, this function is used to create a sync tree and // add impl-side invalidations to it. // virtual for testing. @@ -353,13 +355,17 @@ class CC_EXPORT LayerTreeHostImpl } // MutatorHostClient implementation. - bool IsElementInList(ElementId element_id, - ElementListType list_type) const override; + bool IsElementInPropertyTrees(ElementId element_id, + ElementListType list_type) const override; void SetMutatorsNeedCommit() override; void SetMutatorsNeedRebuildPropertyTrees() override; void SetElementFilterMutated(ElementId element_id, ElementListType list_type, const FilterOperations& filters) override; + void SetElementBackdropFilterMutated( + ElementId element_id, + ElementListType list_type, + const FilterOperations& backdrop_filters) override; void SetElementOpacityMutated(ElementId element_id, ElementListType list_type, float opacity) override; @@ -746,13 +752,7 @@ class CC_EXPORT LayerTreeHostImpl void SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer); - void SetActiveURL(const GURL& url); - - // Called when LayerTreeImpl's LocalSurfaceIdAllocation changes. - void OnLayerTreeLocalSurfaceIdAllocationChanged(); - - // See SyncSurfaceIdAllocator for details. - uint32_t GenerateChildSurfaceSequenceNumberSync(); + void SetActiveURL(const GURL& url, ukm::SourceId source_id); CompositorFrameReportingController* compositor_frame_reporting_controller() const { @@ -826,7 +826,7 @@ class CC_EXPORT LayerTreeHostImpl // Returns true if status changed. bool UpdateGpuRasterizationStatus(); - void UpdateTreeResourcesIfNeeded(); + void UpdateTreeResourcesForGpuRasterizationIfNeeded(); Viewport* viewport() const { return viewport_.get(); } @@ -1160,39 +1160,11 @@ class CC_EXPORT LayerTreeHostImpl base::Optional<RenderFrameMetadata> last_draw_render_frame_metadata_; viz::ChildLocalSurfaceIdAllocator child_local_surface_id_allocator_; - // Set to true if waiting to receive a LocalSurfaceIdAllocation that matches - // that of |child_local_surface_id_allocator_|. - bool waiting_for_local_surface_id_ = false; - std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; - // Stores information needed once we get a response for a particular - // presentation token. - struct FrameTokenInfo { - FrameTokenInfo( - uint32_t token, - base::TimeTicks cc_frame_time, - std::vector<LayerTreeHost::PresentationTimeCallback> callbacks); - FrameTokenInfo(const FrameTokenInfo&) = delete; - FrameTokenInfo(FrameTokenInfo&&); - ~FrameTokenInfo(); - - FrameTokenInfo& operator=(const FrameTokenInfo&) = delete; - FrameTokenInfo& operator=(FrameTokenInfo&&) = default; - - uint32_t token; - - // The compositor frame time used to produce the frame. - base::TimeTicks cc_frame_time; - - // The callbacks to send back to the main thread. - std::vector<LayerTreeHost::PresentationTimeCallback> callbacks; - }; - - base::circular_deque<FrameTokenInfo> frame_token_infos_; + PresentationTimeCallbackBuffer presentation_time_callbacks_; ui::FrameMetrics frame_metrics_; ui::SkippedFrameTracker skipped_frame_tracker_; - int last_color_space_id_ = -1; bool is_animating_for_snap_; const PaintImage::GeneratorClientId paint_image_generator_client_id_; @@ -1214,6 +1186,10 @@ class CC_EXPORT LayerTreeHostImpl // animation completion. ScrollEnd will get called with this deferred state // once the animation is over. base::Optional<ScrollState> deferred_scroll_end_state_; + + // Must be the last member to ensure this is destroyed first in the + // destruction order and invalidates all weak pointers. + base::WeakPtrFactory<LayerTreeHostImpl> weak_factory_; }; } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc index 13a8b429571..80d1f14a001 100644 --- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc @@ -76,11 +76,11 @@ #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/quads/tile_draw_quad.h" #include "components/viz/common/surfaces/frame_sink_id.h" -#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/service/display/gl_renderer.h" #include "components/viz/service/display/skia_output_surface.h" #include "components/viz/test/begin_frame_args_test.h" #include "components/viz/test/fake_output_surface.h" +#include "components/viz/test/fake_skia_output_surface.h" #include "components/viz/test/test_layer_tree_frame_sink.h" #include "gpu/GLES2/gl2extchromium.h" #include "media/base/media.h" @@ -196,14 +196,11 @@ class LayerTreeHostImplTest : public testing::Test, requested_animation_delay_ = delay; } void DidActivateSyncTree() override { - if (set_local_surface_id_on_activate_) { - // Make sure the active tree always has a valid LocalSurfaceId. - host_impl_->active_tree()->SetLocalSurfaceIdAllocationFromParent( - viz::LocalSurfaceIdAllocation( - viz::LocalSurfaceId(1, - base::UnguessableToken::Deserialize(2u, 3u)), - base::TimeTicks::Now())); - } + // Make sure the active tree always has a valid LocalSurfaceId. + host_impl_->active_tree()->SetLocalSurfaceIdAllocationFromParent( + viz::LocalSurfaceIdAllocation( + viz::LocalSurfaceId(1, base::UnguessableToken::Deserialize(2u, 3u)), + base::TimeTicks::Now())); } void WillPrepareTiles() override {} void DidPrepareTiles() override {} @@ -230,11 +227,6 @@ class LayerTreeHostImplTest : public testing::Test, uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback) override {} - void DidGenerateLocalSurfaceIdAllocationOnImplThread( - const viz::LocalSurfaceIdAllocation& allocation) override { - last_generated_local_surface_id_ = allocation; - did_generate_local_surface_id_ = true; - } void NotifyAnimationWorkletStateChange(AnimationWorkletMutationState state, ElementListType tree_type) override {} @@ -471,13 +463,14 @@ class LayerTreeHostImplTest : public testing::Test, scroll->SetElementId(LayerIdToElementIdForTesting(scroll->id())); scroll->SetDrawsContent(true); - std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar = - SolidColorScrollbarLayerImpl::Create(layer_tree_impl, 4, VERTICAL, 10, - 0, false, true); + std::unique_ptr<PaintedScrollbarLayerImpl> scrollbar = + PaintedScrollbarLayerImpl::Create(layer_tree_impl, 4, VERTICAL, false, + true); scrollbar->SetBounds(scrollbar_size); scrollbar->test_properties()->position = gfx::PointF(345, 0); scrollbar->SetScrollElementId(scroll->element_id()); scrollbar->SetDrawsContent(true); + scrollbar->SetHitTestable(true); scrollbar->test_properties()->opacity = 1.f; std::unique_ptr<LayerImpl> squash1 = LayerImpl::Create(layer_tree_impl, 5); @@ -812,9 +805,6 @@ class LayerTreeHostImplTest : public testing::Test, viz::RenderPassList last_on_draw_render_passes_; scoped_refptr<AnimationTimeline> timeline_; std::unique_ptr<base::Thread> image_worker_; - viz::LocalSurfaceIdAllocation last_generated_local_surface_id_; - bool did_generate_local_surface_id_ = false; - bool set_local_surface_id_on_activate_ = true; }; class CommitToPendingTreeLayerTreeHostImplTest : public LayerTreeHostImplTest { @@ -944,52 +934,6 @@ TEST_F(LayerTreeHostImplTest, NotifyIfCanDrawChanged) { EXPECT_TRUE(host_impl_->CanDraw()); EXPECT_TRUE(on_can_draw_state_changed_called_); on_can_draw_state_changed_called_ = false; - - viz::ParentLocalSurfaceIdAllocator parent_allocator; - parent_allocator.GenerateId(); - const uint32_t child_sequence_number1 = - host_impl_->GenerateChildSurfaceSequenceNumberSync(); - EXPECT_NE(child_sequence_number1, viz::kInitialChildSequenceNumber); - EXPECT_FALSE(host_impl_->CanDraw()); - EXPECT_TRUE(on_can_draw_state_changed_called_); - on_can_draw_state_changed_called_ = false; - - host_impl_->active_tree()->SetLocalSurfaceIdAllocationFromParent( - parent_allocator.GetCurrentLocalSurfaceIdAllocation()); - EXPECT_TRUE(host_impl_->CanDraw()); - EXPECT_TRUE(on_can_draw_state_changed_called_); - on_can_draw_state_changed_called_ = false; - - // Without this SetLocalSurfaceIdAllocationFromParent() is called from - // DidActivateSyncTree(). - set_local_surface_id_on_activate_ = false; - // Necessary to set LocalSurfaceIdAllocation in - // |LayerTreeHostImpl::child_local_surface_id_allocator_|. - host_impl_->ActivateSyncTree(); - - const uint32_t child_sequence_number2 = - host_impl_->GenerateChildSurfaceSequenceNumberSync(); - EXPECT_NE(child_sequence_number2, child_sequence_number1); - EXPECT_FALSE(host_impl_->CanDraw()); - EXPECT_TRUE(on_can_draw_state_changed_called_); - on_can_draw_state_changed_called_ = false; - - host_impl_->active_tree()->SetLocalSurfaceIdAllocationFromParent( - parent_allocator.GetCurrentLocalSurfaceIdAllocation()); - EXPECT_FALSE(host_impl_->CanDraw()); - EXPECT_FALSE(on_can_draw_state_changed_called_); - - auto id_from_parent = - parent_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id(); - host_impl_->active_tree()->SetLocalSurfaceIdAllocationFromParent( - viz::LocalSurfaceIdAllocation( - viz::LocalSurfaceId(id_from_parent.parent_sequence_number(), - child_sequence_number2, - id_from_parent.embed_token()), - base::TimeTicks::Now())); - EXPECT_TRUE(host_impl_->CanDraw()); - EXPECT_TRUE(on_can_draw_state_changed_called_); - on_can_draw_state_changed_called_ = false; } TEST_F(LayerTreeHostImplTest, ResourcelessDrawWithEmptyViewport) { @@ -1373,9 +1317,9 @@ TEST_F(LayerTreeHostImplTest, ScrolledOverlappingDrawnScrollbarLayer) { scroll->SetDrawsContent(true); scroll->SetHitTestable(true); - std::unique_ptr<SolidColorScrollbarLayerImpl> drawn_scrollbar = - SolidColorScrollbarLayerImpl::Create(layer_tree_impl, 4, VERTICAL, 10, 0, - false, true); + std::unique_ptr<PaintedScrollbarLayerImpl> drawn_scrollbar = + PaintedScrollbarLayerImpl::Create(layer_tree_impl, 4, VERTICAL, false, + true); drawn_scrollbar->SetBounds(scrollbar_size); drawn_scrollbar->test_properties()->position = gfx::PointF(345, 0); drawn_scrollbar->SetScrollElementId(scroll->element_id()); @@ -2287,8 +2231,22 @@ TEST_F(LayerTreeHostImplTest, AnimationSchedulingOnLayerDestruction) { // Destroy layer, unregister animation target (element). child->test_properties()->parent = nullptr; root->test_properties()->RemoveChild(child); + + // Calling LayerImplTestProperties::RemoveChild above does not actually + // remove the property tree nodes for the removed layer. In the real code, + // you cannot remove a child on LayerImpl, but a child removed on Layer + // will force a full tree sync which will rebuild property trees without that + // child's property tree nodes. Call BuildPropertyTrees to simulate the + // rebuild that would happen during the commit. + host_impl_->active_tree()->BuildPropertyTreesForTesting(); child = nullptr; + // On updating state, we will send an animation event and request one last + // frame. + host_impl_->UpdateAnimationState(true); + EXPECT_TRUE(did_request_next_frame_); + did_request_next_frame_ = false; + // Doing Animate() doesn't request another frame after the current one. host_impl_->Animate(); EXPECT_FALSE(did_request_next_frame_); @@ -2410,8 +2368,8 @@ TEST_F(LayerTreeHostImplTest, ViewportScrollbarGeometry) { // size. const gfx::Size outer_viewport_size = content_size; - SolidColorScrollbarLayerImpl* v_scrollbar; - SolidColorScrollbarLayerImpl* h_scrollbar; + PaintedScrollbarLayerImpl* v_scrollbar; + PaintedScrollbarLayerImpl* h_scrollbar; // Setup { @@ -2434,12 +2392,12 @@ TEST_F(LayerTreeHostImplTest, ViewportScrollbarGeometry) { // Add scrollbars. They will always exist - even if unscrollable - but their // visibility will be determined by whether the content can be scrolled. { - std::unique_ptr<SolidColorScrollbarLayerImpl> v_scrollbar_unique = - SolidColorScrollbarLayerImpl::Create(active_tree, 400, VERTICAL, 10, - 0, false, true); - std::unique_ptr<SolidColorScrollbarLayerImpl> h_scrollbar_unique = - SolidColorScrollbarLayerImpl::Create(active_tree, 401, HORIZONTAL, 10, - 0, false, true); + std::unique_ptr<PaintedScrollbarLayerImpl> v_scrollbar_unique = + PaintedScrollbarLayerImpl::Create(active_tree, 400, VERTICAL, false, + true); + std::unique_ptr<PaintedScrollbarLayerImpl> h_scrollbar_unique = + PaintedScrollbarLayerImpl::Create(active_tree, 401, HORIZONTAL, false, + true); v_scrollbar = v_scrollbar_unique.get(); h_scrollbar = h_scrollbar_unique.get(); @@ -4031,7 +3989,6 @@ class LayerTreeHostImplTestMultiScrollable : public LayerTreeHostImplTest { scrollbar_1_ = scrollbar_1.get(); scrollbar_1->SetScrollElementId(root_scroll->element_id()); scrollbar_1->SetDrawsContent(true); - scrollbar_1->SetHitTestable(true); scrollbar_1->SetBounds(scrollbar_size_1); TouchActionRegion touch_action_region; touch_action_region.Union(kTouchActionNone, gfx::Rect(scrollbar_size_1)); @@ -4062,7 +4019,6 @@ class LayerTreeHostImplTestMultiScrollable : public LayerTreeHostImplTest { scrollbar_2->SetScrollElementId(child_element_id); scrollbar_2->SetDrawsContent(true); - scrollbar_2->SetHitTestable(true); scrollbar_2->SetBounds(scrollbar_size_2); scrollbar_2->SetCurrentPos(0); scrollbar_2->test_properties()->position = gfx::PointF(0, 0); @@ -4155,13 +4111,79 @@ TEST_F(LayerTreeHostImplTestMultiScrollable, ScrollbarFlashWhenMouseEnter) { EXPECT_FALSE(animation_task_.is_null()); } -TEST_F(LayerTreeHostImplTestMultiScrollable, ScrollHitTestOnScrollbar) { +TEST_F(LayerTreeHostImplTest, ScrollHitTestOnScrollbar) { LayerTreeSettings settings = DefaultSettings(); settings.scrollbar_fade_delay = base::TimeDelta::FromMilliseconds(500); settings.scrollbar_fade_duration = base::TimeDelta::FromMilliseconds(300); settings.scrollbar_animator = LayerTreeSettings::NO_ANIMATOR; - SetUpLayers(settings); + gfx::Size viewport_size(300, 200); + gfx::Size content_size(1000, 1000); + gfx::Size child_layer_size(250, 150); + gfx::Size scrollbar_size_1(gfx::Size(15, viewport_size.height())); + gfx::Size scrollbar_size_2(gfx::Size(15, child_layer_size.height())); + + const int scrollbar_1_id = 10; + const int scrollbar_2_id = 11; + const int child_scroll_id = 13; + + CreateHostImpl(settings, CreateLayerTreeFrameSink()); + host_impl_->active_tree()->SetDeviceScaleFactor(1); + host_impl_->active_tree()->SetDeviceViewportSize(viewport_size); + CreateScrollAndContentsLayers(host_impl_->active_tree(), content_size); + host_impl_->active_tree()->InnerViewportContainerLayer()->SetBounds( + viewport_size); + LayerImpl* root_scroll = + host_impl_->active_tree()->OuterViewportScrollLayer(); + + // scrollbar_1 on root scroll. + std::unique_ptr<PaintedScrollbarLayerImpl> scrollbar_1 = + PaintedScrollbarLayerImpl::Create(host_impl_->active_tree(), + scrollbar_1_id, VERTICAL, true, true); + scrollbar_1->SetScrollElementId(root_scroll->element_id()); + scrollbar_1->SetDrawsContent(true); + scrollbar_1->SetHitTestable(true); + scrollbar_1->SetBounds(scrollbar_size_1); + TouchActionRegion touch_action_region; + touch_action_region.Union(kTouchActionNone, gfx::Rect(scrollbar_size_1)); + scrollbar_1->SetTouchActionRegion(touch_action_region); + scrollbar_1->SetCurrentPos(0); + scrollbar_1->test_properties()->position = gfx::PointF(0, 0); + scrollbar_1->test_properties()->opacity = 0.f; + host_impl_->active_tree() + ->InnerViewportContainerLayer() + ->test_properties() + ->AddChild(std::move(scrollbar_1)); + + // scrollbar_2 on child. + std::unique_ptr<PaintedScrollbarLayerImpl> scrollbar_2 = + PaintedScrollbarLayerImpl::Create(host_impl_->active_tree(), + scrollbar_2_id, VERTICAL, true, true); + std::unique_ptr<LayerImpl> child = + LayerImpl::Create(host_impl_->active_tree(), child_scroll_id); + child->test_properties()->position = gfx::PointF(50, 50); + child->SetBounds(child_layer_size); + child->SetDrawsContent(true); + child->SetHitTestable(true); + child->SetScrollable(gfx::Size(100, 100)); + child->SetHitTestable(true); + child->SetElementId(LayerIdToElementIdForTesting(child->id())); + ElementId child_element_id = child->element_id(); + + scrollbar_2->SetScrollElementId(child_element_id); + scrollbar_2->SetDrawsContent(true); + scrollbar_2->SetHitTestable(true); + scrollbar_2->SetBounds(scrollbar_size_2); + scrollbar_2->SetCurrentPos(0); + scrollbar_2->test_properties()->position = gfx::PointF(0, 0); + scrollbar_2->test_properties()->opacity = 0.f; + + child->test_properties()->AddChild(std::move(scrollbar_2)); + root_scroll->test_properties()->AddChild(std::move(child)); + + host_impl_->active_tree()->BuildPropertyTreesForTesting(); + host_impl_->active_tree()->UpdateScrollbarGeometries(); + host_impl_->active_tree()->DidBecomeActive(); // Wheel scroll on root scrollbar should process on impl thread. { @@ -4294,9 +4316,9 @@ TEST_F(LayerTreeHostImplTest, ScrollbarInnerLargerThanOuter) { outer_viewport_size); LayerImpl* root_scroll = host_impl_->active_tree()->OuterViewportScrollLayer(); - std::unique_ptr<SolidColorScrollbarLayerImpl> horiz_scrollbar = - SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), horiz_id, - HORIZONTAL, 5, 5, true, true); + std::unique_ptr<PaintedScrollbarLayerImpl> horiz_scrollbar = + PaintedScrollbarLayerImpl::Create(host_impl_->active_tree(), horiz_id, + HORIZONTAL, true, true); std::unique_ptr<LayerImpl> child = LayerImpl::Create(host_impl_->active_tree(), child_scroll_id); child->SetBounds(content_size); @@ -7891,6 +7913,9 @@ TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetUserScrollable) { host_impl_->active_tree()->BuildPropertyTreesForTesting(); DrawFrame(); + // Ensure that the scroll offset is interpreted as a content offset so it + // should be unaffected by the page scale factor. See + // https://crbug.com/973771. float page_scale_factor = 2.f; host_impl_->active_tree()->PushPageScaleFromMainThread( page_scale_factor, page_scale_factor, page_scale_factor); @@ -7906,7 +7931,6 @@ TEST_F(LayerTreeHostImplTest, SetRootScrollOffsetUserScrollable) { host_impl_->SetSynchronousInputHandlerRootScrollOffset(scroll_offset); EXPECT_VECTOR_EQ(gfx::ScrollOffset(), scroll_tree.current_scroll_offset(inner_element_id)); - scroll_offset.Scale(1.f / page_scale_factor); EXPECT_VECTOR_EQ(scroll_offset, scroll_tree.current_scroll_offset(outer_element_id)); EXPECT_TRUE(did_request_redraw_); @@ -8962,7 +8986,7 @@ class BlendStateCheckLayer : public LayerImpl { test_blending_draw_quad->SetNew( shared_quad_state, quad_rect_, visible_quad_rect, needs_blending, resource_id_, gfx::RectF(0.f, 0.f, 1.f, 1.f), gfx::Size(1, 1), false, - false, false, false); + false, false); EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending()); EXPECT_EQ(has_render_surface_, @@ -9304,7 +9328,7 @@ TEST_F(LayerTreeHostImplTest, MayContainVideo) { class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { protected: LayerTreeHostImplViewportCoveredTest() - : gutter_quad_material_(viz::DrawQuad::SOLID_COLOR), + : gutter_quad_material_(viz::DrawQuad::Material::kSolidColor), child_(nullptr), did_activate_pending_tree_(false) {} @@ -9498,7 +9522,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest { // Make sure that the texture coordinates match their expectations. void ValidateTextureDrawQuads(const viz::QuadList& quad_list) { for (auto* quad : quad_list) { - if (quad->material != viz::DrawQuad::TEXTURE_CONTENT) + if (quad->material != viz::DrawQuad::Material::kTextureContent) continue; const viz::TextureDrawQuad* texture_quad = viz::TextureDrawQuad::MaterialCast(quad); @@ -9814,7 +9838,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { { const auto& root_pass = frame.render_passes.back(); ASSERT_EQ(1u, root_pass->quad_list.size()); - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, root_pass->quad_list.front()->material); } host_impl_->DrawLayers(&frame); @@ -10233,11 +10257,6 @@ TEST_F(LayerTreeHostImplTest, RequireHighResAfterGpuRasterizationToggles) { // RequiresHighResToDraw is set when new output surface is used. EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); - // The first commit will also set RequiresHighResToDraw due to the - // raster color space changing. - host_impl_->ResetRequiresHighResToDraw(); - host_impl_->CommitComplete(); - EXPECT_TRUE(host_impl_->RequiresHighResToDraw()); host_impl_->ResetRequiresHighResToDraw(); host_impl_->SetContentHasSlowPaths(false); @@ -10399,8 +10418,8 @@ class FrameSinkClient : public viz::TestLayerTreeFrameSinkClient { std::unique_ptr<viz::SkiaOutputSurface> CreateDisplaySkiaOutputSurface() override { - NOTIMPLEMENTED(); - return nullptr; + return viz::FakeSkiaOutputSurface::Create3d( + std::move(display_context_provider_)); } std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurface( @@ -10422,7 +10441,20 @@ class FrameSinkClient : public viz::TestLayerTreeFrameSinkClient { scoped_refptr<viz::ContextProvider> display_context_provider_; }; -TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) { +enum RendererType { RENDERER_GL, RENDERER_SKIA }; + +class LayerTreeHostImplTestWithRenderer + : public LayerTreeHostImplTest, + public ::testing::WithParamInterface<RendererType> { + protected: + RendererType renderer_type() const { return GetParam(); } +}; + +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostImplTestWithRenderer, + ::testing::Values(RENDERER_GL, RENDERER_SKIA)); + +TEST_P(LayerTreeHostImplTestWithRenderer, ShutdownReleasesContext) { scoped_refptr<viz::TestContextProvider> context_provider = viz::TestContextProvider::Create(); FrameSinkClient test_client(context_provider); @@ -10430,9 +10462,11 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) { constexpr bool synchronous_composite = true; constexpr bool disable_display_vsync = false; constexpr double refresh_rate = 60.0; + viz::RendererSettings renderer_settings = viz::RendererSettings(); + renderer_settings.use_skia_renderer = renderer_type() == RENDERER_SKIA; auto layer_tree_frame_sink = std::make_unique<viz::TestLayerTreeFrameSink>( context_provider, viz::TestContextProvider::CreateWorker(), nullptr, - viz::RendererSettings(), base::ThreadTaskRunnerHandle::Get().get(), + renderer_settings, base::ThreadTaskRunnerHandle::Get().get(), synchronous_composite, disable_display_vsync, refresh_rate); layer_tree_frame_sink->SetClient(&test_client); @@ -12962,15 +12996,15 @@ TEST_F(LayerTreeHostImplTest, RemoveUnreferencedRenderPass) { // Add a quad to each pass so they aren't empty. auto* color_quad = pass1->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>(); - color_quad->material = viz::DrawQuad::SOLID_COLOR; + color_quad->material = viz::DrawQuad::Material::kSolidColor; color_quad = pass2->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>(); - color_quad->material = viz::DrawQuad::SOLID_COLOR; + color_quad->material = viz::DrawQuad::Material::kSolidColor; color_quad = pass3->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>(); - color_quad->material = viz::DrawQuad::SOLID_COLOR; + color_quad->material = viz::DrawQuad::Material::kSolidColor; // pass3 is referenced by pass2. auto* rpdq = pass2->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>(); - rpdq->material = viz::DrawQuad::RENDER_PASS; + rpdq->material = viz::DrawQuad::Material::kRenderPass; rpdq->render_pass_id = pass3->id; // But pass2 is not referenced by pass1. So pass2 and pass3 should be culled. @@ -12997,16 +13031,16 @@ TEST_F(LayerTreeHostImplTest, RemoveEmptyRenderPass) { // pass1 is not empty, but pass2 and pass3 are. auto* color_quad = pass1->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>(); - color_quad->material = viz::DrawQuad::SOLID_COLOR; + color_quad->material = viz::DrawQuad::Material::kSolidColor; // pass3 is referenced by pass2. auto* rpdq = pass2->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>(); - rpdq->material = viz::DrawQuad::RENDER_PASS; + rpdq->material = viz::DrawQuad::Material::kRenderPass; rpdq->render_pass_id = pass3->id; // pass2 is referenced by pass1. rpdq = pass1->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>(); - rpdq->material = viz::DrawQuad::RENDER_PASS; + rpdq->material = viz::DrawQuad::Material::kRenderPass; rpdq->render_pass_id = pass2->id; // Since pass3 is empty it should be removed. Then pass2 is empty too, and @@ -13019,7 +13053,7 @@ TEST_F(LayerTreeHostImplTest, RemoveEmptyRenderPass) { EXPECT_EQ(1u, frame.render_passes[0]->id); // The viz::RenderPassDrawQuad should be removed from pass1. EXPECT_EQ(1u, pass1->quad_list.size()); - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, pass1->quad_list.ElementAt(0)->material); } @@ -13038,12 +13072,12 @@ TEST_F(LayerTreeHostImplTest, DoNotRemoveEmptyRootRenderPass) { // pass3 is referenced by pass2. auto* rpdq = pass2->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>(); - rpdq->material = viz::DrawQuad::RENDER_PASS; + rpdq->material = viz::DrawQuad::Material::kRenderPass; rpdq->render_pass_id = pass3->id; // pass2 is referenced by pass1. rpdq = pass1->CreateAndAppendDrawQuad<viz::RenderPassDrawQuad>(); - rpdq->material = viz::DrawQuad::RENDER_PASS; + rpdq->material = viz::DrawQuad::Material::kRenderPass; rpdq->render_pass_id = pass2->id; // Since pass3 is empty it should be removed. Then pass2 is empty too, and @@ -14760,5 +14794,50 @@ TEST_F(LayerTreeHostImplTest, SkipOnDrawDoesNotUpdateDrawParams) { EXPECT_EQ(viewport, host_impl_->active_tree()->GetDeviceViewport()); } +// Test that a touch scroll over a SolidColorScrollbarLayer, the scrollbar used +// on Android, does not register as a scrollbar scroll and result in main +// threaded scrolling. +TEST_F(LayerTreeHostImplTest, TouchScrollOnAndroidScrollbar) { + LayerTreeImpl* layer_tree_impl = host_impl_->active_tree(); + gfx::Size viewport_size = gfx::Size(360, 600); + gfx::Size scroll_content_size = gfx::Size(360, 3800); + gfx::Size scrollbar_size = gfx::Size(15, 600); + + host_impl_->active_tree()->SetDeviceViewportSize(viewport_size); + std::unique_ptr<LayerImpl> root = LayerImpl::Create(layer_tree_impl, 1); + root->SetBounds(viewport_size); + root->test_properties()->position = gfx::PointF(); + + std::unique_ptr<LayerImpl> content = LayerImpl::Create(layer_tree_impl, 2); + content->SetBounds(scroll_content_size); + content->SetScrollable(viewport_size); + content->SetHitTestable(true); + content->SetElementId(LayerIdToElementIdForTesting(content->id())); + content->SetDrawsContent(true); + + std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar = + SolidColorScrollbarLayerImpl::Create(layer_tree_impl, 3, VERTICAL, 10, 0, + false, true); + scrollbar->SetBounds(scrollbar_size); + scrollbar->test_properties()->position = gfx::PointF(345, 0); + scrollbar->SetScrollElementId(content->element_id()); + scrollbar->SetDrawsContent(true); + scrollbar->test_properties()->opacity = 1.f; + + root->test_properties()->AddChild(std::move(content)); + root->test_properties()->AddChild(std::move(scrollbar)); + + layer_tree_impl->SetRootLayerForTesting(std::move(root)); + layer_tree_impl->BuildPropertyTreesForTesting(); + layer_tree_impl->DidBecomeActive(); + + // Do a scroll over the scrollbar layer as well as the content layer, which + // should result in scrolling the scroll layer on the impl thread as the + // scrollbar should not be hit. + InputHandler::ScrollStatus status = host_impl_->ScrollBegin( + BeginState(gfx::Point(350, 50)).get(), InputHandler::TOUCHSCREEN); + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); +} + } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_perftest.cc b/chromium/cc/trees/layer_tree_host_perftest.cc index 35953305fc8..92fd3570952 100644 --- a/chromium/cc/trees/layer_tree_host_perftest.cc +++ b/chromium/cc/trees/layer_tree_host_perftest.cc @@ -330,8 +330,11 @@ class BrowserCompositorInvalidateLayerTreePerfTest gpu::CommandBufferId::FromUnsafeValue(1), next_fence_sync_); next_sync_token.SetVerifyFlush(); + + constexpr gfx::Size size(64, 64); viz::TransferableResource resource = viz::TransferableResource::MakeGL( - gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, next_sync_token); + gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, next_sync_token, size, + false /* is_overlay_candidate */); next_fence_sync_++; tab_contents_->SetTransferableResource(resource, std::move(callback)); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc index 4819bbe2825..3f0c28b4311 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc @@ -213,10 +213,10 @@ class LayerTreeHostBlendingPixelTest InitializeFromTestCase(resource_type()); // Force shaders only applies to gl renderer. - if (test_type_ != PIXEL_TEST_GL && flags & kForceShaders) + if (renderer_type_ != RENDERER_GL && flags & kForceShaders) return; - SCOPED_TRACE(TestTypeToString(test_type_)); + SCOPED_TRACE(TestTypeToString(renderer_type_)); SCOPED_TRACE(SkBlendMode_Name(current_blend_mode())); scoped_refptr<SolidColorLayer> root = CreateSolidColorLayer( @@ -232,7 +232,7 @@ class LayerTreeHostBlendingPixelTest this->force_antialiasing_ = (flags & kUseAntialiasing); this->force_blending_with_shaders_ = (flags & kForceShaders); - if ((flags & kUseAntialiasing) && (test_type_ == PIXEL_TEST_GL)) { + if ((flags & kUseAntialiasing) && (renderer_type_ == RENDERER_GL)) { // Blending results might differ with one pixel. // Don't allow large errors here, only off by ones. // However, large error still has to be specified to satisfy @@ -262,8 +262,17 @@ class LayerTreeHostBlendingPixelTest SkColor misc_opaque_color_ = 0xffc86464; }; +INSTANTIATE_TEST_SUITE_P( + B, + LayerTreeHostBlendingPixelTest, + ::testing::Combine(::testing::Values(SOFTWARE, ZERO_COPY, SKIA_GL), + ::testing::ValuesIn(kBlendModes))); + +using LayerTreeHostBlendingPixelTestNonSkia = LayerTreeHostBlendingPixelTest; + +// TODO(crbug.com/948128): Enable these tests for Skia. INSTANTIATE_TEST_SUITE_P(B, - LayerTreeHostBlendingPixelTest, + LayerTreeHostBlendingPixelTestNonSkia, ::testing::Combine(::testing::Values(SOFTWARE, ZERO_COPY), ::testing::ValuesIn(kBlendModes))); @@ -295,7 +304,7 @@ TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithRoot) { RunPixelResourceTest(background, expected); } -TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithBackdropFilter) { +TEST_P(LayerTreeHostBlendingPixelTestNonSkia, BlendingWithBackdropFilter) { const int kRootWidth = 2; const int kRootHeight = 2; InitializeFromTestCase(resource_type()); @@ -311,9 +320,8 @@ TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithBackdropFilter) { background->AddChild(green_lane); FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(.75)); - gfx::RRectF backdrop_filter_bounds; green_lane->SetBackdropFilters(filters); - green_lane->SetBackdropFilterBounds(backdrop_filter_bounds); + green_lane->ClearBackdropFilterBounds(); green_lane->SetBlendMode(current_blend_mode()); SkBitmap expected; diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc index 32c04b5e286..165f1d8879c 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc @@ -19,7 +19,7 @@ namespace { class LayerTreeHostFiltersPixelTest : public LayerTreePixelTest, - public ::testing::WithParamInterface<LayerTreePixelTest::PixelTestType> { + public ::testing::WithParamInterface<LayerTreeTest::RendererType> { protected: void InitializeSettings(LayerTreeSettings* settings) override { LayerTreePixelTest::InitializeSettings(settings); @@ -29,17 +29,17 @@ class LayerTreeHostFiltersPixelTest layer_transforms_should_scale_layer_contents_; } - LayerTreePixelTest::PixelTestType GetPixelTestType() { return GetParam(); } + RendererType renderer_type() { return GetParam(); } // Text string for graphics backend of the RendererType. Suitable for // generating separate base line file paths. const char* GetRendererSuffix() { - switch (GetPixelTestType()) { - case LayerTreePixelTest::PIXEL_TEST_GL: + switch (renderer_type()) { + case RENDERER_GL: return "gl"; - case LayerTreePixelTest::PIXEL_TEST_SKIA_GL: + case RENDERER_SKIA_GL: return "skia"; - case LayerTreePixelTest::PIXEL_TEST_SOFTWARE: + case RENDERER_SOFTWARE: return "sw"; } } @@ -54,17 +54,17 @@ class LayerTreeHostFiltersPixelTest // This matrix swaps the red and green channels, and has a slight // translation in the alpha component, so that it affects transparent // pixels. - SkScalar matrix[20] = { + float matrix[20] = { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 20.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 20 / 255.0f, }; FilterOperations filters; SkImageFilter::CropRect cropRect( SkRect::MakeXYWH(-40000, -40000, 80000, 80000)); filters.Append(FilterOperation::CreateReferenceFilter( - sk_make_sp<ColorFilterPaintFilter>( - SkColorFilters::MatrixRowMajor255(matrix), nullptr, &cropRect))); + sk_make_sp<ColorFilterPaintFilter>(SkColorFilters::Matrix(matrix), + nullptr, &cropRect))); filter_layer->SetFilters(filters); background->SetMasksToBounds(masks_to_bounds); background->AddChild(filter_layer); @@ -75,20 +75,33 @@ class LayerTreeHostFiltersPixelTest bool layer_transforms_should_scale_layer_contents_ = true; }; +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostFiltersPixelTest, + ::testing::Values(LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL, + LayerTreeTest::RENDERER_SOFTWARE)); + +using LayerTreeHostFiltersPixelTestNonSkia = LayerTreeHostFiltersPixelTest; + // TODO(crbug.com/948128): Enable these tests for Skia. -INSTANTIATE_TEST_SUITE_P( - , - LayerTreeHostFiltersPixelTest, - ::testing::Values(LayerTreePixelTest::PIXEL_TEST_GL, - LayerTreePixelTest::PIXEL_TEST_SOFTWARE)); +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostFiltersPixelTestNonSkia, + ::testing::Values(LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SOFTWARE)); -class LayerTreeHostFiltersPixelTestGPU : public LayerTreeHostFiltersPixelTest { -}; +using LayerTreeHostFiltersPixelTestGL = LayerTreeHostFiltersPixelTest; // TODO(crbug.com/948128): Enable these tests for Skia. INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostFiltersPixelTestGL, + ::testing::Values(LayerTreeTest::RENDERER_GL)); + +using LayerTreeHostFiltersPixelTestGPU = LayerTreeHostFiltersPixelTest; + +INSTANTIATE_TEST_SUITE_P(, LayerTreeHostFiltersPixelTestGPU, - ::testing::Values(LayerTreePixelTest::PIXEL_TEST_GL)); + ::testing::Values(LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL)); TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurRect) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( @@ -126,7 +139,7 @@ TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurRect) { small_error_allowed)); #endif - RunPixelTest(GetPixelTestType(), background, + RunPixelTest(renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur.png"))); } @@ -163,22 +176,30 @@ TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurRounded) { percentage_pixels_large_error, percentage_pixels_small_error, average_error_allowed_in_bad_pixels, large_error_allowed, small_error_allowed)); +#else + pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(false); #endif RunPixelTest( - GetPixelTestType(), background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur_rounded.png"))); } TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurOutsets) { + if (renderer_type() == RENDERER_SKIA_GL +#if defined(ENABLE_CC_VULKAN_TESTS) + || renderer_type() == RENDERER_SKIA_VK +#endif + ) { + // TODO(973696): Implement bounds clipping in skia_renderer. + return; + } scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer( gfx::Rect(200, 200), SK_ColorWHITE); - // The green border is outside the layer with backdrop blur, but the - // backdrop blur should use pixels from outside its layer borders, up to the - // radius of the blur effect. So the border should be blurred underneath the - // top layer causing the green to bleed under the transparent layer, but not - // in the 1px region between the transparent layer and the green border. + // The green border is outside the layer with backdrop blur, so the backdrop + // blur should not include pixels from outside its layer borders. So the + // interior region of the transparent layer should be perfectly white. scoped_refptr<SolidColorLayer> green_border = CreateSolidColorLayerWithBorder( gfx::Rect(1, 1, 198, 198), SK_ColorWHITE, 10, kCSSGreen); scoped_refptr<SolidColorLayer> blur = CreateSolidColorLayer( @@ -215,11 +236,11 @@ TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurOutsets) { #endif RunPixelTest( - GetPixelTestType(), background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur_outsets.png"))); } -TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurOffAxis) { +TEST_P(LayerTreeHostFiltersPixelTestGL, BackdropFilterBlurOffAxis) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorTRANSPARENT); @@ -258,8 +279,12 @@ TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurOffAxis) { filters.Append(FilterOperation::CreateBlurFilter( 2.f, SkBlurImageFilter::kClamp_TileMode)); blur->SetBackdropFilters(filters); - // TODO(916311): Fix clipping for 3D transformed elements. - blur->SetBackdropFilterBounds(gfx::RRectF()); + // TODO(916311): We should be able to set the bounds like this, but the + // resulting output is clipped incorrectly. + // gfx::RRectF + // backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())),0); + // blur->SetBackdropFilterBounds(backdrop_filter_bounds); + blur->ClearBackdropFilterBounds(); #if defined(OS_WIN) || defined(ARCH_CPU_ARM64) #if defined(OS_WIN) @@ -283,10 +308,38 @@ TEST_P(LayerTreeHostFiltersPixelTestGPU, BackdropFilterBlurOffAxis) { #endif RunPixelTest( - GetPixelTestType(), background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("backdrop_filter_blur_off_axis.png"))); } +TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBoundsWithChildren) { + scoped_refptr<SolidColorLayer> background = + CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE); + scoped_refptr<SolidColorLayer> green = + CreateSolidColorLayer(gfx::Rect(50, 50, 100, 100), kCSSGreen); + scoped_refptr<SolidColorLayer> invert = + CreateSolidColorLayer(gfx::Rect(30, 30, 140, 40), SK_ColorTRANSPARENT); + scoped_refptr<SolidColorLayer> invert_child1 = + CreateSolidColorLayer(gfx::Rect(50, -20, 40, 20), kCSSOrange); + scoped_refptr<SolidColorLayer> invert_child2 = + CreateSolidColorLayer(gfx::Rect(50, 40, 40, 20), kCSSOrange); + background->AddChild(green); + background->AddChild(invert); + invert->AddChild(invert_child1); + invert->AddChild(invert_child2); + + FilterOperations filters; + filters.Append(FilterOperation::CreateInvertFilter(1.f)); + invert->SetBackdropFilters(filters); + gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(invert->bounds())), + 0); + invert->SetBackdropFilterBounds(backdrop_filter_bounds); + + RunPixelTest(renderer_type(), background, + base::FilePath(FILE_PATH_LITERAL( + "backdrop_filter_bounds_with_children.png"))); +} + class LayerTreeHostFiltersScaledPixelTest : public LayerTreeHostFiltersPixelTest { void SetupTree() override { @@ -318,19 +371,18 @@ class LayerTreeHostFiltersScaledPixelTest device_scale_factor_ = device_scale_factor; RunPixelTest( - GetPixelTestType(), background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } float device_scale_factor_; }; -// TODO(crbug.com/948128): Enable these tests for Skia. -INSTANTIATE_TEST_SUITE_P( - , - LayerTreeHostFiltersScaledPixelTest, - ::testing::Values(LayerTreePixelTest::PIXEL_TEST_GL, - LayerTreePixelTest::PIXEL_TEST_SOFTWARE)); +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostFiltersScaledPixelTest, + ::testing::Values(LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL, + LayerTreeTest::RENDERER_SOFTWARE)); TEST_P(LayerTreeHostFiltersScaledPixelTest, StandardDpi) { RunPixelTestType(100, 1.f); @@ -350,7 +402,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, NullFilter) { filters.Append(FilterOperation::CreateReferenceFilter(nullptr)); foreground->SetFilters(filters); - RunPixelTest(GetPixelTestType(), foreground, + RunPixelTest(renderer_type(), foreground, base::FilePath(FILE_PATH_LITERAL("green.png"))); } @@ -369,7 +421,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, CroppedFilter) { filters.Append(FilterOperation::CreateReferenceFilter(offset)); foreground->SetFilters(filters); - RunPixelTest(GetPixelTestType(), foreground, + RunPixelTest(renderer_type(), foreground, base::FilePath(FILE_PATH_LITERAL("white.png"))); } @@ -381,16 +433,16 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterClipped) { CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorRED); background->AddChild(foreground); - SkScalar matrix[20]; + float matrix[20]; memset(matrix, 0, 20 * sizeof(matrix[0])); // This filter does a red-blue swap, so the foreground becomes blue. - matrix[2] = matrix[6] = matrix[10] = matrix[18] = SK_Scalar1; + matrix[2] = matrix[6] = matrix[10] = matrix[18] = 1.0f; // We filter only the bottom 200x100 pixels of the foreground. SkImageFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100)); FilterOperations filters; filters.Append( FilterOperation::CreateReferenceFilter(sk_make_sp<ColorFilterPaintFilter>( - SkColorFilters::MatrixRowMajor255(matrix), nullptr, &crop_rect))); + SkColorFilters::Matrix(matrix), nullptr, &crop_rect))); // Make the foreground layer's render surface be clipped by the background // layer. @@ -405,7 +457,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterClipped) { transform.Translate(0.0, -100.0); foreground->SetTransform(transform); - RunPixelTest(GetPixelTestType(), background, + RunPixelTest(renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("blue_yellow.png"))); } @@ -417,16 +469,16 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterNonZeroOrigin) { CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorRED); background->AddChild(foreground); - SkScalar matrix[20]; + float matrix[20]; memset(matrix, 0, 20 * sizeof(matrix[0])); // This filter does a red-blue swap, so the foreground becomes blue. - matrix[2] = matrix[6] = matrix[10] = matrix[18] = SK_Scalar1; + matrix[2] = matrix[6] = matrix[10] = matrix[18] = 1.0f; // Set up a crop rec to filter the bottom 200x100 pixels of the foreground. SkImageFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100)); FilterOperations filters; filters.Append( FilterOperation::CreateReferenceFilter(sk_make_sp<ColorFilterPaintFilter>( - SkColorFilters::MatrixRowMajor255(matrix), nullptr, &crop_rect))); + SkColorFilters::Matrix(matrix), nullptr, &crop_rect))); // Make the foreground layer's render surface be clipped by the background // layer. @@ -437,7 +489,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterNonZeroOrigin) { // applied only to the top 100 pixels, not the bottom. foreground->SetFiltersOrigin(gfx::PointF(0.0f, -100.0f)); - RunPixelTest(GetPixelTestType(), background, + RunPixelTest(renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("blue_yellow.png"))); } @@ -478,7 +530,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterScaled) { FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0f)); filter->SetBackdropFilters(filters); - filter->SetBackdropFilterBounds(gfx::RRectF()); + filter->ClearBackdropFilterBounds(); #if defined(OS_WIN) || defined(_MIPS_ARCH_LOONGSON) || defined(ARCH_CPU_ARM64) #if defined(OS_WIN) @@ -504,7 +556,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterScaled) { #endif RunPixelTest( - GetPixelTestType(), background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("backdrop_filter_on_scaled_layer_.png")) .InsertBeforeExtensionASCII(GetRendererSuffix())); } @@ -542,12 +594,9 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterRotated) { filters.Append(FilterOperation::CreateBlurFilter( 5.0f, SkBlurImageFilter::kClamp_TileMode)); filter_layer->SetBackdropFilters(filters); - // TODO(916311): Adding filter bounds here should work, but it clips - // the corner of the red box. - // gfx::RectF backdrop_filter_bounds(gfx::SizeF(filter_layer->bounds())); - gfx::RRectF backdrop_filter_bounds; + gfx::RRectF backdrop_filter_bounds( + gfx::RectF(gfx::SizeF(filter_layer->bounds())), 0); filter_layer->SetBackdropFilterBounds(backdrop_filter_bounds); - background->AddChild(filter_layer); // Allow some fuzziness so that this doesn't fail when Skia makes minor @@ -563,7 +612,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterRotated) { average_error_allowed_in_bad_pixels, large_error_allowed, small_error_allowed)); - RunPixelTest(GetPixelTestType(), background, + RunPixelTest(renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("backdrop_filter_rotated_.png")) .InsertBeforeExtensionASCII(GetRendererSuffix())); } @@ -600,24 +649,26 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageRenderSurfaceScaled) { // Software has some huge differences in the AA'd pixels on the different // trybots. See crbug.com/452198. - float percentage_pixels_large_error = 0.686f; - float percentage_pixels_small_error = 0.0f; - float average_error_allowed_in_bad_pixels = 16.f; - int large_error_allowed = 17; - int small_error_allowed = 0; - pixel_comparator_.reset(new FuzzyPixelComparator( - true, // discard_alpha - percentage_pixels_large_error, percentage_pixels_small_error, - average_error_allowed_in_bad_pixels, large_error_allowed, - small_error_allowed)); + if (renderer_type() == LayerTreeTest::RENDERER_SOFTWARE) { + float percentage_pixels_large_error = 0.686f; + float percentage_pixels_small_error = 0.0f; + float average_error_allowed_in_bad_pixels = 16.f; + int large_error_allowed = 17; + int small_error_allowed = 0; + pixel_comparator_.reset(new FuzzyPixelComparator( + true, // discard_alpha + percentage_pixels_large_error, percentage_pixels_small_error, + average_error_allowed_in_bad_pixels, large_error_allowed, + small_error_allowed)); + } RunPixelTest( - GetPixelTestType(), background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("scaled_render_surface_layer_.png")) .InsertBeforeExtensionASCII(GetRendererSuffix())); } -TEST_P(LayerTreeHostFiltersPixelTest, ZoomFilter) { +TEST_P(LayerTreeHostFiltersPixelTestNonSkia, ZoomFilter) { scoped_refptr<SolidColorLayer> root = CreateSolidColorLayer(gfx::Rect(300, 300), SK_ColorWHITE); @@ -681,7 +732,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, ZoomFilter) { small_error_allowed)); #endif - RunPixelTest(GetPixelTestType(), std::move(root), + RunPixelTest(renderer_type(), std::move(root), base::FilePath(FILE_PATH_LITERAL("zoom_filter_.png")) .InsertBeforeExtensionASCII(GetRendererSuffix())); } @@ -722,7 +773,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, RotatedFilter) { small_error_allowed)); #endif - RunPixelTest(GetPixelTestType(), background, + RunPixelTest(renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("rotated_filter_.png")) .InsertBeforeExtensionASCII(GetRendererSuffix())); } @@ -769,7 +820,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, RotatedDropShadowFilter) { #endif RunPixelTest( - GetPixelTestType(), background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("rotated_drop_shadow_filter_.png")) .InsertBeforeExtensionASCII(GetRendererSuffix())); } @@ -808,10 +859,12 @@ TEST_P(LayerTreeHostFiltersPixelTest, TranslatedFilter) { parent->AddChild(child); clip->AddChild(parent); + if (renderer_type() == RENDERER_SOFTWARE) + pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true); + RunPixelTest( - GetPixelTestType(), clip, - base::FilePath(FILE_PATH_LITERAL("translated_blue_green_alpha_.png")) - .InsertBeforeExtensionASCII(GetRendererSuffix())); + renderer_type(), clip, + base::FilePath(FILE_PATH_LITERAL("translated_blue_green_alpha.png"))); } TEST_P(LayerTreeHostFiltersPixelTest, EnlargedTextureWithAlphaThresholdFilter) { @@ -850,7 +903,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, EnlargedTextureWithAlphaThresholdFilter) { set_enlarge_texture_amount(gfx::Size(50, 50)); RunPixelTest( - GetPixelTestType(), background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("enlarged_texture_on_threshold.png"))); } @@ -888,11 +941,12 @@ TEST_P(LayerTreeHostFiltersPixelTest, EnlargedTextureWithCropOffsetFilter) { set_enlarge_texture_amount(gfx::Size(50, 50)); RunPixelTest( - GetPixelTestType(), background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("enlarged_texture_on_crop_offset.png"))); } -TEST_P(LayerTreeHostFiltersPixelTest, BlurFilterWithClip) { +// TODO(crbug.com/948128): Enable this test for SkiaRenderer. +TEST_P(LayerTreeHostFiltersPixelTestNonSkia, BlurFilterWithClip) { scoped_refptr<SolidColorLayer> child1 = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLUE); scoped_refptr<SolidColorLayer> child2 = @@ -937,7 +991,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, BlurFilterWithClip) { small_error_allowed)); #endif - RunPixelTest(GetPixelTestType(), filter_layer, + RunPixelTest(renderer_type(), filter_layer, base::FilePath(FILE_PATH_LITERAL("blur_filter_with_clip_.png")) .InsertBeforeExtensionASCII(GetRendererSuffix())); } @@ -945,14 +999,14 @@ TEST_P(LayerTreeHostFiltersPixelTest, BlurFilterWithClip) { TEST_P(LayerTreeHostFiltersPixelTestGPU, FilterWithGiantCropRect) { scoped_refptr<SolidColorLayer> tree = BuildFilterWithGiantCropRect(true); RunPixelTest( - GetPixelTestType(), tree, + renderer_type(), tree, base::FilePath(FILE_PATH_LITERAL("filter_with_giant_crop_rect.png"))); } TEST_P(LayerTreeHostFiltersPixelTestGPU, FilterWithGiantCropRectNoClip) { scoped_refptr<SolidColorLayer> tree = BuildFilterWithGiantCropRect(false); RunPixelTest( - GetPixelTestType(), tree, + renderer_type(), tree, base::FilePath(FILE_PATH_LITERAL("filter_with_giant_crop_rect.png"))); } @@ -976,13 +1030,13 @@ class BackdropFilterWithDeviceScaleFactorTest filters.Append(FilterOperation::CreateReferenceFilter( sk_make_sp<OffsetPaintFilter>(0, 80, nullptr))); filtered->SetBackdropFilters(filters); - filtered->SetBackdropFilterBounds(gfx::RRectF()); + filtered->ClearBackdropFilterBounds(); root->AddChild(filtered); // This should appear as a grid of 4 100x100 squares which are: // BLACK WHITE // DARK GREEN LIGHT GREEN - RunPixelTest(GetPixelTestType(), std::move(root), expected_result); + RunPixelTest(renderer_type(), std::move(root), expected_result); } private: @@ -995,12 +1049,12 @@ class BackdropFilterWithDeviceScaleFactorTest float device_scale_factor_ = 1; }; -// TODO(crbug.com/948128): Enable these tests for Skia. -INSTANTIATE_TEST_SUITE_P( - , - BackdropFilterWithDeviceScaleFactorTest, - ::testing::Values(LayerTreePixelTest::PIXEL_TEST_GL, - LayerTreePixelTest::PIXEL_TEST_SOFTWARE)); +// TODO(973699): This test is broken in software_renderer. Re-enable this test +// when fixed. +INSTANTIATE_TEST_SUITE_P(, + BackdropFilterWithDeviceScaleFactorTest, + ::testing::Values(LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL)); TEST_P(BackdropFilterWithDeviceScaleFactorTest, StandardDpi) { RunPixelTestType( diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc index dc63c711f27..9e125057e0d 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc @@ -109,7 +109,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffect) { EffectNode isolation_effect; isolation_effect.clip_id = 1; isolation_effect.stable_id = 2; - isolation_effect.has_render_surface = true; + isolation_effect.render_surface_reason = RenderSurfaceReason::kTest; isolation_effect.transform_id = 1; property_trees.effect_tree.Insert(isolation_effect, 1); @@ -167,7 +167,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, SolidColorLayerEmptyMaskWithEffect) { EffectNode isolation_effect; isolation_effect.clip_id = 1; isolation_effect.stable_id = 2; - isolation_effect.has_render_surface = true; + isolation_effect.render_surface_reason = RenderSurfaceReason::kTest; isolation_effect.transform_id = 1; property_trees.effect_tree.Insert(isolation_effect, 1); @@ -250,7 +250,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, SolidColorEmptyMaskWithEffect) { EffectNode isolation_effect; isolation_effect.clip_id = 1; isolation_effect.stable_id = 2; - isolation_effect.has_render_surface = true; + isolation_effect.render_surface_reason = RenderSurfaceReason::kTest; isolation_effect.transform_id = 1; property_trees.effect_tree.Insert(isolation_effect, 1); @@ -313,7 +313,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, EffectNode isolation_effect; isolation_effect.clip_id = 1; isolation_effect.stable_id = 2; - isolation_effect.has_render_surface = true; + isolation_effect.render_surface_reason = RenderSurfaceReason::kTest; isolation_effect.transform_id = 1; property_trees.effect_tree.Insert(isolation_effect, 1); @@ -322,7 +322,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, mask_effect.stable_id = 3; mask_effect.transform_id = 1; mask_effect.blend_mode = SkBlendMode::kDstIn; - mask_effect.has_render_surface = true; + mask_effect.render_surface_reason = RenderSurfaceReason::kTest; property_trees.effect_tree.Insert(mask_effect, 2); scoped_refptr<SolidColorLayer> background = @@ -378,7 +378,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffectNoContentToMask) { EffectNode isolation_effect; isolation_effect.clip_id = 1; isolation_effect.stable_id = 2; - isolation_effect.has_render_surface = true; + isolation_effect.render_surface_reason = RenderSurfaceReason::kTest; isolation_effect.transform_id = 1; property_trees.effect_tree.Insert(isolation_effect, 1); @@ -418,7 +418,18 @@ TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffectNoContentToMask) { &property_trees); } -TEST_P(LayerTreeHostLayerListPixelTest, ScaledMaskWithEffect) { +using LayerTreeHostLayerListPixelTestNonSkia = LayerTreeHostLayerListPixelTest; + +// TODO(crbug.com/948128): Enable this test for Skia. +INSTANTIATE_TEST_SUITE_P( + PixelResourceTest, + LayerTreeHostLayerListPixelTestNonSkia, + ::testing::Combine( + ::testing::Values(SOFTWARE, GPU, ONE_COPY, ZERO_COPY), + ::testing::Values(Layer::LayerMaskType::SINGLE_TEXTURE_MASK, + Layer::LayerMaskType::MULTI_TEXTURE_MASK))); + +TEST_P(LayerTreeHostLayerListPixelTestNonSkia, ScaledMaskWithEffect) { PropertyTrees property_trees; scoped_refptr<Layer> root_layer; InitializeForLayerListMode(&root_layer, &property_trees); @@ -426,7 +437,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, ScaledMaskWithEffect) { EffectNode isolation_effect; isolation_effect.clip_id = 1; isolation_effect.stable_id = 2; - isolation_effect.has_render_surface = true; + isolation_effect.render_surface_reason = RenderSurfaceReason::kTest; isolation_effect.transform_id = 1; property_trees.effect_tree.Insert(isolation_effect, 1); @@ -502,7 +513,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffectDifferentSize) { EffectNode isolation_effect; isolation_effect.clip_id = 1; isolation_effect.stable_id = 2; - isolation_effect.has_render_surface = true; + isolation_effect.render_surface_reason = RenderSurfaceReason::kTest; isolation_effect.transform_id = 1; property_trees.effect_tree.Insert(isolation_effect, 1); @@ -562,7 +573,7 @@ TEST_P(LayerTreeHostLayerListPixelTest, ImageMaskWithEffect) { EffectNode isolation_effect; isolation_effect.clip_id = 1; isolation_effect.stable_id = 2; - isolation_effect.has_render_surface = true; + isolation_effect.render_surface_reason = RenderSurfaceReason::kTest; isolation_effect.transform_id = 1; property_trees.effect_tree.Insert(isolation_effect, 1); @@ -806,9 +817,16 @@ class CircleContentLayerClient : public ContentLayerClient { using LayerTreeHostMasksForBackdropFiltersPixelTest = ParameterizedPixelResourceTest; +INSTANTIATE_PIXEL_RESOURCE_TEST_SUITE_P( + LayerTreeHostMasksForBackdropFiltersPixelTest); + +using LayerTreeHostMasksForBackdropFiltersPixelTestNonSkia = + ParameterizedPixelResourceTest; + +// TODO(crbug.com/948128): Enable these tests for Skia. INSTANTIATE_TEST_SUITE_P( PixelResourceTest, - LayerTreeHostMasksForBackdropFiltersPixelTest, + LayerTreeHostMasksForBackdropFiltersPixelTestNonSkia, ::testing::Combine( ::testing::Values(SOFTWARE, GPU, ONE_COPY, ZERO_COPY), ::testing::Values(Layer::LayerMaskType::SINGLE_TEXTURE_MASK, @@ -832,9 +850,8 @@ TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest, FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0)); - gfx::RRectF backdrop_filter_bounds; blur->SetBackdropFilters(filters); - blur->SetBackdropFilterBounds(backdrop_filter_bounds); + blur->ClearBackdropFilterBounds(); gfx::Size mask_bounds(100, 100); CircleContentLayerClient mask_client(mask_bounds); @@ -845,21 +862,8 @@ TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest, blur->SetMaskLayer(mask.get()); CHECK_EQ(Layer::LayerMaskType::SINGLE_TEXTURE_MASK, mask->mask_type()); - float percentage_pixels_large_error = 2.5f; // 2.5%, ~250px / (100*100) - float percentage_pixels_small_error = 0.0f; - float average_error_allowed_in_bad_pixels = 100.0f; - int large_error_allowed = 256; - int small_error_allowed = 0; - pixel_comparator_ = std::make_unique<FuzzyPixelComparator>( - true, // discard_alpha - percentage_pixels_large_error, - percentage_pixels_small_error, - average_error_allowed_in_bad_pixels, - large_error_allowed, - small_error_allowed); - base::FilePath image_name = - (test_case_ == GPU) + (test_case_ == GPU || test_case_ == SKIA_GL) ? base::FilePath(FILE_PATH_LITERAL("mask_of_backdrop_filter_gpu.png")) : base::FilePath(FILE_PATH_LITERAL("mask_of_backdrop_filter.png")); RunPixelResourceTest(background, image_name); @@ -940,16 +944,24 @@ class StaticPictureLayer : private ContentLayerClient, public PictureLayer { scoped_refptr<DisplayItemList> display_list_; }; +constexpr uint32_t kUseAntialiasing = 1 << 0; +constexpr uint32_t kForceShaders = 1 << 1; + +struct MaskTestConfig { + PixelResourceTestCase test_case; + uint32_t flags; +}; + class LayerTreeHostMaskAsBlendingPixelTest : public LayerTreeHostPixelResourceTest, - public ::testing::WithParamInterface<int> { + public ::testing::WithParamInterface<MaskTestConfig> { public: LayerTreeHostMaskAsBlendingPixelTest() : LayerTreeHostPixelResourceTest( - GetParam() ? ZERO_COPY : SOFTWARE, + GetParam().test_case, Layer::LayerMaskType::SINGLE_TEXTURE_MASK), - use_antialiasing_(GetParam() == 2 || GetParam() == 4), - force_shaders_(GetParam() == 3 || GetParam() == 4) { + use_antialiasing_(GetParam().flags & kUseAntialiasing), + force_shaders_(GetParam().flags & kForceShaders) { float percentage_pixels_small_error = 0.f; float percentage_pixels_error = 0.f; float average_error_allowed_in_bad_pixels = 0.f; @@ -961,7 +973,7 @@ class LayerTreeHostMaskAsBlendingPixelTest average_error_allowed_in_bad_pixels = 3.5f; large_error_allowed = 15; small_error_allowed = 1; - } else if (test_type_ != PIXEL_TEST_SOFTWARE) { + } else if (test_case_ != SOFTWARE) { percentage_pixels_small_error = 0.9f; percentage_pixels_error = 6.5f; average_error_allowed_in_bad_pixels = 3.5f; @@ -1068,15 +1080,18 @@ class LayerTreeHostMaskAsBlendingPixelTest bool force_shaders_; }; +// TODO(crbug.com/948128): Enable these tests for Skia. +MaskTestConfig const kTestConfigs[] = { + MaskTestConfig{SOFTWARE, 0}, + MaskTestConfig{ZERO_COPY, 0}, + MaskTestConfig{ZERO_COPY, kUseAntialiasing}, + MaskTestConfig{ZERO_COPY, kForceShaders}, + MaskTestConfig{ZERO_COPY, kUseAntialiasing | kForceShaders}, +}; + INSTANTIATE_TEST_SUITE_P(All, LayerTreeHostMaskAsBlendingPixelTest, - ::testing::Range(0, 5)); -// Instantiate 5 test modes of the following: -// 0: SOFTWARE (golden sample) -// 1: GL -// 2: GL + AA -// 3: GL + Forced Shaders -// 4: GL + Forced Shaders + AA + ::testing::ValuesIn(kTestConfigs)); TEST_P(LayerTreeHostMaskAsBlendingPixelTest, PixelAlignedNoop) { // This test verifies the degenerate case of a no-op mask doesn't affect @@ -1214,7 +1229,7 @@ TEST_P(LayerTreeHostMaskAsBlendingPixelTest, RotatedClippedCircle) { mask_isolation->AddChild(mask_layer); base::FilePath image_name = - (test_type_ == PIXEL_TEST_SOFTWARE) + (test_case_ == SOFTWARE) ? base::FilePath( FILE_PATH_LITERAL("mask_as_blending_rotated_circle.png")) : base::FilePath( @@ -1261,7 +1276,7 @@ TEST_P(LayerTreeHostMaskAsBlendingPixelTest, RotatedClippedCircleUnderflow) { mask_isolation->AddChild(mask_layer); base::FilePath image_name = - (test_type_ == PIXEL_TEST_SOFTWARE) + (test_case_ == SOFTWARE) ? base::FilePath(FILE_PATH_LITERAL( "mask_as_blending_rotated_circle_underflow.png")) : base::FilePath(FILE_PATH_LITERAL( @@ -1269,7 +1284,7 @@ TEST_P(LayerTreeHostMaskAsBlendingPixelTest, RotatedClippedCircleUnderflow) { RunPixelResourceTest(root, image_name); } -TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest, +TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTestNonSkia, MaskOfLayerWithBackdropFilterAndBlend) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(128, 128), SK_ColorWHITE); @@ -1294,8 +1309,7 @@ TEST_P(LayerTreeHostMasksForBackdropFiltersPixelTest, FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0)); picture_horizontal->SetBackdropFilters(filters); - gfx::RRectF backdrop_filter_bounds; - picture_horizontal->SetBackdropFilterBounds(backdrop_filter_bounds); + picture_horizontal->ClearBackdropFilterBounds(); background->AddChild(picture_vertical); background->AddChild(picture_horizontal); diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc index 31051051a9d..41660e1fb34 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc @@ -24,16 +24,15 @@ namespace { // Can't templatize a class on its own members, so ReadbackType and // ReadbackTestConfig are declared here, before LayerTreeHostReadbackPixelTest. enum ReadbackType { - READBACK_INVALID, - READBACK_DEFAULT, + READBACK_TEXTURE, READBACK_BITMAP, }; struct ReadbackTestConfig { - ReadbackTestConfig(LayerTreePixelTest::PixelTestType pixel_test_type_, + ReadbackTestConfig(LayerTreeTest::RendererType renderer_type_, ReadbackType readback_type_) - : pixel_test_type(pixel_test_type_), readback_type(readback_type_) {} - LayerTreePixelTest::PixelTestType pixel_test_type; + : renderer_type(renderer_type_), readback_type(readback_type_) {} + LayerTreeTest::RendererType renderer_type; ReadbackType readback_type; }; @@ -42,51 +41,28 @@ class LayerTreeHostReadbackPixelTest public testing::WithParamInterface<ReadbackTestConfig> { protected: LayerTreeHostReadbackPixelTest() - : readback_type_(READBACK_INVALID), - insert_copy_request_after_frame_count_(0) {} - - void RunReadbackTest(PixelTestType test_type, - ReadbackType readback_type, - scoped_refptr<Layer> content_root, - base::FilePath file_name) { - readback_type_ = readback_type; - RunPixelTest(test_type, content_root, file_name); - } + : insert_copy_request_after_frame_count_(0) {} - void RunReadbackTestWithReadbackTarget(PixelTestType type, - ReadbackType readback_type, - scoped_refptr<Layer> content_root, - Layer* target, - base::FilePath file_name) { - readback_type_ = readback_type; - RunPixelTestWithReadbackTarget(type, content_root, target, file_name); - } + RendererType renderer_type() const { return GetParam().renderer_type; } + + ReadbackType readback_type() const { return GetParam().readback_type; } std::unique_ptr<viz::CopyOutputRequest> CreateCopyOutputRequest() override { std::unique_ptr<viz::CopyOutputRequest> request; - if (readback_type_ == READBACK_BITMAP) { + if (readback_type() == READBACK_BITMAP) { request = std::make_unique<viz::CopyOutputRequest>( viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, base::BindOnce( &LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap, base::Unretained(this))); } else { - DCHECK_EQ(readback_type_, READBACK_DEFAULT); - if (test_type_ == PIXEL_TEST_SOFTWARE) { - request = std::make_unique<viz::CopyOutputRequest>( - viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP, - base::BindOnce( - &LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap, - base::Unretained(this))); - } else { - DCHECK_EQ(test_type_, PIXEL_TEST_GL); - request = std::make_unique<viz::CopyOutputRequest>( - viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE, - base::BindOnce( - &LayerTreeHostReadbackPixelTest::ReadbackResultAsTexture, - base::Unretained(this))); - } + DCHECK_NE(renderer_type_, RENDERER_SOFTWARE); + request = std::make_unique<viz::CopyOutputRequest>( + viz::CopyOutputRequest::ResultFormat::RGBA_TEXTURE, + base::BindOnce( + &LayerTreeHostReadbackPixelTest::ReadbackResultAsTexture, + base::Unretained(this))); } if (!copy_subrect_.IsEmpty()) @@ -139,7 +115,6 @@ class LayerTreeHostReadbackPixelTest result->rect(), bitmap)); } - ReadbackType readback_type_; gfx::Rect copy_subrect_; gfx::ColorSpace output_color_space_ = gfx::ColorSpace::CreateSRGB(); int insert_copy_request_after_frame_count_; @@ -153,8 +128,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackRootLayer) { CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN); background->AddChild(green); - RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type, - background, base::FilePath(FILE_PATH_LITERAL("green.png"))); + RunPixelTest(renderer_type(), background, + base::FilePath(FILE_PATH_LITERAL("green.png"))); } TEST_P(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild) { @@ -169,9 +144,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild) { CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE); green->AddChild(blue); - RunReadbackTest( - GetParam().pixel_test_type, GetParam().readback_type, background, - base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png"))); + RunPixelTest(renderer_type(), background, + base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png"))); } TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer) { @@ -182,9 +156,9 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer) { CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN); background->AddChild(green); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - green.get(), base::FilePath(FILE_PATH_LITERAL("green.png"))); + RunPixelTestWithReadbackTarget( + renderer_type(), background, green.get(), + base::FilePath(FILE_PATH_LITERAL("green.png"))); } TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer) { @@ -195,9 +169,9 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer) { CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN); background->AddChild(green); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - green.get(), base::FilePath(FILE_PATH_LITERAL("green_small.png"))); + RunPixelTestWithReadbackTarget( + renderer_type(), background, green.get(), + base::FilePath(FILE_PATH_LITERAL("green_small.png"))); } TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild) { @@ -212,9 +186,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild) { CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE); green->AddChild(blue); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - green.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, green.get(), base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } @@ -235,9 +208,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubtreeSurroundsTargetLayer) { target->AddChild(blue); copy_subrect_ = gfx::Rect(0, 0, 100, 100); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - target.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, target.get(), base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } @@ -259,9 +231,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, target->AddChild(blue); copy_subrect_ = gfx::Rect(50, 50, 100, 100); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - target.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, target.get(), base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } @@ -278,9 +249,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree) { CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE); hidden_target->AddChild(blue); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - hidden_target.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, hidden_target.get(), base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png"))); } @@ -300,8 +270,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, hidden_target->RequestCopyOfOutput( viz::CopyOutputRequest::CreateStubForTesting()); - RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type, - background, base::FilePath(FILE_PATH_LITERAL("black.png"))); + RunPixelTest(renderer_type(), background, + base::FilePath(FILE_PATH_LITERAL("black.png"))); } TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubrect) { @@ -319,8 +289,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubrect) { // Grab the middle of the root layer. copy_subrect_ = gfx::Rect(50, 50, 100, 100); - RunReadbackTest( - GetParam().pixel_test_type, GetParam().readback_type, background, + RunPixelTest( + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } @@ -339,9 +309,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect) { // Grab the middle of the green layer. copy_subrect_ = gfx::Rect(25, 25, 100, 100); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - green.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, green.get(), base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } @@ -362,9 +331,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage) { target->AddChild(blue); insert_copy_request_after_frame_count_ = 1; - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - target.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, target.get(), base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } @@ -386,9 +354,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackOutsideViewportWhenNoDamage) { target->AddChild(blue); insert_copy_request_after_frame_count_ = 1; - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - target.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, target.get(), base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } @@ -407,9 +374,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerOutsideViewport) { CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE); green->AddChild(blue); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - green.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, green.get(), base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png"))); } @@ -426,9 +392,8 @@ TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootOrFirstLayer) { blue->RequestCopyOfOutput(viz::CopyOutputRequest::CreateStubForTesting()); background->AddChild(blue); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - background.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, background.get(), base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png"))); } @@ -445,21 +410,20 @@ TEST_P(LayerTreeHostReadbackPixelTest, MultipleReadbacksOnLayer) { background->RequestCopyOfOutput( viz::CopyOutputRequest::CreateStubForTesting()); - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - background.get(), base::FilePath(FILE_PATH_LITERAL("green.png"))); + RunPixelTestWithReadbackTarget( + renderer_type(), background, background.get(), + base::FilePath(FILE_PATH_LITERAL("green.png"))); } INSTANTIATE_TEST_SUITE_P( - LayerTreeHostReadbackPixelTests, + , LayerTreeHostReadbackPixelTest, ::testing::Values( - ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_SOFTWARE, - READBACK_DEFAULT), - ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL, - READBACK_DEFAULT), - ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL, - READBACK_BITMAP))); + ReadbackTestConfig(LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP), + ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_TEXTURE), + ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_BITMAP), + ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP), + ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE))); class LayerTreeHostReadbackDeviceScalePixelTest : public LayerTreeHostReadbackPixelTest { @@ -513,8 +477,8 @@ TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackSubrect) { // Grab the middle of the root layer. copy_subrect_ = gfx::Rect(25, 25, 50, 50); device_scale_factor_ = 2.f; - RunReadbackTest( - GetParam().pixel_test_type, GetParam().readback_type, background, + RunPixelTest( + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } @@ -541,22 +505,20 @@ TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackNonRootLayerSubrect) { // Grab the green layer's content with blue in the bottom right. copy_subrect_ = gfx::Rect(25, 25, 50, 50); device_scale_factor_ = 2.f; - RunReadbackTestWithReadbackTarget( - GetParam().pixel_test_type, GetParam().readback_type, background, - green.get(), + RunPixelTestWithReadbackTarget( + renderer_type(), background, green.get(), base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } INSTANTIATE_TEST_SUITE_P( - LayerTreeHostReadbackDeviceScalePixelTests, + , LayerTreeHostReadbackDeviceScalePixelTest, ::testing::Values( - ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_SOFTWARE, - READBACK_DEFAULT), - ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL, - READBACK_DEFAULT), - ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL, - READBACK_BITMAP))); + ReadbackTestConfig(LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP), + ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_TEXTURE), + ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_BITMAP), + ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP), + ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE))); class LayerTreeHostReadbackColorSpacePixelTest : public LayerTreeHostReadbackPixelTest { @@ -589,24 +551,20 @@ TEST_P(LayerTreeHostReadbackColorSpacePixelTest, Readback) { background->SetBounds(gfx::Size(200, 200)); background->SetIsDrawable(true); - if (GetParam().pixel_test_type == PIXEL_TEST_SOFTWARE) { - // Software compositing doesn't support color conversion, so the result will - // come out in sRGB, regardless of the display's color properties. - RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type, - background, base::FilePath(FILE_PATH_LITERAL("green.png"))); - } else { - // GL compositing will convert the sRGB green into P3. - RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type, - background, - base::FilePath(FILE_PATH_LITERAL("srgb_green_in_p3.png"))); - } + // The sRGB green should be converted into P3. + RunPixelTest(renderer_type(), background, + base::FilePath(FILE_PATH_LITERAL("srgb_green_in_p3.png"))); } -INSTANTIATE_TEST_SUITE_P(LayerTreeHostReadbackColorSpacePixelTests, - LayerTreeHostReadbackColorSpacePixelTest, - ::testing::Values(ReadbackTestConfig( - LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL, - READBACK_BITMAP))); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostReadbackColorSpacePixelTest, + ::testing::Values( + ReadbackTestConfig(LayerTreeTest::RENDERER_SOFTWARE, READBACK_BITMAP), + ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_TEXTURE), + ReadbackTestConfig(LayerTreeTest::RENDERER_GL, READBACK_BITMAP), + ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_BITMAP), + ReadbackTestConfig(LayerTreeTest::RENDERER_SKIA_GL, READBACK_TEXTURE))); } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc index 1c94cf36b3e..8955987ba23 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc @@ -12,6 +12,7 @@ #include "cc/paint/paint_canvas.h" #include "cc/paint/paint_flags.h" #include "cc/test/layer_tree_pixel_test.h" +#include "cc/test/pixel_comparator.h" #include "cc/test/test_in_process_context_provider.h" #include "cc/trees/layer_tree_impl.h" #include "gpu/command_buffer/client/gles2_interface.h" @@ -21,10 +22,14 @@ namespace cc { namespace { -class LayerTreeHostScrollbarsPixelTest : public LayerTreePixelTest { +class LayerTreeHostScrollbarsPixelTest + : public LayerTreePixelTest, + public ::testing::WithParamInterface<LayerTreeTest::RendererType> { protected: LayerTreeHostScrollbarsPixelTest() = default; + RendererType renderer_type() { return GetParam(); } + void InitializeSettings(LayerTreeSettings* settings) override { settings->layer_transforms_should_scale_layer_contents = true; } @@ -84,7 +89,12 @@ class PaintedScrollbar : public Scrollbar { gfx::Rect rect_; }; -TEST_F(LayerTreeHostScrollbarsPixelTest, NoScale) { +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostScrollbarsPixelTest, + ::testing::Values(LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL)); + +TEST_P(LayerTreeHostScrollbarsPixelTest, NoScale) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE); @@ -95,11 +105,11 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, NoScale) { layer->SetBounds(gfx::Size(200, 200)); background->AddChild(layer); - RunPixelTest(PIXEL_TEST_GL, background, + RunPixelTest(renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("spiral.png"))); } -TEST_F(LayerTreeHostScrollbarsPixelTest, DeviceScaleFactor) { +TEST_P(LayerTreeHostScrollbarsPixelTest, DeviceScaleFactor) { // With a device scale of 2, the scrollbar should still be rendered // pixel-perfect, not show scaling artifacts device_scale_factor_ = 2.f; @@ -114,11 +124,11 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, DeviceScaleFactor) { layer->SetBounds(gfx::Size(100, 100)); background->AddChild(layer); - RunPixelTest(PIXEL_TEST_GL, background, + RunPixelTest(renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("spiral_double_scale.png"))); } -TEST_F(LayerTreeHostScrollbarsPixelTest, TransformScale) { +TEST_P(LayerTreeHostScrollbarsPixelTest, TransformScale) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE); @@ -135,7 +145,7 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, TransformScale) { scale_transform.Scale(2.0, 2.0); layer->SetTransform(scale_transform); - RunPixelTest(PIXEL_TEST_GL, background, + RunPixelTest(renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("spiral_double_scale.png"))); } @@ -145,7 +155,7 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, TransformScale) { #else #define MAYBE_HugeTransformScale HugeTransformScale #endif -TEST_F(LayerTreeHostScrollbarsPixelTest, MAYBE_HugeTransformScale) { +TEST_P(LayerTreeHostScrollbarsPixelTest, MAYBE_HugeTransformScale) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE); @@ -179,7 +189,10 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, MAYBE_HugeTransformScale) { scale_transform.Scale(scale, scale); layer->SetTransform(scale_transform); - RunPixelTest(PIXEL_TEST_GL, background, + if (renderer_type() == RENDERER_SKIA_GL) + pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true); + + RunPixelTest(renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("spiral_64_scale.png"))); } @@ -241,9 +254,14 @@ class PaintedOverlayScrollbar : public PaintedScrollbar { } }; +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostOverlayScrollbarsPixelTest, + ::testing::Values(LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL)); + // Simulate increasing the thickness of a painted overlay scrollbar. Ensure that // the scrollbar border remains crisp. -TEST_F(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledUp) { +TEST_P(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledUp) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE); @@ -261,13 +279,13 @@ TEST_F(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledUp) { layer->SetPosition(gfx::PointF(185, 10)); RunPixelTest( - PIXEL_TEST_GL, background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("overlay_scrollbar_scaled_up.png"))); } // Simulate decreasing the thickness of a painted overlay scrollbar. Ensure that // the scrollbar border remains crisp. -TEST_F(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledDown) { +TEST_P(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledDown) { scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE); @@ -285,7 +303,7 @@ TEST_F(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledDown) { layer->SetPosition(gfx::PointF(185, 10)); RunPixelTest( - PIXEL_TEST_GL, background, + renderer_type(), background, base::FilePath(FILE_PATH_LITERAL("overlay_scrollbar_scaled_down.png"))); } diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc index 8bfca2af17e..fac28b34708 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_synchronous.cc @@ -16,65 +16,57 @@ namespace cc { namespace { -class LayerTreeHostSynchronousPixelTest : public LayerTreePixelTest { - public: +class LayerTreeHostSynchronousPixelTest + : public LayerTreePixelTest, + public ::testing::WithParamInterface<LayerTreeTest::RendererType> { + protected: void InitializeSettings(LayerTreeSettings* settings) override { LayerTreePixelTest::InitializeSettings(settings); settings->single_thread_proxy_scheduler = false; - settings->use_zero_copy = true; + settings->gpu_rasterization_forced = gpu_rasterization_forced_; + settings->use_zero_copy = use_zero_copy_; } + LayerTreeTest::RendererType renderer_type() { return GetParam(); } + void BeginTest() override { LayerTreePixelTest::BeginTest(); PostCompositeImmediatelyToMainThread(); } -}; - -TEST_F(LayerTreeHostSynchronousPixelTest, OneContentLayer) { - gfx::Size bounds(200, 200); - FakeContentLayerClient client; - client.set_bounds(bounds); - PaintFlags green_flags; - green_flags.setColor(SkColorSetARGB(255, 0, 255, 0)); - client.add_draw_rect(gfx::Rect(bounds), green_flags); - scoped_refptr<PictureLayer> root = PictureLayer::Create(&client); - root->SetBounds(bounds); - root->SetIsDrawable(true); + void DoContentLayerTest() { + gfx::Size bounds(200, 200); - RunSingleThreadedPixelTest( - PIXEL_TEST_GL, root, base::FilePath(FILE_PATH_LITERAL("green.png"))); -} + FakeContentLayerClient client; + client.set_bounds(bounds); + PaintFlags green_flags; + green_flags.setColor(SkColorSetARGB(255, 0, 255, 0)); + client.add_draw_rect(gfx::Rect(bounds), green_flags); + scoped_refptr<PictureLayer> root = PictureLayer::Create(&client); + root->SetBounds(bounds); + root->SetIsDrawable(true); -class LayerTreeHostSynchronousGPUPixelTest : public LayerTreePixelTest { - public: - void InitializeSettings(LayerTreeSettings* settings) override { - LayerTreePixelTest::InitializeSettings(settings); - settings->single_thread_proxy_scheduler = false; - settings->gpu_rasterization_forced = true; + RunSingleThreadedPixelTest(renderer_type(), root, + base::FilePath(FILE_PATH_LITERAL("green.png"))); } - void BeginTest() override { - LayerTreePixelTest::BeginTest(); - PostCompositeImmediatelyToMainThread(); - } + bool gpu_rasterization_forced_ = false; + bool use_zero_copy_ = false; }; -TEST_F(LayerTreeHostSynchronousGPUPixelTest, OneContentLayer) { - gfx::Size bounds(200, 200); +INSTANTIATE_TEST_SUITE_P(, + LayerTreeHostSynchronousPixelTest, + ::testing::Values(LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL)); - FakeContentLayerClient client; - client.set_bounds(bounds); - PaintFlags green_flags; - green_flags.setColor(SkColorSetARGB(255, 0, 255, 0)); - client.add_draw_rect(gfx::Rect(bounds), green_flags); - scoped_refptr<PictureLayer> root = PictureLayer::Create(&client); - root->SetBounds(bounds); - client.set_bounds(bounds); - root->SetIsDrawable(true); +TEST_P(LayerTreeHostSynchronousPixelTest, OneContentLayerZeroCopy) { + use_zero_copy_ = true; + DoContentLayerTest(); +} - RunSingleThreadedPixelTest(PIXEL_TEST_GL, root, - base::FilePath(FILE_PATH_LITERAL("green.png"))); +TEST_P(LayerTreeHostSynchronousPixelTest, OneContentLayerGpuRasterization) { + gpu_rasterization_forced_ = true; + DoContentLayerTest(); } } // namespace diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc index 8ed832e7844..ad22f279d6a 100644 --- a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc +++ b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc @@ -21,56 +21,44 @@ namespace cc { namespace { enum RasterMode { - PARTIAL_ONE_COPY, - FULL_ONE_COPY, - PARTIAL_GPU, - FULL_GPU, - PARTIAL_GPU_LOW_BIT_DEPTH, - FULL_GPU_LOW_BIT_DEPTH, - PARTIAL_BITMAP, - FULL_BITMAP, + BITMAP, + ONE_COPY, + GPU, + GPU_LOW_BIT_DEPTH, }; -class LayerTreeHostTilesPixelTest : public LayerTreePixelTest { +struct TilesTestConfig { + LayerTreeTest::RendererType renderer_type; + RasterMode raster_mode; +}; + +class LayerTreeHostTilesPixelTest + : public LayerTreePixelTest, + public ::testing::WithParamInterface<TilesTestConfig> { protected: + RendererType renderer_type() const { return GetParam().renderer_type; } + + RasterMode raster_mode() const { return GetParam().raster_mode; } + void InitializeSettings(LayerTreeSettings* settings) override { LayerTreePixelTest::InitializeSettings(settings); - switch (raster_mode_) { - case PARTIAL_ONE_COPY: + switch (raster_mode()) { + case ONE_COPY: settings->use_zero_copy = false; - settings->use_partial_raster = true; break; - case FULL_ONE_COPY: - settings->use_zero_copy = false; - settings->use_partial_raster = false; - break; - case PARTIAL_BITMAP: - settings->use_partial_raster = true; - break; - case FULL_BITMAP: - settings->use_partial_raster = false; - break; - case PARTIAL_GPU: + case GPU: settings->gpu_rasterization_forced = true; - settings->use_partial_raster = true; break; - case FULL_GPU: + case GPU_LOW_BIT_DEPTH: settings->gpu_rasterization_forced = true; - settings->use_partial_raster = false; - break; - case PARTIAL_GPU_LOW_BIT_DEPTH: - settings->gpu_rasterization_forced = true; - settings->use_partial_raster = true; settings->use_rgba_4444 = true; settings->unpremultiply_and_dither_low_bit_depth_tiles = true; break; - case FULL_GPU_LOW_BIT_DEPTH: - settings->gpu_rasterization_forced = true; - settings->use_partial_raster = false; - settings->use_rgba_4444 = true; - settings->unpremultiply_and_dither_low_bit_depth_tiles = true; + default: break; } + + settings->use_partial_raster = use_partial_raster_; } void BeginTest() override { @@ -84,36 +72,9 @@ class LayerTreeHostTilesPixelTest : public LayerTreePixelTest { target->RequestCopyOfOutput(CreateCopyOutputRequest()); } - void RunRasterPixelTest(bool threaded, - RasterMode mode, - scoped_refptr<Layer> content_root, - base::FilePath file_name) { - raster_mode_ = mode; - - PixelTestType test_type = PIXEL_TEST_SOFTWARE; - switch (mode) { - case PARTIAL_ONE_COPY: - case FULL_ONE_COPY: - case PARTIAL_GPU: - case FULL_GPU: - case PARTIAL_GPU_LOW_BIT_DEPTH: - case FULL_GPU_LOW_BIT_DEPTH: - test_type = PIXEL_TEST_GL; - break; - case PARTIAL_BITMAP: - case FULL_BITMAP: - test_type = PIXEL_TEST_SOFTWARE; - } - - if (threaded) - RunPixelTest(test_type, content_root, file_name); - else - RunSingleThreadedPixelTest(test_type, content_root, file_name); - } - base::FilePath ref_file_; std::unique_ptr<SkBitmap> result_bitmap_; - RasterMode raster_mode_; + bool use_partial_raster_ = false; }; class BlueYellowClient : public ContentLayerClient { @@ -211,81 +172,78 @@ class LayerTreeHostTilesTestPartialInvalidation scoped_refptr<PictureLayer> picture_layer_; }; -TEST_F(LayerTreeHostTilesTestPartialInvalidation, - PartialRaster_SingleThread_OneCopy) { - RunRasterPixelTest( - false, PARTIAL_ONE_COPY, picture_layer_, +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostTilesTestPartialInvalidation, + ::testing::Values(TilesTestConfig{LayerTreeTest::RENDERER_SOFTWARE, BITMAP}, + TilesTestConfig{LayerTreeTest::RENDERER_GL, ONE_COPY}, + TilesTestConfig{LayerTreeTest::RENDERER_GL, GPU}, + TilesTestConfig{LayerTreeTest::RENDERER_SKIA_GL, + ONE_COPY}, + TilesTestConfig{LayerTreeTest::RENDERER_SKIA_GL, GPU})); + +TEST_P(LayerTreeHostTilesTestPartialInvalidation, PartialRaster) { + use_partial_raster_ = true; + RunSingleThreadedPixelTest( + renderer_type(), picture_layer_, base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png"))); } -TEST_F(LayerTreeHostTilesTestPartialInvalidation, - FullRaster_SingleThread_OneCopy) { - RunRasterPixelTest( - false, FULL_ONE_COPY, picture_layer_, +TEST_P(LayerTreeHostTilesTestPartialInvalidation, FullRaster) { + RunSingleThreadedPixelTest( + renderer_type(), picture_layer_, base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png"))); } +using LayerTreeHostTilesTestPartialInvalidationMultiThread = + LayerTreeHostTilesTestPartialInvalidation; + +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostTilesTestPartialInvalidationMultiThread, + ::testing::Values(TilesTestConfig{LayerTreeTest::RENDERER_GL, ONE_COPY}, + TilesTestConfig{LayerTreeTest::RENDERER_SKIA_GL, + ONE_COPY})); + // Flaky on Linux TSAN. https://crbug.com/707711 #if defined(OS_LINUX) && defined(THREAD_SANITIZER) -#define MAYBE_PartialRaster_MultiThread_OneCopy \ - DISABLED_PartialRaster_MultiThread_OneCopy +#define MAYBE_PartialRaster DISABLED_PartialRaster #else -#define MAYBE_PartialRaster_MultiThread_OneCopy \ - PartialRaster_MultiThread_OneCopy +#define MAYBE_PartialRaster PartialRaster #endif -TEST_F(LayerTreeHostTilesTestPartialInvalidation, - MAYBE_PartialRaster_MultiThread_OneCopy) { - RunRasterPixelTest( - true, PARTIAL_ONE_COPY, picture_layer_, +TEST_P(LayerTreeHostTilesTestPartialInvalidationMultiThread, + MAYBE_PartialRaster) { + use_partial_raster_ = true; + RunPixelTest( + renderer_type(), 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_, - base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png"))); -} - -TEST_F(LayerTreeHostTilesTestPartialInvalidation, - PartialRaster_SingleThread_Software) { - RunRasterPixelTest( - false, PARTIAL_BITMAP, picture_layer_, - base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png"))); -} - -TEST_F(LayerTreeHostTilesTestPartialInvalidation, - FulllRaster_SingleThread_Software) { - RunRasterPixelTest( - false, FULL_BITMAP, picture_layer_, - base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png"))); -} - -TEST_F(LayerTreeHostTilesTestPartialInvalidation, - PartialRaster_SingleThread_GpuRaster) { - RunRasterPixelTest( - false, PARTIAL_GPU, picture_layer_, - base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png"))); -} - -TEST_F(LayerTreeHostTilesTestPartialInvalidation, - FullRaster_SingleThread_GpuRaster) { - RunRasterPixelTest( - false, FULL_GPU, picture_layer_, - base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png"))); +TEST_P(LayerTreeHostTilesTestPartialInvalidationMultiThread, FullRaster) { + RunPixelTest(renderer_type(), picture_layer_, + base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png"))); } -TEST_F(LayerTreeHostTilesTestPartialInvalidation, - PartialRaster_SingleThread_GpuRaster_LowBitDepth) { - RunRasterPixelTest(false, PARTIAL_GPU_LOW_BIT_DEPTH, picture_layer_, - base::FilePath(FILE_PATH_LITERAL( - "blue_yellow_partial_flipped_dither.png"))); +using LayerTreeHostTilesTestPartialInvalidationLowBitDepth = + LayerTreeHostTilesTestPartialInvalidation; + +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostTilesTestPartialInvalidationLowBitDepth, + ::testing::Values( + TilesTestConfig{LayerTreeTest::RENDERER_GL, GPU_LOW_BIT_DEPTH}, + TilesTestConfig{LayerTreeTest::RENDERER_SKIA_GL, GPU_LOW_BIT_DEPTH})); + +TEST_P(LayerTreeHostTilesTestPartialInvalidationLowBitDepth, PartialRaster) { + use_partial_raster_ = true; + RunSingleThreadedPixelTest(renderer_type(), picture_layer_, + base::FilePath(FILE_PATH_LITERAL( + "blue_yellow_partial_flipped_dither.png"))); } -TEST_F(LayerTreeHostTilesTestPartialInvalidation, - FullRaster_SingleThread_GpuRaster_LowBitDepth) { - RunRasterPixelTest( - false, FULL_GPU_LOW_BIT_DEPTH, picture_layer_, +TEST_P(LayerTreeHostTilesTestPartialInvalidationLowBitDepth, FullRaster) { + RunSingleThreadedPixelTest( + renderer_type(), picture_layer_, base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped_dither.png"))); } diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc index 1698efbc9fa..f10dada2a20 100644 --- a/chromium/cc/trees/layer_tree_host_unittest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest.cc @@ -351,7 +351,8 @@ class LayerTreeHostTestReadyToActivateNonEmpty // No single thread test because the commit goes directly to the active tree in // single thread mode, so notify ready to activate is skipped. -MULTI_THREAD_TEST_F(LayerTreeHostTestReadyToActivateNonEmpty); +// Flaky: https://crbug.com/947673 +// MULTI_THREAD_TEST_F(LayerTreeHostTestReadyToActivateNonEmpty); // Test if the LTHI receives ReadyToDraw notifications from the TileManager when // no raster tasks get scheduled. @@ -1580,7 +1581,8 @@ class LayerTreeHostTestPrepareTilesWithoutDraw : public LayerTreeHostTest { // This behavior is specific to Android WebView, which only uses // multi-threaded compositor. -MULTI_THREAD_TEST_F(LayerTreeHostTestPrepareTilesWithoutDraw); +// Flaky: https://crbug.com/947673 +// MULTI_THREAD_TEST_F(LayerTreeHostTestPrepareTilesWithoutDraw); // Verify CanDraw() is false until first commit. class LayerTreeHostTestCantDrawBeforeCommit : public LayerTreeHostTest { @@ -5661,20 +5663,22 @@ class TestSwapPromise : public SwapPromise { base::AutoLock lock(result_->lock); EXPECT_FALSE(result_->did_activate_called); EXPECT_FALSE(result_->did_swap_called); - EXPECT_FALSE(result_->did_not_swap_called); + EXPECT_TRUE(!result_->did_not_swap_called || + action_ == SwapPromise::DidNotSwapAction::KEEP_ACTIVE); result_->did_activate_called = true; } void WillSwap(viz::CompositorFrameMetadata* metadata) override { base::AutoLock lock(result_->lock); EXPECT_FALSE(result_->did_swap_called); - EXPECT_FALSE(result_->did_not_swap_called); + EXPECT_TRUE(!result_->did_not_swap_called || + action_ == SwapPromise::DidNotSwapAction::KEEP_ACTIVE); result_->did_swap_called = true; } void DidSwap() override {} - void DidNotSwap(DidNotSwapReason reason) override { + DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override { base::AutoLock lock(result_->lock); EXPECT_FALSE(result_->did_swap_called); EXPECT_FALSE(result_->did_not_swap_called); @@ -5682,13 +5686,17 @@ class TestSwapPromise : public SwapPromise { reason != DidNotSwapReason::SWAP_FAILS); result_->did_not_swap_called = true; result_->reason = reason; + return action_; } + void set_action(DidNotSwapAction action) { action_ = action; } + int64_t TraceId() const override { return 0; } private: // Not owned. TestSwapPromiseResult* result_; + DidNotSwapAction action_ = DidNotSwapAction::BREAK_PROMISE; }; class PinnedLayerTreeSwapPromise : public LayerTreeHostTest { @@ -6041,7 +6049,7 @@ class LayerTreeHostTestKeepSwapPromiseMFBA : public LayerTreeHostTest { MULTI_THREAD_TEST_F(LayerTreeHostTestKeepSwapPromiseMFBA); -class LayerTreeHostTestBreakSwapPromiseForVisibility +class LayerTreeHostTestDeferSwapPromiseForVisibility : public LayerTreeHostTest { protected: void BeginTest() override { PostSetNeedsCommitToMainThread(); } @@ -6050,6 +6058,7 @@ class LayerTreeHostTestBreakSwapPromiseForVisibility layer_tree_host()->SetVisible(false); auto swap_promise = std::make_unique<TestSwapPromise>(&swap_promise_result_); + swap_promise->set_action(SwapPromise::DidNotSwapAction::KEEP_ACTIVE); layer_tree_host()->GetSwapPromiseManager()->QueueSwapPromise( std::move(swap_promise)); } @@ -6060,7 +6069,7 @@ class LayerTreeHostTestBreakSwapPromiseForVisibility sent_queue_request_ = true; MainThreadTaskRunner()->PostTask( FROM_HERE, - base::BindOnce(&LayerTreeHostTestBreakSwapPromiseForVisibility:: + base::BindOnce(&LayerTreeHostTestDeferSwapPromiseForVisibility:: SetVisibleFalseAndQueueSwapPromise, base::Unretained(this))); } @@ -6068,25 +6077,42 @@ class LayerTreeHostTestBreakSwapPromiseForVisibility void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl, CommitEarlyOutReason reason) override { - EndTest(); + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&LayerTreeHostTestDeferSwapPromiseForVisibility:: + CheckSwapPromiseNotCalled, + base::Unretained(this))); } - void AfterTest() override { + void CheckSwapPromiseNotCalled() { { base::AutoLock lock(swap_promise_result_.lock); EXPECT_FALSE(swap_promise_result_.did_activate_called); EXPECT_FALSE(swap_promise_result_.did_swap_called); EXPECT_TRUE(swap_promise_result_.did_not_swap_called); EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_.reason); + EXPECT_FALSE(swap_promise_result_.dtor_called); + } + layer_tree_host()->SetVisible(true); + } + + void DidCommitAndDrawFrame() override { + { + base::AutoLock lock(swap_promise_result_.lock); + EXPECT_TRUE(swap_promise_result_.did_activate_called); + EXPECT_TRUE(swap_promise_result_.did_swap_called); EXPECT_TRUE(swap_promise_result_.dtor_called); } + EndTest(); } + void AfterTest() override {} + TestSwapPromiseResult swap_promise_result_; bool sent_queue_request_ = false; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromiseForVisibility); +SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeferSwapPromiseForVisibility); class SimpleSwapPromiseMonitor : public SwapPromiseMonitor { public: @@ -7095,7 +7121,7 @@ class LayerTreeHostTestCrispUpAfterPinchEnds : public LayerTreeHostTest { viz::RenderPass* root_pass = frame_data->render_passes.back().get(); for (auto* draw_quad : root_pass->quad_list) { // Checkerboards mean an incomplete frame. - if (draw_quad->material != viz::DrawQuad::TILED_CONTENT) + if (draw_quad->material != viz::DrawQuad::Material::kTiledContent) return 0.f; const viz::TileDrawQuad* quad = viz::TileDrawQuad::MaterialCast(draw_quad); @@ -8315,7 +8341,8 @@ class LayerTreeHostTestQueueImageDecode : public LayerTreeHostTest { image_ = DrawImage(CreateDiscardablePaintImage(gfx::Size(400, 400)), SkIRect::MakeWH(400, 400), kNone_SkFilterQuality, - SkMatrix::I(), PaintImage::kDefaultFrameIndex); + SkMatrix::I(), PaintImage::kDefaultFrameIndex, + gfx::ColorSpace()); auto callback = base::BindRepeating( &LayerTreeHostTestQueueImageDecode::ImageDecodeFinished, base::Unretained(this)); @@ -8656,7 +8683,7 @@ class LayerTreeHostTestImageAnimationSynchronousSchedulingSoftwareDraw void InitializeSettings(LayerTreeSettings* settings) override { LayerTreeHostTestImageAnimationSynchronousScheduling::InitializeSettings( settings); - use_software_renderer_ = true; + renderer_type_ = RENDERER_SOFTWARE; } void AfterTest() override { @@ -8732,11 +8759,11 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestImageDecodingHints); class LayerTreeHostTestCheckerboardUkm : public LayerTreeHostTest { public: - LayerTreeHostTestCheckerboardUkm() : url_(GURL("https://example.com")) {} - + LayerTreeHostTestCheckerboardUkm() : url_(GURL("https://example.com")), + ukm_source_id_(123) {} void BeginTest() override { PostSetNeedsCommitToMainThread(); - layer_tree_host()->SetURLForUkm(url_); + layer_tree_host()->SetSourceURL(ukm_source_id_, url_); } void SetupTree() override { @@ -8772,6 +8799,9 @@ class LayerTreeHostTestCheckerboardUkm : public LayerTreeHostTest { auto* recorder = static_cast<ukm::TestUkmRecorder*>( impl->ukm_manager()->recorder_for_testing()); + // Tie the source id to the URL. In production, this is already done in + // Document, and the source id is passed down to cc. + recorder->UpdateSourceURL(ukm_source_id_, url_); const auto& entries = recorder->GetEntriesByName(kUserInteraction); EXPECT_EQ(1u, entries.size()); @@ -8789,6 +8819,7 @@ class LayerTreeHostTestCheckerboardUkm : public LayerTreeHostTest { private: const GURL url_; + const ukm::SourceId ukm_source_id_; FakeContentLayerClient content_layer_client_; }; diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation.cc b/chromium/cc/trees/layer_tree_host_unittest_animation.cc index 6cd39fc0b0d..47a27fd67c8 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc @@ -1537,9 +1537,11 @@ class LayerTreeHostAnimationTestAnimatedLayerRemovedAndAdded EXPECT_FALSE(animation_->keyframe_effect() ->element_animations() ->has_element_in_pending_list()); - EXPECT_FALSE(animation_host()->NeedsTickAnimations()); + // Animations still need one more tick to deliver finished event. + EXPECT_TRUE(animation_host()->NeedsTickAnimations()); break; case 2: + EXPECT_FALSE(animation_host()->NeedsTickAnimations()); layer_tree_host()->root_layer()->AddChild(layer_); EXPECT_TRUE(animation_->keyframe_effect() ->element_animations() @@ -1570,6 +1572,8 @@ class LayerTreeHostAnimationTestAnimatedLayerRemovedAndAdded EXPECT_FALSE(animation_impl->keyframe_effect() ->element_animations() ->has_element_in_active_list()); + // Having updated state on the host_impl during the commit, we no longer + // need to tick animations. EXPECT_FALSE(GetImplAnimationHost(host_impl)->NeedsTickAnimations()); break; case 2: diff --git a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc index 929c6658fe8..5ad5e2a6977 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc @@ -20,20 +20,26 @@ const char kCheckerboardImagesMetric[] = "CheckerboardedImagesCount"; class LayerTreeHostCheckerImagingTest : public LayerTreeTest { public: - LayerTreeHostCheckerImagingTest() : url_(GURL("https://example.com")) {} + LayerTreeHostCheckerImagingTest() : url_(GURL("https://example.com")), + ukm_source_id_(123) {} void BeginTest() override { - layer_tree_host()->SetURLForUkm(url_); + layer_tree_host()->SetSourceURL(ukm_source_id_, url_); PostSetNeedsCommitToMainThread(); } void AfterTest() override {} void VerifyUkmAndEndTest(LayerTreeHostImpl* impl) { - // Change the URL to ensure any accumulated metrics are flushed. - impl->ukm_manager()->SetSourceURL(GURL("chrome://test2")); - auto* recorder = static_cast<ukm::TestUkmRecorder*>( impl->ukm_manager()->recorder_for_testing()); + // Tie the source id to the URL. In production, this is already done in + // Document, and the source id is passed down to cc. + recorder->UpdateSourceURL(ukm_source_id_, url_); + + // Change the source to ensure any accumulated metrics are flushed. + impl->ukm_manager()->SetSourceId(200); + recorder->UpdateSourceURL(200, GURL("chrome://test2")); + const auto& entries = recorder->GetEntriesByName(kRenderingEvent); ASSERT_EQ(1u, entries.size()); auto* entry = entries[0]; @@ -76,6 +82,9 @@ class LayerTreeHostCheckerImagingTest : public LayerTreeTest { // Accessed only on the main thread. FakeContentLayerClient content_layer_client_; GURL url_; + + // Accessed on the impl thread. + const ukm::SourceId ukm_source_id_; }; class LayerTreeHostCheckerImagingTestMergeWithMainFrame diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc index 1f0663462d7..a06f23dc57f 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_context.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc @@ -934,8 +934,10 @@ class LayerTreeHostContextTestDontUseLostResources TextureLayer::CreateForMailbox(nullptr); texture->SetBounds(gfx::Size(10, 10)); texture->SetIsDrawable(true); + constexpr gfx::Size size(64, 64); auto resource = viz::TransferableResource::MakeGL( - mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token); + mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token, size, + false /* is_overlay_candidate */); texture->SetTransferableResource( resource, viz::SingleReleaseCallback::Create(base::BindOnce( &LayerTreeHostContextTestDontUseLostResources:: diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc index cad1e7288bd..5bac6e88f25 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc @@ -18,6 +18,7 @@ #include "components/viz/common/frame_sinks/copy_output_result.h" #include "components/viz/service/display/direct_renderer.h" #include "components/viz/test/fake_output_surface.h" +#include "components/viz/test/fake_skia_output_surface.h" #include "components/viz/test/test_gles2_interface.h" #include "components/viz/test/test_layer_tree_frame_sink.h" #include "gpu/GLES2/gl2extchromium.h" @@ -25,9 +26,24 @@ namespace cc { namespace { -// These tests only use direct rendering, as there is no output to copy for -// delegated renderers. -class LayerTreeHostCopyRequestTest : public LayerTreeTest {}; +auto CombineWithCompositorModes( + const std::vector<LayerTreeTest::RendererType>& types) { + return ::testing::Combine(::testing::ValuesIn(types), + ::testing::Values(CompositorMode::SINGLE_THREADED, + CompositorMode::THREADED)); +} + +class LayerTreeHostCopyRequestTest + : public LayerTreeTest, + public ::testing::WithParamInterface< + ::testing::tuple<LayerTreeTest::RendererType, CompositorMode>> { + public: + RendererType renderer_type() const { return ::testing::get<0>(GetParam()); } + + CompositorMode compositor_mode() const { + return ::testing::get<1>(GetParam()); + } +}; class LayerTreeHostCopyRequestTestMultipleRequests : public LayerTreeHostCopyRequestTest { @@ -136,27 +152,6 @@ class LayerTreeHostCopyRequestTestMultipleRequests void AfterTest() override { EXPECT_EQ(4u, callbacks_.size()); } - std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread( - scoped_refptr<viz::ContextProvider> compositor_context_provider) - override { - if (!use_gl_renderer_) { - return viz::FakeOutputSurface::CreateSoftware( - std::make_unique<viz::SoftwareOutputDevice>()); - } - - scoped_refptr<viz::TestContextProvider> display_context_provider = - viz::TestContextProvider::Create(); - viz::TestContextSupport* context_support = - display_context_provider->support(); - context_support->set_out_of_order_callbacks(out_of_order_callbacks_); - display_context_provider->BindToCurrentThread(); - - return viz::FakeOutputSurface::Create3d( - std::move(display_context_provider)); - } - - bool use_gl_renderer_; - bool out_of_order_callbacks_ = false; std::map<size_t, gfx::Size> callbacks_; FakeContentLayerClient client_; scoped_refptr<FakePictureLayer> root; @@ -164,72 +159,52 @@ class LayerTreeHostCopyRequestTestMultipleRequests scoped_refptr<FakePictureLayer> grand_child; }; -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - GLRenderer_RunSingleThread) { - use_gl_renderer_ = true; - RunTest(CompositorMode::SINGLE_THREADED); -} - -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - GLRenderer_RunMultiThread) { - use_gl_renderer_ = true; - RunTest(CompositorMode::THREADED); -} +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestMultipleRequests, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL, + LayerTreeTest::RENDERER_SOFTWARE})); -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - GLRenderer_RunSingleThread_OutOfOrderCallbacks) { - use_gl_renderer_ = true; - out_of_order_callbacks_ = true; - RunTest(CompositorMode::SINGLE_THREADED); +TEST_P(LayerTreeHostCopyRequestTestMultipleRequests, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); } -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - GLRenderer_RunMultiThread_OutOfOrderCallbacks) { - use_gl_renderer_ = true; - out_of_order_callbacks_ = true; - RunTest(CompositorMode::THREADED); -} - -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - SkiaRenderer_RunSingleThread) { - use_gl_renderer_ = true; - use_skia_renderer_ = true; - RunTest(CompositorMode::SINGLE_THREADED); -} - -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - SkiaRenderer_RunMultiThread) { - use_gl_renderer_ = true; - use_skia_renderer_ = true; - RunTest(CompositorMode::THREADED); -} +// These tests run with |out_of_order_callbacks_| set on the TestContextSupport, +// which causes callbacks for sync queries to be sent in reverse order. +class LayerTreeHostCopyRequestTestMultipleRequestsOutOfOrder + : public LayerTreeHostCopyRequestTestMultipleRequests { + std::unique_ptr<viz::SkiaOutputSurface> + CreateDisplaySkiaOutputSurfaceOnThread() override { + auto skia_output_surface = viz::FakeSkiaOutputSurface::Create3d(); + skia_output_surface->SetOutOfOrderCallbacks(true); + return skia_output_surface; + } -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - SkiaRenderer_RunSingleThread_OutOfOrderCallbacks) { - use_gl_renderer_ = true; - use_skia_renderer_ = true; - out_of_order_callbacks_ = true; - RunTest(CompositorMode::SINGLE_THREADED); -} + std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread( + scoped_refptr<viz::ContextProvider> compositor_context_provider) + override { + // Since this test does not override CreateLayerTreeFrameSink, the + // |compositor_context_provider| will be a viz::TestContextProvider. + auto* context_support = static_cast<viz::TestContextSupport*>( + compositor_context_provider->ContextSupport()); + context_support->set_out_of_order_callbacks(true); -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - SkiaRenderer_RunMultiThread_OutOfOrderCallbacks) { - use_gl_renderer_ = true; - use_skia_renderer_ = true; - out_of_order_callbacks_ = true; - RunTest(CompositorMode::THREADED); -} + return viz::FakeOutputSurface::Create3d( + std::move(compositor_context_provider)); + } +}; -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - SoftwareRenderer_RunSingleThread) { - use_gl_renderer_ = false; - RunTest(CompositorMode::SINGLE_THREADED); -} +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestMultipleRequestsOutOfOrder, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); -TEST_F(LayerTreeHostCopyRequestTestMultipleRequests, - SoftwareRenderer_RunMultiThread) { - use_gl_renderer_ = false; - RunTest(CompositorMode::THREADED); +TEST_P(LayerTreeHostCopyRequestTestMultipleRequestsOutOfOrder, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); } // TODO(crbug.com/564832): Remove this test when the workaround it tests is no @@ -285,7 +260,16 @@ class LayerTreeHostCopyRequestCompletionCausesCommit scoped_refptr<FakePictureLayer> layer_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestCompletionCausesCommit); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestCompletionCausesCommit, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestCompletionCausesCommit, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostCopyRequestTestLayerDestroyed : public LayerTreeHostCopyRequestTest { @@ -332,7 +316,7 @@ class LayerTreeHostCopyRequestTestLayerDestroyed // Destroy the main thread layer right away. main_destroyed_->RemoveFromParent(); - main_destroyed_ = nullptr; + main_destroyed_.reset(); // Should callback with a NULL bitmap. EXPECT_EQ(1, callback_count_); @@ -351,7 +335,7 @@ class LayerTreeHostCopyRequestTestLayerDestroyed // Destroy the impl thread layer. impl_destroyed_->RemoveFromParent(); - impl_destroyed_ = nullptr; + impl_destroyed_.reset(); // No callback yet because it's on the impl side. EXPECT_EQ(1, callback_count_); @@ -383,7 +367,16 @@ class LayerTreeHostCopyRequestTestLayerDestroyed scoped_refptr<FakePictureLayer> impl_destroyed_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestLayerDestroyed); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestLayerDestroyed, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestTestLayerDestroyed, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostCopyRequestTestInHiddenSubtree : public LayerTreeHostCopyRequestTest { @@ -483,7 +476,16 @@ class LayerTreeHostCopyRequestTestInHiddenSubtree scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestInHiddenSubtree); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestInHiddenSubtree, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestTestInHiddenSubtree, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest : public LayerTreeHostCopyRequestTest { @@ -596,8 +598,16 @@ class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostCopyRequestTestClippedOut : public LayerTreeHostCopyRequestTest { @@ -647,7 +657,16 @@ class LayerTreeHostCopyRequestTestClippedOut scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestClippedOut); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestClippedOut, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestTestClippedOut, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostCopyRequestTestScaledLayer : public LayerTreeHostCopyRequestTest { @@ -705,7 +724,16 @@ class LayerTreeHostCopyRequestTestScaledLayer scoped_refptr<FakePictureLayer> child_layer_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestScaledLayer); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestScaledLayer, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestTestScaledLayer, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw : public LayerTreeHostCopyRequestTest { @@ -791,17 +819,36 @@ class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestAsyncTwoReadbacksWithoutDraw); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostTestAsyncTwoReadbacksWithoutDraw, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostTestAsyncTwoReadbacksWithoutDraw, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostCopyRequestTestDeleteSharedImage : public LayerTreeHostCopyRequestTest { protected: + std::unique_ptr<viz::SkiaOutputSurface> + CreateDisplaySkiaOutputSurfaceOnThread() override { + display_context_provider_ = viz::TestContextProvider::Create(); + display_context_provider_->BindToCurrentThread(); + return viz::FakeSkiaOutputSurface::Create3d(display_context_provider_); + } + std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread( scoped_refptr<viz::ContextProvider> compositor_context_provider) override { - display_context_provider_ = viz::TestContextProvider::Create(); - display_context_provider_->BindToCurrentThread(); - return viz::FakeOutputSurface::Create3d(display_context_provider_); + // Since this test does not override CreateLayerTreeFrameSink, the + // |compositor_context_provider| will be a viz::TestContextProvider. + display_context_provider_ = static_cast<viz::TestContextProvider*>( + compositor_context_provider.get()); + return viz::FakeOutputSurface::Create3d( + std::move(compositor_context_provider)); } void SetupTree() override { @@ -844,7 +891,7 @@ class LayerTreeHostCopyRequestTestDeleteSharedImage void DestroyCopyResultAndCheckNumSharedImages() { EXPECT_TRUE(result_); - result_ = nullptr; + result_.reset(); ImplThreadTaskRunner()->PostTask( FROM_HERE, @@ -863,7 +910,7 @@ class LayerTreeHostCopyRequestTestDeleteSharedImage ->shared_image_count()); // Drop the reference to the context provider on the compositor thread. - display_context_provider_ = nullptr; + display_context_provider_.reset(); EndTest(); } @@ -918,11 +965,27 @@ class LayerTreeHostCopyRequestTestDeleteSharedImage std::unique_ptr<viz::CopyOutputResult> result_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestDeleteSharedImage); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestDeleteSharedImage, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestTestDeleteSharedImage, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostCopyRequestTestCountSharedImages : public LayerTreeHostCopyRequestTest { protected: + std::unique_ptr<viz::SkiaOutputSurface> + CreateDisplaySkiaOutputSurfaceOnThread() override { + display_context_provider_ = viz::TestContextProvider::Create(); + display_context_provider_->BindToCurrentThread(); + return viz::FakeSkiaOutputSurface::Create3d(display_context_provider_); + } + std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread( scoped_refptr<viz::ContextProvider> compositor_context_provider) override { @@ -999,7 +1062,13 @@ class LayerTreeHostCopyRequestTestCountSharedImages } } - virtual void DoEndTest() { EndTest(); } + virtual void DoEndTest() { + // Drop the reference to the context provider on the main thread. If the + // reference is dropped during the test destructor, then there will be a + // DCHECK in ~TestContextProvider() for some cases. + display_context_provider_.reset(); + EndTest(); + } scoped_refptr<viz::TestContextProvider> display_context_provider_; int num_swaps_ = 0; @@ -1042,7 +1111,16 @@ class LayerTreeHostCopyRequestTestCreatesSharedImage std::unique_ptr<viz::SingleReleaseCallback> release_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestCreatesSharedImage); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestCreatesSharedImage, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestTestCreatesSharedImage, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostCopyRequestTestDestroyBeforeCopy : public LayerTreeHostCopyRequestTest { @@ -1123,7 +1201,16 @@ class LayerTreeHostCopyRequestTestDestroyBeforeCopy scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestDestroyBeforeCopy); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestDestroyBeforeCopy, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestTestDestroyBeforeCopy, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostCopyRequestTestShutdownBeforeCopy : public LayerTreeHostCopyRequestTest { @@ -1198,7 +1285,16 @@ class LayerTreeHostCopyRequestTestShutdownBeforeCopy scoped_refptr<FakePictureLayer> copy_layer_; }; -SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestShutdownBeforeCopy); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestShutdownBeforeCopy, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestTestShutdownBeforeCopy, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} class LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest : public LayerTreeHostCopyRequestTest { @@ -1324,8 +1420,16 @@ class LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest bool draw_happened_; }; -SINGLE_AND_MULTI_THREAD_TEST_F( - LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest); +INSTANTIATE_TEST_SUITE_P( + , + LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest, + CombineWithCompositorModes({LayerTreeTest::RENDERER_GL, + LayerTreeTest::RENDERER_SKIA_GL})); + +TEST_P(LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest, Test) { + renderer_type_ = renderer_type(); + RunTest(compositor_mode()); +} } // namespace } // namespace cc diff --git a/chromium/cc/trees/layer_tree_host_unittest_masks.cc b/chromium/cc/trees/layer_tree_host_unittest_masks.cc index d0dfd9b9ba7..b0a8b0c9ac2 100644 --- a/chromium/cc/trees/layer_tree_host_unittest_masks.cc +++ b/chromium/cc/trees/layer_tree_host_unittest_masks.cc @@ -77,10 +77,10 @@ class LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin EXPECT_EQ(2u, root_pass->quad_list.size()); // There's a solid color quad under everything. - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, root_pass->quad_list.back()->material); - EXPECT_EQ(viz::DrawQuad::RENDER_PASS, + EXPECT_EQ(viz::DrawQuad::Material::kRenderPass, root_pass->quad_list.front()->material); const viz::RenderPassDrawQuad* render_pass_quad = viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front()); @@ -209,11 +209,11 @@ class LayerTreeTestMaskLayerForSurfaceWithClippedLayer : public LayerTreeTest { EXPECT_EQ(2u, root_pass->quad_list.size()); // There's a solid color quad under everything. - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, root_pass->quad_list.back()->material); // The surface is clipped to 10x20. - EXPECT_EQ(viz::DrawQuad::RENDER_PASS, + EXPECT_EQ(viz::DrawQuad::Material::kRenderPass, root_pass->quad_list.front()->material); const viz::RenderPassDrawQuad* render_pass_quad = viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front()); @@ -355,12 +355,12 @@ class LayerTreeTestMaskLayerForSurfaceWithDifferentScale EXPECT_EQ(2u, root_pass->quad_list.size()); // There's a solid color quad under everything. - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, root_pass->quad_list.back()->material); // The surface is clipped to 10x20, and then scaled by 2, which ends up // being 20x40. - EXPECT_EQ(viz::DrawQuad::RENDER_PASS, + EXPECT_EQ(viz::DrawQuad::Material::kRenderPass, root_pass->quad_list.front()->material); const viz::RenderPassDrawQuad* render_pass_quad = viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front()); @@ -488,10 +488,10 @@ class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest { EXPECT_EQ(2u, root_pass->quad_list.size()); // There's a solid color quad under everything. - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, root_pass->quad_list.back()->material); - EXPECT_EQ(viz::DrawQuad::RENDER_PASS, + EXPECT_EQ(viz::DrawQuad::Material::kRenderPass, root_pass->quad_list.front()->material); const viz::RenderPassDrawQuad* render_pass_quad = viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front()); @@ -619,11 +619,11 @@ class LayerTreeTestMaskWithNonExactTextureSize : public LayerTreeTest { EXPECT_EQ(2u, root_pass->quad_list.size()); // There's a solid color quad under everything. - EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, + EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, root_pass->quad_list.back()->material); // The surface is 100x100 - EXPECT_EQ(viz::DrawQuad::RENDER_PASS, + EXPECT_EQ(viz::DrawQuad::Material::kRenderPass, root_pass->quad_list.front()->material); const viz::RenderPassDrawQuad* render_pass_quad = viz::RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front()); diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc index 8202fa00798..fbd783c9798 100644 --- a/chromium/cc/trees/layer_tree_impl.cc +++ b/chromium/cc/trees/layer_tree_impl.cc @@ -619,35 +619,13 @@ LayerImplList::reverse_iterator LayerTreeImpl::rend() { } bool LayerTreeImpl::IsElementInPropertyTree(ElementId element_id) const { - return elements_in_property_trees_.count(element_id); + return property_trees()->HasElement(element_id); } ElementListType LayerTreeImpl::GetElementTypeForAnimation() const { return IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING; } -void LayerTreeImpl::AddToElementPropertyTreeList(ElementId element_id) { -#if DCHECK_IS_ON() - bool element_id_collision_detected = - elements_in_property_trees_.count(element_id); - - DCHECK(!element_id_collision_detected); -#endif - - elements_in_property_trees_.insert(element_id); - - DCHECK(settings().use_layer_lists); - host_impl_->mutator_host()->RegisterElement(element_id, - GetElementTypeForAnimation()); -} - -void LayerTreeImpl::RemoveFromElementPropertyTreeList(ElementId element_id) { - DCHECK(settings().use_layer_lists); - host_impl_->mutator_host()->UnregisterElement(element_id, - GetElementTypeForAnimation()); - elements_in_property_trees_.erase(element_id); -} - void LayerTreeImpl::AddToElementLayerList(ElementId element_id, LayerImpl* layer) { if (!element_id) @@ -658,9 +636,8 @@ void LayerTreeImpl::AddToElementLayerList(ElementId element_id, element_id.AsValue().release()); if (!settings().use_layer_lists) { - elements_in_property_trees_.insert(element_id); - host_impl_->mutator_host()->RegisterElement(element_id, - GetElementTypeForAnimation()); + host_impl_->mutator_host()->RegisterElementId(element_id, + GetElementTypeForAnimation()); } if (layer->scrollable()) @@ -676,9 +653,8 @@ void LayerTreeImpl::RemoveFromElementLayerList(ElementId element_id) { element_id.AsValue().release()); if (!settings().use_layer_lists) { - elements_in_property_trees_.erase(element_id); - host_impl_->mutator_host()->UnregisterElement(element_id, - GetElementTypeForAnimation()); + host_impl_->mutator_host()->UnregisterElementId( + element_id, GetElementTypeForAnimation()); } element_id_to_scrollable_layer_.erase(element_id); @@ -726,6 +702,18 @@ void LayerTreeImpl::SetFilterMutated(ElementId element_id, set_needs_update_draw_properties(); } +void LayerTreeImpl::SetBackdropFilterMutated( + ElementId element_id, + const FilterOperations& backdrop_filters) { + DCHECK_EQ( + 1u, property_trees()->element_id_to_effect_node_index.count(element_id)); + if (IsSyncTree() || IsRecycleTree()) + element_id_to_backdrop_filter_animations_[element_id] = backdrop_filters; + if (property_trees()->effect_tree.OnBackdropFilterAnimated(element_id, + backdrop_filters)) + set_needs_update_draw_properties(); +} + void LayerTreeImpl::AddPresentationCallbacks( std::vector<LayerTreeHost::PresentationTimeCallback> callbacks) { std::copy(std::make_move_iterator(callbacks.begin()), @@ -827,6 +815,23 @@ void LayerTreeImpl::UpdatePropertyTreeAnimationFromMainThread() { ++element_id_to_filter; } + auto element_id_to_backdrop_filter = + element_id_to_backdrop_filter_animations_.begin(); + while (element_id_to_backdrop_filter != + element_id_to_backdrop_filter_animations_.end()) { + const ElementId id = element_id_to_backdrop_filter->first; + EffectNode* node = property_trees_.effect_tree.FindNodeFromElementId(id); + if (!node || !node->is_currently_animating_backdrop_filter || + node->backdrop_filters == element_id_to_backdrop_filter->second) { + element_id_to_backdrop_filter_animations_.erase( + element_id_to_backdrop_filter++); + continue; + } + node->backdrop_filters = element_id_to_backdrop_filter->second; + property_trees_.effect_tree.set_needs_update(true); + ++element_id_to_backdrop_filter; + } + auto element_id_to_transform = element_id_to_transform_animations_.begin(); while (element_id_to_transform != element_id_to_transform_animations_.end()) { const ElementId id = element_id_to_transform->first; @@ -861,10 +866,9 @@ void LayerTreeImpl::UpdateTransformAnimation(ElementId element_id, list_type); if (node->has_potential_animation != has_potential_animation) { node->has_potential_animation = has_potential_animation; - node->maximum_animation_scale = - mutator_host()->MaximumTargetScale(element_id, list_type); - node->starting_animation_scale = - mutator_host()->AnimationStartScale(element_id, list_type); + mutator_host()->GetAnimationScales(element_id, list_type, + &node->maximum_animation_scale, + &node->starting_animation_scale); transform_tree.set_needs_update(true); set_needs_update_draw_properties(); } @@ -1084,8 +1088,6 @@ void LayerTreeImpl::SetLocalSurfaceIdAllocationFromParent( local_surface_id_allocation_from_parent) { local_surface_id_allocation_from_parent_ = local_surface_id_allocation_from_parent; - if (IsActiveTree()) - host_impl_->OnLayerTreeLocalSurfaceIdAllocationChanged(); } void LayerTreeImpl::RequestNewLocalSurfaceId() { @@ -1422,6 +1424,7 @@ void LayerTreeImpl::BuildPropertyTreesForTesting() { gfx::Rect(GetDeviceViewport().size()), host_impl_->DrawTransform(), &property_trees_); property_trees_.transform_tree.set_source_to_parent_updates_allowed(false); + host_impl_->UpdateElements(GetElementTypeForAnimation()); } const RenderSurfaceList& LayerTreeImpl::GetRenderSurfaceList() const { @@ -1755,8 +1758,15 @@ void LayerTreeImpl::QueuePinnedSwapPromise( void LayerTreeImpl::PassSwapPromises( std::vector<std::unique_ptr<SwapPromise>> new_swap_promises) { - for (auto& swap_promise : swap_promise_list_) - swap_promise->DidNotSwap(SwapPromise::SWAP_FAILS); + for (auto& swap_promise : swap_promise_list_) { + if (swap_promise->DidNotSwap(SwapPromise::SWAP_FAILS) == + SwapPromise::DidNotSwapAction::KEEP_ACTIVE) { + // |swap_promise| must remain active, so place it in |new_swap_promises| + // in order to keep it alive and active. + new_swap_promises.push_back(std::move(swap_promise)); + } + } + swap_promise_list_.clear(); swap_promise_list_.swap(new_swap_promises); } @@ -1784,13 +1794,30 @@ void LayerTreeImpl::ClearSwapPromises() { } void LayerTreeImpl::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) { - for (auto& swap_promise : swap_promise_list_) - swap_promise->DidNotSwap(reason); - swap_promise_list_.clear(); + { + std::vector<std::unique_ptr<SwapPromise>> persistent_swap_promises; + for (auto& swap_promise : swap_promise_list_) { + if (swap_promise->DidNotSwap(reason) == + SwapPromise::DidNotSwapAction::KEEP_ACTIVE) { + persistent_swap_promises.push_back(std::move(swap_promise)); + } + } + // |persistent_swap_promises| must remain active even when swap fails. + swap_promise_list_ = std::move(persistent_swap_promises); + } - for (auto& swap_promise : pinned_swap_promise_list_) - swap_promise->DidNotSwap(reason); - pinned_swap_promise_list_.clear(); + { + std::vector<std::unique_ptr<SwapPromise>> persistent_swap_promises; + for (auto& swap_promise : pinned_swap_promise_list_) { + if (swap_promise->DidNotSwap(reason) == + SwapPromise::DidNotSwapAction::KEEP_ACTIVE) { + persistent_swap_promises.push_back(std::move(swap_promise)); + } + } + + // |persistent_swap_promises| must remain active even when swap fails. + pinned_swap_promise_list_ = std::move(persistent_swap_promises); + } } void LayerTreeImpl::DidModifyTilePriorities() { @@ -2114,9 +2141,10 @@ static void FindClosestMatchingLayer(const gfx::PointF& screen_space_point, } } -struct FindScrollingLayerOrScrollbarFunctor { +struct HitTestScrollingLayerOrScrollbarFunctor { bool operator()(LayerImpl* layer) const { - return layer->scrollable() || layer->is_scrollbar(); + return layer->HitTestable() && + (layer->scrollable() || layer->is_scrollbar()); } }; @@ -2128,7 +2156,7 @@ LayerImpl* LayerTreeImpl::FindFirstScrollingLayerOrScrollbarThatIsHitByPoint( FindClosestMatchingLayerState state; LayerImpl* root_layer = layer_list_[0]; FindClosestMatchingLayer(screen_space_point, root_layer, - FindScrollingLayerOrScrollbarFunctor(), &state); + HitTestScrollingLayerOrScrollbarFunctor(), &state); return state.closest_match; } diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h index 88d798bce13..21f3f87674a 100644 --- a/chromium/cc/trees/layer_tree_impl.h +++ b/chromium/cc/trees/layer_tree_impl.h @@ -183,7 +183,6 @@ class CC_EXPORT LayerTreeImpl { void PushPropertyTreesTo(LayerTreeImpl* tree_impl); void PushPropertiesTo(LayerTreeImpl* tree_impl); void PushSurfaceRangesTo(LayerTreeImpl* tree_impl); - void PushRegisteredElementIdsTo(LayerTreeImpl* tree_impl); void MoveChangeTrackingToLayers(); @@ -200,6 +199,8 @@ class CC_EXPORT LayerTreeImpl { const gfx::Transform& transform); void SetOpacityMutated(ElementId element_id, float opacity); void SetFilterMutated(ElementId element_id, const FilterOperations& filters); + void SetBackdropFilterMutated(ElementId element_id, + const FilterOperations& backdrop_filters); const std::unordered_map<ElementId, float, ElementIdHash>& element_id_to_opacity_animations_for_testing() const { @@ -213,6 +214,10 @@ class CC_EXPORT LayerTreeImpl { element_id_to_filter_animations_for_testing() const { return element_id_to_filter_animations_; } + const std::unordered_map<ElementId, FilterOperations, ElementIdHash>& + element_id_to_backdrop_filter_animations_for_testing() const { + return element_id_to_backdrop_filter_animations_; + } int source_frame_number() const { return source_frame_number_; } void set_source_frame_number(int frame_number) { @@ -645,11 +650,6 @@ class CC_EXPORT LayerTreeImpl { LayerTreeLifecycle& lifecycle() { return lifecycle_; } - const std::unordered_set<ElementId, ElementIdHash>& - elements_in_property_trees() { - return elements_in_property_trees_; - } - std::string LayerListAsJson() const; // TODO(pdr): This should be removed because there is no longer a tree // of layers, only a list. @@ -722,15 +722,14 @@ class CC_EXPORT LayerTreeImpl { // Set of layers that need to push properties. base::flat_set<LayerImpl*> layers_that_should_push_properties_; - // Set of ElementIds which are present in the |layer_list_|. - std::unordered_set<ElementId, ElementIdHash> elements_in_property_trees_; - std::unordered_map<ElementId, float, ElementIdHash> element_id_to_opacity_animations_; std::unordered_map<ElementId, gfx::Transform, ElementIdHash> element_id_to_transform_animations_; std::unordered_map<ElementId, FilterOperations, ElementIdHash> element_id_to_filter_animations_; + std::unordered_map<ElementId, FilterOperations, ElementIdHash> + element_id_to_backdrop_filter_animations_; std::unordered_map<ElementId, LayerImpl*, ElementIdHash> element_id_to_scrollable_layer_; diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc index e703093d5b4..4dc46346a58 100644 --- a/chromium/cc/trees/layer_tree_impl_unittest.cc +++ b/chromium/cc/trees/layer_tree_impl_unittest.cc @@ -2362,16 +2362,39 @@ TEST_F(LayerTreeImplTest, ScrollSizeWithoutLayers) { namespace { -class StubSwapPromise : public SwapPromise, - public base::SupportsWeakPtr<StubSwapPromise> { +class PersistentSwapPromise + : public SwapPromise, + public base::SupportsWeakPtr<PersistentSwapPromise> { public: - StubSwapPromise() = default; - ~StubSwapPromise() override = default; + PersistentSwapPromise() = default; + ~PersistentSwapPromise() override = default; + + void DidActivate() override {} + MOCK_METHOD1(WillSwap, void(viz::CompositorFrameMetadata* metadata)); + MOCK_METHOD0(DidSwap, void()); + + DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override { + return DidNotSwapAction::KEEP_ACTIVE; + } + + void OnCommit() override {} + int64_t TraceId() const override { return 0; } +}; + +class NotPersistentSwapPromise + : public SwapPromise, + public base::SupportsWeakPtr<NotPersistentSwapPromise> { + public: + NotPersistentSwapPromise() = default; + ~NotPersistentSwapPromise() override = default; void DidActivate() override {} void WillSwap(viz::CompositorFrameMetadata* metadata) override {} void DidSwap() override {} - void DidNotSwap(DidNotSwapReason reason) override {} + + DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override { + return DidNotSwapAction::BREAK_PROMISE; + } void OnCommit() override {} int64_t TraceId() const override { return 0; } @@ -2379,31 +2402,64 @@ class StubSwapPromise : public SwapPromise, } // namespace -TEST_F(LayerTreeImplTest, StubSwapPromisesAreDroppedWhenSwapFails) { +TEST_F(LayerTreeImplTest, PersistentSwapPromisesAreKeptAlive) { + const size_t promises_count = 2; + + std::vector<base::WeakPtr<PersistentSwapPromise>> persistent_promises; + std::vector<std::unique_ptr<PersistentSwapPromise>> + persistent_promises_to_pass; + for (size_t i = 0; i < promises_count; ++i) { + persistent_promises_to_pass.push_back( + std::make_unique<PersistentSwapPromise>()); + } + + for (auto& promise : persistent_promises_to_pass) { + persistent_promises.push_back(promise->AsWeakPtr()); + host_impl().active_tree()->QueueSwapPromise(std::move(promise)); + } + + std::vector<std::unique_ptr<SwapPromise>> promises; + host_impl().active_tree()->PassSwapPromises(std::move(promises)); + host_impl().active_tree()->BreakSwapPromises( + SwapPromise::DidNotSwapReason::SWAP_FAILS); + + ASSERT_EQ(promises_count, persistent_promises.size()); + for (size_t i = 0; i < persistent_promises.size(); ++i) { + SCOPED_TRACE(testing::Message() << "While checking case #" << i); + ASSERT_TRUE(persistent_promises[i]); + EXPECT_CALL(*persistent_promises[i], WillSwap(testing::_)); + } + host_impl().active_tree()->FinishSwapPromises(nullptr); +} + +TEST_F(LayerTreeImplTest, NotPersistentSwapPromisesAreDroppedWhenSwapFails) { const size_t promises_count = 2; - std::vector<base::WeakPtr<StubSwapPromise>> weak_swap_promises; - std::vector<std::unique_ptr<StubSwapPromise>> swap_promises_to_pass; + std::vector<base::WeakPtr<NotPersistentSwapPromise>> not_persistent_promises; + std::vector<std::unique_ptr<NotPersistentSwapPromise>> + not_persistent_promises_to_pass; for (size_t i = 0; i < promises_count; ++i) { - swap_promises_to_pass.push_back(std::make_unique<StubSwapPromise>()); + not_persistent_promises_to_pass.push_back( + std::make_unique<NotPersistentSwapPromise>()); } - for (auto& promise : swap_promises_to_pass) { - weak_swap_promises.push_back(promise->AsWeakPtr()); + for (auto& promise : not_persistent_promises_to_pass) { + not_persistent_promises.push_back(promise->AsWeakPtr()); host_impl().active_tree()->QueueSwapPromise(std::move(promise)); } std::vector<std::unique_ptr<SwapPromise>> promises; host_impl().active_tree()->PassSwapPromises(std::move(promises)); - ASSERT_EQ(promises_count, weak_swap_promises.size()); - for (size_t i = 0; i < weak_swap_promises.size(); ++i) { - EXPECT_FALSE(weak_swap_promises[i]) << "While checking case #" << i; + ASSERT_EQ(promises_count, not_persistent_promises.size()); + for (size_t i = 0; i < not_persistent_promises.size(); ++i) { + EXPECT_FALSE(not_persistent_promises[i]) << "While checking case #" << i; } - // Finally, check that the promises do not survive + // Finally, check that not persistent promise doesn't survive // |LayerTreeImpl::BreakSwapPromises|. { - std::unique_ptr<StubSwapPromise> promise(new StubSwapPromise()); + std::unique_ptr<NotPersistentSwapPromise> promise( + new NotPersistentSwapPromise()); auto weak_promise = promise->AsWeakPtr(); host_impl().active_tree()->QueueSwapPromise(std::move(promise)); host_impl().active_tree()->BreakSwapPromises( diff --git a/chromium/cc/trees/layer_tree_mutator.cc b/chromium/cc/trees/layer_tree_mutator.cc index 15d2b6aebb2..9e285596b4a 100644 --- a/chromium/cc/trees/layer_tree_mutator.cc +++ b/chromium/cc/trees/layer_tree_mutator.cc @@ -13,12 +13,12 @@ AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState( std::string name, double current_time, std::unique_ptr<AnimationOptions> options, - int num_effects) + std::unique_ptr<AnimationEffectTimings> effect_timings) : worklet_animation_id(worklet_animation_id), name(name), current_time(current_time), options(std::move(options)), - num_effects(num_effects) {} + effect_timings(std::move(effect_timings)) {} AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState( AddAndUpdateState&&) = default; AnimationWorkletInput::AddAndUpdateState::~AddAndUpdateState() = default; diff --git a/chromium/cc/trees/layer_tree_mutator.h b/chromium/cc/trees/layer_tree_mutator.h index fd5956c21fa..ff1c32579c6 100644 --- a/chromium/cc/trees/layer_tree_mutator.h +++ b/chromium/cc/trees/layer_tree_mutator.h @@ -9,6 +9,7 @@ #include "base/optional.h" #include "base/time/time.h" #include "cc/cc_export.h" +#include "cc/trees/animation_effect_timings.h" #include "cc/trees/animation_options.h" #include <memory> @@ -64,13 +65,13 @@ struct CC_EXPORT AnimationWorkletInput { // Worklet animation's current time, from its associated timeline. double current_time; std::unique_ptr<AnimationOptions> options; - int num_effects; + std::unique_ptr<AnimationEffectTimings> effect_timings; AddAndUpdateState(WorkletAnimationId worklet_animation_id, std::string name, double current_time, std::unique_ptr<AnimationOptions> options, - int num_effects); + std::unique_ptr<AnimationEffectTimings> effect_timings); AddAndUpdateState(AddAndUpdateState&&); ~AddAndUpdateState(); diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h index 644305bc425..092fb1b7ea3 100644 --- a/chromium/cc/trees/layer_tree_settings.h +++ b/chromium/cc/trees/layer_tree_settings.h @@ -172,11 +172,6 @@ class CC_EXPORT LayerTreeSettings { // go away and CC should send Blink fractional values: // https://crbug.com/414283. bool commit_fractional_scroll_deltas = false; - - // If true, LayerTreeHostImpl automatically allocates LocalSurfaceIds as - // necessary. If false, it is clients generate LocalSurfaceIds as necessary. - // TODO(sky): remove this once https://crbug.com/921129 is fixed. - bool automatically_allocate_surface_ids = true; }; } // namespace cc diff --git a/chromium/cc/trees/mutator_host.h b/chromium/cc/trees/mutator_host.h index 377579edb91..03e3ce4d4a0 100644 --- a/chromium/cc/trees/mutator_host.h +++ b/chromium/cc/trees/mutator_host.h @@ -26,9 +26,8 @@ class MutatorHostClient; class LayerTreeMutator; class ScrollTree; -// Used as the return value of MaximumTargetScale() and AnimationStartScale() to -// indicate that there is no active scale animation or the scale cannot be -// computed. +// Used as the return value of GetAnimationScales() to indicate that there is +// no active scale animation or the scale cannot be computed. const float kNotScaled = 0; // A MutatorHost owns all the animation and mutation effects. @@ -47,12 +46,13 @@ class MutatorHost { virtual void ClearMutators() = 0; + virtual void UpdateRegisteredElementIds(ElementListType changed_list) = 0; virtual void InitClientAnimationState() = 0; - virtual void RegisterElement(ElementId element_id, - ElementListType list_type) = 0; - virtual void UnregisterElement(ElementId element_id, + virtual void RegisterElementId(ElementId element_id, ElementListType list_type) = 0; + virtual void UnregisterElementId(ElementId element_id, + ElementListType list_type) = 0; virtual void SetMutatorHostClient(MutatorHostClient* client) = 0; @@ -66,7 +66,7 @@ class MutatorHost { base::TimeDelta duration) = 0; virtual bool NeedsTickAnimations() const = 0; - virtual bool ActivateAnimations() = 0; + virtual bool ActivateAnimations(MutatorEvents* events) = 0; // TODO(smcgruer): Once we only tick scroll-based animations on scroll, we // don't need to pass the scroll tree in here. virtual bool TickAnimations(base::TimeTicks monotonic_time, @@ -88,6 +88,9 @@ class MutatorHost { virtual bool IsAnimatingFilterProperty(ElementId element_id, ElementListType list_type) const = 0; + virtual bool IsAnimatingBackdropFilterProperty( + ElementId element_id, + ElementListType list_type) const = 0; virtual bool IsAnimatingOpacityProperty(ElementId element_id, ElementListType list_type) const = 0; virtual bool IsAnimatingTransformProperty( @@ -97,6 +100,9 @@ class MutatorHost { virtual bool HasPotentiallyRunningFilterAnimation( ElementId element_id, ElementListType list_type) const = 0; + virtual bool HasPotentiallyRunningBackdropFilterAnimation( + ElementId element_id, + ElementListType list_type) const = 0; virtual bool HasPotentiallyRunningOpacityAnimation( ElementId element_id, ElementListType list_type) const = 0; @@ -108,22 +114,18 @@ class MutatorHost { ElementId element_id, TargetProperty::Type property) const = 0; - virtual bool HasOnlyTranslationTransforms( - ElementId element_id, - ElementListType list_type) const = 0; virtual bool AnimationsPreserveAxisAlignment(ElementId element_id) const = 0; - // Returns the maximum scale along any dimension at any destination in active - // scale animations, or kNotScaled if there is no active scale animation or - // the maximum scale cannot be computed. - virtual float MaximumTargetScale(ElementId element_id, - ElementListType list_type) const = 0; - - // Returns the maximum of starting animation scale along any dimension at any - // destination in active scale animations, or kNotScaled if there is no active - // scale animation or the starting scale cannot be computed. - virtual float AnimationStartScale(ElementId element_id, - ElementListType list_type) const = 0; + // Gets scales transform animations. On return, |maximum_scale| is the maximum + // scale along any dimension at any destination in active scale animations, + // and |starting_scale| is the maximum of starting animation scale along any + // dimension at any destination in active scale animations. They are set to + // kNotScaled if there is no active scale animation or the scales cannot be + // computed. + virtual void GetAnimationScales(ElementId element_id, + ElementListType list_type, + float* maximum_scale, + float* starting_scale) const = 0; virtual bool IsElementAnimating(ElementId element_id) const = 0; virtual bool HasTickingKeyframeModelForTesting( diff --git a/chromium/cc/trees/mutator_host_client.h b/chromium/cc/trees/mutator_host_client.h index 44bad2c372b..5d221f3051c 100644 --- a/chromium/cc/trees/mutator_host_client.h +++ b/chromium/cc/trees/mutator_host_client.h @@ -29,8 +29,8 @@ enum class AnimationWorkletMutationState { class MutatorHostClient { public: - virtual bool IsElementInList(ElementId element_id, - ElementListType list_type) const = 0; + virtual bool IsElementInPropertyTrees(ElementId element_id, + ElementListType list_type) const = 0; virtual void SetMutatorsNeedCommit() = 0; virtual void SetMutatorsNeedRebuildPropertyTrees() = 0; @@ -38,6 +38,10 @@ class MutatorHostClient { virtual void SetElementFilterMutated(ElementId element_id, ElementListType list_type, const FilterOperations& filters) = 0; + virtual void SetElementBackdropFilterMutated( + ElementId element_id, + ElementListType list_type, + const FilterOperations& backdrop_filters) = 0; virtual void SetElementOpacityMutated(ElementId element_id, ElementListType list_type, float opacity) = 0; diff --git a/chromium/cc/trees/occlusion_tracker.cc b/chromium/cc/trees/occlusion_tracker.cc index 3c73e1d45bf..e4da0f3f7c4 100644 --- a/chromium/cc/trees/occlusion_tracker.cc +++ b/chromium/cc/trees/occlusion_tracker.cc @@ -341,6 +341,9 @@ void OcclusionTracker::MarkOccludedBehindLayer(const LayerImpl* layer) { if (layer->Is3dSorted()) return; + if (!layer->draw_properties().rounded_corner_bounds.IsEmpty()) + return; + SimpleEnclosedRegion opaque_layer_region = layer->VisibleOpaqueRegion(); if (opaque_layer_region.IsEmpty()) return; diff --git a/chromium/cc/trees/occlusion_tracker_unittest.cc b/chromium/cc/trees/occlusion_tracker_unittest.cc index 80d87380237..04827454e5e 100644 --- a/chromium/cc/trees/occlusion_tracker_unittest.cc +++ b/chromium/cc/trees/occlusion_tracker_unittest.cc @@ -166,17 +166,6 @@ class OcclusionTrackerTest : public testing::Test { return layer_ptr; } - LayerImpl* CreateMaskLayer(LayerImpl* owning_layer, const gfx::Size& bounds) { - LayerTreeImpl* tree = host_->host_impl()->active_tree(); - int id = next_layer_impl_id_++; - std::unique_ptr<TestContentLayerImpl> layer( - new TestContentLayerImpl(tree, id)); - TestContentLayerImpl* layer_ptr = layer.get(); - SetProperties(layer_ptr, identity_matrix, gfx::PointF(), bounds); - SetMask(owning_layer, std::move(layer)); - return layer_ptr; - } - TestContentLayerImpl* CreateDrawingSurface(LayerImpl* parent, const gfx::Transform& transform, const gfx::PointF& position, @@ -905,6 +894,11 @@ class OcclusionTrackerTestFilters : public OcclusionTrackerTest { parent, layer_transform, gfx::PointF(30.f, 30.f), gfx::Size(500, 500), true); + gfx::Transform rounded_corner_transform; + TestContentLayerImpl* rounded_corner_layer = this->CreateDrawingLayer( + parent, rounded_corner_transform, gfx::PointF(30.f, 30.f), + gfx::Size(500, 500), true); + blur_layer->test_properties()->force_render_surface = true; FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(10.f)); @@ -920,10 +914,19 @@ class OcclusionTrackerTestFilters : public OcclusionTrackerTest { filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); opacity_layer->test_properties()->filters = filters; + rounded_corner_layer->test_properties()->rounded_corner_bounds = + gfx::RRectF(1, 2, 3, 4, 5, 6); + this->CalcDrawEtc(parent); TestOcclusionTrackerWithClip occlusion(gfx::Rect(0, 0, 1000, 1000)); + // Rounded corners won't contribute to occlusion. + this->EnterLayer(rounded_corner_layer, &occlusion); + EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty()); + EXPECT_TRUE(occlusion.occlusion_from_inside_target().IsEmpty()); + this->LeaveLayer(rounded_corner_layer, &occlusion); + // Opacity layer won't contribute to occlusion. this->VisitLayer(opacity_layer, &occlusion); this->EnterContributingSurface(opacity_layer, &occlusion); diff --git a/chromium/cc/trees/paint_holding_commit_trigger.h b/chromium/cc/trees/paint_holding_commit_trigger.h new file mode 100644 index 00000000000..fcf4832a5b8 --- /dev/null +++ b/chromium/cc/trees/paint_holding_commit_trigger.h @@ -0,0 +1,28 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_TREES_PAINT_HOLDING_COMMIT_TRIGGER_H_ +#define CC_TREES_PAINT_HOLDING_COMMIT_TRIGGER_H_ + +namespace cc { + +enum class PaintHoldingCommitTrigger { + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + + // The Paint Holding flag is not enabled + kFeatureDisabled = 0, + // Paint Holding is not allowed due to different origin or wrong protocol + kDisallowed = 1, + // The commit was triggered by first contentful paint (FCP) + kFirstContentfulPaint = 2, + // The commit was triggered by a timeout waiting for FCP + kTimeout = 3, + // Required for UMA enum + kMaxValue = kTimeout +}; + +} // namespace cc + +#endif // CC_TREES_PAINT_HOLDING_COMMIT_TRIGGER_H_ diff --git a/chromium/cc/trees/presentation_time_callback_buffer.cc b/chromium/cc/trees/presentation_time_callback_buffer.cc new file mode 100644 index 00000000000..5274d5bdf1c --- /dev/null +++ b/chromium/cc/trees/presentation_time_callback_buffer.cc @@ -0,0 +1,117 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/trees/presentation_time_callback_buffer.h" + +#include <utility> +#include <vector> + +namespace cc { + +PresentationTimeCallbackBuffer::PresentationTimeCallbackBuffer() = default; + +PresentationTimeCallbackBuffer::PresentationTimeCallbackBuffer( + PresentationTimeCallbackBuffer&& other) + : frame_token_infos_(std::move(other.frame_token_infos_)) {} + +PresentationTimeCallbackBuffer& PresentationTimeCallbackBuffer::operator=( + PresentationTimeCallbackBuffer&& other) { + if (this != &other) { + frame_token_infos_ = std::move(other.frame_token_infos_); + } + return *this; +} + +PresentationTimeCallbackBuffer::~PresentationTimeCallbackBuffer() = default; + +PresentationTimeCallbackBuffer::FrameTokenInfo::FrameTokenInfo(uint32_t token) + : token(token) {} + +PresentationTimeCallbackBuffer::FrameTokenInfo::FrameTokenInfo( + FrameTokenInfo&&) = default; +PresentationTimeCallbackBuffer::FrameTokenInfo& +PresentationTimeCallbackBuffer::FrameTokenInfo::operator=(FrameTokenInfo&&) = + default; +PresentationTimeCallbackBuffer::FrameTokenInfo::~FrameTokenInfo() = default; + +void PresentationTimeCallbackBuffer::RegisterMainThreadPresentationCallbacks( + uint32_t frame_token, + std::vector<CallbackType> callbacks) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + FrameTokenInfo& frame_info = GetOrMakeRegistration(frame_token); + + // Splice the given |callbacks| onto the vector of existing callbacks. + auto& sink = frame_info.main_thread_callbacks; + sink.reserve(sink.size() + callbacks.size()); + std::move(callbacks.begin(), callbacks.end(), std::back_inserter(sink)); + + DCHECK_LE(frame_token_infos_.size(), 25u); +} + +void PresentationTimeCallbackBuffer::RegisterFrameTime( + uint32_t frame_token, + base::TimeTicks frame_time) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + FrameTokenInfo& frame_info = GetOrMakeRegistration(frame_token); + + // Protect against clobbering previously registered frame times. + DCHECK(frame_info.frame_time.is_null() || + frame_info.frame_time == frame_time); + frame_info.frame_time = frame_time; + + DCHECK_LE(frame_token_infos_.size(), 25u); +} + +PresentationTimeCallbackBuffer::PendingCallbacks::PendingCallbacks() = default; +PresentationTimeCallbackBuffer::PendingCallbacks::PendingCallbacks( + PendingCallbacks&&) = default; +PresentationTimeCallbackBuffer::PendingCallbacks& +PresentationTimeCallbackBuffer::PendingCallbacks::operator=( + PendingCallbacks&&) = default; +PresentationTimeCallbackBuffer::PendingCallbacks::~PendingCallbacks() = default; + +PresentationTimeCallbackBuffer::PendingCallbacks +PresentationTimeCallbackBuffer::PopPendingCallbacks(uint32_t frame_token) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + PendingCallbacks result; + + while (!frame_token_infos_.empty()) { + auto info = frame_token_infos_.begin(); + if (viz::FrameTokenGT(info->token, frame_token)) + break; + + // Forward compositor frame timings on exact frame token matches. These + // timings correspond to frames that caused on-screen damage. + if (info->token == frame_token && !info->frame_time.is_null()) + result.frame_time = info->frame_time; + + // Collect the main-thread callbacks. It's the caller's job to post them to + // the main thread. + std::move(info->main_thread_callbacks.begin(), + info->main_thread_callbacks.end(), + std::back_inserter(result.main_thread_callbacks)); + + frame_token_infos_.erase(info); + } + + return result; +} + +PresentationTimeCallbackBuffer::FrameTokenInfo& +PresentationTimeCallbackBuffer::GetOrMakeRegistration(uint32_t frame_token) { + // If the freshest registration is for an earlier frame token, add a new + // entry to the queue. + if (frame_token_infos_.empty() || + viz::FrameTokenGT(frame_token, frame_token_infos_.back().token)) { + frame_token_infos_.emplace_back(frame_token); + } + + // Registrations should use monotonically increasing frame tokens. + DCHECK_EQ(frame_token_infos_.back().token, frame_token); + + return frame_token_infos_.back(); +} + +} // namespace cc diff --git a/chromium/cc/trees/presentation_time_callback_buffer.h b/chromium/cc/trees/presentation_time_callback_buffer.h new file mode 100644 index 00000000000..cdebf905c36 --- /dev/null +++ b/chromium/cc/trees/presentation_time_callback_buffer.h @@ -0,0 +1,132 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef CC_TREES_PRESENTATION_TIME_CALLBACK_BUFFER_H_ +#define CC_TREES_PRESENTATION_TIME_CALLBACK_BUFFER_H_ + +#include <vector> + +#include "base/containers/circular_deque.h" +#include "base/sequence_checker.h" +#include "cc/trees/layer_tree_host.h" + +namespace cc { + +// Maintains a queue of callbacks and compositor frame times that we want to +// buffer until a relevant frame is presented. +// +// Callbacks are queued through |RegisterMainThreadPresentationCallbacks|. +// +// Once a frame is presented, users of this class can call +// |PopPendingCallbacks| to get their callbacks back. This class never runs +// callbacks itself so it's up to calling code to |PostTask| as needed. +// +// This class is thread unsafe so concurrent access would require external +// synchronization. In practice, however, instances of this class are only used +// on the compositor thread even though the buffered callbacks are intended to +// be run on the renderer main thread. +// +// CC_EXPORT is only needed for testing. +class CC_EXPORT PresentationTimeCallbackBuffer { + public: + using CallbackType = LayerTreeHost::PresentationTimeCallback; + + PresentationTimeCallbackBuffer(); + + PresentationTimeCallbackBuffer(const PresentationTimeCallbackBuffer&) = + delete; + PresentationTimeCallbackBuffer(PresentationTimeCallbackBuffer&&); + + PresentationTimeCallbackBuffer& operator=( + const PresentationTimeCallbackBuffer&) = delete; + PresentationTimeCallbackBuffer& operator=(PresentationTimeCallbackBuffer&&); + + ~PresentationTimeCallbackBuffer(); + + // Buffers the given |callbacks| in preparation for a GPU frame swap at or + // after the given |frame_token|. Calling code posts these callbacks to the + // main thread once they're popped. + void RegisterMainThreadPresentationCallbacks( + uint32_t frame_token, + std::vector<CallbackType> callbacks); + + // The given |frame_time| is associated with the given |frame_token| and will + // be exposed through |PopPendingCallbacks| if there is an exact frame token + // match. Note that it is an error to register distinct |frame_time|s against + // the same |frame_token|. + void RegisterFrameTime(uint32_t frame_token, base::TimeTicks frame_time); + + // Structured return value for |PopPendingCallbacks|. CC_EXPORT is only + // needed for testing. + struct CC_EXPORT PendingCallbacks { + PendingCallbacks(); + + PendingCallbacks(const PendingCallbacks&) = delete; + PendingCallbacks(PendingCallbacks&&); + + PendingCallbacks& operator=(const PendingCallbacks&) = delete; + PendingCallbacks& operator=(PendingCallbacks&&); + + ~PendingCallbacks(); + + // Holds callbacks registered through + // |RegisterMainThreadPresentationCallbacks|. + std::vector<CallbackType> main_thread_callbacks; + + // Note: calling code needs to test against frame_time.is_null() because + // frame_time is not always defined. See |PopPendingCallbacks|. + base::TimeTicks frame_time; + }; + + // Call this once the presentation for the given |frame_token| has completed. + // Yields any pending callbacks that were registered against a frame token + // that was less than or equal to the given |frame_token|. It is the caller's + // responsibility to run the callbacks on the right threads/sequences. When + // the given |frame_token| is an exact match to a registered entry, + // |frame_time| will be set to the frame time supplied through + // |RegisterFrameTime|. Otherwise, |frame_time| will be default constructed + // and should not be used. Calling code can assume |frame_time| is meaningful + // iff frame_time.is_null() returns false. + PendingCallbacks PopPendingCallbacks(uint32_t frame_token); + + private: + // Stores information needed once we get a response for a particular + // presentation token. + struct FrameTokenInfo { + explicit FrameTokenInfo(uint32_t token); + FrameTokenInfo(const FrameTokenInfo&) = delete; + FrameTokenInfo(FrameTokenInfo&&); + FrameTokenInfo& operator=(const FrameTokenInfo&) = delete; + FrameTokenInfo& operator=(FrameTokenInfo&&); + ~FrameTokenInfo(); + + // A |CompositorFrameMetadata::frame_token| that we use to associate + // presentation feedback with the relevant compositor frame. + uint32_t token; + + // A copy of the |frame_time| from the |BeginFrameArgs| associated with + // frame. Useful for tracking latency between frame requests and frame + // presentations. + base::TimeTicks frame_time; + + // The callbacks to send back to the main thread. + std::vector<CallbackType> main_thread_callbacks; + }; + + // Returns a reference to a |FrameTokenInfo| with the given |frame_token|. + // The instance is created if necessary and occupies the appropriate place in + // |frame_token_infos_|. + FrameTokenInfo& GetOrMakeRegistration(uint32_t frame_token); + + // Queue of pending registrations ordered by |token|. We can use a deque + // because we require callers to use non-decreasing tokens when registering. + base::circular_deque<FrameTokenInfo> frame_token_infos_; + + // When DCHECK is enabled, check that instances of this class aren't being + // used concurrently. + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace cc + +#endif // CC_TREES_PRESENTATION_TIME_CALLBACK_BUFFER_H_ diff --git a/chromium/cc/trees/presentation_time_callback_buffer_unittest.cc b/chromium/cc/trees/presentation_time_callback_buffer_unittest.cc new file mode 100644 index 00000000000..2d6b36f1f54 --- /dev/null +++ b/chromium/cc/trees/presentation_time_callback_buffer_unittest.cc @@ -0,0 +1,159 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/trees/presentation_time_callback_buffer.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +std::vector<cc::PresentationTimeCallbackBuffer::CallbackType> GenerateCallbacks( + int num_callbacks) { + std::vector<cc::PresentationTimeCallbackBuffer::CallbackType> result; + + while (num_callbacks-- > 0) { + // PresentationTimeCallbackBuffer isn't supposed to invoke any callbacks. + // We can check for that by passing callbacks which cause test failure. + result.emplace_back(base::BindOnce([](const gfx::PresentationFeedback&) { + FAIL() << "Callbacks should not be directly invoked by " + "PresentationTimeCallbackBuffer"; + })); + } + + return result; +} + +base::TimeTicks MakeTicks(uint64_t us) { + return base::TimeTicks() + base::TimeDelta::FromMicroseconds(us); +} + +constexpr uint32_t kFrameToken1 = 234; +constexpr uint32_t kFrameToken2 = 345; +constexpr uint32_t kFrameToken3 = 456; +constexpr uint32_t kFrameToken4 = 567; + +} // namespace + +namespace cc { + +TEST(PresentationTimeCallbackBufferTest, TestNoCallbacks) { + PresentationTimeCallbackBuffer buffer; + + auto result = buffer.PopPendingCallbacks(kFrameToken1); + + EXPECT_TRUE(result.main_thread_callbacks.empty()); + EXPECT_TRUE(result.frame_time.is_null()); +} + +TEST(PresentationTimeCallbackBufferTest, TestOneMainThreadCallback) { + PresentationTimeCallbackBuffer buffer; + + buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2, + GenerateCallbacks(1)); + + // Make sure that popping early frame tokens doesn't return irrelevant + // entries. + { + auto result = buffer.PopPendingCallbacks(kFrameToken1); + EXPECT_TRUE(result.main_thread_callbacks.empty()); + EXPECT_TRUE(result.frame_time.is_null()); + } + + { + auto result = buffer.PopPendingCallbacks(kFrameToken2); + EXPECT_EQ(result.main_thread_callbacks.size(), 1ull); + EXPECT_TRUE(result.frame_time.is_null()); + } + + // Make sure that the buffer has removed the registration since the "pop". + { + auto result = buffer.PopPendingCallbacks(kFrameToken2); + EXPECT_TRUE(result.main_thread_callbacks.empty()); + EXPECT_TRUE(result.frame_time.is_null()); + } +} + +TEST(PresentationTimeCallbackBufferTest, TestFrameTimeRegistration) { + PresentationTimeCallbackBuffer buffer; + + base::TimeTicks frame_time = MakeTicks(234); + buffer.RegisterFrameTime(kFrameToken2, frame_time); + + // Make sure that popping early frame tokens doesn't return irrelevant + // entries. + { + auto result = buffer.PopPendingCallbacks(kFrameToken1); + EXPECT_TRUE(result.main_thread_callbacks.empty()); + EXPECT_TRUE(result.frame_time.is_null()); + } + + { + auto result = buffer.PopPendingCallbacks(kFrameToken2); + EXPECT_TRUE(result.main_thread_callbacks.empty()); + EXPECT_FALSE(result.frame_time.is_null()); + EXPECT_EQ(result.frame_time, frame_time); + } + + // Make sure that the buffer has removed the registration since the "pop". + { + auto result = buffer.PopPendingCallbacks(kFrameToken2); + EXPECT_TRUE(result.main_thread_callbacks.empty()); + EXPECT_TRUE(result.frame_time.is_null()); + } +} + +TEST(PresentationTimeCallbackBufferTest, TestCallbackBatchingNoFrameTime) { + PresentationTimeCallbackBuffer buffer; + + base::TimeTicks frame_time1 = MakeTicks(123); + base::TimeTicks frame_time2 = MakeTicks(234); + base::TimeTicks frame_time4 = MakeTicks(456); + + // Register one callback for frame1, two for frame2 and two for frame4. + buffer.RegisterMainThreadPresentationCallbacks(kFrameToken1, + GenerateCallbacks(1)); + buffer.RegisterFrameTime(kFrameToken1, frame_time1); + buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2, + GenerateCallbacks(2)); + buffer.RegisterFrameTime(kFrameToken2, frame_time2); + buffer.RegisterMainThreadPresentationCallbacks(kFrameToken4, + GenerateCallbacks(2)); + buffer.RegisterFrameTime(kFrameToken4, frame_time4); + + // Pop callbacks up to and including frame3. Should be three in total; one + // from frame1 and two from frame2. There shouldn't be a frame time because + // no frame time was registered against exactly kFrameToken3. + { + auto result = buffer.PopPendingCallbacks(kFrameToken3); + EXPECT_EQ(result.main_thread_callbacks.size(), 3ull); + EXPECT_TRUE(result.frame_time.is_null()); + } +} + +TEST(PresentationTimeCallbackBufferTest, TestCallbackBatchingWithFrameTime) { + PresentationTimeCallbackBuffer buffer; + + base::TimeTicks frame_time3 = MakeTicks(345); + + // Register one callback for frame1, two for frame2 and two for frame4. + buffer.RegisterMainThreadPresentationCallbacks(kFrameToken1, + GenerateCallbacks(1)); + buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2, + GenerateCallbacks(2)); + buffer.RegisterFrameTime(kFrameToken3, frame_time3); + buffer.RegisterMainThreadPresentationCallbacks(kFrameToken4, + GenerateCallbacks(2)); + + // Pop callbacks up to and including frame3. Should be three in total; one + // from frame1 and two from frame2. There should be a frame time because + // a frame time was registered against exactly kFrameToken3. + { + auto result = buffer.PopPendingCallbacks(kFrameToken3); + EXPECT_EQ(result.main_thread_callbacks.size(), 3ull); + EXPECT_FALSE(result.frame_time.is_null()); + EXPECT_EQ(result.frame_time, frame_time3); + } +} + +} // namespace cc diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc index 9801773b479..5d6b0b82fa1 100644 --- a/chromium/cc/trees/property_tree.cc +++ b/chromium/cc/trees/property_tree.cc @@ -831,13 +831,13 @@ void EffectTree::UpdateHasMaskingChild(EffectNode* node, // when we actually encounter a masking child. node->has_masking_child = false; if (node->blend_mode == SkBlendMode::kDstIn) { - DCHECK(parent_node->has_render_surface); + DCHECK(parent_node->HasRenderSurface()); parent_node->has_masking_child = true; } } void EffectTree::UpdateSurfaceContentsScale(EffectNode* effect_node) { - if (!effect_node->has_render_surface) { + if (!effect_node->HasRenderSurface()) { effect_node->surface_contents_scale = gfx::Vector2dF(1.0f, 1.0f); return; } @@ -902,6 +902,20 @@ bool EffectTree::OnFilterAnimated(ElementId id, return true; } +bool EffectTree::OnBackdropFilterAnimated( + ElementId id, + const FilterOperations& backdrop_filters) { + EffectNode* node = FindNodeFromElementId(id); + DCHECK(node); + if (node->backdrop_filters == backdrop_filters) + return false; + node->backdrop_filters = backdrop_filters; + node->effect_changed = true; + property_trees()->changed = true; + property_trees()->effect_tree.set_needs_update(true); + return true; +} + void EffectTree::UpdateEffects(int id) { EffectNode* node = Node(id); EffectNode* parent_node = parent(node); @@ -951,7 +965,7 @@ void EffectTree::TakeCopyRequestsAndTransformToSurface( int node_id, std::vector<std::unique_ptr<viz::CopyOutputRequest>>* requests) { EffectNode* effect_node = Node(node_id); - DCHECK(effect_node->has_render_surface); + DCHECK(effect_node->HasRenderSurface()); DCHECK(effect_node->has_copy_request); // The area needs to be transformed from the space of content that draws to @@ -1071,7 +1085,7 @@ void EffectTree::UpdateRenderSurfaces(LayerTreeImpl* layer_tree_impl) { for (int id = kContentsRootNodeId; id < static_cast<int>(size()); ++id) { EffectNode* effect_node = Node(id); bool needs_render_surface = - id == kContentsRootNodeId || effect_node->has_render_surface; + id == kContentsRootNodeId || effect_node->HasRenderSurface(); if (needs_render_surface == !!render_surfaces_[id]) continue; @@ -1120,7 +1134,7 @@ bool EffectTree::CreateOrReuseRenderSurfaces( std::vector<std::pair<uint64_t, int>> stable_id_node_id_list; for (int id = kContentsRootNodeId; id < static_cast<int>(size()); ++id) { EffectNode* node = Node(id); - if (node->has_render_surface) { + if (node->HasRenderSurface()) { stable_id_node_id_list.push_back( std::make_pair(node->stable_id, node->id)); } @@ -1934,6 +1948,24 @@ bool PropertyTrees::ElementIsAnimatingChanged( << "Attempting to animate filter on non existent effect node"; } break; + case TargetProperty::BACKDROP_FILTER: + if (EffectNode* effect_node = + effect_tree.FindNodeFromElementId(element_id)) { + if (mask.currently_running[property]) + effect_node->is_currently_animating_backdrop_filter = + state.currently_running[property]; + if (mask.potentially_animating[property]) + effect_node->has_potential_backdrop_filter_animation = + state.potentially_animating[property]; + // Backdrop-filter animation changes only the node, and the subtree + // does not care, thus there is no need to request property tree + // update. + } else { + DCHECK_NODE_EXISTENCE(check_node_existence, state, property, + needs_rebuild) + << "Attempting to animate filter on non existent effect node"; + } + break; default: break; } @@ -2228,6 +2260,12 @@ ClipRectData* PropertyTrees::FetchClipRectFromCache(int clip_id, return &clip_node->cached_clip_rects->back(); } +bool PropertyTrees::HasElement(ElementId element_id) const { + return element_id_to_effect_node_index.contains(element_id) || + element_id_to_scroll_node_index.contains(element_id) || + element_id_to_transform_node_index.contains(element_id); +} + DrawTransforms& PropertyTrees::GetDrawTransforms(int transform_id, int effect_id) const { const EffectNode* effect_node = effect_tree.Node(effect_id); diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h index 3296420fe6f..f61d2c26a84 100644 --- a/chromium/cc/trees/property_tree.h +++ b/chromium/cc/trees/property_tree.h @@ -319,6 +319,8 @@ class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> { EffectNode* FindNodeFromElementId(ElementId id); bool OnOpacityAnimated(ElementId id, float opacity); bool OnFilterAnimated(ElementId id, const FilterOperations& filters); + bool OnBackdropFilterAnimated(ElementId id, + const FilterOperations& backdrop_filters); void UpdateEffects(int id); @@ -700,6 +702,8 @@ class CC_EXPORT PropertyTrees final { ClipRectData* FetchClipRectFromCache(int clip_id, int target_id); + bool HasElement(ElementId element_id) const; + private: gfx::Vector2dF inner_viewport_container_bounds_delta_; gfx::Vector2dF outer_viewport_container_bounds_delta_; diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc index 0e5434ee2b5..bd5882ee4f9 100644 --- a/chromium/cc/trees/property_tree_builder.cc +++ b/chromium/cc/trees/property_tree_builder.cc @@ -30,7 +30,6 @@ namespace cc { namespace { -template <typename LayerType> struct DataForRecursion { int transform_tree_parent; int transform_tree_parent_fixed; @@ -90,35 +89,30 @@ class PropertyTreeBuilderContext { private: void BuildPropertyTreesInternal( LayerType* layer, - const DataForRecursion<LayerType>& data_from_parent) const; + const DataForRecursion& data_from_parent) const; - bool AddTransformNodeIfNeeded( - const DataForRecursion<LayerType>& data_from_ancestor, - LayerType* layer, - bool created_render_surface, - DataForRecursion<LayerType>* data_for_children) const; + bool AddTransformNodeIfNeeded(const DataForRecursion& data_from_ancestor, + LayerType* layer, + bool created_render_surface, + DataForRecursion* data_for_children) const; - void AddClipNodeIfNeeded( - const DataForRecursion<LayerType>& data_from_ancestor, - LayerType* layer, - bool created_transform_node, - DataForRecursion<LayerType>* data_for_children) const; + void AddClipNodeIfNeeded(const DataForRecursion& data_from_ancestor, + LayerType* layer, + bool created_transform_node, + DataForRecursion* data_for_children) const; - bool AddEffectNodeIfNeeded( - const DataForRecursion<LayerType>& data_from_ancestor, - LayerType* layer, - DataForRecursion<LayerType>* data_for_children) const; + bool AddEffectNodeIfNeeded(const DataForRecursion& data_from_ancestor, + LayerType* layer, + DataForRecursion* data_for_children) const; - void AddScrollNodeIfNeeded( - const DataForRecursion<LayerType>& data_from_ancestor, - LayerType* layer, - DataForRecursion<LayerType>* data_for_children) const; + void AddScrollNodeIfNeeded(const DataForRecursion& data_from_ancestor, + LayerType* layer, + DataForRecursion* data_for_children) const; - bool UpdateRenderSurfaceIfNeeded( - int parent_effect_tree_id, - DataForRecursion<LayerType>* data_for_children, - bool subtree_has_rounded_corner, - bool created_transform_node) const; + bool UpdateRenderSurfaceIfNeeded(int parent_effect_tree_id, + DataForRecursion* data_for_children, + bool subtree_has_rounded_corner, + bool created_transform_node) const; LayerType* root_layer_; const LayerType* page_scale_layer_; @@ -207,18 +201,16 @@ static bool HasRoundedCorner(Layer* layer) { } static bool HasRoundedCorner(LayerImpl* layer) { - return false; + return !layer->test_properties()->rounded_corner_bounds.IsEmpty(); } static gfx::RRectF RoundedCornerBounds(Layer* layer) { - const std::array<uint32_t, 4> radii = layer->corner_radii(); - return gfx::RRectF(gfx::RectF(gfx::Rect(layer->bounds())), radii[0], radii[0], - radii[1], radii[1], radii[2], radii[2], radii[3], - radii[3]); + return gfx::RRectF(gfx::RectF(gfx::Rect(layer->bounds())), + layer->corner_radii()); } static gfx::RRectF RoundedCornerBounds(LayerImpl* layer) { - return gfx::RRectF(); + return layer->test_properties()->rounded_corner_bounds; } static PictureLayer* MaskLayer(Layer* layer) { @@ -286,21 +278,13 @@ bool HasPotentiallyRunningTransformAnimation(const MutatorHost& host, } template <typename LayerType> -bool HasOnlyTranslationTransforms(const MutatorHost& host, LayerType* layer) { - return host.HasOnlyTranslationTransforms(layer->element_id(), - layer->GetElementTypeForAnimation()); -} - -template <typename LayerType> -float MaximumAnimationScale(const MutatorHost& host, LayerType* layer) { - return host.MaximumTargetScale(layer->element_id(), - layer->GetElementTypeForAnimation()); -} - -template <typename LayerType> -float StartingAnimationScale(const MutatorHost& host, LayerType* layer) { - return host.AnimationStartScale(layer->element_id(), - layer->GetElementTypeForAnimation()); +void GetAnimationScales(const MutatorHost& host, + LayerType* layer, + float* maximum_scale, + float* starting_scale) { + return host.GetAnimationScales(layer->element_id(), + layer->GetElementTypeForAnimation(), + maximum_scale, starting_scale); } template <typename LayerType> @@ -319,8 +303,7 @@ bool HasAnyAnimationTargetingProperty(const MutatorHost& host, // ------------------------------------------------------------------- template <typename LayerType> -static int GetTransformParent(const DataForRecursion<LayerType>& data, - LayerType* layer) { +static int GetTransformParent(const DataForRecursion& data, LayerType* layer) { return PositionConstraint(layer).is_fixed_position() ? data.transform_tree_parent_fixed : data.transform_tree_parent; @@ -333,8 +316,7 @@ static bool LayerClipsSubtree(LayerType* layer) { } template <typename LayerType> -static int GetScrollParentId(const DataForRecursion<LayerType>& data, - LayerType* layer) { +static int GetScrollParentId(const DataForRecursion& data, LayerType* layer) { const bool inherits_scroll = !ScrollParent(layer); const int id = inherits_scroll ? data.scroll_tree_parent : ScrollParent(layer)->scroll_tree_index(); @@ -375,10 +357,10 @@ static inline bool HasLatestSequenceNumber(const LayerImpl*, int) { template <typename LayerType> void PropertyTreeBuilderContext<LayerType>::AddClipNodeIfNeeded( - const DataForRecursion<LayerType>& data_from_ancestor, + const DataForRecursion& data_from_ancestor, LayerType* layer, bool created_transform_node, - DataForRecursion<LayerType>* data_for_children) const { + DataForRecursion* data_for_children) const { const bool inherits_clip = !ClipParent(layer); // Sanity check the clip parent already built clip node before us. DCHECK(inherits_clip || @@ -445,10 +427,10 @@ static inline bool ShouldFlattenTransform(LayerImpl* layer) { template <typename LayerType> bool PropertyTreeBuilderContext<LayerType>::AddTransformNodeIfNeeded( - const DataForRecursion<LayerType>& data_from_ancestor, + const DataForRecursion& data_from_ancestor, LayerType* layer, bool created_render_surface, - DataForRecursion<LayerType>* data_for_children) const { + DataForRecursion* data_for_children) const { const bool is_root = !LayerParent(layer); const bool is_page_scale_layer = layer == page_scale_layer_; const bool is_overscroll_elasticity_layer = @@ -576,8 +558,8 @@ bool PropertyTreeBuilderContext<LayerType>::AddTransformNodeIfNeeded( node->has_potential_animation = has_potentially_animated_transform; node->is_currently_animating = TransformIsAnimating(mutator_host_, layer); - node->maximum_animation_scale = MaximumAnimationScale(mutator_host_, layer); - node->starting_animation_scale = StartingAnimationScale(mutator_host_, layer); + GetAnimationScales(mutator_host_, layer, &node->maximum_animation_scale, + &node->starting_animation_scale); float post_local_scale_factor = 1.0f; @@ -716,11 +698,11 @@ static inline bool CacheRenderSurface(LayerImpl* layer) { return layer->test_properties()->cache_render_surface; } -static inline bool ForceRenderSurface(Layer* layer) { +static inline bool ForceRenderSurfaceForTesting(Layer* layer) { return layer->force_render_surface_for_testing(); } -static inline bool ForceRenderSurface(LayerImpl* layer) { +static inline bool ForceRenderSurfaceForTesting(LayerImpl* layer) { return layer->test_properties()->force_render_surface; } @@ -805,11 +787,13 @@ static inline const FilterOperations& BackdropFilters(LayerImpl* layer) { return layer->test_properties()->backdrop_filters; } -static inline const gfx::RRectF& BackdropFilterBounds(Layer* layer) { +static inline const base::Optional<gfx::RRectF>& BackdropFilterBounds( + Layer* layer) { return layer->backdrop_filter_bounds(); } -static inline const gfx::RRectF& BackdropFilterBounds(LayerImpl* layer) { +static inline const base::Optional<gfx::RRectF>& BackdropFilterBounds( + LayerImpl* layer) { return layer->test_properties()->backdrop_filter_bounds; } @@ -846,40 +830,40 @@ static inline bool PropertyChanged(LayerImpl* layer) { } template <typename LayerType> -bool ShouldCreateRenderSurface(const MutatorHost& mutator_host, - LayerType* layer, - gfx::Transform current_transform, - bool animation_axis_aligned) { +RenderSurfaceReason ComputeRenderSurfaceReason(const MutatorHost& mutator_host, + LayerType* layer, + gfx::Transform current_transform, + bool animation_axis_aligned) { const bool preserves_2d_axis_alignment = current_transform.Preserves2dAxisAlignment() && animation_axis_aligned; const bool is_root = !LayerParent(layer); if (is_root) - return true; + return RenderSurfaceReason::kRoot; // If the layer uses a mask. if (MaskLayer(layer)) { - return true; + return RenderSurfaceReason::kMask; } // If the layer uses trilinear filtering. if (TrilinearFiltering(layer)) { - return true; + return RenderSurfaceReason::kTrilinearFiltering; } // If the layer uses a CSS filter. if (!Filters(layer).IsEmpty()) { - return true; + return RenderSurfaceReason::kFilter; } // If the layer uses a CSS backdrop-filter. if (!BackdropFilters(layer).IsEmpty()) { - return true; + return RenderSurfaceReason::kBackdropFilter; } // If the layer will use a CSS filter. In this case, the animation // will start and add a filter to this layer, so it needs a surface. if (HasPotentiallyRunningFilterAnimation(mutator_host, layer)) { - return true; + return RenderSurfaceReason::kFilterAnimation; } int num_descendants_that_draw_content = NumDescendantsThatDrawContent(layer); @@ -888,15 +872,12 @@ bool ShouldCreateRenderSurface(const MutatorHost& mutator_host, // parent (i.e. parent participates in a 3D rendering context). if (LayerIsInExisting3DRenderingContext(layer) && ShouldFlattenTransform(layer) && num_descendants_that_draw_content > 0) { - TRACE_EVENT_INSTANT0( - "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface flattening", - TRACE_EVENT_SCOPE_THREAD); - return true; + return RenderSurfaceReason::k3dTransformFlattening; } if (!IsFastRoundedCorner(layer) && HasRoundedCorner(layer) && num_descendants_that_draw_content > 1) { - return true; + return RenderSurfaceReason::kRoundedCorner; } // If the layer has blending. @@ -904,20 +885,14 @@ bool ShouldCreateRenderSurface(const MutatorHost& mutator_host, // types of quads than viz::RenderPassDrawQuad. Layers having descendants that // draw content will still create a separate rendering surface. if (BlendMode(layer) != SkBlendMode::kSrcOver) { - TRACE_EVENT_INSTANT0( - "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface blending", - TRACE_EVENT_SCOPE_THREAD); - return true; + return RenderSurfaceReason::kBlendMode; } // If the layer clips its descendants but it is not axis-aligned with respect // to its parent. bool layer_clips_external_content = LayerClipsSubtree(layer); if (layer_clips_external_content && !preserves_2d_axis_alignment && num_descendants_that_draw_content > 0) { - TRACE_EVENT_INSTANT0( - "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface clipping", - TRACE_EVENT_SCOPE_THREAD); - return true; + return RenderSurfaceReason::kClipAxisAlignment; } // If the layer has some translucency and does not have a preserves-3d @@ -934,11 +909,8 @@ bool ShouldCreateRenderSurface(const MutatorHost& mutator_host, HasPotentiallyRunningOpacityAnimation(mutator_host, layer); if (may_have_transparency && ShouldFlattenTransform(layer) && at_least_two_layers_in_subtree_draw_content) { - TRACE_EVENT_INSTANT0( - "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface opacity", - TRACE_EVENT_SCOPE_THREAD); DCHECK(!is_root); - return true; + return RenderSurfaceReason::kOpacity; } // If the layer has isolation. // TODO(rosca): to be optimized - create separate rendering surface only when @@ -946,25 +918,22 @@ bool ShouldCreateRenderSurface(const MutatorHost& mutator_host, // (layer has transparent background or descendants overflow). // https://code.google.com/p/chromium/issues/detail?id=301738 if (IsRootForIsolatedGroup(layer)) { - TRACE_EVENT_INSTANT0( - "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface isolation", - TRACE_EVENT_SCOPE_THREAD); - return true; + return RenderSurfaceReason::kRootOrIsolatedGroup; } // If we force it. - if (ForceRenderSurface(layer)) - return true; + if (ForceRenderSurfaceForTesting(layer)) + return RenderSurfaceReason::kTest; // If we cache it. if (CacheRenderSurface(layer)) - return true; + return RenderSurfaceReason::kCache; // If we'll make a copy of the layer's contents. if (HasCopyRequest(layer)) - return true; + return RenderSurfaceReason::kCopyRequest; - return false; + return RenderSurfaceReason::kNone; } static void TakeCopyRequests( @@ -1015,9 +984,9 @@ bool UpdateSubtreeHasCopyRequestRecursive(LayerType* layer) { template <typename LayerType> bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded( - const DataForRecursion<LayerType>& data_from_ancestor, + const DataForRecursion& data_from_ancestor, LayerType* layer, - DataForRecursion<LayerType>* data_for_children) const { + DataForRecursion* data_for_children) const { const bool is_root = !LayerParent(layer); const bool has_transparency = EffectiveOpacity(layer) != 1.f; const bool has_potential_opacity_animation = @@ -1028,10 +997,12 @@ bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded( data_for_children->animation_axis_aligned_since_render_target &= AnimationsPreserveAxisAlignment(mutator_host_, layer); data_for_children->compound_transform_since_render_target *= Transform(layer); - const bool should_create_render_surface = ShouldCreateRenderSurface( + auto render_surface_reason = ComputeRenderSurfaceReason( mutator_host_, layer, data_for_children->compound_transform_since_render_target, data_for_children->animation_axis_aligned_since_render_target); + bool should_create_render_surface = + render_surface_reason != RenderSurfaceReason::kNone; bool not_axis_aligned_since_last_clip = data_from_ancestor.not_axis_aligned_since_last_clip @@ -1063,7 +1034,6 @@ bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded( node->opacity = Opacity(layer); node->blend_mode = BlendMode(layer); node->unscaled_mask_target_size = layer->bounds(); - node->has_render_surface = should_create_render_surface; node->cache_render_surface = CacheRenderSurface(layer); node->has_copy_request = HasCopyRequest(layer); node->filters = Filters(layer); @@ -1081,6 +1051,7 @@ bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded( node->is_currently_animating_filter = FilterIsAnimating(mutator_host_, layer); node->effect_changed = PropertyChanged(layer); node->subtree_has_copy_request = SubtreeHasCopyRequest(layer); + node->render_surface_reason = render_surface_reason; node->closest_ancestor_with_cached_render_surface_id = CacheRenderSurface(layer) ? node_id @@ -1157,7 +1128,7 @@ bool PropertyTreeBuilderContext<LayerType>::AddEffectNodeIfNeeded( template <typename LayerType> bool PropertyTreeBuilderContext<LayerType>::UpdateRenderSurfaceIfNeeded( int parent_effect_tree_id, - DataForRecursion<LayerType>* data_for_children, + DataForRecursion* data_for_children, bool subtree_has_rounded_corner, bool created_transform_node) const { // No effect node was generated for this layer. @@ -1180,7 +1151,7 @@ bool PropertyTreeBuilderContext<LayerType>::UpdateRenderSurfaceIfNeeded( // single rrect per quad at draw time, it would be unable to handle // intersections thus resulting in artifacts. if (subtree_has_rounded_corner && has_rounded_corner) - effect_node->has_render_surface = true; + effect_node->render_surface_reason = RenderSurfaceReason::kRoundedCorner; // Inform the parent that its subtree has rounded corners if one of the two // scenario is true: @@ -1191,9 +1162,9 @@ bool PropertyTreeBuilderContext<LayerType>::UpdateRenderSurfaceIfNeeded( // surface of its own to prevent blending artifacts due to intersecting // rounded corners. *data_for_children->subtree_has_rounded_corner = - (subtree_has_rounded_corner && !effect_node->has_render_surface) || + (subtree_has_rounded_corner && !effect_node->HasRenderSurface()) || has_rounded_corner; - return effect_node->has_render_surface; + return effect_node->HasRenderSurface(); } static inline bool UserScrollableHorizontal(Layer* layer) { @@ -1245,9 +1216,9 @@ void SetHasTransformNode(LayerType* layer, bool val) { template <typename LayerType> void PropertyTreeBuilderContext<LayerType>::AddScrollNodeIfNeeded( - const DataForRecursion<LayerType>& data_from_ancestor, + const DataForRecursion& data_from_ancestor, LayerType* layer, - DataForRecursion<LayerType>* data_for_children) const { + DataForRecursion* data_for_children) const { int parent_id = GetScrollParentId(data_from_ancestor, layer); bool is_root = !LayerParent(layer); @@ -1339,10 +1310,9 @@ void SetBackfaceVisibilityTransform(LayerType* layer, } template <typename LayerType> -void SetSafeOpaqueBackgroundColor( - const DataForRecursion<LayerType>& data_from_ancestor, - LayerType* layer, - DataForRecursion<LayerType>* data_for_children) { +void SetSafeOpaqueBackgroundColor(const DataForRecursion& data_from_ancestor, + LayerType* layer, + DataForRecursion* data_for_children) { SkColor background_color = layer->background_color(); data_for_children->safe_opaque_background_color = SkColorGetA(background_color) == 255 @@ -1363,10 +1333,10 @@ static void SetLayerPropertyChangedForChild(LayerImpl* parent, template <typename LayerType> void PropertyTreeBuilderContext<LayerType>::BuildPropertyTreesInternal( LayerType* layer, - const DataForRecursion<LayerType>& data_from_parent) const { + const DataForRecursion& data_from_parent) const { layer->set_property_tree_sequence_number(property_trees_.sequence_number); - DataForRecursion<LayerType> data_for_children(data_from_parent); + DataForRecursion data_for_children(data_from_parent); *data_for_children.subtree_has_rounded_corner = false; bool created_render_surface = @@ -1498,7 +1468,7 @@ void PropertyTreeBuilderContext<LayerType>::BuildPropertyTrees( return; } - DataForRecursion<LayerType> data_for_recursion; + DataForRecursion data_for_recursion; data_for_recursion.transform_tree_parent = TransformTree::kInvalidNodeId; data_for_recursion.transform_tree_parent_fixed = TransformTree::kInvalidNodeId; diff --git a/chromium/cc/trees/property_tree_unittest.cc b/chromium/cc/trees/property_tree_unittest.cc index 1e0a02ae142..848d6e057fb 100644 --- a/chromium/cc/trees/property_tree_unittest.cc +++ b/chromium/cc/trees/property_tree_unittest.cc @@ -195,7 +195,8 @@ TEST(PropertyTreeTest, TransformsWithFlattening) { int grand_parent = tree.Insert(TransformNode(), 0); int effect_grand_parent = effect_tree.Insert(EffectNode(), 0); - effect_tree.Node(effect_grand_parent)->has_render_surface = true; + effect_tree.Node(effect_grand_parent)->render_surface_reason = + RenderSurfaceReason::kTest; effect_tree.Node(effect_grand_parent)->transform_id = grand_parent; effect_tree.Node(effect_grand_parent)->surface_contents_scale = gfx::Vector2dF(1.f, 1.f); @@ -207,7 +208,8 @@ TEST(PropertyTreeTest, TransformsWithFlattening) { int parent = tree.Insert(TransformNode(), grand_parent); int effect_parent = effect_tree.Insert(EffectNode(), effect_grand_parent); effect_tree.Node(effect_parent)->transform_id = parent; - effect_tree.Node(effect_parent)->has_render_surface = true; + effect_tree.Node(effect_parent)->render_surface_reason = + RenderSurfaceReason::kTest; effect_tree.Node(effect_parent)->surface_contents_scale = gfx::Vector2dF(1.f, 1.f); tree.Node(parent)->source_node_id = grand_parent; @@ -493,7 +495,8 @@ TEST(PropertyTreeTest, SingularTransformSnapTest) { int parent = tree.Insert(TransformNode(), 0); int effect_parent = effect_tree.Insert(EffectNode(), 0); - effect_tree.Node(effect_parent)->has_render_surface = true; + effect_tree.Node(effect_parent)->render_surface_reason = + RenderSurfaceReason::kTest; effect_tree.Node(effect_parent)->surface_contents_scale = gfx::Vector2dF(1.f, 1.f); tree.Node(parent)->scrolls = true; @@ -547,7 +550,7 @@ TEST(EffectTreeTest, CopyOutputRequestsAreTransformed) { EffectTree& effect_tree = property_trees.effect_tree; EffectNode effect_node; - effect_node.has_render_surface = true; + effect_node.render_surface_reason = RenderSurfaceReason::kTest; effect_node.has_copy_request = true; effect_node.transform_id = contents_root.id; effect_node.id = effect_tree.Insert(effect_node, 0); @@ -646,7 +649,7 @@ TEST(EffectTreeTest, CopyOutputRequestsThatBecomeIllegalAreDropped) { EffectTree& effect_tree = property_trees.effect_tree; EffectNode effect_node; - effect_node.has_render_surface = true; + effect_node.render_surface_reason = RenderSurfaceReason::kTest; effect_node.has_copy_request = true; effect_node.transform_id = contents_root.id; effect_node.id = effect_tree.Insert(effect_node, 0); diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h index b275bc84635..10a58a32998 100644 --- a/chromium/cc/trees/proxy.h +++ b/chromium/cc/trees/proxy.h @@ -5,8 +5,6 @@ #ifndef CC_TREES_PROXY_H_ #define CC_TREES_PROXY_H_ -#include <stdint.h> - #include <memory> #include <string> @@ -17,6 +15,7 @@ #include "base/values.h" #include "cc/cc_export.h" #include "cc/input/browser_controls_state.h" +#include "cc/trees/paint_holding_commit_trigger.h" #include "cc/trees/task_runner_provider.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "services/metrics/public/cpp/ukm_source_id.h" @@ -71,7 +70,7 @@ class CC_EXPORT Proxy { virtual void StartDeferringCommits(base::TimeDelta timeout) = 0; // Immediately stop deferring commits. - virtual void StopDeferringCommits() = 0; + virtual void StopDeferringCommits(PaintHoldingCommitTrigger) = 0; virtual bool CommitRequested() const = 0; @@ -93,13 +92,10 @@ class CC_EXPORT Proxy { virtual void RequestBeginMainFrameNotExpected(bool new_state) = 0; - // See description in LayerTreeHost - virtual uint32_t GenerateChildSurfaceSequenceNumberSync() = 0; - // Testing hooks virtual bool MainFrameWillHappenForTesting() = 0; - virtual void SetURLForUkm(const GURL& url) = 0; + virtual void SetSourceURL(ukm::SourceId source_id, const GURL& url) = 0; virtual void ClearHistory() = 0; diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc index 9d5f067d3d0..cdfd8d3a135 100644 --- a/chromium/cc/trees/proxy_impl.cc +++ b/chromium/cc/trees/proxy_impl.cc @@ -497,13 +497,6 @@ void ProxyImpl::DidPresentCompositorFrameOnImplThread( std::move(callbacks), feedback)); } -void ProxyImpl::DidGenerateLocalSurfaceIdAllocationOnImplThread( - const viz::LocalSurfaceIdAllocation& allocation) { - MainThreadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&ProxyMain::DidGenerateLocalSurfaceIdAllocation, - proxy_main_weak_ptr_, allocation)); -} - void ProxyImpl::NotifyAnimationWorkletStateChange( AnimationWorkletMutationState state, ElementListType element_list_type) { @@ -745,9 +738,9 @@ base::SingleThreadTaskRunner* ProxyImpl::MainThreadTaskRunner() { return task_runner_provider_->MainThreadTaskRunner(); } -void ProxyImpl::SetURLForUkm(const GURL& url) { +void ProxyImpl::SetSourceURL(ukm::SourceId source_id, const GURL& url) { DCHECK(IsImplThread()); - host_impl_->SetActiveURL(url); + host_impl_->SetActiveURL(url, source_id); } void ProxyImpl::ClearHistory() { diff --git a/chromium/cc/trees/proxy_impl.h b/chromium/cc/trees/proxy_impl.h index 4916e5a09a6..62636b88386 100644 --- a/chromium/cc/trees/proxy_impl.h +++ b/chromium/cc/trees/proxy_impl.h @@ -58,7 +58,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, LayerTreeHost* layer_tree_host, base::TimeTicks main_thread_start_time, bool hold_commit_for_activation); - void SetURLForUkm(const GURL& url); + void SetSourceURL(ukm::SourceId source_id, const GURL& url); void ClearHistory(); void SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer); @@ -109,8 +109,6 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient, uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback) override; - void DidGenerateLocalSurfaceIdAllocationOnImplThread( - const viz::LocalSurfaceIdAllocation& allocation) override; void NotifyAnimationWorkletStateChange( AnimationWorkletMutationState state, ElementListType element_list_type) override; diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc index 8cb9c0516b2..20299713e6a 100644 --- a/chromium/cc/trees/proxy_main.cc +++ b/chromium/cc/trees/proxy_main.cc @@ -39,7 +39,7 @@ ProxyMain::ProxyMain(LayerTreeHost* layer_tree_host, commit_waits_for_activation_(false), started_(false), defer_main_frame_update_(false), - defer_commits_(false), + defer_commits_(true), frame_sink_bound_weak_factory_(this), weak_factory_(this) { TRACE_EVENT0("cc", "ProxyMain::ProxyMain"); @@ -232,7 +232,7 @@ void ProxyMain::BeginMainFrame( // Check now if we should stop deferring commits if (defer_commits_ && base::TimeTicks::Now() > commits_restart_time_) { - StopDeferringCommits(); + StopDeferringCommits(PaintHoldingCommitTrigger::kTimeout); } // At this point the main frame may have deferred commits to avoid committing @@ -360,11 +360,6 @@ void ProxyMain::DidPresentCompositorFrame( feedback); } -void ProxyMain::DidGenerateLocalSurfaceIdAllocation( - const viz::LocalSurfaceIdAllocation& allocation) { - layer_tree_host_->DidGenerateLocalSurfaceIdAllocation(allocation); -} - bool ProxyMain::IsStarted() const { DCHECK(IsMainThread()); return started_; @@ -480,10 +475,11 @@ void ProxyMain::StartDeferringCommits(base::TimeDelta timeout) { commits_restart_time_ = base::TimeTicks::Now() + timeout; } -void ProxyMain::StopDeferringCommits() { +void ProxyMain::StopDeferringCommits(PaintHoldingCommitTrigger trigger) { if (!defer_commits_) return; defer_commits_ = false; + UMA_HISTOGRAM_ENUMERATION("PaintHolding.CommitTrigger", trigger); commits_restart_time_ = base::TimeTicks(); TRACE_EVENT_ASYNC_END0("cc", "ProxyMain::SetDeferCommits", this); } @@ -547,9 +543,9 @@ void ProxyMain::Stop() { void ProxyMain::SetMutator(std::unique_ptr<LayerTreeMutator> mutator) { TRACE_EVENT0("cc", "ThreadProxy::SetMutator"); ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&ProxyImpl::InitializeMutatorOnImpl, - base::Unretained(proxy_impl_.get()), - base::Passed(std::move(mutator)))); + FROM_HERE, + base::BindOnce(&ProxyImpl::InitializeMutatorOnImpl, + base::Unretained(proxy_impl_.get()), std::move(mutator))); } void ProxyMain::SetPaintWorkletLayerPainter( @@ -558,20 +554,13 @@ void ProxyMain::SetPaintWorkletLayerPainter( ImplThreadTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&ProxyImpl::InitializePaintWorkletLayerPainterOnImpl, - base::Unretained(proxy_impl_.get()), - base::Passed(std::move(painter)))); + base::Unretained(proxy_impl_.get()), std::move(painter))); } bool ProxyMain::SupportsImplScrolling() const { return true; } -uint32_t ProxyMain::GenerateChildSurfaceSequenceNumberSync() { - // This function only makes sense for single-threaded mode. - NOTREACHED(); - return 0u; -} - bool ProxyMain::MainFrameWillHappenForTesting() { DCHECK(IsMainThread()); bool main_frame_will_happen = false; @@ -645,11 +634,12 @@ base::SingleThreadTaskRunner* ProxyMain::ImplThreadTaskRunner() { return task_runner_provider_->ImplThreadTaskRunner(); } -void ProxyMain::SetURLForUkm(const GURL& url) { +void ProxyMain::SetSourceURL(ukm::SourceId source_id, const GURL& url) { DCHECK(IsMainThread()); ImplThreadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&ProxyImpl::SetURLForUkm, - base::Unretained(proxy_impl_.get()), url)); + FROM_HERE, base::BindOnce(&ProxyImpl::SetSourceURL, + base::Unretained(proxy_impl_.get()), + source_id, url)); } void ProxyMain::ClearHistory() { diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h index a9e5fb4c06f..7b110c08a7d 100644 --- a/chromium/cc/trees/proxy_main.h +++ b/chromium/cc/trees/proxy_main.h @@ -10,10 +10,6 @@ #include "cc/trees/proxy.h" #include "cc/trees/proxy_common.h" -namespace viz { -class LocalSurfaceIdAllocation; -} - namespace cc { class MutatorEvents; @@ -62,8 +58,6 @@ class CC_EXPORT ProxyMain : public Proxy { uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback); - void DidGenerateLocalSurfaceIdAllocation( - const viz::LocalSurfaceIdAllocation& allocation); CommitPipelineStage max_requested_pipeline_stage() const { return max_requested_pipeline_stage_; @@ -90,7 +84,7 @@ class CC_EXPORT ProxyMain : public Proxy { bool RequestedAnimatePending() override; void SetDeferMainFrameUpdate(bool defer_main_frame_update) override; void StartDeferringCommits(base::TimeDelta timeout) override; - void StopDeferringCommits() override; + void StopDeferringCommits(PaintHoldingCommitTrigger) override; bool CommitRequested() const override; void Start() override; void Stop() override; @@ -98,14 +92,13 @@ class CC_EXPORT ProxyMain : public Proxy { void SetMutator(std::unique_ptr<LayerTreeMutator> mutator) override; void SetPaintWorkletLayerPainter( std::unique_ptr<PaintWorkletLayerPainter> painter) override; - uint32_t GenerateChildSurfaceSequenceNumberSync() override; bool MainFrameWillHappenForTesting() override; void ReleaseLayerTreeFrameSink() override; void UpdateBrowserControlsState(BrowserControlsState constraints, BrowserControlsState current, bool animate) override; void RequestBeginMainFrameNotExpected(bool new_state) override; - void SetURLForUkm(const GURL& url) override; + void SetSourceURL(ukm::SourceId source_id, const GURL& url) override; void ClearHistory() override; void SetRenderFrameObserver( std::unique_ptr<RenderFrameMetadataObserver> observer) override; diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc index 8a5393d776d..d74fe26e408 100644 --- a/chromium/cc/trees/single_thread_proxy.cc +++ b/chromium/cc/trees/single_thread_proxy.cc @@ -50,7 +50,7 @@ SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host, #endif inside_draw_(false), defer_main_frame_update_(false), - defer_commits_(false), + defer_commits_(true), animate_requested_(false), commit_requested_(false), inside_synchronous_composite_(false), @@ -300,11 +300,13 @@ void SingleThreadProxy::StartDeferringCommits(base::TimeDelta timeout) { commits_restart_time_ = base::TimeTicks::Now() + timeout; } -void SingleThreadProxy::StopDeferringCommits() { +void SingleThreadProxy::StopDeferringCommits( + PaintHoldingCommitTrigger trigger) { if (!defer_commits_) return; defer_commits_ = false; commits_restart_time_ = base::TimeTicks(); + UMA_HISTOGRAM_ENUMERATION("PaintHolding.CommitTrigger", trigger); TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this); } @@ -525,23 +527,12 @@ void SingleThreadProxy::DidPresentCompositorFrameOnImplThread( feedback); } -void SingleThreadProxy::DidGenerateLocalSurfaceIdAllocationOnImplThread( - const viz::LocalSurfaceIdAllocation& allocation) { - DebugScopedSetMainThread main(task_runner_provider_); - layer_tree_host_->DidGenerateLocalSurfaceIdAllocation(allocation); -} - void SingleThreadProxy::NotifyAnimationWorkletStateChange( AnimationWorkletMutationState state, ElementListType element_list_type) { layer_tree_host_->NotifyAnimationWorkletStateChange(state, element_list_type); } -uint32_t SingleThreadProxy::GenerateChildSurfaceSequenceNumberSync() { - DebugScopedSetImplThread impl(task_runner_provider_); - return host_impl_->GenerateChildSurfaceSequenceNumberSync(); -} - void SingleThreadProxy::RequestBeginMainFrameNotExpected(bool new_state) { if (scheduler_on_impl_thread_) { scheduler_on_impl_thread_->SetMainThreadWantsBeginMainFrameNotExpected( @@ -813,7 +804,7 @@ void SingleThreadProxy::BeginMainFrame( // Check now if we should stop deferring commits if (defer_commits_ && base::TimeTicks::Now() > commits_restart_time_) { - StopDeferringCommits(); + StopDeferringCommits(PaintHoldingCommitTrigger::kTimeout); } // At this point the main frame may have deferred commits to avoid committing diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h index 24f95bfb7ad..97a449b3442 100644 --- a/chromium/cc/trees/single_thread_proxy.h +++ b/chromium/cc/trees/single_thread_proxy.h @@ -54,7 +54,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy, bool RequestedAnimatePending() override; void SetDeferMainFrameUpdate(bool defer_main_frame_update) override; void StartDeferringCommits(base::TimeDelta timeout) override; - void StopDeferringCommits() override; + void StopDeferringCommits(PaintHoldingCommitTrigger) override; bool CommitRequested() const override; void Start() override; void Stop() override; @@ -63,7 +63,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy, std::unique_ptr<PaintWorkletLayerPainter> painter) override; bool SupportsImplScrolling() const override; bool MainFrameWillHappenForTesting() override; - void SetURLForUkm(const GURL& url) override { + void SetSourceURL(ukm::SourceId source_id, const GURL& url) override { // Single-threaded mode is only for browser compositing and for renderers in // layout tests. This will still get called in the latter case, but we don't // need to record UKM in that case. @@ -126,14 +126,11 @@ class CC_EXPORT SingleThreadProxy : public Proxy, bool skip_draw) override; void NeedsImplSideInvalidation(bool needs_first_draw_on_activation) override; void RequestBeginMainFrameNotExpected(bool new_state) override; - uint32_t GenerateChildSurfaceSequenceNumberSync() override; void NotifyImageDecodeRequestFinished() override; void DidPresentCompositorFrameOnImplThread( uint32_t frame_token, std::vector<LayerTreeHost::PresentationTimeCallback> callbacks, const gfx::PresentationFeedback& feedback) override; - void DidGenerateLocalSurfaceIdAllocationOnImplThread( - const viz::LocalSurfaceIdAllocation& allocation) override; void NotifyAnimationWorkletStateChange( AnimationWorkletMutationState state, ElementListType element_list_type) override; diff --git a/chromium/cc/trees/swap_promise.h b/chromium/cc/trees/swap_promise.h index b8663a61aa5..b5638c9e391 100644 --- a/chromium/cc/trees/swap_promise.h +++ b/chromium/cc/trees/swap_promise.h @@ -52,13 +52,20 @@ class CC_EXPORT SwapPromise { ACTIVATION_FAILS, }; + enum class DidNotSwapAction { + BREAK_PROMISE, + KEEP_ACTIVE, + }; + SwapPromise() {} virtual ~SwapPromise() {} virtual void DidActivate() = 0; virtual void WillSwap(viz::CompositorFrameMetadata* metadata) = 0; virtual void DidSwap() = 0; - virtual void DidNotSwap(DidNotSwapReason reason) = 0; + // Return |KEEP_ACTIVE| if this promise should remain active (should not be + // broken by the owner). + virtual DidNotSwapAction DidNotSwap(DidNotSwapReason reason) = 0; // This is called when the main thread starts a (blocking) commit virtual void OnCommit() {} diff --git a/chromium/cc/trees/swap_promise_manager.cc b/chromium/cc/trees/swap_promise_manager.cc index 939cc02d1f6..76c2488d2e0 100644 --- a/chromium/cc/trees/swap_promise_manager.cc +++ b/chromium/cc/trees/swap_promise_manager.cc @@ -50,9 +50,14 @@ SwapPromiseManager::TakeSwapPromises() { void SwapPromiseManager::BreakSwapPromises( SwapPromise::DidNotSwapReason reason) { - for (const auto& swap_promise : swap_promise_list_) - swap_promise->DidNotSwap(reason); - swap_promise_list_.clear(); + std::vector<std::unique_ptr<SwapPromise>> keep_active_swap_promises; + for (auto& swap_promise : swap_promise_list_) { + if (swap_promise->DidNotSwap(reason) == + SwapPromise::DidNotSwapAction::KEEP_ACTIVE) { + keep_active_swap_promises.push_back(std::move(swap_promise)); + } + } + swap_promise_list_.swap(keep_active_swap_promises); } } // namespace cc diff --git a/chromium/cc/trees/swap_promise_manager_unittest.cc b/chromium/cc/trees/swap_promise_manager_unittest.cc index d88818e90e2..154feb117f0 100644 --- a/chromium/cc/trees/swap_promise_manager_unittest.cc +++ b/chromium/cc/trees/swap_promise_manager_unittest.cc @@ -32,7 +32,9 @@ class MockSwapPromise : public SwapPromise { void DidActivate() override {} void WillSwap(viz::CompositorFrameMetadata* metadata) override {} void DidSwap() override {} - void DidNotSwap(DidNotSwapReason reason) override {} + DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override { + return DidNotSwapAction::BREAK_PROMISE; + } MOCK_METHOD0(OnCommit, void()); int64_t TraceId() const override { return 0; } }; diff --git a/chromium/cc/trees/target_property.h b/chromium/cc/trees/target_property.h index f28649ce203..407090f27c4 100644 --- a/chromium/cc/trees/target_property.h +++ b/chromium/cc/trees/target_property.h @@ -24,9 +24,10 @@ enum Type { BACKGROUND_COLOR, BOUNDS, CSS_CUSTOM_PROPERTY, + BACKDROP_FILTER, // These sentinels must be last FIRST_TARGET_PROPERTY = TRANSFORM, - LAST_TARGET_PROPERTY = CSS_CUSTOM_PROPERTY + LAST_TARGET_PROPERTY = BACKDROP_FILTER }; } // namespace TargetProperty diff --git a/chromium/cc/trees/transform_node.cc b/chromium/cc/trees/transform_node.cc index bf8f4262a19..d91bf1d61bf 100644 --- a/chromium/cc/trees/transform_node.cc +++ b/chromium/cc/trees/transform_node.cc @@ -30,8 +30,6 @@ TransformNode::TransformNode() node_and_ancestors_have_only_integer_translation(true), scrolls(false), should_be_snapped(false), - moved_by_inner_viewport_bounds_delta_x(false), - moved_by_inner_viewport_bounds_delta_y(false), moved_by_outer_viewport_bounds_delta_x(false), moved_by_outer_viewport_bounds_delta_y(false), in_subtree_of_page_scale_layer(false), @@ -64,10 +62,6 @@ bool TransformNode::operator==(const TransformNode& other) const { other.node_and_ancestors_have_only_integer_translation && scrolls == other.scrolls && should_be_snapped == other.should_be_snapped && - moved_by_inner_viewport_bounds_delta_x == - other.moved_by_inner_viewport_bounds_delta_x && - moved_by_inner_viewport_bounds_delta_y == - other.moved_by_inner_viewport_bounds_delta_y && moved_by_outer_viewport_bounds_delta_x == other.moved_by_outer_viewport_bounds_delta_x && moved_by_outer_viewport_bounds_delta_y == diff --git a/chromium/cc/trees/transform_node.h b/chromium/cc/trees/transform_node.h index ba14b1469b7..5a19ccec9e0 100644 --- a/chromium/cc/trees/transform_node.h +++ b/chromium/cc/trees/transform_node.h @@ -105,11 +105,6 @@ struct CC_EXPORT TransformNode { bool should_be_snapped : 1; - // These are used to position nodes wrt the right or bottom of the inner or - // outer viewport. - bool moved_by_inner_viewport_bounds_delta_x : 1; - bool moved_by_inner_viewport_bounds_delta_y : 1; - // These are used by the compositor to determine which layers need to be // repositioned by the compositor as a result of browser controls // expanding/contracting the outer viewport size before Blink repositions the @@ -143,8 +138,8 @@ struct CC_EXPORT TransformNode { gfx::Vector2dF source_offset; gfx::Vector2dF source_to_parent; - // See ElementAnimations::MaximumTargetScale() and AnimationStartScale() for - // their meanings. Updated by PropertyTrees::AnimationScalesChanged(). + // See MutatorHost::GetAnimationScales() for their meanings. Updated by + // PropertyTrees::AnimationScalesChanged(). float maximum_animation_scale; float starting_animation_scale; diff --git a/chromium/cc/trees/tree_synchronizer.cc b/chromium/cc/trees/tree_synchronizer.cc index 34839495a62..9e329f02eaa 100644 --- a/chromium/cc/trees/tree_synchronizer.cc +++ b/chromium/cc/trees/tree_synchronizer.cc @@ -89,25 +89,6 @@ void PushLayerList(OwnedLayerImplMap* old_layers, } template <typename LayerTreeType> -void PushElementsInPropertyTreesTo(LayerTreeType* host, - LayerTreeImpl* tree_impl) { - for (auto id_iter = tree_impl->elements_in_property_trees().begin(); - id_iter != tree_impl->elements_in_property_trees().end();) { - const auto& id = *(id_iter++); - if (!host->elements_in_property_trees().count(id)) - tree_impl->RemoveFromElementPropertyTreeList(id); - } - - for (const auto& id : host->elements_in_property_trees()) { - if (!tree_impl->IsElementInPropertyTree(id)) { - // TODO(flackr): We should expose adding element ids without a - // layer pointer. - tree_impl->AddToElementPropertyTreeList(id); - } - } -} - -template <typename LayerTreeType> void SynchronizeTreesInternal(LayerTreeType* source_tree, LayerTreeImpl* tree_impl, PropertyTrees* property_trees) { @@ -220,8 +201,6 @@ void TreeSynchronizer::PushLayerProperties(LayerTreeImpl* pending_tree, PushLayerPropertiesInternal(layers.begin(), layers.end(), active_tree); PushLayerPropertiesInternal(picture_layers.begin(), picture_layers.end(), active_tree); - if (pending_tree->settings().use_layer_lists) - PushElementsInPropertyTreesTo(pending_tree, active_tree); pending_tree->ClearLayersThatShouldPushProperties(); } @@ -232,10 +211,6 @@ void TreeSynchronizer::PushLayerProperties(LayerTreeHost* host_tree, "layer_count", layers.size()); PushLayerPropertiesInternal(layers.begin(), layers.end(), host_tree, impl_tree); - // When using layer lists, we may not have layers for all property tree - // node ids and need to synchronize the registered id list. - if (host_tree->IsUsingLayerLists()) - PushElementsInPropertyTreesTo(host_tree, impl_tree); host_tree->ClearLayersThatShouldPushProperties(); } diff --git a/chromium/cc/trees/ukm_manager.cc b/chromium/cc/trees/ukm_manager.cc index cf500c922b8..7b8c98100d6 100644 --- a/chromium/cc/trees/ukm_manager.cc +++ b/chromium/cc/trees/ukm_manager.cc @@ -19,13 +19,12 @@ UkmManager::~UkmManager() { RecordRenderingUkm(); } -void UkmManager::SetSourceURL(const GURL& url) { - // If we accumulating any metrics, record them before reseting the source. +void UkmManager::SetSourceId(ukm::SourceId source_id) { + // If we accumulated any metrics, record them before resetting the source. RecordCheckerboardUkm(); RecordRenderingUkm(); - source_id_ = recorder_->GetNewSourceID(); - recorder_->UpdateSourceURL(source_id_, url); + source_id_ = source_id; } void UkmManager::SetUserInteractionInProgress(bool in_progress) { diff --git a/chromium/cc/trees/ukm_manager.h b/chromium/cc/trees/ukm_manager.h index fef49175828..aeeda10cd0a 100644 --- a/chromium/cc/trees/ukm_manager.h +++ b/chromium/cc/trees/ukm_manager.h @@ -27,7 +27,7 @@ class CC_EXPORT UkmManager { explicit UkmManager(std::unique_ptr<ukm::UkmRecorder> recorder); ~UkmManager(); - void SetSourceURL(const GURL& url); + void SetSourceId(ukm::SourceId source_id); // These metrics are recorded while a user interaction is in progress. void SetUserInteractionInProgress(bool in_progress); diff --git a/chromium/cc/trees/ukm_manager_unittest.cc b/chromium/cc/trees/ukm_manager_unittest.cc index f69ab618536..9f4dd926f5b 100644 --- a/chromium/cc/trees/ukm_manager_unittest.cc +++ b/chromium/cc/trees/ukm_manager_unittest.cc @@ -6,12 +6,14 @@ #include "components/ukm/test_ukm_recorder.h" #include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" namespace cc { namespace { -const char kTestUrl1[] = "https://example.com/foo"; -const char kTestUrl2[] = "https://example.com/bar"; +const char kTestUrl[] = "https://example.com/foo"; +const int64_t kTestSourceId1 = 100; +const int64_t kTestSourceId2 = 200; const char kUserInteraction[] = "Compositor.UserInteraction"; const char kRendering[] = "Compositor.Rendering"; @@ -27,7 +29,11 @@ class UkmManagerTest : public testing::Test { auto recorder = std::make_unique<ukm::TestUkmRecorder>(); test_ukm_recorder_ = recorder.get(); manager_ = std::make_unique<UkmManager>(std::move(recorder)); - manager_->SetSourceURL(GURL(kTestUrl1)); + + // In production, new UKM Source would have been already created, so + // manager only needs to know the source id. + test_ukm_recorder_->UpdateSourceURL(kTestSourceId1, GURL(kTestUrl)); + manager_->SetSourceId(kTestSourceId1); } protected: @@ -49,7 +55,7 @@ TEST_F(UkmManagerTest, Basic) { for (const auto* entry : entries) { original_id = entry->source_id; EXPECT_NE(ukm::kInvalidSourceId, entry->source_id); - test_ukm_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestUrl1)); + test_ukm_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestUrl)); test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardArea, 10); test_ukm_recorder_->ExpectEntryMetric(entry, kMissingTiles, 2); test_ukm_recorder_->ExpectEntryMetric(entry, kCheckerboardAreaRatio, 50); @@ -71,7 +77,7 @@ TEST_F(UkmManagerTest, Basic) { manager_->AddCheckerboardStatsForFrame(10, 1, 100); manager_->AddCheckerboardStatsForFrame(30, 5, 100); - manager_->SetSourceURL(GURL(kTestUrl2)); + manager_->SetSourceId(kTestSourceId2); const auto& entries2 = test_ukm_recorder_->GetEntriesByName(kUserInteraction); EXPECT_EQ(1u, entries2.size()); |